]> err.no Git - sope/commitdiff
added new SoActionInvocation
authorhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Mon, 11 Oct 2004 13:32:18 +0000 (13:32 +0000)
committerhelge <helge@e4a50df8-12e2-0310-a44c-efbce7f8a7e3>
Mon, 11 Oct 2004 13:32:18 +0000 (13:32 +0000)
git-svn-id: http://svn.opengroupware.org/SOPE/trunk@243 e4a50df8-12e2-0310-a44c-efbce7f8a7e3

sope-appserver/NGObjWeb/ChangeLog
sope-appserver/NGObjWeb/SoObjects/GNUmakefile
sope-appserver/NGObjWeb/SoObjects/README
sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.h [new file with mode: 0644]
sope-appserver/NGObjWeb/SoObjects/SoActionInvocation.m [new file with mode: 0644]
sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.h
sope-appserver/NGObjWeb/SoObjects/SoPageInvocation.m
sope-appserver/NGObjWeb/SoObjects/SoProductClassInfo.m
sope-appserver/NGObjWeb/SoObjects/SoSelectorInvocation.h
sope-appserver/NGObjWeb/Version

index 759c20c7260b9466506e8806ce925108e133ff6b..5476e938edeaae841690563edc375dfc93f3b012 100644 (file)
@@ -1,3 +1,14 @@
+2004-10-11  Helge Hess  <helge.hess@opengroupware.org>
+       
+       * 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  <helge.hess@opengroupware.org>
 
        * NGHttp: fixed umlaut decoding on MacOSX, removed some unused code
index 7a6492d631cba10a931257b5117f9409e6696ebf..0f2ba6f1e4b629f0c3e3d2d663a13fec2beae02d 100644 (file)
@@ -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            \
index 624e9a51ece9085c4c248ed25de7d01f172e63c6..d231d3aa2a8f66f71a76f28543a9b1c40a2210dd 100644 (file)
@@ -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 (file)
index 0000000..b039f9c
--- /dev/null
@@ -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 <Foundation/NSObject.h>
+
+/*
+  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 (file)
index 0000000..e16d7a2
--- /dev/null
@@ -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 <NGObjWeb/WOApplication.h>
+#include <NGObjWeb/WODirectAction.h>
+#include <NGObjWeb/WOResponse.h>
+#include <DOM/EDOM.h>
+#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<WOPageGenerationContext>)_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 <WOPageGenerationContext>)_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 */
index 355308d393831e5367709674028c3da8484f6434..fb935528cfff75e1e819618a440aaee2dd06b954 100644 (file)
   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
   02111-1307, USA.
 */
-// $Id$
 
 #ifndef __SoObjects_SoPageInvocation_H__
 #define __SoObjects_SoPageInvocation_H__
 
-#import <Foundation/NSObject.h>
+#include <SoObjects/SoActionInvocation.h>
 
 /*
   An invocation object for WOComponent based SoClass methods.
 @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;
 /* accessors */
 
 - (NSString *)pageName;
-- (NSString *)actionName;
-
-- (void)setArgumentSpecifications:(NSDictionary *)_specs;
-- (NSDictionary *)argumentSpecifications;
-
-/* bindings */
-
-- (BOOL)isBound;
-- (id)bindToObject:(id)_object inContext:(id)_ctx;
 
 @end
 
index a2b9dc07aeec1db5f17422a19160112bf0c2dd51..e16743e186f9f33425b14e80aef4564696678659 100644 (file)
@@ -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 <NGObjWeb/WORequest.h>
 #include <NGObjWeb/WOResourceManager.h>
 #include <NGObjWeb/WOApplication.h>
-#include <DOM/EDOM.h>
 #include "common.h"
 
 @interface WOComponent(UsedPrivates)
 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 <WOPageGenerationContext>)_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 */
index 80669f7fa8794dbc2780470abe6738b21190a3a4..f9ec9ada9f5566bfb60a1d78cdf9e91efe5f5f40 100644 (file)
@@ -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
index 6d3582d2580088b3818990754857ce175db82971..9d5bd02cf8bf37f20c26c464a6032d1180e083b4 100644 (file)
@@ -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__
index 83f5ba0334b7e2df63263893dc15bd6e28f6947f..68b38c79e32adcba65f334905d6d2591bad7481a 100644 (file)
@@ -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