169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/* 269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Javassist, a Java-bytecode translator toolkit. 369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The contents of this file are subject to the Mozilla Public License Version 669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1.1 (the "License"); you may not use this file except in compliance with 769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the License. Alternatively, the contents of this file may be used under 869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * the terms of the GNU Lesser General Public License Version 2.1 or later. 969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 1069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Software distributed under the License is distributed on an "AS IS" basis, 1169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 1269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for the specific language governing rights and limitations under the 1369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * License. 1469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 1569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpackage javassist; 1769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 1869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.io.*; 1969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalimport java.net.*; 2069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 2169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal/** 2269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * A class search-path specified with URL (http). 2369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 2469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see javassist.ClassPath 2569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see ClassPool#insertClassPath(ClassPath) 2669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @see ClassPool#appendClassPath(ClassPath) 2769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 2869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigalpublic class URLClassPath implements ClassPath { 2969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected String hostname; 3069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected int port; 3169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected String directory; 3269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal protected String packageName; 3369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 3469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 3569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Creates a search path specified with URL (http). 3669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 3769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>This search path is used only if a requested 3869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * class name starts with the name specified by <code>packageName</code>. 3969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * If <code>packageName</code> is "org.javassist." and a requested class is 4069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * "org.javassist.test.Main", then the given URL is used for loading that class. 4169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * The <code>URLClassPath</code> obtains a class file from: 4269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <ul><pre>http://www.javassist.org:80/java/classes/org/javassist/test/Main.class 4469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * </pre></ul> 4569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>Here, we assume that <code>host</code> is "www.javassist.org", 4769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <code>port</code> is 80, and <code>directory</code> is "/java/classes/". 4869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 4969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * <p>If <code>packageName</code> is <code>null</code>, the URL is used 5069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * for loading any class. 5169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 5269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param host host name 5369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param port port number 5469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param directory directory name ending with "/". 5569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It can be "/" (root directory). 5669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It must start with "/". 5769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param packageName package name. It must end with "." (dot). 5869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 5969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public URLClassPath(String host, int port, 6069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String directory, String packageName) { 6169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal hostname = host; 6269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.port = port; 6369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.directory = directory; 6469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal this.packageName = packageName; 6569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 6669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 6769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public String toString() { 6869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return hostname + ":" + port + directory; 6969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 7069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 7169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 7269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Opens a class file with http. 7369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 7469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return null if the class file could not be found. 7569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 7669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public InputStream openClassfile(String classname) { 7769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 7869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal URLConnection con = openClassfile0(classname); 7969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (con != null) 8069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return con.getInputStream(); 8169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IOException e) {} 8369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; // not found 8469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 8569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 8669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private URLConnection openClassfile0(String classname) throws IOException { 8769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (packageName == null || classname.startsWith(packageName)) { 8869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String jarname 8969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal = directory + classname.replace('.', '/') + ".class"; 9069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return fetchClass0(hostname, port, jarname); 9169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else 9369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; // not found 9469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 9569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 9669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 9769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Returns the URL. 9869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 9969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @return null if the class file could not be obtained. 10069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 10169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public URL find(String classname) { 10269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 10369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal URLConnection con = openClassfile0(classname); 10469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal InputStream is = con.getInputStream(); 10569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (is != null) { 10669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal is.close(); 10769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return con.getURL(); 10869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 10969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (IOException e) {} 11169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return null; 11269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 11369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 11569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Closes this class path. 11669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 11769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public void close() {} 11869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 11969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal /** 12069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * Reads a class file on an http server. 12169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * 12269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param host host name 12369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param port port number 12469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param directory directory name ending with "/". 12569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It can be "/" (root directory). 12669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * It must start with "/". 12769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal * @param classname fully-qualified class name 12869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal */ 12969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal public static byte[] fetchClass(String host, int port, 13069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String directory, String classname) 13169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws IOException 13269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 13369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal byte[] b; 13469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal URLConnection con = fetchClass0(host, port, 13569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal directory + classname.replace('.', '/') + ".class"); 13669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int size = con.getContentLength(); 13769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal InputStream s = con.getInputStream(); 13869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 13969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (size <= 0) 14069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal b = ClassPoolTail.readStream(s); 14169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal else { 14269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal b = new byte[size]; 14369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int len = 0; 14469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal do { 14569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal int n = s.read(b, len, size - len); 14669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal if (n < 0) 14769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new IOException("the stream was closed: " 14869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal + classname); 14969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal len += n; 15169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } while (len < size); 15269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal finally { 15569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal s.close(); 15669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 15769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 15869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return b; 15969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 16169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal private static URLConnection fetchClass0(String host, int port, 16269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal String filename) 16369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throws IOException 16469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal { 16569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal URL url; 16669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal try { 16769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal url = new URL("http", host, port, filename); 16869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 16969e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal catch (MalformedURLException e) { 17069e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal // should never reache here. 17169e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal throw new IOException("invalid URL?"); 17269e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17369e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal 17469e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal URLConnection con = url.openConnection(); 17569e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal con.connect(); 17669e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal return con; 17769e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal } 17869e17611504376e4d4603925f8528dfc890fd2c6Luis Sigal} 179