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 <NGObjWeb/WORequestHandler.h>
23
24@interface WOPageRequestHandler : WORequestHandler
25@end
26
27//#include "WOPageRequestHandler.h"
28#include "WORequestHandler+private.h"
29#include "WOContext+private.h"
30#include <NGObjWeb/WOApplication.h>
31#include <NGObjWeb/WOComponent.h>
32#include <NGObjWeb/WODirectAction.h>
33#include <NGObjWeb/WORequest.h>
34#include <NGObjWeb/WOResponse.h>
35#include <NGObjWeb/WOSession.h>
36#include <NGObjWeb/WOComponent.h>
37#include <NGObjWeb/WOSessionStore.h>
38#include <NGObjWeb/WOStatisticsStore.h>
39#include "common.h"
40
41static BOOL  perflog             = NO;
42static Class NSDateClass         = Nil;
43static BOOL  debugUnknownActions = NO;
44static BOOL  debugOn             = NO;
45
46@interface WOComponent(Privates)
47- (void)_awakeWithContext:(WOContext *)_ctx;
48- (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
49@end
50
51@implementation WOPageRequestHandler
52
53+ (void)initialize {
54  NSUserDefaults *ud;
55
56  NSDateClass = [NSDate class];
57  ud = [NSUserDefaults standardUserDefaults];
58  perflog = [ud boolForKey:@"WOProfilePageRequestHandler"];
59  debugOn = [ud boolForKey:@"WOPageRequestHandlerDebugEnabled"];
60}
61
62/* debugging */
63
64- (NSString *)loggingPrefix {
65  return @"[pg-handler]";
66}
67- (BOOL)isDebuggingEnabled {
68  return debugOn;
69}
70
71/*
72  The request handler part of a direct action URI looks like this:
73
74    [actionClass/]actionName[?key=value&key=value&...]
75*/
76
77- (WOResponse *)handleRequest:(WORequest *)_request
78  inContext:(WOContext *)context
79  session:(WOSession *)session
80  application:(WOApplication *)app
81{
82  NSString      *actionName;
83  WOResponse    *response;
84  id<WOActionResults> result = nil;
85  NSString      *pageName;
86  WOComponent   *page;
87
88  *(&result) = nil;
89  *(&response)        = nil;
90  *(&actionName)      = nil;
91
92  /* process path */
93  if ((pageName = [_request headerForKey:@"x-httpd-pagename"]) == nil) {
94    NSArray *handlerPath;
95
96    handlerPath = [_request requestHandlerPathArray];
97    switch ([handlerPath count]) {
98      case 0:
99        pageName   = @"Main";
100        actionName = @"default";
101        break;
102      case 1:
103        pageName   = [handlerPath objectAtIndex:0];
104        actionName = @"default";
105        break;
106      default:
107        pageName   = [handlerPath objectAtIndex:0];
108        actionName = [handlerPath objectAtIndex:1];
109        break;
110    }
111
112    if (debugOn) {
113      [self debugWithFormat:@"path:   %@",   handlerPath];
114      [self debugWithFormat:@"page:   %@",   pageName];
115      [self debugWithFormat:@"action: %@", actionName];
116    }
117  }
118  else {
119    if (debugOn)
120      [self debugWithFormat:@"using httpd provided pagename: %@", pageName];
121  }
122
123  if (pageName == nil)
124    pageName = @"Main";
125
126  if ((page = [app pageWithName:pageName inContext:context]) == nil) {
127    [self errorWithFormat:
128            @"could not create page object with name %@", pageName];
129    return nil;
130  }
131
132  [self debugWithFormat:@"created page: %@", page];
133
134  /* setup page context */
135  [page _awakeWithContext:context];
136  [context setPage:page];
137
138  /* take values phase */
139
140  [app takeValuesFromRequest:_request inContext:context];
141
142  /* perform a direct action like action */
143
144  result = [page performActionNamed:actionName];
145
146  /* generate response */
147
148  if (result != page && result != nil) {
149    if ([(id)result isKindOfClass:[WOComponent class]]) {
150      [(WOComponent *)result _awakeWithContext:context];
151      [context setPage:(WOComponent *)result];
152
153      response = [self generateResponseForComponent:(WOComponent *)result
154                       inContext:context
155                       application:app];
156    }
157    else
158      response = [result generateResponse];
159  }
160  else {
161    result = page;
162    response = [self generateResponseForComponent:page
163                     inContext:context
164                     application:app];
165  }
166
167  if ([context hasSession]) {
168    if ([context savePageRequired])
169      [[context session] savePage:(WOComponent *)result];
170  }
171
172  /* check whether a session was created */
173  if ((session == nil) && [context hasSession]) {
174    session = [[[context session] retain] autorelease];
175    [session lock];
176  }
177
178  /* add session cookies to response */
179  [self addCookiesForSession:session
180        toResponse:response
181        inContext:context];
182
183  /* store session if one was active */
184  [self saveSession:session
185        inContext:context
186        withResponse:response
187        application:app];
188
189  return response;
190}
191
192@end /* WOPageRequestHandler */
193
194@implementation WOComponent(DirectActionExtensions)
195
196/* taking form values */
197
198- (void)takeFormValuesForKeyArray:(NSArray *)_keys {
199  NSEnumerator *keys;
200  NSString     *key;
201  WORequest    *rq;
202
203  rq   = [[self context] request];
204  keys = [_keys objectEnumerator];
205
206  while ((key = [keys nextObject]))
207    [self takeValue:[rq formValueForKey:key] forKey:key];
208}
209- (void)takeFormValuesForKeys:(NSString *)_key1,... {
210  va_list   va;
211  NSString  *key;
212  WORequest *rq;
213
214  rq = [[self context] request];
215  va_start(va, _key1);
216  for (key = _key1; key != nil; key = va_arg(va, NSString *))
217    [self takeValue:[rq formValueForKey:key] forKey:key];
218  va_end(va);
219}
220
221/* perform actions */
222
223- (id<WOActionResults>)defaultAction {
224  return self;
225}
226
227- (id<WOActionResults>)performActionNamed:(NSString *)_actionName {
228  SEL actionSel;
229  NSRange rng;
230
231  /* discard everything after a point in the URL */
232  rng = [_actionName rangeOfString:@"."];
233  if (rng.length > 0)
234    _actionName = [_actionName substringToIndex:rng.location];
235
236  _actionName = [_actionName stringByAppendingString:@"Action"];
237
238  if ((actionSel = NSSelectorFromString(_actionName)) == NULL) {
239    [self debugWithFormat:@"did not find selector for action: %@",
240	    _actionName];
241    return [self defaultAction];
242  }
243
244  if ([self respondsToSelector:actionSel])
245    return [self performSelector:actionSel];
246
247  if (debugUnknownActions) {
248    [self logWithFormat:@"Page class %@ cannot handle action %@",
249            NSStringFromClass([self class]), _actionName];
250  }
251  return [self defaultAction];
252}
253
254@end /* WOComponent(DirectActionExtensions) */
255