diff options
Diffstat (limited to 'projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java')
| -rw-r--r-- | projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java new file mode 100644 index 0000000..b735404 --- /dev/null +++ b/projects/net.wotonomy.foundation/src/main/java/net/wotonomy/foundation/NSBundle.java @@ -0,0 +1,418 @@ +/* + Wotonomy: OpenStep design patterns for pure Java applications. + Copyright (C) 2005 Israfil Consulting Services Corporation + Copyright (C) 2005 Christian Gruber + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see http://www.gnu.org + */ +package net.wotonomy.foundation; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Locale; +import java.util.Properties; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarInputStream; + +import net.wotonomy.foundation.internal.NetworkClassLoader; + +/** + * An implementation of NSBundle. Unlike the standard WebObjects NSBundle, this + * implementation loads bundles dynamically. This means that all bundles do not + * need to exist in the classpath at startup time. Practically, this means that + * NSBundle has a custom classloader. + * + * This behaviour is not supported in Apple's WebObjects, and should be used + * only if compatibility is not desired. It is largely intended for internal use + * within this framework, but is exposed through bundleForURL() + * + * Another difference between Wotonomy's NSBundle and Apple's implementation is + * the ability to initialize the application with a custom resource lookup + * "path". + * + * @author cgruber@israfil.net + * @author $Author: cgruber $ + * @version $Revision: 892 $ + * + */ +public class NSBundle { + + /* Class variables */ + + public static final String BundleDidLoadNotification = "NSBundleDidLoadNotification"; + + public static final String LoadedClassesNotification = "NSLoadedClassesNotification"; + + private static final NSMutableArray _allBundles = new NSMutableArray(); + + private static final NSMutableArray _allFrameworks = new NSMutableArray(); + + private static NSMutableDictionary _languageCodes = new NSMutableDictionary(); + + private static NSBundle _mainBundle = null; + + protected static NetworkClassLoader _classLoader = new NetworkClassLoader(ClassLoader.getSystemClassLoader()); + + /* Instance variables */ + + protected String name; + + protected NSMutableDictionary info = null; + + protected String path; + + protected NSMutableArray classNames = new NSMutableArray(); + + protected NSMutableArray packages = new NSMutableArray(); + + protected Properties properties; + + protected boolean isFramework = false; + + protected boolean loaded = false; + + protected Class principalClass; + + /* Constructors */ + + /** + * The default constructor, which is only public to support other framework + * functionality, and to be API compatible with Apple's WebObjects. + * Generally, framework users should use bundleForXXXX() methods. + */ + public NSBundle() { + } + + /* Methods */ + + /** + * @deprecated use mainBundle() to access the application bundle and + * frameworkBundles() to access any frameworks. + */ + public static synchronized NSArray allBundles() { + return _allBundles.immutableClone(); + } + + /** + * @deprecated use frameworkBundles() to access any frameworks. + */ + public static NSArray allFrameworks() { + return frameworkBundles(); + } + + /** + * Returns the bundle that contains the provided class, if any. Otherwise, + * it returns null. Because NSBundles have a specialized class-loader, if + * any two bundles contain duiplicates of the same class, the second will + * fail to load. TODO: Determine if class-load scoping of duplicate classes + * is appropriate. + * + * @param class1 + * @return NSBundle + */ + public static synchronized NSBundle bundleForClass(Class class1) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + /** + * @deprecated Apple's WebObjects says you should not load from arbitrary + * path. + * @param path + * @return + */ + public static synchronized NSBundle bundleWithPath(String path) { + try { + return bundleWithURL(new File(path).toURI().toURL()); + } catch (MalformedURLException e) { + NSLog.err.appendln("Bundle path is invalid: " + path); + return null; + } + } + + /** + * <strong>Note:</strong>This method is only in Wotonomy. + * + * This method returns a bundle at a given URL, registering that bundle as + * well. If the bundle has already been loaded/registered, it is simply + * returned from the cache. + * + * @param url + * @return + */ + public static synchronized NSBundle bundleWithURL(URL url) { + NSBundle result = null; + String sep = System.getProperty("file.separator"); + String protocol = url.getProtocol(); + if (protocol.equals("file")) { + File f = new File(url.getPath()); + if (!f.exists()) { + NSLog.err.appendln("Bundle not found: " + url); + return null; + } + StringBuffer filename = new StringBuffer(f.getName()); + int extensionIndex = filename.lastIndexOf("."); + if (extensionIndex == -1) { + NSLog.err + .appendln("Named URL does not point to a bundle with an extension: " + + url); + return null; + } + String basename = filename.substring(0, extensionIndex); + String extension = filename.substring(extensionIndex + 1, filename + .length()); + System.out.println("basename: " + basename); + System.out.println("extension: " + extension); + result = new NSBundle(); + result.name = basename; + result.isFramework = extension.equals("framework"); + if (f.isDirectory()) { + try { + File javadir = new File(f.getCanonicalPath() + sep + "Contents" + + sep + "Resources" + sep + "Java"); + System.out.println(javadir); + System.out.println(javadir.exists()); + File[] jars = javadir.listFiles(); + + } catch (IOException e) { } + } else { + throw new RuntimeException( + "Compressed bundle files not currently supported."); + } + throw new RuntimeException("Method not finished."); + } else { + try { + JarInputStream j = new JarInputStream(url.openStream()); + JarEntry entry1 = j.getNextJarEntry(); + + JarFile f; + throw new RuntimeException("Method not finished."); + } catch (IOException e) { + NSLog.err + .appendln("IOException loading framework jar from URL " + + url + " - message: " + + e.getLocalizedMessage()); + StringWriter stacktrace = new StringWriter(); + e.printStackTrace(new PrintWriter(stacktrace)); + NSLog.err.appendln(stacktrace); + return null; + } + } + } + + /** + * This method returns a bundle, either from cache, or if it doesn't exist + * yet, it attempts to look it up - first from the classpath, then from the + * resource path. TODO: Determine if the lookup order is the desired + * semantic. + * + * @param name + * @return + */ + public static synchronized NSBundle bundleForName(String name) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public static synchronized NSArray frameworkBundles() { + return _allFrameworks.immutableClone(); + } + + /** + * Used to set the "Main" application bundle, in which primary resources are + * loaded for GUI applications. This is mostly only relevant for + * XXApplication objects. This should therefore not be generally used by + * consumers of the framework. + * + * @param aBundle + */ + public static void setMainBundle(NSBundle aBundle) { + _mainBundle = aBundle; + } + + public static NSBundle mainBundle() { + return _mainBundle; + } + + /** + * Get the default prefix for locale. TODO: This really needs to be made + * dynamic somehow. + * + * @return + */ + protected static String defaultLocalePrefix() { + String language = (String) _languageCodes.objectForKey(Locale + .getDefault().getLanguage()); + return language + ".lproj"; + } + + protected static synchronized NSBundle findOrCreateBundleWithPath(String s) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + /** + * TODO: figure out what this does. + * + * @return + */ + public NSArray bundleClassPackageNames() { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public String bundlePath() { + return this.path; + } + + /** + * Returns a byte array for the given resource path. TODO: Lookup semantics + * in WebObjects javadocs. + * + * @param path + * @return + */ + public byte[] bytesForResourcePath(String path) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public NSArray bundleClassNames() { + return classNames.immutableClone(); + } + + public NSDictionary infoDictionary() { + return info; + } + + /** + * Returns an input stream for a given resource path. TODO: Lookup semantics + * in WebObjects javadocs. + * + * @param path + * @return + */ + public InputStream inputStreamForResourcePath(String path) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public boolean isFramework() { + return isFramework; + } + + public boolean load() { + return loaded; + } + + public String name() { + return name; + } + + /** + * @deprecated Don't use this method, use + * resourcePathForLocalizedResourceNamed() instead. + */ + + public String pathForResource(String aName, String anExtension) { + return this.resourcePathForLocalizedResourceNamed(aName, null); + } + + /** + * @deprecated Don't use this method, use + * resourcePathForLocalizedResourceNamed() instead. + */ + public String pathForResource(String aName, String anExtension, + String subDir) { + return this.resourcePathForLocalizedResourceNamed(aName, subDir); + } + + /** + * @deprecated Don't use this method, use resourcePathsForResources() + * instead. + */ + public NSArray pathsForResources(String aName, String anExtension) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public Class principalClass() { + return principalClass; + } + + public Properties properties() { + return properties; + } + + /** + * @deprecated Resources are now accessed using the bytesForResourcePath() + * and inputStreamForResourcePath() methods. + */ + public String resourcePath() { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public String resourcePathForLocalizedResourceNamed(String aName, + String subDir) { + throw new UnsupportedOperationException("Method not yet implemented."); + // TODO: Implement. + } + + public NSArray resourcePathsForDirectories(String extension, + String subdirPath) { + throw new UnsupportedOperationException("Method not yet implemented."); + } + + public NSArray resourcePathsForLocalizedResources(String extension, + String subdirPath) { + throw new UnsupportedOperationException("Method not yet implemented."); + } + + public NSArray resourcePathsForResources(String extension, String subdirPath) { + throw new UnsupportedOperationException("Method not yet implemented."); + + } + + public String toString() { + int i = 0; + if (classNames != null) + i = classNames.count(); + return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'" + + path + "' packages:'" + packages + "' " + i + " classes >"; + } + + /* Static initialization code */ + + private static void _initLanguages() { + _languageCodes.setObjectForKey("de", "German"); + _languageCodes.setObjectForKey("en", "English"); + _languageCodes.setObjectForKey("eo", "Esperanto"); + _languageCodes.setObjectForKey("es", "Spanish"); + _languageCodes.setObjectForKey("fr", "French"); + _languageCodes.setObjectForKey("ja", "Japanese"); + } + + static { + NSBundle._initLanguages(); + + } + +} |
