]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOComponentRequestHandler.m
major improvements in resource/template lookup with SoProduct's
[sope] / sope-appserver / NGObjWeb / WOComponentRequestHandler.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 "WOComponentRequestHandler.h"
23 #include "WORequestHandler+private.h"
24 #include "WOContext+private.h"
25 #include <NGObjWeb/WOApplication.h>
26 #include <NGObjWeb/WORequest.h>
27 #include <NGObjWeb/WOResponse.h>
28 #include <NGObjWeb/WOSession.h>
29 #include <NGObjWeb/WOComponent.h>
30 #include "common.h"
31
32 @interface WOApplication(Privates)
33 - (WOSession *)_initializeSessionInContext:(WOContext *)_ctx;
34 - (void)_setCurrentContext:(WOContext *)_ctx;
35 @end
36
37 @interface WORequestHandler(URI)
38 - (BOOL)doesRejectFavicon;
39 @end
40
41 @implementation WOComponentRequestHandler
42
43 + (int)version {
44   return [super version] + 0 /* 2 */;
45 }
46 + (void)initialize {
47   NSAssert2([super version] == 2,
48             @"invalid superclass (%@) version %i !",
49             NSStringFromClass([self superclass]), [super version]);
50 }
51
52 - (WOResponse *)restoreSessionWithID:(NSString *)_sid
53   inContext:(WOContext *)_ctx
54 {
55   WOApplication *app = [WOApplication application];
56   WOResponse *response = nil;
57   
58   if (_sid == nil) {
59     // invalid session ID (or no session-ID ?!, which is no error ?) */
60     response = [app handleSessionRestorationErrorInContext:_ctx];
61   }
62   else {
63     WOSession *session = nil;
64     
65     if ((session = [app restoreSessionWithID:_sid inContext:_ctx])) {
66       // awake restored session
67       [_ctx setSession:session];
68       [session _awakeWithContext:_ctx];
69       
70       [session awake];
71       response = nil;
72     }
73     else {
74       response = [app handleSessionRestorationErrorInContext:_ctx];
75     }
76   }
77   return response;
78 }
79
80 /*
81   The request handler path of a component URI looks like this:
82
83     sessionID/componentName/contextID/elementID/instance/server
84 */
85
86 - (WOResponse *)handleRequest:(WORequest *)_request {
87   // TODO: this should be integrated into the WORequestHandler default
88   //       mechanism
89   NSString      *sessionID        = nil;
90   WOApplication *application      = nil;
91   WOContext     *context;
92   WOResponse    *response         = nil;
93   WOSession     *session          = nil;
94   WOComponent   *component        = nil;
95   BOOL          isLocked          = NO;
96   NSString      *handlerPath      = nil;
97
98   if (_request == nil) return nil;
99   
100   if ([self doesRejectFavicon] && [[_request uri] isNotNull]) {
101     // TODO: code copied from WORequestHandler ...
102     if ([@"/favicon.ico" isEqualToString:[_request uri]]) {
103       response = [WOResponse responseWithRequest:_request];
104       [response setStatus:404 /* not found */];
105       [self debugWithFormat:@"rejected favicon request: %@", [_request uri]];
106       return response;
107     }
108   }
109   
110   application = [WOApplication application];
111   handlerPath = [_request requestHandlerPath];
112   
113 #if 0
114   [self logWithFormat:@"[component request handler] path: '%@'", handlerPath];
115 #endif
116
117   if (![application allowsConcurrentRequestHandling]) {
118     [application lockRequestHandling];
119     isLocked = YES;
120   }
121   
122   context = [WOContext contextWithRequest:_request];
123   [application _setCurrentContext:context];
124   
125   /*
126     parse handler path (URL)
127
128     The format is:
129
130       session/context.element-id
131   */
132   if ([handlerPath length] > 0) {
133     NSArray *spath = [_request requestHandlerPathArray];
134
135     if ([spath count] > 1)
136       [context setRequestSenderID:[spath objectAtIndex:1]];
137     if ([spath count] > 0)
138       sessionID = [spath objectAtIndex:0];
139   }
140   
141   if ([sessionID length] == 0)
142     sessionID = [application sessionIDFromRequest:_request];
143   
144 #if 1
145   [self logWithFormat:@"%s: made context %@ (cid=%@, sn=%@) ..",
146           __PRETTY_FUNCTION__, context, [context contextID], sessionID];
147 #endif
148   
149   [application awake];
150   
151   /* restore or create session */
152   if ([sessionID isNotNull]) {
153     response = [self restoreSessionWithID:sessionID inContext:context];
154     session  = response ? nil : [context session];
155     
156     //[self logWithFormat:@"restored session (id=%@): %@", sessionID, session];
157     
158     if ([session isNotNull]) {
159       /* awake stored page */
160       component = [session restorePageForContextID:[context currentElementID]];
161       
162       if (component == nil)
163         response = [application handlePageRestorationErrorInContext:context];
164 #if DEBUG
165       else {
166         [self logWithFormat:@"%s: restored request component: %@", 
167                 __PRETTY_FUNCTION__, component];
168       }
169 #endif
170     }
171     else if (response == nil) {
172       [[WOApplication application] warnWithFormat:
173                                      @"got no session restoration error, "
174                                      @"but missing session !"];
175     }
176   }
177   else {
178     /* create new session */
179     session = [application _initializeSessionInContext:context];
180     if ([session isNotNull]) {
181       /* awake created session */
182       [session awake];
183       component = [application pageWithName:nil inContext:context];
184     }
185     else
186       response = [application handleSessionCreationErrorInContext:context];
187   }
188   
189   if ((session != nil) && (component != nil) && (response == nil)) {
190     WOComponent *newPage = nil;
191
192     [[session retain] autorelease];
193     
194 #if DEBUG
195     NSAssert(application, @"missing application object ..");
196     NSAssert(session,     @"missing session object ..");
197 #endif
198     
199     /* set request page in context */
200     [context setPage:component];
201     
202     /* run take-values phase */
203     [application takeValuesFromRequest:_request inContext:context];
204     
205     /* run invoke-action phase */
206     newPage = [application invokeActionForRequest:_request inContext:context];
207     
208     /* process resulting page */
209     if (newPage == nil) {
210       if ((newPage = [context page]) == nil) {
211         newPage = [application pageWithName:nil inContext:context];
212         [context setPage:newPage];
213       }
214     }
215     else if ([newPage isKindOfClass:[WOComponent class]])
216       [context setPage:newPage];
217
218     [self debugWithFormat:@"%s: new page: %@", __PRETTY_FUNCTION__, newPage];
219     
220     /* generate response */
221     
222     response = [self generateResponseForComponent:[context page]
223                      inContext:context
224                      application:application];
225   }
226   else {
227     [self warnWithFormat:@"%s: did not enter request/response transaction ...",
228             __PRETTY_FUNCTION__];
229   }
230   
231   /* tear down */
232
233   /* sleep objects */
234   [context sleepComponents];
235   [session sleep];
236   
237   /* save objects */
238   
239   if (session != nil) {
240     if ([context savePageRequired])
241       [session savePage:[context page]];
242     
243     [self logWithFormat:@"saving session %@", [session sessionID]];
244     
245     if ([session storesIDsInCookies]) {
246       [self logWithFormat:@"add cookie to session: %@", session];
247       [self addCookiesForSession:session
248             toResponse:response
249             inContext:context];
250     }
251     
252 #if 1
253     [application saveSessionForContext:context];
254 #else
255     [self saveSession:session
256           inContext:context
257           withResponse:response
258           application:application];
259 #endif
260   }
261   
262   [application sleep];
263   
264   /* locking */
265   
266   if (isLocked) {
267     [application unlockRequestHandling];
268     isLocked = NO;
269   }
270   
271   [application _setCurrentContext:nil];
272   return response;
273 }
274
275 @end /* WOComponentRequestHandler */