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.InputStream; 32 import java.io.IOException; 33 import java.util.Hashtable; 34 import java.util.Map; 35 import java.util.Vector; 36 import java.util.zip.ZipEntry; 37 import java.util.zip.ZipFile; 38 39 /** 40 * A class loader for loading classes from a path of directories, 41 * zip files and jar files. 42 */ 43 public class PathClassLoader extends ClassLoader 44 { 45 /** 46 * Create a PathClassLoader, specifying a path. 47 * @param pathString a string containing a sequence of 48 * file paths separated by the platform-specific file 49 * separator, identifying a sequence of locations in which 50 * to look for classes to be loaded 51 * @see File#pathSeparator 52 */ 53 public PathClassLoader(String pathString) { 54 this.path = split(pathString); 55 } 56 57 /** 58 * Create a PathClassLoader, specifying a path and a 59 * base directory for any relative files on the path. 60 * @param baseDir the base directory for any relative 61 * files on the path 62 * @param pathString a string containing a sequence of 63 * file paths separated by the platform-specific file 64 * separator, identifying a sequence of locations in which 65 * to look for classes to be loaded 66 * @see File#pathSeparator 67 */ 68 public PathClassLoader(File baseDir, String pathString) { 69 path = split(pathString); 70 for (int i = 0; i < path.length; i++) { 71 File f = path[i]; 72 if (!f.isAbsolute()) 73 path[i] = new File(baseDir, f.getPath()); 74 } 75 } 76 77 /** 78 * Create a PathCloader, specifying an array of files for the path. 79 * @param path an array of files, identifying a sequence of locations in which 80 * to look for classes to be loaded 81 */ 82 public PathClassLoader(File[] path) { 83 this.path = path; 84 } 85 86 /** 87 * Attempt to load a class if it is not already loaded, and optionally 88 * resolve any imports it might have. 89 * 90 * @param name The fully-qualified name of the class to load. 91 * @param resolve True if imports should be resolved, false otherwise. 92 * @return the class that was loaded 93 * @throws ClassNotFoundException if the class was not found. 94 */ 95 protected Class loadClass(String name, boolean resolve) 96 throws ClassNotFoundException { 97 98 Class<?> cl = classes.get(name); 99 100 if (cl == null) { 101 try { 102 cl = findSystemClass(name); 103 } 104 catch (ClassNotFoundException e) { 105 cl = locateClass(name); 106 } 107 } 108 109 if (resolve) 110 resolveClass(cl); 111 112 return cl; 113 } 114 115 116 private synchronized Class locateClass(String name) 117 throws ClassNotFoundException { 118 //System.err.println("locateClass: " + name); 119 Class<?> c = classes.get(name); 120 if (c != null) 121 return c; 122 123 for (int i = 0; i < path.length; i++) { 124 if (path[i].isDirectory()) 125 c = locateClassInDir(name, path[i]); 126 else 127 c = locateClassInJar(name, path[i]); 128 129 if (c != null) { 130 classes.put(name, c); 131 return c; 132 } 133 } 134 135 throw new ClassNotFoundException(name); 136 } 137 138 private Class locateClassInDir(String name, File dir) 139 throws ClassNotFoundException { 140 //System.err.println("locateClassInDir: " + name + " " + dir); 141 String cname = name.replace('.', '/') + ".class"; 142 try { 143 File file = new File(dir, cname); 144 return readClass(name, new FileInputStream(file), (int)(file.length())); 145 } 146 catch (IOException e) { 147 //System.err.println("locateClassInDir: " + e); 148 return null; 149 } 150 } 151 152 private Class locateClassInJar(String name, File jarFile) 153 throws ClassNotFoundException { 154 //System.err.println("locateClassInJar: " + name + " " + jarFile); 155 String cname = name.replace('.', '/') + ".class"; 156 try { 157 ZipFile z = zips.get(jarFile); 158 if (z == null) { 159 z = new ZipFile(jarFile); 160 zips.put(jarFile, z); 161 } 162 ZipEntry ze = z.getEntry(cname); 163 if (ze == null) 164 return null; 165 return readClass(name, z.getInputStream(ze), (int)(ze.getSize())); 166 } 167 catch (IOException e) { 168 //System.err.println("locateClassInJar: " + e); 169 return null; 170 } 171 } 172 173 private Class readClass(String name, InputStream in, int size) throws IOException { 174 byte[] data = new byte[size]; 175 try { 176 for (int total = 0; total < size; ) { 177 total += in.read(data, total, size - total); 178 } 179 } 180 finally { 181 in.close(); 182 } 183 return defineClass(name, data, 0, data.length); 184 } 185 186 private File[] split(String s) { 187 char pathCh = File.pathSeparatorChar; 188 Vector<File> v = new Vector<>(); 189 int start = 0; 190 for (int i = s.indexOf(pathCh); i != -1; i = s.indexOf(pathCh, start)) { 191 add(s.substring(start, i), v); 192 start = i + 1; 193 } 194 if (start != s.length()) 195 add(s.substring(start), v); 196 File[] path = new File[v.size()]; 197 v.copyInto(path); 198 return path; 199 } 200 201 private void add(String s, Vector<File> v) { 202 if (s.length() != 0) 203 v.addElement(new File(s)); 204 } 205 206 private File[] path; 207 private Map<String, Class<?>> classes = new Hashtable<>(); 208 private Map<File, ZipFile> zips = new Hashtable<>(); 209 }