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 "SxXmlRpcComponent.h"
24 #include "SxComponentRegistry.h"
25 #include "SxComponentMethodSignature.h"
26 #include "SxXmlRpcInvocation.h"
27 #include "SxComponentException.h"
28 #include <XmlRpc/NSObject+XmlRpc.h>
29 #include <NGXmlRpc/NGXmlRpcClient.h>
30 #include <NGObjWeb/WOHTTPConnection.h>
31 #include <NGObjWeb/WOResponse.h>
32 #include <NGObjWeb/WORequest.h>
33 #include <NGStreams/NGSocketExceptions.h>
38 @interface SxComponentRegistry(RemoveComponentFromCache)
39 - (void)_removeComponentFromLookupCache:(NSString *)_cname;
40 @end /* SxComponentRegistry(RemoveComponentFromCache) */
42 @interface SxXmlRpcComponent(Privates)
44 /* this method doesn't prepend component name ... */
45 - (id)_call:(NSString *)_methodName arguments:(NSArray *)_params;
49 @implementation SxXmlRpcComponent
52 return [super version] + 0 /* v1 */;
55 NSAssert2([super version] == 1,
56 @"invalid superclass (%@) version %i !",
57 NSStringFromClass([self superclass]), [super version]);
60 - (id)initWithName:(NSString *)_name
61 registry:(SxComponentRegistry *)_registry
64 return [self initWithName:_name
65 namespace:[[_name componentsSeparatedByString:@"."] lastObject]
70 - (id)initWithName:(NSString *)_name
71 namespace:(NSString *)_namespace
72 registry:(SxComponentRegistry *)_registry
75 if ((self = [self initWithName:_name namespace:_namespace
76 registry:_registry])) {
77 self->url = [_url copy];
78 self->httpConnection =
79 [[WOHTTPConnection alloc] initWithHost:[_url host]
80 onPort:[[_url port] intValue]];
88 [self->lastCredentials release];
89 [self->signatureCache release];
90 [self->httpConnection release];
98 return [self->url path];
101 - (WOHTTPConnection *)httpConnection {
102 return self->httpConnection;
109 - (void)addSuccessfulCredentials:(id)_creds {
110 ASSIGN(self->lastCredentials, _creds);
113 - (NSString *)fqMethodNameForMethod:(NSString *)_method {
116 if (![_method hasPrefix:@"system."]) {
117 if ((ns = [self namespace]) != nil) {
118 return [[ns stringByAppendingString:@"."]
119 stringByAppendingString:_method];
127 - (Class)invocationClass {
128 static Class CompInv = Nil;
129 if (CompInv == Nil) CompInv = [SxXmlRpcInvocation class];
133 - (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
134 methodSignature:(SxComponentMethodSignature *)_signature
137 Overridden to add the last successful credentials to newly created
140 SxComponentInvocation *inv;
142 inv = [super invocationForMethodNamed:_method
143 methodSignature:_signature];
144 [inv setCredentials:self->lastCredentials];
148 - (NSArray *)signaturesForMethodNamed:(NSString *)_method {
149 NSMutableArray *result;
151 NSString *fqMethodName;
154 [self resetLastException];
156 if ([_method length] == 0)
159 if ((signatures = [self->signatureCache objectForKey:_method]))
160 return [signatures isNotNull] ? signatures : nil;
162 fqMethodName = [self fqMethodNameForMethod:_method];
164 signatures = [self _call:@"system.methodSignature"
165 arguments:[NSArray arrayWithObject:fqMethodName]];
167 if ([self lastCallFailed]) {
170 e = [self lastException];
171 [self logWithFormat:@"%s: couldn't get method signature:\n"
173 @" name: %@ (class=%@)\n"
175 __PRETTY_FUNCTION__, _method,
176 NSStringFromClass([e class]), [e name], [e reason]];
180 if (![signatures isKindOfClass:[NSArray class]]) {
183 e = [NSException exceptionWithName:@"InvalidXmlRpcResult"
184 reason:@"system.methodSignature did not return an array"
188 @"system.methodSignature didn't return an array: '%@'<%@>",
189 signatures, NSStringFromClass([signatures class])];
191 if (e) [self setLastException:e];
196 result = [NSMutableArray arrayWithCapacity:[signatures count]];
198 for (i = 0; i < [signatures count]; i++) {
199 SxComponentMethodSignature *signature;
202 bsig = [signatures objectAtIndex:i];
203 signature = [SxComponentMethodSignature signatureWithXmlRpcTypes:bsig];
204 [result addObject:signature];
207 if (self->signatureCache == nil)
208 self->signatureCache = [[NSMutableDictionary alloc] initWithCapacity:32];
210 [self->signatureCache
211 setObject:result?result:(id)[NSNull null]
217 - (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
218 arguments:(NSArray *)_args
220 static NSArray *retType = nil;
221 SxComponentMethodSignature *sig;
222 SxXmlRpcInvocation *inv;
226 retType = [[NSArray alloc] initWithObjects:@"string", nil];
228 xsig = [retType arrayByAddingObjectsFromArray:
229 [_args xmlRpcElementSignature]];
230 sig = [[SxComponentMethodSignature alloc] initWithXmlRpcTypes:xsig];
232 inv = (id)[self invocationForMethodNamed:_method
233 methodSignature:sig];
234 [inv setArguments:_args];
241 - (id)_call:(NSString *)_methodName arguments:(NSArray *)_params {
242 SxComponentInvocation *inv;
243 NSAutoreleasePool *pool;
247 pool = [[NSAutoreleasePool alloc] init];
248 [self resetLastException];
250 inv = [self invocationForMethodNamed:_methodName
253 /* TODO: hh: invoke does not work yet fully, returns true on fail ... */
256 if ((e = [inv lastException])) {
259 retries = [[self componentRegistry] componentRetryCountOnError];
261 if (self->retryCnt < retries) {
262 if ([e isKindOfClass:[NGCouldNotConnectException class]]) {
263 SxXmlRpcComponent *tmpComp;
266 compRegistry = [self componentRegistry];
268 [compRegistry _removeComponentFromLookupCache:[self componentName]];
269 tmpComp = (SxXmlRpcComponent *)
270 [compRegistry getComponent:[self componentName]];
275 tmpUrl = [tmpComp url];
277 [self->url release]; self->url = nil;
278 [self->httpConnection release]; self->httpConnection = nil;
280 self->url = RETAIN(tmpUrl);
282 self->httpConnection =
283 [[WOHTTPConnection alloc] initWithHost:[tmpUrl host]
284 onPort:[[tmpUrl port] intValue]];
286 NSLog(@"%s: trying once again (%d)....", __PRETTY_FUNCTION__,
289 sleep(self->retryCnt*[[self componentRegistry] componentRetryTime]);
291 [self _call:_methodName arguments:_params];
296 NSLog(@"%s: giving up....", __PRETTY_FUNCTION__);
299 [self setLastException:e];
300 [inv resetLastException]; /* do this to avoid retain cycles ! */
302 if ([e respondsToSelector:@selector(setInvocation:)])
303 [(id)e setInvocation:inv];
306 result = [inv returnValue];
309 result = [result retain];
312 return [result autorelease];
315 - (id)call:(NSString *)_methodName arguments:(NSArray *)_params {
316 return [self _call:_methodName arguments:_params];
319 - (id)asyncCall:(NSString *)_methodName arguments:(NSArray *)_args {
320 NSLog(@"%s: asyncCall(%@)", __PRETTY_FUNCTION__, _methodName);
321 return [self call:_methodName arguments:_args];
327 [self->signatureCache removeAllObjects];
332 - (void)encodeWithCoder:(NSCoder *)_coder {
333 [super encodeWithCoder:_coder];
334 [_coder encodeObject:self->httpConnection];
335 [_coder encodeObject:self->url];
337 - (id)initWithCoder:(NSCoder *)_coder {
338 if ((self = [super initWithCoder:_coder])) {
339 self->httpConnection = [[_coder decodeObject] retain];
340 self->url = [[_coder decodeObject] retain];
347 - (NSString *)description {
350 ms = [NSMutableString stringWithCapacity:64];
351 [ms appendFormat:@"<0x%08X[%@]: name=%@",
352 self, NSStringFromClass([self class]),
353 [self componentName]];
354 [ms appendFormat:@" url=%@", [self->url absoluteString]];
355 [ms appendString:@">"];
359 @end /* SxXmlRpcComponent */