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 {
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 - (id)stringTableWithName:(NSString *)_tableName
541 inFramework:(NSString *)_framework
542 languages:(NSArray *)_languages
544 /* side effect: tables are cached (currently not affected by default!) */
546 _WOStringTable *table = nil;
547 NSString *path = nil;
549 fm = [self fileManager];
551 if (_tableName == nil)
552 _tableName = @"Localizable";
554 /* take a look whether a matching table is already loaded */
556 path = [_tableName stringByAppendingPathExtension:@"strings"];
557 path = [self pathForResourceNamed:path inFramework:_framework
558 languages:_languages];
563 if ((table = NSMapGet(self->stringTables, path)) == NULL) {
564 if ([fm fileExistsAtPath:path]) {
565 table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
566 table = [table initWithPath:path];
567 NSMapInsert(self->stringTables, path, table);
574 - (NSString *)stringForKey:(NSString *)_key
575 inTableNamed:(NSString *)_tableName
576 withDefaultValue:(NSString *)_defaultValue
577 inFramework:(NSString *)_framework
578 languages:(NSArray *)_languages
580 _WOStringTable *table = nil;
582 table = [self stringTableWithName:_tableName inFramework:_framework
583 languages:_languages];
585 return (table != nil)
586 ? [table stringForKey:_key withDefaultValue:_defaultValue]
590 - (NSString *)stringForKey:(NSString *)_key
591 inTableNamed:(NSString *)_tableName
592 withDefaultValue:(NSString *)_default
593 languages:(NSArray *)_languages
595 return [self stringForKey:_key inTableNamed:_tableName
596 withDefaultValue:_default
598 languages:_languages];
609 /* component definitions */
611 - (NSString *)pathToComponentNamed:(NSString *)_name
612 inFramework:(NSString *)_framework
614 /* search for component wrapper .. */
615 // TODO: shouldn't we used that for WOx as well?
621 [self warnWithFormat:
622 @"(%s): tried to get path to component with <nil> name !",
623 __PRETTY_FUNCTION__];
628 /* scan for name.$ext resource ... */
629 e = [[[NSUserDefaults standardUserDefaults]
630 arrayForKey:@"WOComponentExtensions"]
633 while ((ext = [e nextObject])) {
637 specName = [_name stringByAppendingPathExtension:ext];
639 path = [self pathForResourceNamed:specName
640 inFramework:_framework
642 if (path) return path;
647 - (NSString *)pathToComponentNamed:(NSString *)_name
648 inFramework:(NSString *)_framework
649 languages:(NSArray *)_langs
651 return [self pathToComponentNamed:_name inFramework:_framework];
654 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
655 languages:(NSArray *)_languages
657 /* definition factory */
658 WOComponentDefinition *cdef;
660 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
666 return [cdef autorelease];
669 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
671 baseURL:(NSURL *)_baseURL
672 frameworkName:(NSString *)_fwname
674 /* definition factory */
675 static Class DefClass;
679 DefClass = [WOComponentDefinition class];
681 // TODO: is retained response intended?
682 cdef = [[DefClass alloc] initWithName:_name
684 baseURL:_baseURL frameworkName:_fwname];
687 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
688 path:(NSString *)_path
689 baseURL:(NSURL *)_baseURL
690 frameworkName:(NSString *)_fwname
694 url = ([_path length] > 0)
695 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
698 return [self _definitionWithName:_name url:url
699 baseURL:_baseURL frameworkName:_fwname];
702 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
703 languages:(NSArray *)_languages
708 if (self->componentDefinitions == NULL)
710 if (![[WOApplication application] isCachingEnabled])
713 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
714 cdef = NSMapGet(self->componentDefinitions, cacheKey);
718 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
719 forComponent:(id)_name
720 languages:(NSArray *)_languages
724 if (self->componentDefinitions == NULL)
726 if (![[WOApplication application] isCachingEnabled])
729 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
730 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : null);
735 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
736 return [_name stringByAppendingPathExtension:@"wox"];
739 /* create component definition */
741 - (void)_getComponentURL:(NSURL **)url_ andName:(NSString **)name_
742 forNameOrURL:(id)_nameOrURL inFramework:(NSString *)_framework
743 languages:(NSArray *)_languages
747 if ([_nameOrURL isKindOfClass:UrlClass]) {
748 // TODO: where is this used currently? It probably was required for forms,
749 // but might not be anymore?
751 *name_ = [*url_ path];
752 if (debugComponentLookup)
753 [self debugWithFormat:@"using URL %@ for component %@", *url_, *name_];
757 /* the _nameOrURL is a string containing the component name */
761 if (_framework == nil && _nameOrURL != nil) {
765 Note: this is a bit of a hack ..., actually this method should never
766 be called without a framework and pages shouldn't be instantiated
767 without specifying their framework.
768 But for legacy reasons this needs to be done and seems to work without
769 problems. It is required for loading components from bundles.
771 if ((_framework = rapidTurnAroundPath) == nil) {
772 if ((clazz = NSClassFromString(_nameOrURL)))
773 _framework = [[NSBundle bundleForClass:clazz] bundlePath];
777 if (debugComponentLookup) {
778 [self logWithFormat:@"component '%@' in framework '%@'",
779 _nameOrURL, _framework];
782 /* look for .wox component */
784 path = [self pathForResourceNamed:
785 [self resourceNameForComponentNamed:*name_]
786 inFramework:_framework
787 languages:_languages];
789 if (debugComponentLookup)
790 [self logWithFormat:@" .wox path: '%@'", path];
792 /* look for .wo component */
794 if ([path length] == 0) {
795 path = [self pathToComponentNamed:*name_
796 inFramework:_framework
797 languages:_languages];
798 if (debugComponentLookup)
799 [self logWithFormat:@" .wo path: '%@'", path];
802 /* make URL from path */
804 *url_ = ([path length] > 0)
805 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
809 - (WOComponentDefinition *)definitionForFileURL:(NSURL *)componentURL
810 componentName:(NSString *)_name inFramework:(NSString *)_framework
811 languages:(NSArray *)_languages
814 NSString *componentPath;
815 BOOL doesCache, isDir;
816 NSEnumerator *languages;
818 NSString *sname = nil;
821 fm = [self fileManager];
822 componentPath = [componentURL path];
823 doesCache = [[WOApplication application] isCachingEnabled];
825 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
826 [[WOApplication application]
828 @"%s: did not find component '%@' at path '%@' !",
830 _name, componentPath];
834 /* if the component spec is a directory (eg a .wo), scan inside for stuff*/
839 appUrl = [[WOApplication application] baseURL];
840 languages = [_languages objectEnumerator];
841 while ((language = [languages nextObject])) {
842 WOComponentDefinition *cdef;
843 NSString *compoundKey = nil;
844 NSString *languagePath = nil;
845 NSString *baseUrl = nil;
846 BOOL isDirectory = NO;
848 if (sname == nil) sname = [_name stringByAppendingString:@"\t"];
849 compoundKey = [sname stringByAppendingString:language];
852 cdef = NSMapGet(self->componentDefinitions, compoundKey);
854 if (cdef == (id)null)
855 /* resource does not exist */
859 if (cdef != nil) return cdef; // found definition in cache
862 /* take a look into the file system */
863 languagePath = [language stringByAppendingPathExtension:@"lproj"];
865 [componentPath stringByAppendingPathComponent:languagePath];
867 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
869 /* register null in cache, so that we know it's non-existent */
870 NSMapInsert(self->componentDefinitions, compoundKey, null);
876 [self warnWithFormat:@"(%s): language entry %@ is not a directory !",
877 __PRETTY_FUNCTION__, languagePath];
878 if (doesCache && (compoundKey != nil)) {
879 // register null in cache, so that we know it's non-existent
880 NSMapInsert(self->componentDefinitions, compoundKey, null);
885 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
886 [appUrl absoluteString], language, _name];
888 /* found appropriate language project */
889 cdef = [self _definitionWithName:_name
891 baseURL:[NSURL URLWithString:baseUrl]
894 [self warnWithFormat:
895 @"(%s): could not load component definition of "
896 @"'%@' from language project: %@",
897 __PRETTY_FUNCTION__, _name, languagePath];
898 if (doesCache && (compoundKey != nil)) {
899 // register null in cache, so that we know it's non-existent
900 NSMapInsert(self->componentDefinitions, compoundKey, null);
905 if (doesCache && (compoundKey != nil)) {
907 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
911 // don't register in cache
912 cdef = [cdef autorelease];
920 - (WOComponentDefinition *)definitionForComponent:(id)_name
921 inFramework:(NSString *)_framework
922 languages:(NSArray *)_languages
924 // TODO: this method is definitely too big! => refacture
926 NSFileManager *fm = nil;
927 WOComponentDefinition *cdef = nil;
932 app = [WOApplication application];
933 doesCache = [app isCachingEnabled];
935 /* lookup component path */
937 // TODO: Explain why _framework and _languages are NOT passed!
938 [self _getComponentURL:&componentURL andName:&_name
939 forNameOrURL:_name inFramework:nil languages:nil];
941 if (debugComponentLookup) {
942 [self logWithFormat:@" component='%@' in framework='%@': url='%@'",
943 _name, _framework, componentURL];
946 appUrl = [app baseURL];
948 /* check whether it's a 'template-less' component ... */
950 if (componentURL == nil) {
951 /* did not find component wrapper ! */
952 [app debugWithFormat:@" component '%@' has no template !", _name];
954 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
958 fm = [self fileManager];
960 /* ensure that the component exists */
962 if ([componentURL isFileURL]) {
963 WOComponentDefinition *cdef;
965 cdef = [self definitionForFileURL:componentURL componentName:_name
966 inFramework:_framework languages:_languages];
967 if (cdef != nil && ![cdef isNotNull])
969 else if (cdef != nil)
976 cdef = NSMapGet(self->componentDefinitions, componentURL);
978 if (cdef == (id)null)
979 /* resource does not exist */
983 if (cdef) return cdef; // found definition in cache
986 /* take a look into the file system */
988 NSString *baseUrl = nil;
990 baseUrl = [NSString stringWithFormat:@"%@/%@",
991 [appUrl absoluteString], [_name lastPathComponent]];
993 cdef = [self _definitionWithName:_name
995 baseURL:[NSURL URLWithString:baseUrl]
998 [self warnWithFormat:
999 @"(%s): could not load component definition of '%@' from "
1000 @"component wrapper: '%@'",
1001 __PRETTY_FUNCTION__, _name, componentURL];
1003 /* register null in cache, so that we know it's non-existent */
1004 NSMapInsert(self->componentDefinitions, componentURL, null);
1010 /* register in cache */
1011 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1015 /* don't register in cache, does not cache */
1016 cdef = [cdef autorelease];
1021 /* did not find component */
1024 - (WOComponentDefinition *)definitionForComponent:(id)_name
1025 languages:(NSArray *)_langs
1027 // TODO: who uses that? Probably should be deprecated?
1028 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1031 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1032 languages:(NSArray *)_languages
1035 First check whether the cdef is cached, otherwise create a new one.
1037 This method is used by the higher level methods and just implements the
1039 The definition itself is created by definitionForComponent:languages:.
1041 WOComponentDefinition *cdef;
1043 /* look into cache */
1045 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1047 if (cdef == (id)null)
1048 /* component does not exist */
1051 if ([cdef respondsToSelector:@selector(touch)])
1056 /* not cached, create a definition */
1058 cdef = [self definitionForComponent:_name languages:_languages];
1060 /* cache created definition */
1062 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1065 - (WOElement *)templateWithName:(NSString *)_name
1066 languages:(NSArray *)_languages
1068 WOComponentDefinition *cdef;
1070 cdef = [self __definitionForComponent:_name languages:_languages];
1074 return (WOElement *)[cdef template];
1077 - (id)pageWithName:(NSString *)_name languages:(NSArray *)_langs {
1079 TODO: this appears to be deprecated since the WOComponent initializer
1080 is now -initWithContext: and we have no context over here ...
1082 NSAutoreleasePool *pool;
1083 WOComponentDefinition *cdef;
1084 WOComponent *component = nil;
1086 pool = [[NSAutoreleasePool alloc] init];
1088 cdef = [self __definitionForComponent:_name languages:_langs];
1090 // TODO: document what the resource manager is used for in the cdef
1092 [[cdef instantiateWithResourceManager:self languages:_langs] retain];
1097 return [component autorelease];
1102 - (NSString *)description {
1103 NSMutableString *ms;
1105 ms = [NSMutableString stringWithCapacity:32];
1106 [ms appendFormat:@"<0x%08X[%@]:", self, NSStringFromClass([self class])];
1107 if ([self->base length] > 0)
1108 [ms appendFormat:@" path='%@'", self->base];
1109 [ms appendString:@">"];
1115 - (void)setData:(NSData *)_data
1116 forKey:(NSString *)_key
1117 mimeType:(NSString *)_type
1118 session:(WOSession *)_session
1120 if ((_key == nil) || (_data == nil))
1123 _type = @"application/octet-stream";
1127 if (self->keyedResources == NULL) {
1128 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1129 NSObjectMapValueCallBacks,
1133 NSMapInsert(self->keyedResources,
1135 [NSDictionary dictionaryWithObjectsAndKeys:
1144 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1149 if (self->keyedResources)
1150 tmp = NSMapGet(self->keyedResources, _key);
1154 tmp = [[tmp retain] autorelease];
1161 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1164 if (self->keyedResources)
1165 NSMapRemove(self->keyedResources, _key);
1170 - (void)flushDataCache {
1173 if (self->keyedResources) {
1174 NSFreeMapTable(self->keyedResources);
1175 self->keyedResources = NULL;
1181 @end /* WOResourceManager */