]> err.no Git - sope/blob - sope-appserver/WEExtensions/WESwitch.m
added strict OSX bundle dependencies
[sope] / sope-appserver / WEExtensions / WESwitch.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 /*
23   WESwitch      { selection | selections };
24   WECase        { key | keys };
25   WEDefaultCase {};
26   
27   Warning: The DefaultCase must appear at the last position!!!
28 */
29
30 /*  
31   example:
32   
33   // wod:
34   Switch:      WESwitch { selection = selection;           };
35   FirstCase:   WECase   { key       = "first";             };
36   SecondCase:  WECase   { keys      = ("second", "third"); };
37   DefaultCase: WEDefaultCase {};
38
39   // html:
40   <#Switch>
41     <#FirstCase>content of first case</#FirstCase>
42     <#SecondCase>content of second case</#SecondCase>
43     <#DefaultCase>content of default case</#SecondCase>
44   </#Switch>
45   
46 */
47 #include <NGObjWeb/WODynamicElement.h>
48
49 @class WOAssociation;
50
51 @interface WESwitch : WODynamicElement
52 {
53 @protected
54   WOAssociation *selection;     // string -> single switch
55   WOAssociation *selections;    // array  -> multi  switch
56   WOElement     *template;
57 }
58 @end
59
60 @interface WECase : WODynamicElement
61 {
62   WOAssociation *key;          // string -> unique identifier
63   WOAssociation *keys;         // array of unique identifiers
64
65   WOAssociation *defaultCase;  // emulates a WEDefaultCase DEPRECATED!!!
66   
67   WOElement     *template;
68 }
69 @end
70
71 @interface WEDefaultCase : WODynamicElement
72 {
73   WOElement *template;
74 }
75 @end
76
77 #include "common.h"
78
79 #if DEBUG
80 static NSString *WESwitch_DefaultCaseFound = @"WESwitch_DefaultCaseFound";
81 #endif
82 static NSString *WESwitch_CaseDidMatch     = @"WESwitch_CaseDidMatch";
83 static NSString *WESwitchSelection         = @"WESwitchSelection";
84 static NSString *WESwitchSelections        = @"WESwitchSelections";
85 static NSString *WESwitchDict              = @"WESwitchDict";
86
87 @implementation WESwitch
88
89 - (id)initWithName:(NSString *)_name
90   associations:(NSDictionary *)_config
91   template:(WOElement *)_subs
92 {
93   if ((self = [super initWithName:_name associations:_config template:_subs])) {
94     self->selection  = WOExtGetProperty(_config, @"selection");
95     self->selections = WOExtGetProperty(_config, @"selections");
96     
97     self->template   = [_subs retain];
98   }
99   return self;
100 }
101
102 - (void)dealloc {
103   [self->template   release];
104   [self->selection  release];
105   [self->selections release];
106   [super dealloc];
107 }
108
109 /* processing requests */
110
111 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
112   WOComponent *cmp   = nil;
113   NSArray     *array = nil;
114   NSString    *k     = nil;
115   unsigned    i, cnt;
116   BOOL        doLazy = YES;
117
118   
119   cmp   = [_ctx component];
120   array = [self->selections valueInComponent:cmp];
121   k     = [self->selection  valueInComponent:cmp];
122   cnt   = [array count];
123
124   if (_req == nil) {
125     [self->template takeValuesFromRequest:_req inContext:_ctx];
126   }
127   else if (k) {
128     [_ctx setObject:k forKey:WESwitchSelection];
129     [self->template takeValuesFromRequest:_req inContext:_ctx];
130     [_ctx removeObjectForKey:WESwitchSelection];
131   }
132   else if (doLazy) {
133     for (i = 0; i < cnt; i++) {
134       [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection];
135       [self->template takeValuesFromRequest:_req inContext:_ctx];
136     }
137     if (cnt == 0) {
138       [_ctx setObject:array forKey:WESwitchSelections];
139       [self->template takeValuesFromRequest:_req inContext:_ctx];
140       [_ctx removeObjectForKey:WESwitchSelections];
141     }
142     [_ctx removeObjectForKey:WESwitchSelection];
143   }
144   else if (cnt > 0) {
145     NSLog(@"Warning(%s):This case is not implemented!!!", __PRETTY_FUNCTION__);
146     [self->template takeValuesFromRequest:_req inContext:_ctx];
147   }
148   
149 #if DEBUG
150   else {
151     [cmp logWithFormat:
152          @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"];
153   }
154 #endif
155
156   [_ctx removeObjectForKey:WESwitch_CaseDidMatch];
157 }
158
159 - (id)invokeActionForRequest:(WORequest *)_request inContext:(WOContext *)_ctx {
160   return [self->template invokeActionForRequest:_request inContext:_ctx];
161 }
162
163 /* generating response */
164
165 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
166   WOComponent *cmp   = nil;
167   NSArray     *array = nil;
168   NSString    *k     = nil;
169   unsigned    i, cnt;
170   BOOL        doLazy = YES;
171
172   
173   cmp   = [_ctx component];
174   array = [self->selections valueInComponent:cmp];
175   k     = [self->selection  valueInComponent:cmp];
176   cnt   = [array count];
177
178   if (_response == nil) {
179     [self->template appendToResponse:_response inContext:_ctx];
180   }
181   else if (k) {
182     [_ctx setObject:k forKey:WESwitchSelection];
183     [self->template appendToResponse:_response inContext:_ctx];
184     [_ctx removeObjectForKey:WESwitchSelection];
185   }
186   else if (doLazy) {
187     for (i=0; i<cnt; i++) {
188       [_ctx setObject:[array objectAtIndex:i] forKey:WESwitchSelection];
189       [self->template appendToResponse:_response inContext:_ctx];
190     }
191     if (cnt == 0) {
192       [_ctx setObject:array forKey:WESwitchSelections];
193       [self->template appendToResponse:_response inContext:_ctx];
194       [_ctx removeObjectForKey:WESwitchSelections];
195     } 
196     [_ctx removeObjectForKey:WESwitchSelection];
197   }
198   else if (cnt > 0) {
199     NSMutableDictionary *dict = nil;
200     
201     // get subcontent of WECases
202     [_ctx setObject:array forKey:WESwitchSelections];
203     [self->template appendToResponse:_response inContext:_ctx];
204     
205     dict = [_ctx objectForKey:WESwitchDict];
206
207     // append subcontent
208     if (dict) {
209       for (i=0; i<cnt; i++) {
210         NSString *k = [array objectAtIndex:i];
211         NSData   *c = [dict objectForKey:k];   // subcontent of WECase
212
213         if (c)
214           [_response appendContentData:c];
215       }
216     }
217     
218     [_ctx removeObjectForKey:WESwitchDict];
219     [_ctx removeObjectForKey:WESwitchSelections];
220   }
221   
222 #if DEBUG
223   else {
224     [cmp logWithFormat:
225          @"Warning! WESwitch: Neither 'selection' nor 'selections' set!!!"];
226   }
227 #endif
228
229   [_ctx removeObjectForKey:WESwitch_CaseDidMatch];
230 }
231
232 @end /* WESwitch */
233
234 @implementation WECase
235
236 - (id)initWithName:(NSString *)_name
237   associations:(NSDictionary *)_config
238   template:(WOElement *)_t
239 {
240   if ((self = [super initWithName:_name associations:_config template:_t])) {
241     self->key  = WOExtGetProperty(_config, @"key");
242     self->keys = WOExtGetProperty(_config, @"keys");
243
244     // DEPRECATED!!!
245     self->defaultCase  = WOExtGetProperty(_config, @"default");
246     
247     self->template = [_t retain];
248   }
249   return self;
250 }
251
252 - (void)dealloc {
253   [self->template    release];
254   [self->key         release];
255   [self->keys        release];
256   [self->defaultCase release];
257   [super dealloc];
258 }
259
260 /* processing requests */
261
262 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
263   NSArray     *selections = nil;
264   NSString    *selection  = nil;
265   NSString    *k          = nil;
266   NSArray     *ks         = nil;
267   
268   k   = [self->key  stringValueInComponent:[_ctx component]];
269   ks  = [self->keys valueInComponent:[_ctx component]];
270   
271   selections = [_ctx objectForKey:WESwitchSelections];
272   selection  = [_ctx objectForKey:WESwitchSelection];
273
274   if ([self->defaultCase boolValueInComponent:[_ctx component]]) {
275     if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)
276       [self->template takeValuesFromRequest:_req inContext:_ctx];
277     return;
278   }
279
280   if ((k == nil) && (ks == nil)) {
281 #if DEBUG
282     [[_ctx component] logWithFormat:
283                       @"Warning! WECase: Neither 'key' nor 'keys' set!!!"];
284 #endif
285     return;
286   }
287   if ((k != nil) && (ks != nil)) {
288 #if DEBUG
289     [[_ctx component] logWithFormat:
290                       @"Warning! WECase: Both, 'key' and 'keys' are set!!!"];
291 #endif
292     return;
293   }
294   
295   if (_req == nil) {
296     [self->template takeValuesFromRequest:nil inContext:_ctx];
297   }
298   if (selection) {
299     if (k && [k isEqualToString:selection]) {
300        [self->template takeValuesFromRequest:_req inContext:_ctx];
301        [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
302     }
303     else if (ks && [ks containsObject:selection]) {
304       [self->template takeValuesFromRequest:_req inContext:_ctx];
305       [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
306     }
307   }
308   else if (selections && [selections count] > 0) {
309     NSLog(@"Warning(%s): This case is not implemented!", __PRETTY_FUNCTION__);
310     [self->template takeValuesFromRequest:_req inContext:_ctx];
311   }
312 }
313
314 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
315   return [self->template invokeActionForRequest:_req inContext:_ctx];
316 }
317
318 /* generating response */
319
320 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
321   NSArray     *selections = nil;
322   NSString    *selection  = nil;
323   NSString    *k          = nil;
324   NSArray     *ks         = nil;
325
326
327   k   = [self->key  stringValueInComponent:[_ctx component]];
328   ks  = [self->keys valueInComponent:[_ctx component]];
329
330   selections = [_ctx objectForKey:WESwitchSelections];
331   selection  = [_ctx objectForKey:WESwitchSelection];
332
333   if ([self->defaultCase boolValueInComponent:[_ctx component]]) {
334     if ([_ctx objectForKey:WESwitch_CaseDidMatch] == nil)
335       [self->template appendToResponse:_response inContext:_ctx];
336     return;
337   }
338
339   if ((k == nil) && (ks == nil)) {
340 #if DEBUG
341     [[_ctx component] logWithFormat:
342                       @"Warning! WECase: Neither 'key' nor 'keys' set!!!"];
343 #endif
344     return;
345   }
346   if ((k != nil) && (ks != nil)) {
347 #if DEBUG
348     [[_ctx component] logWithFormat:
349                       @"Warning! WECase: Both, 'key' and 'keys' are set!!!"];
350 #endif
351     return;
352   }
353   
354   if (_response == nil) {
355     [self->template appendToResponse:nil inContext:_ctx];
356   }
357   if (selection) {
358     if (k && [k isEqualToString:selection]) {
359        [self->template appendToResponse:_response inContext:_ctx];
360        [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
361     }
362     else if (ks && [ks containsObject:selection]) {
363       [self->template appendToResponse:_response inContext:_ctx];
364       [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
365     }
366   }
367   else if (selections && [selections count] > 0) {
368     if ([selections containsObject:k]) {
369       static NSData *emptyData = nil;
370       NSMutableDictionary *dict       = nil;
371       NSData              *oldContent = nil;
372
373       if (emptyData == nil)
374         emptyData = [[NSData alloc] init];
375
376       // get subcontent dictionary
377       dict = [_ctx objectForKey:WESwitchDict];
378       if (dict == nil)
379         dict = [NSMutableDictionary dictionaryWithCapacity:[selections count]];
380
381       // set new content
382       oldContent = [_response content];
383       RETAIN(oldContent);
384       [_response setContent:emptyData];
385       
386       // append template to new content
387       [self->template appendToResponse:_response inContext:_ctx];
388
389       // save new content in dict
390       if ([_response content])
391         [dict setObject:[_response content] forKey:k];
392       [_ctx setObject:dict forKey:WESwitchDict];
393
394       // restore old content
395       [_response setContent:oldContent];
396       [oldContent release]; oldContent = nil;
397
398       // TODO: use NSNumber here?
399       [_ctx setObject:@"YES" forKey:WESwitch_CaseDidMatch];
400     }
401   }
402 }
403
404 @end /* WECase */
405
406 @implementation WEDefaultCase
407
408 - (id)initWithName:(NSString *)_name
409   associations:(NSDictionary *)_config
410   template:(WOElement *)_t
411 {
412   if ((self = [super initWithName:_name associations:_config template:_t])) {
413     self->template = [_t retain];
414   }
415   return self;
416 }
417
418 - (void)dealloc {
419   [self->template release];
420   [super dealloc];
421 }
422
423 /* processing requests */
424
425 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
426   if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil))
427     [self->template takeValuesFromRequest:_req inContext:_ctx];
428 }
429
430 - (id)invokeActionForRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
431   return [self->template invokeActionForRequest:_req inContext:_ctx];
432 }
433
434 /* generating response */
435
436 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
437   if (([_ctx objectForKey:WESwitch_CaseDidMatch] == nil))
438     [self->template appendToResponse:_response inContext:_ctx];
439   
440 #if DEBUG
441   [_ctx setObject:@"Yes" forKey:WESwitch_DefaultCaseFound];
442 #endif
443 }
444
445 @end /* WEDefaultCase */