Coverage Report - net.wotonomy.foundation.NSBundle
 
Classes in this File Line Coverage Branch Coverage Complexity
NSBundle
0% 
0% 
1.788
 
 1  
 /*
 2  
  Wotonomy: OpenStep design patterns for pure Java applications.
 3  
  Copyright (C) 2005 Israfil Consulting Services Corporation
 4  
  Copyright (C) 2005 Christian Gruber
 5  
 
 6  
  This library is free software; you can redistribute it and/or
 7  
  modify it under the terms of the GNU Lesser General Public
 8  
  License as published by the Free Software Foundation; either
 9  
  version 2.1 of the License, or (at your option) any later version.
 10  
 
 11  
  This library is distributed in the hope that it will be useful,
 12  
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  
  Lesser General Public License for more details.
 15  
 
 16  
  You should have received a copy of the GNU Lesser General Public
 17  
  License along with this library; if not, see http://www.gnu.org
 18  
  */
 19  
 package net.wotonomy.foundation;
 20  
 
 21  
 import java.io.File;
 22  
 import java.io.IOException;
 23  
 import java.io.InputStream;
 24  
 import java.io.PrintWriter;
 25  
 import java.io.StringWriter;
 26  
 import java.net.MalformedURLException;
 27  
 import java.net.URL;
 28  
 import java.util.Locale;
 29  
 import java.util.Properties;
 30  
 import java.util.jar.JarEntry;
 31  
 import java.util.jar.JarFile;
 32  
 import java.util.jar.JarInputStream;
 33  
 
 34  
 import net.wotonomy.foundation.internal.NetworkClassLoader;
 35  
 
 36  
 /**
 37  
  * An implementation of NSBundle. Unlike the standard WebObjects NSBundle, this
 38  
  * implementation loads bundles dynamically. This means that all bundles do not
 39  
  * need to exist in the classpath at startup time. Practically, this means that
 40  
  * NSBundle has a custom classloader.
 41  
  * 
 42  
  * This behaviour is not supported in Apple's WebObjects, and should be used
 43  
  * only if compatibility is not desired. It is largely intended for internal use
 44  
  * within this framework, but is exposed through bundleForURL()
 45  
  * 
 46  
  * Another difference between Wotonomy's NSBundle and Apple's implementation is
 47  
  * the ability to initialize the application with a custom resource lookup
 48  
  * "path".
 49  
  * 
 50  
  * @author cgruber@israfil.net
 51  
  * @author $Author: cgruber $
 52  
  * @version $Revision: 892 $
 53  
  * 
 54  
  */
 55  0
 public class NSBundle {
 56  
 
 57  
         /* Class variables */
 58  
 
 59  
         public static final String BundleDidLoadNotification = "NSBundleDidLoadNotification";
 60  
 
 61  
         public static final String LoadedClassesNotification = "NSLoadedClassesNotification";
 62  
 
 63  0
         private static final NSMutableArray _allBundles = new NSMutableArray();
 64  
 
 65  0
         private static final NSMutableArray _allFrameworks = new NSMutableArray();
 66  
 
 67  0
         private static NSMutableDictionary _languageCodes = new NSMutableDictionary();
 68  
 
 69  0
         private static NSBundle _mainBundle = null;
 70  
         
 71  0
         protected static NetworkClassLoader _classLoader = new NetworkClassLoader(ClassLoader.getSystemClassLoader());
 72  
 
 73  
         /* Instance variables */
 74  
 
 75  
         protected String name;
 76  
 
 77  0
         protected NSMutableDictionary info = null;
 78  
 
 79  
         protected String path;
 80  
 
 81  0
         protected NSMutableArray classNames = new NSMutableArray();
 82  
 
 83  0
         protected NSMutableArray packages = new NSMutableArray();
 84  
 
 85  
         protected Properties properties;
 86  
 
 87  0
         protected boolean isFramework = false;
 88  
 
 89  0
         protected boolean loaded = false;
 90  
 
 91  
         protected Class principalClass;
 92  
 
 93  
         /* Constructors */
 94  
 
 95  
         /**
 96  
          * The default constructor, which is only public to support other framework
 97  
          * functionality, and to be API compatible with Apple's WebObjects.
 98  
          * Generally, framework users should use bundleForXXXX() methods.
 99  
          */
 100  0
         public NSBundle() {
 101  0
         }
 102  
 
 103  
         /* Methods */
 104  
 
 105  
         /**
 106  
          * @deprecated use mainBundle() to access the application bundle and
 107  
          *             frameworkBundles() to access any frameworks.
 108  
          */
 109  
         public static synchronized NSArray allBundles() {
 110  0
                 return _allBundles.immutableClone();
 111  
         }
 112  
 
 113  
         /**
 114  
          * @deprecated use frameworkBundles() to access any frameworks.
 115  
          */
 116  
         public static NSArray allFrameworks() {
 117  0
                 return frameworkBundles();
 118  
         }
 119  
 
 120  
         /**
 121  
          * Returns the bundle that contains the provided class, if any. Otherwise,
 122  
          * it returns null. Because NSBundles have a specialized class-loader, if
 123  
          * any two bundles contain duiplicates of the same class, the second will
 124  
          * fail to load. TODO: Determine if class-load scoping of duplicate classes
 125  
          * is appropriate.
 126  
          * 
 127  
          * @param class1
 128  
          * @return NSBundle
 129  
          */
 130  
         public static synchronized NSBundle bundleForClass(Class class1) {
 131  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 132  
                 // TODO: Implement.
 133  
         }
 134  
 
 135  
         /**
 136  
          * @deprecated Apple's WebObjects says you should not load from arbitrary
 137  
          *             path.
 138  
          * @param path
 139  
          * @return
 140  
          */
 141  
         public static synchronized NSBundle bundleWithPath(String path) {
 142  
                 try {
 143  0
                         return bundleWithURL(new File(path).toURI().toURL());
 144  0
                 } catch (MalformedURLException e) {
 145  0
                         NSLog.err.appendln("Bundle path is invalid: " + path);
 146  0
                         return null;
 147  
                 }
 148  
         }
 149  
 
 150  
         /**
 151  
          * <strong>Note:</strong>This method is only in Wotonomy.
 152  
          * 
 153  
          * This method returns a bundle at a given URL, registering that bundle as
 154  
          * well. If the bundle has already been loaded/registered, it is simply
 155  
          * returned from the cache.
 156  
          * 
 157  
          * @param url
 158  
          * @return
 159  
          */
 160  
         public static synchronized NSBundle bundleWithURL(URL url) {
 161  0
                 NSBundle result = null;
 162  0
                 String sep = System.getProperty("file.separator");
 163  0
                 String protocol = url.getProtocol();
 164  0
                 if (protocol.equals("file")) {
 165  0
                         File f = new File(url.getPath());
 166  0
                         if (!f.exists()) {
 167  0
                                 NSLog.err.appendln("Bundle not found: " + url);
 168  0
                                 return null;
 169  
                         }
 170  0
                         StringBuffer filename = new StringBuffer(f.getName());
 171  0
                         int extensionIndex = filename.lastIndexOf(".");
 172  0
                         if (extensionIndex == -1) {
 173  0
                                 NSLog.err
 174  0
                                                 .appendln("Named URL does not point to a bundle with an extension: "
 175  0
                                                                 + url);
 176  0
                                 return null;
 177  
                         }
 178  0
                         String basename = filename.substring(0, extensionIndex);
 179  0
                         String extension = filename.substring(extensionIndex + 1, filename
 180  0
                                         .length());
 181  0
                         System.out.println("basename: " + basename);
 182  0
                         System.out.println("extension: " + extension);
 183  0
                         result = new NSBundle();
 184  0
                         result.name = basename;
 185  0
                         result.isFramework = extension.equals("framework");
 186  0
                         if (f.isDirectory()) {
 187  
                                 try {
 188  0
                                         File javadir = new File(f.getCanonicalPath() + sep + "Contents"
 189  0
                                                         + sep + "Resources" + sep + "Java");
 190  0
                                         System.out.println(javadir);
 191  0
                                         System.out.println(javadir.exists());
 192  0
                                         File[] jars = javadir.listFiles();
 193  
                                         
 194  0
                                 } catch (IOException e) { }
 195  0
                         } else {
 196  0
                                 throw new RuntimeException(
 197  0
                                                 "Compressed bundle files not currently supported.");
 198  
                         }
 199  0
                         throw new RuntimeException("Method not finished.");
 200  
                 } else {
 201  
                         try {
 202  0
                                 JarInputStream j = new JarInputStream(url.openStream());
 203  0
                                 JarEntry entry1 = j.getNextJarEntry();
 204  
 
 205  
                                 JarFile f;
 206  0
                                 throw new RuntimeException("Method not finished.");
 207  0
                         } catch (IOException e) {
 208  0
                                 NSLog.err
 209  0
                                                 .appendln("IOException loading framework jar from URL "
 210  0
                                                                 + url + " - message: "
 211  0
                                                                 + e.getLocalizedMessage());
 212  0
                                 StringWriter stacktrace = new StringWriter();
 213  0
                                 e.printStackTrace(new PrintWriter(stacktrace));
 214  0
                                 NSLog.err.appendln(stacktrace);
 215  0
                                 return null;
 216  
                         }
 217  
                 }
 218  
         }
 219  
 
 220  
         /**
 221  
          * This method returns a bundle, either from cache, or if it doesn't exist
 222  
          * yet, it attempts to look it up - first from the classpath, then from the
 223  
          * resource path. TODO: Determine if the lookup order is the desired
 224  
          * semantic.
 225  
          * 
 226  
          * @param name
 227  
          * @return
 228  
          */
 229  
         public static synchronized NSBundle bundleForName(String name) {
 230  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 231  
                 // TODO: Implement.
 232  
         }
 233  
 
 234  
         public static synchronized NSArray frameworkBundles() {
 235  0
                 return _allFrameworks.immutableClone();
 236  
         }
 237  
 
 238  
         /**
 239  
          * Used to set the "Main" application bundle, in which primary resources are
 240  
          * loaded for GUI applications. This is mostly only relevant for
 241  
          * XXApplication objects. This should therefore not be generally used by
 242  
          * consumers of the framework.
 243  
          * 
 244  
          * @param aBundle
 245  
          */
 246  
         public static void setMainBundle(NSBundle aBundle) {
 247  0
                 _mainBundle = aBundle;
 248  0
         }
 249  
 
 250  
         public static NSBundle mainBundle() {
 251  0
                 return _mainBundle;
 252  
         }
 253  
 
 254  
         /**
 255  
          * Get the default prefix for locale. TODO: This really needs to be made
 256  
          * dynamic somehow.
 257  
          * 
 258  
          * @return
 259  
          */
 260  
         protected static String defaultLocalePrefix() {
 261  0
                 String language = (String) _languageCodes.objectForKey(Locale
 262  0
                                 .getDefault().getLanguage());
 263  0
                 return language + ".lproj";
 264  
         }
 265  
 
 266  
         protected static synchronized NSBundle findOrCreateBundleWithPath(String s) {
 267  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 268  
                 // TODO: Implement.
 269  
         }
 270  
 
 271  
         /**
 272  
          * TODO: figure out what this does.
 273  
          * 
 274  
          * @return
 275  
          */
 276  
         public NSArray bundleClassPackageNames() {
 277  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 278  
                 // TODO: Implement.
 279  
         }
 280  
 
 281  
         public String bundlePath() {
 282  0
                 return this.path;
 283  
         }
 284  
 
 285  
         /**
 286  
          * Returns a byte array for the given resource path. TODO: Lookup semantics
 287  
          * in WebObjects javadocs.
 288  
          * 
 289  
          * @param path
 290  
          * @return
 291  
          */
 292  
         public byte[] bytesForResourcePath(String path) {
 293  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 294  
                 // TODO: Implement.
 295  
         }
 296  
 
 297  
         public NSArray bundleClassNames() {
 298  0
                 return classNames.immutableClone();
 299  
         }
 300  
 
 301  
         public NSDictionary infoDictionary() {
 302  0
                 return info;
 303  
         }
 304  
 
 305  
         /**
 306  
          * Returns an input stream for a given resource path. TODO: Lookup semantics
 307  
          * in WebObjects javadocs.
 308  
          * 
 309  
          * @param path
 310  
          * @return
 311  
          */
 312  
         public InputStream inputStreamForResourcePath(String path) {
 313  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 314  
                 // TODO: Implement.
 315  
         }
 316  
 
 317  
         public boolean isFramework() {
 318  0
                 return isFramework;
 319  
         }
 320  
 
 321  
         public boolean load() {
 322  0
                 return loaded;
 323  
         }
 324  
 
 325  
         public String name() {
 326  0
                 return name;
 327  
         }
 328  
 
 329  
         /**
 330  
          * @deprecated Don't use this method, use
 331  
          *             resourcePathForLocalizedResourceNamed() instead.
 332  
          */
 333  
 
 334  
         public String pathForResource(String aName, String anExtension) {
 335  0
                 return this.resourcePathForLocalizedResourceNamed(aName, null);
 336  
         }
 337  
 
 338  
         /**
 339  
          * @deprecated Don't use this method, use
 340  
          *             resourcePathForLocalizedResourceNamed() instead.
 341  
          */
 342  
         public String pathForResource(String aName, String anExtension,
 343  
                         String subDir) {
 344  0
                 return this.resourcePathForLocalizedResourceNamed(aName, subDir);
 345  
         }
 346  
 
 347  
         /**
 348  
          * @deprecated Don't use this method, use resourcePathsForResources()
 349  
          *             instead.
 350  
          */
 351  
         public NSArray pathsForResources(String aName, String anExtension) {
 352  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 353  
                 // TODO: Implement.
 354  
         }
 355  
 
 356  
         public Class principalClass() {
 357  0
                 return principalClass;
 358  
         }
 359  
 
 360  
         public Properties properties() {
 361  0
                 return properties;
 362  
         }
 363  
 
 364  
         /**
 365  
          * @deprecated Resources are now accessed using the bytesForResourcePath()
 366  
          *             and inputStreamForResourcePath() methods.
 367  
          */
 368  
         public String resourcePath() {
 369  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 370  
                 // TODO: Implement.
 371  
         }
 372  
 
 373  
         public String resourcePathForLocalizedResourceNamed(String aName,
 374  
                         String subDir) {
 375  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 376  
                 // TODO: Implement.
 377  
         }
 378  
 
 379  
         public NSArray resourcePathsForDirectories(String extension,
 380  
                         String subdirPath) {
 381  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 382  
         }
 383  
 
 384  
         public NSArray resourcePathsForLocalizedResources(String extension,
 385  
                         String subdirPath) {
 386  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 387  
         }
 388  
 
 389  
         public NSArray resourcePathsForResources(String extension, String subdirPath) {
 390  0
                 throw new UnsupportedOperationException("Method not yet implemented.");
 391  
 
 392  
         }
 393  
 
 394  
         public String toString() {
 395  0
                 int i = 0;
 396  0
                 if (classNames != null)
 397  0
                         i = classNames.count();
 398  0
                 return "<" + getClass().getName() + " name:'" + name + "' bundlePath:'"
 399  0
                                 + path + "' packages:'" + packages + "' " + i + " classes >";
 400  
         }
 401  
 
 402  
         /* Static initialization code */
 403  
 
 404  
         private static void _initLanguages() {
 405  0
                 _languageCodes.setObjectForKey("de", "German");
 406  0
                 _languageCodes.setObjectForKey("en", "English");
 407  0
                 _languageCodes.setObjectForKey("eo", "Esperanto");
 408  0
                 _languageCodes.setObjectForKey("es", "Spanish");
 409  0
                 _languageCodes.setObjectForKey("fr", "French");
 410  0
                 _languageCodes.setObjectForKey("ja", "Japanese");
 411  0
         }
 412  
 
 413  
         static {
 414  0
                 NSBundle._initLanguages();
 415  
                                                                                
 416  0
         }
 417  
 
 418  
 }