/** GSWDeployedBundle.m - GSWeb: Class GSWDeployedBundle Copyright (C) 1999-2003 Free Software Foundation, Inc. Written by: Manuel Guesdon Date: Mar 1999 $Revision$ $Date$ This file is part of the GNUstep Web Library. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **/ #include "config.h" RCS_ID("$Id$") #include "GSWeb.h" //==================================================================== @implementation GSWDeployedBundle //-------------------------------------------------------------------- -(id)initWithPath:(NSString*)aPath { LOGObjectFnStart(); if ((self=[super init])) { NSDebugMLLog(@"bundles",@"aPath=%@",aPath); ASSIGN(_bundlePath,[aPath stringGoodPath]); NSDebugMLLog(@"bundles",@"_bundlePath=%@",_bundlePath); ASSIGN(_wrapperName,([_bundlePath lastPathComponent])); NSDebugMLLog(@"bundles",@"_wrapperName=%@",_wrapperName); ASSIGN(_projectName,([_wrapperName stringByDeletingPathExtension])); NSDebugMLLog(@"bundles",@"_projectName=%@",_projectName); _isFramework=[_bundlePath hasSuffix:GSFrameworkSuffix];//Ok ? _relativePathsCache=[GSWMultiKeyDictionary new]; _absolutePathsCache=[NSMutableDictionary new]; _urlsCache=[NSMutableDictionary new]; #ifndef NDEBUG _creation_thread_id=objc_thread_id(); #endif _selfLock=[NSRecursiveLock new]; }; LOGObjectFnStop(); return self; }; //-------------------------------------------------------------------- -(void)dealloc { NSDebugFLog(@"Dealloc GSWDeployedBundle %p",(void*)self); DESTROY(_bundlePath); DESTROY(_wrapperName); DESTROY(_projectName); DESTROY(_relativePathsCache); DESTROY(_absolutePathsCache); DESTROY(_urlsCache); GSWLogC("Dealloc GSWDeployedBundle: selfLock"); NSDebugFLog(@"selfLock=%p selfLockn=%d selfLock_thread_id=%p objc_thread_id()=%p creation_thread_id=%p", (void*)_selfLock, _selfLockn, (void*)_selfLock_thread_id, (void*)objc_thread_id(), (void*)_creation_thread_id); fflush(stderr); DESTROY(_selfLock); GSWLogC("Dealloc GSWDeployedBundle Super"); [super dealloc]; NSDebugFLog(@"End Dealloc GSWDeployedBundle %p",(void*)self); }; //-------------------------------------------------------------------- -(NSString*)description { NSString* descr=nil; // GSWLogC("GSWDeployedBundle description A"); descr=[NSString stringWithFormat:@"<%s %p - ", object_get_class_name(self), (void*)self]; // GSWLogC("GSWDeployedBundle description B"); descr=[descr stringByAppendingFormat:@"bundlePath:%@ ", _bundlePath]; // GSWLogC("GSWDeployedBundle description C"); descr=[descr stringByAppendingFormat:@"relativePathsCache=%p>", (void*)_relativePathsCache]; // GSWLogC("GSWDeployedBundle description D"); return descr; }; //-------------------------------------------------------------------- -(GSWProjectBundle*)projectBundle { //OK NSString* projectName=nil; BOOL isFramework=NO; GSWDeployedBundle* projectBundle=nil; LOGObjectFnStart(); projectName=[self projectName]; NSDebugMLLog(@"bundles",@"projectName=%@",projectName); isFramework=[self isFramework]; NSDebugMLLog(@"bundles",@"isFramework=%s",(isFramework ? "YES" : "NO")); projectBundle=[GSWProjectBundle projectBundleForProjectNamed:projectName isFramework:isFramework]; NSDebugMLLog(@"bundles",@"projectBundle=%@",projectBundle); LOGObjectFnStop(); return (GSWProjectBundle*)projectBundle; }; //-------------------------------------------------------------------- -(BOOL)isFramework { return _isFramework; }; //-------------------------------------------------------------------- -(NSString*)wrapperName { LOGObjectFnStart(); LOGObjectFnStop(); return _wrapperName; }; //-------------------------------------------------------------------- -(NSString*)projectName { LOGObjectFnStart(); LOGObjectFnStop(); return _projectName; }; //-------------------------------------------------------------------- -(NSString*)bundlePath { return _bundlePath; }; //-------------------------------------------------------------------- -(NSString*)bundleURLPrefix { NSString* urlPrefix=nil; NSString* wrapperName=nil; if ([self isFramework]) // get framework prefix ? urlPrefix = [GSWApplication frameworksBaseURL]; else urlPrefix = [GSWApplication applicationBaseURL]; NSDebugMLLog(@"bundles",@"urlPrefix=%@",urlPrefix); NSAssert([urlPrefix length]>0,@"No urlPrefix"); wrapperName=[self wrapperName]; NSDebugMLLog(@"bundles",@"wrapperName=%@",wrapperName); NSAssert([wrapperName length]>0,@"No wrapperName"); if (urlPrefix && wrapperName) { urlPrefix=[urlPrefix stringByAppendingPathComponent:wrapperName]; NSDebugMLLog(@"bundles",@"urlPrefix=%@",urlPrefix); }; return urlPrefix; }; //-------------------------------------------------------------------- -(NSArray*)pathsForResourcesOfType:(NSString*)aType { //OK NSArray* paths=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aType=%@",aType); [self lock]; NS_DURING { paths=[self lockedPathsForResourcesOfType:aType]; NSDebugMLLog(@"bundles",@"paths=%@",paths); } NS_HANDLER { NSDebugMLLog(@"bundles",@"EXCEPTION:%@ (%@)", localException,[localException reason]); //TODO [self unlock]; [localException raise]; }; NS_ENDHANDLER; [self unlock]; return paths; }; //-------------------------------------------------------------------- -(NSArray*)lockedPathsForResourcesOfType:(NSString*)aType { LOGObjectFnNotImplemented(); //TODOFN return nil; }; //-------------------------------------------------------------------- -(NSString*)relativePathForResourceNamed:(NSString*)aName language:(NSString*)aLanguage { //OK NSString* path=nil; LOGObjectFnStart(); [self lock]; NSDebugMLLog(@"bundles",@"aName=%@ aLanguage=%@",aName,aLanguage); NS_DURING { path=[self lockedRelativePathForResourceNamed:aName language:aLanguage]; NSDebugMLLog(@"bundles",@"path=%@",path); } NS_HANDLER { NSDebugMLLog(@"bundles",@"EXCEPTION:%@ (%@)", localException,[localException reason]); //TODO [self unlock]; [localException raise]; }; NS_ENDHANDLER; [self unlock]; return path; }; //-------------------------------------------------------------------- -(NSString*)relativePathForResourceNamed:(NSString*)aName languages:(NSArray*)someLanguages { NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ someLanguages=%@",aName,someLanguages); [self lock]; NS_DURING { path=[self lockedRelativePathForResourceNamed:aName languages:someLanguages]; //NSDebugMLLog(@"bundles",@"path=%@",path); } NS_HANDLER { NSDebugMLLog(@"bundles",@"EXCEPTION:%@ (%@)", localException,[localException reason]); //TODO [self unlock]; [localException raise]; }; NS_ENDHANDLER; [self unlock]; LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)lockedRelativePathForResourceNamed:(NSString*)aName language:(NSString*)aLanguage { //OK NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ aLanguage=%@",aName,aLanguage); NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying Resources/WebServer",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"Resources/WebServer" language:aLanguage]; NSDebugMLLog(@"bundles",@"path=%@",path); if (!path) { NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying Resources",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"Resources" language:aLanguage]; NSDebugMLLog(@"bundles",@"path=%@",path); if (!path) { NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying .",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"." language:aLanguage]; NSDebugMLLog(@"bundles",@"path=%@",path); }; }; LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)lockedRelativePathForResourceNamed:(NSString*)aName languages:(NSArray*)someLanguages { //OK NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ someLanguages=%@",aName,someLanguages); NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying Resources/WebServer",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"Resources/WebServer" languages:someLanguages]; NSDebugMLLog(@"bundles",@"path=%@",path); if (!path) { NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying Resources",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"Resources" languages:someLanguages]; NSDebugMLLog(@"bundles",@"path=%@",path); if (!path) { NSDebugMLLog(@"bundles",@"bundlePath=%@ Trying .",_bundlePath); path=[self lockedRelativePathForResourceNamed:aName inDirectory:@"." languages:someLanguages]; NSDebugMLLog(@"bundles",@"path=%@",path); }; }; LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)lockedRelativePathForResourceNamed:(NSString*)aName inDirectory:(id)aDirectory languages:(NSArray*)someLanguages { //OK NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ aDirectory=%@ someLanguages=%@",aName,aDirectory,someLanguages); if (someLanguages) { int i=0; for(i=0;!path && i<[someLanguages count];i++) { path=[self lockedCachedRelativePathForResourceNamed:aName inDirectory:aDirectory language:[someLanguages objectAtIndex:i]]; NSDebugMLLog(@"bundles",@"path=%@",path); }; }; if (!path) path=[self lockedCachedRelativePathForResourceNamed:aName inDirectory:aDirectory language:nil]; NSDebugMLLog(@"bundles",@"path=%@",path); LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)lockedCachedRelativePathForResourceNamed:(NSString*)aName inDirectory:(NSString*)aDirectory language:(NSString*)aLanguage { //OK NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ aDirectory=%@ aLanguage=%@",aName,aDirectory,aLanguage); if (aName) { NSAutoreleasePool* arp = [NSAutoreleasePool new]; NS_DURING { NSString* emptyString=[NSString string]; NSString* bundlePath=[self bundlePath]; NSArray* keys; if ([aDirectory isEqualToString:@"."]) aDirectory=nil; if (aLanguage) keys=[NSArray arrayWithObjects:aName, bundlePath ? bundlePath : emptyString, aDirectory ? aDirectory : emptyString, aLanguage ? aLanguage : emptyString, nil]; else keys=[NSArray arrayWithObjects:aName, bundlePath ? bundlePath : emptyString, aDirectory ? aDirectory : emptyString, nil]; //NSDebugMLLog(@"bundles",@"_keys=%@",_keys); path=[_relativePathsCache objectForKeysArray:keys]; //NSDebugMLLog(@"bundles",@"_path=%@",_path); if (path==GSNotFoundMarker) path=nil; else if (!path) { //call again _relativePathForResourceNamed:inDirectory:language: NSString* completePathTest=nil; BOOL exists=NO; NSFileManager* fileManager=nil; NSString* pathTest=[NSString string]; if (aDirectory) pathTest=[pathTest stringByAppendingPathComponent:aDirectory]; //NSDebugMLLog(@"bundles",@"_pathTest=%@",_pathTest); if (aLanguage) pathTest=[pathTest stringByAppendingPathComponent: [aLanguage stringByAppendingString:GSLanguagePSuffix]]; //NSDebugMLLog(@"bundles",@"pathTest=%@",pathTest); pathTest=[pathTest stringByAppendingPathComponent:aName]; NSDebugMLLog(@"bundles",@"pathTest=%@",pathTest); completePathTest=[bundlePath stringByAppendingPathComponent:pathTest]; NSDebugMLLog(@"bundles",@"completePathTest=%@",completePathTest); fileManager=[NSFileManager defaultManager]; exists=[fileManager fileExistsAtPath:completePathTest]; NSDebugMLLog(@"bundles",@"exists=%s",(exists ? "YES" : "NO")); if (exists) { path=pathTest; [_relativePathsCache setObject:path forKeysArray:keys]; } else [_relativePathsCache setObject:GSNotFoundMarker forKeysArray:keys]; } } NS_HANDLER { localException=ExceptionByAddingUserInfoObjectFrameInfo0(localException, @"lockedCachedRelativePathForResourceNamed:inDirectory:language:"); LOGException(@"%@ (%@)",localException,[localException reason]); RETAIN(localException); DESTROY(arp); AUTORELEASE(localException); [localException raise]; } NS_ENDHANDLER; RETAIN(path); DESTROY(arp); AUTORELEASE(path); }; NSDebugMLLog(@"bundles",@"path=%@",path); LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)lockedRelativePathForResourceNamed:(NSString*)aName inDirectory:(NSString*)aDirectory language:(NSString*)aLanguage { //OK NSString* path=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ aDirectory=%@ aLanguage=%@", aName,aDirectory,aLanguage); path=[self lockedCachedRelativePathForResourceNamed:aName inDirectory:aDirectory language:aLanguage]; LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- /** Returns url for resource anmed aName for languages someLanguages **/ -(NSString*)urlForResourceNamed:(NSString*)aName languages:(NSArray*)someLanguages { NSString* url=nil; LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"aName=%@ someLanguages=%@",aName,someLanguages); [self lock]; NS_DURING { NSString* relativePath=[self lockedRelativePathForResourceNamed:aName languages:someLanguages]; NSDebugMLLog(@"bundles",@"relativePath=%@",relativePath); url=[self lockedCachedURLForRelativePath:relativePath]; NSDebugMLLog(@"bundles",@"url=%@",url); } NS_HANDLER { NSDebugMLLog(@"bundles",@"EXCEPTION:%@ (%@)", localException,[localException reason]); //TODO [self unlock]; [localException raise]; }; NS_ENDHANDLER; [self unlock]; LOGObjectFnStop(); return url; }; /** Returns the absolute path (cached or not) for relativePath. Put it in the cache if it was not cached **/ -(NSString*)lockedCachedAbsolutePathForRelativePath:(NSString*)relativePath { NSString* path=nil; LOGObjectFnStart(); if (relativePath) { // Test if already cached path = [_absolutePathsCache objectForKey:relativePath]; // If not, build it if (!path) { path=[[self bundlePath] stringByAppendingPathComponent:relativePath]; [_absolutePathsCache setObject:path forKey:relativePath]; } } LOGObjectFnStop(); return path; }; //-------------------------------------------------------------------- -(NSString*)absolutePathForRelativePath:(NSString*)relativePath { NSString* path=nil; LOGObjectFnStart(); [self lock]; NS_DURING { path=[self lockedCachedAbsolutePathForRelativePath:relativePath]; NSDebugMLLog(@"bundles",@"path=%@",path); } NS_HANDLER { NSDebugMLLog(@"bundles",@"EXCEPTION:%@ (%@)", localException,[localException reason]); //TODO [self unlock]; [localException raise]; }; NS_ENDHANDLER; [self unlock]; LOGObjectFnStop(); return path; } //-------------------------------------------------------------------- -(NSString*)absolutePathForResourceNamed:(NSString*)aName languages:(NSArray*)someLanguages { NSString* relativePath = [self relativePathForResourceNamed:aName languages:someLanguages]; return [self absolutePathForRelativePath:relativePath]; } //-------------------------------------------------------------------- /** Returns the url (cached or not) for relativePath. Put it in the cache if it was not cached **/ -(NSString*)lockedCachedURLForRelativePath:(NSString*)relativePath { NSString* url=nil; LOGObjectFnStart(); if (relativePath) { // Test if already cached url = [_urlsCache objectForKey:relativePath]; // If not, build it if (!url) { NSString* urlPrefix=[self bundleURLPrefix]; NSDebugMLLog(@"bundles",@"urlPrefix=%@",urlPrefix); url=[urlPrefix stringByAppendingPathComponent:relativePath]; NSDebugMLLog(@"bundles",@"url=%@",url); [_urlsCache setObject:url forKey:relativePath]; }; } LOGObjectFnStop(); return url; }; //-------------------------------------------------------------------- // lock -(void)lock { LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"selfLock=%p selfLockn=%d selfLock_thread_id=%p objc_thread_id()=%p", (void*)_selfLock, _selfLockn, (void*)_selfLock_thread_id, (void*)objc_thread_id()); if (_selfLockn>0) { if (_selfLock_thread_id!=objc_thread_id()) { NSDebugMLog0(@"PROBLEM: owner!=thread id"); }; }; TmpLockBeforeDate(_selfLock,[NSDate dateWithTimeIntervalSinceNow:GSLOCK_DELAY_S]); #ifndef NDEBUG _selfLockn++; _selfLock_thread_id=objc_thread_id(); #endif NSDebugMLLog(@"bundles",@"selfLock=%p selfLockn=%d selfLock_thread_id=%p objc_thread_id()=%p", _selfLock, _selfLockn, (void*)_selfLock_thread_id, (void*)objc_thread_id()); LOGObjectFnStop(); }; //-------------------------------------------------------------------- // unlock -(void)unlock { LOGObjectFnStart(); NSDebugMLLog(@"bundles",@"selfLock=%p selfLockn=%d selfLock_thread_id=%p objc_thread_id()=%p", (void*)_selfLock, _selfLockn, (void*)_selfLock_thread_id, (void*)objc_thread_id()); if (_selfLockn>0) { if (_selfLock_thread_id!=objc_thread_id()) { NSDebugMLog0(@"PROBLEM: owner!=thread id"); }; }; TmpUnlock(_selfLock); #ifndef NDEBUG _selfLockn--; if (_selfLockn==0) _selfLock_thread_id=NULL; #endif NSDebugMLLog(@"bundles",@"selfLock=%p selfLockn=%d selfLock_thread_id=%p objc_thread_id()=%p", (void*)_selfLock, _selfLockn, (void*)_selfLock_thread_id, (void*)objc_thread_id()); LOGObjectFnStop(); }; @end //==================================================================== @implementation GSWDeployedBundle (GSWDeployedBundleA) //-------------------------------------------------------------------- +(id)bundleWithPath:(NSString*)aPath { id bundle=nil; NSDebugMLLog(@"bundles",@"aPath=%@",aPath); bundle=[[[GSWDeployedBundle alloc]initWithPath:aPath]autorelease]; return bundle; }; @end