1/* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16package javassist; 17 18import java.io.*; 19import java.net.*; 20 21/** 22 * A class search-path specified with URL (http). 23 * 24 * @see javassist.ClassPath 25 * @see ClassPool#insertClassPath(ClassPath) 26 * @see ClassPool#appendClassPath(ClassPath) 27 */ 28public class URLClassPath implements ClassPath { 29 protected String hostname; 30 protected int port; 31 protected String directory; 32 protected String packageName; 33 34 /** 35 * Creates a search path specified with URL (http). 36 * 37 * <p>This search path is used only if a requested 38 * class name starts with the name specified by <code>packageName</code>. 39 * If <code>packageName</code> is "org.javassist." and a requested class is 40 * "org.javassist.test.Main", then the given URL is used for loading that class. 41 * The <code>URLClassPath</code> obtains a class file from: 42 * 43 * <ul><pre>http://www.javassist.org:80/java/classes/org/javassist/test/Main.class 44 * </pre></ul> 45 * 46 * <p>Here, we assume that <code>host</code> is "www.javassist.org", 47 * <code>port</code> is 80, and <code>directory</code> is "/java/classes/". 48 * 49 * <p>If <code>packageName</code> is <code>null</code>, the URL is used 50 * for loading any class. 51 * 52 * @param host host name 53 * @param port port number 54 * @param directory directory name ending with "/". 55 * It can be "/" (root directory). 56 * It must start with "/". 57 * @param packageName package name. It must end with "." (dot). 58 */ 59 public URLClassPath(String host, int port, 60 String directory, String packageName) { 61 hostname = host; 62 this.port = port; 63 this.directory = directory; 64 this.packageName = packageName; 65 } 66 67 public String toString() { 68 return hostname + ":" + port + directory; 69 } 70 71 /** 72 * Opens a class file with http. 73 * 74 * @return null if the class file could not be found. 75 */ 76 public InputStream openClassfile(String classname) { 77 try { 78 URLConnection con = openClassfile0(classname); 79 if (con != null) 80 return con.getInputStream(); 81 } 82 catch (IOException e) {} 83 return null; // not found 84 } 85 86 private URLConnection openClassfile0(String classname) throws IOException { 87 if (packageName == null || classname.startsWith(packageName)) { 88 String jarname 89 = directory + classname.replace('.', '/') + ".class"; 90 return fetchClass0(hostname, port, jarname); 91 } 92 else 93 return null; // not found 94 } 95 96 /** 97 * Returns the URL. 98 * 99 * @return null if the class file could not be obtained. 100 */ 101 public URL find(String classname) { 102 try { 103 URLConnection con = openClassfile0(classname); 104 InputStream is = con.getInputStream(); 105 if (is != null) { 106 is.close(); 107 return con.getURL(); 108 } 109 } 110 catch (IOException e) {} 111 return null; 112 } 113 114 /** 115 * Closes this class path. 116 */ 117 public void close() {} 118 119 /** 120 * Reads a class file on an http server. 121 * 122 * @param host host name 123 * @param port port number 124 * @param directory directory name ending with "/". 125 * It can be "/" (root directory). 126 * It must start with "/". 127 * @param classname fully-qualified class name 128 */ 129 public static byte[] fetchClass(String host, int port, 130 String directory, String classname) 131 throws IOException 132 { 133 byte[] b; 134 URLConnection con = fetchClass0(host, port, 135 directory + classname.replace('.', '/') + ".class"); 136 int size = con.getContentLength(); 137 InputStream s = con.getInputStream(); 138 try { 139 if (size <= 0) 140 b = ClassPoolTail.readStream(s); 141 else { 142 b = new byte[size]; 143 int len = 0; 144 do { 145 int n = s.read(b, len, size - len); 146 if (n < 0) 147 throw new IOException("the stream was closed: " 148 + classname); 149 150 len += n; 151 } while (len < size); 152 } 153 } 154 finally { 155 s.close(); 156 } 157 158 return b; 159 } 160 161 private static URLConnection fetchClass0(String host, int port, 162 String filename) 163 throws IOException 164 { 165 URL url; 166 try { 167 url = new URL("http", host, port, filename); 168 } 169 catch (MalformedURLException e) { 170 // should never reache here. 171 throw new IOException("invalid URL?"); 172 } 173 174 URLConnection con = url.openConnection(); 175 con.connect(); 176 return con; 177 } 178} 179