2 Copyright (C) 2002-2004 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo 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
11 OGo 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.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
23 #include "SoPageInvocation.h"
24 #include "SoClassSecurityInfo.h"
25 #include "SoProduct.h"
26 #include "WOContext+SoObjects.h"
27 #include <NGObjWeb/WOComponent.h>
28 #include <NGObjWeb/WOContext.h>
29 #include <NGObjWeb/WOSession.h>
30 #include <NGObjWeb/WOResponse.h>
31 #include <NGObjWeb/WORequest.h>
32 #include <NGObjWeb/WOResourceManager.h>
33 #include <NGObjWeb/WOApplication.h>
37 @interface WOComponent(UsedPrivates)
38 /* this is defined in WOPageRequestHandler */
39 - (id<WOActionResults>)performActionNamed:(NSString *)_actionName;
40 - (id<WOActionResults>)defaultAction;
41 - (void)setResourceManager:(WOResourceManager *)_rm;
44 @interface WOContext(UsedPrivates)
45 - (void)setPage:(WOComponent *)_page;
48 @implementation SoPageInvocation
50 static int debugOn = 0;
53 static BOOL didInit = NO;
55 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
58 debugOn = [ud boolForKey:@"SoPageInvocationDebugEnabled"] ? 1 : 0;
62 - (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action {
63 if ((self = [super init])) {
64 self->pageName = [_pageName copy];
65 self->actionName = [_action copy];
69 - (id)initWithPageName:(NSString *)_pageName {
70 return [self initWithPageName:_pageName actionName:nil];
73 return [self initWithPageName:nil];
75 - (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action
76 product:(SoProduct *)_product
78 if ((self = [self initWithPageName:_pageName actionName:_action])) {
79 self->product = _product;
85 [self->argumentSpecifications release];
87 [self->object release];
88 [self->pageName release];
89 [self->actionName release];
95 - (void)detachFromContainer {
101 - (NSString *)nameInContainer {
102 /* could ask product */
108 - (NSString *)pageName {
109 return self->pageName;
111 - (NSString *)actionName {
112 return self->actionName;
115 - (void)setArgumentSpecifications:(NSDictionary *)_specs {
116 ASSIGNCOPY(self->argumentSpecifications, _specs);
118 - (NSDictionary *)argumentSpecifications {
119 return self->argumentSpecifications;
122 /* argument processing */
124 - (NSDictionary *)extractSOAPArgumentsFromContext:(id)_ctx
125 specification:(id)_spec
128 spec is supposed to be a dictionary with the KVC keys as the
129 keys and DOM query pathes as the values.
131 NSMutableDictionary *args;
136 // TODO: I guess that should be improved a bit in the dispatcher
137 if ((soapEnvelope = [_ctx valueForKey:@"SOAPEnvelope"]) == nil) {
138 // TODO: generate some kind of fault? (NSException?)
139 [self logWithFormat:@"ERROR: no SOAP envelope available in context!"];
143 /* for each positional selector argument we have a query path */
145 args = [NSMutableDictionary dictionaryWithCapacity:8];
146 keys = [_spec keyEnumerator];
147 while ((key = [keys nextObject])) {
151 qppath = [_spec valueForKey:key];
152 value = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil;
154 [args setObject:(value != nil ? value : [NSNull null]) forKey:key];
159 - (NSDictionary *)extractArgumentsFromContext:(id)_ctx
160 forRequestType:(NSString *)_type
161 specification:(id)_spec
163 if ([_type isEqualToString:@"SOAP"])
164 return [self extractSOAPArgumentsFromContext:_ctx specification:_spec];
167 @"ERROR: cannot extract parameters for request type: '%@'", _type];
171 /* page construction */
173 - (WOComponent *)instantiatePageInContext:(id)_ctx {
174 WOResourceManager *rm;
179 [self debugWithFormat:@"instantiate page: %@", self->pageName];
180 if (self->product == nil)
181 [self debugWithFormat:@" no product is set."];
185 [self debugWithFormat:
186 @"Note: got no explicit context for page instantiation, using "
187 @"application context."];
188 _ctx = [[WOApplication application] context];
191 /* lookup available resource manager (product,component,app) */
193 if ((rm = [self->product resourceManager]) == nil) {
194 if ((rm = [[_ctx component] resourceManager]) == nil) {
195 rm = [[_ctx application] resourceManager];
196 if (debugOn) [self debugWithFormat:@" app-rm: %@", rm];
199 if (debugOn) [self debugWithFormat:@" component-rm: %@", rm];
202 if (debugOn) [self debugWithFormat:@" product-rm: %@", rm];
204 /* determine language */
206 languages = [_ctx hasSession]
207 ? [(WOSession *)[_ctx session] languages]
208 : [[(id <WOPageGenerationContext>)_ctx request] browserLanguages];
212 lPage = [rm pageWithName:self->pageName languages:languages];
213 [lPage ensureAwakeInContext:_ctx];
214 [lPage setResourceManager:rm];
216 if (debugOn) [self debugWithFormat:@" page: %@", lPage];
230 - (id)callOnObject:(id)_client inContext:(id)_ctx {
231 NSDictionary *argspec;
235 if (self->object != _client) {
237 return [[self bindToObject:_client inContext:_ctx]
238 callOnObject:_client inContext:_ctx];
241 if ((lPage = self->page) == nil)
242 lPage = [self instantiatePageInContext:_ctx];
245 [self logWithFormat:@"found no page named '%@' for call !",
250 /* make page the "request" page */
252 [_ctx setPage:lPage];
254 /* set client object in page */
256 [lPage setClientObject:_client];
258 /* apply request parameters */
260 rq = [(id <WOPageGenerationContext>)_ctx request];
262 if ([lPage shouldTakeValuesFromRequest:rq inContext:_ctx]) {
263 [[_ctx application] takeValuesFromRequest:rq
267 /* apply extracted parameters (TODO: what should be done first?) */
269 argspec = [self->argumentSpecifications objectForKey:[_ctx soRequestType]];
270 if (argspec != nil) {
273 args = [self extractArgumentsFromContext:_ctx
274 forRequestType:[_ctx soRequestType]
275 specification:argspec];
276 if (debugOn) [self debugWithFormat:@"extracted args %@", args];
278 if (args != nil) [lPage takeValuesFromDictionary:args];
283 if (self->actionName) {
285 [self debugWithFormat:@" performing action %@ on page: %@",
286 self->actionName, lPage];
288 return [lPage performActionNamed:self->actionName];
292 [self debugWithFormat:@" performing default action on page: %@",
295 return [lPage defaultAction];
302 return self->object != nil ? YES : NO;
305 - (id)bindToObject:(id)_object inContext:(id)_ctx {
306 SoPageInvocation *inv;
308 if (_object == nil) return nil;
310 // TODO: clean up this section, a bit hackish
311 inv = [[SoPageInvocation alloc] initWithPageName:self->pageName];
312 inv = [inv autorelease];
314 inv->product = self->product; // non-owned (cannot be detached !!!)
315 inv->object = [_object retain];
316 inv->actionName = [self->actionName copy];
317 inv->page = [[inv instantiatePageInContext:_ctx] retain];
318 inv->argumentSpecifications = [self->argumentSpecifications copy];
320 if (inv->page == nil) {
321 [self logWithFormat:@"ERROR: did not find page method '%@'",
329 /* delivering as content (can happen in DAV !) */
331 - (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx {
332 [_r appendContentString:@"native component method: "];
333 [_r appendContentHTMLString:[self description]];
336 /* key/value coding */
338 - (id)valueForUndefinedKey:(NSString *)_key {
339 if (debugOn) [self debugWithFormat:@"return nil for KVC key: '%@'", _key];
345 - (NSString *)description {
348 ms = [NSMutableString stringWithCapacity:64];
349 [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
351 if (self->pageName) [ms appendFormat:@" page=%@", self->pageName];
352 if (self->actionName) [ms appendFormat:@" action=%@", self->actionName];
354 if (self->object) [ms appendString:@" bound"];
355 if (self->page) [ms appendString:@" instantiated"];
357 if (self->product) [ms appendFormat:@" product=%@", self->product];
359 if ([self->argumentSpecifications count] > 0) {
362 tmp = [self->argumentSpecifications allKeys];
363 tmp = [tmp componentsJoinedByString:@","];
364 [ms appendFormat:@" arg-handlers=%@",tmp];
367 [ms appendString:@">"];
371 @end /* SoPageInvocation */
373 @implementation SoPageInvocation(Logging)
375 - (NSString *)loggingPrefix {
376 return [NSString stringWithFormat:@"[so-page 0x%08X %@]",
377 self, self->pageName];
379 - (BOOL)isDebuggingEnabled {
380 return debugOn ? YES : NO;
383 @end /* SoPageInvocation(Logging) */