1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License.  Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */
15 
16 package javassist.tools.web;
17 
18 import java.io.*;
19 import java.net.*;
20 
21 /**
22  * A sample applet viewer.
23  *
24  * <p>This is a sort of applet viewer that can run any program even if
25  * the main class is not a subclass of <code>Applet</code>.
26  * This viewwer first calls <code>main()</code> in the main class.
27  *
28  * <p>To run, you should type:
29  *
30  * <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul>
31  *
32  * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code>
33  * All classes including <code>Main</code> are fetched from
34  * a server http://<i>host</i>:<i>port</i>.
35  * Only the class file for <code>Viewer</code> must exist
36  * on a local file system at the client side; even other
37  * <code>javassist.*</code> classes are not needed at the client side.
38  * <code>Viewer</code> uses only Java core API classes.
39  *
40  * <p>Note: since a <code>Viewer</code> object is a class loader,
41  * a program loaded by this object can call a method in <code>Viewer</code>.
42  * For example, you can write something like this:
43  *
44  * <ul><pre>
45  * Viewer v = (Viewer)this.getClass().getClassLoader();
46  * String port = v.getPort();
47  * </pre></ul>
48  *
49  */
50 public class Viewer extends ClassLoader {
51     private String server;
52     private int port;
53 
54     /**
55      * Starts a program.
56      */
main(String[] args)57     public static void main(String[] args) throws Throwable {
58         if (args.length >= 3) {
59             Viewer cl = new Viewer(args[0], Integer.parseInt(args[1]));
60             String[] args2 = new String[args.length - 3];
61             System.arraycopy(args, 3, args2, 0, args.length - 3);
62             cl.run(args[2], args2);
63         }
64         else
65             System.err.println(
66         "Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]");
67     }
68 
69     /**
70      * Constructs a viewer.
71      *
72      * @param host              server name
73      * @param p                 port number
74      */
Viewer(String host, int p)75     public Viewer(String host, int p) {
76         server = host;
77         port = p;
78     }
79 
80     /**
81      * Returns the server name.
82      */
getServer()83     public String getServer() { return server; }
84 
85     /**
86      * Returns the port number.
87      */
getPort()88     public int getPort() { return port; }
89 
90     /**
91      * Invokes main() in the class specified by <code>classname</code>.
92      *
93      * @param classname         executed class
94      * @param args              the arguments passed to <code>main()</code>.
95      */
run(String classname, String[] args)96     public void run(String classname, String[] args)
97         throws Throwable
98     {
99         Class c = loadClass(classname);
100         try {
101             c.getDeclaredMethod("main", new Class[] { String[].class })
102                 .invoke(null, new Object[] { args });
103         }
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      */
loadClass(String name, boolean resolve)112     protected synchronized Class loadClass(String name, boolean resolve)
113         throws ClassNotFoundException
114     {
115         Class c = findLoadedClass(name);
116         if (c == null)
117             c = findClass(name);
118 
119         if (c == null)
120             throw new ClassNotFoundException(name);
121 
122         if (resolve)
123             resolveClass(c);
124 
125         return c;
126     }
127 
128     /**
129      * Finds the specified class.  The implementation in this class
130      * fetches the class from the http server.  If the class is
131      * either <code>java.*</code>, <code>javax.*</code>, or
132      * <code>Viewer</code>, then it is loaded by the parent class
133      * loader.
134      *
135      * <p>This method can be overridden by a subclass of
136      * <code>Viewer</code>.
137      */
findClass(String name)138     protected Class findClass(String name) 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             }
150         catch (Exception e) {
151         }
152 
153         return c;
154     }
155 
156     /**
157      * Fetches the class file of the specified class from the http
158      * server.
159      */
fetchClass(String classname)160     protected byte[] fetchClass(String classname) throws Exception
161     {
162         byte[] b;
163         URL url = new URL("http", server, port,
164                           "/" + classname.replace('.', '/') + ".class");
165         URLConnection con = url.openConnection();
166         con.connect();
167         int size = con.getContentLength();
168         InputStream s = con.getInputStream();
169         if (size <= 0)
170             b = readStream(s);
171         else {
172             b = new byte[size];
173             int len = 0;
174             do {
175                 int n = s.read(b, len, size - len);
176                 if (n < 0) {
177                     s.close();
178                     throw new IOException("the stream was closed: "
179                                           + classname);
180                 }
181                 len += n;
182             } while (len < size);
183         }
184 
185         s.close();
186         return b;
187     }
188 
readStream(InputStream fin)189     private byte[] readStream(InputStream fin) throws IOException {
190         byte[] buf = new byte[4096];
191         int size = 0;
192         int len = 0;
193         do {
194             size += len;
195             if (buf.length - size <= 0) {
196                 byte[] newbuf = new byte[buf.length * 2];
197                 System.arraycopy(buf, 0, newbuf, 0, size);
198                 buf = newbuf;
199             }
200 
201             len = fin.read(buf, size, buf.length - size);
202         } while (len >= 0);
203 
204         byte[] result = new byte[size];
205         System.arraycopy(buf, 0, result, 0, size);
206         return result;
207     }
208 }
209