2 Copyright (C) 2000-2005 SKYRIX Software AG
4 This file is part of SOPE.
6 SOPE 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 SOPE 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 SOPE; 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 [self warnWithFormat:@"(%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 warnWithFormat:
263 @"(%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 warnWithFormat:
308 @"(%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 use that for WOx as well?
602 [self warnWithFormat:@"(%s): tried to get path to component with "
604 __PRETTY_FUNCTION__];
609 /* scan for name.$ext resource ... */
610 e = [[[NSUserDefaults standardUserDefaults]
611 arrayForKey:@"WOComponentExtensions"]
614 while ((ext = [e nextObject])) {
618 specName = [_name stringByAppendingPathExtension:ext];
620 path = [self pathForResourceNamed:specName
621 inFramework:_framework
623 if (path != nil) return path;
628 - (NSString *)pathToComponentNamed:(NSString *)_name
629 inFramework:(NSString *)_fw
631 // TODO: is this still used somewhere?
632 return [self pathToComponentNamed:_name inFramework:_fw languages:nil];
635 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
636 languages:(NSArray *)_languages
638 /* definition factory */
639 WOComponentDefinition *cdef;
641 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
647 return [cdef autorelease];
650 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
652 baseURL:(NSURL *)_baseURL
653 frameworkName:(NSString *)_fwname
655 /* definition factory */
656 static Class DefClass;
660 DefClass = [WOComponentDefinition class];
662 cdef = [[DefClass alloc] initWithName:_name
664 baseURL:_baseURL frameworkName:_fwname];
667 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
668 path:(NSString *)_path
669 baseURL:(NSURL *)_baseURL
670 frameworkName:(NSString *)_fwname
674 url = ([_path length] > 0)
675 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
678 return [self _definitionWithName:_name url:url
679 baseURL:_baseURL frameworkName:_fwname];
682 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
683 languages:(NSArray *)_languages
688 if (self->componentDefinitions == NULL)
690 if (![[WOApplication application] isCachingEnabled])
693 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
694 cdef = NSMapGet(self->componentDefinitions, cacheKey);
698 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
699 forComponent:(id)_name
700 languages:(NSArray *)_languages
704 if (self->componentDefinitions == NULL)
706 if (![[WOApplication application] isCachingEnabled])
709 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
710 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
715 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
716 return [_name stringByAppendingPathExtension:@"wox"];
719 - (BOOL)_isValidWrapperDirectory:(NSString *)_path
720 containingTemplate:(NSString *)_name
723 Check whether this actually does contain a template!
725 This is new and hopefully doesn't break anything, but as far as I can
726 see checking for Component.html inside should do the right thing (unless
727 there are template wrappers which are not .wo wrappers ;-)
731 htmlPath = [_name stringByAppendingPathExtension:@"html"];
732 htmlPath = [_path stringByAppendingPathComponent:htmlPath];
733 return [[self fileManager] fileExistsAtPath:htmlPath];
736 - (WOComponentDefinition *)_processWrapperLanguageProjects:(NSString *)_name
737 componentPath:(NSString *)componentPath
738 languages:(NSArray *)_langs
741 this looks for language projects contained in template wrapper
742 directories, eg "Main.wo/English.lproj/"
744 WOComponentDefinition *cdef = nil;
745 NSFileManager *fm = nil;
746 NSEnumerator *languages;
751 if ([_langs count] == 0)
754 doesCache = [[WOApplication application] isCachingEnabled];
755 fm = [self fileManager];
756 sname = [_name stringByAppendingString:@"\t"];
758 languages = [_langs objectEnumerator];
759 while ((language = [languages nextObject])) {
760 NSString *compoundKey = nil;
761 NSString *languagePath = nil;
762 BOOL isDirectory = NO;
763 NSString *baseUrl = nil;
765 // [self logWithFormat:@"check %@ / %@", _name, language];
767 compoundKey = [sname stringByAppendingString:language];
769 cdef = NSMapGet(self->componentDefinitions, compoundKey);
771 if (cdef == (id)null)
772 /* resource does not exist */
776 if (cdef) return cdef; // found definition in cache
779 /* take a look into the file system */
780 languagePath = [language stringByAppendingPathExtension:@"lproj"];
781 languagePath = [componentPath stringByAppendingPathComponent:languagePath];
783 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
785 // register null in cache, so that we know it's non-existent
786 NSMapInsert(self->componentDefinitions, compoundKey, null);
792 [self warnWithFormat:@"(%s): language entry %@ is not a directory !",
793 __PRETTY_FUNCTION__, languagePath];
794 if (doesCache && (compoundKey != nil)) {
795 // register null in cache, so that we know it's non-existent
796 NSMapInsert(self->componentDefinitions, compoundKey, null);
802 Now check whether this actually does contain a template!
804 This is new and hopefully doesn't break anything, but as far as I can
805 see checking for Component.html inside should do the right thing (unless
806 there are template wrappers which are not .wo wrappers ;-)
808 if (![self _isValidWrapperDirectory:languagePath
809 containingTemplate:_name]){
810 [self debugWithFormat:@"no HTML template for inside lproj '%@': '%@'",
811 _name, languagePath];
812 if (doesCache && (compoundKey != nil)) {
813 // register null in cache, so that we know it's non-existent
814 NSMapInsert(self->componentDefinitions, compoundKey, null);
819 /* construct the base URL */
821 baseUrl = [[[WOApplication application] baseURL] absoluteString];
822 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
823 baseUrl, language, _name];
825 /* create WOComponentDefinition object */
827 cdef = [self _definitionWithName:_name
829 baseURL:[NSURL URLWithString:baseUrl]
832 [self warnWithFormat:@"(%s): could not load component definition of "
833 @"'%@' from language project: %@",
834 __PRETTY_FUNCTION__, _name, languagePath];
835 if (doesCache && (compoundKey != nil)) {
836 // register null in cache, so that we know it's non-existent
837 NSMapInsert(self->componentDefinitions, compoundKey, null);
842 if (doesCache && (compoundKey != nil)) {
844 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
848 // don't register in cache
849 cdef = [cdef autorelease];
855 return nil; /* no lproj containing templates was found */
858 - (NSString *)defaultFrameworkForComponentNamed:(NSString *)_name {
861 if (rapidTurnAroundPath != nil)
862 return rapidTurnAroundPath;
864 if ((clazz = NSClassFromString(_name)) == nil)
867 return [[NSBundle bundleForClass:clazz] bundlePath];
870 - (WOComponentDefinition *)definitionForComponent:(id)_name
871 inFramework:(NSString *)_framework
872 languages:(NSArray *)_languages
874 /* this is the primary method for finding a definition */
875 // TODO: this method is too large
877 NSFileManager *fm = nil;
878 WOComponentDefinition *cdef = nil;
880 BOOL doesCache, isDir;
882 app = [WOApplication application];
883 doesCache = [app isCachingEnabled];
885 /* lookup component path */
887 if ([_name isKindOfClass:UrlClass]) {
888 componentURL = _name;
889 _name = [componentURL path];
890 if (debugComponentLookup) {
891 [self debugWithFormat:@"using URL %@ for component %@",
892 componentURL, _name];
899 Note: this is a bit of a hack ..., actually this method should never
900 be called without a framework and pages shouldn't be instantiated
901 without specifying their framework.
902 But for legacy reasons this needs to be done and seems to work
903 without problems. It is required for loading components from
906 if (_framework == nil && _name != nil)
907 _framework = [self defaultFrameworkForComponentNamed:_name];
909 if (debugComponentLookup) {
910 [self logWithFormat:@"lookup: component '%@' in framework '%@'",
914 /* look for .wox component */
916 // TODO: why don't we use -pathForComponentNamed: here?
917 path = [self pathForResourceNamed:
918 [self resourceNameForComponentNamed:_name]
919 inFramework:_framework
920 languages:_languages];
922 if (debugComponentLookup)
923 [self logWithFormat:@"lookup: path-to-resource: '%@'", path];
925 /* look for .wo component */
927 if ([path length] == 0) {
928 path = [self pathToComponentNamed:_name
929 inFramework:_framework
930 languages:_languages];
931 if (debugComponentLookup)
932 [self logWithFormat:@"lookup: path-to-component: '%@'", path];
935 /* make URL from path */
937 componentURL = ([path length] > 0)
938 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
942 if (debugComponentLookup) {
943 [self logWithFormat:@" component='%@' in framework='%@'",
945 [self logWithFormat:@" => '%@'", [componentURL absoluteString]];
948 /* check whether it's a 'template-less' component ... */
950 if (componentURL == nil) {
951 /* did not find component wrapper ! */
952 [app debugWithFormat:@" component '%@' has no template !", _name];
954 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
958 fm = [self fileManager];
960 /* ensure that the component exists */
963 if ([componentURL isFileURL]) {
964 NSString *componentPath;
966 componentPath = [componentURL path];
968 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
969 [[WOApplication application]
971 @"%s: did not find component '%@' at path '%@' !",
973 _name, componentPath];
977 /* if the component spec is a directory (eg a .wo), scan lproj's inside */
978 if (isDir && [_languages count] > 0) {
979 if (debugComponentLookup) {
980 [self logWithFormat:@" check wrapper languages (%d)",
983 cdef = [self _processWrapperLanguageProjects:_name
984 componentPath:componentPath
985 languages:_languages];
987 if (debugComponentLookup)
988 [self logWithFormat:@" => FOUND: %@", cdef];
991 else if (debugComponentLookup)
992 [self logWithFormat:@" ... no language template found ..."];
999 cdef = NSMapGet(self->componentDefinitions, componentURL);
1000 if (cdef == (id)null)
1001 /* resource does not exist */
1005 if (cdef != nil) return cdef; // found definition in cache
1009 in case the "componentURL" is a directory, check whether it contains
1013 if (![self _isValidWrapperDirectory:[componentURL path]
1014 containingTemplate:_name]) {
1015 if (debugComponentLookup)
1016 [self logWithFormat:@" not a valid wrapper '%@': '%@'",
1017 _name, [componentURL absoluteString]];
1019 /* register null in cache, so that we know it's non-existent */
1020 NSMapInsert(self->componentDefinitions, componentURL, null);
1026 /* take a look into the file system */
1028 NSString *baseUrl = nil;
1030 baseUrl = [NSString stringWithFormat:@"%@/%@",
1031 [[app baseURL] absoluteString],
1032 [_name lastPathComponent]];
1034 cdef = [self _definitionWithName:_name
1036 baseURL:[NSURL URLWithString:baseUrl]
1039 [self warnWithFormat:@"(%s): could not load component definition of "
1040 @"'%@' from component wrapper: '%@'",
1041 __PRETTY_FUNCTION__, _name, componentURL];
1043 /* register null in cache, so that we know it's non-existent */
1044 NSMapInsert(self->componentDefinitions, componentURL, null);
1050 /* register in cache */
1051 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1055 /* don't register in cache, does not cache */
1056 cdef = [cdef autorelease];
1061 /* did not find component */
1064 - (WOComponentDefinition *)definitionForComponent:(id)_name
1065 languages:(NSArray *)_langs
1067 /* Note: the framework will be determined base on the class '_name' */
1068 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1073 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1074 languages:(NSArray *)_languages
1076 // TODO: this should add the framework parameter and maybe a context
1077 WOComponentDefinition *cdef;
1079 /* look into cache */
1081 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1083 if (cdef == (id)null)
1084 /* component does not exist */
1087 if ([cdef respondsToSelector:@selector(touch)])
1092 /* not cached, create a definition */
1094 cdef = [self definitionForComponent:_name languages:_languages];
1096 /* cache created definition */
1098 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1101 /* primary call-in's */
1103 - (WOElement *)templateWithName:(NSString *)_name
1104 languages:(NSArray *)_languages
1106 WOComponentDefinition *cdef;
1108 cdef = [self __definitionForComponent:_name languages:_languages];
1109 if (cdef == nil) return nil;
1111 return (WOElement *)[cdef template];
1114 - (WOComponent *)pageWithName:(NSString *)_name
1115 languages:(NSArray *)_languages
1118 TODO: this appears to be deprecated since the WOComponent initializer
1119 is now -initWithContext: and we have no context here ...
1120 Also misses the framework?
1122 NSAutoreleasePool *pool = nil;
1123 WOComponentDefinition *cdef = nil;
1124 WOComponent *component = nil;
1126 pool = [[NSAutoreleasePool alloc] init];
1128 cdef = [self __definitionForComponent:_name languages:_languages];
1131 [cdef instantiateWithResourceManager:(WOResourceManager *)self
1132 languages:_languages];
1133 component = [component retain];
1138 return [component autorelease];
1143 - (void)setData:(NSData *)_data
1144 forKey:(NSString *)_key
1145 mimeType:(NSString *)_type
1146 session:(WOSession *)_session
1148 if ((_key == nil) || (_data == nil))
1151 _type = @"application/octet-stream";
1155 if (self->keyedResources == NULL) {
1156 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1157 NSObjectMapValueCallBacks,
1161 NSMapInsert(self->keyedResources,
1163 [NSDictionary dictionaryWithObjectsAndKeys:
1172 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1177 if (self->keyedResources)
1178 tmp = NSMapGet(self->keyedResources, _key);
1182 tmp = [[tmp retain] autorelease];
1189 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1192 if (self->keyedResources)
1193 NSMapRemove(self->keyedResources, _key);
1198 - (void)flushDataCache {
1201 if (self->keyedResources) {
1202 NSFreeMapTable(self->keyedResources);
1203 self->keyedResources = NULL;
1211 - (NSString *)description {
1212 return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
1213 [self class], self, self->base];
1217 @end /* OWResourceManager */