2 Copyright (C) 2000-2003 SKYRIX Software AG
4 This file is part of OGo
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
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.
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
23 #include "WODirectAction+XmlRpc.h"
24 #include <NGXmlRpc/NSObject+Reflection.h>
25 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
26 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
27 #include <NGObjWeb/WORequest.h>
30 @implementation WODirectAction(XmlRpc)
32 static int CoreOnException = -1;
34 - (NSString *)xmlrpcComponentNamespacePrefix {
37 np = [[NSUserDefaults standardUserDefaults]
38 stringForKey:@"SxDefaultNamespacePrefix"];
43 @"WARNING: SxDefaultNamespacePrefix default is not set !"];
45 np = [(NSHost *)[NSHost currentHost] name];
46 if ([np length] > 0) {
47 if (!isdigit([np characterAtIndex:0])) {
50 parts = [np componentsSeparatedByString:@"."];
51 if ([parts count] == 0) {
53 else if ([parts count] == 1)
54 return [parts objectAtIndex:0];
60 e = [parts reverseObjectEnumerator];
61 while ((s = [e nextObject])) {
67 np = [[np stringByAppendingString:@"."] stringByAppendingString:s];
77 - (NSString *)xmlrpcComponentName {
80 s = NSStringFromClass([self class]);
81 if (![s isEqualToString:@"DirectAction"])
84 return [[NSProcessInfo processInfo] processName];
87 - (NSString *)xmlrpcComponentNamespace {
90 ns = [self xmlrpcComponentNamespacePrefix];
91 n = [self xmlrpcComponentName];
92 return [[ns stringByAppendingString:@"."] stringByAppendingString:n];
95 - (NSArray *)_methodActionNames {
100 sels = [[self respondsToSelectors] objectEnumerator];
102 ma = [NSMutableArray arrayWithCapacity:16];
103 while ((sel = [sels nextObject])) {
105 NSString *actionName;
108 rng = [sel rangeOfString:@"Action"];
109 if (rng.length <= 0) continue;
113 /* ensure that only dots are following the 'Action' */
114 for (idx = (rng.location + rng.length), len = [sel length];
116 unichar c = [sel characterAtIndex:idx];
123 /* go to next selector if ... */
124 if ([actionName length] == 0) continue;
126 /* add to reflection set */
127 [ma addObject:actionName];
129 return [[ma copy] autorelease];
132 - (NSString *)selectorForXmlRpcAction:(NSString *)_name {
133 NSString *actionName;
136 actionName = @"Action";
138 /* check component namespace and strip it ;-) */
140 p = [self xmlrpcComponentNamespace];
142 if ([p length] > 0) {
143 if ([_name hasPrefix:@"system."])
145 else if ([_name hasPrefix:p]) {
146 _name = [_name substringFromIndex:[p length]];
147 if ([_name length] > 0) {
148 if ([_name characterAtIndex:0] == '.')
149 _name = [_name substringFromIndex:1];
154 @"WARNING: tried to invoke XML-RPC method from "
155 @"different component (namespace=%@): %@",
160 /* replace namespace points by '_' */
162 _name = [_name stringByReplacingString:@"." withString:@"_"];
163 actionName = [_name stringByAppendingString:actionName];
169 - (NSString *)selectorForXmlRpcAction:(NSString *)_name
170 parameters:(NSArray *)_params
172 NSString *actionName;
175 actionName = [self selectorForXmlRpcAction:_name];
177 /* append ':' for each parameter */
179 switch ((cnt = [_params count])) {
183 actionName = [actionName stringByAppendingString:@":"];
186 actionName = [actionName stringByAppendingString:@"::"];
189 actionName = [actionName stringByAppendingString:@":::"];
192 actionName = [actionName stringByAppendingString:@"::::"];
196 for (i = 0, cnt = [_params count]; i < cnt; i++)
197 actionName = [actionName stringByAppendingString:@":"];
205 - (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params {
206 NSMethodSignature *sign;
208 NSString *actionName;
213 /* generate selector */
214 actionName = [self selectorForXmlRpcAction:_name parameters:_params];
215 sel = NSSelectorFromString(actionName);
217 if (![self respondsToSelector:sel]) {
218 NSEnumerator *actEnum;
219 NSString *name = nil;
222 actEnum = [[self _methodActionNames] objectEnumerator];
223 name = [actionName stringByReplacingString:@":" withString:@""];
225 while ((act = [actEnum nextObject])) {
226 NSString *tmp = [act stringByReplacingString:@":" withString:@""];
228 if ([tmp isEqualToString:name]) actionName = act;
230 sel = NSSelectorFromString(actionName);
233 /* Note: NULL selectors are not caught by MacOSX -respondsToSel: ! */
234 [self logWithFormat:@"no such XMLRPC action: '%@'", _name];
235 return [NSException exceptionWithName:@"NoSuchAction"
236 reason:@"action not implemented"
239 else if (![self respondsToSelector:sel]) {
240 [self logWithFormat:@"no such XMLRPC action: '%@' (selector=%@)",
241 _name, NSStringFromSelector(sel)];
243 return [NSException exceptionWithName:@"NoSuchAction"
244 reason:@"action not implemented"
249 cnt = [[actionName componentsSeparatedByString:@":"] count] - 1;
252 sign = [[self class] instanceMethodSignatureForSelector:sel];
253 invo = [NSInvocation invocationWithMethodSignature:sign];
254 [invo setSelector:sel];
255 if (cnt == 0) cnt = ([sign numberOfArguments] - 2);
257 [invo setTarget:self];
259 cnt = (cnt > (int)[_params count]) ? (int)[_params count] : cnt;
261 for (i = 0; i < cnt; i++) {
262 id param = [_params objectAtIndex:i];
263 [invo setArgument:¶m atIndex:(i + 2)];
265 // TODO(hh): should fill the remaining args when less params available ?
268 [invo getReturnValue:&result];
273 - (id)_faultForException:(NSException *)_exception {
274 if (CoreOnException == -1) {
277 [[NSUserDefaults standardUserDefaults]
278 boolForKey:@"WOCoreOnXmlRpcFault"] ? 1 : 0;
281 if (CoreOnException) {
282 [self logWithFormat:@"core on exception: %@", _exception];
287 [self logWithFormat:@"turn exception into fault: %@", _exception];
293 XmlRpcMethodCall *call;
294 XmlRpcMethodResponse *mResponse;
297 if (![[[self request] method] isEqualToString:@"POST"]) {
298 /* only POST is allowed for direct XML-RPC requests ! */
300 if ([[[self request] method] isEqualToString:@"GET"])
301 return [self RPC2InfoPageAction];
306 call = [XmlRpcMethodCall alloc];
307 call = [[call initWithRequest:[self request]] autorelease];
314 content = [rq content];
316 [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
317 [self logWithFormat:@" content-len: %d", [content length]];
318 [self logWithFormat:@" encoding: %d", [rq contentEncoding]];
322 [self debugWithFormat:@"decoded XMLRPC call: %@", call];
325 result = [[self performActionNamed:[call methodName]
326 parameters:[call parameters]]
330 result = [[self _faultForException:localException] retain];
334 [[[XmlRpcMethodResponse alloc] initWithResult:result] autorelease];
336 [result release]; result = nil;
338 return [mResponse generateResponse];
340 - (id<WOActionResults>)xmlrpcAction {
341 [self debugWithFormat:@"deprecated, please use /RPC2 as direct action !"];
342 return [self RPC2Action];
345 @end /* WODirectAction(XmlRpc) */