]> err.no Git - sope/blob - sope-appserver/NGXmlRpc/WODirectAction+XmlRpcIntrospection.m
Add libxml2-dev to libsope-xml4.7-dev deps
[sope] / sope-appserver / NGXmlRpc / WODirectAction+XmlRpcIntrospection.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE 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   SOPE 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 SOPE; 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
22 #include "WODirectAction+XmlRpcIntrospection.h"
23 #include "WODirectAction+XmlRpc.h"
24 #include "NSObject+Reflection.h"
25 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
26 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
27 #include <NGObjWeb/WORequest.h>
28 #include "common.h"
29
30 @interface NSMethodSignature(XmlRpcSignature)
31
32 - (NSArray *)xmlRpcSignature;
33
34 @end
35
36 @implementation NSMethodSignature(XmlRpcSignature)
37
38 - (NSString *)xmlRpcTypeForObjCType:(const char *)_type {
39   if (_type == NULL) return nil;
40 #if GNU_RUNTIME
41   switch (*_type) {
42     case _C_ID:
43     case _C_CLASS:
44       return @"string";
45
46     case _C_SEL:
47     case _C_CHARPTR:
48       return @"string";
49       
50     case _C_CHR:
51     case _C_UCHR:
52       return @"boolean";
53       
54     case _C_INT:
55     case _C_UINT:
56     case _C_SHT:
57     case _C_USHT:
58     case _C_LNG:
59     case _C_ULNG:
60       return @"i4";
61
62     case _C_ARY_B:
63       return @"array";
64     case _C_STRUCT_B:
65       return @"struct";
66       
67     case _C_FLT:
68     case _C_DBL:
69       return @"double";
70   }
71 #endif
72   return @"string";
73 }
74
75 - (NSArray *)xmlRpcSignature {
76   NSMutableArray *signature;
77   unsigned i;
78
79   signature = [NSMutableArray arrayWithCapacity:8];
80
81   /* return value */
82   [signature addObject:[self xmlRpcTypeForObjCType:[self methodReturnType]]];
83   
84   /* arguments */
85   for (i = 2; i < [self numberOfArguments]; i++) {
86     const char *t;
87     
88     t = [self getArgumentTypeAtIndex:i];
89     [signature addObject:[self xmlRpcTypeForObjCType:t]];
90   }
91   
92   return signature;
93 }
94
95 @end /* NSMethodSignature(XmlRpcSignature) */
96
97 @implementation WODirectAction(XmlRpcIntrospection)
98
99 static NSArray *blacklist = nil;
100
101 - (NSArray *)system_listMethodsAction {
102   NSMutableArray *ma;
103   NSEnumerator   *sels;
104   NSString       *sel;
105   NSString       *namespace;
106   NSArray        *selectors;
107
108   namespace = [self xmlrpcComponentNamespace];
109
110   if (blacklist == nil) {  
111     blacklist = [[NSArray alloc] initWithObjects:@"RPC2Action",
112                                  @"RPC2InfoPageAction",
113                                  @"xmlrpcAction",
114                                  @"commitFailedAction",
115                                  @"WOStatsAction",
116                                  @"defaultAction",
117                                  @"missingAuthAction",
118                                  @"selectorForXmlRpcAction:",
119                                  @"accessDeniedAction",nil];
120   }
121
122   selectors = [self respondsToSelectors];
123   sels = [selectors objectEnumerator];
124
125   ma = [NSMutableArray arrayWithCapacity:[selectors count]];
126
127   while ((sel = [sels nextObject])) {
128     unsigned idx, len;
129     NSString *actionName;
130     NSRange rng;
131
132     if ([blacklist containsObject:sel])
133       continue;
134
135     rng = [sel rangeOfString:@"Action"];
136     if (rng.length <= 0) continue;
137     
138     /* strip Action */
139     actionName = [sel substringToIndex:rng.location];
140
141     /* ensure that only dots are following the 'Action' */
142     for (idx = (rng.location + rng.length), len = [sel length]; 
143          idx < len; idx++) {
144       unichar c = [sel characterAtIndex:idx];
145       if (c != ':') {
146         actionName = nil;
147         break;
148       }
149     }
150     
151     /* go to next selector if ... */
152     if (![actionName isNotEmpty]) continue;
153     
154     /* make action name XMLRPC-style friendly */    
155     actionName = [actionName stringByReplacingString:@"_" withString:@"."];
156
157     if (namespace == nil)
158       [ma addObject:actionName];
159     else {
160       /* add to reflection set */
161       if ([actionName hasPrefix:@"system."])
162         [ma addObject:actionName];
163       else {
164         NSString *s;
165         
166         s = [[NSString alloc] initWithFormat:@"%@.%@", namespace,actionName];
167         [ma addObject:s];
168         [s release];
169       }
170     }
171   }
172
173   return [[[ma copy] autorelease] sortedArrayUsingSelector:
174                      @selector(caseInsensitiveCompare:)];
175 }
176
177 - (NSArray *)system_methodSignatureAction:(NSString *)_xmlrpcMethod {
178   /*
179     It returns an array of possible signatures for this method. A signature
180     is an array of types. The first of these types is the return type of the
181     method, the rest are parameters.
182
183     Multiple signatures (ie. overloading) are permitted: this is the reason
184     that an array of signatures are returned by this method.
185
186     Signatures themselves are restricted to the top level parameters expected
187     by a method. For instance if a method expects one array of structs as a
188     parameter, and it returns a string, its signature is simply
189     "string, array". If it expects three integers, its signature is
190     "string, int, int, int".
191
192     If no signature is defined for the method, a none-array value is returned.
193   */
194   NSMutableArray *signatures;
195   NSString       *actionName;
196   NSEnumerator   *sels;
197   NSString       *sel;
198   unsigned len;
199   Class clazz;
200
201   clazz      = [self class];
202   signatures = [NSMutableArray arrayWithCapacity:4];
203   actionName = [self selectorForXmlRpcAction:_xmlrpcMethod];
204   
205   len = [actionName length];
206   
207   sels = [[self respondsToSelectors] objectEnumerator];
208   while ((sel = [sels nextObject])) {
209     NSArray *signature;
210     NSMethodSignature *ms;
211     
212     if (![sel hasPrefix:actionName]) continue;
213     
214     ms = [self methodSignatureForSelector:NSSelectorFromString(sel)];
215     if (ms) {
216       signature = [ms xmlRpcSignature];
217     }
218     else {
219       [self logWithFormat:@"missing Objective-C method signature for %@ ...",
220               sel];
221       signature = nil;
222     }
223     
224     if (signature)
225       [signatures addObject:signature];
226   }
227   
228   return [signatures isNotEmpty]
229     ? signatures
230     : (NSMutableArray *)[NSNumber numberWithBool:NO];
231 }
232
233 - (NSString *)system_methodHelpAction:(NSString *)_xmlrpcMethod {
234   return
235     @"Note: the Objective-C runtime cannot return the correct XML-RPC type "
236     @"for object parameters automatically (only for base types ...).";
237 }
238
239 @end /* WODirectAction(XmlRpcIntrospection) */
240
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 isNotEmpty]) {
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) */