]> err.no Git - sope/blob - sope-appserver/NGObjWeb/DynamicElements/WOActionURL.m
Ported "fragmentID" stuff from JOPE to SOPE.
[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%p]: 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 isRenderingDisabled] || [[_ctx request] isFromClientComponent]) {
188     [self->template appendToResponse:_response inContext:_ctx];
189     return;
190   }
191
192   sComponent = [_ctx component];
193   
194   if ([self _appendHrefToResponse:_response inContext:_ctx]) {
195     queryString = [self queryStringForQueryDictionary:
196                           [self->queryDictionary valueInComponent:sComponent]
197                         andQueryParameters:self->queryParameters
198                         inContext:_ctx];
199   }
200   
201   if (self->fragmentIdentifier != nil) {
202     [_response appendContentCharacter:'#'];
203     WOResponse_AddString(_response,
204          [self->fragmentIdentifier stringValueInComponent:sComponent]);
205   }
206   if (queryString != nil) {
207     [_response appendContentCharacter:'?'];
208     WOResponse_AddString(_response, queryString);
209   }
210     
211   /* content */
212   [self->template appendToResponse:_response inContext:_ctx];
213 }
214
215 /* description */
216
217 - (NSString *)associationDescription {
218   NSMutableString *str = [NSMutableString stringWithCapacity:256];
219
220   if (self->fragmentIdentifier)
221     [str appendFormat:@" fragment=%@", self->fragmentIdentifier];
222
223   return str;
224 }
225
226 @end /* WOActionURL */
227
228 @implementation _WOActionActionURL
229
230 - (id)initWithName:(NSString *)_name
231   associations:(NSDictionary *)_config
232   template:(WOElement *)_t
233 {
234   if ((self = [super _initWithName:_name associations:_config template:_t])) {
235     self->action = OWGetProperty(_config, @"action");
236
237     if (self->action == nil) {
238       NSLog(@"missing action association for WOActionURL ..");
239       RELEASE(self);
240       return nil;
241     }
242
243 #if DEBUG
244     if ([_config objectForKey:@"pageName"] ||
245         [_config objectForKey:@"href"]     ||
246         [_config objectForKey:@"directActionName"] ||
247         [_config objectForKey:@"actionClass"]) {
248       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
249             @" (assign only one of pageName, href, "
250             @"directActionName or action)");
251     }
252 #endif
253   }
254   return self;
255 }
256
257 - (void)dealloc {
258   [self->action release];
259   [super dealloc];
260 }
261
262 /* dynamic invocation */
263
264 - (id)invokeActionForRequest:(WORequest *)_request
265   inContext:(WOContext *)_ctx
266 {
267   /* link is active */
268   return [self executeAction:self->action inContext:_ctx];
269 }
270
271 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
272   inContext:(WOContext *)_ctx
273 {
274   WOResponse_AddString(_response, [_ctx componentActionURL]);
275   return YES;
276 }
277
278 /* description */
279
280 - (NSString *)associationDescription {
281   NSMutableString *str = [NSMutableString stringWithCapacity:256];
282
283   [str appendFormat:@" action=%@", self->action];
284   [str appendString:[super associationDescription]];
285   return str;
286 }
287
288 @end /* _WOActionActionURL */
289
290 @implementation _WOPageActionURL
291
292 - (id)initWithName:(NSString *)_name
293   associations:(NSDictionary *)_config
294   template:(WOElement *)_t
295 {
296   if ((self = [super _initWithName:_name associations:_config template:_t])) {
297     self->pageName = OWGetProperty(_config, @"pageName");
298
299     if (self->pageName == nil) {
300       NSLog(@"missing pageName association for WOActionURL ..");
301       RELEASE(self);
302       return nil;
303     }
304
305 #if DEBUG
306     if ([_config objectForKey:@"action"] ||
307         [_config objectForKey:@"href"]     ||
308         [_config objectForKey:@"directActionName"] ||
309         [_config objectForKey:@"actionClass"]) {
310       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
311             @" (assign only one of pageName, href, "
312             @"directActionName or action)");
313     }
314 #endif
315   }
316   return self;
317 }
318
319 - (void)dealloc {
320   [self->pageName release];
321   [super dealloc];
322 }
323
324 /* actions */
325
326 - (id)invokeActionForRequest:(WORequest *)_request
327   inContext:(WOContext *)_ctx
328 {
329   WOComponent *page = nil;
330   NSString    *name = nil;
331
332   name = [self->pageName stringValueInComponent:[_ctx component]];
333   page = [[_ctx application] pageWithName:name inContext:_ctx];
334
335   if (page == nil) {
336     [[_ctx session] logWithFormat:
337                       @"%@[0x%p]: did not find page with name %@ !",
338                       NSStringFromClass([self class]), self, name];
339   }
340   return page;
341 }
342
343 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
344   inContext:(WOContext *)_ctx
345 {
346   WOResponse_AddString(_response, [_ctx componentActionURL]);
347   return YES;
348 }
349
350 /* description */
351
352 - (NSString *)associationDescription {
353   NSMutableString *str = [NSMutableString stringWithCapacity:256];
354
355   [str appendFormat:@" pageName=%@", self->pageName];
356   [str appendString:[super associationDescription]];
357   return str;
358 }
359
360 @end /* _WOPageActionURL */
361
362 @implementation _WODirectActionActionURL
363
364 - (id)initWithName:(NSString *)_name
365   associations:(NSDictionary *)_config
366   template:(WOElement *)_t
367 {
368   if ((self = [super _initWithName:_name associations:_config template:_t])) {
369     WOAssociation *sidInUrlAssoc;
370     
371     sidInUrlAssoc          = OWGetProperty(_config, @"?wosid");
372     self->actionClass      = OWGetProperty(_config, @"actionClass");
373     self->directActionName = OWGetProperty(_config, @"directActionName");
374
375     self->sidInUrl = (sidInUrlAssoc)
376       ? [sidInUrlAssoc boolValueInComponent:nil]
377       : YES;
378     
379 #if DEBUG
380     if ([_config objectForKey:@"action"] ||
381         [_config objectForKey:@"href"]     ||
382         [_config objectForKey:@"pageName"]) {
383       NSLog(@"WARNING: inconsistent association settings in WOActionURL !"
384             @" (assign only one of pageName, href, "
385             @"directActionName or action)");
386     }
387 #endif
388   }
389   return self;
390 }
391
392 - (void)dealloc {
393   [self->actionClass      release];
394   [self->directActionName release];
395   [super dealloc];
396 }
397
398 /* href */
399
400 - (BOOL)_appendHrefToResponse:(WOResponse *)_response
401   inContext:(WOContext *)_ctx
402 {
403   WOComponent         *sComponent;
404   NSString            *daClass;
405   NSString            *daName;
406   NSMutableDictionary *qd;
407   NSDictionary        *tmp;
408
409   sComponent = [_ctx component];
410   daClass = [self->actionClass stringValueInComponent:sComponent];
411   daName  = [self->directActionName stringValueInComponent:sComponent];
412
413   if (daClass) {
414     if (daName) {
415       if (![daClass isEqualToString:@"DirectAction"])
416         daName = [NSString stringWithFormat:@"%@/%@", daClass, daName];
417     }
418     else
419       daName = daClass;
420   }
421
422   qd = [NSMutableDictionary dictionaryWithCapacity:16];
423
424       /* add query dictionary */
425       
426   if (self->queryDictionary) {
427     if ((tmp = [self->queryDictionary valueInComponent:sComponent]))
428       [qd addEntriesFromDictionary:tmp];
429   }
430       
431   /* add ?style parameters */
432
433   if (self->queryParameters) {
434     NSEnumerator *keys;
435     NSString     *key;
436
437     keys = [self->queryParameters keyEnumerator];
438     while ((key = [keys nextObject]) != nil) {
439       id assoc, value;
440
441       assoc = [self->queryParameters objectForKey:key];
442       value = [assoc stringValueInComponent:sComponent];
443           
444       [qd setObject:(value != nil ? value : (id)@"") forKey:key];
445     }
446   }
447       
448   /* add session ID */
449
450   if (self->sidInUrl) {
451     if ([_ctx hasSession]) {
452       WOSession *sn = [_ctx session];
453           
454       [qd setObject:[sn sessionID] forKey:WORequestValueSessionID];
455           
456       if (![sn isDistributionEnabled]) {
457         [qd setObject:[[WOApplication application] number]
458             forKey:WORequestValueInstance];
459       }
460     }
461   }
462
463   WOResponse_AddString(_response,
464                        [_ctx directActionURLForActionNamed:daName
465                              queryDictionary:qd]);
466   return NO;
467 }
468
469 /* description */
470
471 - (NSString *)associationDescription {
472   NSMutableString *str = [NSMutableString stringWithCapacity:256];
473
474   if (self->actionClass != nil)
475     [str appendFormat:@" actionClass=%@", self->actionClass];
476   if (self->directActionName != nil)
477     [str appendFormat:@" directAction=%@", self->directActionName];
478   
479   [str appendString:[super associationDescription]];
480   return str;
481 }
482
483 @end /* _WODirectActionActionURL */