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)(long)NSMapGet(self->existingPathes, path);
127 doesExist = [fm fileExistsAtPath:path];
128 NSMapInsert(self->existingPathes, path,
129 (void *)(doesExist ? 1L : 0xFFL));
132 doesExist = i == 1 ? YES : NO;
135 doesExist = [fm fileExistsAtPath:path];
139 + (void)setResourcePrefix:(NSString *)_prefix {
140 [resourcePrefix autorelease];
141 resourcePrefix = [_prefix copy];
144 - (id)initWithPath:(NSString *)_path {
146 if ([_path length] == 0) {
147 [self errorWithFormat:@"(%s): missing path!", __PRETTY_FUNCTION__];
148 /* this doesn't work with subclasses which do not require a path ... */
156 if ((self = [super init])) {
157 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
158 NSString *rprefix = nil;
161 self->componentDefinitions =
162 NSCreateMapTable(NSObjectMapKeyCallBacks,
163 NSObjectMapValueCallBacks,
166 NSCreateMapTable(NSObjectMapKeyCallBacks,
167 NSObjectMapValueCallBacks,
170 tmp = [_path stringByStandardizingPath];
171 if (tmp) _path = tmp;
173 self->base = [_path copy];
175 if ([WOApplication isCachingEnabled]) {
176 self->existingPathes = NSCreateMapTable(NSObjectMapKeyCallBacks,
177 NSIntMapValueCallBacks,
181 rprefix = [ud stringForKey:@"WOResourcePrefix"];
182 if (rprefix) [[self class] setResourcePrefix:rprefix];
187 return [self initWithPath:[[NGBundle mainBundle] bundlePath]];
191 if (self->existingPathes) NSFreeMapTable(self->existingPathes);
192 if (self->stringTables) NSFreeMapTable(self->stringTables);
193 if (self->componentDefinitions) NSFreeMapTable(self->componentDefinitions);
194 if (self->keyedResources) NSFreeMapTable(self->keyedResources);
195 [self->w3resources release];
196 [self->resources release];
197 [self->base release];
203 - (BOOL)isDebuggingEnabled {
206 - (NSString *)loggingPrefix {
208 sprintf(buf, "[wo-rm-0x%p]", self);
209 return [NSString stringWithCString:buf];
214 - (NSFileManager *)fileManager {
215 static NSFileManager *fm = nil;
217 fm = [[NSFileManager defaultManager] retain];
221 - (NSString *)basePath {
225 - (NSString *)resourcesPath {
229 return self->resources;
231 fm = [self fileManager];
232 if ([self->base length] > 0) {
233 if (![fm fileExistsAtPath:self->base]) {
234 [self warnWithFormat:@"(%s): Resources base path '%@' does not exist !",
235 __PRETTY_FUNCTION__, self->base];
241 if ([rapidTurnAroundPath length] > 0) {
243 In rapid turnaround mode, first check for a Resources subdir in the
244 project directory, then directly in the project dir.
245 Note: you cannot have both! Either put stuff in a Resources subdir *or*
251 tmp = [rapidTurnAroundPath stringByAppendingPathComponent:@"Resources"];
252 if (![fm fileExistsAtPath:tmp isDirectory:&isDir])
255 tmp = rapidTurnAroundPath;
257 self->resources = [tmp copy];
261 [[[self->base stringByAppendingPathComponent:@"Contents"]
262 stringByAppendingPathComponent:@"Resources"]
267 [[self->base stringByAppendingPathComponent:@"Resources"] copy];
270 if ([self->resources length] > 0) {
271 if (![fm fileExistsAtPath:self->resources]) {
272 [self warnWithFormat:
273 @"(%s): Resources path %@ does not exist !",
274 __PRETTY_FUNCTION__, self->resources];
275 [self->resources release]; self->resources = nil;
277 else if (self->existingPathes && (self->resources != nil))
278 NSMapInsert(self->existingPathes, self->resources, (void*)1);
280 return self->resources;
283 - (NSString *)resourcesPathForFramework:(NSString *)_fw {
284 if (_fw == nil || (_fw == rapidTurnAroundPath))
285 return [self resourcesPath];
288 return [[_fw stringByAppendingPathComponent:@"Contents"]
289 stringByAppendingPathComponent:@"Resources"];
291 return [_fw stringByAppendingPathComponent:@"Resources"];
295 - (NSString *)webServerResourcesPath {
298 if (self->w3resources)
299 return self->w3resources;
301 #if GNUSTEP_BASE_LIBRARY && 0
303 [[self->base stringByAppendingPathComponent:@"Resources/WebServer"] copy];
306 [[self->base stringByAppendingPathComponent:@"WebServerResources"] copy];
309 fm = [self fileManager];
310 if ([self->w3resources length] == 0)
313 if (![fm fileExistsAtPath:self->w3resources]) {
314 static BOOL didLog = NO;
317 [self warnWithFormat:
318 @"(%s): WebServerResources path '%@' does not exist !",
319 __PRETTY_FUNCTION__, self->w3resources];
321 [self->w3resources release]; self->w3resources = nil;
323 else if (self->existingPathes && (self->w3resources != nil))
324 NSMapInsert(self->existingPathes, self->w3resources, (void*)1);
326 if (debugResourceLookup)
327 [self logWithFormat:@"WebServerResources: '%@'", self->w3resources];
328 return self->w3resources;
331 - (NSString *)pathForResourceNamed:(NSString *)_name
332 inFramework:(NSString *)_frameworkName
333 languages:(NSArray *)_languages
336 NSString *resource = nil;
340 if (debugResourceLookup) {
341 [self logWithFormat:@"lookup '%@' bundle=%@ languages=%@",
342 _name, _frameworkName, [_languages componentsJoinedByString:@","]];
345 fm = [self fileManager];
346 langCount = [_languages count];
348 if ((w3rp = [self webServerResourcesPath]) != nil) {
349 NSString *langPath = nil;
352 if (debugResourceLookup)
353 [self logWithFormat:@" WebServerResources: %@", w3rp];
355 // first check Language.lproj in WebServerResources
356 for (i = 0; i < langCount; i++) {
357 langPath = [_languages objectAtIndex:i];
358 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
359 langPath = [w3rp stringByAppendingPathComponent:langPath];
361 if (!_pathExists(self, fm, langPath)) {
362 if (debugResourceLookup) {
364 @" no language project for '%@' in WebServerResources: %@",
365 [_languages objectAtIndex:i], langPath];
370 resource = [langPath stringByAppendingPathComponent:_name];
372 if (debugResourceLookup)
373 [self logWithFormat:@" check in WebServerResources: %@", resource];
374 if (_pathExists(self, fm, resource))
378 /* next check in WebServerResources itself */
379 resource = [w3rp stringByAppendingPathComponent:_name];
380 if (debugResourceLookup)
381 [self logWithFormat:@" check in WebServerResources-flat: %@", resource];
382 if (_pathExists(self, fm, resource))
386 if ((rp = [self resourcesPathForFramework:_frameworkName])) {
387 NSString *langPath = nil;
390 if (debugResourceLookup) [self logWithFormat:@" path %@", rp];
392 // first check Language.lproj in Resources
393 for (i = 0; i < langCount; i++) {
394 langPath = [_languages objectAtIndex:i];
395 langPath = [langPath stringByAppendingPathExtension:@"lproj"];
396 langPath = [rp stringByAppendingPathComponent:langPath];
398 if (_pathExists(self, fm, langPath)) {
399 resource = [langPath stringByAppendingPathComponent:_name];
401 if (debugResourceLookup)
402 [self logWithFormat:@" check in Resources: %@", resource];
403 if (_pathExists(self, fm, resource))
408 // next check in Resources itself
409 resource = [rp stringByAppendingPathComponent:_name];
410 if (debugResourceLookup)
411 [self logWithFormat:@" check in Resources-flat: %@", resource];
412 if (_pathExists(self, fm, resource)) {
413 if (debugResourceLookup)
414 [self logWithFormat:@" found => %@", resource];
419 /* and last check in the application directory */
420 if (_pathExists(self, fm, self->base)) {
421 resource = [self->base stringByAppendingPathComponent:_name];
422 if (_pathExists(self, fm, resource))
428 - (NSString *)pathForResourceNamed:(NSString *)_name {
430 return [self pathForResourceNamed:_name inFramework:nil languages:nil];
433 - (NSString *)pathForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
434 _name = [_name stringByAppendingPathExtension:_type];
435 return [self pathForResourceNamed:_name];
440 - (NSString *)_urlForMissingResource:(NSString *)_name request:(WORequest *)_r{
443 app = [WOApplication application];
445 if (!genMissingResourceLinks)
448 return [NSString stringWithFormat:
449 @"/missingresource?name=%@&application=%@",
450 _name, app ? [app name] : [_r applicationName]];
453 - (NSString *)urlForResourceNamed:(NSString *)_name
454 inFramework:(NSString *)_frameworkName
455 languages:(NSArray *)_languages
456 request:(WORequest *)_request
459 NSMutableString *url;
460 NSString *resource = nil, *tmp;
461 NSString *path = nil, *sbase;
464 app = [WOApplication application];
466 if (_languages == nil)
467 _languages = [_request browserLanguages];
469 resource = [self pathForResourceNamed:_name
470 inFramework:_frameworkName
471 languages:_languages];
473 if ([resource rangeOfString:@"/Contents/"].length > 0) {
474 resource = [resource stringByReplacingString:@"/Contents"
479 tmp = [resource stringByStandardizingPath];
480 if (tmp != nil) resource = tmp;
483 if (resource == nil) {
484 if (debugResourceLookup)
485 [self logWithFormat:@"did not find resource (cannot build URL)"];
486 return [self _urlForMissingResource:_name request:_request];
490 tmp = [sbase commonPrefixWithString:resource options:0];
493 path = [sbase substringFromIndex:len];
494 tmp = [resource substringFromIndex:len];
495 if (([path length] > 0) && ![tmp hasPrefix:@"/"] && ![tmp hasPrefix:@"\\"])
496 path = [path stringByAppendingString:@"/"];
497 path = [path stringByAppendingString:tmp];
502 cs = [path componentsSeparatedByString:@"\\"];
503 path = [cs componentsJoinedByString:@"/"];
508 return [self _urlForMissingResource:_name request:_request];
510 url = [[NSMutableString alloc] initWithCapacity:256];
512 [url appendString:[_request adaptorPrefix]];
515 [url appendString:resourcePrefix];
516 if (![url hasSuffix:@"/"]) [url appendString:@"/"];
517 [url appendString:app ? [app name] : [_request applicationName]];
518 [url appendString:suffix];
519 if (![path hasPrefix:@"/"]) [url appendString:@"/"];
520 [url appendString:path];
524 return [path autorelease];
527 - (NSString *)urlForResourceNamed:(NSString *)_name {
529 return [self urlForResourceNamed:_name
534 - (NSString *)urlForResourceNamed:(NSString *)_name ofType:(NSString *)_type {
535 return [self urlForResourceNamed:
536 [_name stringByAppendingPathExtension:_type]];
541 - (id)stringTableWithName:(NSString *)_tableName
542 inFramework:(NSString *)_framework
543 languages:(NSArray *)_languages
545 /* side effect: tables are cached (currently not affected by default!) */
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];
564 if ((table = NSMapGet(self->stringTables, path)) == NULL) {
565 if ([fm fileExistsAtPath:path]) {
566 table = [_WOStringTable allocWithZone:[self zone]]; /* for gcc */
567 table = [table initWithPath:path];
568 NSMapInsert(self->stringTables, path, table);
575 - (NSString *)stringForKey:(NSString *)_key
576 inTableNamed:(NSString *)_tableName
577 withDefaultValue:(NSString *)_defaultValue
578 inFramework:(NSString *)_framework
579 languages:(NSArray *)_languages
581 _WOStringTable *table = nil;
583 table = [self stringTableWithName:_tableName inFramework:_framework
584 languages:_languages];
586 return (table != nil)
587 ? [table stringForKey:_key withDefaultValue:_defaultValue]
591 - (NSString *)stringForKey:(NSString *)_key
592 inTableNamed:(NSString *)_tableName
593 withDefaultValue:(NSString *)_default
594 languages:(NSArray *)_languages
596 return [self stringForKey:_key inTableNamed:_tableName
597 withDefaultValue:_default
599 languages:_languages];
610 /* component definitions */
612 - (NSString *)pathToComponentNamed:(NSString *)_name
613 inFramework:(NSString *)_framework
615 /* search for component wrapper .. */
616 // TODO: shouldn't we used that for WOx as well?
622 [self warnWithFormat:
623 @"(%s): tried to get path to component with <nil> name !",
624 __PRETTY_FUNCTION__];
629 /* scan for name.$ext resource ... */
630 e = [[[NSUserDefaults standardUserDefaults]
631 arrayForKey:@"WOComponentExtensions"]
634 while ((ext = [e nextObject])) {
638 specName = [_name stringByAppendingPathExtension:ext];
640 path = [self pathForResourceNamed:specName
641 inFramework:_framework
643 if (path) return path;
648 - (NSString *)pathToComponentNamed:(NSString *)_name
649 inFramework:(NSString *)_framework
650 languages:(NSArray *)_langs
652 return [self pathToComponentNamed:_name inFramework:_framework];
655 - (WOComponentDefinition *)_definitionForPathlessComponent:(NSString *)_name
656 languages:(NSArray *)_languages
658 /* definition factory */
659 WOComponentDefinition *cdef;
661 cdef = [[WOComponentDefinition allocWithZone:[self zone]]
667 return [cdef autorelease];
670 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
672 baseURL:(NSURL *)_baseURL
673 frameworkName:(NSString *)_fwname
675 /* definition factory */
676 static Class DefClass;
680 DefClass = [WOComponentDefinition class];
682 // TODO: is retained response intended?
683 cdef = [[DefClass alloc] initWithName:_name
685 baseURL:_baseURL frameworkName:_fwname];
688 - (WOComponentDefinition *)_definitionWithName:(NSString *)_name
689 path:(NSString *)_path
690 baseURL:(NSURL *)_baseURL
691 frameworkName:(NSString *)_fwname
695 url = ([_path length] > 0)
696 ? [[[NSURL alloc] initFileURLWithPath:_path] autorelease]
699 return [self _definitionWithName:_name url:url
700 baseURL:_baseURL frameworkName:_fwname];
703 - (WOComponentDefinition *)_cachedDefinitionForComponent:(id)_name
704 languages:(NSArray *)_languages
709 if (self->componentDefinitions == NULL)
711 if (![[WOApplication application] isCachingEnabled])
714 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
715 cdef = NSMapGet(self->componentDefinitions, cacheKey);
719 - (WOComponentDefinition *)_cacheDefinition:(id)_cdef
720 forComponent:(id)_name
721 languages:(NSArray *)_languages
725 if (self->componentDefinitions == NULL)
727 if (![[WOApplication application] isCachingEnabled])
730 cacheKey = [NSArray arrayWithObjects:_name, _languages, nil];
731 NSMapInsert(self->componentDefinitions, cacheKey, _cdef ? _cdef : (id)null);
736 - (NSString *)resourceNameForComponentNamed:(NSString *)_name {
737 return [_name stringByAppendingPathExtension:@"wox"];
740 /* create component definition */
742 - (void)_getComponentURL:(NSURL **)url_ andName:(NSString **)name_
743 forNameOrURL:(id)_nameOrURL inFramework:(NSString *)_framework
744 languages:(NSArray *)_languages
748 if ([_nameOrURL isKindOfClass:UrlClass]) {
749 // TODO: where is this used currently? It probably was required for forms,
750 // but might not be anymore?
752 *name_ = [*url_ path];
753 if (debugComponentLookup)
754 [self debugWithFormat:@"using URL %@ for component %@", *url_, *name_];
758 /* the _nameOrURL is a string containing the component name */
762 if (_framework == nil && _nameOrURL != nil) {
766 Note: this is a bit of a hack ..., actually this method should never
767 be called without a framework and pages shouldn't be instantiated
768 without specifying their framework.
769 But for legacy reasons this needs to be done and seems to work without
770 problems. It is required for loading components from bundles.
772 if ((_framework = rapidTurnAroundPath) == nil) {
773 if ((clazz = NSClassFromString(_nameOrURL)))
774 _framework = [[NSBundle bundleForClass:clazz] bundlePath];
778 if (debugComponentLookup) {
779 [self logWithFormat:@"component '%@' in framework '%@'",
780 _nameOrURL, _framework];
783 /* look for .wox component */
785 path = [self pathForResourceNamed:
786 [self resourceNameForComponentNamed:*name_]
787 inFramework:_framework
788 languages:_languages];
790 if (debugComponentLookup)
791 [self logWithFormat:@" .wox path: '%@'", path];
793 /* look for .wo component */
795 if ([path length] == 0) {
796 path = [self pathToComponentNamed:*name_
797 inFramework:_framework
798 languages:_languages];
799 if (debugComponentLookup)
800 [self logWithFormat:@" .wo path: '%@'", path];
803 /* make URL from path */
805 *url_ = ([path length] > 0)
806 ? [[[UrlClass alloc] initFileURLWithPath:path] autorelease]
810 - (WOComponentDefinition *)definitionForFileURL:(NSURL *)componentURL
811 componentName:(NSString *)_name inFramework:(NSString *)_framework
812 languages:(NSArray *)_languages
815 NSString *componentPath;
816 BOOL doesCache, isDir;
817 NSEnumerator *languages;
819 NSString *sname = nil;
822 fm = [self fileManager];
823 componentPath = [componentURL path];
824 doesCache = [[WOApplication application] isCachingEnabled];
826 if (![fm fileExistsAtPath:componentPath isDirectory:&isDir]) {
827 [[WOApplication application]
829 @"%s: did not find component '%@' at path '%@' !",
831 _name, componentPath];
835 /* if the component spec is a directory (eg a .wo), scan inside for stuff*/
840 appUrl = [[WOApplication application] baseURL];
841 languages = [_languages objectEnumerator];
842 while ((language = [languages nextObject])) {
843 WOComponentDefinition *cdef;
844 NSString *compoundKey = nil;
845 NSString *languagePath = nil;
846 NSString *baseUrl = nil;
847 BOOL isDirectory = NO;
849 if (sname == nil) sname = [_name stringByAppendingString:@"\t"];
850 compoundKey = [sname stringByAppendingString:language];
853 cdef = NSMapGet(self->componentDefinitions, compoundKey);
855 if (cdef == (id)null)
856 /* resource does not exist */
860 if (cdef != nil) return cdef; // found definition in cache
863 /* take a look into the file system */
864 languagePath = [language stringByAppendingPathExtension:@"lproj"];
866 [componentPath stringByAppendingPathComponent:languagePath];
868 if (![fm fileExistsAtPath:languagePath isDirectory:&isDirectory]) {
870 /* register null in cache, so that we know it's non-existent */
871 NSMapInsert(self->componentDefinitions, compoundKey, null);
877 [self warnWithFormat:@"(%s): language entry %@ is not a directory !",
878 __PRETTY_FUNCTION__, languagePath];
879 if (doesCache && (compoundKey != nil)) {
880 // register null in cache, so that we know it's non-existent
881 NSMapInsert(self->componentDefinitions, compoundKey, null);
886 baseUrl = [NSString stringWithFormat:@"%@/%@.lproj/%@.wo",
887 [appUrl absoluteString], language, _name];
889 /* found appropriate language project */
890 cdef = [self _definitionWithName:_name
892 baseURL:[NSURL URLWithString:baseUrl]
895 [self warnWithFormat:
896 @"(%s): could not load component definition of "
897 @"'%@' from language project: %@",
898 __PRETTY_FUNCTION__, _name, languagePath];
899 if (doesCache && (compoundKey != nil)) {
900 // register null in cache, so that we know it's non-existent
901 NSMapInsert(self->componentDefinitions, compoundKey, null);
906 if (doesCache && (compoundKey != nil)) {
908 NSMapInsert(self->componentDefinitions, compoundKey, cdef);
912 // don't register in cache
913 cdef = [cdef autorelease];
921 - (WOComponentDefinition *)definitionForComponent:(id)_name
922 inFramework:(NSString *)_framework
923 languages:(NSArray *)_languages
925 // TODO: this method is definitely too big! => refacture
927 NSFileManager *fm = nil;
928 WOComponentDefinition *cdef = nil;
933 app = [WOApplication application];
934 doesCache = [app isCachingEnabled];
936 /* lookup component path */
938 // TODO: Explain why _framework and _languages are NOT passed!
939 [self _getComponentURL:&componentURL andName:&_name
940 forNameOrURL:_name inFramework:nil languages:nil];
942 if (debugComponentLookup) {
943 [self logWithFormat:@" component='%@' in framework='%@': url='%@'",
944 _name, _framework, componentURL];
947 appUrl = [app baseURL];
949 /* check whether it's a 'template-less' component ... */
951 if (componentURL == nil) {
952 /* did not find component wrapper ! */
953 [app debugWithFormat:@" component '%@' has no template !", _name];
955 cdef = [self _definitionForPathlessComponent:_name languages:_languages];
959 fm = [self fileManager];
961 /* ensure that the component exists */
963 if ([componentURL isFileURL]) {
964 WOComponentDefinition *cdef;
966 cdef = [self definitionForFileURL:componentURL componentName:_name
967 inFramework:_framework languages:_languages];
968 if (cdef != nil && ![cdef isNotNull])
970 else if (cdef != nil)
977 cdef = NSMapGet(self->componentDefinitions, componentURL);
979 if (cdef == (id)null)
980 /* resource does not exist */
984 if (cdef) return cdef; // found definition in cache
987 /* take a look into the file system */
989 NSString *baseUrl = nil;
991 baseUrl = [NSString stringWithFormat:@"%@/%@",
992 [appUrl absoluteString], [_name lastPathComponent]];
994 cdef = [self _definitionWithName:_name
996 baseURL:[NSURL URLWithString:baseUrl]
999 [self warnWithFormat:
1000 @"(%s): could not load component definition of '%@' from "
1001 @"component wrapper: '%@'",
1002 __PRETTY_FUNCTION__, _name, componentURL];
1004 /* register null in cache, so that we know it's non-existent */
1005 NSMapInsert(self->componentDefinitions, componentURL, null);
1011 /* register in cache */
1012 NSMapInsert(self->componentDefinitions, componentURL, cdef);
1016 /* don't register in cache, does not cache */
1017 cdef = [cdef autorelease];
1022 /* did not find component */
1025 - (WOComponentDefinition *)definitionForComponent:(id)_name
1026 languages:(NSArray *)_langs
1028 // TODO: who uses that? Probably should be deprecated?
1029 return [self definitionForComponent:_name inFramework:nil languages:_langs];
1032 - (WOComponentDefinition *)__definitionForComponent:(id)_name
1033 languages:(NSArray *)_languages
1036 First check whether the cdef is cached, otherwise create a new one.
1038 This method is used by the higher level methods and just implements the
1040 The definition itself is created by definitionForComponent:languages:.
1042 WOComponentDefinition *cdef;
1044 /* look into cache */
1046 cdef = [self _cachedDefinitionForComponent:_name languages:_languages];
1048 if (cdef == (id)null)
1049 /* component does not exist */
1052 if ([cdef respondsToSelector:@selector(touch)])
1057 /* not cached, create a definition */
1059 cdef = [self definitionForComponent:_name languages:_languages];
1061 /* cache created definition */
1063 return [self _cacheDefinition:cdef forComponent:_name languages:_languages];
1066 - (WOElement *)templateWithName:(NSString *)_name
1067 languages:(NSArray *)_languages
1069 WOComponentDefinition *cdef;
1071 cdef = [self __definitionForComponent:_name languages:_languages];
1075 return (WOElement *)[cdef template];
1078 - (id)pageWithName:(NSString *)_name languages:(NSArray *)_langs {
1080 TODO: this appears to be deprecated since the WOComponent initializer
1081 is now -initWithContext: and we have no context over here ...
1083 NSAutoreleasePool *pool;
1084 WOComponentDefinition *cdef;
1085 WOComponent *component = nil;
1087 pool = [[NSAutoreleasePool alloc] init];
1089 cdef = [self __definitionForComponent:_name languages:_langs];
1091 // TODO: document what the resource manager is used for in the cdef
1093 [[cdef instantiateWithResourceManager:self languages:_langs] retain];
1098 return [component autorelease];
1103 - (void)setData:(NSData *)_data
1104 forKey:(NSString *)_key
1105 mimeType:(NSString *)_type
1106 session:(WOSession *)_session
1108 if ((_key == nil) || (_data == nil))
1111 _type = @"application/octet-stream";
1115 if (self->keyedResources == NULL) {
1116 self->keyedResources = NSCreateMapTable(NSObjectMapKeyCallBacks,
1117 NSObjectMapValueCallBacks,
1121 NSMapInsert(self->keyedResources,
1123 [NSDictionary dictionaryWithObjectsAndKeys:
1132 - (id)_dataForKey:(NSString *)_key sessionID:(NSString *)_sid {
1137 if (self->keyedResources)
1138 tmp = NSMapGet(self->keyedResources, _key);
1142 tmp = [[tmp retain] autorelease];
1149 - (void)removeDataForKey:(NSString *)_key session:(WOSession *)_session {
1152 if (self->keyedResources)
1153 NSMapRemove(self->keyedResources, _key);
1158 - (void)flushDataCache {
1161 if (self->keyedResources) {
1162 NSFreeMapTable(self->keyedResources);
1163 self->keyedResources = NULL;
1171 - (NSString *)description {
1172 NSMutableString *ms;
1174 ms = [NSMutableString stringWithCapacity:32];
1175 [ms appendFormat:@"<0x%p[%@]:", self, NSStringFromClass([self class])];
1176 if ([self->base length] > 0)
1177 [ms appendFormat:@" path='%@'", self->base];
1178 [ms appendString:@">"];
1182 @end /* WOResourceManager */