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