]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOComponent+Sync.m
added support for complex davResourceTypes
[sope] / sope-appserver / NGObjWeb / WOComponent+Sync.m
1 /*
2   Copyright (C) 2000-2004 SKYRIX Software AG
3
4   This file is part of OpenGroupware.org.
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 <NGObjWeb/WOComponent.h>
24 #include <NGObjWeb/WOAssociation.h>
25 #include "common.h"
26
27 @implementation WOComponent(OptimizedSynching)
28
29 /*
30   optimized component synchronization. Uses extensive runtime caching.
31 */
32
33 static Class lastEnumClass = Nil;
34 static id (*nextKey)(id, SEL);
35 static Class lastWocDictClass = Nil;
36 static id (*wocObjForKey)(id, SEL, id);
37
38 #if NeXT_RUNTIME
39
40 #define CHK_ENUM_CACHE \
41   if (lastEnumClass != *(Class *)keys) {\
42     lastEnumClass = *(Class *)keys;\
43     nextKey = (void*)[keys methodForSelector:@selector(nextObject)];\
44   }
45
46 #define CHK_WOCDICT_CACHE \
47   if (lastWocDictClass != *(Class *)self->wocBindings) {\
48     lastWocDictClass = *(Class *)self->wocBindings;\
49     wocObjForKey = (void*)[self->wocBindings methodForSelector:@selector(objectForKey:)];\
50   }
51
52 #else
53
54 #define CHK_ENUM_CACHE \
55   if (lastEnumClass != *(Class *)keys) {\
56     lastEnumClass = *(Class *)keys;\
57     nextKey = (void*)\
58       method_get_imp(class_get_instance_method(*(Class *)keys, \
59         @selector(nextObject)));\
60   }
61
62 #define CHK_WOCDICT_CACHE \
63   if (lastWocDictClass != *(Class *)self->wocBindings) {\
64     lastWocDictClass = *(Class *)self->wocBindings;\
65     wocObjForKey = (void*)\
66       method_get_imp(class_get_instance_method(*(Class *)self->wocBindings, \
67         @selector(objectForKey:)));\
68   }
69
70 #endif
71
72 void WOComponent_syncFromParent(WOComponent *self, WOComponent *_parent) {
73   NSEnumerator *keys;
74   NSString     *key;
75   void (*takeValue)(id, SEL, id, NSString *);
76   
77   if ((keys = [self->wocBindings keyEnumerator]) == nil)
78     return;
79   
80   CHK_ENUM_CACHE;
81   CHK_WOCDICT_CACHE;
82 #if NeXT_RUNTIME
83   takeValue = (void *)[self methodForSelector:@selector(takeValue:forKey:)];
84 #else  
85   takeValue = (void*)method_get_imp(class_get_instance_method(self->isa,
86                 @selector(takeValue:forKey:)));
87 #endif
88   
89   while ((key = nextKey(keys, @selector(nextObject)))) {
90     static   Class lastAssocClass = Nil; // THREAD
91     static   id    (*valInComp)(id, SEL, WOComponent *);
92     register WOAssociation *binding;
93     register id value;
94     
95     binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
96     
97     if (*(Class *)binding != lastAssocClass) {
98       lastAssocClass = *(Class *)binding;
99 #if NeXT_RUNTIME
100       valInComp = (void *)
101         [binding methodForSelector:@selector(valueInComponent:)];
102 #else
103       valInComp = (void *)
104         method_get_imp(class_get_instance_method(*(Class *)binding,
105           @selector(valueInComponent:)));
106 #endif
107     }
108     
109     // TODO: this is somewhat inefficient because -valueInComponent: does
110     //       value=>object coercion and then takeValue:forKey: does the
111     //       reverse coercion. We could improve performance for base values
112     //       if we implement takeValue:forKey: on our own and just pass over
113     //       the raw value (ie [self setIntA:[assoc intValueComponent:self]])
114     
115     value = valInComp(binding, @selector(valueInComponent:), _parent);
116
117     // TODO: this is a bit problematic in bool contexts if the input
118     //       parameter is a string because ObjC doesn't know about bool
119     //       and will evaluate the string as a char value
120     //       (this is common if you use const:mykey="YES" in WOx)
121     takeValue(self, @selector(takeValue:forKey:), value, key);
122   }
123 }
124
125 void WOComponent_syncToParent(WOComponent *self, WOComponent *_parent) {
126   NSEnumerator *keys;
127   NSString     *key;
128   id (*getValue)(id, SEL, NSString *);
129   
130   if ((keys = [self->wocBindings keyEnumerator]) == nil)
131     return;
132   
133   CHK_ENUM_CACHE;
134   CHK_WOCDICT_CACHE;
135
136 #if NeXT_RUNTIME
137   getValue = (void *)[self methodForSelector:@selector(valueForKey:)];
138 #else
139   getValue = (void*)method_get_imp(class_get_instance_method(self->isa,
140                 @selector(valueForKey:)));
141 #endif
142   
143   while ((key = nextKey(keys, @selector(nextObject)))) {
144     static   Class lastAssocClass = Nil;
145     static   BOOL  (*isSettable)(id, SEL);
146     static   void  (*setValInComp)(id, SEL, id, WOComponent *);
147     register WOAssociation *binding;
148     register id value;
149     
150     binding = wocObjForKey(self->wocBindings, @selector(objectForKey:), key);
151
152     if (*(Class *)binding != lastAssocClass) {
153       lastAssocClass = *(Class *)binding;
154
155 #if NeXT_RUNTIME
156       isSettable   = 
157         (void*)[binding methodForSelector:@selector(isValueSettable)];
158       setValInComp = 
159         (void*)[binding methodForSelector:@selector(setValue:inComponent:)];
160 #else
161       isSettable = (void*)
162         method_get_imp(class_get_instance_method(*(Class *)binding,
163           @selector(isValueSettable)));
164       setValInComp = (void*)
165         method_get_imp(class_get_instance_method(*(Class *)binding,
166           @selector(setValue:inComponent:)));
167 #endif
168     }
169     
170     if (!isSettable(binding, @selector(isValueSettable)))
171       continue;
172     
173     value = getValue(self, @selector(valueForKey:), key);
174     
175     setValInComp(binding, @selector(setValue:inComponent:), value, _parent);
176   }
177 }
178
179 @end /* WOComponent(OptimizedSynching) */