001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist;
017:
018: import java.io.*;
019: import java.net.*;
020:
021: /**
022: * A class search-path specified with URL (http).
023: *
024: * @see javassist.ClassPath
025: * @see ClassPool#insertClassPath(ClassPath)
026: * @see ClassPool#appendClassPath(ClassPath)
027: */
028: public class URLClassPath implements ClassPath {
029: protected String hostname;
030: protected int port;
031: protected String directory;
032: protected String packageName;
033:
034: /**
035: * Creates a search path specified with URL (http).
036: *
037: * <p>This search path is used only if a requested
038: * class name starts with the name specified by <code>packageName</code>.
039: * If <code>packageName</code> is "org.javassist." and a requested class is
040: * "org.javassist.test.Main", then the given URL is used for loading that class.
041: * The <code>URLClassPath</code> obtains a class file from:
042: *
043: * <ul><pre>http://www.javassist.org:80/java/classes/org/javassist/test/Main.class
044: * </pre></ul>
045: *
046: * <p>Here, we assume that <code>host</code> is "www.javassist.org",
047: * <code>port</code> is 80, and <code>directory</code> is "/java/classes/".
048: *
049: * <p>If <code>packageName</code> is <code>null</code>, the URL is used
050: * for loading any class.
051: *
052: * @param host host name
053: * @param port port number
054: * @param directory directory name ending with "/".
055: * It can be "/" (root directory).
056: * It must start with "/".
057: * @param packageName package name. It must end with "." (dot).
058: */
059: public URLClassPath(String host, int port, String directory,
060: String packageName) {
061: hostname = host;
062: this .port = port;
063: this .directory = directory;
064: this .packageName = packageName;
065: }
066:
067: public String toString() {
068: return hostname + ":" + port + directory;
069: }
070:
071: /**
072: * Opens a class file with http.
073: *
074: * @return null if the class file could not be found.
075: */
076: public InputStream openClassfile(String classname) {
077: try {
078: URLConnection con = openClassfile0(classname);
079: if (con != null)
080: return con.getInputStream();
081: } catch (IOException e) {
082: }
083: return null; // not found
084: }
085:
086: private URLConnection openClassfile0(String classname)
087: throws IOException {
088: if (packageName == null || classname.startsWith(packageName)) {
089: String jarname = directory + classname.replace('.', '/')
090: + ".class";
091: return fetchClass0(hostname, port, jarname);
092: } else
093: return null; // not found
094: }
095:
096: /**
097: * Returns the URL.
098: *
099: * @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: } catch (IOException e) {
110: }
111: return null;
112: }
113:
114: /**
115: * Closes this class path.
116: */
117: public void close() {
118: }
119:
120: /**
121: * Reads a class file on an http server.
122: *
123: * @param host host name
124: * @param port port number
125: * @param directory directory name ending with "/".
126: * It can be "/" (root directory).
127: * It must start with "/".
128: * @param classname fully-qualified class name
129: */
130: public static byte[] fetchClass(String host, int port,
131: String directory, String classname) throws IOException {
132: byte[] b;
133: URLConnection con = fetchClass0(host, port, directory
134: + classname.replace('.', '/') + ".class");
135: int size = con.getContentLength();
136: InputStream s = con.getInputStream();
137: try {
138: if (size <= 0)
139: b = ClassPoolTail.readStream(s);
140: else {
141: b = new byte[size];
142: int len = 0;
143: do {
144: int n = s.read(b, len, size - len);
145: if (n < 0)
146: throw new IOException("the stream was closed: "
147: + classname);
148:
149: len += n;
150: } while (len < size);
151: }
152: } finally {
153: s.close();
154: }
155:
156: return b;
157: }
158:
159: private static URLConnection fetchClass0(String host, int port,
160: String filename) throws IOException {
161: URL url;
162: try {
163: url = new URL("http", host, port, filename);
164: } catch (MalformedURLException e) {
165: // should never reache here.
166: throw new IOException("invalid URL?");
167: }
168:
169: URLConnection con = url.openConnection();
170: con.connect();
171: return con;
172: }
173: }
|