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 // ATTENTION: this class is for OGo legacy, so that WO compatibility changes
23 // to WOResourceManager do not break OGo.
24 // So: do not use that class, its DEPRECATED!
26 #include <NGObjWeb/OWResourceManager.h>
27 #include <NGObjWeb/WOComponentDefinition.h>
28 #include "WOComponent+private.h"
29 #include <NGObjWeb/WORequest.h>
30 #include <NGObjWeb/WOApplication.h>
32 #import <Foundation/NSNull.h>
33 #include "_WOStringTable.h"
36 Component Discovery and Page Creation
38 All WO code uses either directly or indirectly the OWResourceManager's
39 -pageWithName:languages: method to instantiate WO components.
41 This methods works in three steps:
43 1. discovery of files associated with the component
44 - (WOComponentDefinition *)definitionForComponent:(id)_name
45 inFramework:(NSString *)_framework
46 languages:(NSArray *)_languages
48 2. creation of a proper WOComponentDefinition, which is some kind
49 of 'blueprint' or 'class' for components
51 3. component instantiation using the definition
53 All the instantiation/setup work is done by a component definition, the
54 resource manager is only responsible for managing those 'blueprint'
57 If you want to customize component creation, you can supply your
58 own WOComponentDefinition in a subclass of OWResourceManager by
60 - (WOComponentDefinition *)definitionForComponent:(id)_name
61 inFramework:(NSString *)_frameworkName
62 languages:(NSArray *)_languages
64 Notably in WO 5.3 the WOResourceManager doesn't seem to handle components
69 Note: this was #if !COMPILE_FOR_GSTEP_MAKE - but there is no difference
70 between Xcode and gstep-make?!
71 The only possible difference might be that .wo wrappers are directly
72 in the bundle/framework root - but this doesn't relate to Resources.
74 OK, this breaks gstep-make based template lookup which places .wo
75 wrappers in .woa/Resources/xxx.wo.
76 This is an issue because .wox are looked up in Contents/Resources
77 but .wo ones in just Resources.
79 This issue should be fixed in recent woapp-gs.make ...
81 #if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
82 # define RSRCDIR_CONTENTS 1
85 @implementation OWResourceManager
91 static NSFileManager *fm = nil;
92 static Class UrlClass = Nil;
93 static NSString *resourcePrefix = @"";
94 static NSString *rapidTurnAroundPath = nil;
95 static NSNull *null = nil;
96 static BOOL debugOn = NO;
97 static BOOL debugComponentLookup = NO;
98 static BOOL debugResourceLookup = NO;
99 static BOOL genMissingResourceLinks = NO;
102 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
103 static BOOL isInitialized = NO;
105 if (isInitialized) return;
108 fm = [[NSFileManager defaultManager] retain];
109 null = [[NSNull null] retain];
110 UrlClass = [NSURL class];
112 defs = [NSDictionary dictionaryWithObjectsAndKeys:
113 [NSArray arrayWithObject:@"wo"],
114 @"WOComponentExtensions",
116 [ud registerDefaults:defs];
117 debugOn = [WOApplication isDebuggingEnabled];
118 debugComponentLookup = [ud boolForKey:@"WODebugComponentLookup"];
119 debugResourceLookup = [ud boolForKey:@"WODebugResourceLookup"];
120 genMissingResourceLinks = [ud boolForKey:@"WOGenerateMissingResourceLinks"];
121 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
125 _pathExists(OWResourceManager *self, NSFileManager *fm, NSString *path)
129 if (self->existingPathes && (path != nil)) {
132 i = (int)NSMapGet(self->existingPathes, path);
134 doesExist = [fm fileExistsAtPath:path];
135 NSMapInsert(self->existingPathes, path, (void*)(doesExist ? 1 : 0xFF));
138 doesExist = i == 1 ? YES : NO;
141 doesExist = [fm fileExistsAtPath:path];
145 + (void)setResourcePrefix:(NSString *)_prefix {
146 [resourcePrefix autorelease];
147 resourcePrefix = [_prefix copy];
150 - (id)initWithPath:(NSString *)_path {
151 if ((self = [super init])) {
152 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
153 NSString *rprefix = nil;
156 self->componentDefinitions =
157 NSCreateMapTable(NSObjectMapKeyCallBacks,
158 NSObjectMapValueCallBacks,
161 NSCreateMapTable(NSObjectMapKeyCallBacks,
162 NSObjectMapValueCallBacks,
165 tmp = [_path stringByStandardizingPath];
166 if (tmp) _path = tmp;
168 self->base = [_path copy];
170 if ([WOApplication isCachingEnabled]) {
171 self->existingPathes = NSCreateMapTable(NSObjectMapKeyCallBacks,
172 NSIntMapValueCallBacks,
176 rprefix = [ud stringForKey:@"WOResourcePrefix"];
177 if (rprefix) [[self class] setResourcePrefix:rprefix];
182 return [self initWithPath:[[NGBundle mainBundle] bundlePath]];
186 if (self->existingPathes) NSFreeMapTable(self->existingPathes);
187 if (self->stringTables) NSFreeMapTable(self->stringTables);
188 if (self->componentDefinitions) NSFreeMapTable(self->componentDefinitions);
189 if (self->keyedResources) NSFreeMapTable(self->keyedResources);
190 [self->w3resources release];
191 [self->resources release];
192 [self->base release];
198 - (BOOL)isDebuggingEnabled {
204 - (NSFileManager *)fileManager {
205 static NSFileManager *fm = nil;
207 fm = [[NSFileManager defaultManager] retain];
211 - (NSString *)basePath {
215 - (NSString *)resourcesPath {
219 return self->resources;
221 fm = [self fileManager];
222 if ([self->base length] > 0) {
223 if (![fm fileExistsAtPath:self->base]) {
224 NSLog(@"WARNING(%s): Resources base path '%@' does not exist !",
225 __PRETTY_FUNCTION__, self->base);
231 if ([rapidTurnAroundPath length] > 0) {
233 In rapid turnaround mode, first check for a Resources subdir in the
234 project directory, then directly in the project dir.
235 Note: you cannot have both! Either put stuff in a Resources subdir *or*
241 tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
242 if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
245 tmp = rapidTurnAroundPath;
247 self->resources = [tmp copy];
251 [[[self->base stringByAppendingPathComponent:@"Contents"]
252 stringByAppendingPathComponent:@"Resources"]
257 [[self->base stringByAppendingPathComponent:@"Resources"] copy];
260 if ([self->resources length] > 0) {
261 if (![fm fileExistsAtPath:self->resources]) {
262 [self debugWithFormat:
263 @"WARNING(%s): Resources path %@ does not exist !",
264 __PRETTY_FUNCTION__, self->resources];
265 [self->resources release]; self->resources = nil;
267 else if (self->existingPathes && (self->resources != nil))
268 NSMapInsert(self->existingPathes, self->resources, (void*)1);
270 return self->resources;
273 - (NSString *)resourcesPathForFramework:(NSString *)_fw {
275 return [self resourcesPath];
278 return [[_fw stringByAppendingPathComponent:@"Contents"]
279 stringByAppendingPathComponent:@"Resources"];
281 return [_fw stringByAppendingPathComponent:@"Resources"];
285 - (NSString *)webServerResourcesPath {
288 if (self->w3resources)
289 return self->w3resources;
291 #if GNUSTEP_BASE_LIBRARY && 0
293 [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
296 [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
299 fm = [self fileManager];
300 if ([self->w3resources length] == 0)
303 if (![fm fileExistsAtPath:self->w3resources]) {
304 static BOOL didLog = NO;
307 [self debugWithFormat:
308 @"WARNING(%s): WebServerResources path '%@' does not exist !",
309 __PRETTY_FUNCTION__, self->w3resources];
311 [self->w3resources release]; self->w3resources = nil;
313 else if (self->existingPathes && (self->w3resources != nil))
314 NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
316 if (debugResourceLookup)
317 [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
318 return self->w3resources;
321 - (NSString *)_lookupResourceNamed:(NSString *)_name inPath:(NSString *)_path
322 inFramework:(NSString *)_frameworkName
323 languages:(NSArray *)_languages
325 unsigned i, langCount;
331 // first check Language.lproj in WebServerResources
332 for (i = 0, langCount = [_languages count]; i < langCount; i++) {
335 langPath = [_languages objectAtIndex:i];
336 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
337 langPath = [_path stringByAppendingPathComponent:langPath];
339 if (!_pathExists(self, fm, langPath)) {
340 if (debugResourceLookup) {
342 @" no language lproj for '%@' in path: %@",
343 [_languages objectAtIndex:i], _path];
348 resource = [langPath stringByAppendingPathComponent:_name];
350 if (_pathExists(self, fm, resource)) {
351 if (debugResourceLookup)
352 [self logWithFormat:@" found path: %@", resource];
355 else if (debugResourceLookup)
356 [self logWithFormat:@" not found in path: %@", resource];
359 /* next check in resources path (WebServerResources or Resources) itself */
360 resource = [_path stringByAppendingPathComponent:_name];
361 if (debugResourceLookup)
362 [self logWithFormat:@" check for flat path: %@", resource];
363 if (_pathExists(self, fm, resource))
369 - (BOOL)shouldLookupResourceInWebServerResources:(NSString *)_name {
370 if ([_name hasSuffix:@".wox"]) return NO;
371 if ([_name hasSuffix:@".wo"]) return NO;
375 - (NSString *)pathForResourceNamed:(NSString *)_name
376 inFramework:(NSString *)_frameworkName
377 languages:(NSArray *)_languages
380 Note: at least in the case of OGo component lookups the framework name is
381 properly filled with the OGo bundle path on lookup, so no
382 NGBundleManager query is necessary.
385 NSString *resource = nil;
388 if (debugResourceLookup) {
389 [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@",
390 _name, _frameworkName, [_languages componentsJoinedByString:@","]];
393 fm = [self fileManager];
394 langCount = [_languages count];
396 /* now check in webserver resources path */
398 if ([self shouldLookupResourceInWebServerResources:_name]) {
399 resource = [self _lookupResourceNamed:_name
400 inPath:[self webServerResourcesPath]
401 inFramework:_frameworkName languages:_languages];
402 if (resource != nil) return resource;
405 /* now check in regular resources path */
407 resource = [self _lookupResourceNamed:_name
408 inPath:[self resourcesPathForFramework:_frameworkName]
409 inFramework:_frameworkName languages:_languages];
410 if (resource != nil) return resource;
412 /* and last check in the application directory */
413 if (_pathExists(self, fm, self->base)) {
414 resource = [self->base stringByAppendingPathComponent:_name];
415 if (_pathExists(self, fm, resource))
421 - (NSString *)pathForResourceNamed:(NSString *)_name {
423 return [self pathForResourceNamed:_name inFramework:nil languages:nil];
426 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
427 _name = [_name stringByAppendingPathExtension:_type];
428 return [self pathForResourceNamed:_name];
433 - (NSString *)urlForResourceNamed:(NSString *)_name
434 inFramework:(NSString *)_frameworkName
435 languages:(NSArray *)_languages
436 request:(WORequest *)_request
439 NSString *resource = nil, *tmp;
441 app = [WOApplication application];
443 if (_languages == nil)
444 _languages = [_request browserLanguages];
446 resource = [self pathForResourceNamed:_name
447 inFramework:_frameworkName
448 languages:_languages];
450 if ([resource rangeOfString:@"/Contents/"].length > 0) {
451 resource = [resource stringByReplacingString:@"/Contents"
456 tmp = [resource stringByStandardizingPath];
457 if (tmp) resource = tmp;
461 NSString *path = nil, *sbase;
465 tmp = [sbase commonPrefixWithString:resource options:0];
468 path = [sbase substringFromIndex:len];
469 tmp = [resource substringFromIndex:len];
470 if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
471 path = [path stringByAppendingString:@"/"];
472 path = [path stringByAppendingString:tmp];
477 cs = [path componentsSeparatedByString:@"\\"];
478 path = [cs componentsJoinedByString:@"/"];
483 static NSString *suffix = nil;
484 NSMutableString *url = nil;
487 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
488 suffix = [ud stringForKey:@"WOApplicationSuffix"];
491 url = [[NSMutableString alloc] initWithCapacity:256];
493 [url appendString:[_request adaptorPrefix]];
496 [url appendString:resourcePrefix];
497 if (![url hasSuffix:@"/"]) [url appendString:@"/"];
498 [url appendString:app ? [app name] : [_request applicationName]];
499 [url appendString:suffix];
500 if (![path hasPrefix:@"/"]) [url appendString:@"/"];
501 [url appendString:path];
506 return [path autorelease];
510 if (genMissingResourceLinks) {
511 return [NSString stringWithFormat:
512 @"/missingresource?name=%@&application=%@",
513 _name, app ? [app name] : [_request applicationName]];
518 - (NSString *)urlForResourceNamed:(NSString *)_name {
520 return [self urlForResourceNamed:_name
525 - (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
526 return [self urlForResourceNamed:
527 [_name stringByAppendingPathExtension:_type]];
532 - (NSString *)stringForKey:(NSString *)_key
533 inTableNamed:(NSString *)_tableName
534 withDefaultValue:(NSString *)_defaultValue
535 inFramework:(NSString *)_framework
536 languages:(NSArray *)_languages;
539 _WOStringTable *table = nil;
540 NSString *path = nil;
542 fm = [self fileManager];
544 if (_tableName == nil)
545 _tableName = @"default";
547 /* take a look whether a matching table is already loaded */
549 path = [_tableName stringByAppendingPathExtension:@"strings"];
550 path = [self pathForResourceNamed:path inFramework:_framework
551 languages:_languages];
554 if ((table = NSMapGet(self->stringTables, path)) == NULL) {
555 if ([fm fileExistsAtPath:path]) {
556 table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
557 table = [table initWithPath:path];
558 NSMapInsert(self->stringTables, path, table);
563 return [table stringForKey:_key withDefaultValue:_defaultValue];
565 /* didn't found table in cache */
567 return _defaultValue;
570 - (NSString *)stringForKey:(NSString *)_key
571 inTableNamed:(NSString *)_tableName
572 withDefaultValue:(NSString *)_default
573 languages:(NSArray *)_languages
575 return [self stringForKey:_key inTableNamed:_tableName
576 withDefaultValue:_default
578 languages:_languages];
589 /* component definitions */
591 - (NSString *)pathToComponentNamed:(NSString *)_name
592 inFramework:(NSString *)_framework
593 languages:(NSArray *)_langs
595 /* search for component wrapper .. */
596 // TODO: shouldn't we used that for WOx as well?
602 NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
603 __PRETTY_FUNCTION__);
608 /* scan for name.$ext resource ... */
609 e = [[[NSUserDefaults standardUserDefaults]
610 arrayForKey:@"WOComponentExtensions"]
613 while ((ext = [e nextObject])) {
617 specName = [_name stringByAppendingPathExtension:ext];
619 path = [self pathForResourceNamed:specName
620 inFramework:_framework
622 if (path != nil) return path;
627 - (NSString *)pathToComponentNamed:(NSString *)_name
628 inFramework:(NSString *)_fw
630 // TODO: is this still used somewhere?
631 return [self pathToComponentNamed:_name inFramework:_fw languages:nil];
634 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
635 languages:(NSArray *)_languages
637 /* definition factory */
638 WOComponentDefinition *cdef;
640 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
646 return [cdef autorelease];
649 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
651 baseURL:(NSURL *)_baseURL
652 frameworkName:(NSString *)_fwname
654 /* definition factory */
655 static Class DefClass;
659 DefClass = [WOComponentDefinition class];
661 cdef = [[DefClass alloc] initWithName:_name
663 baseURL:_baseURL frameworkName:_fwname];
666 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
667 path:(NSString *)_path
668 baseURL:(NSURL *)_baseURL
669 frameworkName:(NSString *)_fwname
673 url = ([_path length] > 0)
674 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
677 return [self _definitionWithName:_name url:url
678 baseURL:_baseURL frameworkName:_fwname];
681 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
682 languages:(NSArray *)_languages
687 if (self->componentDefinitions == NULL)
689 if (![[WOApplication application] isCachingEnabled])
692 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
693 cdef = NSMapGet(self->componentDefinitions, cacheKey);
697 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
698 forComponent:(id)_name
699 languages:(NSArray *)_languages
703 if (self->componentDefinitions == NULL)
705 if (![[WOApplication application] isCachingEnabled])
708 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
709 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
714 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
715 return [_name stringByAppendingPathExtension:@"wox"];
718 - (BOOL)_isValidWrapperDirectory:(NSString *)_path
719 containingTemplate:(NSString *)_name
722 Check whether this actually does contain a template!
724 This is new and hopefully doesn't break anything, but as far as I can
725 see checking for Component.html inside should do the right thing (unless
726 there are template wrappers which are not .wo wrappers ;-)
730 htmlPath = [_name stringByAppendingPathExtension:@"html"];
731 htmlPath = [_path stringByAppendingPathComponent:htmlPath];
732 return [[self fileManager] fileExistsAtPath:htmlPath];
735 - (WOComponentDefinition *)_processWrapperLanguageProjects:(NSString *)_name
736 componentPath:(NSString *)componentPath
737 languages:(NSArray *)_langs
740 this looks for language projects contained in template wrapper
741 directories, eg "Main.wo/English.lproj/"
743 WOComponentDefinition *cdef = nil;
744 NSFileManager *fm = nil;
745 NSEnumerator *languages;
750 if ([_langs count] == 0)
753 doesCache = [[WOApplication application] isCachingEnabled];
754 fm = [self fileManager];
755 sname = [_name stringByAppendingString:@"\t"];
757 languages = [_langs objectEnumerator];
758 while ((language = [languages nextObject])) {
759 NSString *compoundKey = nil;
760 NSString *languagePath = nil;
761 BOOL isDirectory = NO;
762 NSString *baseUrl = nil;
764 // [self logWithFormat:@"check %@ / %@", _name, language];
766 compoundKey = [sname stringByAppendingString:language];
768 cdef = NSMapGet(self->componentDefinitions, compoundKey);
770 if (cdef == (id)null)
771 /* resource does not exist */
775 if (cdef) return cdef; // found definition in cache
778 /* take a look into the file system */
779 languagePath = [language stringByAppendingPathExtension:@"lproj"];
780 languagePath = [componentPath stringByAppendingPathComponent:languagePath];
782 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
784 // register null in cache, so that we know it's non-existent
785 NSMapInsert(self->componentDefinitions, compoundKey, null);
791 NSLog(@"WARNING(%s): language entry %@ is not a directory !",
792 __PRETTY_FUNCTION__, languagePath);
793 if (doesCache && (compoundKey != nil)) {
794 // register null in cache, so that we know it's non-existent
795 NSMapInsert(self->componentDefinitions, compoundKey, null);
801 Now check whether this actually does contain a template!
803 This is new and hopefully doesn't break anything, but as far as I can
804 see checking for Component.html inside should do the right thing (unless
805 there are template wrappers which are not .wo wrappers ;-)
807 if (![self _isValidWrapperDirectory:languagePath
808 containingTemplate:_name]){
809 [self debugWithFormat:@"no HTML template for inside lproj '%@': '%@'",
810 _name, languagePath];
811 if (doesCache && (compoundKey != nil)) {
812 // register null in cache, so that we know it's non-existent
813 NSMapInsert(self->componentDefinitions, compoundKey, null);
818 /* construct the base URL */
820 baseUrl = [[[WOApplication application] baseURL] absoluteString];
821 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
822 baseUrl, language, _name];
824 /* create WOComponentDefinition object */
826 cdef = [self _definitionWithName:_name
828 baseURL:[NSURL URLWithString:baseUrl]
831 NSLog(@"WARNING(%s): could not load component definition of "
832 @"'%@' from language project: %@",
833 __PRETTY_FUNCTION__, _name, languagePath);
834 if (doesCache && (compoundKey != nil)) {
835 // register null in cache, so that we know it's non-existent
836 NSMapInsert(self->componentDefinitions, compoundKey, null);
841 if (doesCache && (compoundKey != nil)) {
843 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
847 // don't register in cache
848 cdef = [cdef autorelease];
854 return nil; /* no lproj containing templates was found */
857 - (NSString *)defaultFrameworkForComponentNamed:(NSString *)_name {
860 if (rapidTurnAroundPath != nil)
861 return rapidTurnAroundPath;
863 if ((clazz = NSClassFromString(_name)) == nil)
866 return [[NSBundle bundleForClass:clazz] bundlePath];
869 - (WOComponentDefinition *)definitionForComponent:(id)_name
870 inFramework:(NSString *)_framework
871 languages:(NSArray *)_languages
873 /* this is the primary method for finding a definition */
874 // TODO: this method is too large
876 NSFileManager *fm = nil;
877 WOComponentDefinition *cdef = nil;
879 BOOL doesCache, isDir;
881 app = [WOApplication application];
882 doesCache = [app isCachingEnabled];
884 /* lookup component path */
886 if ([_name isKindOfClass:UrlClass]) {
887 componentURL = _name;
888 _name = [componentURL path];
889 if (debugComponentLookup) {
890 [self debugWithFormat:@"using URL %@ for component %@",
891 componentURL, _name];
898 Note: this is a bit of a hack ..., actually this method should never
899 be called without a framework and pages shouldn't be instantiated
900 without specifying their framework.
901 But for legacy reasons this needs to be done and seems to work
902 without problems. It is required for loading components from
905 if (_framework == nil && _name != nil)
906 _framework = [self defaultFrameworkForComponentNamed:_name];
908 if (debugComponentLookup) {
909 [self logWithFormat:@"lookup: component '%@' in framework '%@'",
913 /* look for .wox component */
915 // TODO: why don't we use -pathForComponentNamed: here?
916 path = [self pathForResourceNamed:
917 [self resourceNameForComponentNamed:_name]
918 inFramework:_framework
919 languages:_languages];
921 if (debugComponentLookup)
922 [self logWithFormat:@"lookup: path-to-resource: '%@'", path];
924 /* look for .wo component */
926 if ([path length] == 0) {
927 path = [self pathToComponentNamed:_name
928 inFramework:_framework
929 languages:_languages];
930 if (debugComponentLookup)
931 [self logWithFormat:@"lookup: path-to-component: '%@'", path];
934 /* make URL from path */
936 componentURL = ([path length] > 0)
937 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
941 if (debugComponentLookup) {
942 [self logWithFormat:@" component='%@' in framework='%@'",
944 [self logWithFormat:@" => '%@'", [componentURL absoluteString]];
947 /* check whether it's a 'template-less' component ... */
949 if (componentURL == nil) {
950 /* did not find component wrapper ! */
951 [app debugWithFormat:@" component '%@' has no template !", _name];
953 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
957 fm = [self fileManager];
959 /* ensure that the component exists */
962 if ([componentURL isFileURL]) {
963 NSString *componentPath;
965 componentPath = [componentURL path];
967 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
968 [[WOApplication application]
970 @"%s: did not find component '%@' at path '%@' !",
972 _name, componentPath];
976 /* if the component spec is a directory (eg a .wo), scan lproj's inside */
977 if (isDir && [_languages count] > 0) {
978 if (debugComponentLookup) {
979 [self logWithFormat:@" check wrapper languages (%d)",
982 cdef = [self _processWrapperLanguageProjects:_name
983 componentPath:componentPath
984 languages:_languages];
986 if (debugComponentLookup)
987 [self logWithFormat:@" => FOUND: %@", cdef];
990 else if (debugComponentLookup)
991 [self logWithFormat:@" ... no language template found ..."];
998 cdef = NSMapGet(self->componentDefinitions, componentURL);
999 if (cdef == (id)null)
1000 /* resource does not exist */
1004 if (cdef != nil) return cdef; // found definition in cache
1008 in case the "componentURL" is a directory, check whether it contains
1012 if (![self _isValidWrapperDirectory:[componentURL path]
1013 containingTemplate:_name]) {
1014 if (debugComponentLookup)
1015 [self logWithFormat:@" not a valid wrapper '%@': '%@'",
1016 _name, [componentURL absoluteString]];
1018 /* register null in cache, so that we know it's non-existent */
1019 NSMapInsert(self->componentDefinitions, componentURL, null);
1025 /* take a look into the file system */
1027 NSString *baseUrl = nil;
1029 baseUrl = [NSString stringWithFormat:@"%@/%@",
1030 [[app baseURL] absoluteString],
1031 [_name lastPathComponent]];
1033 cdef = [self _definitionWithName:_name
1035 baseURL:[NSURL URLWithString:baseUrl]
1038 NSLog(@"WARNING(%s): could not load component definition of '%@' from "
1039 @"component wrapper: '%@'",
1040 __PRETTY_FUNCTION__, _name, componentURL);
1042 /* register null in cache, so that we know it's non-existent */
1043 NSMapInsert(self->componentDefinitions, componentURL, null);
1049 /* register in cache */
1050 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1054 /* don't register in cache, does not cache */
1055 cdef = [cdef autorelease];
1060 /* did not find component */
1063 - (WOComponentDefinition *)definitionForComponent:(id)_name
1064 languages:(NSArray *)_langs
1066 /* Note: the framework will be determined base on the class '_name' */
1067 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1072 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1073 languages:(NSArray *)_languages
1075 // TODO: this should add the framework parameter and maybe a context
1076 WOComponentDefinition *cdef;
1078 /* look into cache */
1080 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1082 if (cdef == (id)null)
1083 /* component does not exist */
1086 if ([cdef respondsToSelector:@selector(touch)])
1091 /* not cached, create a definition */
1093 cdef = [self definitionForComponent:_name languages:_languages];
1095 /* cache created definition */
1097 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1100 /* primary call-in's */
1102 - (WOElement *)templateWithName:(NSString *)_name
1103 languages:(NSArray *)_languages
1105 WOComponentDefinition *cdef;
1107 cdef = [self __definitionForComponent:_name languages:_languages];
1108 if (cdef == nil) return nil;
1110 return (WOElement *)[cdef template];
1113 - (WOComponent *)pageWithName:(NSString *)_name
1114 languages:(NSArray *)_languages
1117 TODO: this appears to be deprecated since the WOComponent initializer
1118 is now -initWithContext: and we have no context here ...
1119 Also misses the framework?
1121 NSAutoreleasePool *pool = nil;
1122 WOComponentDefinition *cdef = nil;
1123 WOComponent *component = nil;
1125 pool = [[NSAutoreleasePool alloc] init];
1127 cdef = [self __definitionForComponent:_name languages:_languages];
1130 [cdef instantiateWithResourceManager:(WOResourceManager *)self
1131 languages:_languages];
1132 component = [component retain];
1137 return [component autorelease];
1142 - (void)setData:(NSData *)_data
1143 forKey:(NSString *)_key
1144 mimeType:(NSString *)_type
1145 session:(WOSession *)_session
1147 if ((_key == nil) || (_data == nil))
1150 _type = @"application/octet-stream";
1154 if (self->keyedResources == NULL) {
1155 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1156 NSObjectMapValueCallBacks,
1160 NSMapInsert(self->keyedResources,
1162 [NSDictionary dictionaryWithObjectsAndKeys:
1171 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1176 if (self->keyedResources)
1177 tmp = NSMapGet(self->keyedResources, _key);
1181 tmp = [[tmp retain] autorelease];
1188 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1191 if (self->keyedResources)
1192 NSMapRemove(self->keyedResources, _key);
1197 - (void)flushDataCache {
1200 if (self->keyedResources) {
1201 NSFreeMapTable(self->keyedResources);
1202 self->keyedResources = NULL;
1210 - (NSString *)description {
1211 return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
1212 [self class], self, self->base];
1216 @end /* OWResourceManager */