/* 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. */ // $Id$ #include "SoObjectMethodDispatcher.h" #include "SoObject.h" #include "SoClass.h" #include "SoObjectRequestHandler.h" #include "WOContext+SoObjects.h" #include #include #include #include #include "common.h" @implementation SoObjectMethodDispatcher static BOOL debugOn = NO; + (void)initialize { NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; static BOOL didInit = NO; if (didInit) return; didInit = YES; debugOn = [ud boolForKey:@"SoObjectMethodDispatcherDebugEnabled"]; } - (id)initWithObject:(id)_object { if ((self = [super init])) { self->object = [_object retain]; } return self; } - (void)dealloc { [self->object release]; [super dealloc]; } /* perform dispatch */ - (id)dispatchInContext:(WOContext *)_ctx { NSAutoreleasePool *pool; WORequest *rq; id clientObject; id methodObject; id resultObject; pool = [[NSAutoreleasePool alloc] init]; rq = [_ctx request]; /* find client object */ if ((clientObject = [_ctx clientObject])) { if (debugOn) [self debugWithFormat:@"client object set in ctx: %@", clientObject]; } else if ((clientObject = [self->object clientObject])) { if (debugOn) [self debugWithFormat:@"setting client object: %@", clientObject]; [_ctx setClientObject:clientObject]; } // TODO: should check XML-RPC !!! // (hm, why ? XML-RPC is handled by other dispatcher ?) /* find callable (method) object */ if ([self->object isCallable]) { if (debugOn) [self debugWithFormat:@"traversed object is callable: %@", self->object]; methodObject = self->object; } else if ([[self->object soClass] hasKey:[rq method] inContext:_ctx]) { // TODO: I'm not sure whether this step is correct /* the class has a GET method */ methodObject = [self->object lookupName:[rq method] inContext:_ctx acquire:NO]; } else { // TODO: should we replace the methodObject with a redirect to the // default method name? This would ensure proper URLs methodObject = [self->object lookupDefaultMethod]; if (debugOn) [self debugWithFormat:@"using default method: %@", methodObject]; } /* apply arguments */ if ([methodObject respondsToSelector: @selector(takeValuesFromRequest:inContext:)]) { if (debugOn) [self debugWithFormat:@"applying values from request ..."]; [methodObject takeValuesFromRequest:rq inContext:_ctx]; } /* perform call */ if (methodObject == nil || ![methodObject isCallable]) { /* The object is neither callable nor does it have a default method, so we just pass it through. */ resultObject = self->object; if (debugOn) { [self debugWithFormat:@"got no method, using object as result: %@", resultObject]; } } else { resultObject = [methodObject callOnObject:[_ctx clientObject] inContext:_ctx]; if (debugOn) { if ([resultObject isKindOfClass:[WOResponse class]]) { [self debugWithFormat:@"call produced response: 0x%08X (code=%i)", resultObject, [(WOResponse *)resultObject status]]; } else [self debugWithFormat:@"call produced result: %@", resultObject]; } } resultObject = [resultObject retain]; [pool release]; /* deliver result */ return [resultObject autorelease]; } /* logging */ - (NSString *)loggingPrefix { return @"[obj-mth-dispatch]"; } - (BOOL)isDebuggingEnabled { return debugOn ? YES : NO; } /* description */ - (NSString *)description { NSMutableString *ms; ms = [NSMutableString stringWithCapacity:64]; [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass((Class)*(void**)self)]; if (self->object) [ms appendFormat:@" object=%@", self->object]; else [ms appendString:@" "]; [ms appendString:@">"]; return ms; } @end /* SoObjectMethodDispatcher */