2 Copyright (C) 2000-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
22 #include <NGObjWeb/WOApplication.h>
23 #include "WOContext+private.h"
24 #include "WOElement+private.h"
25 #include "WOComponent+private.h"
26 #include <NGObjWeb/WOAdaptor.h>
27 #include <NGObjWeb/WORequest.h>
28 #include <NGObjWeb/WORequestHandler.h>
29 #include <NGObjWeb/WOResourceManager.h>
30 #include <NGObjWeb/WOResponse.h>
31 #include <NGObjWeb/WOSession.h>
32 #include <NGObjWeb/WOSessionStore.h>
33 #include <NGObjWeb/WOStatisticsStore.h>
34 #include <NGObjWeb/WODynamicElement.h>
35 #include <NGObjWeb/WOTemplate.h>
36 #import <EOControl/EOControl.h>
40 @interface WOApplication(PrivateMethods)
41 - (id)_loadComponentDefinitionWithName:(NSString *)_name
42 language:(NSArray *)_langs;
43 - (NSDictionary *)memoryStatistics;
46 static NSRecursiveLock *classLock = nil;
47 static BOOL perflog = NO;
48 static Class NSDateClass = Nil;
49 static Class WOTemplateClass = Nil;
50 static BOOL debugOn = NO;
51 static NSString *rapidTurnAroundPath = nil;
53 @interface WOSessionStore(SnStore)
54 - (void)performExpirationCheck:(NSTimer *)_timer;
57 @implementation WOApplication
60 return [super version] + 5 /* v6 */;
67 clazz = NSClassFromString(@"SNSConnection");
68 c = [(id<NSObject>)clazz performSelector:@selector(defaultSNSConnection)];
71 NSLog(@"could not connect SNS, exiting ..");
75 NSLog(@"SNS enabled");
78 + (void)_initializeWOApp {
79 static BOOL isInitialized = NO;
80 NSAutoreleasePool *pool;
83 if (isInitialized) return;
87 pool = [[NSAutoreleasePool alloc] init];
88 debugOn = [WOApplication isDebuggingEnabled];
90 if (classLock == nil) classLock = [[NSRecursiveLock alloc] init];
91 ud = [NSUserDefaults standardUserDefaults];
93 /* setup SNSConnection */
95 if ([ud boolForKey:@"WOContactSNS"])
98 NSLog(@"SNS support disabled.");
100 NSDateClass = [NSDate class];
101 WOTemplateClass = [WOTemplate class];
103 perflog = [ud boolForKey:@"WOProfileApplication"];
104 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
109 /* old license checks */
111 - (NSCalendarDate *)appExpireDate {
112 // TODO: can we remove that?
115 - (BOOL)isLicenseExpired {
116 // TODO: can we remove that?
122 - (NSString *)_lookupAppPath {
123 static NSString *suffix = nil;
124 static BOOL appPathMissing = NO;
133 ud = [NSUserDefaults standardUserDefaults];
135 // Check if appPath has been forced
136 result = [ud stringForKey:@"WOProjectDirectory"];
141 suffix = [ud stringForKey:@"WOApplicationSuffix"];
143 fm = [NSFileManager defaultManager];
144 cwd = [fm currentDirectoryPath];
146 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
147 result = [[NGBundle mainBundle] bundlePath];
148 //NSLog(@"%s: check path '%@'", __PRETTY_FUNCTION__, result);
153 if ([result hasSuffix:suffix]) {
154 /* started app inside of .woa directory */
155 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
156 result = [[NGBundle mainBundle] bundlePath];
162 NSString *wrapperName;
164 wrapperName = [self->name stringByAppendingString:suffix];
166 /* take a look whether ./AppName.woa exists */
167 result = [result stringByAppendingPathComponent:wrapperName];
168 if (![fm fileExistsAtPath:result]) {
169 /* lookup in process-path */
175 pi = [NSProcessInfo processInfo];
176 env = [pi environment];
177 if ([env objectForKey:@"GNUSTEP_SYSTEM_ROOT"] != nil) {
178 isFlattened = [[[env objectForKey:@"GNUSTEP_FLATTENED"]
179 lowercaseString] isEqualToString:@"yes"];
181 else /* default to flattened if no GNUstep runtime is set */
184 ppath = [[pi arguments] objectAtIndex:0];
185 ppath = [ppath stringByDeletingLastPathComponent]; // del exe-name
188 ppath = [ppath stringByDeletingLastPathComponent]; // lib-combo
189 ppath = [ppath stringByDeletingLastPathComponent]; // os
190 ppath = [ppath stringByDeletingLastPathComponent]; // cpu
192 if ([ppath hasSuffix:suffix])
197 if (![fm fileExistsAtPath:result]) {
198 [self debugWithFormat:@"%s: missing path '%@'",
199 __PRETTY_FUNCTION__, result];
200 appPathMissing = YES;
207 + (NSString *)defaultRequestHandlerClassName {
208 return @"WOComponentRequestHandler";
211 - (void)_logDefaults {
217 ud = [NSUserDefaults standardUserDefaults];
218 keys = [[ud dictionaryRepresentation] allKeys];
219 keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
221 e = [keys objectEnumerator];
222 while((key = [e nextObject]) != nil) {
223 if ([key hasPrefix:@"WO"] || [key isEqualToString:@"NSProjectSearchPath"])
224 NSLog(@"%@ = %@", key, [[ud objectForKey:key] description]);
228 - (id)initWithName:(NSString *)_name {
229 [WOApplication _initializeWOApp];
231 if ((self = [super init])) {
233 WORequestHandler *rh;
236 self->name = [_name copy];
238 ud = [NSUserDefaults standardUserDefaults];
240 [self setPageCacheSize:[ud integerForKey:@"WOPageCacheSize"]];
241 [self setPermanentPageCacheSize:
242 [ud integerForKey:@"WOPermanentPageCacheSize"]];
244 [self setPageRefreshOnBacktrackEnabled:
245 [[ud objectForKey:@"WOPageRefreshOnBacktrack"] boolValue]];
247 [self setCachingEnabled:[WOApplication isCachingEnabled]];
249 /* setup request handlers */
251 self->defaultRequestHandler =
252 [[NSClassFromString([[self class] defaultRequestHandlerClassName])
255 self->requestHandlerRegistry =
256 NSCreateMapTable(NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 8);
258 rk = [WOApplication componentRequestHandlerKey];
260 rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
262 rh = [[NSClassFromString(@"WOComponentRequestHandler") alloc] init];
264 if ([rk length] > 0 && (rh != nil))
265 [self registerRequestHandler:rh forKey:rk];
266 [rh release]; rh = nil;
268 rk = [WOApplication directActionRequestHandlerKey];
269 rh = [[NSClassFromString(@"WODirectActionRequestHandler") alloc] init];
270 if ([rk length] > 0 && rh != nil)
271 [self registerRequestHandler:rh forKey:rk];
272 [rh release]; rh = nil;
274 if ((rh = [[NSClassFromString(@"WOResourceRequestHandler") alloc] init])) {
275 rk = [WOApplication resourceRequestHandlerKey];
277 [self registerRequestHandler:rh forKey:rk];
278 [self registerRequestHandler:rh forKey:@"WebServerResources"];
280 [self registerRequestHandler:rh forKey:@"Resources"];
282 [rh release]; rh = nil;
285 /* setup session store */
287 self->iSessionStore =
288 [[NSClassFromString([self sessionStoreClassName]) alloc] init];
290 /* setup statistics store */
292 self->iStatisticsStore = [[WOStatisticsStore alloc] init];
294 /* register timers */
295 self->expirationTimer =
296 [[NSTimer scheduledTimerWithTimeInterval:
297 [[ud objectForKey:@"WOExpirationTimeInterval"] intValue]
299 selector:@selector(performExpirationCheck:)
304 if ([ud boolForKey:@"WOLogDefaultsOnStartup"])
307 [[NSNotificationCenter defaultCenter]
308 postNotificationName:
309 WOApplicationWillFinishLaunchingNotification
316 return [self initWithName:[[[NSProcessInfo processInfo]
318 stringByDeletingPathExtension]];
322 [[NSNotificationCenter defaultCenter] removeObserver:self];
324 [self->expirationTimer invalidate];
326 if (self->requestHandlerRegistry)
327 NSFreeMapTable(self->requestHandlerRegistry);
329 [self->expirationTimer release];
330 [self->resourceManager release];
331 [self->iSessionStore release];
332 [self->defaultRequestHandler release];
333 [self->path release];
334 [self->name release];
335 [self->instanceNumber release];
339 - (void)processHupSignal:(int)_signal {
340 /* this isn't called immediatly */
341 [self logWithFormat:@"terminating on SIGHUP ..."];
350 - (BOOL)monitoringEnabled {
354 static BOOL missingPath = NO;
355 if (missingPath) return nil;
356 if (self->path == nil) {
357 if ((self->path = [[self _lookupAppPath] copy]) == nil) {
359 [self debugWithFormat:
360 @"WARNING: could not find wrapper of application !"];
369 - (NSString *)number {
370 if (self->instanceNumber == nil) {
373 if ((num = [[NSUserDefaults standardUserDefaults] objectForKey:@"n"])) {
374 self->instanceNumber = [[num stringValue] copy];
378 #if defined(__MINGW32__)
379 pid = (unsigned)GetCurrentProcessId();
381 pid = (unsigned)getpid();
383 self->instanceNumber = [[NSString alloc] initWithFormat:@"%d", pid];
386 return self->instanceNumber;
389 - (void)_setCurrentContext:(WOContext *)_ctx {
390 NSMutableDictionary *info;
392 info = [[NSThread currentThread] threadDictionary];
394 [info setObject:_ctx forKey:@"WOContext"];
396 [info removeObjectForKey:@"WOContext"];
398 - (WOContext *)context {
403 if ((t = [NSThread currentThread]) == nil) {
404 [self logWithFormat:@"ERROR: missing current thread !!!"];
407 if ((td = [t threadDictionary]) == nil) {
409 @"ERROR: missing current thread's dictionary (thread=%@) !!!",
414 return [td objectForKey:@"WOContext"];
417 /* request handlers */
419 - (void)registerRequestHandler:(WORequestHandler *)_hdl
420 forKey:(NSString *)_key
423 NSMapInsert(self->requestHandlerRegistry, _key, _hdl);
426 - (void)removeRequestHandlerForKey:(NSString *)_key {
427 if (_key == nil) return;
429 NSMapRemove(self->requestHandlerRegistry, _key);
433 - (void)setDefaultRequestHandler:(WORequestHandler *)_hdl {
435 ASSIGN(self->defaultRequestHandler, _hdl);
438 - (WORequestHandler *)defaultRequestHandler {
439 return self->defaultRequestHandler;
441 - (WORequestHandler *)requestHandlerForKey:(NSString *)_key {
442 WORequestHandler *handler;
445 handler = [(id)NSMapGet(self->requestHandlerRegistry, _key) retain];
447 handler = [[self defaultRequestHandler] retain];
450 return [handler autorelease];
453 - (NSArray *)registeredRequestHandlerKeys {
454 NSMutableArray *array = [NSMutableArray arrayWithCapacity:16];
457 WORequestHandler *handler;
460 e = NSEnumerateMapTable(self->requestHandlerRegistry);
461 while (NSNextMapEnumeratorPair(&e, (void**)&key, (void**)&handler))
462 [array addObject:key];
465 return [[array copy] autorelease];
468 - (WORequestHandler *)handlerForRequest:(WORequest *)_request {
469 WORequestHandler *handler;
472 if ((key = [_request requestHandlerKey]) == nil)
473 return [self defaultRequestHandler];
475 handler = NSMapGet(self->requestHandlerRegistry, key);
476 return (handler != nil) ? handler : [self defaultRequestHandler];
481 - (WOSession *)_initializeSessionInContext:(WOContext *)_ctx {
484 sn = [self createSessionForRequest:[_ctx request]];
485 [_ctx setSession:sn];
487 if ([sn respondsToSelector:@selector(prepare)]) {
489 [self debugWithFormat:@"calling -prepare on session .."];
491 [sn performSelector:@selector(prepare)];
494 [sn _awakeWithContext:_ctx];
496 [[NSNotificationCenter defaultCenter]
497 postNotificationName:WOSessionDidCreateNotification
499 return [sn autorelease];
502 - (NSString *)sessionIDFromRequest:(WORequest *)_request {
505 if (_request == nil) return nil;
507 /* first look into form values */
508 if ((sessionId = [_request formValueForKey:WORequestValueSessionID])) {
509 if ([sessionId length] > 0)
513 /* now look into the cookies */
514 if ((sessionId = [_request cookieValueForKey:[self name]])) {
515 if ([sessionId respondsToSelector:@selector(objectEnumerator)]) {
518 e = [(id)sessionId objectEnumerator];
519 while ((sessionId = [e nextObject])) {
520 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
525 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
533 - (NSString *)createSessionIDForSession:(WOSession *)_session {
534 /* session id must be 18 chars long for snsd to work ! */
535 static unsigned int sessionCount = 0;
537 unsigned char buf[20];
540 sprintf(buf, "%04X%04X%02X%08X",
541 [[self number] intValue], getpid(), sessionCount,
542 (unsigned int)time(NULL));
543 wosid = [NSString stringWithCString:buf];
547 - (WOSession *)createSessionForRequest:(WORequest *)_request {
548 if ([self respondsToSelector:@selector(createSession)]) {
549 /* call deprecated method */
550 NSLog(@"WARNING: calling deprecated -createSession ..");
551 return [self createSession];
556 if ((snClass = NSClassFromString(@"Session")) == Nil)
557 snClass = [WOSession class];
559 return [[snClass alloc] init];
563 - (WOSession *)restoreSessionWithID:(NSString *)_sid
564 inContext:(WOContext *)_ctx
570 if ([self respondsToSelector:@selector(restoreSession)]) {
571 /* call deprecated method */
572 NSLog(@"WARNING: calling deprecated -restoreSession ..");
573 return [self restoreSession];
577 WOSessionStore *store;
579 if ((store = [self sessionStore]) == nil) {
580 [self logWithFormat:@"missing session store ..."];
583 session = [store restoreSessionWithID:_sid request:[_ctx request]];
585 [_ctx setSession:session];
586 [session _awakeWithContext:_ctx];
589 [self debugWithFormat:@"did not find a session for sid '%@'", _sid];
596 [[NSNotificationCenter defaultCenter]
597 postNotificationName:WOSessionDidRestoreNotification
601 if ([_sid hasPrefix:@"("]) {
604 sid = [_sid propertyList];
606 if ([sid respondsToSelector:@selector(objectEnumerator)]) {
609 [self logWithFormat:@"got multiple session IDs !"];
611 e = [sid objectEnumerator];
612 while ((_sid = [e nextObject])) {
613 if ([_sid isEqualToString:@"nil"])
616 if ((session = [self restoreSessionWithID:_sid inContext:_ctx]))
619 //NSLog(@"WARNING: did not find session for sid %@", _sid);
626 - (void)saveSessionForContext:(WOContext *)_ctx {
627 NSTimeInterval startSave = 0.0;
630 startSave = [[NSDateClass date] timeIntervalSince1970];
632 if ([self respondsToSelector:@selector(saveSession:)]) {
633 /* call deprecated method */
634 NSLog(@"WARNING: calling deprecated -saveSession: ..");
635 [self saveSession:[_ctx session]];
641 NSTimeInterval startSnSleep = 0.0, startStore = 0.0;
646 startSnSleep = [[NSDateClass date] timeIntervalSince1970];
648 /* put session to sleep */
649 [sn _sleepWithContext:_ctx];
653 rt = [[NSDateClass date] timeIntervalSince1970] - startSnSleep;
654 NSLog(@" [woapp]: session -sleep took %4.3fs.",
655 rt < 0.0 ? -1.0 : rt);
658 if ([sn isTerminating]) {
659 [[NSNotificationCenter defaultCenter]
660 postNotificationName:
661 WOSessionDidTerminateNotification
666 startStore = [[NSDateClass date] timeIntervalSince1970];
668 [[self sessionStore] saveSessionForContext:_ctx];
672 rt = [[NSDateClass date] timeIntervalSince1970] - startStore;
673 NSLog(@" [woapp]: storing sn in store took %4.3fs.",
674 rt < 0.0 ? -1.0 : rt);
681 rt = [[NSDateClass date] timeIntervalSince1970] - startSave;
682 NSLog(@"[woapp]: saveSessionForContext took %4.3fs.",
683 rt < 0.0 ? -1.0 : rt);
687 - (void)refuseNewSessions:(BOOL)_flag {
688 self->appFlags.doesRefuseNewSessions = _flag ? 1 : 0;
690 - (BOOL)isRefusingNewSessions {
691 return self->appFlags.doesRefuseNewSessions;
693 - (int)activeSessionsCount {
694 return [[self sessionStore] activeSessionsCount];
697 - (void)setSessionStore:(WOSessionStore *)_store {
698 ASSIGN(self->iSessionStore, _store);
700 - (NSString *)sessionStoreClassName {
701 return [[NSUserDefaults standardUserDefaults] stringForKey:@"WOSessionStore"];
703 - (WOSessionStore *)sessionStore {
704 return self->iSessionStore;
707 - (void)setMinimumActiveSessionsCount:(int)_minimum {
708 self->minimumActiveSessionsCount = _minimum;
710 - (int)minimumActiveSessionsCount {
711 return self->minimumActiveSessionsCount;
714 - (void)performExpirationCheck:(NSTimer *)_timer {
717 /* let session store check for expiration ... */
719 ss = [self sessionStore];
720 if ([ss respondsToSelector:@selector(performExpirationCheck:)])
721 [ss performExpirationCheck:_timer];
723 /* check whether application should terminate ... */
725 if ([self isRefusingNewSessions] &&
726 ([self activeSessionsCount] < [self minimumActiveSessionsCount])) {
727 /* check whether the application instance is still valid .. */
728 [self debugWithFormat:
729 @"application terminates because it refuses new sessions and "
730 @"the active session count (%i) is below the minimum (%i).",
731 [self activeSessionsCount], [self minimumActiveSessionsCount]];
736 - (WOSession *)session {
737 return [[self context] session];
740 - (WOResponse *)handleSessionCreationErrorInContext:(WOContext *)_ctx {
741 WOResponse *response = [_ctx response];
745 pid = GetCurrentProcessId();
750 if ([self respondsToSelector:@selector(handleSessionCreationError)]) {
751 NSLog(@"WARNING: called deprecated -handleSessionCreationError method");
752 return [self handleSessionCreationError];
755 [self logWithFormat:@"could not create session for context %@", _ctx];
757 [response setStatus:200];
758 [response appendContentString:@"<h4>Session Creation Error</h4>\n<pre>"];
759 [response appendContentString:
760 @"Application Instance failed to create session."];
761 [response appendContentHTMLString:
762 [NSString stringWithFormat:
763 @" application: %@\n"
770 [[_ctx request] adaptorPrefix],
774 [[_ctx request] description]]];
775 [response appendContentString:@"</pre>"];
779 - (WOResponse *)handleSessionRestorationErrorInContext:(WOContext *)_ctx {
780 if ([self respondsToSelector:@selector(handleSessionRestorationError)]) {
781 NSLog(@"WARNING: calling deprecated -handleSessionRestorationError "
783 return [self handleSessionRestorationError];
786 [self logWithFormat:@"could not restore session for context %@", _ctx];
792 - (void)setStatisticsStore:(WOStatisticsStore *)_statStore {
793 ASSIGN(self->iStatisticsStore, _statStore);
795 - (WOStatisticsStore *)statisticsStore {
796 return self->iStatisticsStore;
799 - (bycopy NSDictionary *)statistics {
800 return [[self statisticsStore] statistics];
805 - (void)setResourceManager:(WOResourceManager *)_manager {
806 ASSIGN(self->resourceManager, _manager);
808 - (WOResourceManager *)resourceManager {
809 if (self->resourceManager == nil) {
813 if ([(p = [self path]) length] > 0)
814 [self logWithFormat:@"setup WOResourceManager at path '%@' ...", p];
819 self->resourceManager =
820 [(WOResourceManager *)[WOResourceManager alloc] initWithPath:p];
822 return self->resourceManager;
827 WOContext *ctx = [self context];
829 n = [[ctx request] applicationName];
830 n = [@"/" stringByAppendingString:n ? n : [self name]];
832 return [NSURL URLWithString:n relativeToURL:[ctx baseURL]];
835 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
837 return [[self resourceManager] pathForResourceNamed:_name ofType:_type];
840 - (NSString *)stringForKey:(NSString *)_key
841 inTableNamed:(NSString *)_tableName
842 withDefaultValue:(NSString *)_default
845 return [[self resourceManager] stringForKey:_key
846 inTableNamed:_tableName
847 withDefaultValue:_default
849 [(WOSession *)[self session] languages]];
861 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
862 if ([_ctx hasSession])
863 [[_ctx session] takeValuesFromRequest:_req inContext:_ctx];
867 if ((page = [_ctx page])) {
868 WOContext_enterComponent(_ctx, page, nil);
869 [page takeValuesFromRequest:_req inContext:_ctx];
870 WOContext_leaveComponent(_ctx, page);
875 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
878 if ([_ctx hasSession])
879 result = [[_ctx session] invokeActionForRequest:_rq inContext:_ctx];
883 if ((page = [_ctx page])) {
884 WOContext_enterComponent(_ctx, page, nil);
885 result = [[_ctx page] invokeActionForRequest:_rq inContext:_ctx];
886 WOContext_leaveComponent(_ctx, page);
894 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
895 if ([_ctx hasSession])
896 [[_ctx session] appendToResponse:_response inContext:_ctx];
900 if ((page = [_ctx page])) {
901 WOContext_enterComponent(_ctx, page, nil);
902 [page appendToResponse:_response inContext:_ctx];
903 WOContext_leaveComponent(_ctx, page);
907 if(rapidTurnAroundPath != nil) {
910 if((page = [_ctx page])) {
913 template = [page _woComponentTemplate];
914 if([template isKindOfClass:WOTemplateClass]) {
917 _path = [[(WOTemplate *)template url] path];
918 [_response setHeader:_path
919 forKey:@"x-sope-template-path"];
928 - (WOElement *)dynamicElementWithName:(NSString *)_name
929 associations:(NSDictionary *)_associations
930 template:(WOElement *)_template
931 languages:(NSArray *)_languages
933 WOElement *element = nil;
934 Class dynamicElementClass = NSClassFromString(_name);
936 if (dynamicElementClass == Nil) {
937 NSLog(@"WARNING: did not find dynamic element class %@ !", _name);
940 if (![dynamicElementClass isDynamicElement]) {
941 NSLog(@"WARNING: class %@ is not a dynamic element class !", _name);
945 element = [[dynamicElementClass allocWithZone:[_template zone]]
947 associations:_associations
951 - (WOElement *)dynamicElementWithName:(NSString *)_name
952 associations:(NSDictionary *)_associations
953 template:(WOElement *)_template
955 return [self dynamicElementWithName:_name
956 associations:_associations
958 languages:[(WOSession *)[self session] languages]];
963 - (void)setPageRefreshOnBacktrackEnabled:(BOOL)_flag {
964 self->appFlags.isPageRefreshOnBacktrackEnabled = _flag ? 1 : 0;
966 - (BOOL)isPageRefreshOnBacktrackEnabled {
967 return self->appFlags.isPageRefreshOnBacktrackEnabled ? YES : NO;
970 - (void)setCachingEnabled:(BOOL)_flag {
971 self->appFlags.isCachingEnabled = _flag ? 1 : 0;
973 - (BOOL)isCachingEnabled {
974 // component definition caching
975 return self->appFlags.isCachingEnabled ? YES : NO;
978 - (void)setPageCacheSize:(int)_size {
979 self->pageCacheSize = _size;
981 - (int)pageCacheSize {
982 return self->pageCacheSize;
984 - (void)setPermanentPageCacheSize:(int)_size {
985 self->permanentPageCacheSize = _size;
987 - (int)permanentPageCacheSize {
988 return self->permanentPageCacheSize;
991 - (WOComponent *)pageWithName:(NSString *)_name {
993 return [self pageWithName:_name inContext:[self context]];
996 - (WOComponent *)_pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
998 OSX profiling: 3.4% of dispatchRequest?
999 3.0% rm -pageWithName..
1000 1.5% def instantiate
1001 1.3% initWithName:...
1002 0.76% initWithContent:.. (0.43 addobserver)
1003 0.76% rm defForComp (0.43% touch)
1005 0.11% ctx -component
1010 NSAutoreleasePool *pool;
1011 WOResourceManager *rm;
1014 NSDictionary *start, *stop;
1015 start = [self memoryStatistics];
1018 pool = [[NSAutoreleasePool alloc] init];
1020 languages = [_ctx hasSession]
1021 ? [(WOSession *)[_ctx session] languages]
1022 : [[_ctx request] browserLanguages];
1024 if ((rm = [[_ctx component] resourceManager]) == nil)
1025 rm = [self resourceManager];
1027 page = [rm pageWithName:(_name != nil ? _name : @"Main")
1028 languages:languages];
1029 [page ensureAwakeInContext:_ctx];
1031 page = [page retain];
1036 int rss, vmsize, lib;
1037 stop = [self memoryStatistics];
1038 rss = [[stop objectForKey:@"VmRSS"] intValue] -
1039 [[start objectForKey:@"VmRSS"] intValue];
1040 vmsize = [[stop objectForKey:@"VmSize"] intValue] -
1041 [[start objectForKey:@"VmSize"] intValue];
1042 lib = [[stop objectForKey:@"VmLib"] intValue] -
1043 [[start objectForKey:@"VmLib"] intValue];
1044 NSLog(@"loaded component %@; rss=%i vm=%i lib=%i.", _name, rss,vmsize,lib);
1048 return [page autorelease];
1050 - (WOComponent *)pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
1051 return [self _pageWithName:_name inContext:_ctx];
1053 - (WOComponent *)pageWithName:(NSString *)_name forRequest:(WORequest *)_req {
1054 WOResourceManager *rm;
1056 if ((rm = [self resourceManager]) == nil)
1059 return [rm pageWithName:(_name != nil) ? _name : @"Main"
1060 languages:[_req browserLanguages]];
1063 - (void)savePage:(WOComponent *)_page {
1065 [[[self context] session] savePage:_page];
1067 - (id)restorePageForContextID:(NSString *)_ctxId {
1069 return [[[self context] session] restorePageForContextID:_ctxId];
1072 - (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)_ctx {
1073 [self logWithFormat:
1074 @"could not restore page for context-id %@\n in context %@",
1075 [_ctx currentElementID], _ctx];
1077 /* return main page ... */
1078 return [[self pageWithName:nil inContext:_ctx] generateResponse];
1080 - (WOResponse *)handlePageRestorationError {
1082 return [self handlePageRestorationErrorInContext:[self context]];
1087 - (WOResponse *)handleException:(NSException *)_exc
1088 inContext:(WOContext *)_ctx
1090 WORequest *rq = [_ctx request];
1091 WOResponse *r = nil;
1093 if ([self respondsToSelector:@selector(handleException:)]) {
1094 NSLog(@"WARNING: calling deprecated -handleException method !");
1095 return [self handleException:_exc];
1100 static int doCore = -1;
1102 doCore = [[NSUserDefaults standardUserDefaults]
1103 boolForKey:@"WOCoreOnApplicationException"]
1107 [self logWithFormat:@"%@: caught (ctx=%@):\n %@.",
1115 [self logWithFormat:@"%@: caught (without context):\n %@.", self, _exc];
1118 else if (rq == nil) {
1119 [self logWithFormat:@"%@: caught (without request):\n %@.", self, _exc];
1123 static NSString *pageFormat =
1124 @"Application Server caught exception:\n\n"
1133 @" backtrace:\n%@\n";
1134 NSString *str = nil;
1137 [self logWithFormat:@"%@: caught:\n %@\nin context:\n %@.",
1140 #if LIB_FOUNDATION_LIBRARY
1141 if ([NSException respondsToSelector:@selector(backtrace)])
1142 bt = [NSException backtrace];
1145 if ((r = [WOResponse responseWithRequest:rq]) == nil)
1146 [self logWithFormat:@"could not create response !"];
1148 [r setHeader:@"text/html" forKey:@"content-type"];
1149 [r setHeader:@"no-cache" forKey:@"cache-control"];
1150 if(rapidTurnAroundPath != nil) {
1153 templateURL = [[_exc userInfo] objectForKey:@"templateURL"];
1154 if(templateURL != nil)
1155 [r setHeader:[templateURL path] forKey:@"x-sope-template-path"];
1158 str = [NSString stringWithFormat:pageFormat,
1160 ? [[_ctx session] sessionID]
1165 NSStringFromClass([_exc class]),
1168 [[_exc userInfo] description],
1171 [r appendContentString:@"<html><head><title>Caught exception</title></head><body><pre>\n"];
1172 [r appendContentHTMLString:str];
1173 [r appendContentString:@"</pre></body></html>\n"];
1180 - (BOOL)shouldTerminate {
1181 if (![self isRefusingNewSessions])
1183 if ([self activeSessionsCount] >= [self minimumActiveSessionsCount])
1186 /* check whether the application instance is still valid .. */
1187 [self debugWithFormat:
1188 @"application terminates because it refuses new sessions and "
1189 @"the active session count (%i) is below the minimum (%i).",
1190 [self activeSessionsCount], [self minimumActiveSessionsCount]];
1195 [self debugWithFormat:
1196 @"application terminates:\n"
1197 @" %i active sessions\n"
1198 @" %i minimum active sessions\n"
1199 @" refuses new session: %s",
1200 [self activeSessionsCount],
1201 [self minimumActiveSessionsCount],
1202 [self isRefusingNewSessions] ? "yes" : "no"];
1208 - (BOOL)isDebuggingEnabled {
1211 - (NSString *)loggingPrefix {
1212 return [NSString stringWithFormat:@"|%@%@|",
1214 [self isTerminating] ? @" terminating" : @""];
1219 #if !LIB_FOUNDATION_LIBRARY
1220 - (id)valueForUndefinedKey:(NSString *)_key {
1221 [self logWithFormat:@"WARNING: tried to access undefined KVC key: '%@'",
1229 + (Class)eoEditingContextClass {
1230 static Class eoEditingContextClass = Nil;
1231 static BOOL lookedUpForEOEditingContextClass = NO;
1233 if (!lookedUpForEOEditingContextClass) {
1234 eoEditingContextClass = NSClassFromString(@"EOEditingContext");
1235 lookedUpForEOEditingContextClass = YES;
1237 return eoEditingContextClass;
1240 + (BOOL)implementsEditingContexts {
1241 return [self eoEditingContextClass] != NULL ? YES : NO;
1246 - (NSString *)description {
1247 return [NSString stringWithFormat:@"<%@[0x%08X]: name=%@%@>",
1248 NSStringFromClass([self class]), self,
1250 [self isTerminating] ? @" terminating" : @""
1254 @end /* WOApplication */