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
23 #include <NGObjWeb/WOApplication.h>
24 #include "WOContext+private.h"
25 #include "WOElement+private.h"
26 #include "WOComponent+private.h"
27 #include <NGObjWeb/WOAdaptor.h>
28 #include <NGObjWeb/WORequest.h>
29 #include <NGObjWeb/WORequestHandler.h>
30 #include <NGObjWeb/WOResourceManager.h>
31 #include <NGObjWeb/WOResponse.h>
32 #include <NGObjWeb/WOSession.h>
33 #include <NGObjWeb/WOSessionStore.h>
34 #include <NGObjWeb/WOStatisticsStore.h>
35 #include <NGObjWeb/WODynamicElement.h>
36 #include <NGObjWeb/WOTemplate.h>
37 #import <EOControl/EOControl.h>
41 @interface WOApplication(PrivateMethods)
42 - (id)_loadComponentDefinitionWithName:(NSString *)_name
43 language:(NSArray *)_langs;
44 - (NSDictionary *)memoryStatistics;
47 static NSRecursiveLock *classLock = nil;
48 static BOOL perflog = NO;
49 static Class NSDateClass = Nil;
50 static Class WOTemplateClass = Nil;
51 static BOOL debugOn = NO;
52 static NSString *rapidTurnAroundPath = nil;
54 @interface WOSessionStore(SnStore)
55 - (void)performExpirationCheck:(NSTimer *)_timer;
58 @implementation WOApplication
61 return [super version] + 5 /* v6 */;
68 clazz = NSClassFromString(@"SNSConnection");
69 c = [(id<NSObject>)clazz performSelector:@selector(defaultSNSConnection)];
72 NSLog(@"could not connect SNS, exiting ..");
76 NSLog(@"SNS enabled");
79 + (void)_initializeWOApp {
80 static BOOL isInitialized = NO;
81 NSAutoreleasePool *pool;
84 if (isInitialized) return;
88 pool = [[NSAutoreleasePool alloc] init];
89 debugOn = [WOApplication isDebuggingEnabled];
91 if (classLock == nil) classLock = [[NSRecursiveLock alloc] init];
92 ud = [NSUserDefaults standardUserDefaults];
94 /* setup SNSConnection */
96 if ([ud boolForKey:@"WOContactSNS"])
99 NSLog(@"SNS support disabled.");
101 NSDateClass = [NSDate class];
102 WOTemplateClass = [WOTemplate class];
104 perflog = [ud boolForKey:@"WOProfileApplication"];
105 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
110 /* old license checks */
112 - (NSCalendarDate *)appExpireDate {
113 // TODO: can we remove that?
116 - (BOOL)isLicenseExpired {
117 // TODO: can we remove that?
123 - (NSString *)_lookupAppPath {
124 static NSString *suffix = nil;
125 static BOOL appPathMissing = NO;
134 ud = [NSUserDefaults standardUserDefaults];
136 // Check if appPath has been forced
137 result = [ud stringForKey:@"WOProjectDirectory"];
142 suffix = [ud stringForKey:@"WOApplicationSuffix"];
144 fm = [NSFileManager defaultManager];
145 cwd = [fm currentDirectoryPath];
147 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
148 result = [[NGBundle mainBundle] bundlePath];
149 //NSLog(@"%s: check path '%@'", __PRETTY_FUNCTION__, result);
154 if ([result hasSuffix:suffix]) {
155 /* started app inside of .woa directory */
156 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
157 result = [[NGBundle mainBundle] bundlePath];
163 NSString *wrapperName;
165 wrapperName = [self->name stringByAppendingString:suffix];
167 /* take a look whether ./AppName.woa exists */
168 result = [result stringByAppendingPathComponent:wrapperName];
169 if (![fm fileExistsAtPath:result]) {
170 /* lookup in process-path */
173 ppath = [[[NSProcessInfo processInfo] arguments] objectAtIndex:0];
174 ppath = [ppath stringByDeletingLastPathComponent]; // del exe-name
175 ppath = [ppath stringByDeletingLastPathComponent]; // lib-combo
176 ppath = [ppath stringByDeletingLastPathComponent]; // os
177 ppath = [ppath stringByDeletingLastPathComponent]; // cpu
179 if ([ppath hasSuffix:suffix])
184 if (![fm fileExistsAtPath:result]) {
185 [self debugWithFormat:@"%s: missing path '%@'",
186 __PRETTY_FUNCTION__, result];
187 appPathMissing = YES;
194 + (NSString *)defaultRequestHandlerClassName {
195 return @"WOComponentRequestHandler";
198 - (void)_logDefaults {
204 ud = [NSUserDefaults standardUserDefaults];
205 keys = [[ud dictionaryRepresentation] allKeys];
206 keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
208 e = [keys objectEnumerator];
209 while((key = [e nextObject]) != nil) {
210 if ([key hasPrefix:@"WO"] || [key isEqualToString:@"NSProjectSearchPath"])
211 NSLog(@"%@ = %@", key, [[ud objectForKey:key] description]);
215 - (id)initWithName:(NSString *)_name {
216 [WOApplication _initializeWOApp];
218 if ((self = [super init])) {
220 WORequestHandler *rh;
223 self->name = [_name copy];
225 ud = [NSUserDefaults standardUserDefaults];
227 [self setPageCacheSize:[ud integerForKey:@"WOPageCacheSize"]];
228 [self setPermanentPageCacheSize:
229 [ud integerForKey:@"WOPermanentPageCacheSize"]];
231 [self setPageRefreshOnBacktrackEnabled:
232 [[ud objectForKey:@"WOPageRefreshOnBacktrack"] boolValue]];
234 [self setCachingEnabled:[WOApplication isCachingEnabled]];
236 /* setup request handlers */
238 self->defaultRequestHandler =
239 [[NSClassFromString([[self class] defaultRequestHandlerClassName]) alloc] init];
241 self->requestHandlerRegistry =
242 NSCreateMapTable(NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 8);
244 rk = [WOApplication componentRequestHandlerKey];
246 rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
248 rh = [[NSClassFromString(@"WOComponentRequestHandler") alloc] init];
250 if ([rk length] > 0 && (rh != nil))
251 [self registerRequestHandler:rh forKey:rk];
252 [rh release]; rh = nil;
254 rk = [WOApplication directActionRequestHandlerKey];
255 rh = [[NSClassFromString(@"WODirectActionRequestHandler") alloc] init];
256 if ([rk length] > 0 && rh != nil)
257 [self registerRequestHandler:rh forKey:rk];
258 [rh release]; rh = nil;
260 if ((rh = [[NSClassFromString(@"WOResourceRequestHandler") alloc] init])) {
261 rk = [WOApplication resourceRequestHandlerKey];
263 [self registerRequestHandler:rh forKey:rk];
264 [self registerRequestHandler:rh forKey:@"WebServerResources"];
266 [self registerRequestHandler:rh forKey:@"Resources"];
268 [rh release]; rh = nil;
271 /* setup session store */
273 self->iSessionStore =
274 [[NSClassFromString([self sessionStoreClassName]) alloc] init];
276 /* setup statistics store */
278 self->iStatisticsStore = [[WOStatisticsStore alloc] init];
280 /* register timers */
281 self->expirationTimer =
282 [[NSTimer scheduledTimerWithTimeInterval:
283 [[ud objectForKey:@"WOExpirationTimeInterval"] intValue]
285 selector:@selector(performExpirationCheck:)
290 if ([ud boolForKey:@"WOLogDefaultsOnStartup"])
293 [[NSNotificationCenter defaultCenter]
294 postNotificationName:
295 WOApplicationWillFinishLaunchingNotification
302 return [self initWithName:[[[NSProcessInfo processInfo]
304 stringByDeletingPathExtension]];
308 [[NSNotificationCenter defaultCenter] removeObserver:self];
310 [self->expirationTimer invalidate];
312 if (self->requestHandlerRegistry)
313 NSFreeMapTable(self->requestHandlerRegistry);
315 [self->expirationTimer release];
316 [self->resourceManager release];
317 [self->iSessionStore release];
318 [self->defaultRequestHandler release];
319 [self->path release];
320 [self->name release];
321 [self->instanceNumber release];
325 - (void)processHupSignal:(int)_signal {
326 /* this isn't called immediatly */
327 [self logWithFormat:@"terminating on SIGHUP ..."];
336 - (BOOL)monitoringEnabled {
340 static BOOL missingPath = NO;
341 if (missingPath) return nil;
342 if (self->path == nil) {
343 if ((self->path = [[self _lookupAppPath] copy]) == nil) {
345 [self debugWithFormat:
346 @"WARNING: could not find wrapper of application !"];
355 - (NSString *)number {
356 if (self->instanceNumber == nil) {
359 if ((num = [[NSUserDefaults standardUserDefaults] objectForKey:@"n"])) {
360 self->instanceNumber = [[num stringValue] copy];
364 #if defined(__MINGW32__)
365 pid = (unsigned)GetCurrentProcessId();
367 pid = (unsigned)getpid();
369 self->instanceNumber = [[NSString alloc] initWithFormat:@"%d", pid];
372 return self->instanceNumber;
375 - (WOContext *)context {
380 if ((t = [NSThread currentThread]) == nil) {
381 [self logWithFormat:@"ERROR: missing current thread !!!"];
384 if ((td = [t threadDictionary]) == nil) {
386 @"ERROR: missing current thread's dictionary (thread=%@) !!!",
391 return [td objectForKey:@"WOContext"];
394 /* request handlers */
396 - (void)registerRequestHandler:(WORequestHandler *)_hdl
397 forKey:(NSString *)_key
400 NSMapInsert(self->requestHandlerRegistry, _key, _hdl);
403 - (void)removeRequestHandlerForKey:(NSString *)_key {
404 if (_key == nil) return;
406 NSMapRemove(self->requestHandlerRegistry, _key);
410 - (void)setDefaultRequestHandler:(WORequestHandler *)_hdl {
412 ASSIGN(self->defaultRequestHandler, _hdl);
415 - (WORequestHandler *)defaultRequestHandler {
416 return self->defaultRequestHandler;
418 - (WORequestHandler *)requestHandlerForKey:(NSString *)_key {
419 WORequestHandler *handler;
422 handler = [(id)NSMapGet(self->requestHandlerRegistry, _key) retain];
424 handler = [[self defaultRequestHandler] retain];
427 return [handler autorelease];
430 - (NSArray *)registeredRequestHandlerKeys {
431 NSMutableArray *array = [NSMutableArray arrayWithCapacity:16];
434 WORequestHandler *handler;
437 e = NSEnumerateMapTable(self->requestHandlerRegistry);
438 while (NSNextMapEnumeratorPair(&e, (void**)&key, (void**)&handler))
439 [array addObject:key];
442 return [[array copy] autorelease];
445 - (WORequestHandler *)handlerForRequest:(WORequest *)_request {
446 WORequestHandler *handler;
449 if ((key = [_request requestHandlerKey]) == nil)
450 return [self defaultRequestHandler];
452 handler = NSMapGet(self->requestHandlerRegistry, key);
453 return (handler != nil) ? handler : [self defaultRequestHandler];
458 - (WOSession *)_initializeSessionInContext:(WOContext *)_ctx {
461 sn = [self createSessionForRequest:[_ctx request]];
462 [_ctx setSession:sn];
464 if ([sn respondsToSelector:@selector(prepare)]) {
466 [self debugWithFormat:@"calling -prepare on session .."];
468 [sn performSelector:@selector(prepare)];
471 [sn _awakeWithContext:_ctx];
473 [[NSNotificationCenter defaultCenter]
474 postNotificationName:WOSessionDidCreateNotification
476 return [sn autorelease];
479 - (NSString *)sessionIDFromRequest:(WORequest *)_request {
482 if (_request == nil) return nil;
484 /* first look into form values */
485 if ((sessionId = [_request formValueForKey:WORequestValueSessionID])) {
486 if ([sessionId length] > 0)
490 /* now look into the cookies */
491 if ((sessionId = [_request cookieValueForKey:[self name]])) {
492 if ([sessionId respondsToSelector:@selector(objectEnumerator)]) {
495 e = [(id)sessionId objectEnumerator];
496 while ((sessionId = [e nextObject])) {
497 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
502 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
510 - (NSString *)createSessionIDForSession:(WOSession *)_session {
511 /* session id must be 18 chars long for snsd to work ! */
512 static unsigned int sessionCount = 0;
514 unsigned char buf[20];
517 sprintf(buf, "%04X%04X%02X%08X",
518 [[self number] intValue], getpid(), sessionCount,
519 (unsigned int)time(NULL));
520 wosid = [NSString stringWithCString:buf];
524 - (WOSession *)createSessionForRequest:(WORequest *)_request {
525 if ([self respondsToSelector:@selector(createSession)]) {
526 /* call deprecated method */
527 NSLog(@"WARNING: calling deprecated -createSession ..");
528 return [self createSession];
533 if ((snClass = NSClassFromString(@"Session")) == Nil)
534 snClass = [WOSession class];
536 return [[snClass alloc] init];
540 - (WOSession *)restoreSessionWithID:(NSString *)_sid
541 inContext:(WOContext *)_ctx
547 if ([self respondsToSelector:@selector(restoreSession)]) {
548 /* call deprecated method */
549 NSLog(@"WARNING: calling deprecated -restoreSession ..");
550 return [self restoreSession];
554 WOSessionStore *store;
556 if ((store = [self sessionStore]) == nil) {
557 [self logWithFormat:@"missing session store ..."];
560 session = [store restoreSessionWithID:_sid request:[_ctx request]];
562 [_ctx setSession:session];
563 [session _awakeWithContext:_ctx];
566 [self debugWithFormat:@"did not find a session for sid '%@'", _sid];
573 [[NSNotificationCenter defaultCenter]
574 postNotificationName:WOSessionDidRestoreNotification
578 if ([_sid hasPrefix:@"("]) {
581 sid = [_sid propertyList];
583 if ([sid respondsToSelector:@selector(objectEnumerator)]) {
586 [self logWithFormat:@"got multiple session IDs !"];
588 e = [sid objectEnumerator];
589 while ((_sid = [e nextObject])) {
590 if ([_sid isEqualToString:@"nil"])
593 if ((session = [self restoreSessionWithID:_sid inContext:_ctx]))
596 //NSLog(@"WARNING: did not find session for sid %@", _sid);
603 - (void)saveSessionForContext:(WOContext *)_ctx {
604 NSTimeInterval startSave = 0.0;
607 startSave = [[NSDateClass date] timeIntervalSince1970];
609 if ([self respondsToSelector:@selector(saveSession:)]) {
610 /* call deprecated method */
611 NSLog(@"WARNING: calling deprecated -saveSession: ..");
612 [self saveSession:[_ctx session]];
618 NSTimeInterval startSnSleep = 0.0, startStore = 0.0;
623 startSnSleep = [[NSDateClass date] timeIntervalSince1970];
625 /* put session to sleep */
626 [sn _sleepWithContext:_ctx];
630 rt = [[NSDateClass date] timeIntervalSince1970] - startSnSleep;
631 NSLog(@" [woapp]: session -sleep took %4.3fs.",
632 rt < 0.0 ? -1.0 : rt);
635 if ([sn isTerminating]) {
636 [[NSNotificationCenter defaultCenter]
637 postNotificationName:
638 WOSessionDidTerminateNotification
643 startStore = [[NSDateClass date] timeIntervalSince1970];
645 [[self sessionStore] saveSessionForContext:_ctx];
649 rt = [[NSDateClass date] timeIntervalSince1970] - startStore;
650 NSLog(@" [woapp]: storing sn in store took %4.3fs.",
651 rt < 0.0 ? -1.0 : rt);
658 rt = [[NSDateClass date] timeIntervalSince1970] - startSave;
659 NSLog(@"[woapp]: saveSessionForContext took %4.3fs.",
660 rt < 0.0 ? -1.0 : rt);
664 - (void)refuseNewSessions:(BOOL)_flag {
665 self->appFlags.doesRefuseNewSessions = _flag ? 1 : 0;
667 - (BOOL)isRefusingNewSessions {
668 return self->appFlags.doesRefuseNewSessions;
670 - (int)activeSessionsCount {
671 return [[self sessionStore] activeSessionsCount];
674 - (void)setSessionStore:(WOSessionStore *)_store {
675 ASSIGN(self->iSessionStore, _store);
677 - (NSString *)sessionStoreClassName {
678 return [[NSUserDefaults standardUserDefaults] stringForKey:@"WOSessionStore"];
680 - (WOSessionStore *)sessionStore {
681 return self->iSessionStore;
684 - (void)setMinimumActiveSessionsCount:(int)_minimum {
685 self->minimumActiveSessionsCount = _minimum;
687 - (int)minimumActiveSessionsCount {
688 return self->minimumActiveSessionsCount;
691 - (void)performExpirationCheck:(NSTimer *)_timer {
694 /* let session store check for expiration ... */
696 ss = [self sessionStore];
697 if ([ss respondsToSelector:@selector(performExpirationCheck:)])
698 [ss performExpirationCheck:_timer];
700 /* check whether application should terminate ... */
702 if ([self isRefusingNewSessions] &&
703 ([self activeSessionsCount] < [self minimumActiveSessionsCount])) {
704 /* check whether the application instance is still valid .. */
705 [self debugWithFormat:
706 @"application terminates because it refuses new sessions and "
707 @"the active session count (%i) is below the minimum (%i).",
708 [self activeSessionsCount], [self minimumActiveSessionsCount]];
713 - (WOSession *)session {
714 return [[self context] session];
717 - (WOResponse *)handleSessionCreationErrorInContext:(WOContext *)_ctx {
718 WOResponse *response = [_ctx response];
722 pid = GetCurrentProcessId();
727 if ([self respondsToSelector:@selector(handleSessionCreationError)]) {
728 NSLog(@"WARNING: called deprecated -handleSessionCreationError method");
729 return [self handleSessionCreationError];
732 [self logWithFormat:@"could not create session for context %@", _ctx];
734 [response setStatus:200];
735 [response appendContentString:@"<h4>Session Creation Error</h4>\n<pre>"];
736 [response appendContentString:
737 @"Application Instance failed to create session."];
738 [response appendContentHTMLString:
739 [NSString stringWithFormat:
740 @" application: %@\n"
747 [[_ctx request] adaptorPrefix],
751 [[_ctx request] description]]];
752 [response appendContentString:@"</pre>"];
756 - (WOResponse *)handleSessionRestorationErrorInContext:(WOContext *)_ctx {
757 if ([self respondsToSelector:@selector(handleSessionRestorationError)]) {
758 NSLog(@"WARNING: calling deprecated -handleSessionRestorationError "
760 return [self handleSessionRestorationError];
763 [self logWithFormat:@"could not restore session for context %@", _ctx];
769 - (void)setStatisticsStore:(WOStatisticsStore *)_statStore {
770 ASSIGN(self->iStatisticsStore, _statStore);
772 - (WOStatisticsStore *)statisticsStore {
773 return self->iStatisticsStore;
776 - (bycopy NSDictionary *)statistics {
777 return [[self statisticsStore] statistics];
782 - (void)setResourceManager:(WOResourceManager *)_manager {
783 ASSIGN(self->resourceManager, _manager);
785 - (WOResourceManager *)resourceManager {
786 if (self->resourceManager == nil) {
790 if ([(p = [self path]) length] > 0)
791 [self logWithFormat:@"setup WOResourceManager at path '%@' ...", p];
796 self->resourceManager =
797 [(WOResourceManager *)[WOResourceManager alloc] initWithPath:p];
799 return self->resourceManager;
804 WOContext *ctx = [self context];
806 n = [[ctx request] applicationName];
807 n = [@"/" stringByAppendingString:n ? n : [self name]];
809 return [NSURL URLWithString:n relativeToURL:[ctx baseURL]];
812 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
814 return [[self resourceManager] pathForResourceNamed:_name ofType:_type];
817 - (NSString *)stringForKey:(NSString *)_key
818 inTableNamed:(NSString *)_tableName
819 withDefaultValue:(NSString *)_default
822 return [[self resourceManager] stringForKey:_key
823 inTableNamed:_tableName
824 withDefaultValue:_default
826 [(WOSession *)[self session] languages]];
838 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
839 if ([_ctx hasSession])
840 [[_ctx session] takeValuesFromRequest:_req inContext:_ctx];
844 if ((page = [_ctx page])) {
845 WOContext_enterComponent(_ctx, page, nil);
846 [page takeValuesFromRequest:_req inContext:_ctx];
847 WOContext_leaveComponent(_ctx, page);
852 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
855 if ([_ctx hasSession])
856 result = [[_ctx session] invokeActionForRequest:_rq inContext:_ctx];
860 if ((page = [_ctx page])) {
861 WOContext_enterComponent(_ctx, page, nil);
862 result = [[_ctx page] invokeActionForRequest:_rq inContext:_ctx];
863 WOContext_leaveComponent(_ctx, page);
871 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
872 if ([_ctx hasSession])
873 [[_ctx session] appendToResponse:_response inContext:_ctx];
877 if ((page = [_ctx page])) {
878 WOContext_enterComponent(_ctx, page, nil);
879 [page appendToResponse:_response inContext:_ctx];
880 WOContext_leaveComponent(_ctx, page);
884 if(rapidTurnAroundPath != nil) {
887 if((page = [_ctx page])) {
890 template = [page _woComponentTemplate];
891 if([template isKindOfClass:WOTemplateClass]) {
894 _path = [[(WOTemplate *)template url] path];
895 [_response setHeader:_path
896 forKey:@"x-sope-template-path"];
905 - (WOElement *)dynamicElementWithName:(NSString *)_name
906 associations:(NSDictionary *)_associations
907 template:(WOElement *)_template
908 languages:(NSArray *)_languages
910 WOElement *element = nil;
911 Class dynamicElementClass = NSClassFromString(_name);
913 if (dynamicElementClass == Nil) {
914 NSLog(@"WARNING: did not find dynamic element class %@ !", _name);
917 if (![dynamicElementClass isDynamicElement]) {
918 NSLog(@"WARNING: class %@ is not a dynamic element class !", _name);
922 element = [[dynamicElementClass allocWithZone:[_template zone]]
924 associations:_associations
928 - (WOElement *)dynamicElementWithName:(NSString *)_name
929 associations:(NSDictionary *)_associations
930 template:(WOElement *)_template
932 return [self dynamicElementWithName:_name
933 associations:_associations
935 languages:[(WOSession *)[self session] languages]];
940 - (void)setPageRefreshOnBacktrackEnabled:(BOOL)_flag {
941 self->appFlags.isPageRefreshOnBacktrackEnabled = _flag ? 1 : 0;
943 - (BOOL)isPageRefreshOnBacktrackEnabled {
944 return self->appFlags.isPageRefreshOnBacktrackEnabled ? YES : NO;
947 - (void)setCachingEnabled:(BOOL)_flag {
948 self->appFlags.isCachingEnabled = _flag ? 1 : 0;
950 - (BOOL)isCachingEnabled {
951 // component definition caching
952 return self->appFlags.isCachingEnabled ? YES : NO;
955 - (void)setPageCacheSize:(int)_size {
956 self->pageCacheSize = _size;
958 - (int)pageCacheSize {
959 return self->pageCacheSize;
961 - (void)setPermanentPageCacheSize:(int)_size {
962 self->permanentPageCacheSize = _size;
964 - (int)permanentPageCacheSize {
965 return self->permanentPageCacheSize;
968 - (WOComponent *)pageWithName:(NSString *)_name {
970 return [self pageWithName:_name inContext:[self context]];
973 - (WOComponent *)_pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
975 OSX profiling: 3.4% of dispatchRequest?
976 3.0% rm -pageWithName..
978 1.3% initWithName:...
979 0.76% initWithContent:.. (0.43 addobserver)
980 0.76% rm defForComp (0.43% touch)
987 NSAutoreleasePool *pool;
988 WOResourceManager *rm;
991 NSDictionary *start, *stop;
992 start = [self memoryStatistics];
995 pool = [[NSAutoreleasePool alloc] init];
997 languages = [_ctx hasSession]
998 ? [(WOSession *)[_ctx session] languages]
999 : [[_ctx request] browserLanguages];
1001 if ((rm = [[_ctx component] resourceManager]) == nil)
1002 rm = [self resourceManager];
1004 page = [rm pageWithName:(_name ? _name : @"Main")
1005 languages:languages];
1006 [page ensureAwakeInContext:_ctx];
1008 page = [page retain];
1013 int rss, vmsize, lib;
1014 stop = [self memoryStatistics];
1015 rss = [[stop objectForKey:@"VmRSS"] intValue] -
1016 [[start objectForKey:@"VmRSS"] intValue];
1017 vmsize = [[stop objectForKey:@"VmSize"] intValue] -
1018 [[start objectForKey:@"VmSize"] intValue];
1019 lib = [[stop objectForKey:@"VmLib"] intValue] -
1020 [[start objectForKey:@"VmLib"] intValue];
1021 NSLog(@"loaded component %@; rss=%i vm=%i lib=%i.", _name, rss,vmsize,lib);
1025 return [page autorelease];
1027 - (WOComponent *)pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
1028 return [self _pageWithName:_name inContext:_ctx];
1030 - (WOComponent *)pageWithName:(NSString *)_name forRequest:(WORequest *)_req {
1031 WOResourceManager *rm;
1033 if ((rm = [self resourceManager]) == nil)
1036 return [rm pageWithName:_name ? _name : @"Main"
1037 languages:[_req browserLanguages]];
1040 - (void)savePage:(WOComponent *)_page {
1042 [[[self context] session] savePage:_page];
1044 - (id)restorePageForContextID:(NSString *)_ctxId {
1046 return [[[self context] session] restorePageForContextID:_ctxId];
1049 - (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)_ctx {
1050 [self logWithFormat:
1051 @"could not restore page for context-id %@\n in context %@",
1052 [_ctx currentElementID], _ctx];
1054 /* return main page ... */
1055 return [[self pageWithName:nil inContext:_ctx] generateResponse];
1057 - (WOResponse *)handlePageRestorationError {
1059 return [self handlePageRestorationErrorInContext:[self context]];
1064 - (WOResponse *)handleException:(NSException *)_exc
1065 inContext:(WOContext *)_ctx
1067 WORequest *rq = [_ctx request];
1068 WOResponse *r = nil;
1070 if ([self respondsToSelector:@selector(handleException:)]) {
1071 NSLog(@"WARNING: calling deprecated -handleException method !");
1072 return [self handleException:_exc];
1077 static int doCore = -1;
1079 doCore = [[NSUserDefaults standardUserDefaults]
1080 boolForKey:@"WOCoreOnApplicationException"]
1084 [self logWithFormat:@"%@: caught (ctx=%@):\n %@.",
1092 [self logWithFormat:@"%@: caught (without context):\n %@.", self, _exc];
1095 else if (rq == nil) {
1096 [self logWithFormat:@"%@: caught (without request):\n %@.", self, _exc];
1100 static NSString *pageFormat =
1101 @"Application Server caught exception:\n\n"
1110 @" backtrace:\n%@\n";
1111 NSString *str = nil;
1114 [self logWithFormat:@"%@: caught:\n %@\nin context:\n %@.",
1117 #if LIB_FOUNDATION_LIBRARY
1118 if ([NSException respondsToSelector:@selector(backtrace)])
1119 bt = [NSException backtrace];
1122 if ((r = [WOResponse responseWithRequest:rq]) == nil)
1123 [self logWithFormat:@"could not create response !"];
1125 [r setHeader:@"text/html" forKey:@"content-type"];
1126 [r setHeader:@"no-cache" forKey:@"cache-control"];
1127 if(rapidTurnAroundPath != nil) {
1130 templateURL = [[_exc userInfo] objectForKey:@"templateURL"];
1131 if(templateURL != nil)
1132 [r setHeader:[templateURL path] forKey:@"x-sope-template-path"];
1135 str = [NSString stringWithFormat:pageFormat,
1137 ? [[_ctx session] sessionID]
1142 NSStringFromClass([_exc class]),
1145 [[_exc userInfo] description],
1148 [r appendContentString:@"<html><head><title>Caught exception</title></head><body><pre>\n"];
1149 [r appendContentHTMLString:str];
1150 [r appendContentString:@"</pre></body></html>\n"];
1157 - (BOOL)shouldTerminate {
1158 if (![self isRefusingNewSessions])
1160 if ([self activeSessionsCount] >= [self minimumActiveSessionsCount])
1163 /* check whether the application instance is still valid .. */
1164 [self debugWithFormat:
1165 @"application terminates because it refuses new sessions and "
1166 @"the active session count (%i) is below the minimum (%i).",
1167 [self activeSessionsCount], [self minimumActiveSessionsCount]];
1172 [self debugWithFormat:
1173 @"application terminates:\n"
1174 @" %i active sessions\n"
1175 @" %i minimum active sessions\n"
1176 @" refuses new session: %s",
1177 [self activeSessionsCount],
1178 [self minimumActiveSessionsCount],
1179 [self isRefusingNewSessions] ? "yes" : "no"];
1185 - (BOOL)isDebuggingEnabled {
1188 - (NSString *)loggingPrefix {
1189 return [NSString stringWithFormat:@"|%@%@|",
1191 [self isTerminating] ? @" terminating" : @""];
1196 #if !LIB_FOUNDATION_LIBRARY
1197 - (id)valueForUndefinedKey:(NSString *)_key {
1198 [self logWithFormat:@"WARNING: tried to access undefined KVC key: '%@'",
1206 + (Class)eoEditingContextClass {
1207 static Class eoEditingContextClass = Nil;
1208 static BOOL lookedUpForEOEditingContextClass = NO;
1210 if (!lookedUpForEOEditingContextClass) {
1211 eoEditingContextClass = NSClassFromString(@"EOEditingContext");
1212 lookedUpForEOEditingContextClass = YES;
1214 return eoEditingContextClass;
1217 + (BOOL)implementsEditingContexts {
1218 return [self eoEditingContextClass] != NULL ? YES : NO;
1223 - (NSString *)description {
1224 return [NSString stringWithFormat:@"<%@[0x%08X]: name=%@%@>",
1225 NSStringFromClass([self class]), self,
1227 [self isTerminating] ? @" terminating" : @""
1231 @end /* WOApplication */