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