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