]> err.no Git - sope/blob - Recycler/SxComponents/SxXmlRpcComponent.m
use %p for pointer formats
[sope] / Recycler / SxComponents / SxXmlRpcComponent.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 "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>
34 #include "common.h"
35
36 #include <unistd.h>
37
38 @interface SxComponentRegistry(RemoveComponentFromCache)
39 - (void)_removeComponentFromLookupCache:(NSString *)_cname;
40 @end /* SxComponentRegistry(RemoveComponentFromCache) */
41
42 @interface SxXmlRpcComponent(Privates)
43
44 /* this method doesn't prepend component name ... */
45 - (id)_call:(NSString *)_methodName arguments:(NSArray *)_params;
46
47 @end
48
49 @implementation SxXmlRpcComponent
50
51 + (int)version {
52   return [super version] + 0 /* v1 */;
53 }
54 + (void)initialize {
55   NSAssert2([super version] == 1,
56             @"invalid superclass (%@) version %i !",
57             NSStringFromClass([self superclass]), [super version]);
58 }
59
60 - (id)initWithName:(NSString *)_name
61   registry:(SxComponentRegistry *)_registry
62   url:(NSURL *)_url
63 {
64   return [self initWithName:_name
65                namespace:[[_name componentsSeparatedByString:@"."] lastObject]
66                registry:_registry
67                url:_url];
68 }
69
70 - (id)initWithName:(NSString *)_name
71   namespace:(NSString *)_namespace
72   registry:(SxComponentRegistry *)_registry
73   url:(NSURL *)_url
74 {
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]];
81
82     self->retryCnt = 0;
83   }
84   return self;
85 }
86
87 - (void)dealloc {
88   [self->lastCredentials release];
89   [self->signatureCache  release];
90   [self->httpConnection  release];
91   [self->url             release];
92   [super dealloc];
93 }
94
95 /* accessors */
96
97 - (NSString *)uri {
98   return [self->url path];
99 }
100
101 - (WOHTTPConnection *)httpConnection {
102   return self->httpConnection;
103 }
104
105 - (NSURL *)url {
106   return self->url;
107 }
108
109 - (void)addSuccessfulCredentials:(id)_creds {
110   ASSIGN(self->lastCredentials, _creds);
111 }
112
113 - (NSString *)fqMethodNameForMethod:(NSString *)_method {
114   NSString *ns;
115
116   if (![_method hasPrefix:@"system."]) {
117     if ((ns = [self namespace]) != nil) {
118       return [[ns stringByAppendingString:@"."]
119                   stringByAppendingString:_method];
120     }
121   }
122   return _method;
123 }
124
125 /* operations */
126
127 - (Class)invocationClass {
128   static Class CompInv = Nil;
129   if (CompInv == Nil) CompInv = [SxXmlRpcInvocation class];
130   return CompInv;
131 }
132
133 - (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
134   methodSignature:(SxComponentMethodSignature *)_signature
135 {
136   /*
137     Overridden to add the last successful credentials to newly created
138     invocation objects.
139   */
140   SxComponentInvocation *inv;
141   
142   inv = [super invocationForMethodNamed:_method
143                methodSignature:_signature];
144   [inv setCredentials:self->lastCredentials];
145   return inv;
146 }
147
148 - (NSArray *)signaturesForMethodNamed:(NSString *)_method {
149   NSMutableArray *result;
150   NSArray        *signatures;
151   NSString       *fqMethodName;
152   int i;
153   
154   [self resetLastException];
155   
156   if ([_method length] == 0)
157     return nil;
158   
159   if ((signatures = [self->signatureCache objectForKey:_method]))
160     return [signatures isNotNull] ? signatures : (NSArray *)nil;
161
162   fqMethodName = [self fqMethodNameForMethod:_method];
163
164   signatures = [self _call:@"system.methodSignature"
165                      arguments:[NSArray arrayWithObject:fqMethodName]];
166   
167   if ([self lastCallFailed]) {
168     NSException *e;
169     
170     e = [self lastException];
171     [self logWithFormat:@"%s: couldn't get method signature:\n"
172             @"  method: %@\n"
173             @"  name:   %@ (class=%@)\n"
174             @"  reason: %@",
175             __PRETTY_FUNCTION__, _method,
176             NSStringFromClass([e class]), [e name], [e reason]];
177     return nil;
178   }
179   
180   if (![signatures isKindOfClass:[NSArray class]]) {
181     NSException *e;
182     
183     e = [NSException exceptionWithName:@"InvalidXmlRpcResult"
184                      reason:@"system.methodSignature did not return an array"
185                      userInfo:nil];
186     
187     [self logWithFormat:
188             @"system.methodSignature didn't return an array: '%@'<%@>",
189             signatures, NSStringFromClass([signatures class])];
190     
191     if (e) [self setLastException:e];
192     signatures = nil;
193     return nil;
194   }
195   
196   result = [NSMutableArray arrayWithCapacity:[signatures count]];
197   
198   for (i = 0; i < [signatures count]; i++) {
199     SxComponentMethodSignature *signature;
200     NSArray *bsig;
201     
202     bsig = [signatures objectAtIndex:i];
203     signature = [SxComponentMethodSignature signatureWithXmlRpcTypes:bsig];
204     [result addObject:signature];
205   }
206   
207   if (self->signatureCache == nil)
208     self->signatureCache = [[NSMutableDictionary alloc] initWithCapacity:32];
209   
210   [self->signatureCache
211        setObject:(result ? result : (NSMutableArray *)[NSNull null])
212        forKey:_method];
213   
214   return result;
215 }
216
217 - (SxComponentInvocation *)invocationForMethodNamed:(NSString *)_method
218   arguments:(NSArray *)_args
219 {
220   static NSArray *retType = nil;
221   SxComponentMethodSignature *sig;
222   SxXmlRpcInvocation *inv;
223   NSArray *xsig;
224   
225   if (retType == nil)
226     retType = [[NSArray alloc] initWithObjects:@"string", nil];
227   
228   xsig = [retType arrayByAddingObjectsFromArray:
229                     [_args xmlRpcElementSignature]];
230   sig = [[SxComponentMethodSignature alloc] initWithXmlRpcTypes:xsig];
231   
232   inv = (id)[self invocationForMethodNamed:_method
233                   methodSignature:sig];
234   [inv setArguments:_args];
235   
236   RELEASE(sig);
237   
238   return inv;
239 }
240
241 - (id)_call:(NSString *)_methodName arguments:(NSArray *)_params {
242   SxComponentInvocation *inv;
243   NSAutoreleasePool *pool;
244   NSException *e;
245   id result;
246   
247   pool = [[NSAutoreleasePool alloc] init];
248   [self resetLastException];
249
250   inv = [self invocationForMethodNamed:_methodName
251               arguments:_params];
252   
253   /* TODO: hh: invoke does not work yet fully, returns true on fail ... */
254   [inv invoke];
255   
256   if ((e = [inv lastException])) {
257     int retries;
258
259     retries = [[self componentRegistry] componentRetryCountOnError];
260
261     if (self->retryCnt < retries) {
262       if ([e isKindOfClass:[NGCouldNotConnectException class]]) {
263         SxXmlRpcComponent *tmpComp;
264         id compRegistry;
265
266         compRegistry = [self componentRegistry];
267         
268         [compRegistry _removeComponentFromLookupCache:[self componentName]];
269         tmpComp = (SxXmlRpcComponent *)
270           [compRegistry getComponent:[self componentName]];
271         
272         if (tmpComp) {
273           NSURL *tmpUrl;
274         
275           tmpUrl = [tmpComp url];
276         
277           [self->url            release]; self->url            = nil;
278           [self->httpConnection release]; self->httpConnection = nil;
279
280           self->url = RETAIN(tmpUrl);
281
282           self->httpConnection =
283             [[WOHTTPConnection alloc] initWithHost:[tmpUrl host]
284                                       onPort:[[tmpUrl port] intValue]];
285
286           NSLog(@"%s: trying once again (%d)....", __PRETTY_FUNCTION__,
287                 self->retryCnt);
288
289           sleep(self->retryCnt*[[self componentRegistry] componentRetryTime]);
290           self->retryCnt++;
291           [self _call:_methodName arguments:_params];
292         }
293       }
294     }
295     else {
296       NSLog(@"%s: giving up....", __PRETTY_FUNCTION__);
297     }
298     
299     [self setLastException:e];
300     [inv resetLastException]; /* do this to avoid retain cycles ! */
301     
302     if ([e respondsToSelector:@selector(setInvocation:)])
303       [(id)e setInvocation:inv];
304   }
305
306   result = [inv returnValue];
307   self->retryCnt = 0;
308   
309   result = [result retain];
310   [pool release];
311   
312   return [result autorelease];
313 }
314
315 - (id)call:(NSString *)_methodName arguments:(NSArray *)_params {
316   return [self _call:_methodName arguments:_params];
317 }
318
319 - (id)asyncCall:(NSString *)_methodName arguments:(NSArray *)_args {
320   NSLog(@"%s: asyncCall(%@)", __PRETTY_FUNCTION__, _methodName);
321   return [self call:_methodName arguments:_args];
322 }
323
324 /* caching */
325
326 - (void)flush {
327   [self->signatureCache removeAllObjects];
328 }
329
330 /* NSCoding */
331
332 - (void)encodeWithCoder:(NSCoder *)_coder {
333   [super encodeWithCoder:_coder];
334   [_coder encodeObject:self->httpConnection];
335   [_coder encodeObject:self->url];
336 }
337 - (id)initWithCoder:(NSCoder *)_coder {
338   if ((self = [super initWithCoder:_coder])) {
339     self->httpConnection = [[_coder decodeObject] retain];
340     self->url            = [[_coder decodeObject] retain];
341   }
342   return self;
343 }
344
345 /* description */
346
347 - (NSString *)description {
348   NSMutableString *ms;
349
350   ms = [NSMutableString stringWithCapacity:64];
351   [ms appendFormat:@"<0x%p[%@]: name=%@",
352         self, NSStringFromClass([self class]),
353         [self componentName]];
354   [ms appendFormat:@" url=%@", [self->url absoluteString]];
355   [ms appendString:@">"];
356   return ms;
357 }
358
359 @end /* SxXmlRpcComponent */