]> err.no Git - sope/blob - sope-appserver/NGObjWeb/Associations/WOAssociation.m
use %p for pointer formats, fixed gcc 4.1 warnings, minor code improvs
[sope] / sope-appserver / NGObjWeb / Associations / WOAssociation.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 <NGObjWeb/WOAssociation.h>
23 #include "WOValueAssociation.h"
24 #include "WOKeyPathAssociation.h"
25 #include <NGObjWeb/WOApplication.h>
26 #include <NGObjWeb/WOContext.h>
27 #include "common.h"
28
29 @interface WOContext(Cursor)
30 - (id)cursor;
31 @end
32
33 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || \
34     COCOA_Foundation_LIBRARY
35 @interface NSObject(Missing)
36 - (void)subclassResponsibility:(SEL)cmd;
37 - (void)notImplemented:(SEL)cmd;
38 @end
39 #endif
40
41 @implementation WOAssociation
42
43 static Class WOKeyPathAssociationClass = Nil;
44
45 + (int)version {
46   return 2;
47 }
48
49 + (void)initialize {
50   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
51   NSString *s;
52   static BOOL didInit = NO;
53   if (didInit) return;
54   didInit = YES;
55   
56   s = [ud stringForKey:@"WOKeyPathAssociationClass"];
57   if ([s length] > 0) {
58 #if DEBUG
59     NSLog(@"Note: using different class for keypath associations: %@", s);
60 #endif
61     WOKeyPathAssociationClass = NSClassFromString(s);
62   }
63   if (WOKeyPathAssociationClass == Nil)
64     WOKeyPathAssociationClass = [WOKeyPathAssociation class];
65 }
66
67 + (WOAssociation *)associationWithKeyPath:(NSString *)_keyPath {
68   static int WOCacheKeyPathAssociations = -1;
69   static NSMapTable *cache = NULL;
70   static unsigned cacheHits   = 0;
71   static unsigned cacheMisses = 0;
72   WOAssociation *a;
73   
74   if (WOCacheKeyPathAssociations == -1) {
75     WOCacheKeyPathAssociations =
76       [[[NSUserDefaults standardUserDefaults]
77                         objectForKey:@"WOKeyPathAssociationsCacheSize"]
78                         intValue];
79     if (WOCacheKeyPathAssociations > 0) {
80       cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
81                                NSObjectMapValueCallBacks,
82                                WOCacheKeyPathAssociations);
83     }
84   }
85
86   if (cache) {
87     if ((a = NSMapGet(cache, _keyPath))) {
88       cacheHits++;
89 #if 0 && DEBUG
90       printf("%s: cache hits: %d, misses: %d, size:%d\n",
91              __PRETTY_FUNCTION__,
92              cacheHits, cacheMisses, NSCountMapTable(cache));
93 #endif
94       return [[a retain] autorelease];
95     }
96     
97     cacheMisses++;
98     
99     if (cacheMisses > 1000) {
100       if (cacheHits < cacheMisses) {
101         fprintf(stderr,
102                 "%s: disabling association cache "
103                 "(%d cache misses vs %d cache hits)\n",
104                 __PRETTY_FUNCTION__, cacheMisses, cacheHits);
105         if (cache) NSFreeMapTable(cache);
106         cache = NULL;
107       }
108     }
109   }
110   
111   a = [[WOKeyPathAssociationClass alloc] initWithKeyPath:_keyPath];
112   
113   if (cache)
114     NSMapInsert(cache, _keyPath, a);
115   
116   return [a autorelease];
117 }
118 + (WOAssociation *)associationWithValue:(id)_value {
119   static int        WOCacheValueAssociations   = -1;
120   static NSMapTable *cache = NULL;
121   static unsigned   cacheHits   = 0;
122   static unsigned   cacheMisses = 0;
123   static NSNumber   *boolYes    = nil;
124   static NSNumber   *boolNo     = nil;
125   WOAssociation *a;
126   
127   if (_value == nil) return nil;
128   
129   if (boolYes == nil)
130     boolYes = [[NSNumber numberWithBool:YES] retain];
131   if (boolNo == nil)
132     boolNo = [[NSNumber numberWithBool:NO] retain];
133   
134   if (boolYes == _value) {
135     static WOAssociation *yesAssoc = nil;
136     
137     if (yesAssoc == nil)
138       yesAssoc = [[_WOBoolValueAssociation associationWithBool:YES] retain];
139     
140     return yesAssoc;
141   }
142   if (boolNo == _value) {
143     static WOAssociation *noAssoc = nil;
144     
145     if (noAssoc == nil)
146       noAssoc = [[_WOBoolValueAssociation associationWithBool:NO] retain];
147     
148     return noAssoc;
149   }
150   
151   if (![_value conformsToProtocol:@protocol(NSCopying)])
152     /* if the value can't be copied, it shouldn't be cached ! */
153     return [WOValueAssociation associationWithValue:_value];
154   
155   _value = [[_value copyWithZone:NULL] autorelease];
156   
157   if (WOCacheValueAssociations == -1) {
158     WOCacheValueAssociations =
159       [[[NSUserDefaults standardUserDefaults]
160                         objectForKey:@"WOValueAssociationsCacheSize"]
161                         intValue];
162     if (WOCacheValueAssociations > 0) {
163       cache = NSCreateMapTable(NSObjectMapKeyCallBacks,
164                                NSObjectMapValueCallBacks,
165                                WOCacheValueAssociations);
166     }
167   }
168
169   if (cache) {
170     if ((a = NSMapGet(cache, _value))) {
171       cacheHits++;
172 #if 0 && DEBUG
173       printf("%s: cache hits: %d, misses: %d, size:%d\n",
174              __PRETTY_FUNCTION__,
175              cacheHits, cacheMisses, NSCountMapTable(cache));
176 #endif
177       return [[a retain] autorelease];
178     }
179     
180     cacheMisses++;
181     
182     if (cacheMisses > 1000) {
183       if (cacheHits < cacheMisses) {
184         fprintf(stderr,
185                 "%s: disabling association cache "
186                 "(%d cache misses vs %d cache hits)",
187                 __PRETTY_FUNCTION__, cacheMisses, cacheHits);
188         if (cache) NSFreeMapTable(cache);
189         cache = NULL;
190       }
191     }
192   }
193   
194   a = [WOValueAssociation associationWithValue:_value];
195   
196   if (cache != NULL)
197     NSMapInsert(cache, _value, a);
198   
199   return a;
200 }
201
202 /* value */
203
204 - (void)setValue:(id)_value {
205   IS_DEPRECATED;
206   [self setValue:_value
207         inComponent:[[[WOApplication application] context] component]];
208 }
209 - (id)value {
210   IS_DEPRECATED;
211   return [self valueInComponent:
212                  [[[WOApplication application] context] component]];
213 }
214
215 - (void)setValue:(id)_value inComponent:(WOComponent *)_component {
216   [self subclassResponsibility:_cmd];
217 }
218 - (id)valueInComponent:(WOComponent *)_component {
219   [self subclassResponsibility:_cmd];
220   return nil;
221 }
222
223 - (void)setValue:(id)_value inContext:(WOContext *)_ctx {
224   [self setValue:_value inComponent:(id)[_ctx cursor]];
225 }
226 - (id)valueInContext:(WOContext *)_ctx {
227   return [self valueInComponent:(id)[_ctx cursor]];
228 }
229
230 - (BOOL)isValueConstant {
231   [self subclassResponsibility:_cmd];
232   return NO;
233 }
234 - (BOOL)isValueSettable {
235   [self subclassResponsibility:_cmd];
236   return NO;
237 }
238
239 /* description */
240
241 - (NSString *)description {
242   return [NSString stringWithFormat:@"<0x%p[%@]>", 
243                    self, NSStringFromClass([self class])];
244 }
245
246 /* special values */
247
248 - (void)setUnsignedCharValue:(unsigned char)_v inComponent:(WOComponent *)_c {
249   [self setValue:[NSNumber numberWithUnsignedChar:_v] inComponent:_c];
250 }
251 - (void)setCharValue:(signed char)_val inComponent:(WOComponent *)_component {
252   [self setValue:[NSNumber numberWithChar:_val] inComponent:_component];
253 }
254 - (void)setUnsignedIntValue:(unsigned int)_v inComponent:(WOComponent *)_c {
255   [self setValue:[NSNumber numberWithUnsignedInt:_v] inComponent:_c];
256 }
257 - (void)setIntValue:(signed int)_value inComponent:(WOComponent *)_component {
258   [self setValue:[NSNumber numberWithInt:_value] inComponent:_component];
259 }
260 - (void)setBoolValue:(BOOL)_value inComponent:(WOComponent *)_component {
261   [self setValue:[NSNumber numberWithBool:_value] inComponent:_component];
262 }
263
264 - (unsigned char)unsignedCharValueInComponent:(WOComponent *)_component {
265   return [[self valueInComponent:_component] unsignedCharValue];
266 }
267 - (signed char)charValueInComponent:(WOComponent *)_component {
268   return [(id<NGBaseTypeValues>)[self valueInComponent:_component] charValue];
269 }
270 - (unsigned int)unsignedIntValueInComponent:(WOComponent *)_component {
271   return [[self valueInComponent:_component] unsignedIntValue];
272 }
273 - (signed int)intValueInComponent:(WOComponent *)_component {
274   return [[self valueInComponent:_component] intValue];
275 }
276 - (BOOL)boolValueInComponent:(WOComponent *)_component {
277   return [[self valueInComponent:_component] boolValue];
278 }
279
280 - (void)setStringValue:(NSString *)_v inComponent:(WOComponent *)_component {
281   [self setValue:_v inComponent:_component];
282 }
283 - (NSString *)stringValueInComponent:(WOComponent *)_component {
284   return [[self valueInComponent:_component] stringValue];
285 }
286
287 /* special context values */
288
289 - (void)setUnsignedCharValue:(unsigned char)_v inContext:(WOContext *)_c {
290   [self setUnsignedCharValue:_v inComponent:(id)[_c cursor]];
291 }
292 - (void)setCharValue:(signed char)_value inContext:(WOContext *)_ctx {
293   [self setCharValue:_value inComponent:(id)[_ctx cursor]];
294 }
295 - (void)setUnsignedIntValue:(unsigned int)_v inContext:(WOContext *)_c {
296   [self setUnsignedIntValue:_v inComponent:(id)[_c cursor]];
297 }
298 - (void)setIntValue:(signed int)_value inContext:(WOContext *)_ctx {
299   [self setIntValue:_value inComponent:(id)[_ctx cursor]];
300 }
301 - (void)setBoolValue:(BOOL)_value inContext:(WOContext *)_ctx {
302   [self setBoolValue:_value inComponent:(id)[_ctx cursor]];
303 }
304
305 - (unsigned char)unsignedCharValueInContext:(WOContext *)_ctx {
306   return [self unsignedCharValueInComponent:[_ctx cursor]];
307 }
308 - (signed char)charValueInContext:(WOContext *)_ctx {
309   return [self charValueInComponent:[_ctx cursor]];
310 }
311 - (unsigned int)unsignedIntValueInContext:(WOContext *)_ctx {
312   return [self unsignedIntValueInComponent:[_ctx cursor]];
313 }
314 - (signed int)intValueInContext:(WOContext *)_ctx {
315   return [self intValueInComponent:[_ctx cursor]];
316 }
317 - (BOOL)boolValueInContext:(WOContext *)_ctx {
318   return [self boolValueInComponent:[_ctx cursor]];
319 }
320
321 - (void)setStringValue:(NSString *)_v inContext:(WOContext *)_ctx {
322   [self setValue:_v inComponent:[_ctx cursor]];
323 }
324 - (NSString *)stringValueInContext:(WOContext *)_ctx {
325   return [[self valueInComponent:(id)[_ctx cursor]] stringValue];
326 }
327
328 /* copying */
329
330 - (id)copyWithZone:(NSZone *)_zone {
331   // WOAssociations are immutable
332   return [self retain];
333 }
334
335 /* BugTrap */
336
337 - (unsigned int)unsignedIntValue {
338   [self notImplemented:_cmd];
339   return 0;
340 }
341 - (signed int)intValue {
342   [self notImplemented:_cmd];
343   return 0;
344 }
345 - (float)floatValue {
346   [self notImplemented:_cmd];
347   return 0.0;
348 }
349 - (BOOL)boolValue {
350   [self notImplemented:_cmd];
351   return NO;
352 }
353
354 - (NSString *)stringValue {
355   [self notImplemented:_cmd];
356   return nil;
357 }
358
359 @end /* WOAssociation */