]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOActionURL.m
started TAL element builder
[sope] / sope-appserver / NGObjWeb / DynamicElements / WOActionURL.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 "WOHTMLDynamicElement.h"
23 #include "WOElement+private.h"
24 #include <NGObjWeb/WOApplication.h>
25 #include <NGObjWeb/WOResourceManager.h>
26 #include "decommon.h"
27
28 /*
29   WOActionURL associations:
30
31     pageName | action | (directActionName & actionClass)
32     fragmentIdentifier
33     queryDictionary
34 */
35
36 @interface WOActionURL : WOHTMLDynamicElement
37 {
38   // WODynamicElement: extraAttributes
39   // WODynamicElement: otherTagString
40 @protected
41   WOAssociation *fragmentIdentifier;
42   WOElement     *template;
43
44   /* new in WO4: */
45   WOAssociation *queryDictionary;
46   NSDictionary  *queryParameters;  /* associations beginning with ? */
47 }
48
49 @end /* WOActionURL */
50
51 @interface _WOActionActionURL : WOActionURL
52 {
53   WOAssociation *action;
54 }
55 @end
56
57 @interface _WOPageActionURL : WOActionURL
58 {
59   WOAssociation *pageName;
60 }
61 @end
62
63 @interface _WODirectActionActionURL : WOActionURL
64 {
65   WOAssociation *actionClass;
66   WOAssociation *directActionName;
67   BOOL          sidInUrl;          /* include session-id in wa URL ? */
68 }
69 @end
70
71 @interface WOActionURL(PrivateMethods)
72
73 - (id)_initWithName:(NSString *)_name
74   associations:(NSDictionary *)_config
75   template:(WOElement *)_t;
76
77 - (NSString *)associationDescription;
78
79 @end
80
81 @implementation WOActionURL
82
83 + (int)version {
84   return 1;
85 }
86 + (void)initialize {
87   NSAssert2([super version] == 2,
88             @"invalid superclass (%@) version %i !",
89             NSStringFromClass([self superclass]), [super version]);
90 }
91
92 - (id)initWithName:(NSString *)_name
93   associations:(NSDictionary *)_config
94   template:(WOElement *)_t
95 {
96   Class linkClass = Nil;
97   
98   if ([_config objectForKey:@"action"])
99     linkClass = [_WOActionActionURL class];
100   else if ([_config objectForKey:@"pageName"])
101     linkClass = [_WOPageActionURL class];
102   else
103     linkClass = [_WODirectActionActionURL class];
104
105   [self release];
106   return
107     [[linkClass alloc] initWithName:_name associations:_config template:_t];
108 }
109
110 - (id)_initWithName:(NSString *)_name
111   associations:(NSDictionary *)_config
112   template:(WOElement *)_t
113 {
114   if ((self = [super initWithName:_name associations:_config template:_t])) {
115     self->fragmentIdentifier = OWGetProperty(_config, @"fragmentIdentifier");
116     self->queryDictionary    = OWGetProperty(_config, @"queryDictionary");
117     self->queryParameters    = OWExtractQueryParameters(_config);
118     self->template           = [_t retain];
119     self->containsForm       = self->queryParameters ? YES : NO;
120   }
121   return self;
122 }
123
124 - (void)dealloc {
125   [self->template           release];
126   [self->queryDictionary    release];
127   [self->queryParameters    release];
128   [self->fragmentIdentifier release];
129   [super dealloc];
130 }
131
132 /* accessors */
133
134 - (id)template {
135   return self->template;
136 }
137
138 /* handling requests */
139
140 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
141   /* links can take form values !!!! (for query-parameters) */
142
143   if (self->queryParameters) {
144     /* apply values to ?style parameters */
145     WOComponent  *sComponent = [_ctx component];
146     NSEnumerator *keys;
147     NSString     *key;
148
149     keys = [self->queryParameters keyEnumerator];
150     while ((key = [keys nextObject])) {
151       id assoc, value;
152
153       assoc = [self->queryParameters objectForKey:key];
154       value = [_req formValueForKey:key];
155
156       [assoc setValue:value inComponent:sComponent];
157     }
158   }
159   
160   [self->template takeValuesFromRequest:_req inContext:_ctx];
161 }
162
163 - (id)invokeActionForRequest:(WORequest *)_request
164   inContext:(WOContext *)_ctx
165 {
166   [[_ctx session] logWithFormat:@"%@[0x%08X]: no action/page set !",
167                     NSStringFromClass([self class]), self];
168   return nil;
169 }
170
171 - (BOOL)_appendHrefToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
172 #if APPLE_FOUNDATION_LIBRARY || NeXT_Foundation_LIBRARY || \
173     COCOA_Foundation_LIBRARY
174   NSLog(@"subclass responsibility ...");
175 #else
176   [self subclassResponsibility:_cmd];
177 #endif
178   return NO;
179 }
180
181 /* generate response */
182
183 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
184   WOComponent *sComponent;
185   NSString *queryString = nil;
186   
187   if ([[_ctx request] isFromClientComponent])
188     return;
189
190   sComponent = [_ctx component];
191   
192   if ([self _appendHrefToResponse:_response inContext:_ctx]) {
193     queryString = [self queryStringForQueryDictionary:
194                           [self->queryDictionary valueInComponent:sComponent]
195                         andQueryParameters:self->queryParameters
196                         inContext:_ctx];
197   }
198   
199   if (self->fragmentIdentifier != nil) {
200     [_response appendContentCharacter:'#'];
201     WOResponse_AddString(_response,
202          [self->fragmentIdentifier stringValueInComponent:sComponent]);
203   }
204   if (queryString != nil) {
205     [_response appendContentCharacter:'?'];
206     WOResponse_AddString(_response, queryString);
207   }
208     
209   /* content */
210   [self->template appendToResponse:_response inContext:_ctx];
211 }
212
213 /* description */
214
215 - (NSString *)associationDescription {
216   NSMutableString *str = [NSMutableString stringWithCapacity:256];
217
218   if (self->fragmentIdentifier)
219     [str appendFormat:@" fragment=%@", self->fragmentIdentifier];
220
221   return str;
222 }
223
224 @end /* WOActionURL */
225
226 @implementation _WOActionActionURL
227
228 - (id)initWithName:(NSString *)_name
229   associations:(NSDictionary *)_config
230   template:(WOElement *)_t
231 {
232   if ((self = [super _initWithName:_name associations:_config template:_t])) {
233     self->action = OWGetProperty(_config, @"action");
234
235     if (self->action == nil) {
236       NSLog(@"missing action association for WOActionURL ..");
237       RELEASE(self);
238       return nil;
239     }
240
241 #if DEBUG
242     if ([_config objectForKey:@"pageName"] ||
243         [_config objectForKey:@"href"]     ||
244         [_config objectForKey:@"directActionName"] ||
245         [_config objectForKey:@"actionClass"]) {
246       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
247             @" (assign only one of pageName, href, "
248             @"directActionName or action)");
249     }
250 #endif
251   }
252   return self;
253 }
254
255 - (void)dealloc {
256   [self->action release];
257   [super dealloc];
258 }
259
260 /* dynamic invocation */
261
262 - (id)invokeActionForRequest:(WORequest *)_request
263   inContext:(WOContext *)_ctx
264 {
265   /* link is active */
266   return [self executeAction:self->action inContext:_ctx];
267 }
268
269 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
270   inContext:(WOContext *)_ctx
271 {
272   WOResponse_AddString(_response, [_ctx componentActionURL]);
273   return YES;
274 }
275
276 /* description */
277
278 - (NSString *)associationDescription {
279   NSMutableString *str = [NSMutableString stringWithCapacity:256];
280
281   [str appendFormat:@" action=%@", self->action];
282   [str appendString:[super associationDescription]];
283   return str;
284 }
285
286 @end /* _WOActionActionURL */
287
288 @implementation _WOPageActionURL
289
290 - (id)initWithName:(NSString *)_name
291   associations:(NSDictionary *)_config
292   template:(WOElement *)_t
293 {
294   if ((self = [super _initWithName:_name associations:_config template:_t])) {
295     self->pageName = OWGetProperty(_config, @"pageName");
296
297     if (self->pageName == nil) {
298       NSLog(@"missing pageName association for WOActionURL ..");
299       RELEASE(self);
300       return nil;
301     }
302
303 #if DEBUG
304     if ([_config objectForKey:@"action"] ||
305         [_config objectForKey:@"href"]     ||
306         [_config objectForKey:@"directActionName"] ||
307         [_config objectForKey:@"actionClass"]) {
308       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
309             @" (assign only one of pageName, href, "
310             @"directActionName or action)");
311     }
312 #endif
313   }
314   return self;
315 }
316
317 - (void)dealloc {
318   [self->pageName release];
319   [super dealloc];
320 }
321
322 /* actions */
323
324 - (id)invokeActionForRequest:(WORequest *)_request
325   inContext:(WOContext *)_ctx
326 {
327   WOComponent *page = nil;
328   NSString    *name = nil;
329
330   name = [self->pageName stringValueInComponent:[_ctx component]];
331   page = [[_ctx application] pageWithName:name inContext:_ctx];
332
333   if (page == nil) {
334     [[_ctx session] logWithFormat:
335                       @"%@[0x%08X]: did not find page with name %@ !",
336                       NSStringFromClass([self class]), self, name];
337   }
338   return page;
339 }
340
341 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
342   inContext:(WOContext *)_ctx
343 {
344   WOResponse_AddString(_response, [_ctx componentActionURL]);
345   return YES;
346 }
347
348 /* description */
349
350 - (NSString *)associationDescription {
351   NSMutableString *str = [NSMutableString stringWithCapacity:256];
352
353   [str appendFormat:@" pageName=%@", self->pageName];
354   [str appendString:[super associationDescription]];
355   return str;
356 }
357
358 @end /* _WOPageActionURL */
359
360 @implementation _WODirectActionActionURL
361
362 - (id)initWithName:(NSString *)_name
363   associations:(NSDictionary *)_config
364   template:(WOElement *)_t
365 {
366   if ((self = [super _initWithName:_name associations:_config template:_t])) {
367     WOAssociation *sidInUrlAssoc;
368     
369     sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
370     self->actionClass      = OWGetProperty(_config, @"actionClass");
371     self->directActionName = OWGetProperty(_config, @"directActionName");
372
373     self->sidInUrl = (sidInUrlAssoc)
374       ? [sidInUrlAssoc boolValueInComponent:nil]
375       : YES;
376     
377 #if DEBUG
378     if ([_config objectForKey:@"action"] ||
379         [_config objectForKey:@"href"]     ||
380         [_config objectForKey:@"pageName"]) {
381       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
382             @" (assign only one of pageName, href, "
383             @"directActionName or action)");
384     }
385 #endif
386   }
387   return self;
388 }
389
390 - (void)dealloc {
391   [self->actionClass      release];
392   [self->directActionName release];
393   [super dealloc];
394 }
395
396 /* href */
397
398 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
399   inContext:(WOContext *)_ctx
400 {
401   WOComponent         *sComponent;
402   NSString            *daClass;
403   NSString            *daName;
404   NSMutableDictionary *qd;
405   NSDictionary        *tmp;
406
407   sComponent = [_ctx component];
408   daClass = [self->actionClass stringValueInComponent:sComponent];
409   daName  = [self->directActionName stringValueInComponent:sComponent];
410
411   if (daClass) {
412     if (daName) {
413       if (![daClass isEqualToString:@"DirectAction"])
414         daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
415     }
416     else
417       daName = daClass;
418   }
419
420   qd = [NSMutableDictionary dictionaryWithCapacity:16];
421
422       /* add query dictionary */
423       
424   if (self->queryDictionary) {
425     if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
426       [qd addEntriesFromDictionary:tmp];
427   }
428       
429   /* add ?style parameters */
430
431   if (self->queryParameters) {
432     NSEnumerator *keys;
433     NSString     *key;
434
435     keys = [self->queryParameters keyEnumerator];
436     while ((key = [keys nextObject])) {
437       id assoc, value;
438
439       assoc = [self->queryParameters objectForKey:key];
440       value = [assoc stringValueInComponent:sComponent];
441           
442       [qd setObject:(value ? value : @"") forKey:key];
443     }
444   }
445       
446   /* add session ID */
447
448   if (self->sidInUrl) {
449     if ([_ctx hasSession]) {
450       WOSession *sn = [_ctx session];
451           
452       [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
453           
454       if (![sn isDistributionEnabled]) {
455         [qd setObject:[[WOApplication application] number]
456             forKey:WORequestValueInstance];
457       }
458     }
459   }
460
461   WOResponse_AddString(_response,
462                        [_ctx directActionURLForActionNamed:daName
463                              queryDictionary:qd]);
464   return NO;
465 }
466
467 /* description */
468
469 - (NSString *)associationDescription {
470   NSMutableString *str = [NSMutableString stringWithCapacity:256];
471
472   if (self->actionClass)
473     [str appendFormat:@" actionClass=%@", self->actionClass];
474   if (self->directActionName)
475     [str appendFormat:@" directAction=%@", self->directActionName];
476   
477   [str appendString:[super associationDescription]];
478   return str;
479 }
480
481 @end /* _WODirectActionActionURL */