/Users/lyon/j4p/src/javassist/web/Viewer.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 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.web; 
17    
18   import java.io.*; 
19   import java.net.*; 
20    
21   /** 
22    * An 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.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        */ 
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           } else 
64               System.err.println( 
65                       "Usage: java javassist.web.Viewer <host> <port> class [args ...]"); 
66       } 
67    
68       /** 
69        * Constructs a viewer. 
70        * 
71        * @param host              server name 
72        * @param p                 port number 
73        */ 
74       public Viewer(String host, int p) { 
75           server = host; 
76           port = p; 
77       } 
78    
79       /** 
80        * Returns the server name. 
81        */ 
82       public String getServer() { 
83           return server; 
84       } 
85    
86       /** 
87        * Returns the port number. 
88        */ 
89       public int getPort() { 
90           return port; 
91       } 
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        */ 
99       public void run(String classname, String[] args) 
100              throws Throwable { 
101          Class c = loadClass(classname); 
102          try { 
103              c.getDeclaredMethod("main", new Class[]{String[].class}) 
104                      .invoke(null, new Object[]{args}); 
105          } catch (java.lang.reflect.InvocationTargetException e) { 
106              throw e.getTargetException(); 
107          } 
108      } 
109   
110      /** 
111       * Requests the class loader to load a class. 
112       */ 
113      public synchronized Class loadClass(String name, boolean resolve) 
114              throws ClassNotFoundException { 
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       */ 
138      public Class findClass(String name) throws ClassNotFoundException { 
139          Class c = null; 
140          if (name.startsWith("java.") || name.startsWith("javax.") 
141                  || name.equals("javassist.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      public 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      public 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  } 
207