]> err.no Git - sope/blob - Recycler/SxComponents/SxComponentInvocation.m
use %p for pointer formats
[sope] / Recycler / SxComponents / SxComponentInvocation.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 "SxComponentInvocation.h"
24 #include "SxComponentMethodSignature.h"
25 #include "SxComponent.h"
26 #include <NGExtensions/NSString+Ext.h>
27 #include "common.h"
28
29 @implementation SxComponentInvocation
30
31 static NSNull *null = nil;
32
33 + (int)version {
34   return 1;
35 }
36
37 - (void)_ensureArgs {
38   unsigned i, count;
39
40   if (self->arguments) return;
41   if (self->signature == nil) return;
42   if (null == nil) null = [[NSNull null] retain];
43
44   count = [self->signature numberOfArguments];
45   
46   self->arguments = [[NSMutableArray alloc] initWithCapacity:count];
47   for (i = 0; i < count; i++)
48     [self->arguments addObject:null];
49 }
50
51 - (id)initWithMethodSignature:(id)_sig {
52   if (_sig == nil) {
53     [self release];
54     return nil;
55   }
56
57   self->signature = [_sig retain];
58   [self _ensureArgs];
59   
60   return self;
61 }
62 - (id)init {
63   return [self initWithMethodSignature:nil];
64 }
65 - (id)initWithComponent:(SxComponent *)_component
66   methodName:(NSString *)_method
67   signature:(SxComponentMethodSignature *)_signature
68 {
69   if ((self = [self initWithMethodSignature:_signature])) {
70     self->methodName = [_method    copy];
71     self->target     = [_component retain];
72   }
73   return self;
74 }
75
76 - (void)dealloc {
77   [self->credentials   release];
78   [self->lastException release];
79   [self->arguments     release];
80   [self->result        release];
81   [self->target        release];
82   [self->methodName    release];
83   [self->signature     release];
84   [super dealloc];
85 }
86
87 /* arguments */
88
89 - (SxComponentMethodSignature *)methodSignature {
90   return self->signature;
91 }
92
93 - (void)setArgument:(id)_argument atIndex:(int)_idx {
94   if (_argument == nil) _argument = null;
95   [self->arguments replaceObjectAtIndex:_idx withObject:_argument];
96 }
97 - (id)argumentAtIndex:(int)_idx {
98   id res;
99   
100   res = [self->arguments objectAtIndex:_idx];
101   if (res == null) res = nil;
102   return res;
103 }
104 - (void)setArguments:(NSArray *)_args {
105   NSAssert2(([self->signature numberOfArguments] == [_args count]),
106             @"arg count mismatch (%i expected, got %i)",
107             [self->signature numberOfArguments],
108             [_args count]);
109   
110   [self->arguments removeAllObjects];
111   [self->arguments addObjectsFromArray:_args];
112 }
113 - (NSArray *)arguments {
114   return [[self->arguments copy] autorelease];
115 }
116
117 - (BOOL)argumentsRetained {
118   return YES;
119 }
120
121 - (void)setTarget:(SxComponent *)_target {
122   ASSIGN(self->target, _target);
123 }
124 - (SxComponent *)target {
125   return self->target;
126 }
127
128 - (void)setMethodName:(NSString *)_name {
129   ASSIGNCOPY(self->methodName, _name);
130 }
131 - (NSString *)methodName {
132   return self->methodName;
133 }
134
135 - (void)setReturnValue:(id)_result {
136   ASSIGN(self->result, _result);
137 }
138 - (id)returnValue {
139   return self->result;
140 }
141
142 - (void)setLastException:(NSException *)_exception {
143   ASSIGN(self->lastException, _exception);
144 }
145
146 - (NSException *)lastException {
147   return self->lastException;
148 }
149 - (BOOL)lastCallFailed {
150   return self->lastException != nil ? YES : NO;
151 }
152 - (void)resetLastException {
153   ASSIGN(self->lastException, (id)nil);
154 }
155
156 /* credentials */
157
158 - (void)setCredentials:(id)_credentials {
159   ASSIGN(self->credentials, _credentials);
160 }
161 - (id)credentials {
162   return self->credentials;
163 }
164
165 /* Dispatching an Invocation */
166
167 - (NSArray *)argumentsForCall {
168   return self->arguments;
169 }
170
171 - (id)_call:(NSString *)_methodName
172   onTarget:(SxComponent *)_target
173   arguments:(NSArray *)_params
174 {
175   return [_target call:_methodName arguments:_params];
176 }
177 - (BOOL)_asyncCall:(NSString *)_methodName
178   onTarget:(SxComponent *)_target
179   arguments:(NSArray *)_params
180 {
181   return [_target asyncCall:_methodName arguments:_params] ? YES : NO;
182 }
183
184 - (BOOL)invokeWithTarget:(SxComponent *)_target {
185   NSAutoreleasePool *pool;
186   BOOL ok;
187   
188   pool = [[NSAutoreleasePool alloc] init];
189   {
190     NSArray *args;
191     id res;
192
193     /* reset state */
194     [self->lastException release]; self->lastException = nil;
195     [self->result        release]; self->result = nil;
196     
197     /* get arguments */
198     args = [self argumentsForCall];
199     
200     /* invoke remote method */
201     res = [self _call:[self methodName] onTarget:_target arguments:args];
202     
203     /* check for errors */
204     
205     if (self->lastException) {
206       ok = NO;
207       [self setReturnValue:nil];
208     }
209     else {
210       /* store return value */
211       [self setReturnValue:res];
212       ok = YES;
213     }
214   }
215   [pool release];
216
217   return ok;
218 }
219 - (BOOL)invoke {
220   return [self invokeWithTarget:[self target]];
221 }
222
223 /* asynchronous */
224
225 - (void)asyncResultReady:(NSNotification *)_notification {
226   id proxy;
227   
228   if (self->result != [_notification object]) {
229     NSLog(@"%s: WARNING, got an invalid aync result notification: %@",
230           __PRETTY_FUNCTION__, _notification);
231     return;
232   }
233
234   proxy = [self->result retain];
235   [self->result release]; self->result = nil;
236   
237   if ([proxy asyncCallFailed]) {
238     self->lastException = [[proxy asyncResult] retain];
239     [self setReturnValue:nil];
240   }
241   else
242     [self setReturnValue:[proxy asyncResult]];
243   
244   [proxy release]; proxy = nil;
245   
246   [[self->target notificationCenter]
247                  postNotificationName:SxAsyncResultReadyNotificationName
248                  object:self];
249 }
250
251 - (BOOL)asyncInvoke {
252   NSAutoreleasePool *pool;
253   BOOL ok;
254   
255   pool = [[NSAutoreleasePool alloc] init];
256   {
257     NSArray *args;
258     id res;
259
260     /* reset state */
261     [self->lastException release]; self->lastException = nil;
262     [self->result        release]; self->result = nil;
263     
264     /* get arguments */
265     args = [self argumentsForCall];
266     
267     /* invoke remote method */
268     
269     res = [self->target asyncCall:[self methodName] arguments:args];
270     
271     if (![res isAsyncResultPending]) {
272       /* result is ready :-) */
273       
274       /* check for errors */
275       if ([self->target lastCallFailed]) {
276         self->lastException = [res retain];
277         [self setReturnValue:nil];
278         ok = NO;
279       }
280       else {
281         /* store return value */
282         [self setReturnValue:res];
283         ok = YES;
284       }
285     }
286     else {
287       /* result isn't ready yet, register for notification */
288       ok = YES;
289       self->result = [res retain];
290       
291       [[self->target notificationCenter]
292                      addObserver:self selector:@selector(asyncResultReady:)
293                      name:SxAsyncResultReadyNotificationName
294                      object:self->result];
295     }
296   }
297   [pool release];
298   
299   return ok;
300 }
301
302 - (BOOL)isAsyncResultPending {
303   return [self->result isAsyncResultPending];
304 }
305
306 /* NSCoding */
307
308 - (void)encodeWithCoder:(NSCoder *)_coder {
309   [_coder encodeObject:self->target];
310   [_coder encodeObject:self->methodName];
311   [_coder encodeObject:self->signature];
312   [_coder encodeObject:self->arguments];
313   [_coder encodeObject:self->result];
314   [_coder encodeObject:self->lastException];
315 }
316 - (id)initWithCoder:(NSCoder *)_coder {
317   if (null == nil) null = [[NSNull null] retain];
318   
319   self->target        = [[_coder decodeObject] retain];
320   self->methodName    = [[_coder decodeObject] copy];
321   self->signature     = [[_coder decodeObject] retain];
322   self->arguments     = [[_coder decodeObject] retain];
323   self->result        = [[_coder decodeObject] retain];
324   self->lastException = [[_coder decodeObject] retain];
325   
326   if (self->signature == nil) {
327     NSLog(@"%s: missing signature (required during decoding)",
328           __PRETTY_FUNCTION__);
329     [self release];
330     return nil;
331   }
332   [self _ensureArgs];
333   
334   return self;
335 }
336
337 /* KVC */
338
339 /* access the arguments with key "arg<element position>"
340    e.g. 'arg0' for the first element
341 */
342
343 - (int)_indexForKey:(NSString *)_key {
344   NSString *prefix;
345
346   prefix = @"arg";
347   
348   if(![_key hasPrefix:prefix])
349     return -1;
350   
351   return [[_key substringFromIndex:[prefix length]] intValue];
352 }
353
354 - (void)takeValue:(id)_value forKey:(NSString *)_key {
355   int index;
356
357   if ((index = [self _indexForKey:_key]) != -1)
358     [self setArgument:_value atIndex:index];
359 }
360
361 - (id)valueForKey:(NSString *)_key {
362   int index;
363
364   if ((index = [self _indexForKey:_key]) != -1)
365     return [self argumentAtIndex:index];
366
367   return nil;
368 }
369
370 /* description */
371
372 - (NSString *)description {
373   NSMutableString *ms;
374   
375   ms = [NSMutableString stringWithCapacity:128];
376   [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
377   [ms appendFormat:@" %@", self->methodName];
378   if (self->arguments)
379     [ms appendFormat:@" #args=%i", [self->arguments count]];
380   else
381     [ms appendString:@" no-args"];
382   if (self->lastException)
383     [ms appendString:@" exception-is-set"];
384   if (self->result)
385     [ms appendString:@" result-is-set"];
386   if (self->signature == nil)
387     [ms appendString:@" no-signature"];
388   else {
389     [ms appendFormat:@" signature=%@",
390           [[self->signature xmlRpcTypes]
391                             componentsJoinedByString:@","]];
392     if ([self->signature isOneway])
393       [ms appendString:@" oneway"];
394   }
395   [ms appendString:@">"];
396   return ms;
397 }
398
399 @end /* SxComponentInvocation */