Coverage Report - net.wotonomy.foundation.internal.NetworkClassLoader
 
Classes in this File Line Coverage Branch Coverage Complexity
NetworkClassLoader
0% 
0% 
3.5
 
 1  
 /*
 2  
  * ====================================================================
 3  
  *
 4  
  * The Apache Software License, Version 1.1
 5  
  *
 6  
  * Copyright (c) 1999 The Apache Software Foundation.  All rights 
 7  
  * reserved.
 8  
  *
 9  
  * Redistribution and use in source and binary forms, with or without
 10  
  * modification, are permitted provided that the following conditions
 11  
  * are met:
 12  
  *
 13  
  * 1. Redistributions of source code must retain the above copyright
 14  
  *    notice, this list of conditions and the following disclaimer. 
 15  
  *
 16  
  * 2. Redistributions in binary form must reproduce the above copyright
 17  
  *    notice, this list of conditions and the following disclaimer in
 18  
  *    the documentation and/or other materials provided with the
 19  
  *    distribution.
 20  
  *
 21  
  * 3. The end-user documentation included with the redistribution, if
 22  
  *    any, must include the following acknowlegement:  
 23  
  *       "This product includes software developed by the 
 24  
  *        Apache Software Foundation (http://www.apache.org/)."
 25  
  *    Alternately, this acknowlegement may appear in the software itself,
 26  
  *    if and wherever such third-party acknowlegements normally appear.
 27  
  *
 28  
  * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
 29  
  *    Foundation" must not be used to endorse or promote products derived
 30  
  *    from this software without prior written permission. For written 
 31  
  *    permission, please contact apache@apache.org.
 32  
  *
 33  
  * 5. Products derived from this software may not be called "Apache"
 34  
  *    nor may "Apache" appear in their names without prior written
 35  
  *    permission of the Apache Group.
 36  
  *
 37  
  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 38  
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 39  
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 40  
  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 41  
  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 42  
  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 43  
  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 44  
  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 45  
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 46  
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 47  
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 48  
  * SUCH DAMAGE.
 49  
  * ====================================================================
 50  
  */ 
 51  
 
 52  
 package net.wotonomy.foundation.internal;
 53  
 
 54  
 import java.io.ByteArrayInputStream;
 55  
 import java.io.IOException;
 56  
 import java.io.InputStream;
 57  
 import java.net.URL;
 58  
 import java.util.Enumeration;
 59  
 import java.util.Hashtable;
 60  
 
 61  
 /**
 62  
  * The correct name for this class should be URLClassLoader.
 63  
  * But there is already a class by that name in JDK1.2.
 64  
  *
 65  
  * I have had quite a few problems with URLClassLoader in
 66  
  * past, so I ended up writing this ClassLoader. I found that
 67  
  * the Java 2's URLClassLoader, does not close the Jar file once
 68  
  * opened. It is a pretty good optimization step, but if you
 69  
  * modify the class in the jar file, it does not pick it up. Some
 70  
  * operating systems may not let you modify the jar file while it is
 71  
  * still open. IMHO, it does make sense to close the jar file
 72  
  * after you are done reading the class data. But this approach may not
 73  
  * get you the performance of the URLClassLoader, but it works in all
 74  
  * cases and also runs on JDK1.1. I have enhanced this class loader
 75  
  * to read all the zip/jar entries once & cache the data, so that
 76  
  * there is no overhead of opening/closing jar file to pick up
 77  
  * each entry.
 78  
  *
 79  
  *
 80  
  * @author Harish Prabandham
 81  
  */
 82  
 public class NetworkClassLoader extends ClassLoader {
 83  0
     private ClassLoader parent = null; // parent classloader
 84  0
     private Hashtable classCache = new Hashtable();
 85  0
     private Hashtable urlset = new Hashtable();
 86  
 
 87  
     /**
 88  
      * Creates a new instance of the class loader.
 89  
      * @param delegate/parent class loader.
 90  
      */
 91  0
     public NetworkClassLoader(ClassLoader parent) {
 92  0
         setParent(parent);
 93  0
     }
 94  
 
 95  
     /**
 96  
      * Sets the parent/delegate class loader.
 97  
      * @param delegate/parent class loader.
 98  
      */
 99  
     protected final void setParent(ClassLoader parent) {
 100  0
         this.parent = parent;
 101  0
     }
 102  
 
 103  
     /**
 104  
      * Adds the given URL to this class loader. If the URL
 105  
      * ends with "/", then it is assumed to be a directory
 106  
      * otherwise, it is assumed to be a zip/jar file. If the
 107  
      * same URL is added again, the URL is re-opened and this
 108  
      * zip/jar file is used for serving any future class requests.
 109  
      * @param URL where to look for the classes.
 110  
      */
 111  
     public synchronized void addURL(URL url) {
 112  
         // System.out.println("Adding url: " + url);
 113  0
         if(!urlset.containsKey(url)) {
 114  
             try {
 115  0
                 urlset.put(url, new URLResourceReader(url));
 116  0
             }catch(IOException ioe){
 117  
                 // Probably a bad url...
 118  0
             }
 119  0
         } else {
 120  
             // remove the old one & add a new one...
 121  
             try{
 122  0
                 URLResourceReader newu = new URLResourceReader(url);
 123  0
                 URLResourceReader oldu = (URLResourceReader) urlset.get(url);
 124  0
                 oldu.close();
 125  0
                 urlset.remove(url);
 126  0
                 urlset.put(url, newu);
 127  0
             } catch (IOException ioe) {
 128  0
             }
 129  
         }
 130  0
     }
 131  
 
 132  
     /**
 133  
      * @return An enumeration of  URLs where this class loader
 134  
      * looks for classes.
 135  
      */
 136  
     public Enumeration getURLs() {
 137  0
         return urlset.keys();
 138  
     }
 139  
 
 140  
     /**
 141  
      * Call this to bypass the implementation of loadClass.
 142  
      */
 143  
     public Class findClass(String name) {
 144  0
         byte[] b = loadClassData(name);
 145  0
         if ( b == null ) return null;
 146  0
         return defineClass(name, b, 0, b.length);
 147  
     }
 148  
 
 149  
     protected byte[] loadResource(URL url, String resourceName)
 150  
         throws IOException {
 151  0
         URLResourceReader urr = (URLResourceReader) urlset.get(url);
 152  
         // System.out.println("Loading from " + urr + " " + resourceName);
 153  0
         if(urr != null) {
 154  0
             return urr.getResource(resourceName);
 155  
         }
 156  
 
 157  0
         return null;
 158  
     }
 159  
 
 160  
     protected byte[] loadResource(String resource) {
 161  0
         byte[] barray = null;
 162  0
         for(Enumeration e = urlset.keys(); e.hasMoreElements();) {
 163  0
             URL url = (URL) e.nextElement();
 164  
 
 165  
             try {
 166  0
                 barray = loadResource(url, resource);
 167  0
             } catch(Exception ex) {
 168  0
             } finally {
 169  0
                 if(barray != null)
 170  0
                     break;
 171  0
             }
 172  0
         }
 173  
 
 174  0
         return barray;
 175  
     }
 176  
 
 177  
     protected byte[] loadClassData(String classname) {
 178  0
         String resourceName = classname.replace('.', '/') + ".class";
 179  0
         return loadResource(resourceName);
 180  
     }
 181  
 
 182  
     /**
 183  
      * Overridden to search for a resource and return 
 184  
      * a "jar"-style URL or normal "file" URL as necessary.
 185  
      */
 186  
     protected URL findResource(String name) 
 187  
     { //System.out.println( "findResource: " + name ); 
 188  
         URL url;
 189  0
         byte[] barray = null;
 190  
         
 191  0
         for ( Enumeration e = urlset.keys(); e.hasMoreElements();  ) 
 192  
         {
 193  0
             url = (URL) e.nextElement();
 194  
             try 
 195  
             {
 196  0
                 barray = loadResource(url, name); // loads fully: wasteful
 197  
             } 
 198  0
             catch(Exception ex) 
 199  
             {
 200  
                 // do nothing
 201  0
             } 
 202  0
             if( barray != null ) 
 203  
             {
 204  
                 try
 205  
                 {
 206  0
                     String ref = url.toString();
 207  0
                     if ( ref.endsWith( ".jar" ) )
 208  
                     {
 209  
                         //System.out.println( "jar:" + ref + "!/" + name );
 210  0
                         return new URL( "jar:" + ref + "!/" + name );
 211  
                     }
 212  
                     else
 213  
                     {
 214  
                         //System.out.println( new URL( url, name ).toString() );
 215  0
                         return new URL( url, name );
 216  
                     }
 217  
                 }
 218  0
                 catch ( Throwable t )
 219  
                 {
 220  0
                     t.printStackTrace();
 221  
                 }
 222  0
             }
 223  
         }
 224  
 
 225  0
         return null;
 226  
     }
 227  
 
 228  
     /**
 229  
      * @return The resource as the input stream if such a resource
 230  
      * exists, otherwise returns null.
 231  
      */
 232  
     public InputStream getResourceAsStream(String name) {
 233  
         //System.out.println( "getResourceAsStream: " + name );        
 234  0
         InputStream istream = null;
 235  
         
 236  
         // Algorithm:
 237  
         //
 238  
         // 1. first check the system path for the resource
 239  
         // 2. next  check the  delegate/parent class loader for the resource
 240  
         // 3. then attempt to get the resource from the url set.
 241  
         //
 242  
 
 243  
         // Lets check the system path for the resource.
 244  0
         istream = getSystemResourceAsStream(name);
 245  0
         if(istream != null)
 246  0
             return istream;
 247  
 
 248  
         // Lets check the parent/delegate class loader for the resource.
 249  0
         if(parent != null) {
 250  0
             istream = parent.getResourceAsStream(name);
 251  0
             if(istream != null)
 252  0
                 return istream;
 253  
         }
 254  
 
 255  
         // Lets load it ourselves.
 256  0
         byte[] data = loadResource(name);
 257  0
         if(data != null) {
 258  0
             istream = new ByteArrayInputStream(data);
 259  
         }
 260  
 
 261  0
         return istream;
 262  
     }
 263  
 
 264  
     /**
 265  
      * java.lang.ClassLoader's defineClass method is final, so the
 266  
      * its subclasses cannot override this method. But, this class
 267  
      * calls this method in the loadClass() instead.
 268  
      * @param The name of the class without ".class" extension.
 269  
      * @param The class data bytes.
 270  
      * @return The class object.
 271  
      */
 272  
     protected Class defineClass(String classname, byte[] classdata) {
 273  0
         return defineClass(classname, classdata, 0, classdata.length);
 274  
     }
 275  
 
 276  
     public synchronized Class loadClass(String name, boolean resolve)
 277  
         throws ClassNotFoundException {
 278  0
         Class c = null;
 279  
 
 280  
         // Algorithm: (Please do not change the order; unless you
 281  
         // have a good reason to do so).
 282  
         //
 283  
         // 1. first check the system class loader.
 284  
         // 2. next  check the  delegate/parent class loader.
 285  
         // 3. next  check the class cache
 286  
         // 4. then attempt to load classes from the URL set.
 287  
         //
 288  
         
 289  
         // Lets see if the class is in system class loader.
 290  
         try {
 291  0
             c = findSystemClass(name);
 292  0
         }catch(ClassNotFoundException cnfe) {
 293  0
         }finally {
 294  0
             if(c != null)
 295  0
                 return c;
 296  0
         }
 297  
 
 298  
         // Lets see if the class is in parent class loader.
 299  
         try {
 300  0
             if(parent != null)
 301  0
                 c = parent.loadClass(name);
 302  0
         }catch(ClassNotFoundException cnfe) {
 303  0
         }finally {
 304  0
             if(c != null)
 305  0
                 return c;
 306  0
         }
 307  
 
 308  
         // Lets see if the class is in the cache..
 309  0
         c = (Class) classCache.get(name);
 310  
 
 311  0
         if(c != null)
 312  0
             return c;
 313  
 
 314  
 
 315  
         // Lets see if we find the class all by ourselves.
 316  0
         byte[] data = loadClassData(name);
 317  
 
 318  0
         if(data != null) {
 319  
             // we did !!
 320  0
             c = defineClass(name, data);
 321  0
             classCache.put(name, c);
 322  0
             if(resolve)
 323  0
                 resolveClass(c);
 324  
         } else {
 325  
             // We are out of luck at this point...
 326  0
             throw new ClassNotFoundException(name);
 327  
         }
 328  
 
 329  0
         return c;
 330  
     }
 331  
 
 332  
     /**
 333  
      * This method resets this ClassLoader's state. It completely
 334  
      * removes all the URLs and classes in this class loader cache. 
 335  
      */
 336  
     public final void clear() {
 337  0
         urlset.clear();
 338  0
         classCache.clear();
 339  0
     }
 340  
 
 341  
     /**
 342  
      * This method resets this ClassLoader's state and resets the
 343  
      * references for garbage collection.
 344  
      */
 345  
     protected void finalize() throws Throwable {
 346  
         // Cleanup real well. Otherwise, this can be
 347  
         // a major source of memory leaks...
 348  
 
 349  
         // remove all the urls & class entries.
 350  0
         clear();
 351  
         
 352  0
         parent = null;
 353  0
         urlset = null;
 354  0
         classCache = null;
 355  0
     }
 356  
 }
 357  
 
 358  
 
 359  
 
 360  
 
 361  
 
 362  
 
 363  
 
 364  
 
 365  
 
 366  
 
 367  
 
 368