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 // ATTENTION: this class is for OGo legacy, so that WO compatibility changes
24 // to WOResourceManager do not break OGo.
25 // So: do not use that class, its DEPRECATED!
27 #include <NGObjWeb/OWResourceManager.h>
28 #include <NGObjWeb/WOComponentDefinition.h>
29 #include "WOComponent+private.h"
30 #include <NGObjWeb/WORequest.h>
31 #include <NGObjWeb/WOApplication.h>
33 #import <Foundation/NSNull.h>
34 #include "_WOStringTable.h"
37 Component Discovery and Page Creation
39 All WO code uses either directly or indirectly the OWResourceManager's
40 -pageWithName:languages: method to instantiate WO components.
42 This methods works in three steps:
44 1. discovery of files associated with the component
46 2. creation of a proper WOComponentDefinition, which is some kind
47 of 'blueprint' or 'class' for components
49 3. component instantiation using the definition
51 All the instantiation/setup work is done by a component definition, the
52 resource manager is only responsible for managing those 'blueprint'
55 If you want to customize component creation, you can supply your
56 own WOComponentDefinition in a subclass of OWResourceManager by
58 - (WOComponentDefinition *)definitionForComponent:(id)_name
59 inFramework:(NSString *)_frameworkName
60 languages:(NSArray *)_languages
64 Note: this was #if !COMPILE_FOR_GSTEP_MAKE - but there is no difference
65 between Xcode and gstep-make?!
66 The only possible difference might be that .wo wrappers are directly
67 in the bundle/framework root - but this doesn't relate to Resources.
69 OK, this breaks gstep-make based template lookup which places .wo
70 wrappers in .woa/Resources/xxx.wo.
71 This is an issue because .wox are looked up in Contents/Resources
72 but .wo ones in just Resources.
74 This issue should be fixed in recent woapp-gs.make ...
76 #if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
77 # define RSRCDIR_CONTENTS 1
80 @implementation OWResourceManager
86 static Class UrlClass = Nil;
87 static NSString *resourcePrefix = @"";
88 static NSString *rapidTurnAroundPath = nil;
89 static NSNull *null = nil;
90 static BOOL debugOn = NO;
91 static BOOL debugComponentLookup = NO;
92 static BOOL debugResourceLookup = NO;
93 static BOOL genMissingResourceLinks = NO;
96 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
97 static BOOL isInitialized = NO;
99 if (isInitialized) return;
102 null = [[NSNull null] retain];
103 UrlClass = [NSURL class];
105 defs = [NSDictionary dictionaryWithObjectsAndKeys:
106 [NSArray arrayWithObject:@"wo"],
107 @"WOComponentExtensions",
109 [ud registerDefaults:defs];
110 debugOn = [WOApplication isDebuggingEnabled];
111 debugComponentLookup = [ud boolForKey:@"WODebugComponentLookup"];
112 debugResourceLookup = [ud boolForKey:@"WODebugResourceLookup"];
113 genMissingResourceLinks = [ud boolForKey:@"WOGenerateMissingResourceLinks"];
114 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
118 _pathExists(OWResourceManager *self, NSFileManager *fm, NSString *path)
122 if (self->existingPathes && (path != nil)) {
125 i = (int)NSMapGet(self->existingPathes, path);
127 doesExist = [fm fileExistsAtPath:path];
128 NSMapInsert(self->existingPathes, path, (void*)(doesExist ? 1 : 0xFF));
131 doesExist = i == 1 ? YES : NO;
134 doesExist = [fm fileExistsAtPath:path];
138 + (void)setResourcePrefix:(NSString *)_prefix {
139 [resourcePrefix autorelease];
140 resourcePrefix = [_prefix copy];
143 - (id)initWithPath:(NSString *)_path {
145 if ([_path length] == 0) {
146 NSLog(@"ERROR(%s): missing path!", __PRETTY_FUNCTION__);
147 /* this doesn't work with subclasses which do not require a path ... */
155 if ((self = [super init])) {
156 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
157 NSString *rprefix = nil;
160 self->componentDefinitions =
161 NSCreateMapTable(NSObjectMapKeyCallBacks,
162 NSObjectMapValueCallBacks,
165 NSCreateMapTable(NSObjectMapKeyCallBacks,
166 NSObjectMapValueCallBacks,
169 tmp = [_path stringByStandardizingPath];
170 if (tmp) _path = tmp;
172 self->base = [_path copy];
174 if ([WOApplication isCachingEnabled]) {
175 self->existingPathes = NSCreateMapTable(NSObjectMapKeyCallBacks,
176 NSIntMapValueCallBacks,
180 rprefix = [ud stringForKey:@"WOResourcePrefix"];
181 if (rprefix) [[self class] setResourcePrefix:rprefix];
186 return [self initWithPath:[[NGBundle mainBundle] bundlePath]];
190 if (self->existingPathes) NSFreeMapTable(self->existingPathes);
191 if (self->stringTables) NSFreeMapTable(self->stringTables);
192 if (self->componentDefinitions) NSFreeMapTable(self->componentDefinitions);
193 if (self->keyedResources) NSFreeMapTable(self->keyedResources);
194 [self->w3resources release];
195 [self->resources release];
196 [self->base release];
202 - (BOOL)isDebuggingEnabled {
208 - (NSFileManager *)fileManager {
209 static NSFileManager *fm = nil;
211 fm = [[NSFileManager defaultManager] retain];
215 - (NSString *)basePath {
219 - (NSString *)resourcesPath {
223 return self->resources;
225 fm = [self fileManager];
226 if ([self->base length] > 0) {
227 if (![fm fileExistsAtPath:self->base]) {
228 NSLog(@"WARNING(%s): Resources base path '%@' does not exist !",
229 __PRETTY_FUNCTION__, self->base);
235 if ([rapidTurnAroundPath length] > 0) {
237 In rapid turnaround mode, first check for a Resources subdir in the
238 project directory, then directly in the project dir.
239 Note: you cannot have both! Either put stuff in a Resources subdir *or*
245 tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
246 if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
249 tmp = rapidTurnAroundPath;
251 self->resources = [tmp copy];
255 [[[self->base stringByAppendingPathComponent:@"Contents"]
256 stringByAppendingPathComponent:@"Resources"]
261 [[self->base stringByAppendingPathComponent:@"Resources"] copy];
264 if ([self->resources length] > 0) {
265 if (![fm fileExistsAtPath:self->resources]) {
266 [self debugWithFormat:
267 @"WARNING(%s): Resources path %@ does not exist !",
268 __PRETTY_FUNCTION__, self->resources];
269 [self->resources release]; self->resources = nil;
271 else if (self->existingPathes && (self->resources != nil))
272 NSMapInsert(self->existingPathes, self->resources, (void*)1);
274 return self->resources;
277 - (NSString *)resourcesPathForFramework:(NSString *)_fw {
279 return [self resourcesPath];
282 return [[_fw stringByAppendingPathComponent:@"Contents"]
283 stringByAppendingPathComponent:@"Resources"];
285 return [_fw stringByAppendingPathComponent:@"Resources"];
289 - (NSString *)webServerResourcesPath {
292 if (self->w3resources)
293 return self->w3resources;
295 #if GNUSTEP_BASE_LIBRARY && 0
297 [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
300 [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
303 fm = [self fileManager];
304 if ([self->w3resources length] == 0)
307 if (![fm fileExistsAtPath:self->w3resources]) {
308 static BOOL didLog = NO;
311 [self debugWithFormat:
312 @"WARNING(%s): WebServerResources path '%@' does not exist !",
313 __PRETTY_FUNCTION__, self->w3resources];
315 [self->w3resources release]; self->w3resources = nil;
317 else if (self->existingPathes && (self->w3resources != nil))
318 NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
320 if (debugResourceLookup)
321 [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
322 return self->w3resources;
325 - (NSString *)pathForResourceNamed:(NSString *)_name
326 inFramework:(NSString *)_frameworkName
327 languages:(NSArray *)_languages
330 NSString *resource = nil;
334 if (debugResourceLookup) {
335 [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@",
336 _name, _frameworkName, [_languages componentsJoinedByString:@","]];
339 fm = [self fileManager];
340 langCount = [_languages count];
342 if ((w3rp = [self webServerResourcesPath])) {
343 NSString *langPath = nil;
346 // first check Language.lproj in WebServerResources
347 for (i = 0; i < langCount; i++) {
348 langPath = [_languages objectAtIndex:i];
349 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
350 langPath = [w3rp stringByAppendingPathComponent:langPath];
352 if (!_pathExists(self, fm, langPath)) {
353 if (debugResourceLookup) {
355 @" no language project for '%@' in WebServerResources: %@",
356 [_languages objectAtIndex:i],resource];
361 resource = [langPath stringByAppendingPathComponent:_name];
363 if (debugResourceLookup)
364 [self logWithFormat:@" check in WebServerResources: %@", resource];
365 if (_pathExists(self, fm, resource))
369 /* next check in WebServerResources itself */
370 resource = [w3rp stringByAppendingPathComponent:_name];
371 if (debugResourceLookup)
372 [self logWithFormat:@" check in WebServerResources-flat: %@", resource];
373 if (_pathExists(self, fm, resource))
377 if ((rp = [self resourcesPathForFramework:_frameworkName])) {
378 NSString *langPath = nil;
381 if (debugResourceLookup) [self logWithFormat:@" path %@", rp];
383 // first check Language.lproj in Resources
384 for (i = 0; i < langCount; i++) {
385 langPath = [_languages objectAtIndex:i];
386 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
387 langPath = [rp stringByAppendingPathComponent:langPath];
389 if (_pathExists(self, fm, langPath)) {
390 resource = [langPath stringByAppendingPathComponent:_name];
392 if (debugResourceLookup)
393 [self logWithFormat:@" check in Resources: %@", resource];
394 if (_pathExists(self, fm, resource))
399 // next check in Resources itself
400 resource = [rp stringByAppendingPathComponent:_name];
401 if (debugResourceLookup)
402 [self logWithFormat:@" check in Resources-flat: %@", resource];
403 if (_pathExists(self, fm, resource))
407 /* and last check in the application directory */
408 if (_pathExists(self, fm, self->base)) {
409 resource = [self->base stringByAppendingPathComponent:_name];
410 if (_pathExists(self, fm, resource))
416 - (NSString *)pathForResourceNamed:(NSString *)_name {
418 return [self pathForResourceNamed:_name inFramework:nil languages:nil];
421 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
422 _name = [_name stringByAppendingPathExtension:_type];
423 return [self pathForResourceNamed:_name];
428 - (NSString *)urlForResourceNamed:(NSString *)_name
429 inFramework:(NSString *)_frameworkName
430 languages:(NSArray *)_languages
431 request:(WORequest *)_request
434 NSString *resource = nil, *tmp;
436 app = [WOApplication application];
438 if (_languages == nil)
439 _languages = [_request browserLanguages];
441 resource = [self pathForResourceNamed:_name
442 inFramework:_frameworkName
443 languages:_languages];
445 if ([resource rangeOfString:@"/Contents/"].length > 0) {
446 resource = [resource stringByReplacingString:@"/Contents"
451 tmp = [resource stringByStandardizingPath];
452 if (tmp) resource = tmp;
456 NSString *path = nil, *sbase;
460 tmp = [sbase commonPrefixWithString:resource options:0];
463 path = [sbase substringFromIndex:len];
464 tmp = [resource substringFromIndex:len];
465 if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
466 path = [path stringByAppendingString:@"/"];
467 path = [path stringByAppendingString:tmp];
472 cs = [path componentsSeparatedByString:@"\\"];
473 path = [cs componentsJoinedByString:@"/"];
478 static NSString *suffix = nil;
479 NSMutableString *url = nil;
482 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
483 suffix = [ud stringForKey:@"WOApplicationSuffix"];
486 url = [[NSMutableString alloc] initWithCapacity:256];
488 [url appendString:[_request adaptorPrefix]];
491 [url appendString:resourcePrefix];
492 if (![url hasSuffix:@"/"]) [url appendString:@"/"];
493 [url appendString:app ? [app name] : [_request applicationName]];
494 [url appendString:suffix];
495 if (![path hasPrefix:@"/"]) [url appendString:@"/"];
496 [url appendString:path];
501 return [path autorelease];
505 if (genMissingResourceLinks) {
506 return [NSString stringWithFormat:
507 @"/missingresource?name=%@&application=%@",
508 _name, app ? [app name] : [_request applicationName]];
513 - (NSString *)urlForResourceNamed:(NSString *)_name {
515 return [self urlForResourceNamed:_name
520 - (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
521 return [self urlForResourceNamed:
522 [_name stringByAppendingPathExtension:_type]];
527 - (NSString *)stringForKey:(NSString *)_key
528 inTableNamed:(NSString *)_tableName
529 withDefaultValue:(NSString *)_defaultValue
530 inFramework:(NSString *)_framework
531 languages:(NSArray *)_languages;
534 _WOStringTable *table = nil;
535 NSString *path = nil;
537 fm = [self fileManager];
539 if (_tableName == nil)
540 _tableName = @"default";
542 /* take a look whether a matching table is already loaded */
544 path = [_tableName stringByAppendingPathExtension:@"strings"];
545 path = [self pathForResourceNamed:path inFramework:_framework
546 languages:_languages];
549 if ((table = NSMapGet(self->stringTables, path)) == NULL) {
550 if ([fm fileExistsAtPath:path]) {
551 table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
552 table = [table initWithPath:path];
553 NSMapInsert(self->stringTables, path, table);
558 return [table stringForKey:_key withDefaultValue:_defaultValue];
560 /* didn't found table in cache */
562 return _defaultValue;
565 - (NSString *)stringForKey:(NSString *)_key
566 inTableNamed:(NSString *)_tableName
567 withDefaultValue:(NSString *)_default
568 languages:(NSArray *)_languages
570 return [self stringForKey:_key inTableNamed:_tableName
571 withDefaultValue:_default
573 languages:_languages];
584 /* component definitions */
586 - (NSString *)pathToComponentNamed:(NSString *)_name
587 inFramework:(NSString *)_framework
589 /* search for component wrapper .. */
595 NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
596 __PRETTY_FUNCTION__);
601 /* scan for name.$ext resource ... */
602 e = [[[NSUserDefaults standardUserDefaults]
603 arrayForKey:@"WOComponentExtensions"]
606 while ((ext = [e nextObject])) {
610 specName = [_name stringByAppendingPathExtension:ext];
612 path = [self pathForResourceNamed:specName
613 inFramework:_framework
615 if (path) return path;
620 - (NSString *)pathToComponentNamed:(NSString *)_name
621 inFramework:(NSString *)_framework
622 languages:(NSArray *)_langs
624 return [self pathToComponentNamed:_name inFramework:_framework];
627 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
628 languages:(NSArray *)_languages
630 /* definition factory */
631 WOComponentDefinition *cdef;
633 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
639 return [cdef autorelease];
642 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
644 baseURL:(NSURL *)_baseURL
645 frameworkName:(NSString *)_fwname
647 /* definition factory */
648 static Class DefClass;
652 DefClass = [WOComponentDefinition class];
654 cdef = [[DefClass alloc] initWithName:_name
656 baseURL:_baseURL frameworkName:_fwname];
659 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
660 path:(NSString *)_path
661 baseURL:(NSURL *)_baseURL
662 frameworkName:(NSString *)_fwname
666 url = ([_path length] > 0)
667 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
670 return [self _definitionWithName:_name url:url
671 baseURL:_baseURL frameworkName:_fwname];
674 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
675 languages:(NSArray *)_languages
680 if (self->componentDefinitions == NULL)
682 if (![[WOApplication application] isCachingEnabled])
685 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
686 cdef = NSMapGet(self->componentDefinitions, cacheKey);
690 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
691 forComponent:(id)_name
692 languages:(NSArray *)_languages
696 if (self->componentDefinitions == NULL)
698 if (![[WOApplication application] isCachingEnabled])
701 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
702 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
707 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
708 return [_name stringByAppendingPathExtension:@"wox"];
711 - (BOOL)_isValidWrapperDirectory:(NSString *)_path
712 containingTemplate:(NSString *)_name
715 Check whether this actually does contain a template!
717 This is new and hopefully doesn't break anything, but as far as I can
718 see checking for Component.html inside should do the right thing (unless
719 there are template wrappers which are not .wo wrappers ;-)
723 htmlPath = [_name stringByAppendingPathExtension:@"html"];
724 htmlPath = [_path stringByAppendingPathComponent:htmlPath];
725 return [[self fileManager] fileExistsAtPath:htmlPath];
728 - (WOComponentDefinition *)_processWrapperLanguageProjects:(NSString *)_name
729 componentPath:(NSString *)componentPath
730 languages:(NSArray *)_langs
733 this looks for language projects contained in template wrapper
734 directories, eg "Main.wo/English.lproj/"
736 WOComponentDefinition *cdef = nil;
737 NSFileManager *fm = nil;
738 NSEnumerator *languages;
743 if ([_langs count] == 0)
746 doesCache = [[WOApplication application] isCachingEnabled];
747 fm = [self fileManager];
748 sname = [_name stringByAppendingString:@"\t"];
750 languages = [_langs objectEnumerator];
751 while ((language = [languages nextObject])) {
752 NSString *compoundKey = nil;
753 NSString *languagePath = nil;
754 BOOL isDirectory = NO;
755 NSString *baseUrl = nil;
757 // [self logWithFormat:@"check %@ / %@", _name, language];
759 compoundKey = [sname stringByAppendingString:language];
761 cdef = NSMapGet(self->componentDefinitions, compoundKey);
763 if (cdef == (id)null)
764 /* resource does not exist */
768 if (cdef) return cdef; // found definition in cache
771 /* take a look into the file system */
772 languagePath = [language stringByAppendingPathExtension:@"lproj"];
773 languagePath = [componentPath stringByAppendingPathComponent:languagePath];
775 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
777 // register null in cache, so that we know it's non-existent
778 NSMapInsert(self->componentDefinitions, compoundKey, null);
784 NSLog(@"WARNING(%s): language entry %@ is not a directory !",
785 __PRETTY_FUNCTION__, languagePath);
786 if (doesCache && (compoundKey != nil)) {
787 // register null in cache, so that we know it's non-existent
788 NSMapInsert(self->componentDefinitions, compoundKey, null);
794 Now check whether this actually does contain a template!
796 This is new and hopefully doesn't break anything, but as far as I can
797 see checking for Component.html inside should do the right thing (unless
798 there are template wrappers which are not .wo wrappers ;-)
800 if (![self _isValidWrapperDirectory:languagePath
801 containingTemplate:_name]){
802 [self debugWithFormat:@"no HTML template for inside lproj '%@': '%@'",
803 _name, languagePath];
804 if (doesCache && (compoundKey != nil)) {
805 // register null in cache, so that we know it's non-existent
806 NSMapInsert(self->componentDefinitions, compoundKey, null);
811 /* construct the base URL */
813 baseUrl = [[[WOApplication application] baseURL] absoluteString];
814 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
815 baseUrl, language, _name];
817 /* create WOComponentDefinition object */
819 cdef = [self _definitionWithName:_name
821 baseURL:[NSURL URLWithString:baseUrl]
824 NSLog(@"WARNING(%s): could not load component definition of "
825 @"'%@' from language project: %@",
826 __PRETTY_FUNCTION__, _name, languagePath);
827 if (doesCache && (compoundKey != nil)) {
828 // register null in cache, so that we know it's non-existent
829 NSMapInsert(self->componentDefinitions, compoundKey, null);
834 if (doesCache && (compoundKey != nil)) {
836 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
840 // don't register in cache
841 cdef = [cdef autorelease];
847 return nil; /* no lproj containing templates was found */
850 - (WOComponentDefinition *)definitionForComponent:(id)_name
851 inFramework:(NSString *)_framework
852 languages:(NSArray *)_languages
854 // TODO: this method is too large
856 NSFileManager *fm = nil;
857 WOComponentDefinition *cdef = nil;
859 BOOL doesCache, isDir;
861 app = [WOApplication application];
862 doesCache = [app isCachingEnabled];
864 /* lookup component path */
866 if ([_name isKindOfClass:UrlClass]) {
867 componentURL = _name;
868 _name = [componentURL path];
869 if (debugComponentLookup) {
870 [self debugWithFormat:@"using URL %@ for component %@",
871 componentURL, _name];
877 if (_framework == nil && _name != nil) {
881 Note: this is a bit of a hack ..., actually this method should never
882 be called without a framework and pages shouldn't be instantiated
883 without specifying their framework.
884 But for legacy reasons this needs to be done and seems to work without
885 problems. It is required for loading components from bundles.
887 if ((_framework = rapidTurnAroundPath) == nil) {
888 if ((clazz = NSClassFromString(_name)))
889 _framework = [[NSBundle bundleForClass:clazz] bundlePath];
893 if (debugComponentLookup) {
894 [self logWithFormat:@"lookup: component '%@' in framework '%@'",
898 /* look for .wox component */
900 path = [self pathForResourceNamed:
901 [self resourceNameForComponentNamed:_name]
902 inFramework:_framework
903 languages:_languages];
905 if (debugComponentLookup)
906 [self logWithFormat:@"lookup: path-to-resource: '%@'", path];
908 /* look for .wo component */
910 if ([path length] == 0) {
911 path = [self pathToComponentNamed:_name
912 inFramework:_framework
913 languages:_languages];
914 if (debugComponentLookup)
915 [self logWithFormat:@"lookup: path-to-component: '%@'", path];
918 /* make URL from path */
920 componentURL = ([path length] > 0)
921 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
925 if (debugComponentLookup) {
926 [self logWithFormat:@" component='%@' in framework='%@'",
928 [self logWithFormat:@" => '%@'", [componentURL absoluteString]];
931 /* check whether it's a 'template-less' component ... */
933 if (componentURL == nil) {
934 /* did not find component wrapper ! */
935 [app debugWithFormat:@" component '%@' has no template !", _name];
937 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
941 fm = [self fileManager];
943 /* ensure that the component exists */
946 if ([componentURL isFileURL]) {
947 NSString *componentPath;
949 componentPath = [componentURL path];
951 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
952 [[WOApplication application]
954 @"%s: did not find component '%@' at path '%@' !",
956 _name, componentPath];
960 /* if the component spec is a directory (eg a .wo), scan lproj's inside */
961 if (isDir && [_languages count] > 0) {
962 if (debugComponentLookup) {
963 [self logWithFormat:@" check wrapper languages (%d)",
966 cdef = [self _processWrapperLanguageProjects:_name
967 componentPath:componentPath
968 languages:_languages];
970 if (debugComponentLookup)
971 [self logWithFormat:@" => FOUND: %@", cdef];
974 else if (debugComponentLookup)
975 [self logWithFormat:@" ... no language template found ..."];
982 cdef = NSMapGet(self->componentDefinitions, componentURL);
983 if (cdef == (id)null)
984 /* resource does not exist */
988 if (cdef != nil) return cdef; // found definition in cache
992 in case the "componentURL" is a directory, check whether it contains
996 if (![self _isValidWrapperDirectory:[componentURL path]
997 containingTemplate:_name]) {
998 if (debugComponentLookup)
999 [self logWithFormat:@" not a valid wrapper '%@': '%@'",
1000 _name, [componentURL absoluteString]];
1002 /* register null in cache, so that we know it's non-existent */
1003 NSMapInsert(self->componentDefinitions, componentURL, null);
1009 /* take a look into the file system */
1011 NSString *baseUrl = nil;
1013 baseUrl = [NSString stringWithFormat:@"%@/%@",
1014 [[app baseURL] absoluteString],
1015 [_name lastPathComponent]];
1017 cdef = [self _definitionWithName:_name
1019 baseURL:[NSURL URLWithString:baseUrl]
1022 NSLog(@"WARNING(%s): could not load component definition of '%@' from "
1023 @"component wrapper: '%@'",
1024 __PRETTY_FUNCTION__, _name, componentURL);
1026 /* register null in cache, so that we know it's non-existent */
1027 NSMapInsert(self->componentDefinitions, componentURL, null);
1033 /* register in cache */
1034 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1038 /* don't register in cache, does not cache */
1039 cdef = [cdef autorelease];
1044 /* did not find component */
1047 - (WOComponentDefinition *)definitionForComponent:(id)_name
1048 languages:(NSArray *)_langs
1050 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1053 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1054 languages:(NSArray *)_languages
1056 WOComponentDefinition *cdef;
1058 /* look into cache */
1060 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1062 if (cdef == (id)null)
1063 /* component does not exist */
1066 if ([cdef respondsToSelector:@selector(touch)])
1071 /* not cached, create a definition */
1073 cdef = [self definitionForComponent:_name languages:_languages];
1075 /* cache created definition */
1077 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1080 - (WOElement *)templateWithName:(NSString *)_name
1081 languages:(NSArray *)_languages
1083 WOComponentDefinition *cdef;
1085 cdef = [self __definitionForComponent:_name languages:_languages];
1086 if (cdef == nil) return nil;
1088 return (WOElement *)[cdef template];
1091 - (WOComponent *)pageWithName:(NSString *)_name
1092 languages:(NSArray *)_languages
1095 TODO: this appears to be deprecated since the WOComponent initializer
1096 is now -initWithContext: and we have no context here ...
1098 NSAutoreleasePool *pool = nil;
1099 WOComponentDefinition *cdef = nil;
1100 WOComponent *component = nil;
1102 pool = [[NSAutoreleasePool alloc] init];
1104 cdef = [self __definitionForComponent:_name languages:_languages];
1107 [cdef instantiateWithResourceManager:(WOResourceManager *)self
1108 languages:_languages];
1109 component = [component retain];
1114 return [component autorelease];
1119 - (NSString *)description {
1120 return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
1121 [self class], self, self->base];
1125 @end /* OWResourceManager */
1127 @implementation OWResourceManager(KeyedData)
1129 - (void)setData:(NSData *)_data
1130 forKey:(NSString *)_key
1131 mimeType:(NSString *)_type
1132 session:(WOSession *)_session
1134 if ((_key == nil) || (_data == nil))
1137 _type = @"application/octet-stream";
1141 if (self->keyedResources == NULL) {
1142 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1143 NSObjectMapValueCallBacks,
1147 NSMapInsert(self->keyedResources,
1149 [NSDictionary dictionaryWithObjectsAndKeys:
1158 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1163 if (self->keyedResources)
1164 tmp = NSMapGet(self->keyedResources, _key);
1168 tmp = [[tmp retain] autorelease];
1175 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1178 if (self->keyedResources)
1179 NSMapRemove(self->keyedResources, _key);
1184 - (void)flushDataCache {
1187 if (self->keyedResources) {
1188 NSFreeMapTable(self->keyedResources);
1189 self->keyedResources = NULL;
1195 @end /* OWResourceManager(KeyedData) */
1197 @implementation OWResourceManager(JavaScript)
1199 - (id)_jsfunc_pathForResourceNamed:(NSArray *)_args {
1200 unsigned argc = [_args count];
1202 return [self pathForResourceNamed:
1203 argc > 0 ? [_args objectAtIndex:0] : nil
1204 inFramework:argc > 1 ? [_args objectAtIndex:1] : nil
1205 languages:argc > 2 ? [_args objectAtIndex:2] : nil];
1208 - (id)_jsfunc_loadPropertyListNamed:(NSArray *)_args {
1211 if ((s = [self _jsfunc_pathForResourceNamed:_args]) == nil)
1214 if ((s = [NSString stringWithContentsOfFile:s]) == nil)
1217 return [s propertyList];
1220 @end /* OWResourceManager(JavaScript) */