]> err.no Git - sope/blob - sope-appserver/NGXmlRpc/WODirectAction+XmlRpcIntrospection.m
milli => micro
[sope] / sope-appserver / NGXmlRpc / WODirectAction+XmlRpcIntrospection.m
1 /*
2   Copyright (C) 2000-2003 SKYRIX Software AG
3
4   This file is part of OGo
5
6   OGo is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with OGo; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21 // $Id$
22
23 #include "WODirectAction+XmlRpcIntrospection.h"
24 #include "WODirectAction+XmlRpc.h"
25 #include "NSObject+Reflection.h"
26 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
27 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
28 #include <NGObjWeb/WORequest.h>
29 #include "common.h"
30
31 @interface NSMethodSignature(XmlRpcSignature)
32
33 - (NSArray *)xmlRpcSignature;
34
35 @end
36
37 @implementation NSMethodSignature(XmlRpcSignature)
38
39 - (NSString *)xmlRpcTypeForObjCType:(const char *)_type {
40   if (_type == NULL) return nil;
41 #if GNU_RUNTIME
42   switch (*_type) {
43     case _C_ID:
44     case _C_CLASS:
45       return @"string";
46
47     case _C_SEL:
48     case _C_CHARPTR:
49       return @"string";
50       
51     case _C_CHR:
52     case _C_UCHR:
53       return @"boolean";
54       
55     case _C_INT:
56     case _C_UINT:
57     case _C_SHT:
58     case _C_USHT:
59     case _C_LNG:
60     case _C_ULNG:
61       return @"i4";
62
63     case _C_ARY_B:
64       return @"array";
65     case _C_STRUCT_B:
66       return @"struct";
67       
68     case _C_FLT:
69     case _C_DBL:
70       return @"double";
71   }
72 #endif
73   return @"string";
74 }
75
76 - (NSArray *)xmlRpcSignature {
77   NSMutableArray *signature;
78   unsigned i;
79
80   signature = [NSMutableArray arrayWithCapacity:8];
81
82   /* return value */
83   [signature addObject:[self xmlRpcTypeForObjCType:[self methodReturnType]]];
84   
85   /* arguments */
86   for (i = 2; i < [self numberOfArguments]; i++) {
87     const char *t;
88     
89     t = [self getArgumentTypeAtIndex:i];
90     [signature addObject:[self xmlRpcTypeForObjCType:t]];
91   }
92   
93   return signature;
94 }
95
96 @end /* NSMethodSignature(XmlRpcSignature) */
97
98 @implementation WODirectAction(XmlRpcIntrospection)
99
100 static NSArray *blacklist = nil;
101
102 - (NSArray *)system_listMethodsAction {
103   NSMutableArray *ma;
104   NSEnumerator   *sels;
105   NSString       *sel;
106   NSString       *namespace;
107   NSArray        *selectors;
108
109   namespace = [self xmlrpcComponentNamespace];
110
111   if (blacklist == nil) {  
112     blacklist = [[NSArray alloc] initWithObjects:@"RPC2Action",
113                                  @"RPC2InfoPageAction",
114                                  @"xmlrpcAction",
115                                  @"commitFailedAction",
116                                  @"WOStatsAction",
117                                  @"defaultAction",
118                                  @"missingAuthAction",
119                                  @"selectorForXmlRpcAction:",
120                                  @"accessDeniedAction",nil];
121   }
122
123   selectors = [self respondsToSelectors];
124   sels = [selectors objectEnumerator];
125
126   ma = [NSMutableArray arrayWithCapacity:[selectors count]];
127
128   while ((sel = [sels nextObject])) {
129     unsigned idx, len;
130     NSString *actionName;
131     NSRange rng;
132
133     if ([blacklist containsObject:sel])
134       continue;
135
136     rng = [sel rangeOfString:@"Action"];
137     if (rng.length <= 0) continue;
138     
139     /* strip Action */
140     actionName = [sel substringToIndex:rng.location];
141
142     /* ensure that only dots are following the 'Action' */
143     for (idx = (rng.location + rng.length), len = [sel length]; 
144          idx < len; idx++) {
145       unichar c = [sel characterAtIndex:idx];
146       if (c != ':') {
147         actionName = nil;
148         break;
149       }
150     }
151     
152     /* go to next selector if ... */
153     if ([actionName length] == 0) continue;
154     
155     /* make action name XMLRPC-style friendly */    
156     actionName = [actionName stringByReplacingString:@"_" withString:@"."];
157
158     if (namespace == nil)
159       [ma addObject:actionName];
160     else {
161       /* add to reflection set */
162       if ([actionName hasPrefix:@"system."])
163         [ma addObject:actionName];
164       else {
165         NSString *s;
166         
167         s = [[NSString alloc] initWithFormat:@"%@.%@", namespace,actionName];
168         [ma addObject:s];
169         [s release];
170       }
171     }
172   }
173
174   return [[[ma copy] autorelease] sortedArrayUsingSelector:
175                      @selector(caseInsensitiveCompare:)];
176 }
177
178 - (NSArray *)system_methodSignatureAction:(NSString *)_xmlrpcMethod {
179   /*
180     It returns an array of possible signatures for this method. A signature
181     is an array of types. The first of these types is the return type of the
182     method, the rest are parameters.
183
184     Multiple signatures (ie. overloading) are permitted: this is the reason
185     that an array of signatures are returned by this method.
186
187     Signatures themselves are restricted to the top level parameters expected
188     by a method. For instance if a method expects one array of structs as a
189     parameter, and it returns a string, its signature is simply
190     "string, array". If it expects three integers, its signature is
191     "string, int, int, int".
192
193     If no signature is defined for the method, a none-array value is returned.
194   */
195   NSMutableArray *signatures;
196   NSString       *actionName;
197   NSEnumerator   *sels;
198   NSString       *sel;
199   unsigned len;
200   Class clazz;
201
202   clazz      = [self class];
203   signatures = [NSMutableArray arrayWithCapacity:4];
204   actionName = [self selectorForXmlRpcAction:_xmlrpcMethod];
205   
206   len = [actionName length];
207   
208   sels = [[self respondsToSelectors] objectEnumerator];
209   while ((sel = [sels nextObject])) {
210     NSArray *signature;
211     NSMethodSignature *ms;
212     
213     if (![sel hasPrefix:actionName]) continue;
214     
215     ms = [self methodSignatureForSelector:NSSelectorFromString(sel)];
216     if (ms) {
217       signature = [ms xmlRpcSignature];
218     }
219     else {
220       [self logWithFormat:@"missing Objective-C method signature for %@ ...",
221               sel];
222       signature = nil;
223     }
224     
225     if (signature)
226       [signatures addObject:signature];
227   }
228   
229   return ([signatures count] > 0)
230     ? signatures
231     : (id)[NSNumber numberWithBool:NO];
232 }
233
234 - (NSString *)system_methodHelpAction:(NSString *)_xmlrpcMethod {
235   return
236     @"Note: the Objective-C runtime cannot return the correct XML-RPC type "
237     @"for object parameters automatically (only for base types ...).";
238 }
239
240 @end /* WODirectAction(XmlRpcIntrospection) */
241
242 #include <NGObjWeb/WOResponse.h>
243
244 @implementation WODirectAction(XmlRpcInfo)
245
246 - (id<WOActionResults>)RPC2InfoPageAction {
247   WOResponse *r;
248   NSEnumerator *e;
249   id tmp;
250
251   r = [WOResponse alloc];
252   r = [[r initWithRequest:[self request]] autorelease];
253   [r setHeader:@"text/html" forKey:@"content-type"];
254
255   [r appendContentString:@"<html><head><title>WebService at "];
256   [r appendContentHTMLString:[[self request] uri]];
257   [r appendContentString:@"</title></head><body bgcolor=\"#FFFFFF\">"];
258   
259   [r appendContentString:@"<h3>WebService at "];
260   [r appendContentHTMLString:[[self request] uri]];
261   [r appendContentString:@"</h3>"];
262   
263   [r appendContentString:@"<h4>methods</h4>"];
264
265   [r appendContentString:@"<table border='1'>\n"];
266   [r appendContentString:
267      @"<tr><th>name</th><th>signature</th><th>info</th></tr>\n"];
268   
269   e = [[self system_listMethodsAction] objectEnumerator];
270   while ((tmp = [e nextObject])) {
271     NSString *mname, *info;
272     id sig;
273
274     mname = [tmp stringValue];
275     [r appendContentString:@"<tr>"];
276     
277     [r appendContentString:@"<td>"];
278     [r appendContentHTMLString:mname];
279     [r appendContentString:@"</td>"];
280     
281     sig  = [self system_methodSignatureAction:mname];
282     info = [self system_methodHelpAction:mname];
283
284     [r appendContentString:@"<td>"];
285     if ([sig isKindOfClass:[NSArray class]]) {
286       [r appendContentHTMLString:[sig stringValue]];
287     }
288     [r appendContentString:@"</td>"];
289
290     if ([info length] > 0) {
291       [r appendContentString:@"<td>"];
292       [r appendContentString:info];
293       [r appendContentString:@"</td>"];
294     }
295     
296     [r appendContentString:@"</tr>\n"];
297   }
298   [r appendContentString:@"</table>"];
299   
300   [r appendContentString:@"</body></html>"];
301   
302   return r;
303 }
304
305 @end /* WODirectAction(XmlRpcInfo) */