/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- 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,
 * or the Apache License Version 2.0.
 *
 * 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.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;

A sample applet viewer.

This is a sort of applet viewer that can run any program even if the main class is not a subclass of Applet. This viewwer first calls main() in the main class.

To run, you should type:

% java javassist.tools.web.Viewer host port Main arg1, ...

This command calls Main.main() with arg1,... All classes including Main are fetched from a server http://host:port. Only the class file for Viewer must exist on a local file system at the client side; even other javassist.* classes are not needed at the client side. Viewer uses only Java core API classes.

Note: since a Viewer object is a class loader, a program loaded by this object can call a method in Viewer. For example, you can write something like this:

Viewer v = (Viewer)this.getClass().getClassLoader();
String port = v.getPort();
/** * 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: * * <pre>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</pre> * * <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: * * <pre> * Viewer v = (Viewer)this.getClass().getClassLoader(); * String port = v.getPort(); * </pre> * */
public class Viewer extends ClassLoader { private String server; private int port;
Starts a program.
/** * 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.
Params:
  • host – server name
  • p – port number
/** * 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.
/** * Returns the server name. */
public String getServer() { return server; }
Returns the port number.
/** * Returns the port number. */
public int getPort() { return port; }
Invokes main() in the class specified by classname.
Params:
  • classname – executed class
  • args – the arguments passed to main().
/** * 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.
/** * Requests the class loader to load a class. */
@Override 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 java.*, javax.*, or Viewer, then it is loaded by the parent class loader.

This method can be overridden by a subclass of Viewer.

/** * 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>. */
@Override 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.
/** * 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; } }