]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WODirectActionRequestHandler.m
major improvements in resource/template lookup with SoProduct's
[sope] / sope-appserver / NGObjWeb / WODirectActionRequestHandler.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 "WODirectActionRequestHandler.h"
23 #include "WORequestHandler+private.h"
24 #include "WOContext+private.h"
25 #include <NGObjWeb/WOApplication.h>
26 #include <NGObjWeb/WOComponent.h>
27 #include <NGObjWeb/WODirectAction.h>
28 #include <NGObjWeb/WORequest.h>
29 #include <NGObjWeb/WOResponse.h>
30 #include <NGObjWeb/WOSession.h>
31 #include <NGObjWeb/WOSessionStore.h>
32 #include <NGObjWeb/WOStatisticsStore.h>
33 #include "common.h"
34
35 #if APPLE_RUNTIME || NeXT_RUNTIME
36 #  include <objc/objc-class.h>
37 #endif
38
39 static BOOL  usePool = NO;
40 static BOOL  perflog = NO;
41 static BOOL  debugOn = NO;
42 static Class NSDateClass = Nil;
43
44 @implementation WODirectActionRequestHandler
45
46 + (int)version {
47   return [super version] + 0 /* 2 */;
48 }
49 + (void)initialize {
50   NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
51   
52   NSAssert2([super version] == 2,
53             @"invalid superclass (%@) version %i !",
54             NSStringFromClass([self superclass]), [super version]);
55
56   NSDateClass = [NSDate class];
57   perflog = [ud boolForKey:@"WOProfileDirectActionRequestHandler"];
58 }
59
60 - (NSString *)loggingPrefix {
61   return @"[da-handler]";
62 }
63
64 /*
65   The request handler part of a direct action URI looks like this:
66   
67     [actionClass/]actionName[?key=value&key=value&...]
68 */
69
70 - (BOOL)isComponentClass:(Class)_clazz {
71   if (_clazz == Nil) 
72     return NO;
73   while ((_clazz = _clazz->super_class) != Nil) {
74     if (_clazz == [WOComponent    class]) return YES;
75     if (_clazz == [WODirectAction class]) return NO;
76     if (_clazz == [NSObject       class]) return NO;
77   }
78   return NO;
79 }
80
81 - (id)instantiateObjectForActionClass:(Class)actionClass
82   inContext:(WOContext *)context
83   application:(WOApplication *)app
84 {
85   WOComponent *component;
86   
87   if (actionClass == Nil)
88     return nil;
89   
90   if (![self isComponentClass:actionClass]) {
91     /* create direct action object */
92     id actionObject;
93     
94     if (![actionClass instancesRespondToSelector:
95                         @selector(initWithContext:)]) {
96       [self logWithFormat:@"tried to use class '%@' as a direct-action class",
97               NSStringFromClass(actionClass)];
98       return nil;
99     }
100     
101     actionObject =
102       [(WODirectAction *)[actionClass alloc] initWithContext:context];
103     actionObject = [actionObject autorelease];
104     return actionObject;
105   }
106   
107   /* special initialization for WOComponents used as direct actions */
108     
109   component = [app pageWithName:NSStringFromClass(actionClass)
110                    inContext:context];
111   [context setPage:(id)component];
112   
113   /* TODO: why was that commented out? */
114   if ([component shouldTakeValuesFromRequest:[context request]
115                  inContext:context])
116     [app takeValuesFromRequest:[context request] inContext:context];
117   
118   return component;
119 }
120
121 - (WOResponse *)handleRequest:(WORequest *)_request
122   inContext:(WOContext *)context
123   session:(WOSession *)session
124   application:(WOApplication *)app
125 {
126   NSAutoreleasePool   *pool2;
127   NSString            *actionClassName;
128   NSString            *actionName;
129   WOResponse          *response;
130   NSArray             *handlerPath;
131   Class               actionClass = Nil;
132   WODirectAction      *actionObject = nil;
133   id<WOActionResults> result = nil;
134
135   pool2 = usePool ? [[NSAutoreleasePool alloc] init] : nil;
136   
137   *(&result) = nil;
138   *(&response)        = nil;
139   *(&actionClassName) = nil;
140   *(&actionName)      = nil;
141   *(&handlerPath)     = nil;
142   
143   /* process path */
144   
145   handlerPath = [_request requestHandlerPathArray];
146
147   if (debugOn) {
148     [self debugWithFormat:@"path=%@ array=%@",
149           [_request requestHandlerPath], handlerPath];
150   }
151   
152   // TODO: fix OGo bug #1028
153   switch ([handlerPath count]) {
154     case 0:
155       actionClassName = @"DirectAction";
156       actionName      = @"default";
157       break;
158     case 1:
159       actionClassName = @"DirectAction";
160       actionName      = [handlerPath objectAtIndex:0];
161       break;
162     case 2:
163       actionClassName = [handlerPath objectAtIndex:0];
164       actionName      = [handlerPath objectAtIndex:1];
165       break;
166
167     default:
168       actionClassName = [handlerPath objectAtIndex:0];
169       actionName      = [handlerPath objectAtIndex:1];
170       // TODO: set path info in ctx?
171       if (debugOn) {
172         [self logWithFormat:@"invalid direction action URL: %@",
173                 [_request requestHandlerPath]];
174       }
175       break;
176   }
177
178   if ([actionName length] == 0)
179     actionName = @"default";
180
181   if ((*(&actionClass) = NSClassFromString(actionClassName)) == Nil) {
182     [self errorWithFormat:@"did not find direct action class %@",
183             actionClassName];
184     actionClass = [WODirectAction class];
185   }
186   
187   if (debugOn) {
188     [self debugWithFormat:
189             @"[direct action request handler] class=%@ action=%@ ..",
190             actionClassName, actionName];
191   }
192   
193   /* process request */
194   
195   actionObject = [self instantiateObjectForActionClass:actionClass
196                        inContext:context
197                        application:app];
198   
199   if (actionObject == nil) {
200     [self errorWithFormat:
201             @"could not create direct action object of class %@",
202             actionClassName];
203     actionObject = nil;
204   }
205   else {
206     static Class WOComponentClass = Nil;
207     
208     if (WOComponentClass == Nil)
209       WOComponentClass = [WOComponent class];
210     
211     result = [(id)[actionObject performActionNamed:actionName] retain];
212     
213     if (result == nil) result = [[context page] retain];
214     
215     if ([(id)result isKindOfClass:WOComponentClass]) {
216       [(id)result _awakeWithContext:context];
217       [context setPage:(WOComponent *)result];
218       
219       response = [self generateResponseForComponent:(WOComponent *)result
220                        inContext:context
221                        application:app];
222       
223       if ([context hasSession]) {
224         if ([context savePageRequired])
225           [[context session] savePage:(WOComponent *)result];
226       }
227       
228       response = [response retain];
229     }
230     else {
231       /* generate response */
232       response = [[result generateResponse] retain];
233     }
234               
235     [context sleepComponents];
236     
237     [(id)result release]; result = nil;
238     
239     /* check whether a session was created */
240     if ((session == nil) && [context hasSession]) {
241       session = [[[context session] retain] autorelease];
242       [session lock];
243     }
244     
245     if (usePool) {
246       session = [session retain];
247       [pool2 release]; pool2 = nil;
248       session = [session autorelease];
249     }
250     response = [response autorelease];
251   }
252   
253   return response;
254 }
255
256 @end /* WODirectActionRequestHandler */