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 "SoClassRegistry.h"
25 #include "SoSecurityManager.h"
26 #include "WOContext+SoObjects.h"
27 #include <EOControl/EOClassDescription.h>
28 #include <NGObjWeb/WOApplication.h>
29 #include <NGObjWeb/WORequest.h>
32 @interface NSObject(Folders)
36 @implementation NSObject(SoObject)
38 static int debugLookup = -1;
39 static int debugBaseURL = -1;
40 static void _initialize(void) {
41 if (debugLookup == -1) {
42 debugLookup = [[NSUserDefaults standardUserDefaults]
43 boolForKey:@"SoDebugKeyLookup"] ? 1 : 0;
45 if (debugBaseURL == -1) {
46 debugBaseURL = [[NSUserDefaults standardUserDefaults]
47 boolForKey:@"SoDebugBaseURL"] ? 1 : 0;
53 + (SoClass *)soClass {
54 static SoClassRegistry *registry = nil; // THREAD
56 registry = [[SoClassRegistry sharedClassRegistry] retain];
57 return [registry soClassForClass:self];
59 - (SoClass *)soClass {
60 return [[self class] soClass];
62 - (NSString *)soClassName {
63 return [[self soClass] className];
66 + (SoClassSecurityInfo *)soClassSecurityInfo {
67 return [[self soClass] soClassSecurityInfo];
70 - (NSClassDescription *)soClassDescription {
71 return [[self soClass] soClassDescription];
83 - (id)callOnObject:(id)_client inContext:(id)_ctx {
87 - (NSString *)defaultMethodNameInContext:(id)_ctx {
90 - (id)lookupDefaultMethod {
93 // TODO: lookupDefaultMethod should be rewritten to take a context!
94 ctx = [[WOApplication application] context];
96 // TODO: we might want to return a redirect?!
98 return [self lookupName:[self defaultMethodNameInContext:ctx]
105 - (BOOL)hasName:(NSString *)_key inContext:(id)_ctx {
106 /* this corresponds to Zope's/Pythons __hasattr__() */
107 if ([[self soClass] hasKey:_key inContext:_ctx])
109 if ([[self toOneRelationshipKeys] containsObject:_key])
114 - (id)lookupName:(NSString *)_key inContext:(id)_ctx acquire:(BOOL)_flag {
115 /* this corresponds to Zope's/Pythons __getattr__() */
120 [self debugWithFormat:@"lookup key '%@'", _key];
122 /* we might want to cache class methods ? */
123 if ((value = [[self soClass] lookupKey:_key inContext:_ctx]) == nil) {
125 [self logWithFormat:@" did not find key '%@' in SoClass: %@",
126 _key, [self soClass]];
129 if ([[self toOneRelationshipKeys] containsObject:_key]) {
132 @" %@ is a toOneRelationshipKey (use -valueForKey:)", _key];
134 value = [self valueForKey:_key];
139 if ((value = [value bindToObject:self inContext:_ctx]) == nil) {
141 [self logWithFormat:@" value from class did not bind: %@",
146 else if (_flag) { /* try to acquire from container */
148 [self logWithFormat:@" try to acquire %@ from container ...", _key];
149 value = [[self container] lookupName:_key inContext:_ctx acquire:YES];
152 if (debugLookup) [self logWithFormat:@" looked up value: %@", value];
156 - (NSException *)validateName:(NSString *)_key inContext:(id)_ctx {
157 static SoSecurityManager *sm = nil;
158 if (sm == nil) sm = [[SoSecurityManager sharedSecurityManager] retain];
159 return [sm validateName:_key ofObject:self inContext:_ctx];
164 - (id)bindToObject:(id)_object inContext:(id)_ctx {
170 - (NSString *)ownerInContext:(id)_ctx {
171 /* objects are not owned by default, suggest to inherit owner */
172 return [[self container] ownerInContext:_ctx];
174 - (id)authenticatorInContext:(id)_ctx {
175 return [[_ctx application] authenticatorInContext:_ctx];
183 - (void)detachFromContainer {
185 - (NSString *)nameInContainer {
189 - (NSArray *)objectContainmentStack {
193 if ((object = [self container]) == nil)
195 return [NSArray arrayWithObject:self];
197 ma = [[NSMutableArray alloc] initWithCapacity:16];
198 for (object = self; object; object = [object container])
199 [ma insertObject:(object ? object : (id)[NSNull null]) atIndex:0];
201 object = [ma shallowCopy];
203 return [object autorelease];
206 - (NSArray *)reversedPathArrayToSoObject {
208 id object, nextObject;
210 if ((object = [self container]) == nil)
212 return [NSArray array];
214 ma = [NSMutableArray arrayWithCapacity:16];
215 for (object = self; (nextObject = [object container]); object = nextObject) {
218 oname = [object nameInContainer];
219 [ma addObject:(oname ? oname : (id)[NSNull null])];
223 - (NSArray *)pathArrayToSoObject {
227 if ((pathArray = [self reversedPathArrayToSoObject]) == nil)
230 e = [pathArray reverseObjectEnumerator];
231 pathArray = [[[NSArray alloc] initWithObjectsFromEnumerator:e] autorelease];
235 - (NSString *)baseURLInContext:(id)_ctx {
240 // TODO: should we check the traversal path?
242 if ((parent = [self container]) != nil) {
243 /* Note: cannot use -stringByAppendingPathComponent: on OSX! */
246 if (parent == self) {
247 [self warnWithFormat:
248 @"container==object in baseURL calculation (loop?): %@",
252 baseURL = [parent baseURLInContext:_ctx];
253 if (![baseURL hasSuffix:@"/"])
254 baseURL = [baseURL stringByAppendingString:@"/"];
256 name = [[self nameInContainer] stringByEscapingURL];
257 baseURL = [baseURL stringByAppendingString:name];
260 [self logWithFormat:@"baseURL(%@,%@): %@",
261 [self nameInContainer], [[self container] baseURL], baseURL];
265 baseURL = [self rootURLInContext:_ctx];
267 [self logWithFormat:@"ROOT baseURL(no container, name=%@): %@",
268 [self nameInContainer], baseURL];
272 /* add a trailing slash for folders */
274 if (![baseURL hasSuffix:@"/"]) {
275 if ([self respondsToSelector:@selector(isFolderish)]) {
276 if ([self isFolderish])
277 baseURL = [baseURL stringByAppendingString:@"/"];
283 - (NSString *)rootURLInContext:(id)_ctx {
285 BOOL isHTTPS = NO; // TODO: what about https??
292 if ((rootURL = [_ctx rootURL]) != nil) {
294 [self logWithFormat:@" using root-url from context: %@",
300 // TODO: this is somewhat weird, why don't we use WOContext for URL gen.?
302 rq = [(WOContext *)_ctx request];
303 port = [[rq headerForKey:@"x-webobjects-server-port"] intValue];
305 /* TODO: how to handle Evolution bug which sends invalid port ? */
307 static BOOL didWarn = NO;
309 [self warnWithFormat:@"(%s:%i): got an empty port, probably buggy "
310 @"SOAP host header!",
311 __PRETTY_FUNCTION__, __LINE__];
317 ms = [[NSMutableString alloc] initWithCapacity:128];
319 if ((tmp = [rq headerForKey:@"host"])) {
320 /* check whether we have a host header with port */
321 if ([tmp rangeOfString:@":"].length == 0)
327 [[rq headerForKey:@"x-webobjects-server-url"] hasPrefix:@"https"];
328 [ms appendString:isHTTPS ? @"https://" : @"http://"];
329 [ms appendString:tmp];
331 else if ((tmp = [rq headerForKey:@"x-webobjects-server-url"])) {
332 /* sometimes the URL is just wrong! (suggests port 80) */
333 if ([tmp hasSuffix:@":0"] && [tmp length] > 2) // TODO: bad bad bad
334 tmp = [tmp substringToIndex:([tmp length] - 2)];
335 [ms appendString:tmp];
338 [ms appendString:isHTTPS ? @"https://" : @"http://"];
340 [ms appendString:[rq headerForKey:@"x-webobjects-server-name"]];
341 if ((isHTTPS ? (port != 443) : (port != 80)) && port != 0)
342 [ms appendFormat:@":%i", port];
344 if (![ms hasSuffix:@"/"]) [ms appendString:@"/"];
346 /* appname, two cases: */
347 /* a) direct access, eg /MyFolder */
348 /* b) access via app, eg /MyApp/so/MyFolder */
349 [ms appendString:[rq applicationName]];
350 if (![ms hasSuffix:@"/"]) [ms appendString:@"/"];
353 rootURL = [[ms copy] autorelease];
356 [self logWithFormat:@" constructed root-url: %@", rootURL];
358 /* some hack for the request handler? */
359 rh = [rq requestHandlerKey];
360 if ([[[_ctx application] registeredRequestHandlerKeys] containsObject:rh])
361 rootURL = [rootURL stringByAppendingFormat:@"%@/", rh];
364 [self logWithFormat:@" setting root-url in context: %@",
367 [(WOContext *)_ctx setRootURL:rootURL];
371 - (NSString *)baseURL {
372 /* you should use the context method ! */
373 return [self baseURLInContext:[[WOApplication application] context]];
376 @end /* NSObject(SoObject) */
378 @implementation WOApplication(Authenticator)
380 - (NSString *)ownerInContext:(id)_ctx {
381 /* objects are not owned by default */
384 - (id)authenticatorInContext:(id)_ctx {
388 @end /* WOApplication(Authenticator) */