From: helge Date: Mon, 11 Oct 2004 13:32:18 +0000 (+0000) Subject: added new SoActionInvocation X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=476e80b79cf58896f1e3f508098e21b230666df6;p=sope added new SoActionInvocation git-svn-id: http://svn.opengroupware.org/SOPE/trunk@243 e4a50df8-12e2-0310-a44c-efbce7f8a7e3 --- diff --git a/sope-appserver/NGObjWeb/ChangeLog b/sope-appserver/NGObjWeb/ChangeLog index 759c20c7..5476e938 100644 --- a/sope-appserver/NGObjWeb/ChangeLog +++ b/sope-appserver/NGObjWeb/ChangeLog @@ -1,3 +1,14 @@ +2004-10-11 Helge Hess + + * v4.3.59 + + * SoObjects/SoProductClassInfo.m: added support for action invocations + (triggered by either 'actionClass' or 'directActionName' key in + product.plist) + + * SoObjects/SoPageInvocation.m: moved most of the implementation to a + new SoActionInvocation class which can invoke WODirectAction objects + 2004-10-10 Helge Hess * NGHttp: fixed umlaut decoding on MacOSX, removed some unused code diff --git a/sope-appserver/NGObjWeb/SoObjects/GNUmakefile b/sope-appserver/NGObjWeb/SoObjects/GNUmakefile index 7a6492d6..0f2ba6f1 100644 --- a/sope-appserver/NGObjWeb/SoObjects/GNUmakefile +++ b/sope-appserver/NGObjWeb/SoObjects/GNUmakefile @@ -20,6 +20,7 @@ SoObjects_HEADER_FILES = \ SoObjectMethodDispatcher.h \ SoObjectRequestHandler.h \ SoPageInvocation.h \ + SoActionInvocation.h \ SoPermissions.h \ SoProduct.h \ SoProductClassInfo.h \ @@ -55,6 +56,7 @@ SoObjects_OBJC_FILES = \ SoObjectXmlRpcDispatcher.m \ SoObjectSOAPDispatcher.m \ SoPageInvocation.m \ + SoActionInvocation.m \ SoPermissions.m \ SoProduct.m \ SoProductClassInfo.m \ diff --git a/sope-appserver/NGObjWeb/SoObjects/README b/sope-appserver/NGObjWeb/SoObjects/README index 624e9a51..d231d3aa 100644 --- a/sope-appserver/NGObjWeb/SoObjects/README +++ b/sope-appserver/NGObjWeb/SoObjects/README @@ -1,10 +1,8 @@ -# $Id$ - SoObjects ========= -An attempt to rewrite some Zope concepts in NGObjWeb, basically object -publishing. +An attempt to rewrite some Zope concepts in NGObjWeb, basically the thing which +is called "object publishing". It defines a new type system (SoClasses) and a new KVC system (which returns methods/selectors as objects). @@ -21,8 +19,8 @@ NOTES - we support ASP style ?Cmd query parameters ! - we support :method form parameters - - both, when found, are added to the traversal path, this has the advantage - that it leaves the URI of a node intact +=> both, when found, are added to the traversal path, this has the advantage + that it leaves the URI of a node intact Class Hierarchy =============== diff --git a/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.h b/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.h new file mode 100644 index 00000000..b039f9c8 --- /dev/null +++ b/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.h @@ -0,0 +1,71 @@ +/* + Copyright (C) 2002-2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#ifndef __SoObjects_SoActionInvocation_H__ +#define __SoObjects_SoActionInvocation_H__ + +#import + +/* + An invocation object for WODirectAction based SoClass methods. + + If the invocation is bound, the action is instantiated and initialized, + if it is called, the "actionName" is called and the result is returned or + if no "actionName" is set, the default action is called. +*/ + +@class NSString, NSDictionary, NSMutableString; + +@interface SoActionInvocation : NSObject +{ + NSString *actionClassName; + NSString *actionName; + + /* for bound invocations */ + id methodObject; + id object; + + NSDictionary *argumentSpecifications; +} + +- (id)initWithActionClassName:(NSString *)_cn; +- (id)initWithActionClassName:(NSString *)_cn actionName:(NSString *)_action; + +/* accessors */ + +- (NSString *)actionClassName; +- (NSString *)actionName; + +- (void)setArgumentSpecifications:(NSDictionary *)_specs; +- (NSDictionary *)argumentSpecifications; + +/* bindings */ + +- (BOOL)isBound; +- (id)bindToObject:(id)_object inContext:(id)_ctx; + +/* description */ + +- (void)appendAttributesToDescription:(NSMutableString *)_ms; + +@end + +#endif /* __SoObjects_SoActionInvocation_H__ */ diff --git a/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m b/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m new file mode 100644 index 00000000..e16d7a2c --- /dev/null +++ b/sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m @@ -0,0 +1,344 @@ +/* + Copyright (C) 2002-2004 SKYRIX Software AG + + This file is part of OpenGroupware.org. + + OGo is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any + later version. + + OGo is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with OGo; see the file COPYING. If not, write to the + Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. +*/ + +#include "SoActionInvocation.h" +#include "SoClassSecurityInfo.h" +#include "SoProduct.h" +#include "WOContext+SoObjects.h" +#include +#include +#include +#include +#include "common.h" + +@implementation SoActionInvocation + +static int debugOn = 0; + ++ (void)initialize { + static BOOL didInit = NO; + if (!didInit) { + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; + didInit = YES; + + debugOn = [ud boolForKey:@"SoPageInvocationDebugEnabled"] ? 1 : 0; + } +} + +- (id)initWithActionClassName:(NSString *)_cn actionName:(NSString *)_action { + if ((self = [super init])) { + self->actionClassName = [_cn copy]; + self->actionName = [_action copy]; + } + return self; +} +- (id)initWithActionClassName:(NSString *)_cn { + return [self initWithActionClassName:_cn actionName:nil]; +} +- (id)init { + return [self initWithActionClassName:nil actionName:nil]; +} + +- (void)dealloc { + [self->argumentSpecifications release]; + [self->methodObject release]; + [self->object release]; + [self->actionClassName release]; + [self->actionName release]; + [super dealloc]; +} + +/* accessors */ + +- (NSString *)defaultActionClassName { + return @"DirectAction"; +} +- (NSString *)actionClassName { + return [self->actionClassName isNotNull] + ? self->actionClassName + : [self defaultActionClassName]; +} +- (NSString *)actionName { + return self->actionName; +} + +- (void)setArgumentSpecifications:(NSDictionary *)_specs { + ASSIGNCOPY(self->argumentSpecifications, _specs); +} +- (NSDictionary *)argumentSpecifications { + return self->argumentSpecifications; +} + +/* argument processing */ + +- (NSDictionary *)extractSOAPArgumentsFromContext:(id)_ctx + specification:(id)_spec +{ + /* + spec is supposed to be a dictionary with the KVC keys as the + keys and DOM query pathes as the values. + */ + NSMutableDictionary *args; + NSEnumerator *keys; + NSString *key; + id soapEnvelope; + + // TODO: I guess that should be improved a bit in the dispatcher + if ((soapEnvelope = [_ctx valueForKey:@"SOAPEnvelope"]) == nil) { + // TODO: generate some kind of fault? (NSException?) + [self logWithFormat:@"ERROR: no SOAP envelope available in context!"]; + return nil; + } + + /* for each positional selector argument we have a query path */ + + args = [NSMutableDictionary dictionaryWithCapacity:8]; + keys = [_spec keyEnumerator]; + while ((key = [keys nextObject])) { + NSString *qppath; + id value; + + qppath = [_spec valueForKey:key]; + value = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil; + + [args setObject:(value != nil ? value : [NSNull null]) forKey:key]; + } + return args; +} + +- (NSDictionary *)extractArgumentsFromContext:(id)_ctx + forRequestType:(NSString *)_type + specification:(id)_spec +{ + if ([_type isEqualToString:@"SOAP"]) + return [self extractSOAPArgumentsFromContext:_ctx specification:_spec]; + + [self logWithFormat: + @"ERROR: cannot extract parameters for request type: '%@'", _type]; + return nil; +} + +/* page construction */ + +- (id)instantiateMethodInContext:(id)_ctx { + Class clazz; + id lMethod; + + if (debugOn) + [self debugWithFormat:@"instantiate method: %@", self->methodObject]; + + if (_ctx == nil) { + [self debugWithFormat: + @"Note: got no explicit context for method instantiation, using " + @"application context."]; + _ctx = [[WOApplication application] context]; + } + + /* find class */ + + if ((clazz = NSClassFromString([self actionClassName])) == Nil) { + [self logWithFormat:@"ERROR: did not find action class: %@", + [self actionClassName]]; + return nil; + } + + /* instantiate */ + + if ([clazz instancesRespondToSelector:@selector(initWithContext:)]) + lMethod = [[clazz alloc] initWithContext:_ctx]; + else if ([clazz instancesRespondToSelector:@selector(initWithRequest:)]) { + lMethod = [[clazz alloc] initWithRequest: + [(id)_ctx request]]; + } + else + lMethod = [[clazz alloc] init]; + + if (debugOn) [self debugWithFormat:@" page: %@", lMethod]; + + return lMethod; +} + +/* invocation */ + +- (BOOL)isCallable { + return YES; +} +- (id)clientObject { + return self->object; +} + +- (void)_prepareContext:(id)_ctx withMethodObject:(id)_method { + /* for subclasses */ +} + +- (id)callOnObject:(id)_client inContext:(id)_ctx { + NSDictionary *argspec; + id method; + WORequest *rq; + + if (self->object != _client) { + /* rebind */ + return [[self bindToObject:_client inContext:_ctx] + callOnObject:_client inContext:_ctx]; + } + + if ((method = self->methodObject) == nil) + method = [self instantiateMethodInContext:_ctx]; + + if (method == nil) { + [self logWithFormat:@"found no method named '%@' for call !", + [self actionClassName]]; + return nil; + } + + /* make page the "request" page */ + + [self _prepareContext:_ctx withMethodObject:method]; + + /* set client object in page */ + + if ([method respondsToSelector:@selector(setClientObject:)]) + [method setClientObject:_client]; + + /* apply request parameters */ + + rq = [(id )_ctx request]; + + if ([method shouldTakeValuesFromRequest:rq inContext:_ctx]) { + [[_ctx application] takeValuesFromRequest:rq + inContext:_ctx]; + } + + /* apply extracted parameters (TODO: what should be done first?) */ + + argspec = [self->argumentSpecifications objectForKey:[_ctx soRequestType]]; + if (argspec != nil) { + NSDictionary *args; + + args = [self extractArgumentsFromContext:_ctx + forRequestType:[_ctx soRequestType] + specification:argspec]; + if (debugOn) [self debugWithFormat:@"extracted args %@", args]; + + if (args != nil) [method takeValuesFromDictionary:args]; + } + + /* call action */ + + if (self->actionName) { + if (debugOn) { + [self debugWithFormat:@" performing action %@ on page: %@", + self->actionName, method]; + } + return [method performActionNamed:self->actionName]; + } + else { + if (debugOn) { + [self debugWithFormat:@" performing default action on page: %@", + method]; + } + return [method defaultAction]; + } +} + +/* bindings */ + +- (BOOL)isBound { + return self->object != nil ? YES : NO; +} + +- (id)bindToObject:(id)_object inContext:(id)_ctx { + SoActionInvocation *inv; + + if (_object == nil) return nil; + + // TODO: clean up this section, a bit hackish + inv = [[[self class] alloc] initWithActionClassName:self->actionClassName]; + inv = [inv autorelease]; + + inv->object = [_object retain]; + inv->actionName = [self->actionName copy]; + inv->argumentSpecifications = [self->argumentSpecifications copy]; + + inv->methodObject = [[inv instantiateMethodInContext:_ctx] retain]; + if (inv->methodObject == nil) { + [self logWithFormat:@"ERROR: did not find method '%@'", + [self actionClassName]]; + return nil; + } + + return inv; +} + +/* delivering as content (can happen in DAV !) */ + +- (void)appendToResponse:(WOResponse *)_r inContext:(WOContext *)_ctx { + [_r appendContentString:@"native action method: "]; + [_r appendContentHTMLString:[self description]]; +} + +/* key/value coding */ + +- (id)valueForUndefinedKey:(NSString *)_key { + if (debugOn) [self debugWithFormat:@"return nil for KVC key: '%@'", _key]; + return nil; +} + +/* description */ + +- (void)appendAttributesToDescription:(NSMutableString *)ms { + NSString *tmp; + + if ((tmp = [self actionClassName])) [ms appendFormat:@" class=%@", tmp]; + if (self->actionName) [ms appendFormat:@" action=%@", self->actionName]; + + if (self->object) [ms appendString:@" bound"]; + if (self->methodObject) [ms appendString:@" instantiated"]; + + if ([self->argumentSpecifications count] > 0) { + id tmp; + + tmp = [self->argumentSpecifications allKeys]; + tmp = [tmp componentsJoinedByString:@","]; + [ms appendFormat:@" arg-handlers=%@",tmp]; + } +} +- (NSString *)description { + NSMutableString *ms; + + ms = [NSMutableString stringWithCapacity:64]; + [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; + [self appendAttributesToDescription:ms]; + [ms appendString:@">"]; + return ms; +} + +/* Logging */ + +- (NSString *)loggingPrefix { + return [NSString stringWithFormat:@"[so-action 0x%08X %@]", + self, self->actionClassName]; +} +- (BOOL)isDebuggingEnabled { + return debugOn ? YES : NO; +} + +@end /* SoActionInvocation */ diff --git a/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.h b/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.h index 355308d3..fb935528 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.h +++ b/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.h @@ -18,12 +18,11 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #ifndef __SoObjects_SoPageInvocation_H__ #define __SoObjects_SoPageInvocation_H__ -#import +#include /* An invocation object for WOComponent based SoClass methods. @@ -37,17 +36,9 @@ @class WOComponent; @class SoProduct; -@interface SoPageInvocation : NSObject +@interface SoPageInvocation : SoActionInvocation { - NSString *pageName; - NSString *actionName; - SoProduct *product; /* non-retained ! */ - - /* for bound invocations */ - WOComponent *page; - id object; - - NSDictionary *argumentSpecifications; + SoProduct *product; /* non-retained ! */ } - (id)initWithPageName:(NSString *)_pageName; @@ -58,15 +49,6 @@ /* accessors */ - (NSString *)pageName; -- (NSString *)actionName; - -- (void)setArgumentSpecifications:(NSDictionary *)_specs; -- (NSDictionary *)argumentSpecifications; - -/* bindings */ - -- (BOOL)isBound; -- (id)bindToObject:(id)_object inContext:(id)_ctx; @end diff --git a/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.m b/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.m index a2b9dc07..e16743e1 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.m +++ b/sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.m @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #include "SoPageInvocation.h" #include "SoClassSecurityInfo.h" @@ -31,7 +30,6 @@ #include #include #include -#include #include "common.h" @interface WOComponent(UsedPrivates) @@ -50,44 +48,36 @@ static int debugOn = 0; + (void)initialize { + NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; static BOOL didInit = NO; - if (!didInit) { - NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; - didInit = YES; + if (didInit) return; + didInit = YES; - debugOn = [ud boolForKey:@"SoPageInvocationDebugEnabled"] ? 1 : 0; - } + debugOn = [ud boolForKey:@"SoPageInvocationDebugEnabled"] ? 1 : 0; } -- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action { - if ((self = [super init])) { - self->pageName = [_pageName copy]; - self->actionName = [_action copy]; - } - return self; -} - (id)initWithPageName:(NSString *)_pageName { - return [self initWithPageName:_pageName actionName:nil]; + return [self initWithActionClassName:_pageName]; } -- (id)init { - return [self initWithPageName:nil]; +- (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action { + return [self initWithActionClassName:_pageName actionName:_action]; } - (id)initWithPageName:(NSString *)_pageName actionName:(NSString *)_action product:(SoProduct *)_product { - if ((self = [self initWithPageName:_pageName actionName:_action])) { + if ((self = [self initWithPageName:_pageName actionName:_action]) != nil) { self->product = _product; } return self; } -- (void)dealloc { - [self->argumentSpecifications release]; - [self->page release]; - [self->object release]; - [self->pageName release]; - [self->actionName release]; - [super dealloc]; +/* accessors */ + +- (NSString *)pageName { + return [self actionClassName]; +} +- (NSString *)defaultActionClassName { + return @"Main"; } /* containment */ @@ -103,69 +93,11 @@ static int debugOn = 0; return nil; } -/* accessors */ - -- (NSString *)pageName { - return self->pageName; -} -- (NSString *)actionName { - return self->actionName; -} - -- (void)setArgumentSpecifications:(NSDictionary *)_specs { - ASSIGNCOPY(self->argumentSpecifications, _specs); -} -- (NSDictionary *)argumentSpecifications { - return self->argumentSpecifications; -} - -/* argument processing */ - -- (NSDictionary *)extractSOAPArgumentsFromContext:(id)_ctx - specification:(id)_spec -{ - /* - spec is supposed to be a dictionary with the KVC keys as the - keys and DOM query pathes as the values. - */ - NSMutableDictionary *args; - NSEnumerator *keys; - NSString *key; - id soapEnvelope; - - // TODO: I guess that should be improved a bit in the dispatcher - if ((soapEnvelope = [_ctx valueForKey:@"SOAPEnvelope"]) == nil) { - // TODO: generate some kind of fault? (NSException?) - [self logWithFormat:@"ERROR: no SOAP envelope available in context!"]; - return nil; - } - - /* for each positional selector argument we have a query path */ - - args = [NSMutableDictionary dictionaryWithCapacity:8]; - keys = [_spec keyEnumerator]; - while ((key = [keys nextObject])) { - NSString *qppath; - id value; - - qppath = [_spec valueForKey:key]; - value = [qppath isNotNull] ? [soapEnvelope lookupQueryPath:qppath] : nil; - - [args setObject:(value != nil ? value : [NSNull null]) forKey:key]; - } - return args; -} +/* calling */ -- (NSDictionary *)extractArgumentsFromContext:(id)_ctx - forRequestType:(NSString *)_type - specification:(id)_spec -{ - if ([_type isEqualToString:@"SOAP"]) - return [self extractSOAPArgumentsFromContext:_ctx specification:_spec]; - - [self logWithFormat: - @"ERROR: cannot extract parameters for request type: '%@'", _type]; - return nil; +- (void)_prepareContext:(id)_ctx withMethodObject:(id)_method { + /* make page the "request" page */ + [_ctx setPage:_method]; } /* page construction */ @@ -176,7 +108,7 @@ static int debugOn = 0; NSArray *languages; if (debugOn) { - [self debugWithFormat:@"instantiate page: %@", self->pageName]; + [self debugWithFormat:@"instantiate page: %@", self->methodObject]; if (self->product == nil) [self debugWithFormat:@" no product is set."]; } @@ -209,7 +141,7 @@ static int debugOn = 0; /* instantiate */ - lPage = [rm pageWithName:self->pageName languages:languages]; + lPage = [rm pageWithName:[self pageName] languages:languages]; [lPage ensureAwakeInContext:_ctx]; [lPage setResourceManager:rm]; @@ -217,90 +149,12 @@ static int debugOn = 0; return lPage; } - -/* invocation */ - -- (BOOL)isCallable { - return YES; -} -- (id)clientObject { - return self->object; +- (id)instantiateMethodInContext:(id)_ctx { + /* override default method */ + return [self instantiatePageInContext:_ctx]; } -- (id)callOnObject:(id)_client inContext:(id)_ctx { - NSDictionary *argspec; - WOComponent *lPage; - WORequest *rq; - - if (self->object != _client) { - /* rebind */ - return [[self bindToObject:_client inContext:_ctx] - callOnObject:_client inContext:_ctx]; - } - - if ((lPage = self->page) == nil) - lPage = [self instantiatePageInContext:_ctx]; - - if (lPage == nil) { - [self logWithFormat:@"found no page named '%@' for call !", - self->pageName]; - return nil; - } - - /* make page the "request" page */ - - [_ctx setPage:lPage]; - - /* set client object in page */ - - [lPage setClientObject:_client]; - - /* apply request parameters */ - - rq = [(id )_ctx request]; - - if ([lPage shouldTakeValuesFromRequest:rq inContext:_ctx]) { - [[_ctx application] takeValuesFromRequest:rq - inContext:_ctx]; - } - - /* apply extracted parameters (TODO: what should be done first?) */ - - argspec = [self->argumentSpecifications objectForKey:[_ctx soRequestType]]; - if (argspec != nil) { - NSDictionary *args; - - args = [self extractArgumentsFromContext:_ctx - forRequestType:[_ctx soRequestType] - specification:argspec]; - if (debugOn) [self debugWithFormat:@"extracted args %@", args]; - - if (args != nil) [lPage takeValuesFromDictionary:args]; - } - - /* call action */ - - if (self->actionName) { - if (debugOn) { - [self debugWithFormat:@" performing action %@ on page: %@", - self->actionName, lPage]; - } - return [lPage performActionNamed:self->actionName]; - } - else { - if (debugOn) { - [self debugWithFormat:@" performing default action on page: %@", - lPage]; - } - return [lPage defaultAction]; - } -} - -/* bindings */ - -- (BOOL)isBound { - return self->object != nil ? YES : NO; -} +/* binding */ - (id)bindToObject:(id)_object inContext:(id)_ctx { SoPageInvocation *inv; @@ -308,21 +162,21 @@ static int debugOn = 0; if (_object == nil) return nil; // TODO: clean up this section, a bit hackish - inv = [[SoPageInvocation alloc] initWithPageName:self->pageName]; + inv = [[[self class] alloc] initWithActionClassName:self->actionClassName]; inv = [inv autorelease]; - inv->product = self->product; // non-owned (cannot be detached !!!) - inv->object = [_object retain]; - inv->actionName = [self->actionName copy]; - inv->page = [[inv instantiatePageInContext:_ctx] retain]; + /* Note: product must be set _before_ instantiate! */ + inv->object = [_object retain]; + inv->actionName = [self->actionName copy]; + inv->product = self->product; // non-owned (cannot be detached !!!) inv->argumentSpecifications = [self->argumentSpecifications copy]; - if (inv->page == nil) { - [self logWithFormat:@"ERROR: did not find page method '%@'", - self->pageName]; + inv->methodObject = [[inv instantiateMethodInContext:_ctx] retain]; + if (inv->methodObject == nil) { + [self logWithFormat:@"ERROR: did not find method '%@'", + [self actionClassName]]; return nil; } - return inv; } @@ -333,51 +187,21 @@ static int debugOn = 0; [_r appendContentHTMLString:[self description]]; } -/* key/value coding */ - -- (id)valueForUndefinedKey:(NSString *)_key { - if (debugOn) [self debugWithFormat:@"return nil for KVC key: '%@'", _key]; - return nil; -} - /* description */ -- (NSString *)description { - NSMutableString *ms; - - ms = [NSMutableString stringWithCapacity:64]; - [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])]; - - if (self->pageName) [ms appendFormat:@" page=%@", self->pageName]; - if (self->actionName) [ms appendFormat:@" action=%@", self->actionName]; - - if (self->object) [ms appendString:@" bound"]; - if (self->page) [ms appendString:@" instantiated"]; - - if (self->product) [ms appendFormat:@" product=%@", self->product]; - - if ([self->argumentSpecifications count] > 0) { - id tmp; - - tmp = [self->argumentSpecifications allKeys]; - tmp = [tmp componentsJoinedByString:@","]; - [ms appendFormat:@" arg-handlers=%@",tmp]; - } - - [ms appendString:@">"]; - return ms; +- (void)appendAttributesToDescription:(NSMutableString *)_ms { + [super appendAttributesToDescription:_ms]; + if (self->product) [_ms appendFormat:@" product=%@", self->product]; } -@end /* SoPageInvocation */ - -@implementation SoPageInvocation(Logging) +/* Logging */ - (NSString *)loggingPrefix { return [NSString stringWithFormat:@"[so-page 0x%08X %@]", - self, self->pageName]; + self, [self pageName]]; } - (BOOL)isDebuggingEnabled { return debugOn ? YES : NO; } -@end /* SoPageInvocation(Logging) */ +@end /* SoPageInvocation */ diff --git a/sope-appserver/NGObjWeb/SoObjects/SoProductClassInfo.m b/sope-appserver/NGObjWeb/SoObjects/SoProductClassInfo.m index 80669f7f..f9ec9ada 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoProductClassInfo.m +++ b/sope-appserver/NGObjWeb/SoObjects/SoProductClassInfo.m @@ -21,6 +21,7 @@ // $Id: SoProductClassInfo.m 1 2004-08-20 10:08:27Z znek $ #include "SoProductClassInfo.h" +#include "SoActionInvocation.h" #include "SoPageInvocation.h" #include "SoSelectorInvocation.h" #include "SoClassSecurityInfo.h" @@ -304,7 +305,44 @@ static int loadDebugOn = 0; @implementation SoProductSlotSetInfo(ManifestLoading) - (BOOL)isPageInvocationManifest:(NSDictionary *)_m { - return [_m objectForKey:@"pageName"] ? YES : NO; + return [_m objectForKey:@"pageName"] != nil ? YES : NO; +} +- (BOOL)isActionInvocationManifest:(NSDictionary *)_m { + if ([_m objectForKey:@"actionClass"] != nil) return YES; + if ([_m objectForKey:@"directActionName"] != nil) return YES; + return NO; +} + +- (id)makeActionInvocationForMethodNamed:(NSString *)_name + manifest:(NSDictionary *)_m +{ + /* + Page invocation: + { + actionClass = "DirectAction"; + directActionName = "doIt"; + arguments = { + SOAP = { + login = "loginRequest/auth/username/!textValue"; + password = "loginRequest/auth/password/!textValue"; + }; + } + } + */ + SoActionInvocation *method; + NSString *actionClass, *actionName; + NSDictionary *argspecs; + + actionClass = [_m objectForKey:@"className"]; + argspecs = [_m objectForKey:@"arguments"]; + + if ((actionName = [_m objectForKey:@"directActionName"]) == nil) + actionName = [_m objectForKey:@"actionName"]; + + method = [[SoActionInvocation alloc] + initWithActionClassName:actionClass actionName:actionName]; + [method setArgumentSpecifications:argspecs]; + return method; } - (id)makePageInvocationForMethodNamed:(NSString *)_name @@ -428,6 +466,8 @@ static int loadDebugOn = 0; if ([self isPageInvocationManifest:_m]) method = [self makePageInvocationForMethodNamed:_name manifest:_m]; + else if ([self isActionInvocationManifest:_m]) + method = [self makeActionInvocationForMethodNamed:_name manifest:_m]; else if ((selector = [_m objectForKey:@"selector"])) method = [self makeInvocationForMethodNamed:_name selector:selector]; else diff --git a/sope-appserver/NGObjWeb/SoObjects/SoSelectorInvocation.h b/sope-appserver/NGObjWeb/SoObjects/SoSelectorInvocation.h index 6d3582d2..9d5bd02c 100644 --- a/sope-appserver/NGObjWeb/SoObjects/SoSelectorInvocation.h +++ b/sope-appserver/NGObjWeb/SoObjects/SoSelectorInvocation.h @@ -18,7 +18,6 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -// $Id$ #ifndef __SoObjects_SoSelectorInvocation_H__ #define __SoObjects_SoSelectorInvocation_H__ diff --git a/sope-appserver/NGObjWeb/Version b/sope-appserver/NGObjWeb/Version index 83f5ba03..68b38c79 100644 --- a/sope-appserver/NGObjWeb/Version +++ b/sope-appserver/NGObjWeb/Version @@ -1,6 +1,6 @@ # version file -SUBMINOR_VERSION:=58 +SUBMINOR_VERSION:=59 # v4.3.42 requires libNGExtensions v4.3.116 # v4.3.40 requires libNGExtensions v4.3.115