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 {
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 = @"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 [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];
771 /* look for .wox component */
773 path = [self pathForResourceNamed:
774 [self resourceNameForComponentNamed:*name_]
775 inFramework:_framework
776 languages:_languages];
778 if (debugComponentLookup)
779 [self logWithFormat:@" path: '%@'", path];
781 /* look for .wo component */
783 if ([path length] == 0) {
784 path = [self pathToComponentNamed:*name_
785 inFramework:_framework
786 languages:_languages];
787 if (debugComponentLookup)
788 [self logWithFormat:@" path: '%@'", path];
791 /* make URL from path */
793 *url_ = ([path length] > 0)
794 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
798 - (WOComponentDefinition *)definitionForFileURL:(NSURL *)componentURL
799 componentName:(NSString *)_name inFramework:(NSString *)_framework
800 languages:(NSArray *)_languages
803 NSString *componentPath;
804 BOOL doesCache, isDir;
805 NSEnumerator *languages;
807 NSString *sname = nil;
810 fm = [self fileManager];
811 componentPath = [componentURL path];
812 doesCache = [[WOApplication application] isCachingEnabled];
814 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
815 [[WOApplication application]
817 @"%s: did not find component '%@' at path '%@' !",
819 _name, componentPath];
823 /* if the component spec is a directory (eg a .wo), scan inside for stuff*/
828 appUrl = [[WOApplication application] baseURL];
829 languages = [_languages objectEnumerator];
830 while ((language = [languages nextObject])) {
831 WOComponentDefinition *cdef;
832 NSString *compoundKey = nil;
833 NSString *languagePath = nil;
834 NSString *baseUrl = nil;
835 BOOL isDirectory = NO;
837 if (sname == nil) sname = [_name stringByAppendingString:@"\t"];
838 compoundKey = [sname stringByAppendingString:language];
841 cdef = NSMapGet(self->componentDefinitions, compoundKey);
843 if (cdef == (id)null)
844 /* resource does not exist */
848 if (cdef != nil) return cdef; // found definition in cache
851 /* take a look into the file system */
852 languagePath = [language stringByAppendingPathExtension:@"lproj"];
854 [componentPath stringByAppendingPathComponent:languagePath];
856 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
858 /* register null in cache, so that we know it's non-existent */
859 NSMapInsert(self->componentDefinitions, compoundKey, null);
865 [self warnWithFormat:@"(%s): language entry %@ is not a directory !",
866 __PRETTY_FUNCTION__, languagePath];
867 if (doesCache && (compoundKey != nil)) {
868 // register null in cache, so that we know it's non-existent
869 NSMapInsert(self->componentDefinitions, compoundKey, null);
874 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
875 [appUrl absoluteString], language, _name];
877 /* found appropriate language project */
878 cdef = [self _definitionWithName:_name
880 baseURL:[NSURL URLWithString:baseUrl]
883 [self warnWithFormat:
884 @"(%s): could not load component definition of "
885 @"'%@' from language project: %@",
886 __PRETTY_FUNCTION__, _name, languagePath];
887 if (doesCache && (compoundKey != nil)) {
888 // register null in cache, so that we know it's non-existent
889 NSMapInsert(self->componentDefinitions, compoundKey, null);
894 if (doesCache && (compoundKey != nil)) {
896 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
900 // don't register in cache
901 cdef = [cdef autorelease];
909 - (WOComponentDefinition *)definitionForComponent:(id)_name
910 inFramework:(NSString *)_framework
911 languages:(NSArray *)_languages
913 // TODO: this method is definitely too big! => refacture
915 NSFileManager *fm = nil;
916 WOComponentDefinition *cdef = nil;
921 app = [WOApplication application];
922 doesCache = [app isCachingEnabled];
924 /* lookup component path */
926 [self _getComponentURL:&componentURL andName:&_name
927 forNameOrURL:_name inFramework:nil languages:nil];
929 if (debugComponentLookup) {
930 [self logWithFormat:@" component='%@' in framework='%@': url='%@'",
931 _name, _framework, componentURL];
934 appUrl = [app baseURL];
936 /* check whether it's a 'template-less' component ... */
938 if (componentURL == nil) {
939 /* did not find component wrapper ! */
940 [app debugWithFormat:@" component '%@' has no template !", _name];
942 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
946 fm = [self fileManager];
948 /* ensure that the component exists */
950 if ([componentURL isFileURL]) {
951 WOComponentDefinition *cdef;
953 cdef = [self definitionForFileURL:componentURL componentName:_name
954 inFramework:_framework languages:_languages];
955 if (cdef != nil && ![cdef isNotNull])
957 else if (cdef != nil)
964 cdef = NSMapGet(self->componentDefinitions, componentURL);
966 if (cdef == (id)null)
967 /* resource does not exist */
971 if (cdef) return cdef; // found definition in cache
974 /* take a look into the file system */
976 NSString *baseUrl = nil;
978 baseUrl = [NSString stringWithFormat:@"%@/%@",
979 [appUrl absoluteString], [_name lastPathComponent]];
981 cdef = [self _definitionWithName:_name
983 baseURL:[NSURL URLWithString:baseUrl]
986 [self warnWithFormat:
987 @"(%s): could not load component definition of '%@' from "
988 @"component wrapper: '%@'",
989 __PRETTY_FUNCTION__, _name, componentURL];
991 /* register null in cache, so that we know it's non-existent */
992 NSMapInsert(self->componentDefinitions, componentURL, null);
998 /* register in cache */
999 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1003 /* don't register in cache, does not cache */
1004 cdef = [cdef autorelease];
1009 /* did not find component */
1012 - (WOComponentDefinition *)definitionForComponent:(id)_name
1013 languages:(NSArray *)_langs
1015 // TODO: who uses that? Probably should be deprecated?
1016 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1019 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1020 languages:(NSArray *)_languages
1023 First check whether the cdef is cached, otherwise create a new one.
1025 This method is used by the higher level methods and just implements the
1027 The definition itself is created by definitionForComponent:languages:.
1029 WOComponentDefinition *cdef;
1031 /* look into cache */
1033 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1035 if (cdef == (id)null)
1036 /* component does not exist */
1039 if ([cdef respondsToSelector:@selector(touch)])
1044 /* not cached, create a definition */
1046 cdef = [self definitionForComponent:_name languages:_languages];
1048 /* cache created definition */
1050 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1053 - (WOElement *)templateWithName:(NSString *)_name
1054 languages:(NSArray *)_languages
1056 WOComponentDefinition *cdef;
1058 cdef = [self __definitionForComponent:_name languages:_languages];
1059 if (cdef == nil) return nil;
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 return [NSString stringWithFormat:@"<%@[0x%08X]: path=%@>",
1091 [self class], self, self->base];
1097 - (void)setData:(NSData *)_data
1098 forKey:(NSString *)_key
1099 mimeType:(NSString *)_type
1100 session:(WOSession *)_session
1102 if ((_key == nil) || (_data == nil))
1105 _type = @"application/octet-stream";
1109 if (self->keyedResources == NULL) {
1110 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1111 NSObjectMapValueCallBacks,
1115 NSMapInsert(self->keyedResources,
1117 [NSDictionary dictionaryWithObjectsAndKeys:
1126 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1131 if (self->keyedResources)
1132 tmp = NSMapGet(self->keyedResources, _key);
1136 tmp = [[tmp retain] autorelease];
1143 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1146 if (self->keyedResources)
1147 NSMapRemove(self->keyedResources, _key);
1152 - (void)flushDataCache {
1155 if (self->keyedResources) {
1156 NSFreeMapTable(self->keyedResources);
1157 self->keyedResources = NULL;
1163 @end /* WOResourceManager */