]> err.no Git - sope/blob - sope-appserver/NGXmlRpc/NGXmlRpcAction+Registry.m
added strict OSX bundle dependencies
[sope] / sope-appserver / NGXmlRpc / NGXmlRpcAction+Registry.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
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
9   later version.
10
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.
15
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
19   02111-1307, USA.
20 */
21
22 #include <NGXmlRpc/NGXmlRpcAction.h>
23 #include "common.h"
24
25 @interface NGXmlRpcActionSelMapping : NSObject
26 {
27   NSMutableArray *signatures;
28   NSMutableArray *selectors;
29   unsigned count;
30 }
31
32 - (void)registerSelector:(SEL)_sel forSignature:(NSArray *)_signature;
33 - (SEL)selectorForSignature:(NSArray *)_signature;
34 - (NSArray *)signatures;
35
36 @end
37
38 @implementation NGXmlRpcActionSelMapping
39
40 static int logSelMapping = -1;
41
42 - (id)init {
43   if (logSelMapping == -1) {
44     logSelMapping = [[NSUserDefaults standardUserDefaults]
45                       boolForKey:@"WOLogXmlRpcSelectorMapping"]
46       ? 1 : 0;
47   }
48
49   self->signatures = [[NSMutableArray alloc] initWithCapacity:2];
50   self->selectors  = [[NSMutableArray alloc] initWithCapacity:2];
51   return self;
52 }
53 - (void)dealloc {
54   RELEASE(self->selectors);
55   RELEASE(self->signatures);
56   [super dealloc];
57 }
58
59 - (void)registerSelector:(SEL)_sel forSignature:(NSArray *)_signature {
60   [self->signatures addObject:_signature];
61   [self->selectors  addObject:NSStringFromSelector(_sel)];
62   self->count++;
63 }
64
65 - (BOOL)signature:(NSArray *)_base matches:(NSArray *)_query {
66   unsigned bc, qc;
67   
68   bc = [_base  count];
69   qc = [_query count];
70   if (bc != qc) return NO;
71   /* should check further */
72   return YES;
73 }
74 - (SEL)selectorForSignature:(NSArray *)_signature {
75   unsigned i;
76   
77   for (i = 0; i < self->count; i++) {
78     NSArray *sig;
79     
80     sig = [self->signatures objectAtIndex:i];
81     if ([self signature:sig matches:_signature])
82       return NSSelectorFromString([self->selectors objectAtIndex:i]);
83   }
84 #if DEBUG
85   if (self->count > 0) {
86     [self debugWithFormat:
87             @"found no signature matching argcount %i, signatures: %@, got: %@",
88             ([_signature count] - 1),
89             self->signatures, _signature];
90   }
91 #endif
92   return NULL;
93 }
94 - (NSArray *)signatures {
95   return self->signatures;
96 }
97
98 @end /* NGXmlRpcActionSelMapping */
99
100 @implementation NGXmlRpcAction(Registry)
101
102 /* class registry */
103
104 static NSMutableDictionary *uriToClass = nil;
105 static NSMutableDictionary *classToMethodDict = nil;
106
107 + (void)registerActionClass:(Class)_class forURI:(NSString *)_uri {
108   [(id<NSObject>)_class self]; /* ensure initialize */
109   if (uriToClass == nil)
110     uriToClass = [[NSMutableDictionary alloc] initWithCapacity:4];
111   [uriToClass setObject:_class forKey:_uri];
112   
113   NSLog(@"%s: mapped uri '%@' to class %@", __PRETTY_FUNCTION__,
114         _uri, NSStringFromClass(_class));
115 }
116 + (Class)actionClassForURI:(NSString *)_uri {
117   return [uriToClass objectForKey:_uri];
118 }
119
120 + (void)registerSelector:(SEL)_selector
121   forMethodNamed:(NSString *)_method
122   signature:(id)_signature
123 {
124   NSMutableDictionary      *md;
125   NGXmlRpcActionSelMapping *methodInfo;
126
127   if (![_signature isKindOfClass:[NSArray class]])
128     _signature = [[_signature stringValue] componentsSeparatedByString:@","];
129   
130   if (classToMethodDict == nil)
131     classToMethodDict = [[NSMutableDictionary alloc] initWithCapacity:4];
132   
133   if ((md = [classToMethodDict objectForKey:self]) == nil) {
134     md = [[NSMutableDictionary alloc] initWithCapacity:16];
135     [classToMethodDict setObject:md forKey:self];
136     RELEASE(md);
137   }
138
139   if ((methodInfo = [md objectForKey:_method]) == nil) {
140     methodInfo = [[NGXmlRpcActionSelMapping alloc] init];
141     [md setObject:methodInfo forKey:_method];
142     RELEASE(methodInfo);
143   }
144   
145   [methodInfo registerSelector:_selector forSignature:_signature];
146   
147   if (logSelMapping) {
148     NSLog(@"%@: registered selector %@ for method %@ %@",
149           NSStringFromClass(self),
150           NSStringFromSelector(_selector),
151           _method,
152           [_signature componentsJoinedByString:@","]);
153   }
154 }
155 + (SEL)selectorForActionNamed:(NSString *)_name
156   signature:(NSArray *)_signature
157 {
158   NSMutableDictionary      *methodDict;
159   NGXmlRpcActionSelMapping *methodInfo;
160   
161   if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
162     /* nothing registered */
163     return NULL;
164   
165   if ((methodInfo = [methodDict objectForKey:_name]) == nil)
166     /* no action with that name is registered */
167     return NULL;
168   
169   return [methodInfo selectorForSignature:_signature];
170 }
171
172 + (NSArray *)registeredMethodNames {
173   NSMutableDictionary *methodDict;
174   
175   if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
176     /* nothing registered */
177     return nil;
178   return [methodDict allKeys];
179 }
180 + (NSArray *)signaturesForMethodNamed:(NSString *)_name {
181   NSMutableDictionary      *methodDict;
182   NGXmlRpcActionSelMapping *methodInfo;
183   
184   if ((methodDict = [classToMethodDict objectForKey:self]) == nil)
185     /* nothing registered */
186     return NULL;
187   
188   if ((methodInfo = [methodDict objectForKey:_name]) == nil)
189     /* no action with that name is registered */
190     return NULL;
191   
192   return [methodInfo signatures];
193 }
194
195 /* mapping files */
196
197 + (BOOL)registerSystemMethods {
198   if ([self instancesRespondToSelector:@selector(system_listMethodsAction)]) {
199     [self registerSelector:@selector(system_listMethodsAction)
200           forMethodNamed:@"system.listMethods"
201           signature:[NSArray arrayWithObject:@"array"]];
202   }
203   else {
204     NSLog(@"WARNING(%s): class does not have a listMethods action !",
205           __PRETTY_FUNCTION__);
206   }
207   if ([self instancesRespondToSelector:
208               @selector(system_methodSignatureAction:)]) {
209     [self registerSelector:@selector(system_methodSignatureAction:)
210           forMethodNamed:@"system.methodSignature"
211           signature:[NSArray arrayWithObjects:@"array", @"string", nil]];
212   }
213   if ([self instancesRespondToSelector:
214               @selector(system_methodHelpAction:)]) {
215     [self registerSelector:@selector(system_methodHelpAction:)
216           forMethodNamed:@"system.methodHelp"
217           signature:[NSArray arrayWithObjects:@"string", @"string", nil]];
218   }
219   return YES;
220 }
221
222 + (BOOL)registerMappingsInFile:(NSString *)_path {
223   NSString     *path;
224   NSDictionary *cfg;
225   NSEnumerator *keys;
226   NSString     *methodName;
227   
228   if (![_path isAbsolutePath]) {
229     NSBundle *b;
230     
231     b = [NSBundle bundleForClass:self];
232     if ((path = [b pathForResource:_path ofType:@"plist"]) == nil)
233       path = _path;
234   }
235   else
236     path = _path;
237   
238   NSLog(@"%s: register mappings in file %@", __PRETTY_FUNCTION__, path);
239   
240   if ((cfg = [NSDictionary dictionaryWithContentsOfFile:path]) == nil) {
241     NSLog(@"%s:   could not load file %@", __PRETTY_FUNCTION__, path);
242     return NO;
243   }
244   
245   if (![self registerSystemMethods])
246     return NO;
247   
248   keys = [cfg keyEnumerator];
249   while ((methodName = [keys nextObject])) {
250     NSDictionary *mi;
251     NSEnumerator *sigs;
252     NSArray      *sig;
253     
254     if ([methodName hasPrefix:@"__"])
255       continue;
256     
257     mi = [cfg objectForKey:methodName];
258     if (![mi respondsToSelector:@selector(keyEnumerator)]) {
259       [self logWithFormat:@"entry '%@' in mapping file is no dictionary, skipping: %@", methodName, mi];
260       continue;
261     }
262     
263     sigs = [mi keyEnumerator];
264     while ((sig = [sigs nextObject])) {
265       NSString *selName;
266       SEL sel;
267       
268       selName = [mi objectForKey:sig];
269       
270       if ((sel = NSSelectorFromString(selName)) == NULL) {
271         NSLog(@"%s:  did not find selector '%@'", __PRETTY_FUNCTION__,
272               selName);
273         continue;
274       }
275       
276       if (![self instancesRespondToSelector:sel]) {
277         NSLog(@"WARNING(%s):  instances of %@ do not respond to selector '%@'",
278               __PRETTY_FUNCTION__, NSStringFromClass(self),
279               selName);
280       }
281       
282       [self registerSelector:sel
283             forMethodNamed:methodName
284             signature:sig];
285     }
286   }
287   return YES;
288 }
289
290 @end /* NGXmlRpcAction(Registry) */