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