diff options
Diffstat (limited to 'src/main/javassist/tools/web/Viewer.java')
-rw-r--r-- | src/main/javassist/tools/web/Viewer.java | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/src/main/javassist/tools/web/Viewer.java b/src/main/javassist/tools/web/Viewer.java new file mode 100644 index 00000000..6e737406 --- /dev/null +++ b/src/main/javassist/tools/web/Viewer.java @@ -0,0 +1,208 @@ +/* + * Javassist, a Java-bytecode translator toolkit. + * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. Alternatively, the contents of this file may be used under + * the terms of the GNU Lesser General Public License Version 2.1 or later. + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + */ + +package javassist.tools.web; + +import java.io.*; +import java.net.*; + +/** + * A sample applet viewer. + * + * <p>This is a sort of applet viewer that can run any program even if + * the main class is not a subclass of <code>Applet</code>. + * This viewwer first calls <code>main()</code> in the main class. + * + * <p>To run, you should type: + * + * <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul> + * + * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code> + * All classes including <code>Main</code> are fetched from + * a server http://<i>host</i>:<i>port</i>. + * Only the class file for <code>Viewer</code> must exist + * on a local file system at the client side; even other + * <code>javassist.*</code> classes are not needed at the client side. + * <code>Viewer</code> uses only Java core API classes. + * + * <p>Note: since a <code>Viewer</code> object is a class loader, + * a program loaded by this object can call a method in <code>Viewer</code>. + * For example, you can write something like this: + * + * <ul><pre> + * Viewer v = (Viewer)this.getClass().getClassLoader(); + * String port = v.getPort(); + * </pre></ul> + * + */ +public class Viewer extends ClassLoader { + private String server; + private int port; + + /** + * Starts a program. + */ + public static void main(String[] args) throws Throwable { + if (args.length >= 3) { + Viewer cl = new Viewer(args[0], Integer.parseInt(args[1])); + String[] args2 = new String[args.length - 3]; + System.arraycopy(args, 3, args2, 0, args.length - 3); + cl.run(args[2], args2); + } + else + System.err.println( + "Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]"); + } + + /** + * Constructs a viewer. + * + * @param host server name + * @param p port number + */ + public Viewer(String host, int p) { + server = host; + port = p; + } + + /** + * Returns the server name. + */ + public String getServer() { return server; } + + /** + * Returns the port number. + */ + public int getPort() { return port; } + + /** + * Invokes main() in the class specified by <code>classname</code>. + * + * @param classname executed class + * @param args the arguments passed to <code>main()</code>. + */ + public void run(String classname, String[] args) + throws Throwable + { + Class c = loadClass(classname); + try { + c.getDeclaredMethod("main", new Class[] { String[].class }) + .invoke(null, new Object[] { args }); + } + catch (java.lang.reflect.InvocationTargetException e) { + throw e.getTargetException(); + } + } + + /** + * Requests the class loader to load a class. + */ + protected synchronized Class loadClass(String name, boolean resolve) + throws ClassNotFoundException + { + Class c = findLoadedClass(name); + if (c == null) + c = findClass(name); + + if (c == null) + throw new ClassNotFoundException(name); + + if (resolve) + resolveClass(c); + + return c; + } + + /** + * Finds the specified class. The implementation in this class + * fetches the class from the http server. If the class is + * either <code>java.*</code>, <code>javax.*</code>, or + * <code>Viewer</code>, then it is loaded by the parent class + * loader. + * + * <p>This method can be overridden by a subclass of + * <code>Viewer</code>. + */ + protected Class findClass(String name) throws ClassNotFoundException { + Class c = null; + if (name.startsWith("java.") || name.startsWith("javax.") + || name.equals("javassist.tools.web.Viewer")) + c = findSystemClass(name); + + if (c == null) + try { + byte[] b = fetchClass(name); + if (b != null) + c = defineClass(name, b, 0, b.length); + } + catch (Exception e) { + } + + return c; + } + + /** + * Fetches the class file of the specified class from the http + * server. + */ + protected byte[] fetchClass(String classname) throws Exception + { + byte[] b; + URL url = new URL("http", server, port, + "/" + classname.replace('.', '/') + ".class"); + URLConnection con = url.openConnection(); + con.connect(); + int size = con.getContentLength(); + InputStream s = con.getInputStream(); + if (size <= 0) + b = readStream(s); + else { + b = new byte[size]; + int len = 0; + do { + int n = s.read(b, len, size - len); + if (n < 0) { + s.close(); + throw new IOException("the stream was closed: " + + classname); + } + len += n; + } while (len < size); + } + + s.close(); + return b; + } + + private byte[] readStream(InputStream fin) throws IOException { + byte[] buf = new byte[4096]; + int size = 0; + int len = 0; + do { + size += len; + if (buf.length - size <= 0) { + byte[] newbuf = new byte[buf.length * 2]; + System.arraycopy(buf, 0, newbuf, 0, size); + buf = newbuf; + } + + len = fin.read(buf, size, buf.length - size); + } while (len >= 0); + + byte[] result = new byte[size]; + System.arraycopy(buf, 0, result, 0, size); + return result; + } +} |