package er.extensions.appserver; import java.io.File; import com.webobjects._ideservices._WOProject; import com.webobjects.appserver.WOApplication; import com.webobjects.appserver._private.WODeployedBundle; import com.webobjects.appserver._private.WOProjectBundle; import com.webobjects.foundation.NSArray; import com.webobjects.foundation.NSBundle; import com.webobjects.foundation.NSLog; import com.webobjects.foundation.NSMutableDictionary; import com.webobjects.foundation.NSPathUtilities; import com.webobjects.foundation.NSProperties; import com.webobjects.foundation.NSPropertyListSerialization; import com.webobjects.foundation._NSStringUtilities; import er.extensions.foundation.ERXProperties; /** * Replacement of the WODeployedBundle which adds: * <ul> * <li> Determines whether the Bundle is embedded within the Main Bundle * <li> If so, mark the state and the name of embedding main bundle * <li> Resource URLs for embedded Frameworks are automatically adapted to refer to the embedded Framework, * rather than to the Frameworks base URL * </ul> * * There are two styles of webserver resource packages, with ANT (old style) builds, embedded frameworks are embedded this way * MyApp.woa/Frameworks/EmbeddedFramework.framework/... * * while with Maven builds (and some newer ANT builds), frameworks are embedded in the WebServerResources package the same way as in the Application package: * MyApp.woa/Contents/Frameworks/EmbeddedFramework.framework/... * * ERXDeployedBundle introduces automatic url generation for embedded frameworks. The new property WOEmbeddedFrameworksPath * helps adjusting to the deployment schemes on embedding: * * in the cited cases above, the property should be * WOEmbeddedFrameworksPath=Frameworks (default) * or * WOEmbeddedFrameworksPath=Contents/Frameworks * * However if WOFrameworksBaseURL is custom defined, you get the behaviour as before, there is nointervention in url generation. * In the case of a mixed deployment (some frameworks globally installed, some embedded), the property WOOverrideEmbeddedFrameworksPath * lets activate automatic url generation for embedded frameworks, while globally installad frameworks do get their path from WOFrameworksBaseURL. * * @author mstoll */ public class ERXDeployedBundle extends WODeployedBundle { private final NSMutableDictionary _myURLs; private static final NSMutableDictionary TheBundles = new NSMutableDictionary(NSBundle.frameworkBundles().count()); private static final boolean _allowRapidTurnaround = NSPropertyListSerialization.booleanForString(NSProperties.getProperty("WOAllowRapidTurnaround")); private boolean isEmbeddedFramework = false; private String embeddingWrapperName = null; private static final String defaultFrameworkBaseURL = "/WebObjects/Frameworks"; /** * Initializer, determines by comparing bundle paths whether bundle is embedded. * * @param nsb the given NSBundle */ public ERXDeployedBundle(NSBundle nsb) { super(nsb); _myURLs = new NSMutableDictionary(); embeddingWrapperName = NSBundle.mainBundle().name() + ".woa"; if(bundlePath().startsWith(NSBundle.mainBundle().bundlePath())) { isEmbeddedFramework = true; } } @Override public String urlForResource(String resourceName, NSArray languagesList) { String aRelativePath = relativePathForResource(resourceName, languagesList); String aURL = null; synchronized(_myURLs) { aURL = _cachedURL(aRelativePath); } return aURL; } /** * Get cached URL for relative path within current bundle. If URL not yet in cache, * create one, taking into account whether the current Bundle is embedded within main Bundle * * @param aRelativePath a relative path to a resource within current Bundle * @return The URL path to the resource */ private String _cachedURL(String aRelativePath) { String aURL = null; if(aRelativePath != null) { aURL = (String)_myURLs.objectForKey(aRelativePath); if(aURL == null) { String aBaseURL = null; if(isFramework()) { // WOFrameworksBaseURL is never null but rather by default "/WebObjects/Frameworks" boolean enableAutomaticEmbeddedFrameworkPath = defaultFrameworkBaseURL.equals(WOApplication.application().frameworksBaseURL()) || ERXProperties.booleanForKeyWithDefault("WOOverrideEmbeddedFrameworksPath", false); if(isEmbeddedFramework && enableAutomaticEmbeddedFrameworkPath) { String embeddedFrameworkPath = ERXProperties.stringForKeyWithDefault("WOEmbeddedFrameworksPath", "Frameworks"); aBaseURL = WOApplication.application().applicationBaseURL() + "/" + embeddingWrapperName + "/" + embeddedFrameworkPath; } else aBaseURL = WOApplication.application().frameworksBaseURL(); } else aBaseURL = WOApplication.application().applicationBaseURL(); String aWrapperName = wrapperName(); if(aBaseURL != null && aWrapperName != null) { aURL = _NSStringUtilities.concat(aBaseURL, File.separator, aWrapperName, File.separator, aRelativePath); aURL = NSPathUtilities._standardizedPath(aURL); _myURLs.setObjectForKey(aURL, aRelativePath); } } } return aURL; } public static synchronized WODeployedBundle bundleWithNSBundle(NSBundle nsBundle) { Object aBundle = TheBundles.objectForKey(nsBundle); if(aBundle == null) { WODeployedBundle deployedBundle = new ERXDeployedBundle(nsBundle); if(_allowRapidTurnaround) { String bundlePath = nsBundle.bundlePathURL().getPath(); try { if(_WOProject.ideProjectAtPath(bundlePath) != null) aBundle = new WOProjectBundle(bundlePath, deployedBundle); else aBundle = deployedBundle; } catch(Exception e) { if(NSLog.debugLoggingAllowedForLevel(1)) { NSLog.debug.appendln((new StringBuilder()).append("<WOProjectBundle>: Warning - Unable to find project at path ").append(nsBundle.bundlePathURL().getPath()).append(" - Ignoring project.").toString()); NSLog.debug.appendln(e); } aBundle = deployedBundle; } } else { aBundle = deployedBundle; } TheBundles.setObjectForKey(aBundle, nsBundle); } return (WODeployedBundle)aBundle; } public static synchronized WODeployedBundle deployedBundleForFrameworkNamed(String aFrameworkName) { WODeployedBundle aBundle = null; NSArray bundleArray = TheBundles.allValues(); int baCount = TheBundles.count(); NSBundle nsBundle = NSBundle.bundleForName(aFrameworkName); if(nsBundle == null) nsBundle = NSBundle.bundleWithPath(aFrameworkName); if(nsBundle != null) { int i = 0; do { if(i >= baCount) break; WODeployedBundle aFrameworkBundle = (WODeployedBundle)bundleArray.objectAtIndex(i); if(nsBundle.equals(aFrameworkBundle.nsBundle())) { aBundle = aFrameworkBundle; WODeployedBundle dBundle = aBundle.projectBundle(); if(dBundle != null) aBundle = dBundle; break; } i++; } while(true); } return aBundle; } public boolean isEmbedded() { return isEmbeddedFramework; } }