1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 1996, 2009, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.util;
  28 
  29 import java.io.File;
  30 import java.io.FileInputStream;
  31 import java.io.FileNotFoundException;
  32 import java.io.InputStream;
  33 import java.io.IOException;
  34 import java.net.URL;
  35 import java.util.Hashtable;
  36 import java.util.Map;
  37 
  38 /**
  39  * This class loader loads classes from files a specified directory.
  40  * @see com.sun.javatest.util.PathClassLoader
  41  * @deprecated use PathClassLoader
  42  */
  43 public class DirectoryClassLoader extends ClassLoader
  44 {
  45     /**
  46      * Constructor that provides the name of the directory in which to search
  47      * for a given class.
  48      *
  49      * @param dir  The File specifying the directory to search.
  50      */
  51     public DirectoryClassLoader(File dir) {
  52         loadDir = dir;
  53     }
  54 
  55     /**
  56      * Constructor that provides the name of the directory in which to search
  57      * for a given class.
  58      *
  59      * @param dirName  A file pathname specifying the directory to search.
  60      */
  61     public DirectoryClassLoader(String dirName) {
  62         loadDir = new File(dirName);
  63     }
  64 
  65     //----------ClassLoader methods---------------------------------------------
  66 
  67     /**
  68      * Attempt to load a class if it is not already loaded, and optionally
  69      * resolve any imports it might have.
  70      *
  71      * @param name The fully-qualified name of the class to load.
  72      * @param resolve True if imports should be resolved, false otherwise.
  73      * @return the class that was loaded
  74      * @throws ClassNotFoundException if the class was not found.
  75      */
  76     protected Class loadClass(String name, boolean resolve)
  77         throws ClassNotFoundException {
  78 
  79         // check the cache first
  80         Class<?> cl = classes.get(name);
  81 
  82         // not found in the cache?
  83         if (cl == null) {
  84             // see if it is a system class
  85             try {
  86                 cl = findSystemClass(name);
  87             }
  88             catch (ClassNotFoundException e) {
  89                 // It's not a system class, look in the directory for this
  90                 // class loader.  If there is an IO problem, we'll throw
  91                 // ClassNotFoundException; if the class file is read correctly
  92                 // but is an invalid class, we'll get a LinkageError
  93                 cl = locateClass(name);
  94             }
  95         }
  96 
  97         if (resolve)
  98             resolveClass(cl);
  99 
 100         return cl;
 101 
 102     }
 103 
 104     /**
 105      * Returns an input stream for reading the specified resource.
 106      *
 107      * @param  name the resource name
 108      * @return an input stream for reading the resource, or <code>null</code>
 109      *         if the resource could not be found
 110      *
 111      *  redundant in 1.2
 112      */
 113     public InputStream getResourceAsStream(String name) {
 114         URL url = getResource(name);
 115         try {
 116             return url != null ? url.openStream() : null;
 117         } catch (IOException e) {
 118             return null;
 119         }
 120     }
 121 
 122     /**
 123      * Finds the resource with the given name. A resource is some data
 124      * (images, audio, text, etc) that can be accessed by class code
 125      * in a way that is independent of the location of the code.
 126      * <p>
 127      * The name of a resource is a "/"-separated path name that identifies
 128      * the resource.
 129      * <p>
 130      * This method will first search the parent class loader for the
 131      * resource, then call <code>findResource</code> to find the
 132      * resource.
 133      *
 134      * @param  name resource name
 135      * @return a URL for reading the resource, or <code>null</code> if
 136      *         the resource could not be found or the caller doesn't have
 137      *          adequate privileges to get the resource.
 138      *
 139      *  redundant in 1.2
 140      */
 141     public URL getResource(String name) {
 142         // the ordering of this code looks very strange, but it
 143         // corresponds to the implementation in JDK 1.2.
 144         URL url = getSystemResource(name);
 145         if (url == null) {
 146             url = findResource(name);
 147         }
 148         return url;
 149     }
 150 
 151     /**
 152      * Finds the resource with the given name. Class loader
 153      * implementations should override this method to specify where to
 154      * find resources.
 155      *
 156      * @param  name the resource name
 157      * @return a URL for reading the resource, or <code>null</code>
 158      *         if the resource could not be found
 159      * @since  JDK1.2
 160      */
 161     public URL findResource(String name) {
 162        try {
 163            File f = new File(loadDir, name);
 164            if (f.exists())
 165                return new URL("file:" + f.getAbsolutePath());
 166            else
 167                return null;
 168        }
 169        catch (java.net.MalformedURLException e) {
 170            return null;
 171        }
 172     }
 173 
 174     //----------internal methods------------------------------------------------
 175 
 176     private synchronized Class locateClass(String name)
 177         throws ClassNotFoundException {
 178         //This check is currently necessary; we just
 179         // check the cache at the one call site, but that was not
 180         // synchronized, so there is a very small remote chance another
 181         // caller has just loaded this class.
 182         Class<?> cl = classes.get(name);
 183         if (cl != null)
 184             return cl;
 185 
 186         String cname = name.replace('.', '/') + ".class";
 187 
 188         File file = new File(loadDir, cname);
 189 
 190         try {
 191             byte[] data;
 192             try (InputStream in = new FileInputStream(file)) {
 193                 int len = in.available();
 194                 data = new byte[len];
 195                 for (int total = 0; total < data.length; ) {
 196                     total += in.read(data, total, data.length - total);
 197                 }
 198             }
 199             // the next line may throw LinkageError, which we let
 200             // escape to the caller
 201             cl = defineClass(name, data, 0, data.length);
 202             classes.put(name, cl);
 203             return cl;
 204         }
 205         catch (FileNotFoundException e) {
 206             // ClassNotFoundException is obviously the correct
 207             // exception to throw in this case
 208             throw new ClassNotFoundException(name);
 209         }
 210         catch (IOException e) {
 211             // This one is more iffy; we found a file, but had trouble
 212             // reading it; still use ClassNotFoundException for now.
 213             throw new ClassNotFoundException(name);
 214         }
 215 
 216     }
 217 
 218     //----------Data members----------------------------------------------------
 219 
 220     private File loadDir;
 221     private Map<String, Class<?>> classes = new Hashtable<>();
 222 }