2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
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
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.
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
22 #include "WODirectAction+XmlRpc.h"
23 #include <NGXmlRpc/NSObject+Reflection.h>
24 #include <NGXmlRpc/XmlRpcMethodCall+WO.h>
25 #include <NGXmlRpc/XmlRpcMethodResponse+WO.h>
26 #include <NGObjWeb/WORequest.h>
29 @implementation WODirectAction(XmlRpc)
31 static int CoreOnException = -1;
33 - (NSString *)xmlrpcComponentNamespacePrefix {
34 // TODO: should be deprecated
38 ud = [NSUserDefaults standardUserDefaults];
39 np = [ud stringForKey:@"SxDefaultNamespacePrefix"];
44 @"WARNING: SxDefaultNamespacePrefix default is not set !"];
46 np = [(NSHost *)[NSHost currentHost] name];
47 if ([np length] > 0) {
48 if (!isdigit([np characterAtIndex:0])) {
51 parts = [np componentsSeparatedByString:@"."];
52 if ([parts count] == 0) {
54 else if ([parts count] == 1)
55 return [parts objectAtIndex:0];
61 e = [parts reverseObjectEnumerator];
62 while ((s = [e nextObject])) {
68 np = [[np stringByAppendingString:@"."] stringByAppendingString:s];
78 - (NSString *)xmlrpcComponentName {
79 // TODO: should be deprecated
82 s = NSStringFromClass([self class]);
83 if (![s isEqualToString:@"DirectAction"])
86 return [[NSProcessInfo processInfo] processName];
89 - (NSString *)xmlrpcComponentNamespace {
90 // TODO: should be deprecated
93 ns = [self xmlrpcComponentNamespacePrefix];
94 n = [self xmlrpcComponentName];
95 return [[ns stringByAppendingString:@"."] stringByAppendingString:n];
98 - (NSArray *)_methodActionNames {
103 sels = [[self respondsToSelectors] objectEnumerator];
105 ma = [NSMutableArray arrayWithCapacity:16];
106 while ((sel = [sels nextObject])) {
108 NSString *actionName;
111 rng = [sel rangeOfString:@"Action"];
112 if (rng.length <= 0) continue;
116 /* ensure that only dots are following the 'Action' */
117 for (idx = (rng.location + rng.length), len = [sel length];
119 unichar c = [sel characterAtIndex:idx];
126 /* go to next selector if ... */
127 if ([actionName length] == 0) continue;
129 /* add to reflection set */
130 [ma addObject:actionName];
132 return [[ma copy] autorelease];
135 - (NSString *)selectorForXmlRpcAction:(NSString *)_name {
136 NSString *actionName;
139 actionName = @"Action";
141 /* check component namespace and strip it ;-) */
143 p = [self xmlrpcComponentNamespace];
145 if ([p length] > 0) {
146 if ([_name hasPrefix:@"system."])
148 else if ([_name hasPrefix:p]) {
149 _name = [_name substringFromIndex:[p length]];
150 if ([_name length] > 0) {
151 if ([_name characterAtIndex:0] == '.')
152 _name = [_name substringFromIndex:1];
157 @"WARNING: tried to invoke XML-RPC method from "
158 @"different component (namespace=%@): %@",
163 /* replace namespace points by '_' */
165 _name = [_name stringByReplacingString:@"." withString:@"_"];
166 actionName = [_name stringByAppendingString:actionName];
172 - (NSString *)selectorForXmlRpcAction:(NSString *)_name
173 parameters:(NSArray *)_params
175 NSString *actionName;
178 actionName = [self selectorForXmlRpcAction:_name];
180 /* append ':' for each parameter */
182 switch ((cnt = [_params count])) {
186 actionName = [actionName stringByAppendingString:@":"];
189 actionName = [actionName stringByAppendingString:@"::"];
192 actionName = [actionName stringByAppendingString:@":::"];
195 actionName = [actionName stringByAppendingString:@"::::"];
199 for (i = 0, cnt = [_params count]; i < cnt; i++)
200 actionName = [actionName stringByAppendingString:@":"];
208 - (id)performActionNamed:(NSString *)_name parameters:(NSArray *)_params {
209 NSMethodSignature *sign;
211 NSString *actionName;
216 /* generate selector */
217 actionName = [self selectorForXmlRpcAction:_name parameters:_params];
218 sel = NSSelectorFromString(actionName);
220 if (![self respondsToSelector:sel]) {
221 NSEnumerator *actEnum;
222 NSString *name = nil;
225 actEnum = [[self _methodActionNames] objectEnumerator];
226 name = [actionName stringByReplacingString:@":" withString:@""];
228 while ((act = [actEnum nextObject])) {
229 NSString *tmp = [act stringByReplacingString:@":" withString:@""];
231 if ([tmp isEqualToString:name]) actionName = act;
233 sel = NSSelectorFromString(actionName);
236 /* Note: NULL selectors are not caught by MacOSX -respondsToSel: ! */
237 [self logWithFormat:@"no such XMLRPC action: '%@'", _name];
238 return [NSException exceptionWithName:@"NoSuchAction"
239 reason:@"action not implemented"
242 else if (![self respondsToSelector:sel]) {
243 [self logWithFormat:@"no such XMLRPC action: '%@' (selector=%@)",
244 _name, NSStringFromSelector(sel)];
246 return [NSException exceptionWithName:@"NoSuchAction"
247 reason:@"action not implemented"
252 cnt = [[actionName componentsSeparatedByString:@":"] count] - 1;
255 sign = [[self class] instanceMethodSignatureForSelector:sel];
256 invo = [NSInvocation invocationWithMethodSignature:sign];
257 [invo setSelector:sel];
258 if (cnt == 0) cnt = ([sign numberOfArguments] - 2);
260 [invo setTarget:self];
262 cnt = (cnt > (int)[_params count]) ? (int)[_params count] : cnt;
264 for (i = 0; i < cnt; i++) {
267 param = [_params objectAtIndex:i];
268 [invo setArgument:¶m atIndex:(i + 2)];
270 // TODO(hh): should fill the remaining args when less params available ?
273 [invo getReturnValue:&result];
278 - (id)_faultForException:(NSException *)_exception {
279 if (CoreOnException == -1) {
282 [[NSUserDefaults standardUserDefaults]
283 boolForKey:@"WOCoreOnXmlRpcFault"] ? 1 : 0;
286 if (CoreOnException) {
287 [self logWithFormat:@"core on exception: %@", _exception];
292 [self logWithFormat:@"turn exception into fault: %@", _exception];
298 XmlRpcMethodCall *call;
299 XmlRpcMethodResponse *mResponse;
302 if (![[[self request] method] isEqualToString:@"POST"]) {
303 /* only POST is allowed for direct XML-RPC requests ! */
305 if ([[[self request] method] isEqualToString:@"GET"])
306 return [self RPC2InfoPageAction];
311 call = [XmlRpcMethodCall alloc];
312 call = [[call initWithRequest:[self request]] autorelease];
319 content = [rq content];
321 [self logWithFormat:@"couldn't decode XMLRPC content:\n"];
322 [self logWithFormat:@" content-len: %d", [content length]];
323 [self logWithFormat:@" encoding: %d", [rq contentEncoding]];
327 [self debugWithFormat:@"decoded XMLRPC call: %@", call];
330 result = [[self performActionNamed:[call methodName]
331 parameters:[call parameters]]
335 result = [[self _faultForException:localException] retain];
339 [[[XmlRpcMethodResponse alloc] initWithResult:result] autorelease];
341 [result release]; result = nil;
343 return [mResponse generateResponse];
345 - (id<WOActionResults>)xmlrpcAction {
346 [self debugWithFormat:@"deprecated, please use /RPC2 as direct action !"];
347 return [self RPC2Action];
350 @end /* WODirectAction(XmlRpc) */