Clover coverage report - PLT Utilities Test Coverage (plt-20120304-r5436)
Coverage timestamp: Sat Mar 3 2012 22:01:56 CST
file stats: LOC: 174   Methods: 12
NCLOC: 78   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
PathClassLoader.java 50% 71.1% 58.3% 66.1%
coverage coverage
 1    /*BEGIN_COPYRIGHT_BLOCK*
 2   
 3    PLT Utilities BSD License
 4   
 5    Copyright (c) 2007-2010 JavaPLT group at Rice University
 6    All rights reserved.
 7   
 8    Developed by: Java Programming Languages Team
 9    Rice University
 10    http://www.cs.rice.edu/~javaplt/
 11   
 12    Redistribution and use in source and binary forms, with or without modification, are permitted
 13    provided that the following conditions are met:
 14   
 15    - Redistributions of source code must retain the above copyright notice, this list of conditions
 16    and the following disclaimer.
 17    - Redistributions in binary form must reproduce the above copyright notice, this list of
 18    conditions and the following disclaimer in the documentation and/or other materials provided
 19    with the distribution.
 20    - Neither the name of the JavaPLT group, Rice University, nor the names of the library's
 21    contributors may be used to endorse or promote products derived from this software without
 22    specific prior written permission.
 23   
 24    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 25    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 26    FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS AND
 27    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 28    DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 29    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
 30    IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 31    OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 32   
 33    *END_COPYRIGHT_BLOCK*/
 34   
 35    package edu.rice.cs.plt.reflect;
 36   
 37    import java.net.URL;
 38    import java.net.URLClassLoader;
 39    import java.net.MalformedURLException;
 40    import java.io.File;
 41    import java.io.InputStream;
 42    import java.io.IOException;
 43    import java.util.Enumeration;
 44    import java.util.List;
 45    import java.util.LinkedList;
 46   
 47    import edu.rice.cs.plt.iter.IterUtil;
 48    import edu.rice.cs.plt.io.IOUtil;
 49   
 50    import static edu.rice.cs.plt.debug.DebugUtil.error;
 51    import static edu.rice.cs.plt.debug.DebugUtil.debug;
 52   
 53    /**
 54    * A class loader that mimics the standard application system loader by loading classes from
 55    * a file path of directories and jar files. This class also supports a <em>dynamic</em>
 56    * class path: an {@code Iterable} provided as input to the constructor is held, not copied,
 57    * and subsequent changes to that iterable are reflected in the path that is searched. Of
 58    * course, once a class is loaded, subsequent changes to the path will not change the class
 59    * bound to that name. The dynamic nature of the search path makes possible unusual errors --
 60    * a class may be valid in the path in which it is initially loaded, but when the JVM
 61    * later transitively resolves the referenced classes, they may no longer exist, or may be
 62    * shadowed. This is not a unique problem, however -- the standard system class loader is
 63    * based on an underlying file system that may also change in arbitrary ways at any time.
 64    */
 65    public class PathClassLoader extends AbstractClassLoader {
 66   
 67    /**
 68    * Locate a resource in the given path. Returns {@code null} if the resource is not found.
 69    * If multiple queries will be performed on the same path, a PathClassLoader instance
 70    * should be created for better performance.
 71    */
 72  0 public static URL getResourceInPath(String name, File... path) {
 73  0 return getResourceInPath(name, IterUtil.asIterable(path));
 74    }
 75   
 76    /**
 77    * Locate a resource in the given path. Returns {@code null} if the resource is not found.
 78    * If multiple queries will be performed on the same path, a PathClassLoader instance
 79    * should be created for better performance.
 80    */
 81  0 public static URL getResourceInPath(String name, Iterable<File> path) {
 82  0 return new PathClassLoader(EmptyClassLoader.INSTANCE, path).getResource(name);
 83    }
 84   
 85    /**
 86    * Locate a resource in the given path. Returns {@code null} if the resource is not found.
 87    * If multiple queries will be performed on the same path, a PathClassLoader instance
 88    * should be created for better performance.
 89    */
 90  0 public static InputStream getResourceInPathAsStream(String name, File... path) {
 91  0 return getResourceInPathAsStream(name, IterUtil.asIterable(path));
 92    }
 93   
 94    /**
 95    * Locate a resource in the given path. Returns {@code null} if the resource is not found.
 96    * If multiple queries will be performed on the same path, a PathClassLoader instance
 97    * should be created for better performance.
 98    */
 99  0 public static InputStream getResourceInPathAsStream(String name, Iterable<File> path) {
 100  0 return new PathClassLoader(EmptyClassLoader.INSTANCE, path).getResourceAsStream(name);
 101    }
 102   
 103   
 104    private final Iterable<? extends File> _path;
 105    private URLClassLoader _urlLoader;
 106    private Iterable<File> _urlLoaderPath;
 107   
 108    /**
 109    * Create a path class loader with the default parent ({@link ClassLoader#getSystemClassLoader})
 110    * and the specified path.
 111    */
 112  4 public PathClassLoader(File... path) { this(IterUtil.asIterable(path)); }
 113   
 114    /**
 115    * Create a path class loader with the default parent ({@link ClassLoader#getSystemClassLoader})
 116    * and the specified path.
 117    */
 118  4 public PathClassLoader(Iterable<? extends File> path) {
 119  4 super();
 120  4 _path = path;
 121  4 updateURLLoader();
 122    }
 123   
 124    /** Create a path class loader with the given parent and path */
 125  11 public PathClassLoader(ClassLoader parent, File... path) { this(parent, IterUtil.asIterable(path)); }
 126   
 127    /** Create a path class loader with the given parent and path */
 128  12 public PathClassLoader(ClassLoader parent, Iterable<? extends File> path) {
 129  12 super(parent);
 130  12 _path = path;
 131  12 updateURLLoader();
 132    }
 133   
 134  16 private void updateURLLoader() {
 135  16 _urlLoaderPath = IterUtil.snapshot(_path);
 136  16 List<URL> urls = new LinkedList<URL>();
 137  16 for (File f : _urlLoaderPath) {
 138  40 try { urls.add(f.toURI().toURL()); }
 139  0 catch (IllegalArgumentException e) { error.log(e); }
 140  0 catch (MalformedURLException e) { error.log(e); }
 141    // just skip the path element if there's an error
 142    }
 143  16 _urlLoader = new URLClassLoader(urls.toArray(new URL[urls.size()]), EmptyClassLoader.INSTANCE);
 144    }
 145   
 146  82 @Override protected Class<?> findClass(String name) throws ClassNotFoundException {
 147  82 URL resource = findResource(name.replace('.', '/') + ".class");
 148  43 if (resource == null) { throw new ClassNotFoundException(); }
 149    else {
 150  39 try {
 151  39 InputStream stream = resource.openStream();
 152  39 try {
 153  39 byte[] bytes = IOUtil.toByteArray(stream);
 154  39 Class<?> result = defineClass(name, bytes, 0, bytes.length);
 155  39 definePackageForClass(name);
 156  39 return result;
 157    }
 158  39 finally { stream.close(); }
 159    }
 160  0 catch (IOException e) { throw new ClassNotFoundException("Can't access class file", e); }
 161    }
 162    }
 163   
 164  83 @Override protected URL findResource(String name) {
 165  0 if (!IterUtil.isEqual(_path, _urlLoaderPath)) { updateURLLoader(); }
 166  83 return _urlLoader.findResource(name);
 167    }
 168   
 169  0 @Override protected Enumeration<URL> findResources(String name) throws IOException {
 170  0 if (!IterUtil.isEqual(_path, _urlLoaderPath)) { updateURLLoader(); }
 171  0 return _urlLoader.findResources(name);
 172    }
 173   
 174    }