]> err.no Git - sope/blob - sope-appserver/NGObjWeb/WOComponentRequestHandler.m
bugfix, bumped dyld versions
[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 Pulic 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   WOSession *session;
57   
58   if (_sid == nil) {
59     // invalid session ID (or no session-ID ?!, which is no error ?) */
60     return [app handleSessionRestorationErrorInContext:_ctx];
61   }
62   
63   if ((session = [app restoreSessionWithID:_sid inContext:_ctx]) != nil) {
64     /* awake restored session */
65     [_ctx setSession:session];
66     [session _awakeWithContext:_ctx];
67     
68     [session awake];
69     return nil;
70   }
71   
72   return [app handleSessionRestorationErrorInContext:_ctx];
73 }
74
75 /*
76   The request handler path of a component URI looks like this:
77
78     sessionID/componentName/contextID/elementID/instance/server
79 */
80
81 - (WOResponse *)handleRequest:(WORequest *)_request {
82   // TODO: this should be integrated into the WORequestHandler default
83   //       mechanism
84   NSString      *sessionID        = nil;
85   WOApplication *application      = nil;
86   WOContext     *context;
87   WOResponse    *response         = nil;
88   WOSession     *session          = nil;
89   WOComponent   *component        = nil;
90   BOOL          isLocked          = NO;
91   NSString      *handlerPath      = nil;
92
93   if (_request == nil) return nil;
94   
95   if ([self doesRejectFavicon] && [[_request uri] isNotNull]) {
96     // TODO: code copied from WORequestHandler ...
97     if ([@"/favicon.ico" isEqualToString:[_request uri]]) {
98       response = [WOResponse responseWithRequest:_request];
99       [response setStatus:404 /* not found */];
100       [self debugWithFormat:@"rejected favicon request: %@", [_request uri]];
101       return response;
102     }
103   }
104   
105   application = [WOApplication application];
106   handlerPath = [_request requestHandlerPath];
107   
108 #if 0
109   [self logWithFormat:@"[component request handler] path: '%@'", handlerPath];
110 #endif
111
112   if (![application allowsConcurrentRequestHandling]) {
113     [application lockRequestHandling];
114     isLocked = YES;
115   }
116   
117   context = [WOContext contextWithRequest:_request];
118   [application _setCurrentContext:context];
119   
120   /*
121     parse handler path (URL)
122
123     The format is:
124
125       session/context.element-id
126   */
127   if ([handlerPath length] > 0) {
128     NSArray *spath = [_request requestHandlerPathArray];
129
130     if ([spath count] > 1)
131       [context setRequestSenderID:[spath objectAtIndex:1]];
132     if ([spath count] > 0)
133       sessionID = [spath objectAtIndex:0];
134   }
135   
136   if ([sessionID length] == 0)
137     sessionID = [application sessionIDFromRequest:_request];
138   
139 #if 1
140   [self logWithFormat:@"%s: made context %@ (cid=%@, sn=%@) ..",
141           __PRETTY_FUNCTION__, context, [context contextID], sessionID];
142 #endif
143   
144   [application awake];
145   
146   /* restore or create session */
147   if ([sessionID isNotNull]) {
148     if ((response = [self restoreSessionWithID:sessionID inContext:context]))
149       session = nil;
150     else {
151       /* 
152          Note: this creates a _new_ session if the restoration handler did not
153                return a response! We check that below by comparing the session
154                IDs.
155       */
156       session = [context session];
157     }
158     
159     [self debugWithFormat:@"restored session (id=%@): %@", sessionID, session];
160     
161     if (session && (![sessionID isEqualToString:[session sessionID]])) {
162       [self errorWithFormat:@"session-ids do not match (%@ vs %@)",
163               sessionID, [session sessionID]];
164     }
165     
166     if ([session isNotNull]) {
167       NSString *eid;
168       
169       /*
170          only try to restore a page if we still have the same session and if
171          the request contains an element-id (eg if we reconnect to the main
172          URL we do not have an element-id
173       */
174       eid = [context currentElementID];
175       if ([sessionID isEqualToString:[session sessionID]] && eid != nil) {
176         /* awake stored page from "old" session */
177         component = [session restorePageForContextID:eid];
178         
179         if (component == nil) {
180           [self logWithFormat:@"could not restore component from session: %@",
181                 session];
182           response = [application handlePageRestorationErrorInContext:context];
183         }
184       }
185       else /* a new session was created (but no restore-error response ret.) */
186         component = [application pageWithName:nil inContext:context];
187     }
188     else if (response == nil) {
189       [[WOApplication application] warnWithFormat:
190                                      @"got no session restoration error, "
191                                      @"but missing session!"];
192     }
193   }
194   else {
195     /* create new session */
196     session = [application _initializeSessionInContext:context];
197     if ([session isNotNull]) {
198       /* awake created session */
199       [session awake];
200       component = [application pageWithName:nil inContext:context];
201     }
202     else
203       response = [application handleSessionCreationErrorInContext:context];
204   }
205   
206   if ((session != nil) && (component != nil) && (response == nil)) {
207     WOComponent *newPage = nil;
208
209     [[session retain] autorelease];
210     
211 #if DEBUG
212     NSAssert(application, @"missing application object ..");
213     NSAssert(session,     @"missing session object ..");
214 #endif
215     
216     /* set request page in context */
217     [context setPage:component];
218     
219     /* run take-values phase */
220     [application takeValuesFromRequest:_request inContext:context];
221     
222     /* run invoke-action phase */
223     newPage = [application invokeActionForRequest:_request inContext:context];
224     
225     /* process resulting page */
226     if (newPage == nil) {
227       if ((newPage = [context page]) == nil) {
228         newPage = [application pageWithName:nil inContext:context];
229         [context setPage:newPage];
230       }
231     }
232     else if ([newPage isKindOfClass:[WOComponent class]])
233       [context setPage:newPage];
234
235     [self debugWithFormat:@"%s: new page: %@", __PRETTY_FUNCTION__, newPage];
236     
237     /* generate response */
238     
239     response = [self generateResponseForComponent:[context page]
240                      inContext:context
241                      application:application];
242   }
243   else {
244     [self warnWithFormat:@"%s: did not enter request/response transaction ...",
245             __PRETTY_FUNCTION__];
246   }
247   
248   /* tear down */
249
250   /* sleep objects */
251   [context sleepComponents];
252   [session sleep];
253   
254   /* save objects */
255   
256   if (session != nil) {
257     if ([context savePageRequired])
258       [session savePage:[context page]];
259     
260     [self debugWithFormat:@"saving session %@", [session sessionID]];
261     
262     if ([session storesIDsInCookies]) {
263       [self debugWithFormat:@"add cookie to session: %@", session];
264       [self addCookiesForSession:session
265             toResponse:response
266             inContext:context];
267     }
268     
269 #if 1 // TODO: explain that
270     [application saveSessionForContext:context];
271 #else
272     [self saveSession:session
273           inContext:context
274           withResponse:response
275           application:application];
276 #endif
277   }
278   
279   [application sleep];
280   
281   /* locking */
282   
283   if (isLocked) {
284     [application unlockRequestHandling];
285     isLocked = NO;
286   }
287   
288   [application _setCurrentContext:nil];
289   return response;
290 }
291
292 @end /* WOComponentRequestHandler */