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
24 #include "SoClassRegistry.h"
26 #include "SoSecurityManager.h"
27 #include <EOControl/EOClassDescription.h>
28 #include <NGObjWeb/WOContext.h>
29 #include <NGObjWeb/WOApplication.h>
30 #include <NGObjWeb/WORequest.h>
33 @interface NSObject(Folders)
37 static NSString *SoRootURLVarKey = @"SoRootURL";
39 @implementation NSObject(SoObject)
41 static int debugLookup = -1;
42 static int debugBaseURL = -1;
43 static void _initialize(void) {
44 if (debugLookup == -1) {
45 debugLookup = [[NSUserDefaults standardUserDefaults]
46 boolForKey:@"SoDebugKeyLookup"] ? 1 : 0;
48 if (debugBaseURL == -1) {
49 debugBaseURL = [[NSUserDefaults standardUserDefaults]
50 boolForKey:@"SoDebugBaseURL"] ? 1 : 0;
56 + (SoClass *)soClass {
57 static SoClassRegistry *registry = nil; // THREAD
59 registry = [[SoClassRegistry sharedClassRegistry] retain];
60 return [registry soClassForClass:self];
62 - (SoClass *)soClass {
63 return [[self class] soClass];
65 - (NSString *)soClassName {
66 return [[self soClass] className];
69 + (SoClassSecurityInfo *)soClassSecurityInfo {
70 return [[self soClass] soClassSecurityInfo];
73 - (NSClassDescription *)soClassDescription {
74 return [[self soClass] soClassDescription];
86 - (id)callOnObject:(id)_client inContext:(id)_ctx {
90 - (NSString *)defaultMethodNameInContext:(id)_ctx {
93 - (id)lookupDefaultMethod {
96 // TODO: lookupDefaultMethod should be rewritten to take a context!
97 ctx = [[WOApplication application] context];
99 // TODO: we might want to return a redirect?!
101 return [self lookupName:[self defaultMethodNameInContext:ctx]
108 - (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
109 /* this corresponds to Zope's/Pythons __hasattr__() */
110 if ([[self soClass] hasKey:_key inContext:_ctx])
112 if ([[self toOneRelationshipKeys] containsObject:_key])
117 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
118 /* this corresponds to Zope's/Pythons __getattr__() */
123 [self debugWithFormat:@"lookup key '%@'", _key];
125 /* we might want to cache class methods ? */
126 if ((value = [[self soClass] lookupKey:_key inContext:_ctx]) == nil) {
128 [self logWithFormat:@" did not find key '%@' in SoClass: %@",
129 _key, [self soClass]];
132 if ([[self toOneRelationshipKeys] containsObject:_key]) {
135 @" %@ is a toOneRelationshipKey (use -valueForKey:)", _key];
137 value = [self valueForKey:_key];
142 if ((value = [value bindToObject:self inContext:_ctx]) == nil) {
144 [self logWithFormat:@" value from class did not bind: %@",
149 else if (_flag) { /* try to acquire from container */
151 [self logWithFormat:@" try to acquire %@ from container ...", _key];
152 value = [[self container] lookupName:_key inContext:_ctx acquire:YES];
155 if (debugLookup) [self logWithFormat:@" looked up value: %@", value];
159 - (NSException *)validateName:(NSString *)_key inContext:(id)_ctx {
160 static SoSecurityManager *sm = nil;
161 if (sm == nil) sm = [[SoSecurityManager sharedSecurityManager] retain];
162 return [sm validateName:_key ofObject:self inContext:_ctx];
167 - (id)bindToObject:(id)_object inContext:(id)_ctx {
173 - (NSString *)ownerInContext:(id)_ctx {
174 /* objects are not owned by default, suggest to inherit owner */
175 return [[self container] ownerInContext:_ctx];
177 - (id)authenticatorInContext:(id)_ctx {
178 return [[_ctx application] authenticatorInContext:_ctx];
186 - (void)detachFromContainer {
188 - (NSString *)nameInContainer {
192 - (NSArray *)objectContainmentStack {
196 if ((object = [self container]) == nil)
198 return [NSArray arrayWithObject:self];
200 ma = [[NSMutableArray alloc] initWithCapacity:16];
201 for (object = self; object; object = [object container])
202 [ma insertObject:(object ? object : (id)[NSNull null]) atIndex:0];
204 object = [ma shallowCopy];
206 return [object autorelease];
209 - (NSArray *)reversedPathArrayToSoObject {
211 id object, nextObject;
213 if ((object = [self container]) == nil)
215 return [NSArray array];
217 ma = [NSMutableArray arrayWithCapacity:16];
218 for (object = self; (nextObject = [object container]); object = nextObject) {
221 oname = [object nameInContainer];
222 [ma addObject:(oname ? oname : (id)[NSNull null])];
226 - (NSArray *)pathArrayToSoObject {
230 if ((pathArray = [self reversedPathArrayToSoObject]) == nil)
233 e = [pathArray reverseObjectEnumerator];
234 pathArray = [[[NSArray alloc] initWithObjectsFromEnumerator:e] autorelease];
238 - (NSString *)baseURLInContext:(id)_ctx {
243 // TODO: should we check the traversal path?
245 if ((parent = [self container]) != nil) {
246 /* Note: cannot use -stringByAppendingPathComponent: on OSX! */
249 if (parent == self) {
251 @"WARNING: container==object in baseURL calculation (loop?): %@",
255 baseURL = [parent baseURLInContext:_ctx];
256 if (![baseURL hasSuffix:@"/"])
257 baseURL = [baseURL stringByAppendingString:@"/"];
259 name = [[self nameInContainer] stringByEscapingURL];
260 baseURL = [baseURL stringByAppendingString:name];
263 [self logWithFormat:@"baseURL(%@,%@): %@",
264 [self nameInContainer], [[self container] baseURL], baseURL];
268 baseURL = [self rootURLInContext:_ctx];
270 [self logWithFormat:@"ROOT baseURL(no container, name=%@): %@",
271 [self nameInContainer], baseURL];
275 /* add a trailing slash for folders */
277 if (![baseURL hasSuffix:@"/"]) {
278 if ([self respondsToSelector:@selector(isFolderish)]) {
279 if ([self isFolderish])
280 baseURL = [baseURL stringByAppendingString:@"/"];
286 - (NSString *)rootURLInContext:(id)_ctx {
288 BOOL isHTTPS = NO; // TODO: what about https??
295 if ((rootURL = [(WOContext *)_ctx objectForKey:SoRootURLVarKey]) != nil) {
297 [self logWithFormat:@" using root-url from context (SoRootURL): %@",
303 // TODO: this is somewhat weird, why don't we use WOContext for URL gen.?
305 rq = [(WOContext *)_ctx request];
306 port = [[rq headerForKey:@"x-webobjects-server-port"] intValue];
308 /* TODO: how to handle Evolution bug which sends invalid port ? */
310 static BOOL didWarn = NO;
313 @"WARNING(%s:%i): got an empty port, probably buggy "
314 @"SOUP host header!",
315 __PRETTY_FUNCTION__, __LINE__];
321 ms = [[NSMutableString alloc] initWithCapacity:128];
323 if ((tmp = [rq headerForKey:@"host"])) {
324 /* check whether we have a host header with port */
325 if ([tmp rangeOfString:@":"].length == 0)
331 [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"];
332 [ms appendString:isHTTPS ? @"https://" : @"http://"];
333 [ms appendString:tmp];
335 else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"])) {
336 /* sometimes the URL is just wrong! (suggests port 80) */
337 if ([tmp hasSuffix:@":0"] && [tmp length] > 2) // TODO: bad bad bad
338 tmp = [tmp substringToIndex:([tmp length] - 2)];
339 [ms appendString:tmp];
342 [ms appendString:isHTTPS ? @"https://" : @"http://"];
344 [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]];
345 if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0)
346 [ms appendFormat:@":%i", port];
348 if (![ms hasSuffix:@"/"]) [ms appendString:@"/"];
350 /* appname, two cases: */
351 /* a) direct access, eg /MyFolder */
352 /* b) access via app, eg /MyApp/so/MyFolder */
353 [ms appendString:[rq applicationName]];
354 [ms appendString:@"/"];
357 rootURL = [[ms copy] autorelease];
360 [self logWithFormat:@" constructed root-url: %@", rootURL];
362 /* some hack for the request handler? */
363 rh = [rq requestHandlerKey];
364 if ([[[_ctx application] registeredRequestHandlerKeys] containsObject:rh])
365 rootURL = [rootURL stringByAppendingFormat:@"%@/", rh];
368 [self logWithFormat:@" setting root-url in context (SoRootURL): %@",
371 [(WOContext *)_ctx setObject:rootURL forKey:SoRootURLVarKey];
375 - (NSString *)baseURL {
376 /* you should use the context method ! */
377 return [self baseURLInContext:[[WOApplication application] context]];
380 @end /* NSObject(SoObject) */
382 @implementation WOApplication(Authenticator)
384 - (NSString *)ownerInContext:(id)_ctx {
385 /* objects are not owned by default */
388 - (id)authenticatorInContext:(id)_ctx {
392 @end /* WOApplication(Authenticator) */