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.tools.web;
017:
018: import java.io.*;
019: import java.net.*;
020:
021: /**
022: * A sample applet viewer.
023: *
024: * <p>This is a sort of applet viewer that can run any program even if
025: * the main class is not a subclass of <code>Applet</code>.
026: * This viewwer first calls <code>main()</code> in the main class.
027: *
028: * <p>To run, you should type:
029: *
030: * <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul>
031: *
032: * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code>
033: * All classes including <code>Main</code> are fetched from
034: * a server http://<i>host</i>:<i>port</i>.
035: * Only the class file for <code>Viewer</code> must exist
036: * on a local file system at the client side; even other
037: * <code>javassist.*</code> classes are not needed at the client side.
038: * <code>Viewer</code> uses only Java core API classes.
039: *
040: * <p>Note: since a <code>Viewer</code> object is a class loader,
041: * a program loaded by this object can call a method in <code>Viewer</code>.
042: * For example, you can write something like this:
043: *
044: * <ul><pre>
045: * Viewer v = (Viewer)this.getClass().getClassLoader();
046: * String port = v.getPort();
047: * </pre></ul>
048: *
049: */
050: public class Viewer extends ClassLoader {
051: private String server;
052: private int port;
053:
054: /**
055: * Starts a program.
056: */
057: public static void main(String[] args) throws Throwable {
058: if (args.length >= 3) {
059: Viewer cl = new Viewer(args[0], Integer.parseInt(args[1]));
060: String[] args2 = new String[args.length - 3];
061: System.arraycopy(args, 3, args2, 0, args.length - 3);
062: cl.run(args[2], args2);
063: } else
064: System.err
065: .println("Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]");
066: }
067:
068: /**
069: * Constructs a viewer.
070: *
071: * @param host server name
072: * @param p port number
073: */
074: public Viewer(String host, int p) {
075: server = host;
076: port = p;
077: }
078:
079: /**
080: * Returns the server name.
081: */
082: public String getServer() {
083: return server;
084: }
085:
086: /**
087: * Returns the port number.
088: */
089: public int getPort() {
090: return port;
091: }
092:
093: /**
094: * Invokes main() in the class specified by <code>classname</code>.
095: *
096: * @param classname executed class
097: * @param args the arguments passed to <code>main()</code>.
098: */
099: public void run(String classname, String[] args) throws Throwable {
100: Class c = loadClass(classname);
101: try {
102: c.getDeclaredMethod("main", new Class[] { String[].class })
103: .invoke(null, new Object[] { args });
104: } catch (java.lang.reflect.InvocationTargetException e) {
105: throw e.getTargetException();
106: }
107: }
108:
109: /**
110: * Requests the class loader to load a class.
111: */
112: protected synchronized Class loadClass(String name, boolean resolve)
113: throws ClassNotFoundException {
114: Class c = findLoadedClass(name);
115: if (c == null)
116: c = findClass(name);
117:
118: if (c == null)
119: throw new ClassNotFoundException(name);
120:
121: if (resolve)
122: resolveClass(c);
123:
124: return c;
125: }
126:
127: /**
128: * Finds the specified class. The implementation in this class
129: * fetches the class from the http server. If the class is
130: * either <code>java.*</code>, <code>javax.*</code>, or
131: * <code>Viewer</code>, then it is loaded by the parent class
132: * loader.
133: *
134: * <p>This method can be overridden by a subclass of
135: * <code>Viewer</code>.
136: */
137: protected Class findClass(String name)
138: throws ClassNotFoundException {
139: Class c = null;
140: if (name.startsWith("java.") || name.startsWith("javax.")
141: || name.equals("javassist.tools.web.Viewer"))
142: c = findSystemClass(name);
143:
144: if (c == null)
145: try {
146: byte[] b = fetchClass(name);
147: if (b != null)
148: c = defineClass(name, b, 0, b.length);
149: } catch (Exception e) {
150: }
151:
152: return c;
153: }
154:
155: /**
156: * Fetches the class file of the specified class from the http
157: * server.
158: */
159: protected byte[] fetchClass(String classname) throws Exception {
160: byte[] b;
161: URL url = new URL("http", server, port, "/"
162: + classname.replace('.', '/') + ".class");
163: URLConnection con = url.openConnection();
164: con.connect();
165: int size = con.getContentLength();
166: InputStream s = con.getInputStream();
167: if (size <= 0)
168: b = readStream(s);
169: else {
170: b = new byte[size];
171: int len = 0;
172: do {
173: int n = s.read(b, len, size - len);
174: if (n < 0) {
175: s.close();
176: throw new IOException("the stream was closed: "
177: + classname);
178: }
179: len += n;
180: } while (len < size);
181: }
182:
183: s.close();
184: return b;
185: }
186:
187: private byte[] readStream(InputStream fin) throws IOException {
188: byte[] buf = new byte[4096];
189: int size = 0;
190: int len = 0;
191: do {
192: size += len;
193: if (buf.length - size <= 0) {
194: byte[] newbuf = new byte[buf.length * 2];
195: System.arraycopy(buf, 0, newbuf, 0, size);
196: buf = newbuf;
197: }
198:
199: len = fin.read(buf, size, buf.length - size);
200: } while (len >= 0);
201:
202: byte[] result = new byte[size];
203: System.arraycopy(buf, 0, result, 0, size);
204: return result;
205: }
206: }
|