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/WOResourceManager.h>
23 #include <NGObjWeb/WOComponentDefinition.h>
24 #include "WOComponent+private.h"
25 #include <NGObjWeb/WORequest.h>
26 #include <NGObjWeb/WOApplication.h>
28 #import <Foundation/NSNull.h>
29 #include "_WOStringTable.h"
32 Component Discovery and Page Creation
34 All WO code uses either directly or indirectly the WOResourceManager's
35 -pageWithName:languages: method to instantiate WO components.
37 This methods works in three steps:
39 1. discovery of files associated with the component
41 2. creation of a proper WOComponentDefinition, which is some kind
42 of 'blueprint' or 'class' for components
44 3. component instantiation using the definition
46 All the instantiation/setup work is done by a component definition, the
47 resource manager is only responsible for managing those 'blueprint'
50 If you want to customize component creation, you can supply your
51 own WOComponentDefinition in a subclass of WOResourceManager by
53 - (WOComponentDefinition *)definitionForComponent:(id)_name
54 inFramework:(NSString *)_frameworkName
55 languages:(NSArray *)_languages
59 Note: this was #if !COMPILE_FOR_GSTEP_MAKE - but there is no difference
60 between Xcode and gstep-make?!
61 The only possible difference might be that .wo wrappers are directly
62 in the bundle/framework root - but this doesn't relate to Resources.
64 OK, this breaks gstep-make based template lookup which places .wo
65 wrappers in .woa/Resources/xxx.wo.
66 This is an issue because .wox are looked up in Contents/Resources
67 but .wo ones in just Resources.
69 This issue should be fixed in recent woapp-gs.make ...
71 Update: since for SOPE 4.3 we only work with gstep-make 1.10, this seems to
74 #if COCOA_Foundation_LIBRARY || NeXT_Foundation_LIBRARY
75 # define RSRCDIR_CONTENTS 1
78 @implementation WOResourceManager
84 static Class UrlClass = Nil;
85 static NSString *resourcePrefix = @"";
86 static NSString *rapidTurnAroundPath = nil;
87 static NSString *suffix = nil;
88 static NSNull *null = nil;
89 static BOOL debugOn = NO;
90 static BOOL debugComponentLookup = NO;
91 static BOOL debugResourceLookup = NO;
92 static BOOL genMissingResourceLinks = NO;
95 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
96 static BOOL isInitialized = NO;
98 if (isInitialized) return;
101 null = [[NSNull null] retain];
102 UrlClass = [NSURL class];
104 defs = [NSDictionary dictionaryWithObjectsAndKeys:
105 [NSArray arrayWithObject:@"wo"],
106 @"WOComponentExtensions",
108 [ud registerDefaults:defs];
109 debugOn = [WOApplication isDebuggingEnabled];
110 debugComponentLookup = [ud boolForKey:@"WODebugComponentLookup"];
111 debugResourceLookup = [ud boolForKey:@"WODebugResourceLookup"];
112 genMissingResourceLinks = [ud boolForKey:@"WOGenerateMissingResourceLinks"];
113 rapidTurnAroundPath = [[ud stringForKey:@"WOProjectDirectory"] copy];
114 suffix = [[ud stringForKey:@"WOApplicationSuffix"] copy];
118 _pathExists(WOResourceManager *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 {
205 - (NSString *)loggingPrefix {
206 unsigned char buf[32];
207 sprintf(buf, "[wo-rm-0x%08X]", (unsigned)self);
208 return [NSString stringWithCString:buf];
213 - (NSFileManager *)fileManager {
214 static NSFileManager *fm = nil;
216 fm = [[NSFileManager defaultManager] retain];
220 - (NSString *)basePath {
224 - (NSString *)resourcesPath {
228 return self->resources;
230 fm = [self fileManager];
231 if ([self->base length] > 0) {
232 if (![fm fileExistsAtPath:self->base]) {
233 NSLog(@"WARNING(%s): Resources base path '%@' does not exist !",
234 __PRETTY_FUNCTION__, self->base);
240 if ([rapidTurnAroundPath length] > 0) {
242 In rapid turnaround mode, first check for a Resources subdir in the
243 project directory, then directly in the project dir.
244 Note: you cannot have both! Either put stuff in a Resources subdir *or*
250 tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
251 if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
254 tmp = rapidTurnAroundPath;
256 self->resources = [tmp copy];
260 [[[self->base stringByAppendingPathComponent:@"Contents"]
261 stringByAppendingPathComponent:@"Resources"]
266 [[self->base stringByAppendingPathComponent:@"Resources"] copy];
269 if ([self->resources length] > 0) {
270 if (![fm fileExistsAtPath:self->resources]) {
271 [self debugWithFormat:
272 @"WARNING(%s): Resources path %@ does not exist !",
273 __PRETTY_FUNCTION__, self->resources];
274 [self->resources release]; self->resources = nil;
276 else if (self->existingPathes && (self->resources != nil))
277 NSMapInsert(self->existingPathes, self->resources, (void*)1);
279 return self->resources;
282 - (NSString *)resourcesPathForFramework:(NSString *)_fw {
284 return [self resourcesPath];
287 return [[_fw stringByAppendingPathComponent:@"Contents"]
288 stringByAppendingPathComponent:@"Resources"];
290 return [_fw stringByAppendingPathComponent:@"Resources"];
294 - (NSString *)webServerResourcesPath {
297 if (self->w3resources)
298 return self->w3resources;
300 #if GNUSTEP_BASE_LIBRARY && 0
302 [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
305 [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
308 fm = [self fileManager];
309 if ([self->w3resources length] == 0)
312 if (![fm fileExistsAtPath:self->w3resources]) {
313 static BOOL didLog = NO;
316 [self debugWithFormat:
317 @"WARNING(%s): WebServerResources path '%@' does not exist !",
318 __PRETTY_FUNCTION__, self->w3resources];
320 [self->w3resources release]; self->w3resources = nil;
322 else if (self->existingPathes && (self->w3resources != nil))
323 NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
325 if (debugResourceLookup)
326 [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
327 return self->w3resources;
330 - (NSString *)pathForResourceNamed:(NSString *)_name
331 inFramework:(NSString *)_frameworkName
332 languages:(NSArray *)_languages
335 NSString *resource = nil;
339 if (debugResourceLookup) {
340 [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@",
341 _name, _frameworkName, [_languages componentsJoinedByString:@","]];
344 fm = [self fileManager];
345 langCount = [_languages count];
347 if ((w3rp = [self webServerResourcesPath]) != nil) {
348 NSString *langPath = nil;
351 if (debugResourceLookup)
352 [self logWithFormat:@" WebServerResources: %@", w3rp];
354 // first check Language.lproj in WebServerResources
355 for (i = 0; i < langCount; i++) {
356 langPath = [_languages objectAtIndex:i];
357 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
358 langPath = [w3rp stringByAppendingPathComponent:langPath];
360 if (!_pathExists(self, fm, langPath)) {
361 if (debugResourceLookup) {
363 @" no language project for '%@' in WebServerResources: %@",
364 [_languages objectAtIndex:i], langPath];
369 resource = [langPath stringByAppendingPathComponent:_name];
371 if (debugResourceLookup)
372 [self logWithFormat:@" check in WebServerResources: %@", resource];
373 if (_pathExists(self, fm, resource))
377 /* next check in WebServerResources itself */
378 resource = [w3rp stringByAppendingPathComponent:_name];
379 if (debugResourceLookup)
380 [self logWithFormat:@" check in WebServerResources-flat: %@", resource];
381 if (_pathExists(self, fm, resource))
385 if ((rp = [self resourcesPathForFramework:_frameworkName])) {
386 NSString *langPath = nil;
389 if (debugResourceLookup) [self logWithFormat:@" path %@", rp];
391 // first check Language.lproj in Resources
392 for (i = 0; i < langCount; i++) {
393 langPath = [_languages objectAtIndex:i];
394 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
395 langPath = [rp stringByAppendingPathComponent:langPath];
397 if (_pathExists(self, fm, langPath)) {
398 resource = [langPath stringByAppendingPathComponent:_name];
400 if (debugResourceLookup)
401 [self logWithFormat:@" check in Resources: %@", resource];
402 if (_pathExists(self, fm, resource))
407 // next check in Resources itself
408 resource = [rp stringByAppendingPathComponent:_name];
409 if (debugResourceLookup)
410 [self logWithFormat:@" check in Resources-flat: %@", resource];
411 if (_pathExists(self, fm, resource)) {
412 if (debugResourceLookup)
413 [self logWithFormat:@" found => %@", resource];
418 /* and last check in the application directory */
419 if (_pathExists(self, fm, self->base)) {
420 resource = [self->base stringByAppendingPathComponent:_name];
421 if (_pathExists(self, fm, resource))
427 - (NSString *)pathForResourceNamed:(NSString *)_name {
429 return [self pathForResourceNamed:_name inFramework:nil languages:nil];
432 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
433 _name = [_name stringByAppendingPathExtension:_type];
434 return [self pathForResourceNamed:_name];
439 - (NSString *)_urlForMissingResource:(NSString *)_name request:(WORequest *)_r{
442 app = [WOApplication application];
444 if (!genMissingResourceLinks)
447 return [NSString stringWithFormat:
448 @"/missingresource?name=%@&application=%@",
449 _name, app ? [app name] : [_r applicationName]];
452 - (NSString *)urlForResourceNamed:(NSString *)_name
453 inFramework:(NSString *)_frameworkName
454 languages:(NSArray *)_languages
455 request:(WORequest *)_request
458 NSMutableString *url;
459 NSString *resource = nil, *tmp;
460 NSString *path = nil, *sbase;
463 app = [WOApplication application];
465 if (_languages == nil)
466 _languages = [_request browserLanguages];
468 resource = [self pathForResourceNamed:_name
469 inFramework:_frameworkName
470 languages:_languages];
472 if ([resource rangeOfString:@"/Contents/"].length > 0) {
473 resource = [resource stringByReplacingString:@"/Contents"
478 tmp = [resource stringByStandardizingPath];
479 if (tmp != nil) resource = tmp;
482 if (resource == nil) {
483 if (debugResourceLookup)
484 [self logWithFormat:@"did not find resource (cannot build URL)"];
485 return [self _urlForMissingResource:_name request:_request];
489 tmp = [sbase commonPrefixWithString:resource options:0];
492 path = [sbase substringFromIndex:len];
493 tmp = [resource substringFromIndex:len];
494 if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
495 path = [path stringByAppendingString:@"/"];
496 path = [path stringByAppendingString:tmp];
501 cs = [path componentsSeparatedByString:@"\\"];
502 path = [cs componentsJoinedByString:@"/"];
507 return [self _urlForMissingResource:_name request:_request];
509 url = [[NSMutableString alloc] initWithCapacity:256];
511 [url appendString:[_request adaptorPrefix]];
514 [url appendString:resourcePrefix];
515 if (![url hasSuffix:@"/"]) [url appendString:@"/"];
516 [url appendString:app ? [app name] : [_request applicationName]];
517 [url appendString:suffix];
518 if (![path hasPrefix:@"/"]) [url appendString:@"/"];
519 [url appendString:path];
523 return [path autorelease];
526 - (NSString *)urlForResourceNamed:(NSString *)_name {
528 return [self urlForResourceNamed:_name
533 - (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
534 return [self urlForResourceNamed:
535 [_name stringByAppendingPathExtension:_type]];
540 - (NSString *)stringForKey:(NSString *)_key
541 inTableNamed:(NSString *)_tableName
542 withDefaultValue:(NSString *)_defaultValue
543 inFramework:(NSString *)_framework
544 languages:(NSArray *)_languages;
547 _WOStringTable *table = nil;
548 NSString *path = nil;
550 fm = [self fileManager];
552 if (_tableName == nil)
553 _tableName = @"default";
555 /* take a look whether a matching table is already loaded */
557 path = [_tableName stringByAppendingPathExtension:@"strings"];
558 path = [self pathForResourceNamed:path inFramework:_framework
559 languages:_languages];
562 if ((table = NSMapGet(self->stringTables, path)) == NULL) {
563 if ([fm fileExistsAtPath:path]) {
564 table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
565 table = [table initWithPath:path];
566 NSMapInsert(self->stringTables, path, table);
571 return [table stringForKey:_key withDefaultValue:_defaultValue];
573 /* didn't found table in cache */
575 return _defaultValue;
578 - (NSString *)stringForKey:(NSString *)_key
579 inTableNamed:(NSString *)_tableName
580 withDefaultValue:(NSString *)_default
581 languages:(NSArray *)_languages
583 return [self stringForKey:_key inTableNamed:_tableName
584 withDefaultValue:_default
586 languages:_languages];
597 /* component definitions */
599 - (NSString *)pathToComponentNamed:(NSString *)_name
600 inFramework:(NSString *)_framework
602 /* search for component wrapper .. */
603 // TODO: shouldn't we used that for WOx as well?
609 NSLog(@"WARNING(%s): tried to get path to component with <nil> name !",
610 __PRETTY_FUNCTION__);
615 /* scan for name.$ext resource ... */
616 e = [[[NSUserDefaults standardUserDefaults]
617 arrayForKey:@"WOComponentExtensions"]
620 while ((ext = [e nextObject])) {
624 specName = [_name stringByAppendingPathExtension:ext];
626 path = [self pathForResourceNamed:specName
627 inFramework:_framework
629 if (path) return path;
634 - (NSString *)pathToComponentNamed:(NSString *)_name
635 inFramework:(NSString *)_framework
636 languages:(NSArray *)_langs
638 return [self pathToComponentNamed:_name inFramework:_framework];
641 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
642 languages:(NSArray *)_languages
644 /* definition factory */
645 WOComponentDefinition *cdef;
647 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
653 return [cdef autorelease];
656 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
658 baseURL:(NSURL *)_baseURL
659 frameworkName:(NSString *)_fwname
661 /* definition factory */
662 static Class DefClass;
666 DefClass = [WOComponentDefinition class];
668 // TODO: is retained response intended?
669 cdef = [[DefClass alloc] initWithName:_name
671 baseURL:_baseURL frameworkName:_fwname];
674 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
675 path:(NSString *)_path
676 baseURL:(NSURL *)_baseURL
677 frameworkName:(NSString *)_fwname
681 url = ([_path length] > 0)
682 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
685 return [self _definitionWithName:_name url:url
686 baseURL:_baseURL frameworkName:_fwname];
689 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
690 languages:(NSArray *)_languages
695 if (self->componentDefinitions == NULL)
697 if (![[WOApplication application] isCachingEnabled])
700 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
701 cdef = NSMapGet(self->componentDefinitions, cacheKey);
705 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
706 forComponent:(id)_name
707 languages:(NSArray *)_languages
711 if (self->componentDefinitions == NULL)
713 if (![[WOApplication application] isCachingEnabled])
716 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
717 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
722 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
723 return [_name stringByAppendingPathExtension:@"wox"];
726 /* create component definition */
728 - (void)_getComponentURL:(NSURL **)url_ andName:(NSString **)name_
729 forNameOrURL:(id)_nameOrURL inFramework:(NSString *)_framework
730 languages:(NSArray *)_languages
734 if ([_nameOrURL isKindOfClass:UrlClass]) {
735 // TODO: where is this used currently? It probably was required for forms,
736 // but might not be anymore?
738 *name_ = [*url_ path];
739 if (debugComponentLookup)
740 [self debugWithFormat:@"using URL %@ for component %@", *url_, *name_];
744 /* the _nameOrURL is a string containing the component name */
748 if (_framework == nil && _nameOrURL != nil) {
752 Note: this is a bit of a hack ..., actually this method should never
753 be called without a framework and pages shouldn't be instantiated
754 without specifying their framework.
755 But for legacy reasons this needs to be done and seems to work without
756 problems. It is required for loading components from bundles.
758 if ((_framework = rapidTurnAroundPath) == nil) {
759 if ((clazz = NSClassFromString(_nameOrURL)))
760 _framework = [[NSBundle bundleForClass:clazz] bundlePath];
764 if (debugComponentLookup) {
765 [self logWithFormat:@"component '%@' in framework '%@'",
766 _nameOrURL, _framework];
770 /* look for .wox component */
772 path = [self pathForResourceNamed:
773 [self resourceNameForComponentNamed:*name_]
774 inFramework:_framework
775 languages:_languages];
777 if (debugComponentLookup)
778 [self logWithFormat:@" path: '%@'", path];
780 /* look for .wo component */
782 if ([path length] == 0) {
783 path = [self pathToComponentNamed:*name_
784 inFramework:_framework
785 languages:_languages];
786 if (debugComponentLookup)
787 [self logWithFormat:@" path: '%@'", path];
790 /* make URL from path */
792 *url_ = ([path length] > 0)
793 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
797 - (WOComponentDefinition *)definitionForFileURL:(NSURL *)componentURL
798 componentName:(NSString *)_name inFramework:(NSString *)_framework
799 languages:(NSArray *)_languages
802 NSString *componentPath;
803 BOOL doesCache, isDir;
804 NSEnumerator *languages;
806 NSString *sname = nil;
809 fm = [self fileManager];
810 componentPath = [componentURL path];
811 doesCache = [[WOApplication application] isCachingEnabled];
813 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
814 [[WOApplication application]
816 @"%s: did not find component '%@' at path '%@' !",
818 _name, componentPath];
822 /* if the component spec is a directory (eg a .wo), scan inside for stuff*/
827 appUrl = [[WOApplication application] baseURL];
828 languages = [_languages objectEnumerator];
829 while ((language = [languages nextObject])) {
830 WOComponentDefinition *cdef;
831 NSString *compoundKey = nil;
832 NSString *languagePath = nil;
833 NSString *baseUrl = nil;
834 BOOL isDirectory = NO;
836 if (sname == nil) sname = [_name stringByAppendingString:@"\t"];
837 compoundKey = [sname stringByAppendingString:language];
840 cdef = NSMapGet(self->componentDefinitions, compoundKey);
842 if (cdef == (id)null)
843 /* resource does not exist */
847 if (cdef != nil) return cdef; // found definition in cache
850 /* take a look into the file system */
851 languagePath = [language stringByAppendingPathExtension:@"lproj"];
853 [componentPath stringByAppendingPathComponent:languagePath];
855 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
857 /* register null in cache, so that we know it's non-existent */
858 NSMapInsert(self->componentDefinitions, compoundKey, null);
864 NSLog(@"WARNING(%s): language entry %@ is not a directory !",
865 __PRETTY_FUNCTION__, languagePath);
866 if (doesCache && (compoundKey != nil)) {
867 // register null in cache, so that we know it's non-existent
868 NSMapInsert(self->componentDefinitions, compoundKey, null);
873 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
874 [appUrl absoluteString], language, _name];
876 /* found appropriate language project */
877 cdef = [self _definitionWithName:_name
879 baseURL:[NSURL URLWithString:baseUrl]
882 NSLog(@"WARNING(%s): could not load component definition of "
883 @"'%@' from language project: %@",
884 __PRETTY_FUNCTION__, _name, languagePath);
885 if (doesCache && (compoundKey != nil)) {
886 // register null in cache, so that we know it's non-existent
887 NSMapInsert(self->componentDefinitions, compoundKey, null);
892 if (doesCache && (compoundKey != nil)) {
894 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
898 // don't register in cache
899 cdef = [cdef autorelease];
907 - (WOComponentDefinition *)definitionForComponent:(id)_name
908 inFramework:(NSString *)_framework
909 languages:(NSArray *)_languages
911 // TODO: this method is definitely too big! => refacture
913 NSFileManager *fm = nil;
914 WOComponentDefinition *cdef = nil;
919 app = [WOApplication application];
920 doesCache = [app isCachingEnabled];
922 /* lookup component path */
924 [self _getComponentURL:&componentURL andName:&_name
925 forNameOrURL:_name inFramework:nil languages:nil];
927 if (debugComponentLookup) {
928 [self logWithFormat:@" component='%@' in framework='%@': url='%@'",
929 _name, _framework, componentURL];
932 appUrl = [app baseURL];
934 /* check whether it's a 'template-less' component ... */
936 if (componentURL == nil) {
937 /* did not find component wrapper ! */
938 [app debugWithFormat:@" component '%@' has no template !", _name];
940 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
944 fm = [self fileManager];
946 /* ensure that the component exists */
948 if ([componentURL isFileURL]) {
949 WOComponentDefinition *cdef;
951 cdef = [self definitionForFileURL:componentURL componentName:_name
952 inFramework:_framework languages:_languages];
953 if (cdef != nil && ![cdef isNotNull])
955 else if (cdef != nil)
962 cdef = NSMapGet(self->componentDefinitions, componentURL);
964 if (cdef == (id)null)
965 /* resource does not exist */
969 if (cdef) return cdef; // found definition in cache
972 /* take a look into the file system */
974 NSString *baseUrl = nil;
976 baseUrl = [NSString stringWithFormat:@"%@/%@",
977 [appUrl absoluteString], [_name lastPathComponent]];
979 cdef = [self _definitionWithName:_name
981 baseURL:[NSURL URLWithString:baseUrl]
984 NSLog(@"WARNING(%s): could not load component definition of '%@' from "
985 @"component wrapper: '%@'",
986 __PRETTY_FUNCTION__, _name, componentURL);
988 /* register null in cache, so that we know it's non-existent */
989 NSMapInsert(self->componentDefinitions, componentURL, null);
995 /* register in cache */
996 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1000 /* don't register in cache, does not cache */
1001 cdef = [cdef autorelease];
1006 /* did not find component */
1009 - (WOComponentDefinition *)definitionForComponent:(id)_name
1010 languages:(NSArray *)_langs
1012 // TODO: who uses that? Probably should be deprecated?
1013 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1016 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1017 languages:(NSArray *)_languages
1020 First check whether the cdef is cached, otherwise create a new one.
1022 This method is used by the higher level methods and just implements the
1024 The definition itself is created by definitionForComponent:languages:.
1026 WOComponentDefinition *cdef;
1028 /* look into cache */
1030 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1032 if (cdef == (id)null)
1033 /* component does not exist */
1036 if ([cdef respondsToSelector:@selector(touch)])
1041 /* not cached, create a definition */
1043 cdef = [self definitionForComponent:_name languages:_languages];
1045 /* cache created definition */
1047 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1050 - (WOElement *)templateWithName:(NSString *)_name
1051 languages:(NSArray *)_languages
1053 WOComponentDefinition *cdef;
1055 cdef = [self __definitionForComponent:_name languages:_languages];
1056 if (cdef == nil) return nil;
1058 return (WOElement *)[cdef template];
1061 - (WOComponent *)pageWithName:(NSString *)_name languages:(NSArray *)_langs {
1063 TODO: this appears to be deprecated since the WOComponent initializer
1064 is now -initWithContext: and we have no context over here ...
1066 NSAutoreleasePool *pool;
1067 WOComponentDefinition *cdef;
1068 WOComponent *component = nil;
1070 pool = [[NSAutoreleasePool alloc] init];
1072 cdef = [self __definitionForComponent:_name languages:_langs];
1074 // TODO: document what the resource manager is used for in the cdef
1076 [[cdef instantiateWithResourceManager:self languages:_langs] retain];
1081 return [component autorelease];
1086 - (NSString *)description {
1087 return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
1088 [self class], self, self->base];
1094 - (void)setData:(NSData *)_data
1095 forKey:(NSString *)_key
1096 mimeType:(NSString *)_type
1097 session:(WOSession *)_session
1099 if ((_key == nil) || (_data == nil))
1102 _type = @"application/octet-stream";
1106 if (self->keyedResources == NULL) {
1107 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1108 NSObjectMapValueCallBacks,
1112 NSMapInsert(self->keyedResources,
1114 [NSDictionary dictionaryWithObjectsAndKeys:
1123 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1128 if (self->keyedResources)
1129 tmp = NSMapGet(self->keyedResources, _key);
1133 tmp = [[tmp retain] autorelease];
1140 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1143 if (self->keyedResources)
1144 NSMapRemove(self->keyedResources, _key);
1149 - (void)flushDataCache {
1152 if (self->keyedResources) {
1153 NSFreeMapTable(self->keyedResources);
1154 self->keyedResources = NULL;
1160 @end /* WOResourceManager */