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 NGLogger *perfLogger = nil;
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 [self logFatalWithFormat:@"could not connect SNS, exiting .."];
75 [self logInfoWithFormat:@"SNS enabled"];
78 + (void)_initializeWOApp {
79 static BOOL isInitialized = NO;
80 NSAutoreleasePool *pool;
84 if (isInitialized) return;
88 pool = [[NSAutoreleasePool alloc] init];
89 debugOn = [WOApplication isDebuggingEnabled];
91 [[self logger] setLogLevel:NGLogLevelInfo];
93 if (classLock == nil) classLock = [[NSRecursiveLock alloc] init];
94 ud = [NSUserDefaults standardUserDefaults];
96 /* setup SNSConnection */
98 if ([ud boolForKey:@"WOContactSNS"])
101 [self logInfoWithFormat:@"SNS support disabled."];
103 NSDateClass = [NSDate class];
104 WOTemplateClass = [WOTemplate class];
106 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
108 lm = [NGLoggerManager defaultLoggerManager];
109 perfLogger = [lm loggerForDefaultKey:@"WOProfileApplication"];
114 /* old license checks */
116 - (NSCalendarDate *)appExpireDate {
117 // TODO: can we remove that?
120 - (BOOL)isLicenseExpired {
121 // TODO: can we remove that?
127 - (NSString *)_lookupAppPath {
128 static NSString *suffix = nil;
129 static BOOL appPathMissing = NO;
138 ud = [NSUserDefaults standardUserDefaults];
140 // Check if appPath has been forced
141 result = [ud stringForKey:@"WOProjectDirectory"];
146 suffix = [ud stringForKey:@"WOApplicationSuffix"];
148 fm = [NSFileManager defaultManager];
149 cwd = [fm currentDirectoryPath];
151 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
152 result = [[NGBundle mainBundle] bundlePath];
153 //NSLog(@"%s: check path '%@'", __PRETTY_FUNCTION__, result);
158 if ([result hasSuffix:suffix]) {
159 /* started app inside of .woa directory */
160 #if NeXT_Foundation_LIBRARY || COCOA_Foundation_LIBRARY
161 result = [[NGBundle mainBundle] bundlePath];
167 NSString *wrapperName;
169 wrapperName = [self->name stringByAppendingString:suffix];
171 /* take a look whether ./AppName.woa exists */
172 result = [result stringByAppendingPathComponent:wrapperName];
173 if (![fm fileExistsAtPath:result]) {
174 /* lookup in process-path */
180 pi = [NSProcessInfo processInfo];
181 env = [pi environment];
182 if ([env objectForKey:@"GNUSTEP_SYSTEM_ROOT"] != nil) {
183 isFlattened = [[[env objectForKey:@"GNUSTEP_FLATTENED"]
184 lowercaseString] isEqualToString:@"yes"];
186 else /* default to flattened if no GNUstep runtime is set */
189 ppath = [[pi arguments] objectAtIndex:0];
190 ppath = [ppath stringByDeletingLastPathComponent]; // del exe-name
193 ppath = [ppath stringByDeletingLastPathComponent]; // lib-combo
194 ppath = [ppath stringByDeletingLastPathComponent]; // os
195 ppath = [ppath stringByDeletingLastPathComponent]; // cpu
197 if ([ppath hasSuffix:suffix])
202 if (![fm fileExistsAtPath:result]) {
203 [self debugWithFormat:@"%s: missing path '%@'",
204 __PRETTY_FUNCTION__, result];
205 appPathMissing = YES;
212 + (NSString *)defaultRequestHandlerClassName {
213 return @"WOComponentRequestHandler";
216 - (void)_logDefaults {
222 ud = [NSUserDefaults standardUserDefaults];
223 keys = [[ud dictionaryRepresentation] allKeys];
224 keys = [keys sortedArrayUsingSelector:@selector(caseInsensitiveCompare:)];
226 e = [keys objectEnumerator];
227 while((key = [e nextObject]) != nil) {
228 if ([key hasPrefix:@"WO"] || [key isEqualToString:@"NSProjectSearchPath"])
229 [self logInfoWithFormat:@"[default]: %@ = %@",
231 [[ud objectForKey:key] description]];
235 - (id)initWithName:(NSString *)_name {
236 [WOApplication _initializeWOApp];
238 if ((self = [super init])) {
240 WORequestHandler *rh;
243 self->name = [_name copy];
245 ud = [NSUserDefaults standardUserDefaults];
247 [self setPageCacheSize:[ud integerForKey:@"WOPageCacheSize"]];
248 [self setPermanentPageCacheSize:
249 [ud integerForKey:@"WOPermanentPageCacheSize"]];
251 [self setPageRefreshOnBacktrackEnabled:
252 [[ud objectForKey:@"WOPageRefreshOnBacktrack"] boolValue]];
254 [self setCachingEnabled:[WOApplication isCachingEnabled]];
256 /* setup request handlers */
258 self->defaultRequestHandler =
259 [[NSClassFromString([[self class] defaultRequestHandlerClassName])
262 self->requestHandlerRegistry =
263 NSCreateMapTable(NSObjectMapKeyCallBacks, NSObjectMapValueCallBacks, 8);
265 rk = [WOApplication componentRequestHandlerKey];
267 rh = [[NSClassFromString(@"OWViewRequestHandler") alloc] init];
269 rh = [[NSClassFromString(@"WOComponentRequestHandler") alloc] init];
271 if ([rk length] > 0 && (rh != nil))
272 [self registerRequestHandler:rh forKey:rk];
273 [rh release]; rh = nil;
275 rk = [WOApplication directActionRequestHandlerKey];
276 rh = [[NSClassFromString(@"WODirectActionRequestHandler") alloc] init];
277 if ([rk length] > 0 && rh != nil)
278 [self registerRequestHandler:rh forKey:rk];
279 [rh release]; rh = nil;
281 if ((rh = [[NSClassFromString(@"WOResourceRequestHandler") alloc] init])) {
282 rk = [WOApplication resourceRequestHandlerKey];
284 [self registerRequestHandler:rh forKey:rk];
285 [self registerRequestHandler:rh forKey:@"WebServerResources"];
287 [self registerRequestHandler:rh forKey:@"Resources"];
289 [rh release]; rh = nil;
292 /* setup session store */
294 self->iSessionStore =
295 [[NSClassFromString([self sessionStoreClassName]) alloc] init];
297 /* setup statistics store */
299 self->iStatisticsStore = [[WOStatisticsStore alloc] init];
301 /* register timers */
302 self->expirationTimer =
303 [[NSTimer scheduledTimerWithTimeInterval:
304 [[ud objectForKey:@"WOExpirationTimeInterval"] intValue]
306 selector:@selector(performExpirationCheck:)
311 if ([ud boolForKey:@"WOLogDefaultsOnStartup"])
314 [[NSNotificationCenter defaultCenter]
315 postNotificationName:
316 WOApplicationWillFinishLaunchingNotification
323 return [self initWithName:[[[NSProcessInfo processInfo]
325 stringByDeletingPathExtension]];
329 [[NSNotificationCenter defaultCenter] removeObserver:self];
331 [self->expirationTimer invalidate];
333 if (self->requestHandlerRegistry)
334 NSFreeMapTable(self->requestHandlerRegistry);
336 [self->expirationTimer release];
337 [self->resourceManager release];
338 [self->iSessionStore release];
339 [self->defaultRequestHandler release];
340 [self->path release];
341 [self->name release];
342 [self->instanceNumber release];
346 - (void)processHupSignal:(int)_signal {
347 /* this isn't called immediatly */
348 [self logInfoWithFormat:@"terminating on SIGHUP ..."];
357 - (BOOL)monitoringEnabled {
361 static BOOL missingPath = NO;
365 if (self->path == nil) {
366 if ((self->path = [[self _lookupAppPath] copy]) == nil) {
367 [self logDebugWithFormat:@"could not find wrapper of application !"];
375 - (NSString *)number {
376 if (self->instanceNumber == nil) {
379 if ((num = [[NSUserDefaults standardUserDefaults] objectForKey:@"n"])) {
380 self->instanceNumber = [[num stringValue] copy];
384 #if defined(__MINGW32__)
385 pid = (unsigned)GetCurrentProcessId();
387 pid = (unsigned)getpid();
389 self->instanceNumber = [[NSString alloc] initWithFormat:@"%d", pid];
392 return self->instanceNumber;
395 - (void)_setCurrentContext:(WOContext *)_ctx {
396 NSMutableDictionary *info;
398 info = [[NSThread currentThread] threadDictionary];
400 [info setObject:_ctx forKey:@"WOContext"];
402 [info removeObjectForKey:@"WOContext"];
404 - (WOContext *)context {
409 if ((t = [NSThread currentThread]) == nil) {
410 [self logErrorWithFormat:@"missing current thread !!!"];
413 if ((td = [t threadDictionary]) == nil) {
414 [self logErrorWithFormat:
415 @"missing current thread's dictionary (thread=%@) !!!",
420 return [td objectForKey:@"WOContext"];
423 /* request handlers */
425 - (void)registerRequestHandler:(WORequestHandler *)_hdl
426 forKey:(NSString *)_key
429 NSMapInsert(self->requestHandlerRegistry, _key, _hdl);
432 - (void)removeRequestHandlerForKey:(NSString *)_key {
433 if (_key == nil) return;
435 NSMapRemove(self->requestHandlerRegistry, _key);
439 - (void)setDefaultRequestHandler:(WORequestHandler *)_hdl {
441 ASSIGN(self->defaultRequestHandler, _hdl);
444 - (WORequestHandler *)defaultRequestHandler {
445 return self->defaultRequestHandler;
447 - (WORequestHandler *)requestHandlerForKey:(NSString *)_key {
448 WORequestHandler *handler;
451 handler = [(id)NSMapGet(self->requestHandlerRegistry, _key) retain];
453 handler = [[self defaultRequestHandler] retain];
456 return [handler autorelease];
459 - (NSArray *)registeredRequestHandlerKeys {
460 NSMutableArray *array = [NSMutableArray arrayWithCapacity:16];
463 WORequestHandler *handler;
466 e = NSEnumerateMapTable(self->requestHandlerRegistry);
467 while (NSNextMapEnumeratorPair(&e, (void**)&key, (void**)&handler))
468 [array addObject:key];
471 return [[array copy] autorelease];
474 - (WORequestHandler *)handlerForRequest:(WORequest *)_request {
475 WORequestHandler *handler;
478 if ((key = [_request requestHandlerKey]) == nil)
479 return [self defaultRequestHandler];
481 handler = NSMapGet(self->requestHandlerRegistry, key);
482 return (handler != nil) ? handler : [self defaultRequestHandler];
487 - (WOSession *)_initializeSessionInContext:(WOContext *)_ctx {
490 sn = [self createSessionForRequest:[_ctx request]];
491 [_ctx setSession:sn];
493 if ([sn respondsToSelector:@selector(prepare)]) {
495 [self debugWithFormat:@"calling -prepare on session .."];
497 [sn performSelector:@selector(prepare)];
500 [sn _awakeWithContext:_ctx];
502 [[NSNotificationCenter defaultCenter]
503 postNotificationName:WOSessionDidCreateNotification
505 return [sn autorelease];
508 - (NSString *)sessionIDFromRequest:(WORequest *)_request {
511 if (_request == nil) return nil;
513 /* first look into form values */
514 if ((sessionId = [_request formValueForKey:WORequestValueSessionID])) {
515 if ([sessionId length] > 0)
519 /* now look into the cookies */
520 if ((sessionId = [_request cookieValueForKey:[self name]])) {
521 if ([sessionId respondsToSelector:@selector(objectEnumerator)]) {
524 e = [(id)sessionId objectEnumerator];
525 while ((sessionId = [e nextObject])) {
526 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
531 if ([sessionId length] > 0 && ![sessionId isEqual:@"nil"])
539 - (NSString *)createSessionIDForSession:(WOSession *)_session {
540 /* session id must be 18 chars long for snsd to work ! */
541 static unsigned int sessionCount = 0;
543 unsigned char buf[20];
546 sprintf(buf, "%04X%04X%02X%08X",
547 [[self number] intValue], getpid(), sessionCount,
548 (unsigned int)time(NULL));
549 wosid = [NSString stringWithCString:buf];
553 - (WOSession *)createSessionForRequest:(WORequest *)_request {
554 if ([self respondsToSelector:@selector(createSession)]) {
555 /* call deprecated method */
556 [self logWarnWithFormat:@"calling deprecated -createSession .."];
557 return [self createSession];
562 if ((snClass = NSClassFromString(@"Session")) == Nil)
563 snClass = [WOSession class];
565 return [[snClass alloc] init];
569 - (WOSession *)restoreSessionWithID:(NSString *)_sid
570 inContext:(WOContext *)_ctx
576 if ([self respondsToSelector:@selector(restoreSession)]) {
577 /* call deprecated method */
578 [self logWarnWithFormat:@"calling deprecated -restoreSession .."];
579 return [self restoreSession];
583 WOSessionStore *store;
585 if ((store = [self sessionStore]) == nil) {
586 [self logErrorWithFormat:@"missing session store ..."];
589 session = [store restoreSessionWithID:_sid request:[_ctx request]];
591 [_ctx setSession:session];
592 [session _awakeWithContext:_ctx];
595 [self debugWithFormat:@"did not find a session for sid '%@'", _sid];
602 [[NSNotificationCenter defaultCenter]
603 postNotificationName:WOSessionDidRestoreNotification
607 if ([_sid hasPrefix:@"("]) {
610 sid = [_sid propertyList];
612 if ([sid respondsToSelector:@selector(objectEnumerator)]) {
615 [self logErrorWithFormat:@"got multiple session IDs !"];
617 e = [sid objectEnumerator];
618 while ((_sid = [e nextObject])) {
619 if ([_sid isEqualToString:@"nil"])
622 if ((session = [self restoreSessionWithID:_sid inContext:_ctx]))
625 //NSLog(@"WARNING: did not find session for sid %@", _sid);
632 - (void)saveSessionForContext:(WOContext *)_ctx {
633 NSTimeInterval startSave = 0.0;
636 startSave = [[NSDateClass date] timeIntervalSince1970];
638 if ([self respondsToSelector:@selector(saveSession:)]) {
639 /* call deprecated method */
640 [self logWarnWithFormat:@"calling deprecated -saveSession: .."];
641 [self saveSession:[_ctx session]];
647 NSTimeInterval startSnSleep = 0.0, startStore = 0.0;
652 startSnSleep = [[NSDateClass date] timeIntervalSince1970];
654 /* put session to sleep */
655 [sn _sleepWithContext:_ctx];
659 rt = [[NSDateClass date] timeIntervalSince1970] - startSnSleep;
660 [perfLogger logInfoWithFormat:@"[woapp]: session -sleep took %4.3fs.",
661 rt < 0.0 ? -1.0 : rt];
664 if ([sn isTerminating]) {
665 [[NSNotificationCenter defaultCenter]
666 postNotificationName:
667 WOSessionDidTerminateNotification
672 startStore = [[NSDateClass date] timeIntervalSince1970];
674 [[self sessionStore] saveSessionForContext:_ctx];
678 rt = [[NSDateClass date] timeIntervalSince1970] - startStore;
679 [perfLogger logInfoWithFormat:@"[woapp]: storing sn in store took %4.3fs.",
680 rt < 0.0 ? -1.0 : rt];
687 rt = [[NSDateClass date] timeIntervalSince1970] - startSave;
688 [perfLogger logInfoWithFormat:@"[woapp]: saveSessionForContext took %4.3fs.",
689 rt < 0.0 ? -1.0 : rt];
693 - (void)refuseNewSessions:(BOOL)_flag {
694 self->appFlags.doesRefuseNewSessions = _flag ? 1 : 0;
696 - (BOOL)isRefusingNewSessions {
697 return self->appFlags.doesRefuseNewSessions;
699 - (int)activeSessionsCount {
700 return [[self sessionStore] activeSessionsCount];
703 - (void)setSessionStore:(WOSessionStore *)_store {
704 ASSIGN(self->iSessionStore, _store);
706 - (NSString *)sessionStoreClassName {
707 return [[NSUserDefaults standardUserDefaults] stringForKey:@"WOSessionStore"];
709 - (WOSessionStore *)sessionStore {
710 return self->iSessionStore;
713 - (void)setMinimumActiveSessionsCount:(int)_minimum {
714 self->minimumActiveSessionsCount = _minimum;
716 - (int)minimumActiveSessionsCount {
717 return self->minimumActiveSessionsCount;
720 - (void)performExpirationCheck:(NSTimer *)_timer {
723 /* let session store check for expiration ... */
725 ss = [self sessionStore];
726 if ([ss respondsToSelector:@selector(performExpirationCheck:)])
727 [ss performExpirationCheck:_timer];
729 /* check whether application should terminate ... */
731 if ([self isRefusingNewSessions] &&
732 ([self activeSessionsCount] < [self minimumActiveSessionsCount])) {
733 /* check whether the application instance is still valid .. */
734 [self debugWithFormat:
735 @"application terminates because it refuses new sessions and "
736 @"the active session count (%i) is below the minimum (%i).",
737 [self activeSessionsCount], [self minimumActiveSessionsCount]];
742 - (WOSession *)session {
743 return [[self context] session];
746 - (WOResponse *)handleSessionCreationErrorInContext:(WOContext *)_ctx {
747 WOResponse *response = [_ctx response];
751 pid = GetCurrentProcessId();
756 if ([self respondsToSelector:@selector(handleSessionCreationError)]) {
757 [self logWarnWithFormat:@"called deprecated -handleSessionCreationError method"];
758 return [self handleSessionCreationError];
761 [self logErrorWithFormat:@"could not create session for context %@", _ctx];
763 [response setStatus:200];
764 [response appendContentString:@"<h4>Session Creation Error</h4>\n<pre>"];
765 [response appendContentString:
766 @"Application Instance failed to create session."];
767 [response appendContentHTMLString:
768 [NSString stringWithFormat:
769 @" application: %@\n"
776 [[_ctx request] adaptorPrefix],
780 [[_ctx request] description]]];
781 [response appendContentString:@"</pre>"];
785 - (WOResponse *)handleSessionRestorationErrorInContext:(WOContext *)_ctx {
786 if ([self respondsToSelector:@selector(handleSessionRestorationError)]) {
787 [self logWarnWithFormat:@"calling deprecated "
788 @"-handleSessionRestorationError method"];
789 return [self handleSessionRestorationError];
792 [self logErrorWithFormat:@"could not restore session for context %@", _ctx];
798 - (void)setStatisticsStore:(WOStatisticsStore *)_statStore {
799 ASSIGN(self->iStatisticsStore, _statStore);
801 - (WOStatisticsStore *)statisticsStore {
802 return self->iStatisticsStore;
805 - (bycopy NSDictionary *)statistics {
806 return [[self statisticsStore] statistics];
811 - (void)setResourceManager:(WOResourceManager *)_manager {
812 ASSIGN(self->resourceManager, _manager);
814 - (WOResourceManager *)resourceManager {
815 if (self->resourceManager == nil) {
819 if ([(p = [self path]) length] > 0)
820 [self logDebugWithFormat:@"setup WOResourceManager at path '%@' ...", p];
825 self->resourceManager =
826 [(WOResourceManager *)[WOResourceManager alloc] initWithPath:p];
828 return self->resourceManager;
833 WOContext *ctx = [self context];
835 n = [[ctx request] applicationName];
836 n = [@"/" stringByAppendingString:n ? n : [self name]];
838 return [NSURL URLWithString:n relativeToURL:[ctx baseURL]];
841 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
843 return [[self resourceManager] pathForResourceNamed:_name ofType:_type];
846 - (NSString *)stringForKey:(NSString *)_key
847 inTableNamed:(NSString *)_tableName
848 withDefaultValue:(NSString *)_default
851 return [[self resourceManager] stringForKey:_key
852 inTableNamed:_tableName
853 withDefaultValue:_default
855 [(WOSession *)[self session] languages]];
867 - (void)takeValuesFromRequest:(WORequest *)_req inContext:(WOContext *)_ctx {
868 if ([_ctx hasSession])
869 [[_ctx session] takeValuesFromRequest:_req inContext:_ctx];
873 if ((page = [_ctx page])) {
874 WOContext_enterComponent(_ctx, page, nil);
875 [page takeValuesFromRequest:_req inContext:_ctx];
876 WOContext_leaveComponent(_ctx, page);
881 - (id)invokeActionForRequest:(WORequest *)_rq inContext:(WOContext *)_ctx {
884 if ([_ctx hasSession])
885 result = [[_ctx session] invokeActionForRequest:_rq inContext:_ctx];
889 if ((page = [_ctx page])) {
890 WOContext_enterComponent(_ctx, page, nil);
891 result = [[_ctx page] invokeActionForRequest:_rq inContext:_ctx];
892 WOContext_leaveComponent(_ctx, page);
900 - (void)appendToResponse:(WOResponse *)_response inContext:(WOContext *)_ctx {
901 if ([_ctx hasSession])
902 [[_ctx session] appendToResponse:_response inContext:_ctx];
906 if ((page = [_ctx page])) {
907 WOContext_enterComponent(_ctx, page, nil);
908 [page appendToResponse:_response inContext:_ctx];
909 WOContext_leaveComponent(_ctx, page);
913 if(rapidTurnAroundPath != nil) {
916 if((page = [_ctx page])) {
919 template = [page _woComponentTemplate];
920 if([template isKindOfClass:WOTemplateClass]) {
923 _path = [[(WOTemplate *)template url] path];
924 [_response setHeader:_path
925 forKey:@"x-sope-template-path"];
934 - (WOElement *)dynamicElementWithName:(NSString *)_name
935 associations:(NSDictionary *)_associations
936 template:(WOElement *)_template
937 languages:(NSArray *)_languages
939 WOElement *element = nil;
940 Class dynamicElementClass = NSClassFromString(_name);
942 if (dynamicElementClass == Nil) {
943 [self logWarnWithFormat:@"did not find dynamic element class %@ !", _name];
946 if (![dynamicElementClass isDynamicElement]) {
947 [self logWarnWithFormat:@"class %@ is not a dynamic element class !", _name];
951 element = [[dynamicElementClass allocWithZone:[_template zone]]
953 associations:_associations
957 - (WOElement *)dynamicElementWithName:(NSString *)_name
958 associations:(NSDictionary *)_associations
959 template:(WOElement *)_template
961 return [self dynamicElementWithName:_name
962 associations:_associations
964 languages:[(WOSession *)[self session] languages]];
969 - (void)setPageRefreshOnBacktrackEnabled:(BOOL)_flag {
970 self->appFlags.isPageRefreshOnBacktrackEnabled = _flag ? 1 : 0;
972 - (BOOL)isPageRefreshOnBacktrackEnabled {
973 return self->appFlags.isPageRefreshOnBacktrackEnabled ? YES : NO;
976 - (void)setCachingEnabled:(BOOL)_flag {
977 self->appFlags.isCachingEnabled = _flag ? 1 : 0;
979 - (BOOL)isCachingEnabled {
980 // component definition caching
981 return self->appFlags.isCachingEnabled ? YES : NO;
984 - (void)setPageCacheSize:(int)_size {
985 self->pageCacheSize = _size;
987 - (int)pageCacheSize {
988 return self->pageCacheSize;
990 - (void)setPermanentPageCacheSize:(int)_size {
991 self->permanentPageCacheSize = _size;
993 - (int)permanentPageCacheSize {
994 return self->permanentPageCacheSize;
997 - (WOComponent *)pageWithName:(NSString *)_name {
999 return [self pageWithName:_name inContext:[self context]];
1002 - (WOComponent *)_pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
1004 OSX profiling: 3.4% of dispatchRequest?
1005 3.0% rm -pageWithName..
1006 1.5% def instantiate
1007 1.3% initWithName:...
1008 0.76% initWithContent:.. (0.43 addobserver)
1009 0.76% rm defForComp (0.43% touch)
1011 0.11% ctx -component
1016 NSAutoreleasePool *pool;
1017 WOResourceManager *rm;
1020 NSDictionary *start, *stop;
1021 start = [self memoryStatistics];
1024 pool = [[NSAutoreleasePool alloc] init];
1026 languages = [_ctx hasSession]
1027 ? [(WOSession *)[_ctx session] languages]
1028 : [[_ctx request] browserLanguages];
1030 if ((rm = [[_ctx component] resourceManager]) == nil)
1031 rm = [self resourceManager];
1033 page = [rm pageWithName:(_name != nil ? _name : @"Main")
1034 languages:languages];
1035 [page ensureAwakeInContext:_ctx];
1037 page = [page retain];
1042 int rss, vmsize, lib;
1043 stop = [self memoryStatistics];
1044 rss = [[stop objectForKey:@"VmRSS"] intValue] -
1045 [[start objectForKey:@"VmRSS"] intValue];
1046 vmsize = [[stop objectForKey:@"VmSize"] intValue] -
1047 [[start objectForKey:@"VmSize"] intValue];
1048 lib = [[stop objectForKey:@"VmLib"] intValue] -
1049 [[start objectForKey:@"VmLib"] intValue];
1050 [self logDebugWithFormat:@"loaded component %@; rss=%i vm=%i lib=%i.",
1051 _name, rss,vmsize,lib];
1055 return [page autorelease];
1057 - (WOComponent *)pageWithName:(NSString *)_name inContext:(WOContext *)_ctx {
1058 return [self _pageWithName:_name inContext:_ctx];
1060 - (WOComponent *)pageWithName:(NSString *)_name forRequest:(WORequest *)_req {
1061 WOResourceManager *rm;
1063 if ((rm = [self resourceManager]) == nil)
1066 return [rm pageWithName:(_name != nil) ? _name : @"Main"
1067 languages:[_req browserLanguages]];
1070 - (void)savePage:(WOComponent *)_page {
1072 [[[self context] session] savePage:_page];
1074 - (id)restorePageForContextID:(NSString *)_ctxId {
1076 return [[[self context] session] restorePageForContextID:_ctxId];
1079 - (WOResponse *)handlePageRestorationErrorInContext:(WOContext *)_ctx {
1080 [self logErrorWithFormat:
1081 @"could not restore page for context-id %@\n in context %@",
1082 [_ctx currentElementID], _ctx];
1084 /* return main page ... */
1085 return [[self pageWithName:nil inContext:_ctx] generateResponse];
1087 - (WOResponse *)handlePageRestorationError {
1089 return [self handlePageRestorationErrorInContext:[self context]];
1094 - (WOResponse *)handleException:(NSException *)_exc
1095 inContext:(WOContext *)_ctx
1097 WORequest *rq = [_ctx request];
1098 WOResponse *r = nil;
1100 if ([self respondsToSelector:@selector(handleException:)]) {
1101 [self logWarnWithFormat:@"calling deprecated -handleException method !"];
1102 return [self handleException:_exc];
1107 static int doCore = -1;
1109 doCore = [[NSUserDefaults standardUserDefaults]
1110 boolForKey:@"WOCoreOnApplicationException"]
1114 [self logFatalWithFormat:@"%@: caught (ctx=%@):\n %@.",
1122 [self logFatalWithFormat:@"%@: caught (without context):\n %@.",
1126 else if (rq == nil) {
1127 [self logFatalWithFormat:@"%@: caught (without request):\n %@.",
1132 static NSString *pageFormat =
1133 @"Application Server caught exception:\n\n"
1142 @" backtrace:\n%@\n";
1143 NSString *str = nil;
1146 [self logErrorWithFormat:@"%@: caught:\n %@\nin context:\n %@.",
1149 #if LIB_FOUNDATION_LIBRARY
1150 if ([NSException respondsToSelector:@selector(backtrace)])
1151 bt = [NSException backtrace];
1154 if ((r = [WOResponse responseWithRequest:rq]) == nil)
1155 [self logErrorWithFormat:@"could not create response !"];
1157 [r setHeader:@"text/html" forKey:@"content-type"];
1158 [r setHeader:@"no-cache" forKey:@"cache-control"];
1159 if(rapidTurnAroundPath != nil) {
1162 templateURL = [[_exc userInfo] objectForKey:@"templateURL"];
1163 if(templateURL != nil)
1164 [r setHeader:[templateURL path] forKey:@"x-sope-template-path"];
1167 str = [NSString stringWithFormat:pageFormat,
1169 ? [[_ctx session] sessionID]
1174 NSStringFromClass([_exc class]),
1177 [[_exc userInfo] description],
1180 [r appendContentString:@"<html><head><title>Caught exception</title></head><body><pre>\n"];
1181 [r appendContentHTMLString:str];
1182 [r appendContentString:@"</pre></body></html>\n"];
1189 - (BOOL)shouldTerminate {
1190 if (![self isRefusingNewSessions])
1192 if ([self activeSessionsCount] >= [self minimumActiveSessionsCount])
1195 /* check whether the application instance is still valid .. */
1196 [self debugWithFormat:
1197 @"application terminates because it refuses new sessions and "
1198 @"the active session count (%i) is below the minimum (%i).",
1199 [self activeSessionsCount], [self minimumActiveSessionsCount]];
1204 [self debugWithFormat:
1205 @"application terminates:\n"
1206 @" %i active sessions\n"
1207 @" %i minimum active sessions\n"
1208 @" refuses new session: %s",
1209 [self activeSessionsCount],
1210 [self minimumActiveSessionsCount],
1211 [self isRefusingNewSessions] ? "yes" : "no"];
1217 - (BOOL)isDebuggingEnabled {
1220 - (NSString *)loggingPrefix {
1221 return [NSString stringWithFormat:@"|%@%@|",
1223 [self isTerminating] ? @" terminating" : @""];
1228 #if !LIB_FOUNDATION_LIBRARY
1229 - (id)valueForUndefinedKey:(NSString *)_key {
1230 [self logWarnWithFormat:@"tried to access undefined KVC key: '%@'",
1238 + (Class)eoEditingContextClass {
1239 static Class eoEditingContextClass = Nil;
1240 static BOOL lookedUpForEOEditingContextClass = NO;
1242 if (!lookedUpForEOEditingContextClass) {
1243 eoEditingContextClass = NSClassFromString(@"EOEditingContext");
1244 lookedUpForEOEditingContextClass = YES;
1246 return eoEditingContextClass;
1249 + (BOOL)implementsEditingContexts {
1250 return [self eoEditingContextClass] != NULL ? YES : NO;
1255 - (NSString *)description {
1256 return [NSString stringWithFormat:@"<%@[0x%08X]: name=%@%@>",
1257 NSStringFromClass([self class]), self,
1259 [self isTerminating] ? @" terminating" : @""
1263 @end /* WOApplication */