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 #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 [self errorWithFormat:@"(%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 [self warnWithFormat:@"(%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 warnWithFormat:
272 @"(%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 {
283 if (_fw == nil || (_fw == rapidTurnAroundPath))
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 warnWithFormat:
317 @"(%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 = @"Localizable";
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 [self warnWithFormat:
610 @"(%s): tried to get path to component with <nil> name !",
611 __PRETTY_FUNCTION__];
616 /* scan for name.$ext resource ... */
617 e = [[[NSUserDefaults standardUserDefaults]
618 arrayForKey:@"WOComponentExtensions"]
621 while ((ext = [e nextObject])) {
625 specName = [_name stringByAppendingPathExtension:ext];
627 path = [self pathForResourceNamed:specName
628 inFramework:_framework
630 if (path) return path;
635 - (NSString *)pathToComponentNamed:(NSString *)_name
636 inFramework:(NSString *)_framework
637 languages:(NSArray *)_langs
639 return [self pathToComponentNamed:_name inFramework:_framework];
642 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
643 languages:(NSArray *)_languages
645 /* definition factory */
646 WOComponentDefinition *cdef;
648 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
654 return [cdef autorelease];
657 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
659 baseURL:(NSURL *)_baseURL
660 frameworkName:(NSString *)_fwname
662 /* definition factory */
663 static Class DefClass;
667 DefClass = [WOComponentDefinition class];
669 // TODO: is retained response intended?
670 cdef = [[DefClass alloc] initWithName:_name
672 baseURL:_baseURL frameworkName:_fwname];
675 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
676 path:(NSString *)_path
677 baseURL:(NSURL *)_baseURL
678 frameworkName:(NSString *)_fwname
682 url = ([_path length] > 0)
683 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
686 return [self _definitionWithName:_name url:url
687 baseURL:_baseURL frameworkName:_fwname];
690 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
691 languages:(NSArray *)_languages
696 if (self->componentDefinitions == NULL)
698 if (![[WOApplication application] isCachingEnabled])
701 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
702 cdef = NSMapGet(self->componentDefinitions, cacheKey);
706 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
707 forComponent:(id)_name
708 languages:(NSArray *)_languages
712 if (self->componentDefinitions == NULL)
714 if (![[WOApplication application] isCachingEnabled])
717 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
718 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
723 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
724 return [_name stringByAppendingPathExtension:@"wox"];
727 /* create component definition */
729 - (void)_getComponentURL:(NSURL **)url_ andName:(NSString **)name_
730 forNameOrURL:(id)_nameOrURL inFramework:(NSString *)_framework
731 languages:(NSArray *)_languages
735 if ([_nameOrURL isKindOfClass:UrlClass]) {
736 // TODO: where is this used currently? It probably was required for forms,
737 // but might not be anymore?
739 *name_ = [*url_ path];
740 if (debugComponentLookup)
741 [self debugWithFormat:@"using URL %@ for component %@", *url_, *name_];
745 /* the _nameOrURL is a string containing the component name */
749 if (_framework == nil && _nameOrURL != nil) {
753 Note: this is a bit of a hack ..., actually this method should never
754 be called without a framework and pages shouldn't be instantiated
755 without specifying their framework.
756 But for legacy reasons this needs to be done and seems to work without
757 problems. It is required for loading components from bundles.
759 if ((_framework = rapidTurnAroundPath) == nil) {
760 if ((clazz = NSClassFromString(_nameOrURL)))
761 _framework = [[NSBundle bundleForClass:clazz] bundlePath];
765 if (debugComponentLookup) {
766 [self logWithFormat:@"component '%@' in framework '%@'",
767 _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:@" .wox 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:@" .wo 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 [self warnWithFormat:@"(%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 [self warnWithFormat:
883 @"(%s): could not load component definition of "
884 @"'%@' from language project: %@",
885 __PRETTY_FUNCTION__, _name, languagePath];
886 if (doesCache && (compoundKey != nil)) {
887 // register null in cache, so that we know it's non-existent
888 NSMapInsert(self->componentDefinitions, compoundKey, null);
893 if (doesCache && (compoundKey != nil)) {
895 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
899 // don't register in cache
900 cdef = [cdef autorelease];
908 - (WOComponentDefinition *)definitionForComponent:(id)_name
909 inFramework:(NSString *)_framework
910 languages:(NSArray *)_languages
912 // TODO: this method is definitely too big! => refacture
914 NSFileManager *fm = nil;
915 WOComponentDefinition *cdef = nil;
920 app = [WOApplication application];
921 doesCache = [app isCachingEnabled];
923 /* lookup component path */
925 [self _getComponentURL:&componentURL andName:&_name
926 forNameOrURL:_name inFramework:nil languages:nil];
928 if (debugComponentLookup) {
929 [self logWithFormat:@" component='%@' in framework='%@': url='%@'",
930 _name, _framework, componentURL];
933 appUrl = [app baseURL];
935 /* check whether it's a 'template-less' component ... */
937 if (componentURL == nil) {
938 /* did not find component wrapper ! */
939 [app debugWithFormat:@" component '%@' has no template !", _name];
941 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
945 fm = [self fileManager];
947 /* ensure that the component exists */
949 if ([componentURL isFileURL]) {
950 WOComponentDefinition *cdef;
952 cdef = [self definitionForFileURL:componentURL componentName:_name
953 inFramework:_framework languages:_languages];
954 if (cdef != nil && ![cdef isNotNull])
956 else if (cdef != nil)
963 cdef = NSMapGet(self->componentDefinitions, componentURL);
965 if (cdef == (id)null)
966 /* resource does not exist */
970 if (cdef) return cdef; // found definition in cache
973 /* take a look into the file system */
975 NSString *baseUrl = nil;
977 baseUrl = [NSString stringWithFormat:@"%@/%@",
978 [appUrl absoluteString], [_name lastPathComponent]];
980 cdef = [self _definitionWithName:_name
982 baseURL:[NSURL URLWithString:baseUrl]
985 [self warnWithFormat:
986 @"(%s): could not load component definition of '%@' from "
987 @"component wrapper: '%@'",
988 __PRETTY_FUNCTION__, _name, componentURL];
990 /* register null in cache, so that we know it's non-existent */
991 NSMapInsert(self->componentDefinitions, componentURL, null);
997 /* register in cache */
998 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1002 /* don't register in cache, does not cache */
1003 cdef = [cdef autorelease];
1008 /* did not find component */
1011 - (WOComponentDefinition *)definitionForComponent:(id)_name
1012 languages:(NSArray *)_langs
1014 // TODO: who uses that? Probably should be deprecated?
1015 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1018 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1019 languages:(NSArray *)_languages
1022 First check whether the cdef is cached, otherwise create a new one.
1024 This method is used by the higher level methods and just implements the
1026 The definition itself is created by definitionForComponent:languages:.
1028 WOComponentDefinition *cdef;
1030 /* look into cache */
1032 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1034 if (cdef == (id)null)
1035 /* component does not exist */
1038 if ([cdef respondsToSelector:@selector(touch)])
1043 /* not cached, create a definition */
1045 cdef = [self definitionForComponent:_name languages:_languages];
1047 /* cache created definition */
1049 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1052 - (WOElement *)templateWithName:(NSString *)_name
1053 languages:(NSArray *)_languages
1055 WOComponentDefinition *cdef;
1057 cdef = [self __definitionForComponent:_name languages:_languages];
1061 return (WOElement *)[cdef template];
1064 - (WOComponent *)pageWithName:(NSString *)_name languages:(NSArray *)_langs {
1066 TODO: this appears to be deprecated since the WOComponent initializer
1067 is now -initWithContext: and we have no context over here ...
1069 NSAutoreleasePool *pool;
1070 WOComponentDefinition *cdef;
1071 WOComponent *component = nil;
1073 pool = [[NSAutoreleasePool alloc] init];
1075 cdef = [self __definitionForComponent:_name languages:_langs];
1077 // TODO: document what the resource manager is used for in the cdef
1079 [[cdef instantiateWithResourceManager:self languages:_langs] retain];
1084 return [component autorelease];
1089 - (NSString *)description {
1090 NSMutableString *ms;
1092 ms = [NSMutableString stringWithCapacity:32];
1093 [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
1094 if ([self->base length] > 0)
1095 [ms appendFormat:@" path='%@'", self->base];
1096 [ms appendString:@">"];
1102 - (void)setData:(NSData *)_data
1103 forKey:(NSString *)_key
1104 mimeType:(NSString *)_type
1105 session:(WOSession *)_session
1107 if ((_key == nil) || (_data == nil))
1110 _type = @"application/octet-stream";
1114 if (self->keyedResources == NULL) {
1115 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1116 NSObjectMapValueCallBacks,
1120 NSMapInsert(self->keyedResources,
1122 [NSDictionary dictionaryWithObjectsAndKeys:
1131 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1136 if (self->keyedResources)
1137 tmp = NSMapGet(self->keyedResources, _key);
1141 tmp = [[tmp retain] autorelease];
1148 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1151 if (self->keyedResources)
1152 NSMapRemove(self->keyedResources, _key);
1157 - (void)flushDataCache {
1160 if (self->keyedResources) {
1161 NSFreeMapTable(self->keyedResources);
1162 self->keyedResources = NULL;
1168 @end /* WOResourceManager */