]> source.dussan.org Git - javassist.git/commitdiff
restructred sub packages
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Wed, 11 Jan 2006 06:06:30 +0000 (06:06 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Wed, 11 Jan 2006 06:06:30 +0000 (06:06 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@233 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

80 files changed:
Readme.html
build.xml
sample/duplicate/DuplicatedObject.java
sample/duplicate/Main.java
sample/evolve/DemoServer.java
sample/evolve/Evolution.java
sample/evolve/VersionManager.java
sample/hotswap/Test.java
sample/reflect/Main.java
sample/reflect/Person.java
sample/reflect/VerboseMetaobj.java
sample/rmi/CountApplet.java
sample/rmi/Counter.java
sample/rmi/start.html
sample/rmi/webdemo.html
src/main/javassist/CtClass.java
src/main/javassist/CtMethod.java
src/main/javassist/bytecode/Bytecode.java
src/main/javassist/bytecode/Descriptor.java
src/main/javassist/bytecode/annotation/package.html
src/main/javassist/expr/MethodCall.java
src/main/javassist/reflect/CannotCreateException.java [deleted file]
src/main/javassist/reflect/CannotInvokeException.java [deleted file]
src/main/javassist/reflect/CannotReflectException.java [deleted file]
src/main/javassist/reflect/ClassMetaobject.java [deleted file]
src/main/javassist/reflect/Compiler.java [deleted file]
src/main/javassist/reflect/Loader.java [deleted file]
src/main/javassist/reflect/Metalevel.java [deleted file]
src/main/javassist/reflect/Metaobject.java [deleted file]
src/main/javassist/reflect/Reflection.java [deleted file]
src/main/javassist/reflect/Sample.java [deleted file]
src/main/javassist/reflect/package.html [deleted file]
src/main/javassist/rmi/AppletServer.java [deleted file]
src/main/javassist/rmi/ObjectImporter.java [deleted file]
src/main/javassist/rmi/ObjectNotFoundException.java [deleted file]
src/main/javassist/rmi/Proxy.java [deleted file]
src/main/javassist/rmi/RemoteException.java [deleted file]
src/main/javassist/rmi/RemoteRef.java [deleted file]
src/main/javassist/rmi/Sample.java [deleted file]
src/main/javassist/rmi/StubGenerator.java [deleted file]
src/main/javassist/rmi/package.html [deleted file]
src/main/javassist/tools/HotSwapper.java [deleted file]
src/main/javassist/tools/package.html
src/main/javassist/tools/reflect/CannotCreateException.java [new file with mode: 0644]
src/main/javassist/tools/reflect/CannotInvokeException.java [new file with mode: 0644]
src/main/javassist/tools/reflect/CannotReflectException.java [new file with mode: 0644]
src/main/javassist/tools/reflect/ClassMetaobject.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Compiler.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Loader.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Metalevel.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Metaobject.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Reflection.java [new file with mode: 0644]
src/main/javassist/tools/reflect/Sample.java [new file with mode: 0644]
src/main/javassist/tools/reflect/package.html [new file with mode: 0644]
src/main/javassist/tools/rmi/AppletServer.java [new file with mode: 0644]
src/main/javassist/tools/rmi/ObjectImporter.java [new file with mode: 0644]
src/main/javassist/tools/rmi/ObjectNotFoundException.java [new file with mode: 0644]
src/main/javassist/tools/rmi/Proxy.java [new file with mode: 0644]
src/main/javassist/tools/rmi/RemoteException.java [new file with mode: 0644]
src/main/javassist/tools/rmi/RemoteRef.java [new file with mode: 0644]
src/main/javassist/tools/rmi/Sample.java [new file with mode: 0644]
src/main/javassist/tools/rmi/StubGenerator.java [new file with mode: 0644]
src/main/javassist/tools/rmi/package.html [new file with mode: 0644]
src/main/javassist/tools/web/BadHttpRequest.java [new file with mode: 0644]
src/main/javassist/tools/web/Viewer.java [new file with mode: 0644]
src/main/javassist/tools/web/Webserver.java [new file with mode: 0644]
src/main/javassist/tools/web/package.html [new file with mode: 0644]
src/main/javassist/util/HotSwapper.java [new file with mode: 0644]
src/main/javassist/util/package.html [new file with mode: 0644]
src/main/javassist/util/proxy/FactoryHelper.java [new file with mode: 0644]
src/main/javassist/util/proxy/MethodFilter.java [new file with mode: 0644]
src/main/javassist/util/proxy/MethodHandler.java [new file with mode: 0644]
src/main/javassist/util/proxy/ProxyFactory.java [new file with mode: 0644]
src/main/javassist/util/proxy/ProxyObject.java [new file with mode: 0644]
src/main/javassist/util/proxy/RuntimeSupport.java [new file with mode: 0644]
src/main/javassist/util/proxy/package.html [new file with mode: 0644]
src/main/javassist/web/BadHttpRequest.java [deleted file]
src/main/javassist/web/Viewer.java [deleted file]
src/main/javassist/web/Webserver.java [deleted file]
src/main/javassist/web/package.html [deleted file]

index 4699d7152d8cc1fe4b08316f703f351c3544e741..9c88637d573ca3812876013e53cac2cc2e099b64 100644 (file)
@@ -137,7 +137,7 @@ set CLASSPATH=.;javassist.jar
 
 <ul><pre>
 % javac sample/reflect/*.java
-% java javassist.reflect.Loader sample.reflect.Main Joe
+% java javassist.tools.reflect.Loader sample.reflect.Main Joe
 </pre></ul>
 
 <p>Compare this result with that of the regular execution without reflection:
@@ -151,7 +151,7 @@ set CLASSPATH=.;javassist.jar
    To do this, type the commands:
 
 <ul><pre>
-% java javassist.reflect.Compiler sample.reflect.Person -m sample.reflect.VerboseMetaobj
+% java javassist.tools.reflect.Compiler sample.reflect.Person -m sample.reflect.VerboseMetaobj
 </pre></ul>
 
 <p>   Then,
@@ -292,14 +292,18 @@ see javassist.Dump.
   <li>The return type of CtClass.stopPruning() was changed from void
     to boolean.
   <li>toMethod() in javassist.CtConstructor has been implemented.
-  <li>javassist.preproc package was elminated and the source was
-      moved to the sample directory.
-</ul>
-
-<p>- version 3.1
-
-<ul>
-  <li>javassist.tool package was renamed to javassist.tools.
+  <li>It includes new javassist.util.proxy package
+      similar to Enhancer of CGLIB.
+
+  <p>
+  <li>The subpackages of Javassist were restructured.
+  <ul>
+    <li>javassist.tool package was renamed to javassist.tools.
+    <li>HotSwapper was moved to javassist.util.
+    <li>Several subpackages were moved to javassist.tools.
+    <li>javassist.preproc package was elminated and the source was
+        moved to the sample directory.
+  </ul>
 </ul>
 
 <p>- version 3.1 RC2 in September 7, 2005
index b7562364e6152dac47034c099d486c4db1211769..1f78b28ac1e35db7302fe2146ff9cb511e7e7d96 100644 (file)
--- a/build.xml
+++ b/build.xml
@@ -109,18 +109,18 @@ to ${build.classes.dir}.</echo>
            excludepackagenames="javassist.compiler.*,javassist.convert.*"
            sourcepath="src/main"
            defaultexcludes="yes"
+           locale="en_US"
+           charset="iso-8859-1"
            destdir="html"
            author="true"
            version="true"
            use="true"
-           Locale="en_US"
-           charset="iso-8859-1"
-           Public="true"
+           public="true"
            nohelp="true"
            windowtitle="Javassist API">
       <doctitle><![CDATA[<h1>Javassist</h1>]]></doctitle>
       <bottom><![CDATA[<i>Javassist, a Java-bytecode translator toolkit. 
-Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
+Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
     </javadoc>
   </target>
 
@@ -151,7 +151,8 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
 
   <target name = "sample-all"
           depends="sample-test,sample-reflect,sample-duplicate,sample-vector">
-    <echo>** please run sample-rmi and sample-evolve separately **</echo>
+    <echo>** please run sample-rmi, sample-evolve, and</echo>
+    <echo>   sample-hotswap (or -hotswap5) separately **</echo>
   </target>
 
   <target name = "sample-test" depends="sample" >
@@ -161,7 +162,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
   </target>
 
   <target name = "sample-reflect" depends="sample" >
-    <java fork="true" dir="${run.dir}" classname="javassist.reflect.Loader">
+    <java fork="true" dir="${run.dir}" classname="javassist.tools.reflect.Loader">
       <classpath refid="classpath"/>
       <arg line="sample.reflect.Main Joe" />
     </java>
@@ -212,6 +213,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
   <!-- for JDK 1.4 -->
   <target name = "sample-hotswap" depends="sample">
     <echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo>
+    <echo>** for JDK 1.4</echo>
     <java fork="true" dir="${run.dir}" classname="Test">
       <jvmarg line="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000" />
       <classpath refid="classpath"/>
@@ -221,6 +223,7 @@ Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.</i>]]></bottom>
   <!-- for Java 5 -->
   <target name = "sample-hotswap5" depends="sample">
     <echo>** JAVA_HOME/lib/tools.jar must be included in CLASS_PATH</echo>
+    <echo>** for JDK 1.5 or later</echo>
     <java fork="true" dir="${run.dir}" classname="Test">
       <jvmarg line="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000" />
       <classpath refid="classpath"/>
index 5995abccb24253a37eec54062bc73d3a3208060a..7161493c9512edda71d301531e942a79b9d7d42f 100644 (file)
@@ -1,6 +1,6 @@
 package sample.duplicate;\r
 \r
-import javassist.reflect.*;\r
+import javassist.tools.reflect.*;\r
 \r
 public class DuplicatedObject extends Metaobject {\r
     private DuplicatedObject backup;\r
index e152a23e1e2d6ab20219512d510617ba4644595f..064f13cd6493fef7502d77c3fefee2a6a871df6e 100644 (file)
@@ -3,7 +3,7 @@ package sample.duplicate;
 /*\r
   Runtime metaobject (JDK 1.2 or later only).\r
 \r
-  With the javassist.reflect package, the users can attach a metaobject\r
+  With the javassist.tools.reflect package, the users can attach a metaobject\r
   to an object.  The metaobject can control the behavior of the object.\r
   For example, you can implement fault tolerancy with this ability.  One\r
   of the implementation techniques of fault tolernacy is to make a copy\r
@@ -30,15 +30,15 @@ package sample.duplicate;
   % java sample.duplicate.Main\r
 \r
   You would see two balls in a window.  This is because\r
-  sample.duplicate.Viewer is loaded by javassist.reflect.Loader so that\r
+  sample.duplicate.Viewer is loaded by javassist.tools.reflect.Loader so that\r
   a metaobject would be attached.\r
 */\r
 public class Main {\r
     public static void main(String[] args) throws Throwable {\r
-       javassist.reflect.Loader cl = new javassist.reflect.Loader();\r
+       javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader();\r
        cl.makeReflective("sample.duplicate.Ball",\r
                          "sample.duplicate.DuplicatedObject",\r
-                         "javassist.reflect.ClassMetaobject");\r
+                         "javassist.tools.reflect.ClassMetaobject");\r
        cl.run("sample.duplicate.Viewer", args);\r
     }\r
 }\r
index dd64c55070fe7ef3ab5cbdca8e350a06a2212618..b334bccb2f4de568cda5cdb7e015246889ed38ca 100644 (file)
@@ -1,6 +1,6 @@
 package sample.evolve;\r
 \r
-import javassist.web.*;\r
+import javassist.tools.web.*;\r
 import java.io.*;\r
 \r
 /**\r
index ecae09212b6f184880ba94aa692a686f403a5d71..e804ff46c2436571432b71f79135c373a367cf04 100644 (file)
@@ -60,9 +60,9 @@ public class Evolution implements Translator {
     private void onLoadUpdatable(String classname) throws NotFoundException,\r
             CannotCompileException {\r
         // if the class is a concrete class,\r
-        // classname is <updatableClassName>$<version>.\r
+        // classname is <updatableClassName>$$<version>.\r
 \r
-        int i = classname.lastIndexOf('$');\r
+        int i = classname.lastIndexOf("$$");\r
         if (i <= 0)\r
             return;\r
 \r
@@ -72,7 +72,7 @@ public class Evolution implements Translator {
 \r
         int version;\r
         try {\r
-            version = Integer.parseInt(classname.substring(i + 1));\r
+            version = Integer.parseInt(classname.substring(i + 2));\r
         }\r
         catch (NumberFormatException e) {\r
             throw new NotFoundException(classname, e);\r
index 184397fd39c595b200daeec937501d3ff3381b02..efecee1961bf8c89d295500b781f270aed58db88 100644 (file)
@@ -41,7 +41,7 @@ public class VersionManager {
         else\r
             version = ((Integer)found).intValue() + 1;\r
 \r
-        Class c = Class.forName(qualifiedClassname + '$' + version);\r
+        Class c = Class.forName(qualifiedClassname + "$$" + version);\r
         versionNo.put(qualifiedClassname, new Integer(version));\r
         return c;\r
     }\r
index e15afc9a578861e6cfe44ba7fe7dffa381b1730b..651d21849b6cc1e398aba7b0321a2b3327613742 100644 (file)
@@ -1,5 +1,5 @@
 import java.io.*;
-import javassist.tools.HotSwapper;
+import javassist.util.HotSwapper;
 
 public class Test {
     public static void main(String[] args) throws Exception {
index d9733abc0df6b154981a99fdbce0fc3ca02313a2..972e8964d0f4104e9e14239a57ddbcebce59eeba 100644 (file)
@@ -1,6 +1,6 @@
 package sample.reflect;\r
 \r
-import javassist.reflect.Loader;\r
+import javassist.tools.reflect.Loader;\r
 \r
 /*\r
   The "verbose metaobject" example (JDK 1.2 or later only).\r
@@ -14,7 +14,7 @@ import javassist.reflect.Loader;
 \r
   To run,\r
 \r
-  % java javassist.reflect.Loader sample.reflect.Main Joe\r
+  % java javassist.tools.reflect.Loader sample.reflect.Main Joe\r
 \r
   Compare this result with that of the regular execution without reflection:\r
 \r
@@ -25,7 +25,7 @@ public class Main {
         Loader cl = (Loader)Main.class.getClassLoader();\r
         cl.makeReflective("sample.reflect.Person",\r
                           "sample.reflect.VerboseMetaobj",\r
-                          "javassist.reflect.ClassMetaobject");\r
+                          "javassist.tools.reflect.ClassMetaobject");\r
 \r
         cl.run("sample.reflect.Person", args);\r
     }\r
index 445d38078b354bc87989f276b8e8c6afa68e69d3..90ccb18f6d48b7ffafabac39cd29384d6db048e2 100644 (file)
@@ -4,8 +4,8 @@
 \r
 package sample.reflect;\r
 \r
-import javassist.reflect.Metalevel;\r
-import javassist.reflect.Metaobject;\r
+import javassist.tools.reflect.Metalevel;\r
+import javassist.tools.reflect.Metaobject;\r
 \r
 public class Person {\r
     public String name;\r
index 91dba579f41c4a194ba76064f0f4602aaae4818d..cc47999ce73c3a36a4e6c01ce8971a9ee2a6cd7a 100644 (file)
@@ -1,6 +1,6 @@
 package sample.reflect;\r
 \r
-import javassist.reflect.*;\r
+import javassist.tools.reflect.*;\r
 \r
 public class VerboseMetaobj extends Metaobject {\r
     public VerboseMetaobj(Object self, Object[] args) {\r
index 0bebdaf9291dddd0b1a783c35a6e3f659d385bf3..e4ee0ee2ee96b8a0cda269603a46399a381ebd6e 100644 (file)
@@ -3,9 +3,9 @@ package sample.rmi;
 import java.applet.*;\r
 import java.awt.*;\r
 import java.awt.event.*;\r
-import javassist.rmi.ObjectImporter;\r
-import javassist.rmi.ObjectNotFoundException;\r
-import javassist.web.Viewer;\r
+import javassist.tools.rmi.ObjectImporter;\r
+import javassist.tools.rmi.ObjectNotFoundException;\r
+import javassist.tools.web.Viewer;\r
 \r
 public class CountApplet extends Applet implements ActionListener {\r
     private Font font;\r
index f8a0fcf58feb246d834b5a535e7e4ee893fa3b88..0920ca735c3281a3dca68898e65f5dc53170187f 100644 (file)
@@ -1,6 +1,6 @@
 package sample.rmi;\r
 \r
-import javassist.rmi.AppletServer;\r
+import javassist.tools.rmi.AppletServer;\r
 import java.io.IOException;\r
 import javassist.CannotCompileException;\r
 import javassist.NotFoundException;\r
index 696b629c7d24160f005cd8683f6d5513bfc755a2..33321ad1b71e14988b54e1a0c8fd97276e219791 100644 (file)
@@ -12,4 +12,4 @@ Start!
 \r
 <p>If you don't want to use a web browser, do as follows:\r
 \r
-<ul><pre>% java javassist.web.Viewer localhost 5001 sample.rmi.CountApplet</pre></ul>\r
+<ul><pre>% java javassist.tools.web.Viewer localhost 5001 sample.rmi.CountApplet</pre></ul>\r
index d313ec3c475206fa2a8cf9f36f69619d89c41f00..a2b595ce6fb14ffd32e1a029d6ee5eff224f1dee 100644 (file)
@@ -6,7 +6,7 @@
 local object.  The applet can communicate through a socket with the\r
 host that executes the web server distributing that applet.  However,\r
 the applet cannot directly call a method on an object if the object is\r
-on a remote host.  The <code>javassist.rmi</code> package provides\r
+on a remote host.  The <code>javassist.tools.rmi</code> package provides\r
 a mechanism for the applet to transparently access the remote object.\r
 The rules that the applet must be subject to are simpler than the\r
 standard Java RMI.\r
@@ -36,7 +36,7 @@ Look at the lines shown with red:
 <p><b>Figure 1: Applet</b>\r
 \r
 <pre>\r
-<font color="red">import javassist.rmi.ObjectImporter;</font>\r
+<font color="red">import javassist.tools.rmi.ObjectImporter;</font>\r
 \r
 public class CountApplet extends Applet implements ActionListener {\r
   private Font font;\r
@@ -106,7 +106,7 @@ public class Counter {
 }\r
 </pre>\r
 \r
-<p>Note that the <code>javassist.rmi</code> package does not require\r
+<p>Note that the <code>javassist.tools.rmi</code> package does not require\r
 the <code>Counter</code> class to be an interface unlike the Java RMI,\r
 with which <code>Counter</code> must be an interface and it must be\r
 implemented by another class.\r
@@ -167,7 +167,7 @@ following features:
 <p> With the Java RMI or Voyager, the applet programmer must define\r
 an interface for every remote object class and access the remote object\r
 through that interface.\r
-On the other hand, the <code>javassist.rmi</code> package does not\r
+On the other hand, the <code>javassist.tools.rmi</code> package does not\r
 require the programmer to follow that programming convention.\r
 It is suitable for writing simple distributed programs like applets.\r
 \r
index 74ab0d3e9d498642e59b1051a6aded866a3b8494..d4178e7f9aa1bff67e34569fac50ac2e32417191 100644 (file)
@@ -703,7 +703,7 @@ public abstract class CtClass {
      *
      * @param name      method name
      * @param desc      method descriptor
-     * @see CtBehavior.getSignature()
+     * @see CtBehavior#getSignature()
      * @see javassist.bytecode.Descriptor
      */
     public CtMethod getMethod(String name, String desc)
index 043c8d3bf0c24c25edc72be59d4ba08bd270ba65..abb42b88d7eadcdf2f3b4e62820954622d044000 100644 (file)
@@ -118,7 +118,7 @@ public final class CtMethod extends CtBehavior {
      *
      * @param src               the source text. 
      * @param declaring    the class to which the created method is added.
-     * @see CtNewMethod.make(String, CtClass)
+     * @see CtNewMethod#make(String, CtClass)
      */
     public static CtMethod make(String src, CtClass declaring)
         throws CannotCompileException
index a1f74c6dac6e1321406ccf30875339815da57034..b2a0ee23b471f73753ac1d66fc6c936a65db31da 100644 (file)
@@ -1339,7 +1339,7 @@ public class Bytecode extends ByteVector implements Cloneable, Opcode {
      * Appends PUTSTATIC.
      *
      * @param classname         the fully-qualified name of the target class.
-     * @param filedName         the field name.
+     * @param fieldName         the field name.
      * @param desc              the descriptor of the field type.
      */
     public void addPutstatic(String classname, String fieldName, String desc) {
index ef194b7f4248cd3034e04711ba821927a334419a..39577ce286db9527de02640ab7778faa909e37c4 100644 (file)
@@ -717,7 +717,6 @@ public class Descriptor {
 
         /**
          * Returns the first character of the current element.
-         * @return
          */
         public char currentChar() { return desc.charAt(curPos); }
 
index 6cf7e53802a0252921e24a3a4e1f0f4fb79aa238..d0656db6c3d49a5e2ccb539b55bd31a1e3d92119 100644 (file)
@@ -1,6 +1,6 @@
 <html>
 <body>
-Annotations API.
+Bytecode-level Annotations API.
 
 <p>This package provides low-level API for editing annotations attributes.
 
index 7bc2c388cc78b6c941edafe33326cb6b256f1e9b..9fd29e2a6235967e64166724d0704526e0e4c3ca 100644 (file)
@@ -120,7 +120,7 @@ public class MethodCall extends Expr {
      * The method signature is represented by a character string
      * called method descriptor, which is defined in the JVM specification.
      *
-     * @see javassist.CtBehavior.getSignature()
+     * @see javassist.CtBehavior#getSignature()
      * @see javassist.bytecode.Descriptor
      * @since 3.1
      */
diff --git a/src/main/javassist/reflect/CannotCreateException.java b/src/main/javassist/reflect/CannotCreateException.java
deleted file mode 100644 (file)
index a093383..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-/**
- * Signals that <code>ClassMetaobject.newInstance()</code> fails.
- */
-public class CannotCreateException extends Exception {
-    public CannotCreateException(String s) {
-        super(s);
-    }
-
-    public CannotCreateException(Exception e) {
-        super("by " + e.toString());
-    }
-}
diff --git a/src/main/javassist/reflect/CannotInvokeException.java b/src/main/javassist/reflect/CannotInvokeException.java
deleted file mode 100644 (file)
index c778e89..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.IllegalAccessException;
-
-/**
- * Thrown when method invocation using the reflection API has thrown
- * an exception.
- *
- * @see javassist.reflect.Metaobject#trapMethodcall(int, Object[])
- * @see javassist.reflect.ClassMetaobject#trapMethodcall(int, Object[])
- * @see javassist.reflect.ClassMetaobject#invoke(Object, int, Object[])
- */
-public class CannotInvokeException extends RuntimeException {
-
-    private Throwable err = null;
-
-    /**
-     * Returns the cause of this exception.  It may return null.
-     */
-    public Throwable getReason() { return err; }
-
-    /**
-     * Constructs a CannotInvokeException with an error message.
-     */
-    public CannotInvokeException(String reason) {
-        super(reason);
-    }
-
-    /**
-     * Constructs a CannotInvokeException with an InvocationTargetException.
-     */
-    public CannotInvokeException(InvocationTargetException e) {
-        super("by " + e.getTargetException().toString());
-        err = e.getTargetException();
-    }
-
-    /**
-     * Constructs a CannotInvokeException with an IllegalAccessException.
-     */
-    public CannotInvokeException(IllegalAccessException e) {
-        super("by " + e.toString());
-        err = e;
-    }
-
-    /**
-     * Constructs a CannotInvokeException with an ClassNotFoundException.
-     */
-    public CannotInvokeException(ClassNotFoundException e) {
-        super("by " + e.toString());
-        err = e;
-    }
-}
diff --git a/src/main/javassist/reflect/CannotReflectException.java b/src/main/javassist/reflect/CannotReflectException.java
deleted file mode 100644 (file)
index 036ebf4..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import javassist.CannotCompileException;
-
-/**
- * Thrown by <code>makeReflective()</code> in <code>Reflection</code>
- * when there is an attempt to reflect
- * a class that is either an interface or a subclass of
- * either ClassMetaobject or Metaobject.
- *
- * @author Brett Randall
- * @see javassist.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass)
- * @see javassist.CannotCompileException
- */
-public class CannotReflectException extends CannotCompileException {
-    public CannotReflectException(String msg) {
-        super(msg);
-    }
-}
diff --git a/src/main/javassist/reflect/ClassMetaobject.java b/src/main/javassist/reflect/ClassMetaobject.java
deleted file mode 100644 (file)
index 6132845..0000000
+++ /dev/null
@@ -1,367 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import java.lang.reflect.*;
-import java.util.Arrays;
-import java.io.Serializable;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-/**
- * A runtime class metaobject.
- *
- * <p>A <code>ClassMetaobject</code> is created for every
- * class of reflective objects.  It can be used to hold values
- * shared among the reflective objects of the same class.
- *
- * <p>To obtain a class metaobject, calls <code>_getClass()</code>
- * on a reflective object.  For example,
- *
- * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
- * </pre></ul>
- *
- * @see javassist.reflect.Metaobject
- * @see javassist.reflect.Metalevel
- */
-public class ClassMetaobject implements Serializable {
-    /**
-     * The base-level methods controlled by a metaobject
-     * are renamed so that they begin with
-     * <code>methodPrefix "_m_"</code>.
-     */
-    static final String methodPrefix = "_m_";
-    static final int methodPrefixLen = 3;
-
-    private Class javaClass;
-    private Constructor[] constructors;
-    private Method[] methods;
-
-    /**
-     * Specifies how a <code>java.lang.Class</code> object is loaded.
-     *
-     * <p>If true, it is loaded by:
-     * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
-     * <p>If false, it is loaded by <code>Class.forName()</code>.
-     * The default value is false.
-     */
-    public static boolean useContextClassLoader = false;
-
-    /**
-     * Constructs a <code>ClassMetaobject</code>.
-     *
-     * @param params    <code>params[0]</code> is the name of the class
-     *                  of the reflective objects.
-     */
-    public ClassMetaobject(String[] params)
-    {
-        try {
-            javaClass = getClassObject(params[0]);
-        }
-        catch (ClassNotFoundException e) {
-            javaClass = null;
-        }
-
-        constructors = javaClass.getConstructors();
-        methods = null;
-    }
-
-    private void writeObject(ObjectOutputStream out) throws IOException {
-        out.writeUTF(javaClass.getName());
-    }
-
-    private void readObject(ObjectInputStream in)
-        throws IOException, ClassNotFoundException
-    {
-        javaClass = getClassObject(in.readUTF());
-        constructors = javaClass.getConstructors();
-        methods = null;
-    }
-
-    private Class getClassObject(String name) throws ClassNotFoundException {
-        if (useContextClassLoader)
-            return Thread.currentThread().getContextClassLoader()
-                   .loadClass(name);
-        else
-            return Class.forName(name);
-    }
-
-    /**
-     * Obtains the <code>java.lang.Class</code> representing this class.
-     */
-    public final Class getJavaClass() {
-        return javaClass;
-    }
-
-    /**
-     * Obtains the name of this class.
-     */
-    public final String getName() {
-        return javaClass.getName();
-    }
-
-    /**
-     * Returns true if <code>obj</code> is an instance of this class.
-     */
-    public final boolean isInstance(Object obj) {
-        return javaClass.isInstance(obj);
-    }
-
-    /**
-     * Creates a new instance of the class.
-     *
-     * @param args              the arguments passed to the constructor.
-     */
-    public final Object newInstance(Object[] args)
-        throws CannotCreateException
-    {
-        int n = constructors.length;
-        for (int i = 0; i < n; ++i) {
-            try {
-                return constructors[i].newInstance(args);
-            }
-            catch (IllegalArgumentException e) {
-                // try again
-            }
-            catch (InstantiationException e) {
-                throw new CannotCreateException(e);
-            }
-            catch (IllegalAccessException e) {
-                throw new CannotCreateException(e);
-            }
-            catch (InvocationTargetException e) {
-                throw new CannotCreateException(e);
-            }
-        }
-
-        throw new CannotCreateException("no constructor matches");
-    }
-
-    /**
-     * Is invoked when <code>static</code> fields of the base-level
-     * class are read and the runtime system intercepts it.
-     * This method simply returns the value of the field.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     */
-    public Object trapFieldRead(String name) {
-        Class jc = getJavaClass();
-        try {
-            return jc.getField(name).get(null);
-        }
-        catch (NoSuchFieldException e) {
-            throw new RuntimeException(e.toString());
-        }
-        catch (IllegalAccessException e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Is invoked when <code>static</code> fields of the base-level
-     * class are modified and the runtime system intercepts it.
-     * This method simply sets the field to the given value.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     */
-    public void trapFieldWrite(String name, Object value) {
-        Class jc = getJavaClass();
-        try {
-            jc.getField(name).set(null, value);
-        }
-        catch (NoSuchFieldException e) {
-            throw new RuntimeException(e.toString());
-        }
-        catch (IllegalAccessException e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Invokes a method whose name begins with
-     * <code>methodPrefix "_m_"</code> and the identifier.
-     *
-     * @exception CannotInvokeException         if the invocation fails.
-     */
-    static public Object invoke(Object target, int identifier, Object[] args)
-        throws Throwable
-    {
-        Method[] allmethods = target.getClass().getMethods();
-        int n = allmethods.length;
-        String head = methodPrefix + identifier;
-        for (int i = 0; i < n; ++i)
-            if (allmethods[i].getName().startsWith(head)) {
-                try {
-                    return allmethods[i].invoke(target, args);
-                } catch (java.lang.reflect.InvocationTargetException e) {
-                    throw e.getTargetException();
-                } catch (java.lang.IllegalAccessException e) {
-                    throw new CannotInvokeException(e);
-                }
-            }
-
-        throw new CannotInvokeException("cannot find a method");
-    }
-
-    /**
-     * Is invoked when <code>static</code> methods of the base-level
-     * class are called and the runtime system intercepts it.
-     * This method simply executes the intercepted method invocation
-     * with the original parameters and returns the resulting value.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     */
-    public Object trapMethodcall(int identifier, Object[] args) 
-        throws Throwable
-    {
-        try {
-            Method[] m = getReflectiveMethods();
-            return m[identifier].invoke(null, args);
-        }
-        catch (java.lang.reflect.InvocationTargetException e) {
-            throw e.getTargetException();
-        }
-        catch (java.lang.IllegalAccessException e) {
-            throw new CannotInvokeException(e);
-        }
-    }
-
-    /**
-     * Returns an array of the methods defined on the given reflective
-     * object.  This method is for the internal use only.
-     */
-    public final Method[] getReflectiveMethods() {
-        if (methods != null)
-            return methods;
-
-        Class baseclass = getJavaClass();
-        Method[] allmethods = baseclass.getDeclaredMethods();
-        int n = allmethods.length;
-        int[] index = new int[n];
-        int max = 0;
-        for (int i = 0; i < n; ++i) {
-            Method m = allmethods[i];
-            String mname = m.getName();
-            if (mname.startsWith(methodPrefix)) {
-                int k = 0;
-                for (int j = methodPrefixLen;; ++j) {
-                    char c = mname.charAt(j);
-                    if ('0' <= c && c <= '9')
-                        k = k * 10 + c - '0';
-                    else
-                        break;
-                }
-
-                index[i] = ++k;
-                if (k > max)
-                    max = k;
-            }
-        }
-
-        methods = new Method[max];
-        for (int i = 0; i < n; ++i)
-            if (index[i] > 0)
-                methods[index[i] - 1] = allmethods[i];
-
-        return methods;
-    }
-
-    /**
-     * Returns the <code>java.lang.reflect.Method</code> object representing
-     * the method specified by <code>identifier</code>.
-     *
-     * <p>Note that the actual method returned will be have an altered,
-     * reflective name i.e. <code>_m_2_..</code>.
-     *
-     * @param identifier        the identifier index
-     *                          given to <code>trapMethodcall()</code> etc.
-     * @see Metaobject#trapMethodcall(int,Object[])
-     * @see #trapMethodcall(int,Object[])
-     */
-    public final Method getMethod(int identifier) {
-        return getReflectiveMethods()[identifier];
-    }
-
-    /**
-     * Returns the name of the method specified
-     * by <code>identifier</code>.
-     */
-    public final String getMethodName(int identifier) {
-        String mname = getReflectiveMethods()[identifier].getName();
-        int j = ClassMetaobject.methodPrefixLen;
-        for (;;) {
-            char c = mname.charAt(j++);
-            if (c < '0' || '9' < c)
-                break;
-        }
-
-        return mname.substring(j);
-    }
-
-    /**
-     * Returns an array of <code>Class</code> objects representing the
-     * formal parameter types of the method specified
-     * by <code>identifier</code>.
-     */
-    public final Class[] getParameterTypes(int identifier) {
-        return getReflectiveMethods()[identifier].getParameterTypes();
-    }
-
-    /**
-     * Returns a <code>Class</code> objects representing the
-     * return type of the method specified by <code>identifier</code>.
-     */
-    public final Class getReturnType(int identifier) {
-        return getReflectiveMethods()[identifier].getReturnType();
-    }
-
-    /**
-     * Returns the identifier index of the method, as identified by its
-     * original name.
-     *
-     * <p>This method is useful, in conjuction with
-     * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
-     * to the original method in the reflected class (i.e. not the proxy
-     * method), using the original name of the method.
-     *
-     * <p>Written by Brett Randall and Shigeru Chiba. 
-     *
-     * @param originalName      The original name of the reflected method
-     * @param argTypes          array of Class specifying the method signature
-     * @return      the identifier index of the original method
-     * @throws NoSuchMethodException    if the method does not exist
-     * 
-     * @see ClassMetaobject#getMethod(int)
-     */
-    public final int getMethodIndex(String originalName, Class[] argTypes)
-        throws NoSuchMethodException
-    {
-        Method[] mthds = getReflectiveMethods();
-        for (int i = 0; i < mthds.length; i++) {
-            if (mthds[i] == null)
-                continue;
-
-            // check name and parameter types match
-            if (getMethodName(i).equals(originalName)
-                && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
-                return i;
-        }
-
-        throw new NoSuchMethodException("Method " + originalName
-                                        + " not found");
-    }
-}
diff --git a/src/main/javassist/reflect/Compiler.java b/src/main/javassist/reflect/Compiler.java
deleted file mode 100644 (file)
index 734f598..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import javassist.CtClass;
-import javassist.ClassPool;
-import java.io.PrintStream;
-
-class CompiledClass {
-    public String classname;
-    public String metaobject;
-    public String classobject;
-}
-
-/**
- * A bytecode translator for reflection.
- *
- * <p>This translator directly modifies class files on a local disk so that
- * the classes represented by those class files are reflective.
- * After the modification, the class files can be run with the standard JVM
- * without <code>javassist.reflect.Loader</code>
- * or any other user-defined class loader.
- *
- * <p>The modified class files are given as the command-line parameters,
- * which are a sequence of fully-qualified class names followed by options:
- *
- * <p><code>-m <i>classname</i></code> : specifies the class of the
- * metaobjects associated with instances of the class followed by
- * this option.  The default is <code>javassit.reflect.Metaobject</code>.
- *
- * <p><code>-c <i>classname</i></code> : specifies the class of the
- * class metaobjects associated with instances of the class followed by
- * this option.  The default is <code>javassit.reflect.ClassMetaobject</code>.
- *
- * <p>If a class name is not followed by any options, the class indicated
- * by that class name is not reflective.
- * 
- * <p>For example,
- * <ul><pre>% java Compiler Dog -m MetaDog -c CMetaDog Cat -m MetaCat Cow
- * </pre></ul>
- *
- * <p>modifies class files <code>Dog.class</code>, <code>Cat.class</code>,
- * and <code>Cow.class</code>.
- * The metaobject of a Dog object is a MetaDog object and the class
- * metaobject is a CMetaDog object.
- * The metaobject of a Cat object is a MetaCat object but
- * the class metaobject is a default one.
- * Cow objects are not reflective.
- *
- * <p>Note that if the super class is also made reflective, it must be done
- * before the sub class.
- *
- * @see javassist.reflect.Metaobject
- * @see javassist.reflect.ClassMetaobject
- * @see javassist.reflect.Reflection
- */
-public class Compiler {
-
-    public static void main(String[] args) throws Exception {
-        if (args.length == 0) {
-            help(System.err);
-            return;
-        }
-
-        CompiledClass[] entries = new CompiledClass[args.length];
-        int n = parse(args, entries);
-
-        if (n < 1) {
-            System.err.println("bad parameter.");
-            return;
-        }
-
-        processClasses(entries, n);
-    }
-
-    private static void processClasses(CompiledClass[] entries, int n)
-        throws Exception
-    {
-        Reflection implementor = new Reflection();
-        ClassPool pool = ClassPool.getDefault();
-        implementor.start(pool);
-
-        for (int i = 0; i < n; ++i) {
-            CtClass c = pool.get(entries[i].classname);
-            if (entries[i].metaobject != null
-                                        || entries[i].classobject != null) {
-                String metaobj, classobj;
-
-                if (entries[i].metaobject == null)
-                    metaobj = "javassist.reflect.Metaobject";
-                else
-                    metaobj = entries[i].metaobject;
-
-                if (entries[i].classobject == null)
-                    classobj = "javassist.reflect.ClassMetaobject";
-                else
-                    classobj = entries[i].classobject;
-
-                if (!implementor.makeReflective(c, pool.get(metaobj),
-                                              pool.get(classobj)))
-                    System.err.println("Warning: " + c.getName()
-                                + " is reflective.  It was not changed.");
-
-                System.err.println(c.getName() + ": " + metaobj + ", "
-                                   + classobj);
-            }
-            else
-                System.err.println(c.getName() + ": not reflective");
-        }
-
-        for (int i = 0; i < n; ++i) {
-            implementor.onLoad(pool, entries[i].classname);
-            pool.get(entries[i].classname).writeFile();
-        }
-    }
-
-    private static int parse(String[] args, CompiledClass[] result) {
-        int n = -1;
-        for (int i = 0; i < args.length; ++i) {
-            String a = args[i];
-            if (a.equals("-m"))
-                if (n < 0 || i + 1 > args.length)
-                    return -1;
-                else
-                    result[n].metaobject = args[++i];
-            else if (a.equals("-c"))
-                if (n < 0 || i + 1 > args.length)
-                    return -1;
-                else
-                    result[n].classobject = args[++i];
-            else if (a.charAt(0) == '-')
-                return -1;
-            else {
-                CompiledClass cc = new CompiledClass();
-                cc.classname = a;
-                cc.metaobject = null;
-                cc.classobject = null;
-                result[++n] = cc;
-            }
-        }
-
-        return n + 1;
-    }
-
-    private static void help(PrintStream out) {
-        out.println("Usage: java javassist.reflect.Compiler");
-        out.println("            (<class> [-m <metaobject>] [-c <class metaobject>])+");
-    }
-}
diff --git a/src/main/javassist/reflect/Loader.java b/src/main/javassist/reflect/Loader.java
deleted file mode 100644 (file)
index 76dce4d..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import javassist.CannotCompileException;
-import javassist.NotFoundException;
-import javassist.ClassPool;
-
-/**
- * A class loader for reflection.
- *
- * <p>To run a program, say <code>MyApp</code>,
- * including a reflective class,
- * you must write a start-up program as follows:
- *
- * <ul><pre>
- * public class Main {
- *   public static void main(String[] args) throws Throwable {
- *     javassist.reflect.Loader cl
- *         = (javassist.reflect.Loader)Main.class.getClassLoader();
- *     cl.makeReflective("Person", "MyMetaobject",
- *                       "javassist.reflect.ClassMetaobject");
- *     cl.run("MyApp", args);
- *   }
- * }
- * </pre></ul>
- *
- * <p>Then run this program as follows:
- *
- * <ul><pre>% java javassist.reflect.Loader Main arg1, ...</pre></ul>
- *
- * <p>This command runs <code>Main.main()</code> with <code>arg1</code>, ...
- * and <code>Main.main()</code> runs <code>MyApp.main()</code> with
- * <code>arg1</code>, ...
- * The <code>Person</code> class is modified
- * to be a reflective class.  Method calls on a <code>Person</code>
- * object are intercepted by an instance of <code>MyMetaobject</code>.
- *
- * <p>Also, you can run <code>MyApp</code> in a slightly different way:
- *
- * <ul><pre>
- * public class Main2 {
- *   public static void main(String[] args) throws Throwable {
- *     javassist.reflect.Loader cl = new javassist.reflect.Loader();
- *     cl.makeReflective("Person", "MyMetaobject",
- *                       "javassist.reflect.ClassMetaobject");
- *     cl.run("MyApp", args);
- *   }
- * }
- * </pre></ul>
- *
- * <p>This program is run as follows:
- *
- * <ul><pre>% java Main2 arg1, ...</pre></ul>
- *
- * <p>The difference from the former one is that the class <code>Main</code>
- * is loaded by <code>javassist.reflect.Loader</code> whereas the class
- * <code>Main2</code> is not.  Thus, <code>Main</code> belongs
- * to the same name space (security domain) as <code>MyApp</code>
- * whereas <code>Main2</code> does not; <code>Main2</code> belongs
- * to the same name space as <code>javassist.reflect.Loader</code>.
- * For more details,
- * see the notes in the manual page of <code>javassist.Loader</code>.
- *
- * <p>The class <code>Main2</code> is equivalent to this class:
- *
- * <ul><pre>
- * public class Main3 {
- *   public static void main(String[] args) throws Throwable {
- *     Reflection reflection = new Reflection();
- *     javassist.Loader cl
- *         = new javassist.Loader(ClassPool.getDefault(reflection));
- *     reflection.makeReflective("Person", "MyMetaobject",
- *                               "javassist.reflect.ClassMetaobject");
- *     cl.run("MyApp", args);
- *   }
- * }
- * </pre></ul>
- *
- * <p><b>Note:</b>
- *
- * <p><code>javassist.reflect.Loader</code> does not make a class reflective
- * if that class is in a <code>java.*</code> or
- * <code>javax.*</code> pacakge because of the specifications
- * on the class loading algorithm of Java.  The JVM does not allow to
- * load such a system class with a user class loader.
- *
- * <p>To avoid this limitation, those classes should be statically
- * modified with <code>javassist.reflect.Compiler</code> and the original
- * class files should be replaced.
- *
- * @see javassist.reflect.Reflection
- * @see javassist.reflect.Compiler
- * @see javassist.Loader
- */
-public class Loader extends javassist.Loader {
-    protected Reflection reflection;
-
-    /**
-     * Loads a class with an instance of <code>Loader</code>
-     * and calls <code>main()</code> in that class.
-     *
-     * @param args              command line parameters.
-     * <ul>
-     * <code>args[0]</code> is the class name to be loaded.
-     * <br><code>args[1..n]</code> are parameters passed
-     *                      to the target <code>main()</code>.
-     * </ul>
-     */
-    public static void main(String[] args) throws Throwable {
-        Loader cl = new Loader();
-        cl.run(args);
-    }
-
-    /**
-     * Constructs a new class loader.
-     */
-    public Loader() throws CannotCompileException, NotFoundException {
-        super();
-        delegateLoadingOf("javassist.reflect.Loader");
-
-        reflection = new Reflection();
-        ClassPool pool = ClassPool.getDefault();
-        addTranslator(pool, reflection);
-    }
-
-    /**
-     * Produces a reflective class.
-     * If the super class is also made reflective, it must be done
-     * before the sub class.
-     *
-     * @param clazz             the reflective class.
-     * @param metaobject        the class of metaobjects.
-     *                          It must be a subclass of
-     *                          <code>Metaobject</code>.
-     * @param metaclass         the class of the class metaobject.
-     *                          It must be a subclass of
-     *                          <code>ClassMetaobject</code>.
-     * @return <code>false</code>       if the class is already reflective.
-     *
-     * @see javassist.reflect.Metaobject
-     * @see javassist.reflect.ClassMetaobject
-     */
-    public boolean makeReflective(String clazz,
-                                  String metaobject, String metaclass)
-        throws CannotCompileException, NotFoundException
-    {
-        return reflection.makeReflective(clazz, metaobject, metaclass);
-    }
-}
diff --git a/src/main/javassist/reflect/Metalevel.java b/src/main/javassist/reflect/Metalevel.java
deleted file mode 100644 (file)
index 8192267..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-/**
- * An interface to access a metaobject and a class metaobject.
- * This interface is implicitly implemented by the reflective
- * class.
- */
-public interface Metalevel {
-    /**
-     * Obtains the class metaobject associated with this object.
-     */
-    ClassMetaobject _getClass();
-
-    /**
-     * Obtains the metaobject associated with this object.
-     */
-    Metaobject _getMetaobject();
-
-    /**
-     * Changes the metaobject associated with this object.
-     */
-    void _setMetaobject(Metaobject m);
-}
diff --git a/src/main/javassist/reflect/Metaobject.java b/src/main/javassist/reflect/Metaobject.java
deleted file mode 100644 (file)
index 8c3749a..0000000
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import java.lang.reflect.Method;
-import java.io.Serializable;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-
-/**
- * A runtime metaobject.
- *
- * <p>A <code>Metaobject</code> is created for
- * every object at the base level.  A different reflective object is
- * associated with a different metaobject.
- *
- * <p>The metaobject intercepts method calls
- * on the reflective object at the base-level.  To change the behavior
- * of the method calls, a subclass of <code>Metaobject</code>
- * should be defined.
- *
- * <p>To obtain a metaobject, calls <code>_getMetaobject()</code>
- * on a reflective object.  For example,
- *
- * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject();
- * </pre></ul>
- *
- * @see javassist.reflect.ClassMetaobject
- * @see javassist.reflect.Metalevel
- */
-public class Metaobject implements Serializable {
-    protected ClassMetaobject classmetaobject;
-    protected Metalevel baseobject;
-    protected Method[] methods;
-
-    /**
-     * Constructs a <code>Metaobject</code>.  The metaobject is
-     * constructed before the constructor is called on the base-level
-     * object.
-     *
-     * @param self      the object that this metaobject is associated with.
-     * @param args      the parameters passed to the constructor of
-     *                  <code>self</code>.
-     */
-    public Metaobject(Object self, Object[] args) {
-        baseobject = (Metalevel)self;
-        classmetaobject = baseobject._getClass();
-        methods = classmetaobject.getReflectiveMethods();
-    }
-
-    /**
-     * Constructs a <code>Metaobject</code> without initialization.
-     * If calling this constructor, a subclass should be responsible
-     * for initialization.
-     */
-    protected Metaobject() {
-        baseobject = null;
-        classmetaobject = null;
-        methods = null;
-    }
-
-    private void writeObject(ObjectOutputStream out) throws IOException {
-        out.writeObject(baseobject);
-    }
-
-    private void readObject(ObjectInputStream in)
-        throws IOException, ClassNotFoundException
-    {
-        baseobject = (Metalevel)in.readObject();
-        classmetaobject = baseobject._getClass();
-        methods = classmetaobject.getReflectiveMethods();
-    }
-
-    /**
-     * Obtains the class metaobject associated with this metaobject.
-     *
-     * @see javassist.reflect.ClassMetaobject
-     */
-    public final ClassMetaobject getClassMetaobject() {
-        return classmetaobject;
-    }
-
-    /**
-     * Obtains the object controlled by this metaobject.
-     */
-    public final Object getObject() {
-        return baseobject;
-    }
-
-    /**
-     * Changes the object controlled by this metaobject.
-     *
-     * @param self      the object
-     */
-    public final void setObject(Object self) {
-        baseobject = (Metalevel)self;
-        classmetaobject = baseobject._getClass();
-        methods = classmetaobject.getReflectiveMethods();
-
-        // call _setMetaobject() after the metaobject is settled.
-        baseobject._setMetaobject(this);
-    }
-
-    /**
-     * Returns the name of the method specified
-     * by <code>identifier</code>.
-     */
-    public final String getMethodName(int identifier) {
-        String mname = methods[identifier].getName();
-        int j = ClassMetaobject.methodPrefixLen;
-        for (;;) {
-            char c = mname.charAt(j++);
-            if (c < '0' || '9' < c)
-                break;
-        }
-
-        return mname.substring(j);
-    }
-
-    /**
-     * Returns an array of <code>Class</code> objects representing the
-     * formal parameter types of the method specified
-     * by <code>identifier</code>.
-     */
-    public final Class[] getParameterTypes(int identifier) {
-        return methods[identifier].getParameterTypes();
-    }
-
-    /**
-     * Returns a <code>Class</code> objects representing the
-     * return type of the method specified by <code>identifier</code>.
-     */
-    public final Class getReturnType(int identifier) {
-        return methods[identifier].getReturnType();
-    }
-
-    /**
-     * Is invoked when public fields of the base-level
-     * class are read and the runtime system intercepts it.
-     * This method simply returns the value of the field.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     */
-    public Object trapFieldRead(String name) {
-        Class jc = getClassMetaobject().getJavaClass();
-        try {
-            return jc.getField(name).get(getObject());
-        }
-        catch (NoSuchFieldException e) {
-            throw new RuntimeException(e.toString());
-        }
-        catch (IllegalAccessException e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Is invoked when public fields of the base-level
-     * class are modified and the runtime system intercepts it.
-     * This method simply sets the field to the given value.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     */
-    public void trapFieldWrite(String name, Object value) {
-        Class jc = getClassMetaobject().getJavaClass();
-        try {
-            jc.getField(name).set(getObject(), value);
-        }
-        catch (NoSuchFieldException e) {
-            throw new RuntimeException(e.toString());
-        }
-        catch (IllegalAccessException e) {
-            throw new RuntimeException(e.toString());
-        }
-    }
-
-    /**
-     * Is invoked when base-level method invocation is intercepted.
-     * This method simply executes the intercepted method invocation
-     * with the original parameters and returns the resulting value.
-     *
-     * <p>Every subclass of this class should redefine this method.
-     *
-     * <p>Note: this method is not invoked if the base-level method
-     * is invoked by a constructor in the super class.  For example,
-     *
-     * <ul><pre>abstract class A {
-     *   abstract void initialize();
-     *   A() {
-     *       initialize();    // not intercepted
-     *   }
-     * }
-     *
-     * class B extends A {
-     *   void initialize() { System.out.println("initialize()"); }
-     *   B() {
-     *       super();
-     *       initialize();    // intercepted
-     *   }
-     * }</pre></ul>
-     *
-     * <p>if an instance of B is created,
-     * the invocation of initialize() in B is intercepted only once.
-     * The first invocation by the constructor in A is not intercepted.
-     * This is because the link between a base-level object and a
-     * metaobject is not created until the execution of a
-     * constructor of the super class finishes.
-     */
-    public Object trapMethodcall(int identifier, Object[] args) 
-        throws Throwable
-    {
-        try {
-            return methods[identifier].invoke(getObject(), args);
-        }
-        catch (java.lang.reflect.InvocationTargetException e) {
-            throw e.getTargetException();
-        }
-        catch (java.lang.IllegalAccessException e) {
-            throw new CannotInvokeException(e);
-        }
-    }
-}
diff --git a/src/main/javassist/reflect/Reflection.java b/src/main/javassist/reflect/Reflection.java
deleted file mode 100644 (file)
index cd4f441..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-import javassist.*;
-import javassist.CtMethod.ConstParameter;
-
-/**
- * The class implementing the behavioral reflection mechanism.
- *
- * <p>If a class is reflective,
- * then all the method invocations on every
- * instance of that class are intercepted by the runtime
- * metaobject controlling that instance.  The methods inherited from the
- * super classes are also intercepted except final methods.  To intercept
- * a final method in a super class, that super class must be also reflective.
- *
- * <p>To do this, the original class file representing a reflective class:
- *
- * <ul><pre>
- * class Person {
- *   public int f(int i) { return i + 1; }
- *   public int value;
- * }
- * </pre></ul>
- *
- * <p>is modified so that it represents a class:
- *
- * <ul><pre>
- * class Person implements Metalevel {
- *   public int _original_f(int i) { return i + 1; }
- *   public int f(int i) { <i>delegate to the metaobject</i> }
- *
- *   public int value;
- *   public int _r_value() { <i>read "value"</i> }
- *   public void _w_value(int v) { <i>write "value"</i> }
- *
- *   public ClassMetaobject _getClass() { <i>return a class metaobject</i> }
- *   public Metaobject _getMetaobject() { <i>return a metaobject</i> }
- *   public void _setMetaobject(Metaobject m) { <i>change a metaobject</i> }
- * }
- * </pre></ul>
- *
- * @see javassist.reflect.ClassMetaobject
- * @see javassist.reflect.Metaobject
- * @see javassist.reflect.Loader
- * @see javassist.reflect.Compiler
- */
-public class Reflection implements Translator {
-
-    static final String classobjectField = "_classobject";
-    static final String classobjectAccessor = "_getClass";
-    static final String metaobjectField = "_metaobject";
-    static final String metaobjectGetter = "_getMetaobject";
-    static final String metaobjectSetter = "_setMetaobject";
-    static final String readPrefix = "_r_";
-    static final String writePrefix = "_w_";
-
-    static final String metaobjectClassName = "javassist.reflect.Metaobject";
-    static final String classMetaobjectClassName
-        = "javassist.reflect.ClassMetaobject";
-
-    protected CtMethod trapMethod, trapStaticMethod;
-    protected CtMethod trapRead, trapWrite;
-    protected CtClass[] readParam;
-
-    protected ClassPool classPool;
-    protected CodeConverter converter;
-
-    private boolean isExcluded(String name) {
-        return name.startsWith(ClassMetaobject.methodPrefix)
-            || name.equals(classobjectAccessor)
-            || name.equals(metaobjectSetter)
-            || name.equals(metaobjectGetter)
-            || name.startsWith(readPrefix)
-            || name.startsWith(writePrefix);
-    }
-
-    /**
-     * Constructs a new <code>Reflection</code> object.
-     */
-    public Reflection() {
-        classPool = null;
-        converter = new CodeConverter();
-    }
-
-    /**
-     * Initializes the object.
-     */
-    public void start(ClassPool pool) throws NotFoundException {
-        classPool = pool;
-        final String msg
-            = "javassist.reflect.Sample is not found or broken.";
-        try {
-            CtClass c = classPool.get("javassist.reflect.Sample");
-            trapMethod = c.getDeclaredMethod("trap");
-            trapStaticMethod = c.getDeclaredMethod("trapStatic");
-            trapRead = c.getDeclaredMethod("trapRead");
-            trapWrite = c.getDeclaredMethod("trapWrite");
-            readParam
-                = new CtClass[] { classPool.get("java.lang.Object") };
-        }
-        catch (NotFoundException e) {
-            throw new RuntimeException(msg);
-        }
-    }
-
-    /**
-     * Inserts hooks for intercepting accesses to the fields declared
-     * in reflective classes.
-     */
-    public void onLoad(ClassPool pool, String classname)
-        throws CannotCompileException, NotFoundException
-    {
-        CtClass clazz = pool.get(classname);
-        clazz.instrument(converter);
-    }
-
-    /**
-     * Produces a reflective class.
-     * If the super class is also made reflective, it must be done
-     * before the sub class.
-     *
-     * @param classname         the name of the reflective class
-     * @param metaobject        the class name of metaobjects.
-     * @param metaclass         the class name of the class metaobject.
-     * @return <code>false</code>       if the class is already reflective.
-     *
-     * @see javassist.reflect.Metaobject
-     * @see javassist.reflect.ClassMetaobject
-     */
-    public boolean makeReflective(String classname,
-                                  String metaobject, String metaclass)
-        throws CannotCompileException, NotFoundException
-    {
-        return makeReflective(classPool.get(classname),
-                              classPool.get(metaobject),
-                              classPool.get(metaclass));
-    }
-
-    /**
-     * Produces a reflective class.
-     * If the super class is also made reflective, it must be done
-     * before the sub class.
-     *
-     * @param clazz             the reflective class.
-     * @param metaobject        the class of metaobjects.
-     *                          It must be a subclass of
-     *                          <code>Metaobject</code>.
-     * @param metaclass         the class of the class metaobject.
-     *                          It must be a subclass of
-     *                          <code>ClassMetaobject</code>.
-     * @return <code>false</code>       if the class is already reflective.
-     *
-     * @see javassist.reflect.Metaobject
-     * @see javassist.reflect.ClassMetaobject
-     */
-    public boolean makeReflective(Class clazz,
-                                  Class metaobject, Class metaclass)
-        throws CannotCompileException, NotFoundException
-    {
-        return makeReflective(clazz.getName(), metaobject.getName(),
-                              metaclass.getName());
-    }
-
-    /**
-     * Produces a reflective class.  It modifies the given
-     * <code>CtClass</code> object and makes it reflective.
-     * If the super class is also made reflective, it must be done
-     * before the sub class.
-     *
-     * @param clazz             the reflective class.
-     * @param metaobject        the class of metaobjects.
-     *                          It must be a subclass of
-     *                          <code>Metaobject</code>.
-     * @param metaclass         the class of the class metaobject.
-     *                          It must be a subclass of
-     *                          <code>ClassMetaobject</code>.
-     * @return <code>false</code>       if the class is already reflective.
-     *
-     * @see javassist.reflect.Metaobject
-     * @see javassist.reflect.ClassMetaobject
-     */
-    public boolean makeReflective(CtClass clazz,
-                                  CtClass metaobject, CtClass metaclass)
-        throws CannotCompileException, CannotReflectException,
-               NotFoundException
-    {
-        if (clazz.isInterface())
-            throw new CannotReflectException(
-                    "Cannot reflect an interface: " + clazz.getName());
-
-        if (clazz.subclassOf(classPool.get(classMetaobjectClassName)))
-            throw new CannotReflectException(
-                "Cannot reflect a subclass of ClassMetaobject: "
-                + clazz.getName());
-
-        if (clazz.subclassOf(classPool.get(metaobjectClassName)))
-            throw new CannotReflectException(
-                "Cannot reflect a subclass of Metaobject: "
-                + clazz.getName());
-
-        registerReflectiveClass(clazz);
-        return modifyClassfile(clazz, metaobject, metaclass);
-    }
-
-    /**
-     * Registers a reflective class.  The field accesses to the instances
-     * of this class are instrumented.
-     */
-    private void registerReflectiveClass(CtClass clazz) {
-        CtField[] fs = clazz.getDeclaredFields();
-        for (int i = 0; i < fs.length; ++i) {
-            CtField f = fs[i];
-            int mod = f.getModifiers();
-            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
-                String name = f.getName();
-                converter.replaceFieldRead(f, clazz, readPrefix + name);
-                converter.replaceFieldWrite(f, clazz, writePrefix + name);
-            }
-        }
-    }
-
-    private boolean modifyClassfile(CtClass clazz, CtClass metaobject,
-                                    CtClass metaclass)
-        throws CannotCompileException, NotFoundException
-    {
-        if (clazz.getAttribute("Reflective") != null)
-            return false;       // this is already reflective.
-        else
-            clazz.setAttribute("Reflective", new byte[0]);
-
-        CtClass mlevel = classPool.get("javassist.reflect.Metalevel");
-        boolean addMeta = !clazz.subtypeOf(mlevel);
-        if (addMeta)
-            clazz.addInterface(mlevel);
-
-        processMethods(clazz, addMeta);
-        processFields(clazz);
-
-        CtField f;
-        if (addMeta) {
-            f = new CtField(classPool.get("javassist.reflect.Metaobject"),
-                            metaobjectField, clazz);
-            f.setModifiers(Modifier.PROTECTED);
-            clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject));
-
-            clazz.addMethod(CtNewMethod.getter(metaobjectGetter, f));
-            clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f));
-        }
-
-        f = new CtField(classPool.get("javassist.reflect.ClassMetaobject"),
-                        classobjectField, clazz);
-        f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
-        clazz.addField(f, CtField.Initializer.byNew(metaclass,
-                                        new String[] { clazz.getName() }));
-
-        clazz.addMethod(CtNewMethod.getter(classobjectAccessor, f));
-        return true;
-    }
-
-    private void processMethods(CtClass clazz, boolean dontSearch)
-        throws CannotCompileException, NotFoundException
-    {
-        CtMethod[] ms = clazz.getMethods();
-        for (int i = 0; i < ms.length; ++i) {
-            CtMethod m = ms[i];
-            int mod = m.getModifiers();
-            if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod))
-                processMethods0(mod, clazz, m, i, dontSearch);
-        }
-    }
-
-    private void processMethods0(int mod, CtClass clazz,
-                        CtMethod m, int identifier, boolean dontSearch)
-        throws CannotCompileException, NotFoundException
-    {
-        CtMethod body;
-        String name = m.getName();
-
-        if (isExcluded(name))   // internally-used method inherited
-            return;             // from a reflective class.
-
-        CtMethod m2;
-        if (m.getDeclaringClass() == clazz) {
-            if (Modifier.isNative(mod))
-                return;
-
-            m2 = m;
-            if (Modifier.isFinal(mod)) {
-                mod &= ~Modifier.FINAL;
-                m2.setModifiers(mod);
-            }
-        }
-        else {
-            if (Modifier.isFinal(mod))
-                return;
-
-            mod &= ~Modifier.NATIVE;
-            m2 = CtNewMethod.delegator(findOriginal(m, dontSearch), clazz);
-            m2.setModifiers(mod);
-            clazz.addMethod(m2);
-        }
-
-        m2.setName(ClassMetaobject.methodPrefix + identifier
-                      + "_" + name);
-
-        if (Modifier.isStatic(mod))
-            body = trapStaticMethod;
-        else
-            body = trapMethod;
-
-        CtMethod wmethod
-            = CtNewMethod.wrapped(m.getReturnType(), name,
-                                  m.getParameterTypes(), m.getExceptionTypes(),
-                                  body, ConstParameter.integer(identifier),
-                                  clazz);
-        wmethod.setModifiers(mod);
-        clazz.addMethod(wmethod);
-    }
-
-    private CtMethod findOriginal(CtMethod m, boolean dontSearch)
-        throws NotFoundException
-    {
-        if (dontSearch)
-            return m;
-
-        String name = m.getName();
-        CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods();
-        for (int i = 0; i < ms.length; ++i) {
-            String orgName = ms[i].getName();
-            if (orgName.endsWith(name)
-                && orgName.startsWith(ClassMetaobject.methodPrefix)
-                && ms[i].getSignature().equals(m.getSignature()))
-                return ms[i];
-        }
-
-        return m;
-    }
-
-    private void processFields(CtClass clazz)
-        throws CannotCompileException, NotFoundException
-    {
-        CtField[] fs = clazz.getDeclaredFields();
-        for (int i = 0; i < fs.length; ++i) {
-            CtField f = fs[i];
-            int mod = f.getModifiers();
-            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
-                mod |= Modifier.STATIC;
-                String name = f.getName();
-                CtClass ftype = f.getType();
-                CtMethod wmethod
-                    = CtNewMethod.wrapped(ftype, readPrefix + name,
-                                          readParam, null, trapRead,
-                                          ConstParameter.string(name),
-                                          clazz);
-                wmethod.setModifiers(mod);
-                clazz.addMethod(wmethod);
-                CtClass[] writeParam = new CtClass[2];
-                writeParam[0] = classPool.get("java.lang.Object");
-                writeParam[1] = ftype;
-                wmethod = CtNewMethod.wrapped(CtClass.voidType,
-                                writePrefix + name,
-                                writeParam, null, trapWrite,
-                                ConstParameter.string(name), clazz);
-                wmethod.setModifiers(mod);
-                clazz.addMethod(wmethod);
-            }
-        }
-    }
-}
diff --git a/src/main/javassist/reflect/Sample.java b/src/main/javassist/reflect/Sample.java
deleted file mode 100644 (file)
index 81bad69..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.reflect;
-
-/**
- * A template used for defining a reflective class.
- */
-public class Sample {
-    private Metaobject _metaobject;
-    private static ClassMetaobject _classobject;
-
-    public Object trap(Object[] args, int identifier) throws Throwable {
-        Metaobject mobj;
-        mobj = _metaobject;
-        if (mobj == null)
-            return ClassMetaobject.invoke(this, identifier, args);
-        else
-            return mobj.trapMethodcall(identifier, args);
-    }
-
-    public static Object trapStatic(Object[] args, int identifier)
-        throws Throwable
-    {
-        return _classobject.trapMethodcall(identifier, args);
-    }
-
-    public static Object trapRead(Object[] args, String name) {
-        if (args[0] == null)
-            return _classobject.trapFieldRead(name);
-        else
-            return ((Metalevel)args[0])._getMetaobject().trapFieldRead(name);
-    }
-
-    public static Object trapWrite(Object[] args, String name) {
-        Metalevel base = (Metalevel)args[0];
-        if (base == null)
-            _classobject.trapFieldWrite(name, args[1]);
-        else
-            base._getMetaobject().trapFieldWrite(name, args[1]);
-
-        return null;
-    }
-}
diff --git a/src/main/javassist/reflect/package.html b/src/main/javassist/reflect/package.html
deleted file mode 100644 (file)
index 10a4196..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-<html>
-<body>
-Runtime Behavioral Reflection.
-
-<p>(also recently known as interceptors or AOP?)
-
-<p>This package enables a metaobject to trap method calls and field
-accesses  on a regular Java object.  It provides a class
-<code>Reflection</code>, which is a main module for implementing
-runtime behavioral reflection.
-It also provides
-a class <code>Loader</code> and <code>Compiler</code>
-as utilities for dynamically or statically
-translating a regular class into a reflective class.
-
-<p>An instance of the reflective class is associated with
-a runtime metaobject and a runtime class metaobject, which control
-the behavior of that instance.
-The runtime
-metaobject is created for every (base-level) instance but the
-runtime class metaobject is created for every (base-level) class.
-<code>Metaobject</code> is the root class of the runtime
-metaobject and <code>ClassMetaobject</code> is the root class
-of the runtime class metaobject.
-
-<p>This package is provided as a sample implementation of the
-reflection mechanism with Javassist.  All the programs in this package
-uses only the regular Javassist API; they never call any hidden
-methods.
-
-<p>The most significant class in this package is <code>Reflection</code>.
-See the description of this class first.
-
-</body>
-</html>
diff --git a/src/main/javassist/rmi/AppletServer.java b/src/main/javassist/rmi/AppletServer.java
deleted file mode 100644 (file)
index 89cc92a..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-import java.io.*;
-import javassist.web.*;
-import javassist.CannotCompileException;
-import javassist.NotFoundException;
-import javassist.ClassPool;
-import java.lang.reflect.Method;
-import java.util.Hashtable;
-import java.util.Vector;
-
-/**
- * An AppletServer object is a web server that an ObjectImporter
- * communicates with.  It makes the objects specified by
- * <code>exportObject()</code> remotely accessible from applets.
- * If the classes of the exported objects are requested by the client-side
- * JVM, this web server sends proxy classes for the requested classes.
- *
- * @see javassist.rmi.ObjectImporter
- */
-public class AppletServer extends Webserver {
-    private StubGenerator stubGen;
-    private Hashtable exportedNames;
-    private Vector exportedObjects;
-
-    private static final byte[] okHeader
-                                = "HTTP/1.0 200 OK\r\n\r\n".getBytes();
-
-    /**
-     * Constructs a web server.
-     *
-     * @param port      port number
-     */
-    public AppletServer(String port)
-        throws IOException, NotFoundException, CannotCompileException
-    {
-        this(Integer.parseInt(port));
-    }
-
-    /**
-     * Constructs a web server.
-     *
-     * @param port      port number
-     */
-    public AppletServer(int port)
-        throws IOException, NotFoundException, CannotCompileException
-    {
-        this(ClassPool.getDefault(), new StubGenerator(), port);
-    }
-
-    /**
-     * Constructs a web server.
-     *
-     * @param port      port number
-     * @param src       the source of classs files.
-     */
-    public AppletServer(int port, ClassPool src)
-        throws IOException, NotFoundException, CannotCompileException
-    {
-        this(new ClassPool(src), new StubGenerator(), port);
-    }
-
-    private AppletServer(ClassPool loader, StubGenerator gen, int port)
-        throws IOException, NotFoundException, CannotCompileException
-    {
-        super(port);
-        exportedNames = new Hashtable();
-        exportedObjects = new Vector();
-        stubGen = gen;
-        addTranslator(loader, gen);
-    }
-
-    /**
-     * Begins the HTTP service.
-     */
-    public void run() {
-        super.run();
-    }
-
-    /**
-     * Exports an object.
-     * This method produces the bytecode of the proxy class used
-     * to access the exported object.  A remote applet can load
-     * the proxy class and call a method on the exported object.
-     *
-     * @param name      the name used for looking the object up.
-     * @param obj       the exported object.
-     * @return          the object identifier
-     *
-     * @see javassist.rmi.ObjectImporter#lookupObject(String)
-     */
-    public synchronized int exportObject(String name, Object obj)
-        throws CannotCompileException
-    {
-        Class clazz = obj.getClass();
-        ExportedObject eo = new ExportedObject();
-        eo.object = obj;
-        eo.methods = clazz.getMethods();
-        exportedObjects.addElement(eo);
-        eo.identifier = exportedObjects.size() - 1;
-        if (name != null)
-            exportedNames.put(name, eo);
-
-        try {
-            stubGen.makeProxyClass(clazz);
-        }
-        catch (NotFoundException e) {
-            throw new CannotCompileException(e);
-        }
-
-        return eo.identifier;
-    }
-
-    /**
-     * Processes a request from a web browser (an ObjectImporter).
-     */
-    public void doReply(InputStream in, OutputStream out, String cmd)
-        throws IOException, BadHttpRequest
-    {
-        if (cmd.startsWith("POST /rmi "))
-            processRMI(in, out);
-        else if (cmd.startsWith("POST /lookup "))
-            lookupName(cmd, in, out);
-        else
-            super.doReply(in, out, cmd);
-    }
-
-    private void processRMI(InputStream ins, OutputStream outs)
-        throws IOException
-    {
-        ObjectInputStream in = new ObjectInputStream(ins);
-
-        int objectId = in.readInt();
-        int methodId = in.readInt();
-        Exception err = null;
-        Object rvalue = null;
-        try {
-            ExportedObject eo
-                = (ExportedObject)exportedObjects.elementAt(objectId);
-            Object[] args = readParameters(in);
-            rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object,
-                                                               args));
-        }
-        catch(Exception e) {
-            err = e;
-            logging2(e.toString());
-        }
-
-        outs.write(okHeader);
-        ObjectOutputStream out = new ObjectOutputStream(outs);
-        if (err != null) {
-            out.writeBoolean(false);
-            out.writeUTF(err.toString());
-        }
-        else
-            try {
-                out.writeBoolean(true);
-                out.writeObject(rvalue);
-            }
-            catch (NotSerializableException e) {
-                logging2(e.toString());
-            }
-            catch (InvalidClassException e) {
-                logging2(e.toString());
-            }
-
-        out.flush();
-        out.close();
-        in.close();
-    }
-
-    private Object[] readParameters(ObjectInputStream in)
-        throws IOException, ClassNotFoundException
-    {
-        int n = in.readInt();
-        Object[] args = new Object[n];
-        for (int i = 0; i < n; ++i) {
-            Object a = in.readObject();
-            if (a instanceof RemoteRef) {
-                RemoteRef ref = (RemoteRef)a;
-                ExportedObject eo
-                    = (ExportedObject)exportedObjects.elementAt(ref.oid);
-                a = eo.object;
-            }
-
-            args[i] = a;
-        }
-
-        return args;
-    }
-
-    private Object convertRvalue(Object rvalue)
-        throws CannotCompileException
-    {
-        if (rvalue == null)
-            return null;        // the return type is void.
-
-        String classname = rvalue.getClass().getName();
-        if (stubGen.isProxyClass(classname))
-            return new RemoteRef(exportObject(null, rvalue), classname);
-        else
-            return rvalue;
-    }
-
-    private void lookupName(String cmd, InputStream ins, OutputStream outs)
-        throws IOException
-    {
-        ObjectInputStream in = new ObjectInputStream(ins);
-        String name = DataInputStream.readUTF(in);
-        ExportedObject found = (ExportedObject)exportedNames.get(name);
-        outs.write(okHeader);
-        ObjectOutputStream out = new ObjectOutputStream(outs);
-        if (found == null) {
-            logging2(name + "not found.");
-            out.writeInt(-1);           // error code
-            out.writeUTF("error");
-        }
-        else {
-            logging2(name);
-            out.writeInt(found.identifier);
-            out.writeUTF(found.object.getClass().getName());
-        }
-
-        out.flush();
-        out.close();
-        in.close();
-    }
-}
-
-class ExportedObject {
-    public int identifier;
-    public Object object;
-    public Method[] methods;
-}
diff --git a/src/main/javassist/rmi/ObjectImporter.java b/src/main/javassist/rmi/ObjectImporter.java
deleted file mode 100644 (file)
index adad468..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-import java.io.*;
-import java.net.*;
-import java.applet.Applet;
-import java.lang.reflect.*;
-
-/**
- * The object importer enables applets to call a method on a remote
- * object running on the <code>Webserver</code>.
- *
- * <p>To access the remote
- * object, the applet first calls <code>lookupObject()</code> and
- * obtains a proxy object, which is a reference to that object.
- * The class name of the proxy object is identical to that of
- * the remote object.
- * The proxy object provides the same set of methods as the remote object.
- * If one of the methods is invoked on the proxy object,
- * the invocation is delegated to the remote object.
- * From the viewpoint of the applet, therefore, the two objects are
- * identical. The applet can access the object on the server
- * with the regular Java syntax without concern about the actual
- * location.
- *
- * <p>The methods remotely called by the applet must be <code>public</code>.
- * This is true even if the applet's class and the remote object's classs
- * belong to the same package.
- *
- * <p>If class X is a class of remote objects, a subclass of X must be
- * also a class of remote objects.  On the other hand, this restriction
- * is not applied to the superclass of X.  The class X does not have to
- * contain a constructor taking no arguments.
- *
- * <p>The parameters to a remote method is passed in the <i>call-by-value</i>
- * manner.  Thus all the parameter classes must implement
- * <code>java.io.Serializable</code>.  However, if the parameter is the
- * proxy object, the reference to the remote object instead of a copy of
- * the object is passed to the method.
- *
- * <p>Because of the limitations of the current implementation,
- * <ul>
- * <li>The parameter objects cannot contain the proxy
- * object as a field value.
- * <li>If class <code>C</code> is of the remote object, then
- * the applet cannot instantiate <code>C</code> locally or remotely.
- * </ul>
- *
- * <p>All the exceptions thrown by the remote object are converted
- * into <code>RemoteException</code>.  Since this exception is a subclass
- * of <code>RuntimeException</code>, the caller method does not need
- * to catch the exception.  However, good programs should catch
- * the <code>RuntimeException</code>.
- *
- * @see javassist.rmi.AppletServer
- * @see javassist.rmi.RemoteException
- * @see javassist.web.Viewer
- */
-public class ObjectImporter implements java.io.Serializable {
-    private final byte[] endofline = { 0x0d, 0x0a };
-    private String servername, orgServername;
-    private int port, orgPort;
-
-    protected byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
-    protected byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
-
-    /**
-     * Constructs an object importer.
-     *
-     * <p>Remote objects are imported from the web server that the given
-     * applet has been loaded from.
-     *
-     * @param applet    the applet loaded from the <code>Webserver</code>.
-     */
-    public ObjectImporter(Applet applet) {
-        URL codebase = applet.getCodeBase();
-        orgServername = servername = codebase.getHost();
-        orgPort = port = codebase.getPort();
-    }
-
-    /**
-     * Constructs an object importer.
-     *
-     * <p>If you run a program with <code>javassist.web.Viewer</code>,
-     * you can construct an object importer as follows:
-     *
-     * <ul><pre>
-     * Viewer v = (Viewer)this.getClass().getClassLoader();
-     * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
-     * </pre></ul>
-     *
-     * @see javassist.web.Viewer
-     */
-    public ObjectImporter(String servername, int port) {
-        this.orgServername = this.servername = servername;
-        this.orgPort = this.port = port;
-    }
-
-    /**
-     * Finds the object exported by a server with the specified name.
-     * If the object is not found, this method returns null.
-     *
-     * @param name      the name of the exported object.
-     * @return          the proxy object or null.
-     */
-    public Object getObject(String name) {
-        try {
-            return lookupObject(name);
-        }
-        catch (ObjectNotFoundException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Sets an http proxy server.  After this method is called, the object
-     * importer connects a server through the http proxy server.
-     */
-    public void setHttpProxy(String host, int port) {
-        String proxyHeader = "POST http://" + orgServername + ":" + orgPort;
-        String cmd = proxyHeader + "/lookup HTTP/1.0";
-        lookupCommand = cmd.getBytes();
-        cmd = proxyHeader + "/rmi HTTP/1.0";
-        rmiCommand = cmd.getBytes();
-        this.servername = host;
-        this.port = port;
-    }
-
-    /**
-     * Finds the object exported by the server with the specified name.
-     * It sends a POST request to the server (via an http proxy server
-     * if needed).
-     *
-     * @param name      the name of the exported object.
-     * @return          the proxy object.
-     */
-    public Object lookupObject(String name) throws ObjectNotFoundException
-    {
-        try {
-            Socket sock = new Socket(servername, port);
-            OutputStream out = sock.getOutputStream();
-            out.write(lookupCommand);
-            out.write(endofline);
-            out.write(endofline);
-
-            ObjectOutputStream dout = new ObjectOutputStream(out);
-            dout.writeUTF(name);
-            dout.flush();
-
-            InputStream in = new BufferedInputStream(sock.getInputStream());
-            skipHeader(in);
-            ObjectInputStream din = new ObjectInputStream(in);
-            int n = din.readInt();
-            String classname = din.readUTF();
-            din.close();
-            dout.close();
-            sock.close();
-
-            if (n >= 0)
-                return createProxy(n, classname);
-        }
-        catch (Exception e) {
-            e.printStackTrace();
-            throw new ObjectNotFoundException(name, e);
-        }
-
-        throw new ObjectNotFoundException(name);
-    }
-
-    private static final Class[] proxyConstructorParamTypes
-        = new Class[] { ObjectImporter.class, int.class };
-
-    private Object createProxy(int oid, String classname) throws Exception {
-        Class c = Class.forName(classname);
-        Constructor cons = c.getConstructor(proxyConstructorParamTypes);
-        return cons.newInstance(new Object[] { this, new Integer(oid) });
-    }
-
-    /**
-     * Calls a method on a remote object.
-     * It sends a POST request to the server (via an http proxy server
-     * if needed).
-     *
-     * <p>This method is called by only proxy objects.
-     */
-    public Object call(int objectid, int methodid, Object[] args)
-        throws RemoteException
-    {
-        boolean result;
-        Object rvalue;
-        String errmsg;
-
-        try {
-            /* This method establishes a raw tcp connection for sending
-             * a POST message.  Thus the object cannot communicate a
-             * remote object beyond a fire wall.  To avoid this problem,
-             * the connection should be established with a mechanism
-             * collaborating a proxy server.  Unfortunately, java.lang.URL
-             * does not seem to provide such a mechanism.
-             *
-             * You might think that using HttpURLConnection is a better
-             * way than constructing a raw tcp connection.  Unfortunately,
-             * URL.openConnection() does not return an HttpURLConnection
-             * object in Netscape's JVM.  It returns a
-             * netscape.net.URLConnection object.
-             *
-             * lookupObject() has the same problem.
-             */
-            Socket sock = new Socket(servername, port);
-            OutputStream out = new BufferedOutputStream(
-                                                sock.getOutputStream());
-            out.write(rmiCommand);
-            out.write(endofline);
-            out.write(endofline);
-
-            ObjectOutputStream dout = new ObjectOutputStream(out);
-            dout.writeInt(objectid);
-            dout.writeInt(methodid);
-            writeParameters(dout, args);
-            dout.flush();
-
-            InputStream ins = new BufferedInputStream(sock.getInputStream());
-            skipHeader(ins);
-            ObjectInputStream din = new ObjectInputStream(ins);
-            result = din.readBoolean();
-            rvalue = null;
-            errmsg = null;
-            if (result)
-                rvalue = din.readObject();
-            else
-                errmsg = din.readUTF();
-
-            din.close();
-            dout.close();
-            sock.close();
-
-            if (rvalue instanceof RemoteRef) {
-                RemoteRef ref = (RemoteRef)rvalue;
-                rvalue = createProxy(ref.oid, ref.classname);
-            }
-        }
-        catch (ClassNotFoundException e) {
-            throw new RemoteException(e);
-        }
-        catch (IOException e) {
-            throw new RemoteException(e);
-        }
-        catch (Exception e) {
-            throw new RemoteException(e);
-        }
-
-        if (result)
-            return rvalue;
-        else
-            throw new RemoteException(errmsg);
-    }
-
-    private void skipHeader(InputStream in) throws IOException {
-        int len;
-        do {
-            int c;
-            len = 0;
-            while ((c = in.read()) >= 0 && c != 0x0d)
-                ++len;
-
-            in.read();  /* skip 0x0a (LF) */
-        } while (len > 0);
-    }
-
-    private void writeParameters(ObjectOutputStream dout, Object[] params)
-        throws IOException
-    {
-        int n = params.length;
-        dout.writeInt(n);
-        for (int i = 0; i < n; ++i)
-            if (params[i] instanceof Proxy) {
-                Proxy p = (Proxy)params[i];
-                dout.writeObject(new RemoteRef(p._getObjectId()));
-            }
-            else
-                dout.writeObject(params[i]);
-    }
-}
diff --git a/src/main/javassist/rmi/ObjectNotFoundException.java b/src/main/javassist/rmi/ObjectNotFoundException.java
deleted file mode 100644 (file)
index 85bc316..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-public class ObjectNotFoundException extends Exception {
-    public ObjectNotFoundException(String name) {
-        super(name + " is not exported");
-    }
-
-    public ObjectNotFoundException(String name, Exception e) {
-        super(name + " because of " + e.toString());
-    }
-}
diff --git a/src/main/javassist/rmi/Proxy.java b/src/main/javassist/rmi/Proxy.java
deleted file mode 100644 (file)
index f627ac6..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-/**
- * An interface implemented by proxy classes.
- *
- * @see javassist.rmi.StubGenerator
- */
-public interface Proxy {
-    int _getObjectId();
-}
diff --git a/src/main/javassist/rmi/RemoteException.java b/src/main/javassist/rmi/RemoteException.java
deleted file mode 100644 (file)
index ceb04f9..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-/**
- * <code>RemoteException</code> represents any exception thrown
- * during remote method invocation.
- */
-public class RemoteException extends RuntimeException {
-    public RemoteException(String msg) {
-        super(msg);
-    }
-
-    public RemoteException(Exception e) {
-        super("by " + e.toString());
-    }
-}
diff --git a/src/main/javassist/rmi/RemoteRef.java b/src/main/javassist/rmi/RemoteRef.java
deleted file mode 100644 (file)
index fbd93ad..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-/**
- * Remote reference.  This class is internally used for sending a remote
- * reference through a network stream.
- */
-public class RemoteRef implements java.io.Serializable {
-    public int oid;
-    public String classname;
-
-    public RemoteRef(int i) {
-        oid = i;
-        classname = null;
-    }
-
-    public RemoteRef(int i, String name) {
-        oid = i;
-        classname = name;
-    }
-}
diff --git a/src/main/javassist/rmi/Sample.java b/src/main/javassist/rmi/Sample.java
deleted file mode 100644 (file)
index b632cd0..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-/**
- * A template used for defining a proxy class.
- * The class file of this class is read by the <code>StubGenerator</code>
- * class.
- */
-public class Sample {
-    private ObjectImporter importer;
-    private int objectId;
-
-    public Object forward(Object[] args, int identifier) {
-        return importer.call(objectId, identifier, args);
-    }
-
-    public static Object forwardStatic(Object[] args, int identifier)
-        throws RemoteException
-    {
-        throw new RemoteException("cannot call a static method.");
-    }
-}
diff --git a/src/main/javassist/rmi/StubGenerator.java b/src/main/javassist/rmi/StubGenerator.java
deleted file mode 100644 (file)
index eac4091..0000000
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.rmi;
-
-import javassist.*;
-import java.lang.reflect.Method;
-import java.util.Hashtable;
-import javassist.CtMethod.ConstParameter;
-
-/**
- * A stub-code generator.  It is used for producing a proxy class.
- *
- * <p>The proxy class for class A is as follows:
- *
- * <ul><pre>public class A implements Proxy, Serializable {
- *   private ObjectImporter importer;
- *   private int objectId;
- *   public int _getObjectId() { return objectId; }
- *   public A(ObjectImporter oi, int id) {
- *     importer = oi; objectId = id;
- *   }
- *
- *   ... the same methods that the original class A declares ...
- * }</pre></ul>
- *
- * <p>Instances of the proxy class is created by an
- * <code>ObjectImporter</code> object.
- */
-public class StubGenerator implements Translator {
-    private static final String fieldImporter = "importer";
-    private static final String fieldObjectId = "objectId";
-    private static final String accessorObjectId = "_getObjectId";
-    private static final String sampleClass = "javassist.rmi.Sample";
-
-    private ClassPool classPool;
-    private Hashtable proxyClasses;
-    private CtMethod forwardMethod;
-    private CtMethod forwardStaticMethod;
-
-    private CtClass[] proxyConstructorParamTypes;
-    private CtClass[] interfacesForProxy;
-    private CtClass[] exceptionForProxy;
-
-    /**
-     * Constructs a stub-code generator.
-     */
-    public StubGenerator() {
-        proxyClasses = new Hashtable();
-    }
-
-    /**
-     * Initializes the object.
-     * This is a method declared in javassist.Translator.
-     *
-     * @see javassist.Translator#start(ClassPool)
-     */
-    public void start(ClassPool pool) throws NotFoundException {
-        classPool = pool;
-        CtClass c = pool.get(sampleClass);
-        forwardMethod = c.getDeclaredMethod("forward");
-        forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
-
-        proxyConstructorParamTypes
-            = pool.get(new String[] { "javassist.rmi.ObjectImporter",
-                                         "int" });
-        interfacesForProxy
-            = pool.get(new String[] { "java.io.Serializable",
-                                         "javassist.rmi.Proxy" });
-        exceptionForProxy
-            = new CtClass[] { pool.get("javassist.rmi.RemoteException") };
-    }
-
-    /**
-     * Does nothing.
-     * This is a method declared in javassist.Translator.
-     * @see javassist.Translator#onLoad(ClassPool,String)
-     */
-    public void onLoad(ClassPool pool, String classname) {}
-
-    /**
-     * Returns <code>true</code> if the specified class is a proxy class
-     * recorded by <code>makeProxyClass()</code>.
-     *
-     * @param name              a fully-qualified class name
-     */
-    public boolean isProxyClass(String name) {
-        return proxyClasses.get(name) != null;
-    }
-
-    /**
-     * Makes a proxy class.  The produced class is substituted
-     * for the original class.
-     *
-     * @param clazz             the class referenced
-     *                          through the proxy class.
-     * @return          <code>false</code> if the proxy class
-     *                  has been already produced.
-     */
-    public synchronized boolean makeProxyClass(Class clazz)
-        throws CannotCompileException, NotFoundException
-    {
-        String classname = clazz.getName();
-        if (proxyClasses.get(classname) != null)
-            return false;
-        else {
-            CtClass ctclazz = produceProxyClass(classPool.get(classname),
-                                                clazz);
-            proxyClasses.put(classname, ctclazz);
-            modifySuperclass(ctclazz);
-            return true;
-        }
-    }
-
-    private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
-        throws CannotCompileException, NotFoundException
-    {
-        int modify = orgclass.getModifiers();
-        if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
-            || !Modifier.isPublic(modify))
-            throw new CannotCompileException(orgclass.getName()
-                        + " must be public, non-native, and non-abstract.");
-
-        CtClass proxy = classPool.makeClass(orgclass.getName(),
-                                              orgclass.getSuperclass());
-
-        proxy.setInterfaces(interfacesForProxy);
-
-        CtField f
-            = new CtField(classPool.get("javassist.rmi.ObjectImporter"),
-                          fieldImporter, proxy);
-        f.setModifiers(Modifier.PRIVATE);
-        proxy.addField(f, CtField.Initializer.byParameter(0));
-
-        f = new CtField(CtClass.intType, fieldObjectId, proxy);
-        f.setModifiers(Modifier.PRIVATE);
-        proxy.addField(f, CtField.Initializer.byParameter(1)); 
-
-        proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
-
-        proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
-        CtConstructor cons
-            = CtNewConstructor.skeleton(proxyConstructorParamTypes,
-                                        null, proxy);
-        proxy.addConstructor(cons);
-
-        try {
-            addMethods(proxy, orgRtClass.getMethods());
-            return proxy;
-        }
-        catch (SecurityException e) {
-            throw new CannotCompileException(e);
-        }
-    }
-
-    private CtClass toCtClass(Class rtclass) throws NotFoundException {
-        String name;
-        if (!rtclass.isArray())
-            name = rtclass.getName();
-        else {
-            StringBuffer sbuf = new StringBuffer();
-            do {
-                sbuf.append("[]");
-                rtclass = rtclass.getComponentType();
-            } while(rtclass.isArray());
-            sbuf.insert(0, rtclass.getName());
-            name = sbuf.toString();
-        }
-            
-        return classPool.get(name);
-    }
-
-    private CtClass[] toCtClass(Class[] rtclasses) throws NotFoundException {
-        int n = rtclasses.length;
-        CtClass[] ctclasses = new CtClass[n];
-        for (int i = 0; i < n; ++i)
-            ctclasses[i] = toCtClass(rtclasses[i]);
-
-        return ctclasses;
-    }
-
-    /* ms must not be an array of CtMethod.  To invoke a method ms[i]
-     * on a server, a client must send i to the server.
-     */
-    private void addMethods(CtClass proxy, Method[] ms)
-        throws CannotCompileException, NotFoundException
-    {
-        CtMethod wmethod;
-        for (int i = 0; i < ms.length; ++i) {
-            Method m = ms[i];
-            int mod = m.getModifiers();
-            if (m.getDeclaringClass() != Object.class
-                        && !Modifier.isFinal(mod))
-                if (Modifier.isPublic(mod)) {
-                    CtMethod body;
-                    if (Modifier.isStatic(mod))
-                        body = forwardStaticMethod;
-                    else
-                        body = forwardMethod;
-
-                    wmethod
-                        = CtNewMethod.wrapped(toCtClass(m.getReturnType()),
-                                              m.getName(),
-                                              toCtClass(m.getParameterTypes()),
-                                              exceptionForProxy,
-                                              body,
-                                              ConstParameter.integer(i),
-                                              proxy);
-                    wmethod.setModifiers(mod);
-                    proxy.addMethod(wmethod);
-                }
-                else if (!Modifier.isProtected(mod)
-                         && !Modifier.isPrivate(mod))
-                    // if package method
-                    throw new CannotCompileException(
-                        "the methods must be public, protected, or private.");
-        }
-    }
-
-    /**
-     * Adds a default constructor to the super classes.
-     */
-    private void modifySuperclass(CtClass orgclass)
-        throws CannotCompileException, NotFoundException
-    {
-        CtClass superclazz;
-        for (;; orgclass = superclazz) {
-            superclazz = orgclass.getSuperclass();
-            if (superclazz == null)
-                break;
-
-            try {
-                superclazz.getDeclaredConstructor(null);
-                break;  // the constructor with no arguments is found.
-            }
-            catch (NotFoundException e) {
-            }
-
-            superclazz.addConstructor(
-                        CtNewConstructor.defaultConstructor(superclazz));
-        }
-    }
-}
diff --git a/src/main/javassist/rmi/package.html b/src/main/javassist/rmi/package.html
deleted file mode 100644 (file)
index 5432a94..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-<html>
-<body>
-Sample implementation of remote method invocation.
-
-<p>This package enables applets to access remote objects
-running on the web server with regular Java syntax.
-It is provided as a sample implementation with Javassist.
-All the programs in this package uses only the regular
-Javassist API; they never call any hidden methods.
-
-<p>The most significant class of this package is
-<code>ObjectImporter</code>.
-See the description of this class first.
-
-</body>
-</html>
diff --git a/src/main/javassist/tools/HotSwapper.java b/src/main/javassist/tools/HotSwapper.java
deleted file mode 100644 (file)
index 7b5b5fa..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.tools;
-
-import com.sun.jdi.*;
-import com.sun.jdi.connect.*;
-import com.sun.jdi.event.*;
-import com.sun.jdi.request.*;
-import java.io.*;
-import java.util.*;
-
-class Trigger {
-    void doSwap() {}
-}
-
-/**
- * A utility class for dynamically reloading a class by
- * the Java Platform Debugger Architecture (JPDA), or <it>HotSwap</code>.
- * It works only with JDK 1.4 and later.
- *
- * <p><b>Note:</b> The new definition of the reloaded class must declare
- * the same set of methods and fields as the original definition.  The
- * schema change between the original and new definitions is not allowed
- * by the JPDA. 
- *
- * <p>To use this class, the JVM must be launched with the following
- * command line options:
- *
- * <ul>
- * <p>For Java 1.4,<br>
- * <pre>java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000</pre>
- * <p>For Java 5,<br>
- * <pre>java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000</pre>
- * </ul>
- *
- * <p>Note that 8000 is the port number used by <code>HotSwapper</code>.
- * Any port number can be specified.  Since <code>HotSwapper</code> does not
- * launch another JVM for running a target application, this port number
- * is used only for inter-thread communication.
- *
- * <p>Furthermore, <code>JAVA_HOME/lib/tools.jar</code> must be included
- * in the class path.
- *
- * <p>Using <code>HotSwapper</code> is easy.  See the following example:
- *
- * <ul><pre>
- * CtClass clazz = ...
- * byte[] classFile = clazz.toBytecode();
- * HotSwapper hs = new HostSwapper(8000);  // 8000 is a port number.
- * hs.reload("Test", classFile);
- * </pre></ul>
- *
- * <p><code>reload()</code>
- * first unload the <code>Test</code> class and load a new version of
- * the <code>Test</code> class.
- * <code>classFile</code> is a byte array containing the new contents of
- * the class file for the <code>Test</code> class.  The developers can
- * repatedly call <code>reload()</code> on the same <code>HotSwapper</code>
- * object so that they can reload a number of classes.
- *
- * @since 3.1
- */
-public class HotSwapper {
-    private VirtualMachine jvm;
-    private MethodEntryRequest request;
-    private Map newClassFiles;
-
-    private Trigger trigger;
-
-    private static final String HOST_NAME = "localhost";
-    private static final String TRIGGER_NAME = "javassist.tools.Trigger";
-
-    /**
-     * Connects to the JVM.
-     *
-     * @param port     the port number used for the connection to the JVM.
-     */
-    public HotSwapper(int port)
-        throws IOException, IllegalConnectorArgumentsException
-    {
-        this(Integer.toString(port));
-    }
-
-    /**
-     * Connects to the JVM.
-     *
-     * @param port     the port number used for the connection to the JVM.
-     */
-    public HotSwapper(String port)
-        throws IOException, IllegalConnectorArgumentsException
-    {
-        jvm = null;
-        request = null;
-        newClassFiles = null;
-        trigger = new Trigger();
-        AttachingConnector connector
-            = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
-
-        Map arguments = connector.defaultArguments();
-        ((Connector.Argument)arguments.get("hostname")).setValue(HOST_NAME);
-        ((Connector.Argument)arguments.get("port")).setValue(port);
-        jvm = connector.attach(arguments);
-        EventRequestManager manager = jvm.eventRequestManager();
-        request = methodEntryRequests(manager, TRIGGER_NAME);
-    }
-
-    private Connector findConnector(String connector) throws IOException {
-        List connectors = Bootstrap.virtualMachineManager().allConnectors();
-        Iterator iter = connectors.iterator();
-        while (iter.hasNext()) {
-            Connector con = (Connector)iter.next();
-            if (con.name().equals(connector)) {
-                return con;
-            }
-        }
-
-        throw new IOException("Not found: " + connector);
-    }
-
-    private static MethodEntryRequest methodEntryRequests(
-                                EventRequestManager manager,
-                                String classpattern) {
-        MethodEntryRequest mereq = manager.createMethodEntryRequest();
-        mereq.addClassFilter(classpattern);
-        mereq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
-        return mereq;
-    }
-
-    /* Stops triggering a hotswapper when reload() is called.
-     */
-    private void deleteEventRequest(EventRequestManager manager,
-                                    MethodEntryRequest request) {
-        manager.deleteEventRequest(request);
-    }
-
-    /**
-     * Reloads a class.
-     *
-     * @param className                the fully-qualified class name.
-     * @param classFile                the contents of the class file.
-     */
-    public void reload(String className, byte[] classFile) {
-        ReferenceType classtype = toRefType(className);
-        Map map = new HashMap();
-        map.put(classtype, classFile);
-        reload2(map, className);
-    }
-
-    /**
-     * Reloads a class.
-     *
-     * @param classFiles       a map between fully-qualified class names
-     *                         and class files.  The type of the class names
-     *                         is <code>String</code> and the type of the
-     *                         class files is <code>byte[]</code>.
-     */
-    public void reload(Map classFiles) {
-        Set set = classFiles.entrySet();
-        Iterator it = set.iterator();
-        Map map = new HashMap();
-        String className = null;
-        while (it.hasNext()) {
-            Map.Entry e = (Map.Entry)it.next();
-            className = (String)e.getKey();
-            map.put(toRefType(className), e.getValue());
-        }
-
-        if (className != null)
-            reload2(map, className + " etc.");
-    }
-
-    private ReferenceType toRefType(String className) {
-        List list = jvm.classesByName(className);
-        if (list == null || list.isEmpty())
-            throw new RuntimeException("no such a class: " + className);
-        else
-            return (ReferenceType)list.get(0);
-    }
-
-    private void reload2(Map map, String msg) {
-        synchronized (trigger) {
-            startDaemon();
-            newClassFiles = map;
-            request.enable();
-            trigger.doSwap();
-            request.disable();
-            Map ncf = newClassFiles;
-            if (ncf != null) {
-                newClassFiles = null;
-                throw new RuntimeException("failed to reload: " + msg);
-            }
-        }
-    }
-
-    private void startDaemon() {
-        new Thread() {
-            private void errorMsg(Throwable e) {
-                System.err.print("Exception in thread \"HotSwap\" ");
-                e.printStackTrace(System.err);
-            }
-
-            public void run() {
-                EventSet events = null;
-                try {
-                    events = waitEvent();
-                    EventIterator iter = events.eventIterator();
-                    while (iter.hasNext()) {
-                        Event event = iter.nextEvent();
-                        if (event instanceof MethodEntryEvent) {
-                            hotswap();
-                            break;
-                        }
-                    }
-                }
-                catch (Throwable e) {
-                    errorMsg(e);
-                }
-                try {
-                    if (events != null)
-                        events.resume();
-                }
-                catch (Throwable e) {
-                    errorMsg(e);
-                }
-            }
-        }.start();
-    }
-
-    EventSet waitEvent() throws InterruptedException {
-        EventQueue queue = jvm.eventQueue();
-        return queue.remove();
-    }
-
-    void hotswap() {
-        Map map = newClassFiles;
-        jvm.redefineClasses(map);
-        newClassFiles = null;
-    }
-}
index 1566e121c18852cfc871a9f090cce1b569df3af1..bee6208da323fc1097f588f95646f8c0337127bf 100644 (file)
@@ -1,6 +1,6 @@
 <html>
 <body>
-Utility classes.
+Covenient tools.
 
 </body>
 </html>
diff --git a/src/main/javassist/tools/reflect/CannotCreateException.java b/src/main/javassist/tools/reflect/CannotCreateException.java
new file mode 100644 (file)
index 0000000..efa1411
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+/**
+ * Signals that <code>ClassMetaobject.newInstance()</code> fails.
+ */
+public class CannotCreateException extends Exception {
+    public CannotCreateException(String s) {
+        super(s);
+    }
+
+    public CannotCreateException(Exception e) {
+        super("by " + e.toString());
+    }
+}
diff --git a/src/main/javassist/tools/reflect/CannotInvokeException.java b/src/main/javassist/tools/reflect/CannotInvokeException.java
new file mode 100644 (file)
index 0000000..d283d6d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.IllegalAccessException;
+
+/**
+ * Thrown when method invocation using the reflection API has thrown
+ * an exception.
+ *
+ * @see javassist.tools.reflect.Metaobject#trapMethodcall(int, Object[])
+ * @see javassist.tools.reflect.ClassMetaobject#trapMethodcall(int, Object[])
+ * @see javassist.tools.reflect.ClassMetaobject#invoke(Object, int, Object[])
+ */
+public class CannotInvokeException extends RuntimeException {
+
+    private Throwable err = null;
+
+    /**
+     * Returns the cause of this exception.  It may return null.
+     */
+    public Throwable getReason() { return err; }
+
+    /**
+     * Constructs a CannotInvokeException with an error message.
+     */
+    public CannotInvokeException(String reason) {
+        super(reason);
+    }
+
+    /**
+     * Constructs a CannotInvokeException with an InvocationTargetException.
+     */
+    public CannotInvokeException(InvocationTargetException e) {
+        super("by " + e.getTargetException().toString());
+        err = e.getTargetException();
+    }
+
+    /**
+     * Constructs a CannotInvokeException with an IllegalAccessException.
+     */
+    public CannotInvokeException(IllegalAccessException e) {
+        super("by " + e.toString());
+        err = e;
+    }
+
+    /**
+     * Constructs a CannotInvokeException with an ClassNotFoundException.
+     */
+    public CannotInvokeException(ClassNotFoundException e) {
+        super("by " + e.toString());
+        err = e;
+    }
+}
diff --git a/src/main/javassist/tools/reflect/CannotReflectException.java b/src/main/javassist/tools/reflect/CannotReflectException.java
new file mode 100644 (file)
index 0000000..30c448b
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import javassist.CannotCompileException;
+
+/**
+ * Thrown by <code>makeReflective()</code> in <code>Reflection</code>
+ * when there is an attempt to reflect
+ * a class that is either an interface or a subclass of
+ * either ClassMetaobject or Metaobject.
+ *
+ * @author Brett Randall
+ * @see javassist.tools.reflect.Reflection#makeReflective(CtClass,CtClass,CtClass)
+ * @see javassist.CannotCompileException
+ */
+public class CannotReflectException extends CannotCompileException {
+    public CannotReflectException(String msg) {
+        super(msg);
+    }
+}
diff --git a/src/main/javassist/tools/reflect/ClassMetaobject.java b/src/main/javassist/tools/reflect/ClassMetaobject.java
new file mode 100644 (file)
index 0000000..d0a645c
--- /dev/null
@@ -0,0 +1,367 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import java.lang.reflect.*;
+import java.util.Arrays;
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * A runtime class metaobject.
+ *
+ * <p>A <code>ClassMetaobject</code> is created for every
+ * class of reflective objects.  It can be used to hold values
+ * shared among the reflective objects of the same class.
+ *
+ * <p>To obtain a class metaobject, calls <code>_getClass()</code>
+ * on a reflective object.  For example,
+ *
+ * <ul><pre>ClassMetaobject cm = ((Metalevel)reflectiveObject)._getClass();
+ * </pre></ul>
+ *
+ * @see javassist.tools.reflect.Metaobject
+ * @see javassist.tools.reflect.Metalevel
+ */
+public class ClassMetaobject implements Serializable {
+    /**
+     * The base-level methods controlled by a metaobject
+     * are renamed so that they begin with
+     * <code>methodPrefix "_m_"</code>.
+     */
+    static final String methodPrefix = "_m_";
+    static final int methodPrefixLen = 3;
+
+    private Class javaClass;
+    private Constructor[] constructors;
+    private Method[] methods;
+
+    /**
+     * Specifies how a <code>java.lang.Class</code> object is loaded.
+     *
+     * <p>If true, it is loaded by:
+     * <ul><pre>Thread.currentThread().getContextClassLoader().loadClass()</pre></ul>
+     * <p>If false, it is loaded by <code>Class.forName()</code>.
+     * The default value is false.
+     */
+    public static boolean useContextClassLoader = false;
+
+    /**
+     * Constructs a <code>ClassMetaobject</code>.
+     *
+     * @param params    <code>params[0]</code> is the name of the class
+     *                  of the reflective objects.
+     */
+    public ClassMetaobject(String[] params)
+    {
+        try {
+            javaClass = getClassObject(params[0]);
+        }
+        catch (ClassNotFoundException e) {
+            javaClass = null;
+        }
+
+        constructors = javaClass.getConstructors();
+        methods = null;
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.writeUTF(javaClass.getName());
+    }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        javaClass = getClassObject(in.readUTF());
+        constructors = javaClass.getConstructors();
+        methods = null;
+    }
+
+    private Class getClassObject(String name) throws ClassNotFoundException {
+        if (useContextClassLoader)
+            return Thread.currentThread().getContextClassLoader()
+                   .loadClass(name);
+        else
+            return Class.forName(name);
+    }
+
+    /**
+     * Obtains the <code>java.lang.Class</code> representing this class.
+     */
+    public final Class getJavaClass() {
+        return javaClass;
+    }
+
+    /**
+     * Obtains the name of this class.
+     */
+    public final String getName() {
+        return javaClass.getName();
+    }
+
+    /**
+     * Returns true if <code>obj</code> is an instance of this class.
+     */
+    public final boolean isInstance(Object obj) {
+        return javaClass.isInstance(obj);
+    }
+
+    /**
+     * Creates a new instance of the class.
+     *
+     * @param args              the arguments passed to the constructor.
+     */
+    public final Object newInstance(Object[] args)
+        throws CannotCreateException
+    {
+        int n = constructors.length;
+        for (int i = 0; i < n; ++i) {
+            try {
+                return constructors[i].newInstance(args);
+            }
+            catch (IllegalArgumentException e) {
+                // try again
+            }
+            catch (InstantiationException e) {
+                throw new CannotCreateException(e);
+            }
+            catch (IllegalAccessException e) {
+                throw new CannotCreateException(e);
+            }
+            catch (InvocationTargetException e) {
+                throw new CannotCreateException(e);
+            }
+        }
+
+        throw new CannotCreateException("no constructor matches");
+    }
+
+    /**
+     * Is invoked when <code>static</code> fields of the base-level
+     * class are read and the runtime system intercepts it.
+     * This method simply returns the value of the field.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     */
+    public Object trapFieldRead(String name) {
+        Class jc = getJavaClass();
+        try {
+            return jc.getField(name).get(null);
+        }
+        catch (NoSuchFieldException e) {
+            throw new RuntimeException(e.toString());
+        }
+        catch (IllegalAccessException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    /**
+     * Is invoked when <code>static</code> fields of the base-level
+     * class are modified and the runtime system intercepts it.
+     * This method simply sets the field to the given value.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     */
+    public void trapFieldWrite(String name, Object value) {
+        Class jc = getJavaClass();
+        try {
+            jc.getField(name).set(null, value);
+        }
+        catch (NoSuchFieldException e) {
+            throw new RuntimeException(e.toString());
+        }
+        catch (IllegalAccessException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    /**
+     * Invokes a method whose name begins with
+     * <code>methodPrefix "_m_"</code> and the identifier.
+     *
+     * @exception CannotInvokeException         if the invocation fails.
+     */
+    static public Object invoke(Object target, int identifier, Object[] args)
+        throws Throwable
+    {
+        Method[] allmethods = target.getClass().getMethods();
+        int n = allmethods.length;
+        String head = methodPrefix + identifier;
+        for (int i = 0; i < n; ++i)
+            if (allmethods[i].getName().startsWith(head)) {
+                try {
+                    return allmethods[i].invoke(target, args);
+                } catch (java.lang.reflect.InvocationTargetException e) {
+                    throw e.getTargetException();
+                } catch (java.lang.IllegalAccessException e) {
+                    throw new CannotInvokeException(e);
+                }
+            }
+
+        throw new CannotInvokeException("cannot find a method");
+    }
+
+    /**
+     * Is invoked when <code>static</code> methods of the base-level
+     * class are called and the runtime system intercepts it.
+     * This method simply executes the intercepted method invocation
+     * with the original parameters and returns the resulting value.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     */
+    public Object trapMethodcall(int identifier, Object[] args) 
+        throws Throwable
+    {
+        try {
+            Method[] m = getReflectiveMethods();
+            return m[identifier].invoke(null, args);
+        }
+        catch (java.lang.reflect.InvocationTargetException e) {
+            throw e.getTargetException();
+        }
+        catch (java.lang.IllegalAccessException e) {
+            throw new CannotInvokeException(e);
+        }
+    }
+
+    /**
+     * Returns an array of the methods defined on the given reflective
+     * object.  This method is for the internal use only.
+     */
+    public final Method[] getReflectiveMethods() {
+        if (methods != null)
+            return methods;
+
+        Class baseclass = getJavaClass();
+        Method[] allmethods = baseclass.getDeclaredMethods();
+        int n = allmethods.length;
+        int[] index = new int[n];
+        int max = 0;
+        for (int i = 0; i < n; ++i) {
+            Method m = allmethods[i];
+            String mname = m.getName();
+            if (mname.startsWith(methodPrefix)) {
+                int k = 0;
+                for (int j = methodPrefixLen;; ++j) {
+                    char c = mname.charAt(j);
+                    if ('0' <= c && c <= '9')
+                        k = k * 10 + c - '0';
+                    else
+                        break;
+                }
+
+                index[i] = ++k;
+                if (k > max)
+                    max = k;
+            }
+        }
+
+        methods = new Method[max];
+        for (int i = 0; i < n; ++i)
+            if (index[i] > 0)
+                methods[index[i] - 1] = allmethods[i];
+
+        return methods;
+    }
+
+    /**
+     * Returns the <code>java.lang.reflect.Method</code> object representing
+     * the method specified by <code>identifier</code>.
+     *
+     * <p>Note that the actual method returned will be have an altered,
+     * reflective name i.e. <code>_m_2_..</code>.
+     *
+     * @param identifier        the identifier index
+     *                          given to <code>trapMethodcall()</code> etc.
+     * @see Metaobject#trapMethodcall(int,Object[])
+     * @see #trapMethodcall(int,Object[])
+     */
+    public final Method getMethod(int identifier) {
+        return getReflectiveMethods()[identifier];
+    }
+
+    /**
+     * Returns the name of the method specified
+     * by <code>identifier</code>.
+     */
+    public final String getMethodName(int identifier) {
+        String mname = getReflectiveMethods()[identifier].getName();
+        int j = ClassMetaobject.methodPrefixLen;
+        for (;;) {
+            char c = mname.charAt(j++);
+            if (c < '0' || '9' < c)
+                break;
+        }
+
+        return mname.substring(j);
+    }
+
+    /**
+     * Returns an array of <code>Class</code> objects representing the
+     * formal parameter types of the method specified
+     * by <code>identifier</code>.
+     */
+    public final Class[] getParameterTypes(int identifier) {
+        return getReflectiveMethods()[identifier].getParameterTypes();
+    }
+
+    /**
+     * Returns a <code>Class</code> objects representing the
+     * return type of the method specified by <code>identifier</code>.
+     */
+    public final Class getReturnType(int identifier) {
+        return getReflectiveMethods()[identifier].getReturnType();
+    }
+
+    /**
+     * Returns the identifier index of the method, as identified by its
+     * original name.
+     *
+     * <p>This method is useful, in conjuction with
+     * <link>ClassMetaobject#getMethod()</link>, to obtain a quick reference
+     * to the original method in the reflected class (i.e. not the proxy
+     * method), using the original name of the method.
+     *
+     * <p>Written by Brett Randall and Shigeru Chiba. 
+     *
+     * @param originalName      The original name of the reflected method
+     * @param argTypes          array of Class specifying the method signature
+     * @return      the identifier index of the original method
+     * @throws NoSuchMethodException    if the method does not exist
+     * 
+     * @see ClassMetaobject#getMethod(int)
+     */
+    public final int getMethodIndex(String originalName, Class[] argTypes)
+        throws NoSuchMethodException
+    {
+        Method[] mthds = getReflectiveMethods();
+        for (int i = 0; i < mthds.length; i++) {
+            if (mthds[i] == null)
+                continue;
+
+            // check name and parameter types match
+            if (getMethodName(i).equals(originalName)
+                && Arrays.equals(argTypes, mthds[i].getParameterTypes()))
+                return i;
+        }
+
+        throw new NoSuchMethodException("Method " + originalName
+                                        + " not found");
+    }
+}
diff --git a/src/main/javassist/tools/reflect/Compiler.java b/src/main/javassist/tools/reflect/Compiler.java
new file mode 100644 (file)
index 0000000..7e1fb94
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import javassist.CtClass;
+import javassist.ClassPool;
+import java.io.PrintStream;
+
+class CompiledClass {
+    public String classname;
+    public String metaobject;
+    public String classobject;
+}
+
+/**
+ * A bytecode translator for reflection.
+ *
+ * <p>This translator directly modifies class files on a local disk so that
+ * the classes represented by those class files are reflective.
+ * After the modification, the class files can be run with the standard JVM
+ * without <code>javassist.tools.reflect.Loader</code>
+ * or any other user-defined class loader.
+ *
+ * <p>The modified class files are given as the command-line parameters,
+ * which are a sequence of fully-qualified class names followed by options:
+ *
+ * <p><code>-m <i>classname</i></code> : specifies the class of the
+ * metaobjects associated with instances of the class followed by
+ * this option.  The default is <code>javassit.reflect.Metaobject</code>.
+ *
+ * <p><code>-c <i>classname</i></code> : specifies the class of the
+ * class metaobjects associated with instances of the class followed by
+ * this option.  The default is <code>javassit.reflect.ClassMetaobject</code>.
+ *
+ * <p>If a class name is not followed by any options, the class indicated
+ * by that class name is not reflective.
+ * 
+ * <p>For example,
+ * <ul><pre>% java Compiler Dog -m MetaDog -c CMetaDog Cat -m MetaCat Cow
+ * </pre></ul>
+ *
+ * <p>modifies class files <code>Dog.class</code>, <code>Cat.class</code>,
+ * and <code>Cow.class</code>.
+ * The metaobject of a Dog object is a MetaDog object and the class
+ * metaobject is a CMetaDog object.
+ * The metaobject of a Cat object is a MetaCat object but
+ * the class metaobject is a default one.
+ * Cow objects are not reflective.
+ *
+ * <p>Note that if the super class is also made reflective, it must be done
+ * before the sub class.
+ *
+ * @see javassist.tools.reflect.Metaobject
+ * @see javassist.tools.reflect.ClassMetaobject
+ * @see javassist.tools.reflect.Reflection
+ */
+public class Compiler {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            help(System.err);
+            return;
+        }
+
+        CompiledClass[] entries = new CompiledClass[args.length];
+        int n = parse(args, entries);
+
+        if (n < 1) {
+            System.err.println("bad parameter.");
+            return;
+        }
+
+        processClasses(entries, n);
+    }
+
+    private static void processClasses(CompiledClass[] entries, int n)
+        throws Exception
+    {
+        Reflection implementor = new Reflection();
+        ClassPool pool = ClassPool.getDefault();
+        implementor.start(pool);
+
+        for (int i = 0; i < n; ++i) {
+            CtClass c = pool.get(entries[i].classname);
+            if (entries[i].metaobject != null
+                                        || entries[i].classobject != null) {
+                String metaobj, classobj;
+
+                if (entries[i].metaobject == null)
+                    metaobj = "javassist.tools.reflect.Metaobject";
+                else
+                    metaobj = entries[i].metaobject;
+
+                if (entries[i].classobject == null)
+                    classobj = "javassist.tools.reflect.ClassMetaobject";
+                else
+                    classobj = entries[i].classobject;
+
+                if (!implementor.makeReflective(c, pool.get(metaobj),
+                                              pool.get(classobj)))
+                    System.err.println("Warning: " + c.getName()
+                                + " is reflective.  It was not changed.");
+
+                System.err.println(c.getName() + ": " + metaobj + ", "
+                                   + classobj);
+            }
+            else
+                System.err.println(c.getName() + ": not reflective");
+        }
+
+        for (int i = 0; i < n; ++i) {
+            implementor.onLoad(pool, entries[i].classname);
+            pool.get(entries[i].classname).writeFile();
+        }
+    }
+
+    private static int parse(String[] args, CompiledClass[] result) {
+        int n = -1;
+        for (int i = 0; i < args.length; ++i) {
+            String a = args[i];
+            if (a.equals("-m"))
+                if (n < 0 || i + 1 > args.length)
+                    return -1;
+                else
+                    result[n].metaobject = args[++i];
+            else if (a.equals("-c"))
+                if (n < 0 || i + 1 > args.length)
+                    return -1;
+                else
+                    result[n].classobject = args[++i];
+            else if (a.charAt(0) == '-')
+                return -1;
+            else {
+                CompiledClass cc = new CompiledClass();
+                cc.classname = a;
+                cc.metaobject = null;
+                cc.classobject = null;
+                result[++n] = cc;
+            }
+        }
+
+        return n + 1;
+    }
+
+    private static void help(PrintStream out) {
+        out.println("Usage: java javassist.tools.reflect.Compiler");
+        out.println("            (<class> [-m <metaobject>] [-c <class metaobject>])+");
+    }
+}
diff --git a/src/main/javassist/tools/reflect/Loader.java b/src/main/javassist/tools/reflect/Loader.java
new file mode 100644 (file)
index 0000000..36189ed
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import javassist.CannotCompileException;
+import javassist.NotFoundException;
+import javassist.ClassPool;
+
+/**
+ * A class loader for reflection.
+ *
+ * <p>To run a program, say <code>MyApp</code>,
+ * including a reflective class,
+ * you must write a start-up program as follows:
+ *
+ * <ul><pre>
+ * public class Main {
+ *   public static void main(String[] args) throws Throwable {
+ *     javassist.tools.reflect.Loader cl
+ *         = (javassist.tools.reflect.Loader)Main.class.getClassLoader();
+ *     cl.makeReflective("Person", "MyMetaobject",
+ *                       "javassist.tools.reflect.ClassMetaobject");
+ *     cl.run("MyApp", args);
+ *   }
+ * }
+ * </pre></ul>
+ *
+ * <p>Then run this program as follows:
+ *
+ * <ul><pre>% java javassist.tools.reflect.Loader Main arg1, ...</pre></ul>
+ *
+ * <p>This command runs <code>Main.main()</code> with <code>arg1</code>, ...
+ * and <code>Main.main()</code> runs <code>MyApp.main()</code> with
+ * <code>arg1</code>, ...
+ * The <code>Person</code> class is modified
+ * to be a reflective class.  Method calls on a <code>Person</code>
+ * object are intercepted by an instance of <code>MyMetaobject</code>.
+ *
+ * <p>Also, you can run <code>MyApp</code> in a slightly different way:
+ *
+ * <ul><pre>
+ * public class Main2 {
+ *   public static void main(String[] args) throws Throwable {
+ *     javassist.tools.reflect.Loader cl = new javassist.tools.reflect.Loader();
+ *     cl.makeReflective("Person", "MyMetaobject",
+ *                       "javassist.tools.reflect.ClassMetaobject");
+ *     cl.run("MyApp", args);
+ *   }
+ * }
+ * </pre></ul>
+ *
+ * <p>This program is run as follows:
+ *
+ * <ul><pre>% java Main2 arg1, ...</pre></ul>
+ *
+ * <p>The difference from the former one is that the class <code>Main</code>
+ * is loaded by <code>javassist.tools.reflect.Loader</code> whereas the class
+ * <code>Main2</code> is not.  Thus, <code>Main</code> belongs
+ * to the same name space (security domain) as <code>MyApp</code>
+ * whereas <code>Main2</code> does not; <code>Main2</code> belongs
+ * to the same name space as <code>javassist.tools.reflect.Loader</code>.
+ * For more details,
+ * see the notes in the manual page of <code>javassist.Loader</code>.
+ *
+ * <p>The class <code>Main2</code> is equivalent to this class:
+ *
+ * <ul><pre>
+ * public class Main3 {
+ *   public static void main(String[] args) throws Throwable {
+ *     Reflection reflection = new Reflection();
+ *     javassist.Loader cl
+ *         = new javassist.Loader(ClassPool.getDefault(reflection));
+ *     reflection.makeReflective("Person", "MyMetaobject",
+ *                               "javassist.tools.reflect.ClassMetaobject");
+ *     cl.run("MyApp", args);
+ *   }
+ * }
+ * </pre></ul>
+ *
+ * <p><b>Note:</b>
+ *
+ * <p><code>javassist.tools.reflect.Loader</code> does not make a class reflective
+ * if that class is in a <code>java.*</code> or
+ * <code>javax.*</code> pacakge because of the specifications
+ * on the class loading algorithm of Java.  The JVM does not allow to
+ * load such a system class with a user class loader.
+ *
+ * <p>To avoid this limitation, those classes should be statically
+ * modified with <code>javassist.tools.reflect.Compiler</code> and the original
+ * class files should be replaced.
+ *
+ * @see javassist.tools.reflect.Reflection
+ * @see javassist.tools.reflect.Compiler
+ * @see javassist.Loader
+ */
+public class Loader extends javassist.Loader {
+    protected Reflection reflection;
+
+    /**
+     * Loads a class with an instance of <code>Loader</code>
+     * and calls <code>main()</code> in that class.
+     *
+     * @param args              command line parameters.
+     * <ul>
+     * <code>args[0]</code> is the class name to be loaded.
+     * <br><code>args[1..n]</code> are parameters passed
+     *                      to the target <code>main()</code>.
+     * </ul>
+     */
+    public static void main(String[] args) throws Throwable {
+        Loader cl = new Loader();
+        cl.run(args);
+    }
+
+    /**
+     * Constructs a new class loader.
+     */
+    public Loader() throws CannotCompileException, NotFoundException {
+        super();
+        delegateLoadingOf("javassist.tools.reflect.Loader");
+
+        reflection = new Reflection();
+        ClassPool pool = ClassPool.getDefault();
+        addTranslator(pool, reflection);
+    }
+
+    /**
+     * Produces a reflective class.
+     * If the super class is also made reflective, it must be done
+     * before the sub class.
+     *
+     * @param clazz             the reflective class.
+     * @param metaobject        the class of metaobjects.
+     *                          It must be a subclass of
+     *                          <code>Metaobject</code>.
+     * @param metaclass         the class of the class metaobject.
+     *                          It must be a subclass of
+     *                          <code>ClassMetaobject</code>.
+     * @return <code>false</code>       if the class is already reflective.
+     *
+     * @see javassist.tools.reflect.Metaobject
+     * @see javassist.tools.reflect.ClassMetaobject
+     */
+    public boolean makeReflective(String clazz,
+                                  String metaobject, String metaclass)
+        throws CannotCompileException, NotFoundException
+    {
+        return reflection.makeReflective(clazz, metaobject, metaclass);
+    }
+}
diff --git a/src/main/javassist/tools/reflect/Metalevel.java b/src/main/javassist/tools/reflect/Metalevel.java
new file mode 100644 (file)
index 0000000..db45cad
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+/**
+ * An interface to access a metaobject and a class metaobject.
+ * This interface is implicitly implemented by the reflective
+ * class.
+ */
+public interface Metalevel {
+    /**
+     * Obtains the class metaobject associated with this object.
+     */
+    ClassMetaobject _getClass();
+
+    /**
+     * Obtains the metaobject associated with this object.
+     */
+    Metaobject _getMetaobject();
+
+    /**
+     * Changes the metaobject associated with this object.
+     */
+    void _setMetaobject(Metaobject m);
+}
diff --git a/src/main/javassist/tools/reflect/Metaobject.java b/src/main/javassist/tools/reflect/Metaobject.java
new file mode 100644 (file)
index 0000000..e89b539
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import java.lang.reflect.Method;
+import java.io.Serializable;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+
+/**
+ * A runtime metaobject.
+ *
+ * <p>A <code>Metaobject</code> is created for
+ * every object at the base level.  A different reflective object is
+ * associated with a different metaobject.
+ *
+ * <p>The metaobject intercepts method calls
+ * on the reflective object at the base-level.  To change the behavior
+ * of the method calls, a subclass of <code>Metaobject</code>
+ * should be defined.
+ *
+ * <p>To obtain a metaobject, calls <code>_getMetaobject()</code>
+ * on a reflective object.  For example,
+ *
+ * <ul><pre>Metaobject m = ((Metalevel)reflectiveObject)._getMetaobject();
+ * </pre></ul>
+ *
+ * @see javassist.tools.reflect.ClassMetaobject
+ * @see javassist.tools.reflect.Metalevel
+ */
+public class Metaobject implements Serializable {
+    protected ClassMetaobject classmetaobject;
+    protected Metalevel baseobject;
+    protected Method[] methods;
+
+    /**
+     * Constructs a <code>Metaobject</code>.  The metaobject is
+     * constructed before the constructor is called on the base-level
+     * object.
+     *
+     * @param self      the object that this metaobject is associated with.
+     * @param args      the parameters passed to the constructor of
+     *                  <code>self</code>.
+     */
+    public Metaobject(Object self, Object[] args) {
+        baseobject = (Metalevel)self;
+        classmetaobject = baseobject._getClass();
+        methods = classmetaobject.getReflectiveMethods();
+    }
+
+    /**
+     * Constructs a <code>Metaobject</code> without initialization.
+     * If calling this constructor, a subclass should be responsible
+     * for initialization.
+     */
+    protected Metaobject() {
+        baseobject = null;
+        classmetaobject = null;
+        methods = null;
+    }
+
+    private void writeObject(ObjectOutputStream out) throws IOException {
+        out.writeObject(baseobject);
+    }
+
+    private void readObject(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        baseobject = (Metalevel)in.readObject();
+        classmetaobject = baseobject._getClass();
+        methods = classmetaobject.getReflectiveMethods();
+    }
+
+    /**
+     * Obtains the class metaobject associated with this metaobject.
+     *
+     * @see javassist.tools.reflect.ClassMetaobject
+     */
+    public final ClassMetaobject getClassMetaobject() {
+        return classmetaobject;
+    }
+
+    /**
+     * Obtains the object controlled by this metaobject.
+     */
+    public final Object getObject() {
+        return baseobject;
+    }
+
+    /**
+     * Changes the object controlled by this metaobject.
+     *
+     * @param self      the object
+     */
+    public final void setObject(Object self) {
+        baseobject = (Metalevel)self;
+        classmetaobject = baseobject._getClass();
+        methods = classmetaobject.getReflectiveMethods();
+
+        // call _setMetaobject() after the metaobject is settled.
+        baseobject._setMetaobject(this);
+    }
+
+    /**
+     * Returns the name of the method specified
+     * by <code>identifier</code>.
+     */
+    public final String getMethodName(int identifier) {
+        String mname = methods[identifier].getName();
+        int j = ClassMetaobject.methodPrefixLen;
+        for (;;) {
+            char c = mname.charAt(j++);
+            if (c < '0' || '9' < c)
+                break;
+        }
+
+        return mname.substring(j);
+    }
+
+    /**
+     * Returns an array of <code>Class</code> objects representing the
+     * formal parameter types of the method specified
+     * by <code>identifier</code>.
+     */
+    public final Class[] getParameterTypes(int identifier) {
+        return methods[identifier].getParameterTypes();
+    }
+
+    /**
+     * Returns a <code>Class</code> objects representing the
+     * return type of the method specified by <code>identifier</code>.
+     */
+    public final Class getReturnType(int identifier) {
+        return methods[identifier].getReturnType();
+    }
+
+    /**
+     * Is invoked when public fields of the base-level
+     * class are read and the runtime system intercepts it.
+     * This method simply returns the value of the field.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     */
+    public Object trapFieldRead(String name) {
+        Class jc = getClassMetaobject().getJavaClass();
+        try {
+            return jc.getField(name).get(getObject());
+        }
+        catch (NoSuchFieldException e) {
+            throw new RuntimeException(e.toString());
+        }
+        catch (IllegalAccessException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    /**
+     * Is invoked when public fields of the base-level
+     * class are modified and the runtime system intercepts it.
+     * This method simply sets the field to the given value.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     */
+    public void trapFieldWrite(String name, Object value) {
+        Class jc = getClassMetaobject().getJavaClass();
+        try {
+            jc.getField(name).set(getObject(), value);
+        }
+        catch (NoSuchFieldException e) {
+            throw new RuntimeException(e.toString());
+        }
+        catch (IllegalAccessException e) {
+            throw new RuntimeException(e.toString());
+        }
+    }
+
+    /**
+     * Is invoked when base-level method invocation is intercepted.
+     * This method simply executes the intercepted method invocation
+     * with the original parameters and returns the resulting value.
+     *
+     * <p>Every subclass of this class should redefine this method.
+     *
+     * <p>Note: this method is not invoked if the base-level method
+     * is invoked by a constructor in the super class.  For example,
+     *
+     * <ul><pre>abstract class A {
+     *   abstract void initialize();
+     *   A() {
+     *       initialize();    // not intercepted
+     *   }
+     * }
+     *
+     * class B extends A {
+     *   void initialize() { System.out.println("initialize()"); }
+     *   B() {
+     *       super();
+     *       initialize();    // intercepted
+     *   }
+     * }</pre></ul>
+     *
+     * <p>if an instance of B is created,
+     * the invocation of initialize() in B is intercepted only once.
+     * The first invocation by the constructor in A is not intercepted.
+     * This is because the link between a base-level object and a
+     * metaobject is not created until the execution of a
+     * constructor of the super class finishes.
+     */
+    public Object trapMethodcall(int identifier, Object[] args) 
+        throws Throwable
+    {
+        try {
+            return methods[identifier].invoke(getObject(), args);
+        }
+        catch (java.lang.reflect.InvocationTargetException e) {
+            throw e.getTargetException();
+        }
+        catch (java.lang.IllegalAccessException e) {
+            throw new CannotInvokeException(e);
+        }
+    }
+}
diff --git a/src/main/javassist/tools/reflect/Reflection.java b/src/main/javassist/tools/reflect/Reflection.java
new file mode 100644 (file)
index 0000000..06ce2cc
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+import javassist.*;
+import javassist.CtMethod.ConstParameter;
+
+/**
+ * The class implementing the behavioral reflection mechanism.
+ *
+ * <p>If a class is reflective,
+ * then all the method invocations on every
+ * instance of that class are intercepted by the runtime
+ * metaobject controlling that instance.  The methods inherited from the
+ * super classes are also intercepted except final methods.  To intercept
+ * a final method in a super class, that super class must be also reflective.
+ *
+ * <p>To do this, the original class file representing a reflective class:
+ *
+ * <ul><pre>
+ * class Person {
+ *   public int f(int i) { return i + 1; }
+ *   public int value;
+ * }
+ * </pre></ul>
+ *
+ * <p>is modified so that it represents a class:
+ *
+ * <ul><pre>
+ * class Person implements Metalevel {
+ *   public int _original_f(int i) { return i + 1; }
+ *   public int f(int i) { <i>delegate to the metaobject</i> }
+ *
+ *   public int value;
+ *   public int _r_value() { <i>read "value"</i> }
+ *   public void _w_value(int v) { <i>write "value"</i> }
+ *
+ *   public ClassMetaobject _getClass() { <i>return a class metaobject</i> }
+ *   public Metaobject _getMetaobject() { <i>return a metaobject</i> }
+ *   public void _setMetaobject(Metaobject m) { <i>change a metaobject</i> }
+ * }
+ * </pre></ul>
+ *
+ * @see javassist.tools.reflect.ClassMetaobject
+ * @see javassist.tools.reflect.Metaobject
+ * @see javassist.tools.reflect.Loader
+ * @see javassist.tools.reflect.Compiler
+ */
+public class Reflection implements Translator {
+
+    static final String classobjectField = "_classobject";
+    static final String classobjectAccessor = "_getClass";
+    static final String metaobjectField = "_metaobject";
+    static final String metaobjectGetter = "_getMetaobject";
+    static final String metaobjectSetter = "_setMetaobject";
+    static final String readPrefix = "_r_";
+    static final String writePrefix = "_w_";
+
+    static final String metaobjectClassName = "javassist.tools.reflect.Metaobject";
+    static final String classMetaobjectClassName
+        = "javassist.tools.reflect.ClassMetaobject";
+
+    protected CtMethod trapMethod, trapStaticMethod;
+    protected CtMethod trapRead, trapWrite;
+    protected CtClass[] readParam;
+
+    protected ClassPool classPool;
+    protected CodeConverter converter;
+
+    private boolean isExcluded(String name) {
+        return name.startsWith(ClassMetaobject.methodPrefix)
+            || name.equals(classobjectAccessor)
+            || name.equals(metaobjectSetter)
+            || name.equals(metaobjectGetter)
+            || name.startsWith(readPrefix)
+            || name.startsWith(writePrefix);
+    }
+
+    /**
+     * Constructs a new <code>Reflection</code> object.
+     */
+    public Reflection() {
+        classPool = null;
+        converter = new CodeConverter();
+    }
+
+    /**
+     * Initializes the object.
+     */
+    public void start(ClassPool pool) throws NotFoundException {
+        classPool = pool;
+        final String msg
+            = "javassist.tools.reflect.Sample is not found or broken.";
+        try {
+            CtClass c = classPool.get("javassist.tools.reflect.Sample");
+            trapMethod = c.getDeclaredMethod("trap");
+            trapStaticMethod = c.getDeclaredMethod("trapStatic");
+            trapRead = c.getDeclaredMethod("trapRead");
+            trapWrite = c.getDeclaredMethod("trapWrite");
+            readParam
+                = new CtClass[] { classPool.get("java.lang.Object") };
+        }
+        catch (NotFoundException e) {
+            throw new RuntimeException(msg);
+        }
+    }
+
+    /**
+     * Inserts hooks for intercepting accesses to the fields declared
+     * in reflective classes.
+     */
+    public void onLoad(ClassPool pool, String classname)
+        throws CannotCompileException, NotFoundException
+    {
+        CtClass clazz = pool.get(classname);
+        clazz.instrument(converter);
+    }
+
+    /**
+     * Produces a reflective class.
+     * If the super class is also made reflective, it must be done
+     * before the sub class.
+     *
+     * @param classname         the name of the reflective class
+     * @param metaobject        the class name of metaobjects.
+     * @param metaclass         the class name of the class metaobject.
+     * @return <code>false</code>       if the class is already reflective.
+     *
+     * @see javassist.tools.reflect.Metaobject
+     * @see javassist.tools.reflect.ClassMetaobject
+     */
+    public boolean makeReflective(String classname,
+                                  String metaobject, String metaclass)
+        throws CannotCompileException, NotFoundException
+    {
+        return makeReflective(classPool.get(classname),
+                              classPool.get(metaobject),
+                              classPool.get(metaclass));
+    }
+
+    /**
+     * Produces a reflective class.
+     * If the super class is also made reflective, it must be done
+     * before the sub class.
+     *
+     * @param clazz             the reflective class.
+     * @param metaobject        the class of metaobjects.
+     *                          It must be a subclass of
+     *                          <code>Metaobject</code>.
+     * @param metaclass         the class of the class metaobject.
+     *                          It must be a subclass of
+     *                          <code>ClassMetaobject</code>.
+     * @return <code>false</code>       if the class is already reflective.
+     *
+     * @see javassist.tools.reflect.Metaobject
+     * @see javassist.tools.reflect.ClassMetaobject
+     */
+    public boolean makeReflective(Class clazz,
+                                  Class metaobject, Class metaclass)
+        throws CannotCompileException, NotFoundException
+    {
+        return makeReflective(clazz.getName(), metaobject.getName(),
+                              metaclass.getName());
+    }
+
+    /**
+     * Produces a reflective class.  It modifies the given
+     * <code>CtClass</code> object and makes it reflective.
+     * If the super class is also made reflective, it must be done
+     * before the sub class.
+     *
+     * @param clazz             the reflective class.
+     * @param metaobject        the class of metaobjects.
+     *                          It must be a subclass of
+     *                          <code>Metaobject</code>.
+     * @param metaclass         the class of the class metaobject.
+     *                          It must be a subclass of
+     *                          <code>ClassMetaobject</code>.
+     * @return <code>false</code>       if the class is already reflective.
+     *
+     * @see javassist.tools.reflect.Metaobject
+     * @see javassist.tools.reflect.ClassMetaobject
+     */
+    public boolean makeReflective(CtClass clazz,
+                                  CtClass metaobject, CtClass metaclass)
+        throws CannotCompileException, CannotReflectException,
+               NotFoundException
+    {
+        if (clazz.isInterface())
+            throw new CannotReflectException(
+                    "Cannot reflect an interface: " + clazz.getName());
+
+        if (clazz.subclassOf(classPool.get(classMetaobjectClassName)))
+            throw new CannotReflectException(
+                "Cannot reflect a subclass of ClassMetaobject: "
+                + clazz.getName());
+
+        if (clazz.subclassOf(classPool.get(metaobjectClassName)))
+            throw new CannotReflectException(
+                "Cannot reflect a subclass of Metaobject: "
+                + clazz.getName());
+
+        registerReflectiveClass(clazz);
+        return modifyClassfile(clazz, metaobject, metaclass);
+    }
+
+    /**
+     * Registers a reflective class.  The field accesses to the instances
+     * of this class are instrumented.
+     */
+    private void registerReflectiveClass(CtClass clazz) {
+        CtField[] fs = clazz.getDeclaredFields();
+        for (int i = 0; i < fs.length; ++i) {
+            CtField f = fs[i];
+            int mod = f.getModifiers();
+            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
+                String name = f.getName();
+                converter.replaceFieldRead(f, clazz, readPrefix + name);
+                converter.replaceFieldWrite(f, clazz, writePrefix + name);
+            }
+        }
+    }
+
+    private boolean modifyClassfile(CtClass clazz, CtClass metaobject,
+                                    CtClass metaclass)
+        throws CannotCompileException, NotFoundException
+    {
+        if (clazz.getAttribute("Reflective") != null)
+            return false;       // this is already reflective.
+        else
+            clazz.setAttribute("Reflective", new byte[0]);
+
+        CtClass mlevel = classPool.get("javassist.tools.reflect.Metalevel");
+        boolean addMeta = !clazz.subtypeOf(mlevel);
+        if (addMeta)
+            clazz.addInterface(mlevel);
+
+        processMethods(clazz, addMeta);
+        processFields(clazz);
+
+        CtField f;
+        if (addMeta) {
+            f = new CtField(classPool.get("javassist.tools.reflect.Metaobject"),
+                            metaobjectField, clazz);
+            f.setModifiers(Modifier.PROTECTED);
+            clazz.addField(f, CtField.Initializer.byNewWithParams(metaobject));
+
+            clazz.addMethod(CtNewMethod.getter(metaobjectGetter, f));
+            clazz.addMethod(CtNewMethod.setter(metaobjectSetter, f));
+        }
+
+        f = new CtField(classPool.get("javassist.tools.reflect.ClassMetaobject"),
+                        classobjectField, clazz);
+        f.setModifiers(Modifier.PRIVATE | Modifier.STATIC);
+        clazz.addField(f, CtField.Initializer.byNew(metaclass,
+                                        new String[] { clazz.getName() }));
+
+        clazz.addMethod(CtNewMethod.getter(classobjectAccessor, f));
+        return true;
+    }
+
+    private void processMethods(CtClass clazz, boolean dontSearch)
+        throws CannotCompileException, NotFoundException
+    {
+        CtMethod[] ms = clazz.getMethods();
+        for (int i = 0; i < ms.length; ++i) {
+            CtMethod m = ms[i];
+            int mod = m.getModifiers();
+            if (Modifier.isPublic(mod) && !Modifier.isAbstract(mod))
+                processMethods0(mod, clazz, m, i, dontSearch);
+        }
+    }
+
+    private void processMethods0(int mod, CtClass clazz,
+                        CtMethod m, int identifier, boolean dontSearch)
+        throws CannotCompileException, NotFoundException
+    {
+        CtMethod body;
+        String name = m.getName();
+
+        if (isExcluded(name))   // internally-used method inherited
+            return;             // from a reflective class.
+
+        CtMethod m2;
+        if (m.getDeclaringClass() == clazz) {
+            if (Modifier.isNative(mod))
+                return;
+
+            m2 = m;
+            if (Modifier.isFinal(mod)) {
+                mod &= ~Modifier.FINAL;
+                m2.setModifiers(mod);
+            }
+        }
+        else {
+            if (Modifier.isFinal(mod))
+                return;
+
+            mod &= ~Modifier.NATIVE;
+            m2 = CtNewMethod.delegator(findOriginal(m, dontSearch), clazz);
+            m2.setModifiers(mod);
+            clazz.addMethod(m2);
+        }
+
+        m2.setName(ClassMetaobject.methodPrefix + identifier
+                      + "_" + name);
+
+        if (Modifier.isStatic(mod))
+            body = trapStaticMethod;
+        else
+            body = trapMethod;
+
+        CtMethod wmethod
+            = CtNewMethod.wrapped(m.getReturnType(), name,
+                                  m.getParameterTypes(), m.getExceptionTypes(),
+                                  body, ConstParameter.integer(identifier),
+                                  clazz);
+        wmethod.setModifiers(mod);
+        clazz.addMethod(wmethod);
+    }
+
+    private CtMethod findOriginal(CtMethod m, boolean dontSearch)
+        throws NotFoundException
+    {
+        if (dontSearch)
+            return m;
+
+        String name = m.getName();
+        CtMethod[] ms = m.getDeclaringClass().getDeclaredMethods();
+        for (int i = 0; i < ms.length; ++i) {
+            String orgName = ms[i].getName();
+            if (orgName.endsWith(name)
+                && orgName.startsWith(ClassMetaobject.methodPrefix)
+                && ms[i].getSignature().equals(m.getSignature()))
+                return ms[i];
+        }
+
+        return m;
+    }
+
+    private void processFields(CtClass clazz)
+        throws CannotCompileException, NotFoundException
+    {
+        CtField[] fs = clazz.getDeclaredFields();
+        for (int i = 0; i < fs.length; ++i) {
+            CtField f = fs[i];
+            int mod = f.getModifiers();
+            if ((mod & Modifier.PUBLIC) != 0 && (mod & Modifier.FINAL) == 0) {
+                mod |= Modifier.STATIC;
+                String name = f.getName();
+                CtClass ftype = f.getType();
+                CtMethod wmethod
+                    = CtNewMethod.wrapped(ftype, readPrefix + name,
+                                          readParam, null, trapRead,
+                                          ConstParameter.string(name),
+                                          clazz);
+                wmethod.setModifiers(mod);
+                clazz.addMethod(wmethod);
+                CtClass[] writeParam = new CtClass[2];
+                writeParam[0] = classPool.get("java.lang.Object");
+                writeParam[1] = ftype;
+                wmethod = CtNewMethod.wrapped(CtClass.voidType,
+                                writePrefix + name,
+                                writeParam, null, trapWrite,
+                                ConstParameter.string(name), clazz);
+                wmethod.setModifiers(mod);
+                clazz.addMethod(wmethod);
+            }
+        }
+    }
+}
diff --git a/src/main/javassist/tools/reflect/Sample.java b/src/main/javassist/tools/reflect/Sample.java
new file mode 100644 (file)
index 0000000..4e70236
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.reflect;
+
+/**
+ * A template used for defining a reflective class.
+ */
+public class Sample {
+    private Metaobject _metaobject;
+    private static ClassMetaobject _classobject;
+
+    public Object trap(Object[] args, int identifier) throws Throwable {
+        Metaobject mobj;
+        mobj = _metaobject;
+        if (mobj == null)
+            return ClassMetaobject.invoke(this, identifier, args);
+        else
+            return mobj.trapMethodcall(identifier, args);
+    }
+
+    public static Object trapStatic(Object[] args, int identifier)
+        throws Throwable
+    {
+        return _classobject.trapMethodcall(identifier, args);
+    }
+
+    public static Object trapRead(Object[] args, String name) {
+        if (args[0] == null)
+            return _classobject.trapFieldRead(name);
+        else
+            return ((Metalevel)args[0])._getMetaobject().trapFieldRead(name);
+    }
+
+    public static Object trapWrite(Object[] args, String name) {
+        Metalevel base = (Metalevel)args[0];
+        if (base == null)
+            _classobject.trapFieldWrite(name, args[1]);
+        else
+            base._getMetaobject().trapFieldWrite(name, args[1]);
+
+        return null;
+    }
+}
diff --git a/src/main/javassist/tools/reflect/package.html b/src/main/javassist/tools/reflect/package.html
new file mode 100644 (file)
index 0000000..10a4196
--- /dev/null
@@ -0,0 +1,35 @@
+<html>
+<body>
+Runtime Behavioral Reflection.
+
+<p>(also recently known as interceptors or AOP?)
+
+<p>This package enables a metaobject to trap method calls and field
+accesses  on a regular Java object.  It provides a class
+<code>Reflection</code>, which is a main module for implementing
+runtime behavioral reflection.
+It also provides
+a class <code>Loader</code> and <code>Compiler</code>
+as utilities for dynamically or statically
+translating a regular class into a reflective class.
+
+<p>An instance of the reflective class is associated with
+a runtime metaobject and a runtime class metaobject, which control
+the behavior of that instance.
+The runtime
+metaobject is created for every (base-level) instance but the
+runtime class metaobject is created for every (base-level) class.
+<code>Metaobject</code> is the root class of the runtime
+metaobject and <code>ClassMetaobject</code> is the root class
+of the runtime class metaobject.
+
+<p>This package is provided as a sample implementation of the
+reflection mechanism with Javassist.  All the programs in this package
+uses only the regular Javassist API; they never call any hidden
+methods.
+
+<p>The most significant class in this package is <code>Reflection</code>.
+See the description of this class first.
+
+</body>
+</html>
diff --git a/src/main/javassist/tools/rmi/AppletServer.java b/src/main/javassist/tools/rmi/AppletServer.java
new file mode 100644 (file)
index 0000000..5056e24
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+import java.io.*;
+
+import javassist.tools.web.*;
+import javassist.CannotCompileException;
+import javassist.NotFoundException;
+import javassist.ClassPool;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import java.util.Vector;
+
+/**
+ * An AppletServer object is a web server that an ObjectImporter
+ * communicates with.  It makes the objects specified by
+ * <code>exportObject()</code> remotely accessible from applets.
+ * If the classes of the exported objects are requested by the client-side
+ * JVM, this web server sends proxy classes for the requested classes.
+ *
+ * @see javassist.tools.rmi.ObjectImporter
+ */
+public class AppletServer extends Webserver {
+    private StubGenerator stubGen;
+    private Hashtable exportedNames;
+    private Vector exportedObjects;
+
+    private static final byte[] okHeader
+                                = "HTTP/1.0 200 OK\r\n\r\n".getBytes();
+
+    /**
+     * Constructs a web server.
+     *
+     * @param port      port number
+     */
+    public AppletServer(String port)
+        throws IOException, NotFoundException, CannotCompileException
+    {
+        this(Integer.parseInt(port));
+    }
+
+    /**
+     * Constructs a web server.
+     *
+     * @param port      port number
+     */
+    public AppletServer(int port)
+        throws IOException, NotFoundException, CannotCompileException
+    {
+        this(ClassPool.getDefault(), new StubGenerator(), port);
+    }
+
+    /**
+     * Constructs a web server.
+     *
+     * @param port      port number
+     * @param src       the source of classs files.
+     */
+    public AppletServer(int port, ClassPool src)
+        throws IOException, NotFoundException, CannotCompileException
+    {
+        this(new ClassPool(src), new StubGenerator(), port);
+    }
+
+    private AppletServer(ClassPool loader, StubGenerator gen, int port)
+        throws IOException, NotFoundException, CannotCompileException
+    {
+        super(port);
+        exportedNames = new Hashtable();
+        exportedObjects = new Vector();
+        stubGen = gen;
+        addTranslator(loader, gen);
+    }
+
+    /**
+     * Begins the HTTP service.
+     */
+    public void run() {
+        super.run();
+    }
+
+    /**
+     * Exports an object.
+     * This method produces the bytecode of the proxy class used
+     * to access the exported object.  A remote applet can load
+     * the proxy class and call a method on the exported object.
+     *
+     * @param name      the name used for looking the object up.
+     * @param obj       the exported object.
+     * @return          the object identifier
+     *
+     * @see javassist.tools.rmi.ObjectImporter#lookupObject(String)
+     */
+    public synchronized int exportObject(String name, Object obj)
+        throws CannotCompileException
+    {
+        Class clazz = obj.getClass();
+        ExportedObject eo = new ExportedObject();
+        eo.object = obj;
+        eo.methods = clazz.getMethods();
+        exportedObjects.addElement(eo);
+        eo.identifier = exportedObjects.size() - 1;
+        if (name != null)
+            exportedNames.put(name, eo);
+
+        try {
+            stubGen.makeProxyClass(clazz);
+        }
+        catch (NotFoundException e) {
+            throw new CannotCompileException(e);
+        }
+
+        return eo.identifier;
+    }
+
+    /**
+     * Processes a request from a web browser (an ObjectImporter).
+     */
+    public void doReply(InputStream in, OutputStream out, String cmd)
+        throws IOException, BadHttpRequest
+    {
+        if (cmd.startsWith("POST /rmi "))
+            processRMI(in, out);
+        else if (cmd.startsWith("POST /lookup "))
+            lookupName(cmd, in, out);
+        else
+            super.doReply(in, out, cmd);
+    }
+
+    private void processRMI(InputStream ins, OutputStream outs)
+        throws IOException
+    {
+        ObjectInputStream in = new ObjectInputStream(ins);
+
+        int objectId = in.readInt();
+        int methodId = in.readInt();
+        Exception err = null;
+        Object rvalue = null;
+        try {
+            ExportedObject eo
+                = (ExportedObject)exportedObjects.elementAt(objectId);
+            Object[] args = readParameters(in);
+            rvalue = convertRvalue(eo.methods[methodId].invoke(eo.object,
+                                                               args));
+        }
+        catch(Exception e) {
+            err = e;
+            logging2(e.toString());
+        }
+
+        outs.write(okHeader);
+        ObjectOutputStream out = new ObjectOutputStream(outs);
+        if (err != null) {
+            out.writeBoolean(false);
+            out.writeUTF(err.toString());
+        }
+        else
+            try {
+                out.writeBoolean(true);
+                out.writeObject(rvalue);
+            }
+            catch (NotSerializableException e) {
+                logging2(e.toString());
+            }
+            catch (InvalidClassException e) {
+                logging2(e.toString());
+            }
+
+        out.flush();
+        out.close();
+        in.close();
+    }
+
+    private Object[] readParameters(ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        int n = in.readInt();
+        Object[] args = new Object[n];
+        for (int i = 0; i < n; ++i) {
+            Object a = in.readObject();
+            if (a instanceof RemoteRef) {
+                RemoteRef ref = (RemoteRef)a;
+                ExportedObject eo
+                    = (ExportedObject)exportedObjects.elementAt(ref.oid);
+                a = eo.object;
+            }
+
+            args[i] = a;
+        }
+
+        return args;
+    }
+
+    private Object convertRvalue(Object rvalue)
+        throws CannotCompileException
+    {
+        if (rvalue == null)
+            return null;        // the return type is void.
+
+        String classname = rvalue.getClass().getName();
+        if (stubGen.isProxyClass(classname))
+            return new RemoteRef(exportObject(null, rvalue), classname);
+        else
+            return rvalue;
+    }
+
+    private void lookupName(String cmd, InputStream ins, OutputStream outs)
+        throws IOException
+    {
+        ObjectInputStream in = new ObjectInputStream(ins);
+        String name = DataInputStream.readUTF(in);
+        ExportedObject found = (ExportedObject)exportedNames.get(name);
+        outs.write(okHeader);
+        ObjectOutputStream out = new ObjectOutputStream(outs);
+        if (found == null) {
+            logging2(name + "not found.");
+            out.writeInt(-1);           // error code
+            out.writeUTF("error");
+        }
+        else {
+            logging2(name);
+            out.writeInt(found.identifier);
+            out.writeUTF(found.object.getClass().getName());
+        }
+
+        out.flush();
+        out.close();
+        in.close();
+    }
+}
+
+class ExportedObject {
+    public int identifier;
+    public Object object;
+    public Method[] methods;
+}
diff --git a/src/main/javassist/tools/rmi/ObjectImporter.java b/src/main/javassist/tools/rmi/ObjectImporter.java
new file mode 100644 (file)
index 0000000..75f5aa6
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+import java.io.*;
+import java.net.*;
+import java.applet.Applet;
+import java.lang.reflect.*;
+
+/**
+ * The object importer enables applets to call a method on a remote
+ * object running on the <code>Webserver</code> (the <b>main</b> class of this
+ * package).
+ *
+ * <p>To access the remote
+ * object, the applet first calls <code>lookupObject()</code> and
+ * obtains a proxy object, which is a reference to that object.
+ * The class name of the proxy object is identical to that of
+ * the remote object.
+ * The proxy object provides the same set of methods as the remote object.
+ * If one of the methods is invoked on the proxy object,
+ * the invocation is delegated to the remote object.
+ * From the viewpoint of the applet, therefore, the two objects are
+ * identical. The applet can access the object on the server
+ * with the regular Java syntax without concern about the actual
+ * location.
+ *
+ * <p>The methods remotely called by the applet must be <code>public</code>.
+ * This is true even if the applet's class and the remote object's classs
+ * belong to the same package.
+ *
+ * <p>If class X is a class of remote objects, a subclass of X must be
+ * also a class of remote objects.  On the other hand, this restriction
+ * is not applied to the superclass of X.  The class X does not have to
+ * contain a constructor taking no arguments.
+ *
+ * <p>The parameters to a remote method is passed in the <i>call-by-value</i>
+ * manner.  Thus all the parameter classes must implement
+ * <code>java.io.Serializable</code>.  However, if the parameter is the
+ * proxy object, the reference to the remote object instead of a copy of
+ * the object is passed to the method.
+ *
+ * <p>Because of the limitations of the current implementation,
+ * <ul>
+ * <li>The parameter objects cannot contain the proxy
+ * object as a field value.
+ * <li>If class <code>C</code> is of the remote object, then
+ * the applet cannot instantiate <code>C</code> locally or remotely.
+ * </ul>
+ *
+ * <p>All the exceptions thrown by the remote object are converted
+ * into <code>RemoteException</code>.  Since this exception is a subclass
+ * of <code>RuntimeException</code>, the caller method does not need
+ * to catch the exception.  However, good programs should catch
+ * the <code>RuntimeException</code>.
+ *
+ * @see javassist.tools.rmi.AppletServer
+ * @see javassist.tools.rmi.RemoteException
+ * @see javassist.tools.web.Viewer
+ */
+public class ObjectImporter implements java.io.Serializable {
+    private final byte[] endofline = { 0x0d, 0x0a };
+    private String servername, orgServername;
+    private int port, orgPort;
+
+    protected byte[] lookupCommand = "POST /lookup HTTP/1.0".getBytes();
+    protected byte[] rmiCommand = "POST /rmi HTTP/1.0".getBytes();
+
+    /**
+     * Constructs an object importer.
+     *
+     * <p>Remote objects are imported from the web server that the given
+     * applet has been loaded from.
+     *
+     * @param applet    the applet loaded from the <code>Webserver</code>.
+     */
+    public ObjectImporter(Applet applet) {
+        URL codebase = applet.getCodeBase();
+        orgServername = servername = codebase.getHost();
+        orgPort = port = codebase.getPort();
+    }
+
+    /**
+     * Constructs an object importer.
+     *
+     * <p>If you run a program with <code>javassist.tools.web.Viewer</code>,
+     * you can construct an object importer as follows:
+     *
+     * <ul><pre>
+     * Viewer v = (Viewer)this.getClass().getClassLoader();
+     * ObjectImporter oi = new ObjectImporter(v.getServer(), v.getPort());
+     * </pre></ul>
+     *
+     * @see javassist.tools.web.Viewer
+     */
+    public ObjectImporter(String servername, int port) {
+        this.orgServername = this.servername = servername;
+        this.orgPort = this.port = port;
+    }
+
+    /**
+     * Finds the object exported by a server with the specified name.
+     * If the object is not found, this method returns null.
+     *
+     * @param name      the name of the exported object.
+     * @return          the proxy object or null.
+     */
+    public Object getObject(String name) {
+        try {
+            return lookupObject(name);
+        }
+        catch (ObjectNotFoundException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Sets an http proxy server.  After this method is called, the object
+     * importer connects a server through the http proxy server.
+     */
+    public void setHttpProxy(String host, int port) {
+        String proxyHeader = "POST http://" + orgServername + ":" + orgPort;
+        String cmd = proxyHeader + "/lookup HTTP/1.0";
+        lookupCommand = cmd.getBytes();
+        cmd = proxyHeader + "/rmi HTTP/1.0";
+        rmiCommand = cmd.getBytes();
+        this.servername = host;
+        this.port = port;
+    }
+
+    /**
+     * Finds the object exported by the server with the specified name.
+     * It sends a POST request to the server (via an http proxy server
+     * if needed).
+     *
+     * @param name      the name of the exported object.
+     * @return          the proxy object.
+     */
+    public Object lookupObject(String name) throws ObjectNotFoundException
+    {
+        try {
+            Socket sock = new Socket(servername, port);
+            OutputStream out = sock.getOutputStream();
+            out.write(lookupCommand);
+            out.write(endofline);
+            out.write(endofline);
+
+            ObjectOutputStream dout = new ObjectOutputStream(out);
+            dout.writeUTF(name);
+            dout.flush();
+
+            InputStream in = new BufferedInputStream(sock.getInputStream());
+            skipHeader(in);
+            ObjectInputStream din = new ObjectInputStream(in);
+            int n = din.readInt();
+            String classname = din.readUTF();
+            din.close();
+            dout.close();
+            sock.close();
+
+            if (n >= 0)
+                return createProxy(n, classname);
+        }
+        catch (Exception e) {
+            e.printStackTrace();
+            throw new ObjectNotFoundException(name, e);
+        }
+
+        throw new ObjectNotFoundException(name);
+    }
+
+    private static final Class[] proxyConstructorParamTypes
+        = new Class[] { ObjectImporter.class, int.class };
+
+    private Object createProxy(int oid, String classname) throws Exception {
+        Class c = Class.forName(classname);
+        Constructor cons = c.getConstructor(proxyConstructorParamTypes);
+        return cons.newInstance(new Object[] { this, new Integer(oid) });
+    }
+
+    /**
+     * Calls a method on a remote object.
+     * It sends a POST request to the server (via an http proxy server
+     * if needed).
+     *
+     * <p>This method is called by only proxy objects.
+     */
+    public Object call(int objectid, int methodid, Object[] args)
+        throws RemoteException
+    {
+        boolean result;
+        Object rvalue;
+        String errmsg;
+
+        try {
+            /* This method establishes a raw tcp connection for sending
+             * a POST message.  Thus the object cannot communicate a
+             * remote object beyond a fire wall.  To avoid this problem,
+             * the connection should be established with a mechanism
+             * collaborating a proxy server.  Unfortunately, java.lang.URL
+             * does not seem to provide such a mechanism.
+             *
+             * You might think that using HttpURLConnection is a better
+             * way than constructing a raw tcp connection.  Unfortunately,
+             * URL.openConnection() does not return an HttpURLConnection
+             * object in Netscape's JVM.  It returns a
+             * netscape.net.URLConnection object.
+             *
+             * lookupObject() has the same problem.
+             */
+            Socket sock = new Socket(servername, port);
+            OutputStream out = new BufferedOutputStream(
+                                                sock.getOutputStream());
+            out.write(rmiCommand);
+            out.write(endofline);
+            out.write(endofline);
+
+            ObjectOutputStream dout = new ObjectOutputStream(out);
+            dout.writeInt(objectid);
+            dout.writeInt(methodid);
+            writeParameters(dout, args);
+            dout.flush();
+
+            InputStream ins = new BufferedInputStream(sock.getInputStream());
+            skipHeader(ins);
+            ObjectInputStream din = new ObjectInputStream(ins);
+            result = din.readBoolean();
+            rvalue = null;
+            errmsg = null;
+            if (result)
+                rvalue = din.readObject();
+            else
+                errmsg = din.readUTF();
+
+            din.close();
+            dout.close();
+            sock.close();
+
+            if (rvalue instanceof RemoteRef) {
+                RemoteRef ref = (RemoteRef)rvalue;
+                rvalue = createProxy(ref.oid, ref.classname);
+            }
+        }
+        catch (ClassNotFoundException e) {
+            throw new RemoteException(e);
+        }
+        catch (IOException e) {
+            throw new RemoteException(e);
+        }
+        catch (Exception e) {
+            throw new RemoteException(e);
+        }
+
+        if (result)
+            return rvalue;
+        else
+            throw new RemoteException(errmsg);
+    }
+
+    private void skipHeader(InputStream in) throws IOException {
+        int len;
+        do {
+            int c;
+            len = 0;
+            while ((c = in.read()) >= 0 && c != 0x0d)
+                ++len;
+
+            in.read();  /* skip 0x0a (LF) */
+        } while (len > 0);
+    }
+
+    private void writeParameters(ObjectOutputStream dout, Object[] params)
+        throws IOException
+    {
+        int n = params.length;
+        dout.writeInt(n);
+        for (int i = 0; i < n; ++i)
+            if (params[i] instanceof Proxy) {
+                Proxy p = (Proxy)params[i];
+                dout.writeObject(new RemoteRef(p._getObjectId()));
+            }
+            else
+                dout.writeObject(params[i]);
+    }
+}
diff --git a/src/main/javassist/tools/rmi/ObjectNotFoundException.java b/src/main/javassist/tools/rmi/ObjectNotFoundException.java
new file mode 100644 (file)
index 0000000..e54a325
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+public class ObjectNotFoundException extends Exception {
+    public ObjectNotFoundException(String name) {
+        super(name + " is not exported");
+    }
+
+    public ObjectNotFoundException(String name, Exception e) {
+        super(name + " because of " + e.toString());
+    }
+}
diff --git a/src/main/javassist/tools/rmi/Proxy.java b/src/main/javassist/tools/rmi/Proxy.java
new file mode 100644 (file)
index 0000000..1512b87
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+/**
+ * An interface implemented by proxy classes.
+ *
+ * @see javassist.tools.rmi.StubGenerator
+ */
+public interface Proxy {
+    int _getObjectId();
+}
diff --git a/src/main/javassist/tools/rmi/RemoteException.java b/src/main/javassist/tools/rmi/RemoteException.java
new file mode 100644 (file)
index 0000000..27ebe71
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+/**
+ * <code>RemoteException</code> represents any exception thrown
+ * during remote method invocation.
+ */
+public class RemoteException extends RuntimeException {
+    public RemoteException(String msg) {
+        super(msg);
+    }
+
+    public RemoteException(Exception e) {
+        super("by " + e.toString());
+    }
+}
diff --git a/src/main/javassist/tools/rmi/RemoteRef.java b/src/main/javassist/tools/rmi/RemoteRef.java
new file mode 100644 (file)
index 0000000..edbf349
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+/**
+ * Remote reference.  This class is internally used for sending a remote
+ * reference through a network stream.
+ */
+public class RemoteRef implements java.io.Serializable {
+    public int oid;
+    public String classname;
+
+    public RemoteRef(int i) {
+        oid = i;
+        classname = null;
+    }
+
+    public RemoteRef(int i, String name) {
+        oid = i;
+        classname = name;
+    }
+}
diff --git a/src/main/javassist/tools/rmi/Sample.java b/src/main/javassist/tools/rmi/Sample.java
new file mode 100644 (file)
index 0000000..a65b908
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+/**
+ * A template used for defining a proxy class.
+ * The class file of this class is read by the <code>StubGenerator</code>
+ * class.
+ */
+public class Sample {
+    private ObjectImporter importer;
+    private int objectId;
+
+    public Object forward(Object[] args, int identifier) {
+        return importer.call(objectId, identifier, args);
+    }
+
+    public static Object forwardStatic(Object[] args, int identifier)
+        throws RemoteException
+    {
+        throw new RemoteException("cannot call a static method.");
+    }
+}
diff --git a/src/main/javassist/tools/rmi/StubGenerator.java b/src/main/javassist/tools/rmi/StubGenerator.java
new file mode 100644 (file)
index 0000000..7681bd6
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.rmi;
+
+import javassist.*;
+import java.lang.reflect.Method;
+import java.util.Hashtable;
+import javassist.CtMethod.ConstParameter;
+
+/**
+ * A stub-code generator.  It is used for producing a proxy class.
+ *
+ * <p>The proxy class for class A is as follows:
+ *
+ * <ul><pre>public class A implements Proxy, Serializable {
+ *   private ObjectImporter importer;
+ *   private int objectId;
+ *   public int _getObjectId() { return objectId; }
+ *   public A(ObjectImporter oi, int id) {
+ *     importer = oi; objectId = id;
+ *   }
+ *
+ *   ... the same methods that the original class A declares ...
+ * }</pre></ul>
+ *
+ * <p>Instances of the proxy class is created by an
+ * <code>ObjectImporter</code> object.
+ */
+public class StubGenerator implements Translator {
+    private static final String fieldImporter = "importer";
+    private static final String fieldObjectId = "objectId";
+    private static final String accessorObjectId = "_getObjectId";
+    private static final String sampleClass = "javassist.tools.rmi.Sample";
+
+    private ClassPool classPool;
+    private Hashtable proxyClasses;
+    private CtMethod forwardMethod;
+    private CtMethod forwardStaticMethod;
+
+    private CtClass[] proxyConstructorParamTypes;
+    private CtClass[] interfacesForProxy;
+    private CtClass[] exceptionForProxy;
+
+    /**
+     * Constructs a stub-code generator.
+     */
+    public StubGenerator() {
+        proxyClasses = new Hashtable();
+    }
+
+    /**
+     * Initializes the object.
+     * This is a method declared in javassist.Translator.
+     *
+     * @see javassist.Translator#start(ClassPool)
+     */
+    public void start(ClassPool pool) throws NotFoundException {
+        classPool = pool;
+        CtClass c = pool.get(sampleClass);
+        forwardMethod = c.getDeclaredMethod("forward");
+        forwardStaticMethod = c.getDeclaredMethod("forwardStatic");
+
+        proxyConstructorParamTypes
+            = pool.get(new String[] { "javassist.tools.rmi.ObjectImporter",
+                                         "int" });
+        interfacesForProxy
+            = pool.get(new String[] { "java.io.Serializable",
+                                         "javassist.tools.rmi.Proxy" });
+        exceptionForProxy
+            = new CtClass[] { pool.get("javassist.tools.rmi.RemoteException") };
+    }
+
+    /**
+     * Does nothing.
+     * This is a method declared in javassist.Translator.
+     * @see javassist.Translator#onLoad(ClassPool,String)
+     */
+    public void onLoad(ClassPool pool, String classname) {}
+
+    /**
+     * Returns <code>true</code> if the specified class is a proxy class
+     * recorded by <code>makeProxyClass()</code>.
+     *
+     * @param name              a fully-qualified class name
+     */
+    public boolean isProxyClass(String name) {
+        return proxyClasses.get(name) != null;
+    }
+
+    /**
+     * Makes a proxy class.  The produced class is substituted
+     * for the original class.
+     *
+     * @param clazz             the class referenced
+     *                          through the proxy class.
+     * @return          <code>false</code> if the proxy class
+     *                  has been already produced.
+     */
+    public synchronized boolean makeProxyClass(Class clazz)
+        throws CannotCompileException, NotFoundException
+    {
+        String classname = clazz.getName();
+        if (proxyClasses.get(classname) != null)
+            return false;
+        else {
+            CtClass ctclazz = produceProxyClass(classPool.get(classname),
+                                                clazz);
+            proxyClasses.put(classname, ctclazz);
+            modifySuperclass(ctclazz);
+            return true;
+        }
+    }
+
+    private CtClass produceProxyClass(CtClass orgclass, Class orgRtClass)
+        throws CannotCompileException, NotFoundException
+    {
+        int modify = orgclass.getModifiers();
+        if (Modifier.isAbstract(modify) || Modifier.isNative(modify)
+            || !Modifier.isPublic(modify))
+            throw new CannotCompileException(orgclass.getName()
+                        + " must be public, non-native, and non-abstract.");
+
+        CtClass proxy = classPool.makeClass(orgclass.getName(),
+                                              orgclass.getSuperclass());
+
+        proxy.setInterfaces(interfacesForProxy);
+
+        CtField f
+            = new CtField(classPool.get("javassist.tools.rmi.ObjectImporter"),
+                          fieldImporter, proxy);
+        f.setModifiers(Modifier.PRIVATE);
+        proxy.addField(f, CtField.Initializer.byParameter(0));
+
+        f = new CtField(CtClass.intType, fieldObjectId, proxy);
+        f.setModifiers(Modifier.PRIVATE);
+        proxy.addField(f, CtField.Initializer.byParameter(1)); 
+
+        proxy.addMethod(CtNewMethod.getter(accessorObjectId, f));
+
+        proxy.addConstructor(CtNewConstructor.defaultConstructor(proxy));
+        CtConstructor cons
+            = CtNewConstructor.skeleton(proxyConstructorParamTypes,
+                                        null, proxy);
+        proxy.addConstructor(cons);
+
+        try {
+            addMethods(proxy, orgRtClass.getMethods());
+            return proxy;
+        }
+        catch (SecurityException e) {
+            throw new CannotCompileException(e);
+        }
+    }
+
+    private CtClass toCtClass(Class rtclass) throws NotFoundException {
+        String name;
+        if (!rtclass.isArray())
+            name = rtclass.getName();
+        else {
+            StringBuffer sbuf = new StringBuffer();
+            do {
+                sbuf.append("[]");
+                rtclass = rtclass.getComponentType();
+            } while(rtclass.isArray());
+            sbuf.insert(0, rtclass.getName());
+            name = sbuf.toString();
+        }
+            
+        return classPool.get(name);
+    }
+
+    private CtClass[] toCtClass(Class[] rtclasses) throws NotFoundException {
+        int n = rtclasses.length;
+        CtClass[] ctclasses = new CtClass[n];
+        for (int i = 0; i < n; ++i)
+            ctclasses[i] = toCtClass(rtclasses[i]);
+
+        return ctclasses;
+    }
+
+    /* ms must not be an array of CtMethod.  To invoke a method ms[i]
+     * on a server, a client must send i to the server.
+     */
+    private void addMethods(CtClass proxy, Method[] ms)
+        throws CannotCompileException, NotFoundException
+    {
+        CtMethod wmethod;
+        for (int i = 0; i < ms.length; ++i) {
+            Method m = ms[i];
+            int mod = m.getModifiers();
+            if (m.getDeclaringClass() != Object.class
+                        && !Modifier.isFinal(mod))
+                if (Modifier.isPublic(mod)) {
+                    CtMethod body;
+                    if (Modifier.isStatic(mod))
+                        body = forwardStaticMethod;
+                    else
+                        body = forwardMethod;
+
+                    wmethod
+                        = CtNewMethod.wrapped(toCtClass(m.getReturnType()),
+                                              m.getName(),
+                                              toCtClass(m.getParameterTypes()),
+                                              exceptionForProxy,
+                                              body,
+                                              ConstParameter.integer(i),
+                                              proxy);
+                    wmethod.setModifiers(mod);
+                    proxy.addMethod(wmethod);
+                }
+                else if (!Modifier.isProtected(mod)
+                         && !Modifier.isPrivate(mod))
+                    // if package method
+                    throw new CannotCompileException(
+                        "the methods must be public, protected, or private.");
+        }
+    }
+
+    /**
+     * Adds a default constructor to the super classes.
+     */
+    private void modifySuperclass(CtClass orgclass)
+        throws CannotCompileException, NotFoundException
+    {
+        CtClass superclazz;
+        for (;; orgclass = superclazz) {
+            superclazz = orgclass.getSuperclass();
+            if (superclazz == null)
+                break;
+
+            try {
+                superclazz.getDeclaredConstructor(null);
+                break;  // the constructor with no arguments is found.
+            }
+            catch (NotFoundException e) {
+            }
+
+            superclazz.addConstructor(
+                        CtNewConstructor.defaultConstructor(superclazz));
+        }
+    }
+}
diff --git a/src/main/javassist/tools/rmi/package.html b/src/main/javassist/tools/rmi/package.html
new file mode 100644 (file)
index 0000000..5432a94
--- /dev/null
@@ -0,0 +1,16 @@
+<html>
+<body>
+Sample implementation of remote method invocation.
+
+<p>This package enables applets to access remote objects
+running on the web server with regular Java syntax.
+It is provided as a sample implementation with Javassist.
+All the programs in this package uses only the regular
+Javassist API; they never call any hidden methods.
+
+<p>The most significant class of this package is
+<code>ObjectImporter</code>.
+See the description of this class first.
+
+</body>
+</html>
diff --git a/src/main/javassist/tools/web/BadHttpRequest.java b/src/main/javassist/tools/web/BadHttpRequest.java
new file mode 100644 (file)
index 0000000..606ce99
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.web;
+
+/**
+ * Thrown when receiving an invalid HTTP request.
+ */
+public class BadHttpRequest extends Exception {
+    private Exception e;
+
+    public BadHttpRequest() { e = null; }
+
+    public BadHttpRequest(Exception _e) { e = _e; }
+
+    public String toString() {
+        if (e == null)
+            return super.toString();
+        else
+            return e.toString();
+    }
+}
diff --git a/src/main/javassist/tools/web/Viewer.java b/src/main/javassist/tools/web/Viewer.java
new file mode 100644 (file)
index 0000000..6e73740
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.web;
+
+import java.io.*;
+import java.net.*;
+
+/**
+ * A sample applet viewer.
+ *
+ * <p>This is a sort of applet viewer that can run any program even if
+ * the main class is not a subclass of <code>Applet</code>.
+ * This viewwer first calls <code>main()</code> in the main class.
+ *
+ * <p>To run, you should type:
+ *
+ * <ul><code>% java javassist.tools.web.Viewer <i>host port</i> Main arg1, ...</code></ul>
+ *
+ * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code>
+ * All classes including <code>Main</code> are fetched from
+ * a server http://<i>host</i>:<i>port</i>.
+ * Only the class file for <code>Viewer</code> must exist
+ * on a local file system at the client side; even other
+ * <code>javassist.*</code> classes are not needed at the client side.
+ * <code>Viewer</code> uses only Java core API classes.
+ *
+ * <p>Note: since a <code>Viewer</code> object is a class loader,
+ * a program loaded by this object can call a method in <code>Viewer</code>.
+ * For example, you can write something like this:
+ *
+ * <ul><pre>
+ * Viewer v = (Viewer)this.getClass().getClassLoader();
+ * String port = v.getPort();
+ * </pre></ul>
+ *
+ */
+public class Viewer extends ClassLoader {
+    private String server;
+    private int port;
+
+    /**
+     * Starts a program.
+     */
+    public static void main(String[] args) throws Throwable {
+        if (args.length >= 3) {
+            Viewer cl = new Viewer(args[0], Integer.parseInt(args[1]));
+            String[] args2 = new String[args.length - 3];
+            System.arraycopy(args, 3, args2, 0, args.length - 3);
+            cl.run(args[2], args2);
+        }
+        else
+            System.err.println(
+        "Usage: java javassist.tools.web.Viewer <host> <port> class [args ...]");
+    }
+
+    /**
+     * Constructs a viewer.
+     *
+     * @param host              server name
+     * @param p                 port number
+     */
+    public Viewer(String host, int p) {
+        server = host;
+        port = p;
+    }
+
+    /**
+     * Returns the server name.
+     */
+    public String getServer() { return server; }
+
+    /**
+     * Returns the port number.
+     */
+    public int getPort() { return port; }
+
+    /**
+     * Invokes main() in the class specified by <code>classname</code>.
+     *
+     * @param classname         executed class
+     * @param args              the arguments passed to <code>main()</code>.
+     */
+    public void run(String classname, String[] args)
+        throws Throwable
+    {
+        Class c = loadClass(classname);
+        try {
+            c.getDeclaredMethod("main", new Class[] { String[].class })
+                .invoke(null, new Object[] { args });
+        }
+        catch (java.lang.reflect.InvocationTargetException e) {
+            throw e.getTargetException();
+        }
+    }
+
+    /**
+     * Requests the class loader to load a class.
+     */
+    protected synchronized Class loadClass(String name, boolean resolve)
+        throws ClassNotFoundException
+    {
+        Class c = findLoadedClass(name);
+        if (c == null)
+            c = findClass(name);
+
+        if (c == null)
+            throw new ClassNotFoundException(name);
+
+        if (resolve)
+            resolveClass(c);
+
+        return c;
+    }
+
+    /**
+     * Finds the specified class.  The implementation in this class
+     * fetches the class from the http server.  If the class is
+     * either <code>java.*</code>, <code>javax.*</code>, or
+     * <code>Viewer</code>, then it is loaded by the parent class
+     * loader.
+     *
+     * <p>This method can be overridden by a subclass of
+     * <code>Viewer</code>.
+     */
+    protected Class findClass(String name) throws ClassNotFoundException {
+        Class c = null;
+        if (name.startsWith("java.") || name.startsWith("javax.")
+            || name.equals("javassist.tools.web.Viewer"))
+            c = findSystemClass(name);
+
+        if (c == null)
+            try {
+                byte[] b = fetchClass(name);
+                if (b != null)
+                    c = defineClass(name, b, 0, b.length);
+            }
+        catch (Exception e) {
+        }
+
+        return c;
+    }
+
+    /**
+     * Fetches the class file of the specified class from the http
+     * server.
+     */
+    protected byte[] fetchClass(String classname) throws Exception
+    {
+        byte[] b;
+        URL url = new URL("http", server, port,
+                          "/" + classname.replace('.', '/') + ".class");
+        URLConnection con = url.openConnection();
+        con.connect();
+        int size = con.getContentLength();
+        InputStream s = con.getInputStream();
+        if (size <= 0)
+            b = readStream(s);
+        else {
+            b = new byte[size];
+            int len = 0;
+            do {
+                int n = s.read(b, len, size - len);
+                if (n < 0) {
+                    s.close();
+                    throw new IOException("the stream was closed: "
+                                          + classname);
+                }
+                len += n;
+            } while (len < size);
+        }
+
+        s.close();
+        return b;
+    }
+
+    private byte[] readStream(InputStream fin) throws IOException {
+        byte[] buf = new byte[4096];
+        int size = 0;
+        int len = 0;
+        do {
+            size += len;
+            if (buf.length - size <= 0) {
+                byte[] newbuf = new byte[buf.length * 2];
+                System.arraycopy(buf, 0, newbuf, 0, size);
+                buf = newbuf;
+            }
+
+            len = fin.read(buf, size, buf.length - size);
+        } while (len >= 0);
+
+        byte[] result = new byte[size];
+        System.arraycopy(buf, 0, result, 0, size);
+        return result;
+    }
+}
diff --git a/src/main/javassist/tools/web/Webserver.java b/src/main/javassist/tools/web/Webserver.java
new file mode 100644 (file)
index 0000000..e580fec
--- /dev/null
@@ -0,0 +1,406 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.tools.web;
+
+import java.net.*;
+import java.io.*;
+import java.util.Date;
+import javassist.*;
+
+/**
+ * A web server for running sample programs.
+ *
+ * <p>This enables a Java program to instrument class files loaded by
+ * web browsers for applets.  Since the (standard) security manager
+ * does not allow an applet to create and use a class loader,
+ * instrumenting class files must be done by this web server.
+ *
+ * <p><b>Note:</b> although this class is included in the Javassist API,
+ * it is provided as a sample implementation of the web server using
+ * Javassist.  Especially, there might be security flaws in this server.
+ * Please use this with YOUR OWN RISK.
+ */
+public class Webserver {
+    private ServerSocket socket;
+    private ClassPool classPool;
+    protected Translator translator;
+
+    private final static byte[] endofline = { 0x0d, 0x0a };
+    private byte[] filebuffer = new byte[4096];
+
+    private final static int typeHtml = 1;
+    private final static int typeClass = 2;
+    private final static int typeGif = 3;
+    private final static int typeJpeg = 4;
+    private final static int typeText = 5;
+
+    /**
+     * If this field is not null, the class files taken from
+     * <code>ClassPool</code> are written out under the directory
+     * specified by this field.  The directory name must not end
+     * with a directory separator.
+     */
+    public String debugDir = null;
+
+    /**
+     * The top directory of html (and .gif, .class, ...) files.
+     * It must end with the directory separator such as "/".
+     * (For portability, "/" should be used as the directory separator.
+     * Javassist automatically translates "/" into a platform-dependent
+     * character.)
+     * If this field is null, the top directory is the current one where
+     * the JVM is running.
+     *
+     * <p>If the given URL indicates a class file and the class file
+     * is not found under the directory specified by this variable,
+     * then <code>Class.getResourceAsStream()</code> is called
+     * for searching the Java class paths.
+     */
+    public String htmlfileBase = null;
+
+    /**
+     * Starts a web server.
+     * The port number is specified by the first argument.
+     */
+    public static void main(String[] args) throws IOException {
+        if (args.length == 1) {
+            Webserver web = new Webserver(args[0]);
+            web.run();
+        }
+        else
+            System.err.println(
+                        "Usage: java javassist.tools.web.Webserver <port number>");
+    }
+
+    /**
+     * Constructs a web server.
+     *
+     * @param port      port number
+     */
+    public Webserver(String port) throws IOException {
+        this(Integer.parseInt(port));
+    }
+
+    /**
+     * Constructs a web server.
+     *
+     * @param port      port number
+     */
+    public Webserver(int port) throws IOException {
+        socket = new ServerSocket(port);
+        classPool = null;
+        translator = null;
+    }
+
+    /**
+     * Requests the web server to use the specified
+     * <code>ClassPool</code> object for obtaining a class file.
+     */
+    public void setClassPool(ClassPool loader) {
+        classPool = loader;
+    }
+
+    /**
+     * Adds a translator, which is called whenever a client requests
+     * a class file.
+     *
+     * @param cp        the <code>ClassPool</code> object for obtaining
+     *                  a class file.
+     * @param t         a translator.
+     */
+    public void addTranslator(ClassPool cp, Translator t)
+        throws NotFoundException, CannotCompileException
+    {
+        classPool = cp;
+        translator = t;
+        t.start(classPool);
+    }
+
+    /**
+     * Closes the socket.
+     */
+    public void end() throws IOException {
+        socket.close();
+    }
+
+    /**
+     * Prints a log message.
+     */
+    public void logging(String msg) {
+        System.out.println(msg);
+    }
+
+    /**
+     * Prints a log message.
+     */
+    public void logging(String msg1, String msg2) {
+        System.out.print(msg1);
+        System.out.print(" ");
+        System.out.println(msg2);
+    }
+
+    /**
+     * Prints a log message.
+     */
+    public void logging(String msg1, String msg2, String msg3) {
+        System.out.print(msg1);
+        System.out.print(" ");
+        System.out.print(msg2);
+        System.out.print(" ");
+        System.out.println(msg3);
+    }
+
+    /**
+     * Prints a log message with indentation.
+     */
+    public void logging2(String msg) {
+        System.out.print("    ");
+        System.out.println(msg);
+    }
+
+    /**
+     * Begins the HTTP service.
+     */
+    public void run() {
+        System.err.println("ready to service...");
+        for (;;)
+            try {
+                ServiceThread th = new ServiceThread(this, socket.accept());
+                th.start();
+            }
+            catch (IOException e) {
+                logging(e.toString());
+            }
+    }
+
+    final void process(Socket clnt) throws IOException {
+        InputStream in = new BufferedInputStream(clnt.getInputStream());
+        String cmd = readLine(in);
+        logging(clnt.getInetAddress().getHostName(),
+                new Date().toString(), cmd);
+        while (skipLine(in) > 0){
+        }
+
+        OutputStream out = new BufferedOutputStream(clnt.getOutputStream());
+        try {
+            doReply(in, out, cmd);
+        }
+        catch (BadHttpRequest e) {
+            replyError(out, e);
+        }
+
+        out.flush();
+        in.close();
+        out.close();
+        clnt.close();
+    }
+
+    private String readLine(InputStream in) throws IOException {
+        StringBuffer buf = new StringBuffer();
+        int c;
+        while ((c = in.read()) >= 0 && c != 0x0d)
+            buf.append((char)c);
+
+        in.read();      /* skip 0x0a (LF) */
+        return buf.toString();
+    }
+
+    private int skipLine(InputStream in) throws IOException {
+        int c;
+        int len = 0;
+        while ((c = in.read()) >= 0 && c != 0x0d)
+            ++len;
+
+        in.read();      /* skip 0x0a (LF) */
+        return len;
+    }
+
+    /**
+     * Proceses a HTTP request from a client.
+     *
+     * @param out       the output stream to a client
+     * @param cmd       the command received from a client
+     */
+    public void doReply(InputStream in, OutputStream out, String cmd)
+        throws IOException, BadHttpRequest
+    {
+        int len;
+        int fileType;
+        String filename, urlName;
+
+        if (cmd.startsWith("GET /"))
+            filename = urlName = cmd.substring(5, cmd.indexOf(' ', 5));
+        else
+            throw new BadHttpRequest();
+
+        if (filename.endsWith(".class"))
+            fileType = typeClass;
+        else if (filename.endsWith(".html") || filename.endsWith(".htm"))
+            fileType = typeHtml;
+        else if (filename.endsWith(".gif"))
+            fileType = typeGif;
+        else if (filename.endsWith(".jpg"))
+            fileType = typeJpeg;
+        else
+            fileType = typeText;        // or textUnknown
+
+        len = filename.length();
+        if (fileType == typeClass
+            && letUsersSendClassfile(out, filename, len))
+            return;
+
+        checkFilename(filename, len);
+        if (htmlfileBase != null)
+            filename = htmlfileBase + filename;
+
+        if (File.separatorChar != '/')
+            filename = filename.replace('/', File.separatorChar);
+
+        File file = new File(filename);
+        if (file.canRead()) {
+            sendHeader(out, file.length(), fileType);
+            FileInputStream fin = new FileInputStream(file);
+            for (;;) {
+                len = fin.read(filebuffer);
+                if (len <= 0)
+                    break;
+                else
+                    out.write(filebuffer, 0, len);
+            }
+
+            fin.close();
+            return;
+        }
+
+        // If the file is not found under the html-file directory,
+        // then Class.getResourceAsStream() is tried.
+
+        if (fileType == typeClass) {
+            InputStream fin
+                = getClass().getResourceAsStream("/" + urlName);
+            if (fin != null) {
+                ByteArrayOutputStream barray = new ByteArrayOutputStream();
+                for (;;) {
+                    len = fin.read(filebuffer);
+                    if (len <= 0)
+                        break;
+                    else
+                        barray.write(filebuffer, 0, len);
+                }
+
+                byte[] classfile = barray.toByteArray();
+                sendHeader(out, classfile.length, typeClass);
+                out.write(classfile);
+                fin.close();
+                return;
+            }
+        }
+
+        throw new BadHttpRequest();
+    }
+
+    private void checkFilename(String filename, int len)
+        throws BadHttpRequest
+    {
+        for (int i = 0; i < len; ++i) {
+            char c = filename.charAt(i);
+            if (!Character.isJavaIdentifierPart(c) && c != '.' && c != '/')
+                throw new BadHttpRequest();
+        }
+
+        if (filename.indexOf("..") >= 0)
+            throw new BadHttpRequest();
+    }
+
+    private boolean letUsersSendClassfile(OutputStream out,
+                                          String filename, int length)
+        throws IOException, BadHttpRequest
+    {
+        if (classPool == null)
+            return false;
+
+        byte[] classfile;
+        String classname
+            = filename.substring(0, length - 6).replace('/', '.');
+        try {
+            if (translator != null)
+                translator.onLoad(classPool, classname);
+
+            CtClass c = classPool.get(classname);
+            classfile = c.toBytecode();
+            if (debugDir != null)
+                c.writeFile(debugDir);
+        }
+        catch (Exception e) {
+            throw new BadHttpRequest(e);
+        }
+
+        sendHeader(out, classfile.length, typeClass);
+        out.write(classfile);
+        return true;
+    }
+
+    private void sendHeader(OutputStream out, long dataLength, int filetype)
+        throws IOException
+    {
+        out.write("HTTP/1.0 200 OK".getBytes());
+        out.write(endofline);
+        out.write("Content-Length: ".getBytes());
+        out.write(Long.toString(dataLength).getBytes());
+        out.write(endofline);
+        if (filetype == typeClass)
+            out.write("Content-Type: application/octet-stream".getBytes());
+        else if (filetype == typeHtml)
+            out.write("Content-Type: text/html".getBytes());
+        else if (filetype == typeGif)
+            out.write("Content-Type: image/gif".getBytes());
+        else if (filetype == typeJpeg)
+            out.write("Content-Type: image/jpg".getBytes());
+        else if (filetype == typeText)
+            out.write("Content-Type: text/plain".getBytes());
+
+        out.write(endofline);
+        out.write(endofline);
+    }
+
+    private void replyError(OutputStream out, BadHttpRequest e)
+        throws IOException
+    {
+        logging2("bad request: " + e.toString());
+        out.write("HTTP/1.0 400 Bad Request".getBytes());
+        out.write(endofline);
+        out.write(endofline);
+        out.write("<H1>Bad Request</H1>".getBytes());
+    }
+}
+
+class ServiceThread extends Thread {
+    Webserver web;
+    Socket sock;
+
+    public ServiceThread(Webserver w, Socket s) {
+        web = w;
+        sock = s;
+    }
+
+    public void run() {
+        try {
+            web.process(sock);
+        }
+        catch (IOException e) {
+        }
+    }
+}
diff --git a/src/main/javassist/tools/web/package.html b/src/main/javassist/tools/web/package.html
new file mode 100644 (file)
index 0000000..0c7fb45
--- /dev/null
@@ -0,0 +1,7 @@
+<html>
+<body>
+Simple web server for running sample code.
+
+<p>This package provides a simple web server for sample packages.
+</body>
+</html>
diff --git a/src/main/javassist/util/HotSwapper.java b/src/main/javassist/util/HotSwapper.java
new file mode 100644 (file)
index 0000000..07abe7a
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.util;
+
+import com.sun.jdi.*;
+import com.sun.jdi.connect.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+import java.io.*;
+import java.util.*;
+
+class Trigger {
+    void doSwap() {}
+}
+
+/**
+ * A utility class for dynamically reloading a class by
+ * the Java Platform Debugger Architecture (JPDA), or <it>HotSwap</code>.
+ * It works only with JDK 1.4 and later.
+ *
+ * <p><b>Note:</b> The new definition of the reloaded class must declare
+ * the same set of methods and fields as the original definition.  The
+ * schema change between the original and new definitions is not allowed
+ * by the JPDA. 
+ *
+ * <p>To use this class, the JVM must be launched with the following
+ * command line options:
+ *
+ * <ul>
+ * <p>For Java 1.4,<br>
+ * <pre>java -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000</pre>
+ * <p>For Java 5,<br>
+ * <pre>java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000</pre>
+ * </ul>
+ *
+ * <p>Note that 8000 is the port number used by <code>HotSwapper</code>.
+ * Any port number can be specified.  Since <code>HotSwapper</code> does not
+ * launch another JVM for running a target application, this port number
+ * is used only for inter-thread communication.
+ *
+ * <p>Furthermore, <code>JAVA_HOME/lib/tools.jar</code> must be included
+ * in the class path.
+ *
+ * <p>Using <code>HotSwapper</code> is easy.  See the following example:
+ *
+ * <ul><pre>
+ * CtClass clazz = ...
+ * byte[] classFile = clazz.toBytecode();
+ * HotSwapper hs = new HostSwapper(8000);  // 8000 is a port number.
+ * hs.reload("Test", classFile);
+ * </pre></ul>
+ *
+ * <p><code>reload()</code>
+ * first unload the <code>Test</code> class and load a new version of
+ * the <code>Test</code> class.
+ * <code>classFile</code> is a byte array containing the new contents of
+ * the class file for the <code>Test</code> class.  The developers can
+ * repatedly call <code>reload()</code> on the same <code>HotSwapper</code>
+ * object so that they can reload a number of classes.
+ *
+ * @since 3.1
+ */
+public class HotSwapper {
+    private VirtualMachine jvm;
+    private MethodEntryRequest request;
+    private Map newClassFiles;
+
+    private Trigger trigger;
+
+    private static final String HOST_NAME = "localhost";
+    private static final String TRIGGER_NAME = Trigger.class.getName();
+
+    /**
+     * Connects to the JVM.
+     *
+     * @param port     the port number used for the connection to the JVM.
+     */
+    public HotSwapper(int port)
+        throws IOException, IllegalConnectorArgumentsException
+    {
+        this(Integer.toString(port));
+    }
+
+    /**
+     * Connects to the JVM.
+     *
+     * @param port     the port number used for the connection to the JVM.
+     */
+    public HotSwapper(String port)
+        throws IOException, IllegalConnectorArgumentsException
+    {
+        jvm = null;
+        request = null;
+        newClassFiles = null;
+        trigger = new Trigger();
+        AttachingConnector connector
+            = (AttachingConnector)findConnector("com.sun.jdi.SocketAttach");
+
+        Map arguments = connector.defaultArguments();
+        ((Connector.Argument)arguments.get("hostname")).setValue(HOST_NAME);
+        ((Connector.Argument)arguments.get("port")).setValue(port);
+        jvm = connector.attach(arguments);
+        EventRequestManager manager = jvm.eventRequestManager();
+        request = methodEntryRequests(manager, TRIGGER_NAME);
+    }
+
+    private Connector findConnector(String connector) throws IOException {
+        List connectors = Bootstrap.virtualMachineManager().allConnectors();
+        Iterator iter = connectors.iterator();
+        while (iter.hasNext()) {
+            Connector con = (Connector)iter.next();
+            if (con.name().equals(connector)) {
+                return con;
+            }
+        }
+
+        throw new IOException("Not found: " + connector);
+    }
+
+    private static MethodEntryRequest methodEntryRequests(
+                                EventRequestManager manager,
+                                String classpattern) {
+        MethodEntryRequest mereq = manager.createMethodEntryRequest();
+        mereq.addClassFilter(classpattern);
+        mereq.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
+        return mereq;
+    }
+
+    /* Stops triggering a hotswapper when reload() is called.
+     */
+    private void deleteEventRequest(EventRequestManager manager,
+                                    MethodEntryRequest request) {
+        manager.deleteEventRequest(request);
+    }
+
+    /**
+     * Reloads a class.
+     *
+     * @param className                the fully-qualified class name.
+     * @param classFile                the contents of the class file.
+     */
+    public void reload(String className, byte[] classFile) {
+        ReferenceType classtype = toRefType(className);
+        Map map = new HashMap();
+        map.put(classtype, classFile);
+        reload2(map, className);
+    }
+
+    /**
+     * Reloads a class.
+     *
+     * @param classFiles       a map between fully-qualified class names
+     *                         and class files.  The type of the class names
+     *                         is <code>String</code> and the type of the
+     *                         class files is <code>byte[]</code>.
+     */
+    public void reload(Map classFiles) {
+        Set set = classFiles.entrySet();
+        Iterator it = set.iterator();
+        Map map = new HashMap();
+        String className = null;
+        while (it.hasNext()) {
+            Map.Entry e = (Map.Entry)it.next();
+            className = (String)e.getKey();
+            map.put(toRefType(className), e.getValue());
+        }
+
+        if (className != null)
+            reload2(map, className + " etc.");
+    }
+
+    private ReferenceType toRefType(String className) {
+        List list = jvm.classesByName(className);
+        if (list == null || list.isEmpty())
+            throw new RuntimeException("no such a class: " + className);
+        else
+            return (ReferenceType)list.get(0);
+    }
+
+    private void reload2(Map map, String msg) {
+        synchronized (trigger) {
+            startDaemon();
+            newClassFiles = map;
+            request.enable();
+            trigger.doSwap();
+            request.disable();
+            Map ncf = newClassFiles;
+            if (ncf != null) {
+                newClassFiles = null;
+                throw new RuntimeException("failed to reload: " + msg);
+            }
+        }
+    }
+
+    private void startDaemon() {
+        new Thread() {
+            private void errorMsg(Throwable e) {
+                System.err.print("Exception in thread \"HotSwap\" ");
+                e.printStackTrace(System.err);
+            }
+
+            public void run() {
+                EventSet events = null;
+                try {
+                    events = waitEvent();
+                    EventIterator iter = events.eventIterator();
+                    while (iter.hasNext()) {
+                        Event event = iter.nextEvent();
+                        if (event instanceof MethodEntryEvent) {
+                            hotswap();
+                            break;
+                        }
+                    }
+                }
+                catch (Throwable e) {
+                    errorMsg(e);
+                }
+                try {
+                    if (events != null)
+                        events.resume();
+                }
+                catch (Throwable e) {
+                    errorMsg(e);
+                }
+            }
+        }.start();
+    }
+
+    EventSet waitEvent() throws InterruptedException {
+        EventQueue queue = jvm.eventQueue();
+        return queue.remove();
+    }
+
+    void hotswap() {
+        Map map = newClassFiles;
+        jvm.redefineClasses(map);
+        newClassFiles = null;
+    }
+}
diff --git a/src/main/javassist/util/package.html b/src/main/javassist/util/package.html
new file mode 100644 (file)
index 0000000..349d996
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+Utility classes.
+</body>
+</html>
diff --git a/src/main/javassist/util/proxy/FactoryHelper.java b/src/main/javassist/util/proxy/FactoryHelper.java
new file mode 100644 (file)
index 0000000..01bd6bf
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.util.proxy;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import javassist.CannotCompileException;
+import javassist.bytecode.ClassFile;
+
+/**
+ * A helper class for implementing <code>ProxyFactory</code>.
+ * The users of <code>ProxyFactory</code> do not have to see this class.
+ *
+ * @see ProxyFactory
+ */
+public class FactoryHelper {
+    /**
+     * Returns an index for accessing arrays in this class.
+     *
+     * @throws RuntimeException     if a given type is not a primitive type.
+     */
+    public static final int typeIndex(Class type) {
+        Class[] list = primitiveTypes;
+        int n = list.length;
+        for (int i = 0; i < n; i++)
+            if (list[i] == type)
+                return i;
+
+        throw new RuntimeException("bad type:" + type.getName());
+    }
+
+    /**
+     * <code>Class</code> objects representing primitive types.
+     */
+    public static final Class[] primitiveTypes = {
+        Boolean.TYPE, Byte.TYPE, Character.TYPE, Short.TYPE, Integer.TYPE,
+        Long.TYPE, Float.TYPE, Double.TYPE, Void.TYPE
+    };
+
+    /**
+     * The fully-qualified names of wrapper classes for primitive types.
+     */
+    public static final String[] wrapperTypes = {
+        "java.lang.Boolean", "java.lang.Byte", "java.lang.Character",
+        "java.lang.Short", "java.lang.Integer", "java.lang.Long",
+        "java.lang.Float", "java.lang.Double", "java.lang.Void"
+    };
+
+    /**
+     * The descriptors of the constructors of wrapper classes.
+     */
+    public static final String[] wrapperDesc = {
+        "(Z)V", "(B)V", "(C)V", "(S)V", "(I)V", "(J)V",
+        "(F)V", "(D)V"
+    };
+
+    /**
+     * The names of methods for obtaining a primitive value
+     * from a wrapper object.  For example, <code>intValue()</code>
+     * is such a method for obtaining an integer value from a
+     * <code>java.lang.Integer</code> object.
+     */
+    public static final String[] unwarpMethods = {
+        "booleanValue", "byteValue", "charValue", "shortValue",
+        "intValue", "longValue", "floatValue", "doubleValue"
+    };
+
+    /**
+     * The descriptors of the unwrapping methods contained
+     * in <code>unwrapMethods</code>.
+     */
+    public static final String[] unwrapDesc = {
+        "()Z", "()B", "()C", "()S", "()I", "()J", "()F", "()D" 
+    };
+
+    /**
+     * The data size of primitive types.  <code>long</code>
+     * and <code>double</code> are 2; the others are 1.
+     */
+    public static final int[] dataSize = {
+        1, 1, 1, 1, 1, 2, 1, 2
+    };
+
+    /**
+     * Loads a class file by a given class loader.
+     */
+    public static Class toClass(ClassFile cf, ClassLoader loader)
+            throws CannotCompileException
+    {
+        try {
+            byte[] b = toBytecode(cf);
+            Class cl = Class.forName("java.lang.ClassLoader");
+            java.lang.reflect.Method method = cl.getDeclaredMethod(
+                    "defineClass", new Class[] { String.class, byte[].class,
+                    Integer.TYPE, Integer.TYPE });
+            method.setAccessible(true);
+            Object[] args = new Object[] { cf.getName(), b, new Integer(0),
+                    new Integer(b.length) };
+            Class clazz = (Class)method.invoke(loader, args);
+            method.setAccessible(false);
+            return clazz;
+        }
+        catch (RuntimeException e) {
+            throw e;
+        }
+        catch (java.lang.reflect.InvocationTargetException e) {
+            throw new CannotCompileException(e.getTargetException());
+        }
+        catch (Exception e) {
+            throw new CannotCompileException(e);
+        }
+    }
+
+    private static byte[] toBytecode(ClassFile cf) throws IOException {
+        ByteArrayOutputStream barray = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(barray);
+        try {
+            cf.write(out);
+        }
+        finally {
+            out.close();
+        }
+
+        return barray.toByteArray();
+    }
+
+    /**
+     * Writes a class file.
+     */
+    public static void writeFile(ClassFile cf, String directoryName)
+            throws CannotCompileException {
+        try {
+            writeFile0(cf, directoryName);
+        }
+        catch (IOException e) {
+            throw new CannotCompileException(e);
+        }
+    }
+
+    private static void writeFile0(ClassFile cf, String directoryName)
+            throws CannotCompileException, IOException {
+        String classname = cf.getName();
+        String filename = directoryName + File.separatorChar
+                + classname.replace('.', File.separatorChar) + ".class";
+        int pos = filename.lastIndexOf(File.separatorChar);
+        if (pos > 0) {
+            String dir = filename.substring(0, pos);
+            if (!dir.equals("."))
+                new File(dir).mkdirs();
+        }
+
+        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(
+                new FileOutputStream(filename)));
+        try {
+            cf.write(out);
+        }
+        catch (IOException e) {
+            throw e;
+        }
+        finally {
+            out.close();
+        }
+    }
+}
diff --git a/src/main/javassist/util/proxy/MethodFilter.java b/src/main/javassist/util/proxy/MethodFilter.java
new file mode 100644 (file)
index 0000000..67f9e40
--- /dev/null
@@ -0,0 +1,30 @@
+/*\r
+ * Javassist, a Java-bytecode translator toolkit.\r
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License.  Alternatively, the contents of this file may be used under\r
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ */\r
+\r
+package javassist.util.proxy;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+/**\r
+ * Selector of the methods implemented by a handler.\r
+ *\r
+ * @see ProxyFactory#setFilter(MethodFilter)\r
+ */\r
+public interface MethodFilter {\r
+    /**\r
+     * Returns true if the given method is implemented by a handler.\r
+     */\r
+    boolean isHandled(Method m);\r
+}\r
diff --git a/src/main/javassist/util/proxy/MethodHandler.java b/src/main/javassist/util/proxy/MethodHandler.java
new file mode 100644 (file)
index 0000000..7bd28ba
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Javassist, a Java-bytecode translator toolkit.\r
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License.  Alternatively, the contents of this file may be used under\r
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ */\r
+\r
+package javassist.util.proxy;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+/**\r
+ * The interface implemented by the invocation handler of a proxy\r
+ * instance.\r
+ *\r
+ * @see ProxyFactory#setHandler(MethodHandler)\r
+ */\r
+public interface MethodHandler {\r
+    /**\r
+     * Is called when a method is invoked on a proxy instance associated\r
+     * with this handler.  This method must process that method invocation.\r
+     *\r
+     * @param self          the proxy instance.\r
+     * @param thisMethod    the overridden method declared in the super\r
+     *                      class or interface.\r
+     * @param proceed       the forwarder method for invoking the overridden \r
+     *                      method.  It is null if the overridden mehtod is\r
+     *                      abstract or declared in the interface.\r
+     * @param args          an array of objects containing the values of\r
+     *                      the arguments passed in the method invocation\r
+     *                      on the proxy instance.  If a parameter type is\r
+     *                      a primitive type, the type of the array element\r
+     *                      is a wrapper class.\r
+     * @return              the resulting value of the method invocation.\r
+     *\r
+     * @throws Exception    if the method invocation fails.\r
+     */\r
+    Object invoke(Object self, Method thisMethod, Method proceed,\r
+                  Object[] args) throws Exception;\r
+}\r
diff --git a/src/main/javassist/util/proxy/ProxyFactory.java b/src/main/javassist/util/proxy/ProxyFactory.java
new file mode 100644 (file)
index 0000000..356c23b
--- /dev/null
@@ -0,0 +1,699 @@
+/*\r
+ * Javassist, a Java-bytecode translator toolkit.\r
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License.  Alternatively, the contents of this file may be used under\r
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ */\r
+\r
+package javassist.util.proxy;\r
+\r
+import java.lang.reflect.Field;\r
+import java.lang.reflect.Method;\r
+import java.lang.reflect.Constructor;\r
+import java.lang.reflect.Member;\r
+import java.lang.reflect.Modifier;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.Map;\r
+import java.util.Set;\r
+\r
+import javassist.CannotCompileException;\r
+import javassist.bytecode.*;\r
+\r
+/**\r
+ * Factory of dynamic proxy classes.\r
+ *\r
+ * <p>This factory generates a class that extends the given super class and implements\r
+ * the given interfaces.  The calls of the methods inherited from the super class are\r
+ * forwarded and then <code>invoke()</code> is called on the method handler\r
+ * associated with the generated class.  The calls of the methods from the interfaces\r
+ * are also forwarded to the method handler.\r
+ *\r
+ * <p>For example, if the following code is executed,\r
+ * \r
+ * <ul><pre>\r
+ * ProxyFactory f = new ProxyFactory();\r
+ * f.setSuperclass(Foo.class);\r
+ * MethodHandler mi = new MethodHandler() {\r
+ *     public Object invoke(Object self, Method m, Method proceed,\r
+ *                          Object[] args) throws Exception {\r
+ *         System.out.println("Name: " + m.getName());\r
+ *         proceed.invoke(self, args);  // execute the original method.\r
+ *     }\r
+ * };\r
+ * f.setHandler(mi);\r
+ * Class c = f.createClass();\r
+ * Foo foo = (Foo)c.newInstance();\r
+ * </pre></ul>\r
+ *\r
+ * <p>Then, the following method call will be forwarded to MethodHandler\r
+ * <code>mi</code> and prints a message before executing the originally called method\r
+ * <code>bar()</code> in <code>Foo</code>.\r
+ *\r
+ * <ul><pre>\r
+ * foo.bar();\r
+ * </pre></ul>\r
+ *\r
+ * <p>To change the method handler during runtime,\r
+ * execute the following code:\r
+ *\r
+ * <ul><pre>\r
+ * MethodHandler mi2 = ... ;    // another handler\r
+ * ((ProxyObject)foo).setHandler(mi2);\r
+ * </pre></ul>\r
+ *\r
+ * <p>Here is an example of method handler.  It does not execute\r
+ * anything except invoking the original method:\r
+ *\r
+ * <ul><pre>\r
+ * class SimpleHandler implements MethodHandler {\r
+ *     public Object invoke(Object self, Method m,\r
+ *                          Method proceed, Object[] args) throws Exception {\r
+ *         return proceed.invoke(self, args);\r
+ *     }\r
+ * }\r
+ * </pre></ul>\r
+ *\r
+ * @see MethodHandler\r
+ * @since 3.1\r
+ */\r
+public class ProxyFactory {\r
+    private Class superClass;\r
+    private Class[] interfaces;\r
+    private MethodFilter methodFilter;\r
+    private MethodHandler handler;\r
+    private Class thisClass;\r
+\r
+    /**\r
+     * If the value of this variable is not null, the class file of\r
+     * the generated proxy class is written under the directory specified\r
+     * by this variable.  For example, if the value is \r
+     * <code>"."</code>, then the class file is written under the current\r
+     * directory.  This method is for debugging.\r
+     *\r
+     * <p>The default value is null.\r
+     */\r
+    public String writeDirectory;\r
+\r
+    private static final Class OBJECT_TYPE = Object.class;\r
+\r
+    private static final String HOLDER = "_methods_";\r
+    private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";\r
+    private static final String HANDLER = "handler";\r
+    private static final String DEFAULT_INTERCEPTOR = "default_interceptor";\r
+    private static final String HANDLER_TYPE\r
+        = 'L' + MethodHandler.class.getName().replace('.', '/') + ';';\r
+    private static final String HANDLER_SETTER = "setHandler";\r
+    private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";\r
+\r
+    /**\r
+     * Constructs a factory of proxy class.\r
+     */\r
+    public ProxyFactory() {\r
+        superClass = null;\r
+        interfaces = null;\r
+        methodFilter = null;\r
+        handler = new MethodHandler() {\r
+            public Object invoke(Object self, Method m,\r
+                                 Method proceed, Object[] args)\r
+                throws Exception\r
+            {\r
+                return proceed.invoke(self, args);\r
+            }\r
+        };\r
+        thisClass = null;\r
+        writeDirectory = null;\r
+    }\r
+\r
+    /**\r
+     * Sets the super class of a proxy class.\r
+     */\r
+    public void setSuperclass(Class clazz) {\r
+        superClass = clazz;\r
+    }\r
+\r
+    /**\r
+     * Sets the interfaces of a proxy class.\r
+     */\r
+    public void setInterfaces(Class[] ifs) {\r
+        interfaces = ifs;\r
+    }\r
+\r
+    /**\r
+     * Sets a filter that selects the methods that will be controlled by a handler.\r
+     */\r
+    public void setFilter(MethodFilter mf) {\r
+        methodFilter = mf;\r
+    }\r
+\r
+    /**\r
+     * Generates a proxy class.\r
+     */\r
+    public Class createClass() {\r
+        if (thisClass == null)\r
+            try {\r
+                ClassFile cf = make();\r
+                ClassLoader cl = getClassLoader();\r
+                if (writeDirectory != null)\r
+                    FactoryHelper.writeFile(cf, writeDirectory);\r
+\r
+                thisClass = FactoryHelper.toClass(cf, cl);\r
+                setHandler();\r
+            }\r
+            catch (CannotCompileException e) {\r
+                throw new RuntimeException(e.getMessage(), e);\r
+            }\r
+\r
+        return thisClass;\r
+    }\r
+\r
+    protected ClassLoader getClassLoader() {\r
+        if (superClass != null && !superClass.getName().equals("java.lang.Object"))\r
+            return superClass.getClassLoader();\r
+        else if (interfaces != null && interfaces.length > 0)\r
+            return interfaces[0].getClassLoader();\r
+        else\r
+            return this.getClass().getClassLoader();\r
+            // return Thread.currentThread().getContextClassLoader();\r
+    }\r
+\r
+    /**\r
+     * Sets the default invocation handler.  This invocation handler is shared\r
+     * among all the instances of a proxy class unless another is explicitly\r
+     * specified.\r
+     */\r
+    public void setHandler(MethodHandler mi) {\r
+        handler = mi;\r
+        setHandler();\r
+    }\r
+\r
+    private void setHandler() {\r
+        if (thisClass != null && handler != null)\r
+            try {\r
+                Field f = thisClass.getField(DEFAULT_INTERCEPTOR);\r
+                f.setAccessible(true);\r
+                f.set(null, handler);\r
+                f.setAccessible(false);\r
+            }\r
+            catch (Exception e) {\r
+                throw new RuntimeException(e);\r
+            }\r
+    }\r
+\r
+    private static int counter = 0;\r
+\r
+    private ClassFile make() throws CannotCompileException {\r
+        String superName, classname;\r
+        if (interfaces == null)\r
+            interfaces = new Class[0];\r
+\r
+        if (superClass == null) {\r
+            superClass = OBJECT_TYPE;\r
+            superName = superClass.getName();\r
+            classname = interfaces.length == 0 ? superName\r
+                                               : interfaces[0].getName(); \r
+        }\r
+        else {\r
+            superName = superClass.getName();\r
+            classname = superName;\r
+        }\r
+\r
+        if (Modifier.isFinal(superClass.getModifiers()))\r
+            throw new CannotCompileException(superName + " is final");\r
+\r
+        // generate a proxy name.\r
+        classname = classname + "_$$_javassist_" + counter++;\r
+        if (classname.startsWith("java."))\r
+            classname = "org.javassist.tmp." + classname;\r
+\r
+        ClassFile cf = new ClassFile(false, classname, superName);\r
+        cf.setAccessFlags(AccessFlag.PUBLIC);\r
+        setInterfaces(cf, interfaces);\r
+        ConstPool pool = cf.getConstPool();\r
+        FieldInfo finfo = new FieldInfo(pool, DEFAULT_INTERCEPTOR, HANDLER_TYPE);\r
+        finfo.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);\r
+        cf.addField(finfo);\r
+\r
+        FieldInfo finfo2 = new FieldInfo(pool, HANDLER, HANDLER_TYPE);\r
+        finfo2.setAccessFlags(AccessFlag.PRIVATE);\r
+        cf.addField(finfo2);\r
+\r
+        HashMap allMethods = getMethods(superClass, interfaces);\r
+        int size = allMethods.size();\r
+        makeConstructors(classname, cf, pool, classname);\r
+        int s = overrideMethods(cf, pool, classname, allMethods);\r
+        addMethodsHolder(cf, pool, classname, s);\r
+        addSetter(classname, cf, pool);\r
+\r
+        thisClass = null;          \r
+        return cf;\r
+    }\r
+\r
+    private static void setInterfaces(ClassFile cf, Class[] interfaces) {\r
+        String setterIntf = ProxyObject.class.getName();\r
+        String[] list;\r
+        if (interfaces == null || interfaces.length == 0)\r
+            list = new String[] { setterIntf };\r
+        else {\r
+            list = new String[interfaces.length + 1];\r
+            for (int i = 0; i < interfaces.length; i++)\r
+                list[i] = interfaces[i].getName();\r
+\r
+            list[interfaces.length] = setterIntf;\r
+        }\r
+\r
+        cf.setInterfaces(list);\r
+    }\r
+\r
+    private static void addMethodsHolder(ClassFile cf, ConstPool cp,\r
+                                         String classname, int size)\r
+        throws CannotCompileException\r
+    {\r
+        FieldInfo finfo = new FieldInfo(cp, HOLDER, HOLDER_TYPE);\r
+        finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);\r
+        cf.addField(finfo);\r
+        MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");\r
+        Bytecode code = new Bytecode(cp, 0, 0);\r
+        code.addIconst(size * 2);\r
+        code.addAnewarray("java.lang.reflect.Method");\r
+        code.addPutstatic(classname, HOLDER, HOLDER_TYPE);\r
+        code.addOpcode(Bytecode.RETURN);\r
+        minfo.setCodeAttribute(code.toCodeAttribute());\r
+        cf.addMethod(minfo);\r
+    }\r
+\r
+    private static void addSetter(String classname, ClassFile cf, ConstPool cp)\r
+        throws CannotCompileException\r
+    {\r
+        MethodInfo minfo = new MethodInfo(cp, HANDLER_SETTER,\r
+                                          HANDLER_SETTER_TYPE);\r
+        minfo.setAccessFlags(AccessFlag.PUBLIC);\r
+        Bytecode code = new Bytecode(cp, 2, 2);\r
+        code.addAload(0);\r
+        code.addAload(1);\r
+        code.addPutfield(classname, HANDLER, HANDLER_TYPE);\r
+        code.addOpcode(Bytecode.RETURN);\r
+        minfo.setCodeAttribute(code.toCodeAttribute());\r
+        cf.addMethod(minfo);\r
+    }\r
+\r
+    private int overrideMethods(ClassFile cf, ConstPool cp, String className,\r
+                                HashMap allMethods)\r
+        throws CannotCompileException\r
+    {\r
+        String prefix = makeUniqueName("_d", allMethods);\r
+        Set entries = allMethods.entrySet();\r
+        Iterator it = entries.iterator();\r
+        int index = 0;\r
+        while (it.hasNext()) {\r
+            Map.Entry e = (Map.Entry)it.next();\r
+            String key = (String)e.getKey();\r
+            Method meth = (Method)e.getValue();\r
+            int mod = meth.getModifiers();\r
+            if (!Modifier.isFinal(mod) && !Modifier.isStatic(mod)\r
+                    && isVisible(mod, className, meth))\r
+                if (methodFilter == null || methodFilter.isHandled(meth))\r
+                    override(className, meth, prefix, index++,\r
+                             keyToDesc(key), cf, cp);\r
+        }\r
+\r
+        return index;\r
+    }\r
+\r
+    private void override(String thisClassname, Method meth, String prefix,\r
+                          int index, String desc, ClassFile cf, ConstPool cp)\r
+        throws CannotCompileException\r
+    {\r
+        Class declClass = meth.getDeclaringClass();\r
+        String delegatorName = prefix + index + meth.getName();\r
+        if (Modifier.isAbstract(meth.getModifiers()))\r
+            delegatorName = null;\r
+        else {\r
+            MethodInfo delegator\r
+                = makeDelegator(meth, desc, cp, declClass, delegatorName);\r
+            cf.addMethod(delegator);\r
+        }\r
+\r
+        MethodInfo forwarder\r
+            = makeForwarder(thisClassname, meth, desc, cp, declClass,\r
+                            delegatorName, index);\r
+        cf.addMethod(forwarder);\r
+    }\r
+\r
+    private void makeConstructors(String thisClassName, ClassFile cf,\r
+            ConstPool cp, String classname) throws CannotCompileException\r
+    {\r
+        Constructor[] cons = superClass.getDeclaredConstructors();\r
+        for (int i = 0; i < cons.length; i++) {\r
+            Constructor c = cons[i];\r
+            int mod = c.getModifiers();\r
+            if (!Modifier.isFinal(mod) && !Modifier.isPrivate(mod)\r
+                    && isVisible(mod, classname, c)) {\r
+                MethodInfo m = makeConstructor(thisClassName, c, cp, superClass);\r
+                cf.addMethod(m);\r
+            }\r
+        }\r
+    }\r
+\r
+    private static String makeUniqueName(String name, HashMap hash) {\r
+        Set keys = hash.keySet();\r
+        if (makeUniqueName0(name, keys.iterator()))\r
+            return name;\r
+\r
+        for (int i = 100; i < 999; i++) {\r
+            String s = name + i;\r
+            if (makeUniqueName0(s, keys.iterator()))\r
+                return s;\r
+        }\r
+\r
+        throw new RuntimeException("cannot make a unique method name");\r
+    }\r
+\r
+    private static boolean makeUniqueName0(String name, Iterator it) {\r
+        while (it.hasNext()) {\r
+            String key = (String)it.next();\r
+            if (key.startsWith(name))\r
+                return false;\r
+        }\r
+\r
+        return true;\r
+    }\r
+\r
+    /**\r
+     * Returns true if the method is visible from the class.\r
+     *\r
+     * @param mod       the modifiers of the method. \r
+     */\r
+    private static boolean isVisible(int mod, String from, Member meth) {\r
+        if ((mod & Modifier.PRIVATE) != 0)\r
+            return false;\r
+        else if ((mod & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0)\r
+            return true;\r
+        else {\r
+            String p = getPackageName(from);\r
+            String q = getPackageName(meth.getDeclaringClass().getName());\r
+            if (p == null)\r
+                return q == null;\r
+            else\r
+                return p.equals(q);\r
+        }\r
+    }\r
+\r
+    private static String getPackageName(String name) {\r
+        int i = name.lastIndexOf('.');\r
+        if (i < 0)\r
+            return null;\r
+        else\r
+            return name.substring(0, i);\r
+    }\r
+\r
+    private static HashMap getMethods(Class superClass, Class[] interfaceTypes) {\r
+        HashMap hash = new HashMap();\r
+        for (int i = 0; i < interfaceTypes.length; i++)\r
+            getMethods(hash, interfaceTypes[i]);\r
+\r
+        getMethods(hash, superClass);\r
+        return hash;\r
+    }\r
+\r
+    private static void getMethods(HashMap hash, Class clazz) {\r
+        Class[] ifs = clazz.getInterfaces();\r
+        for (int i = 0; i < ifs.length; i++)\r
+            getMethods(hash, ifs[i]);\r
+\r
+        Class parent = clazz.getSuperclass();\r
+        if (parent != null)\r
+            getMethods(hash, parent);\r
+\r
+        Method[] methods = clazz.getDeclaredMethods();\r
+        for (int i = 0; i < methods.length; i++)\r
+            if (!Modifier.isPrivate(methods[i].getModifiers())) {\r
+                Method m = methods[i];\r
+                String key = m.getName() + ':' + RuntimeSupport.makeDescriptor(m);\r
+                hash.put(key, methods[i]);\r
+            }\r
+    }\r
+\r
+    private static String keyToDesc(String key) {\r
+        return key.substring(key.indexOf(':') + 1);\r
+    }\r
+\r
+    private static MethodInfo makeConstructor(String thisClassName, Constructor cons,\r
+                                              ConstPool cp, Class superClass) {\r
+        String desc = RuntimeSupport.makeDescriptor(cons.getParameterTypes(),\r
+                                                    Void.TYPE);\r
+        MethodInfo minfo = new MethodInfo(cp, "<init>", desc);\r
+        minfo.setAccessFlags(Modifier.PUBLIC);      // cons.getModifiers() & ~Modifier.NATIVE\r
+        setThrows(minfo, cp, cons.getExceptionTypes());\r
+        Bytecode code = new Bytecode(cp, 0, 0);\r
+        code.addAload(0);\r
+        code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);\r
+        code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);\r
+        code.addAload(0);\r
+        int s = addLoadParameters(code, cons.getParameterTypes(), 1);\r
+        code.addInvokespecial(superClass.getName(), "<init>", desc);\r
+        code.addOpcode(Opcode.RETURN);\r
+        code.setMaxLocals(++s);\r
+        minfo.setCodeAttribute(code.toCodeAttribute());\r
+        return minfo;\r
+    }\r
+\r
+    private static MethodInfo makeDelegator(Method meth, String desc,\r
+                ConstPool cp, Class declClass, String delegatorName) {\r
+        MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);\r
+        delegator.setAccessFlags(Modifier.FINAL | Modifier.PUBLIC\r
+                | (meth.getModifiers() & ~(Modifier.PRIVATE\r
+                                           | Modifier.PROTECTED\r
+                                           | Modifier.ABSTRACT\r
+                                           | Modifier.NATIVE\r
+                                           | Modifier.SYNCHRONIZED)));\r
+        setThrows(delegator, cp, meth);\r
+        Bytecode code = new Bytecode(cp, 0, 0);\r
+        code.addAload(0);\r
+        int s = addLoadParameters(code, meth.getParameterTypes(), 1);\r
+        code.addInvokespecial(declClass.getName(), meth.getName(), desc);\r
+        addReturn(code, meth.getReturnType());\r
+        code.setMaxLocals(++s);\r
+        delegator.setCodeAttribute(code.toCodeAttribute());\r
+        return delegator;\r
+    }\r
+\r
+    /**\r
+     * @param delegatorName     null if the original method is abstract.\r
+     */\r
+    private static MethodInfo makeForwarder(String thisClassName,\r
+                    Method meth, String desc, ConstPool cp,\r
+                    Class declClass, String delegatorName, int index) {\r
+        MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);\r
+        forwarder.setAccessFlags(Modifier.FINAL\r
+                    | (meth.getModifiers() & ~(Modifier.ABSTRACT\r
+                                               | Modifier.NATIVE\r
+                                               | Modifier.SYNCHRONIZED)));\r
+        setThrows(forwarder, cp, meth);\r
+        int args = Descriptor.paramSize(desc);\r
+        Bytecode code = new Bytecode(cp, 0, args + 2);\r
+        /*\r
+         * if (methods[index * 2] == null) {\r
+         *   methods[index * 2]\r
+         *     = RuntimeSupport.findMethod(this, <overridden name>, <desc>);\r
+         *   methods[index * 2 + 1]\r
+         *     = RuntimeSupport.findMethod(this, <delegator name>, <desc>);\r
+         *     or = null // the original method is abstract.\r
+         * }\r
+         * return ($r)handler.invoke(this, methods[index * 2],\r
+         *                methods[index * 2 + 1], $args);\r
+         */\r
+        int origIndex = index * 2;\r
+        int delIndex = index * 2 + 1;\r
+        int arrayVar = args + 1;\r
+        code.addGetstatic(thisClassName, HOLDER, HOLDER_TYPE);\r
+        code.addAstore(arrayVar);\r
+        code.addAload(arrayVar);\r
+        code.addIconst(origIndex);\r
+        code.addOpcode(Opcode.AALOAD);\r
+        code.addOpcode(Opcode.IFNONNULL);\r
+        int pc = code.currentPc();\r
+        code.addIndex(0);\r
+\r
+        callFindMethod(code, "findSuperMethod", arrayVar, origIndex, meth.getName(), desc);\r
+        callFindMethod(code, "findMethod", arrayVar, delIndex, delegatorName, desc);\r
+\r
+        code.write16bit(pc, code.currentPc() - pc + 1);\r
+        code.addAload(0);\r
+        code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);\r
+        code.addAload(0);\r
+\r
+        code.addAload(arrayVar);\r
+        code.addIconst(origIndex);\r
+        code.addOpcode(Opcode.AALOAD);\r
+\r
+        code.addAload(arrayVar);\r
+        code.addIconst(delIndex);\r
+        code.addOpcode(Opcode.AALOAD);\r
+\r
+        makeParameterList(code, meth.getParameterTypes());\r
+        code.addInvokeinterface(MethodHandler.class.getName(), "invoke",\r
+            "(Ljava/lang/Object;Ljava/lang/reflect/Method;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;",\r
+            5);\r
+        Class retType = meth.getReturnType();\r
+        addUnwrapper(code, retType);\r
+        addReturn(code, retType);\r
+\r
+        forwarder.setCodeAttribute(code.toCodeAttribute());\r
+        return forwarder;\r
+    }\r
+\r
+    private static void setThrows(MethodInfo minfo, ConstPool cp, Method orig) {\r
+        Class[] exceptions = orig.getExceptionTypes();\r
+        setThrows(minfo, cp, exceptions);\r
+    }\r
+\r
+    private static void setThrows(MethodInfo minfo, ConstPool cp,\r
+                                  Class[] exceptions) {\r
+        if (exceptions.length == 0)\r
+            return;\r
+\r
+        String[] list = new String[exceptions.length];\r
+        for (int i = 0; i < exceptions.length; i++)\r
+            list[i] = exceptions[i].getName();\r
+\r
+        ExceptionsAttribute ea = new ExceptionsAttribute(cp);\r
+        ea.setExceptions(list);\r
+        minfo.setExceptionsAttribute(ea);\r
+    }\r
+\r
+    private static int addLoadParameters(Bytecode code, Class[] params,\r
+                                         int offset) {\r
+        int stacksize = 0;\r
+        int n = params.length;\r
+        for (int i = 0; i < n; ++i)\r
+            stacksize += addLoad(code, stacksize + offset, params[i]);\r
+\r
+        return stacksize;\r
+    }\r
+\r
+    private static int addLoad(Bytecode code, int n, Class type) {\r
+        if (type.isPrimitive()) {\r
+            if (type == Long.TYPE) {\r
+                code.addLload(n);\r
+                return 2;\r
+            }\r
+            else if (type == Float.TYPE)\r
+                code.addFload(n);\r
+            else if (type == Double.TYPE) {\r
+                code.addDload(n);\r
+                return 2;\r
+            }\r
+            else\r
+                code.addIload(n);\r
+        }\r
+        else\r
+            code.addAload(n);\r
+\r
+        return 1;\r
+    }\r
+\r
+    private static int addReturn(Bytecode code, Class type) {\r
+        if (type.isPrimitive()) {\r
+            if (type == Long.TYPE) {\r
+                code.addOpcode(Opcode.LRETURN);\r
+                return 2;\r
+            }\r
+            else if (type == Float.TYPE)\r
+                code.addOpcode(Opcode.FRETURN);\r
+            else if (type == Double.TYPE) {\r
+                code.addOpcode(Opcode.DRETURN);\r
+                return 2;\r
+            }\r
+            else if (type == Void.TYPE) {\r
+                code.addOpcode(Opcode.RETURN);\r
+                return 0;\r
+            }\r
+            else\r
+                code.addOpcode(Opcode.IRETURN);\r
+        }\r
+        else\r
+            code.addOpcode(Opcode.ARETURN);\r
+\r
+        return 1;\r
+    }\r
+\r
+    private static void makeParameterList(Bytecode code, Class[] params) {\r
+        int regno = 1;\r
+        int n = params.length;\r
+        code.addIconst(n);\r
+        code.addAnewarray("java/lang/Object");\r
+        for (int i = 0; i < n; i++) {\r
+            code.addOpcode(Opcode.DUP);\r
+            code.addIconst(i);\r
+            Class type = params[i];\r
+            if (type.isPrimitive())\r
+                regno = makeWrapper(code, type, regno);\r
+            else {\r
+                code.addAload(regno);\r
+                regno++;\r
+            }\r
+\r
+            code.addOpcode(Opcode.AASTORE);\r
+        }\r
+    }\r
+\r
+    private static int makeWrapper(Bytecode code, Class type, int regno) {\r
+        int index = FactoryHelper.typeIndex(type);\r
+        String wrapper = FactoryHelper.wrapperTypes[index]; \r
+        code.addNew(wrapper);\r
+        code.addOpcode(Opcode.DUP);\r
+        addLoad(code, regno, type);\r
+        code.addInvokespecial(wrapper, "<init>",\r
+                              FactoryHelper.wrapperDesc[index]);\r
+        return regno + FactoryHelper.dataSize[index];\r
+    }\r
+\r
+    /**\r
+     * @param methodName        might be null.\r
+     */\r
+    private static void callFindMethod(Bytecode code, String findMethod,\r
+            int arrayVar, int index, String methodName, String desc) {\r
+        String findClass = RuntimeSupport.class.getName();\r
+        String findDesc\r
+            = "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/reflect/Method;";\r
+\r
+        code.addAload(arrayVar);\r
+        code.addIconst(index);\r
+        if (methodName == null)\r
+            code.addOpcode(Opcode.ACONST_NULL);\r
+        else {\r
+            code.addAload(0);\r
+            code.addLdc(methodName);\r
+            code.addLdc(desc);\r
+            code.addInvokestatic(findClass, findMethod, findDesc);\r
+        }\r
+\r
+        code.addOpcode(Opcode.AASTORE);\r
+    }\r
+\r
+    private static void addUnwrapper(Bytecode code, Class type) {\r
+        if (type.isPrimitive()) {\r
+            if (type == Void.TYPE)\r
+                code.addOpcode(Opcode.POP);\r
+            else {\r
+                int index = FactoryHelper.typeIndex(type);\r
+                String wrapper = FactoryHelper.wrapperTypes[index];\r
+                code.addCheckcast(wrapper);\r
+                code.addInvokevirtual(wrapper,\r
+                                      FactoryHelper.unwarpMethods[index],\r
+                                      FactoryHelper.unwrapDesc[index]);\r
+            }\r
+        }\r
+        else\r
+            code.addCheckcast(type.getName());\r
+    }\r
+}\r
diff --git a/src/main/javassist/util/proxy/ProxyObject.java b/src/main/javassist/util/proxy/ProxyObject.java
new file mode 100644 (file)
index 0000000..4cba5c7
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License.  Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+
+package javassist.util.proxy;
+
+/**
+ * The interface implemented by proxy classes.
+ *
+ * @see ProxyFactory
+ */
+public interface ProxyObject {
+    /**
+     * Sets a handler.  It can be used for changing handlers
+     * during runtime.
+     */
+    void setHandler(MethodHandler mi);
+}
diff --git a/src/main/javassist/util/proxy/RuntimeSupport.java b/src/main/javassist/util/proxy/RuntimeSupport.java
new file mode 100644 (file)
index 0000000..837ed6c
--- /dev/null
@@ -0,0 +1,157 @@
+/*\r
+ * Javassist, a Java-bytecode translator toolkit.\r
+ * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.\r
+ *\r
+ * The contents of this file are subject to the Mozilla Public License Version\r
+ * 1.1 (the "License"); you may not use this file except in compliance with\r
+ * the License.  Alternatively, the contents of this file may be used under\r
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.\r
+ *\r
+ * Software distributed under the License is distributed on an "AS IS" basis,\r
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License\r
+ * for the specific language governing rights and limitations under the\r
+ * License.\r
+ */\r
+\r
+package javassist.util.proxy;\r
+\r
+import java.lang.reflect.Method;\r
+\r
+/**\r
+ * Runtime support routines that the classes generated by ProxyFactory use.\r
+ *\r
+ * @see ProxyFactory\r
+ */\r
+public class RuntimeSupport {\r
+    /**\r
+     * Finds a method with the given name and descriptor.\r
+     * It searches only the class of self.\r
+     *\r
+     * @throws RuntimeException     if the method is not found.\r
+     */\r
+    public static Method findMethod(Object self, String name, String desc) {\r
+        Method m = findMethod2(self.getClass(), name, desc);\r
+        if (m == null)\r
+            error(self, name, desc);\r
+\r
+        return m;\r
+    }\r
+\r
+    /**\r
+     * Finds a method that has the given name and descriptor and is declared\r
+     * in the super class.\r
+     *\r
+     * @throws RuntimeException     if the method is not found.\r
+     */\r
+    public static Method findSuperMethod(Object self, String name, String desc) {\r
+        Class clazz = self.getClass();\r
+        Method m = findSuperMethod2(clazz.getSuperclass(), name, desc);\r
+        if (m == null)\r
+            m = searchInterfaces(clazz, name, desc);\r
+\r
+        if (m == null)\r
+            error(self, name, desc);\r
+\r
+        return m;\r
+    }\r
+\r
+    private static void error(Object self, String name, String desc) {\r
+        throw new RuntimeException("not found " + name + ":" + desc\r
+                + " in " + self.getClass().getName());\r
+    }\r
+\r
+    private static Method findSuperMethod2(Class clazz, String name, String desc) {\r
+        Method m = findMethod2(clazz, name, desc);\r
+        if (m != null)\r
+            return m; \r
+\r
+        Class superClass = clazz.getSuperclass();\r
+        if (superClass != null) {\r
+            m = findSuperMethod2(superClass, name, desc);\r
+            if (m != null)\r
+                return m;\r
+        }\r
+\r
+        return searchInterfaces(clazz, name, desc);\r
+    }\r
+\r
+    private static Method searchInterfaces(Class clazz, String name, String desc) {\r
+        Method m = null;\r
+        Class[] interfaces = clazz.getInterfaces();\r
+        for (int i = 0; i < interfaces.length; i++) {\r
+            m = findSuperMethod2(interfaces[i], name, desc);\r
+            if (m != null)\r
+                return m;\r
+        }\r
+\r
+        return m;\r
+    }\r
+\r
+    private static Method findMethod2(Class clazz, String name, String desc) {\r
+        Method[] methods = clazz.getDeclaredMethods();\r
+        int n = methods.length;\r
+        for (int i = 0; i < n; i++)\r
+            if (methods[i].getName().equals(name)\r
+                && makeDescriptor(methods[i]).equals(desc))\r
+            return methods[i];\r
+\r
+        return null;\r
+    }\r
+\r
+    /**\r
+     * Makes a descriptor for a given method.\r
+     */\r
+    public static String makeDescriptor(Method m) {\r
+        Class[] params = m.getParameterTypes();\r
+        return makeDescriptor(params, m.getReturnType());\r
+    }\r
+\r
+    /**\r
+     * Makes a descriptor for a given method.\r
+     *\r
+     * @param params    parameter types.\r
+     * @param retType   return type.\r
+     */\r
+    public static String makeDescriptor(Class[] params, Class retType) {\r
+        StringBuffer sbuf = new StringBuffer();\r
+        sbuf.append('(');\r
+        for (int i = 0; i < params.length; i++)\r
+            makeDesc(sbuf, params[i]);\r
+\r
+        sbuf.append(')');\r
+        makeDesc(sbuf, retType);\r
+        return sbuf.toString();\r
+    }\r
+\r
+    private static void makeDesc(StringBuffer sbuf, Class type) {\r
+        if (type.isArray()) {\r
+            sbuf.append('[');\r
+            makeDesc(sbuf, type.getComponentType());\r
+        }\r
+        else if (type.isPrimitive()) {\r
+            if (type == Void.TYPE)\r
+                sbuf.append('V');\r
+            else if (type == Integer.TYPE)\r
+                sbuf.append('I');\r
+            else if (type == Byte.TYPE)\r
+                sbuf.append('B');\r
+            else if (type == Long.TYPE)\r
+                sbuf.append('J');\r
+            else if (type == Double.TYPE)\r
+                sbuf.append('D');\r
+            else if (type == Float.TYPE)\r
+                sbuf.append('F');\r
+            else if (type == Character.TYPE)\r
+                sbuf.append('C');\r
+            else if (type == Short.TYPE)\r
+                sbuf.append('S');\r
+            else if (type == Boolean.TYPE)\r
+                sbuf.append('Z');\r
+            else\r
+                throw new RuntimeException("bad type: " + type.getName());\r
+        }\r
+        else\r
+            sbuf.append('L').append(type.getName().replace('.', '/'))\r
+                .append(';');\r
+    }\r
+}\r
diff --git a/src/main/javassist/util/proxy/package.html b/src/main/javassist/util/proxy/package.html
new file mode 100644 (file)
index 0000000..6c1354f
--- /dev/null
@@ -0,0 +1,5 @@
+<html>
+<body>
+Dynamic proxy (similar to <code>Enhancer</code> of <a href="http://cglib.sourceforge.net/">cglib</a>).
+</body>
+</html>
diff --git a/src/main/javassist/web/BadHttpRequest.java b/src/main/javassist/web/BadHttpRequest.java
deleted file mode 100644 (file)
index a1aee86..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.web;
-
-/**
- * Thrown when receiving an invalid HTTP request.
- */
-public class BadHttpRequest extends Exception {
-    private Exception e;
-
-    public BadHttpRequest() { e = null; }
-
-    public BadHttpRequest(Exception _e) { e = _e; }
-
-    public String toString() {
-        if (e == null)
-            return super.toString();
-        else
-            return e.toString();
-    }
-}
diff --git a/src/main/javassist/web/Viewer.java b/src/main/javassist/web/Viewer.java
deleted file mode 100644 (file)
index debc52a..0000000
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.web;
-
-import java.io.*;
-import java.net.*;
-
-/**
- * A sample applet viewer.
- *
- * <p>This is a sort of applet viewer that can run any program even if
- * the main class is not a subclass of <code>Applet</code>.
- * This viewwer first calls <code>main()</code> in the main class.
- *
- * <p>To run, you should type:
- *
- * <ul><code>% java javassist.web.Viewer <i>host port</i> Main arg1, ...</code></ul>
- *
- * <p>This command calls <code>Main.main()</code> with <code>arg1,...</code>
- * All classes including <code>Main</code> are fetched from
- * a server http://<i>host</i>:<i>port</i>.
- * Only the class file for <code>Viewer</code> must exist
- * on a local file system at the client side; even other
- * <code>javassist.*</code> classes are not needed at the client side.
- * <code>Viewer</code> uses only Java core API classes.
- *
- * <p>Note: since a <code>Viewer</code> object is a class loader,
- * a program loaded by this object can call a method in <code>Viewer</code>.
- * For example, you can write something like this:
- *
- * <ul><pre>
- * Viewer v = (Viewer)this.getClass().getClassLoader();
- * String port = v.getPort();
- * </pre></ul>
- *
- */
-public class Viewer extends ClassLoader {
-    private String server;
-    private int port;
-
-    /**
-     * Starts a program.
-     */
-    public static void main(String[] args) throws Throwable {
-        if (args.length >= 3) {
-            Viewer cl = new Viewer(args[0], Integer.parseInt(args[1]));
-            String[] args2 = new String[args.length - 3];
-            System.arraycopy(args, 3, args2, 0, args.length - 3);
-            cl.run(args[2], args2);
-        }
-        else
-            System.err.println(
-        "Usage: java javassist.web.Viewer <host> <port> class [args ...]");
-    }
-
-    /**
-     * Constructs a viewer.
-     *
-     * @param host              server name
-     * @param p                 port number
-     */
-    public Viewer(String host, int p) {
-        server = host;
-        port = p;
-    }
-
-    /**
-     * Returns the server name.
-     */
-    public String getServer() { return server; }
-
-    /**
-     * Returns the port number.
-     */
-    public int getPort() { return port; }
-
-    /**
-     * Invokes main() in the class specified by <code>classname</code>.
-     *
-     * @param classname         executed class
-     * @param args              the arguments passed to <code>main()</code>.
-     */
-    public void run(String classname, String[] args)
-        throws Throwable
-    {
-        Class c = loadClass(classname);
-        try {
-            c.getDeclaredMethod("main", new Class[] { String[].class })
-                .invoke(null, new Object[] { args });
-        }
-        catch (java.lang.reflect.InvocationTargetException e) {
-            throw e.getTargetException();
-        }
-    }
-
-    /**
-     * Requests the class loader to load a class.
-     */
-    protected synchronized Class loadClass(String name, boolean resolve)
-        throws ClassNotFoundException
-    {
-        Class c = findLoadedClass(name);
-        if (c == null)
-            c = findClass(name);
-
-        if (c == null)
-            throw new ClassNotFoundException(name);
-
-        if (resolve)
-            resolveClass(c);
-
-        return c;
-    }
-
-    /**
-     * Finds the specified class.  The implementation in this class
-     * fetches the class from the http server.  If the class is
-     * either <code>java.*</code>, <code>javax.*</code>, or
-     * <code>Viewer</code>, then it is loaded by the parent class
-     * loader.
-     *
-     * <p>This method can be overridden by a subclass of
-     * <code>Viewer</code>.
-     */
-    protected Class findClass(String name) throws ClassNotFoundException {
-        Class c = null;
-        if (name.startsWith("java.") || name.startsWith("javax.")
-            || name.equals("javassist.web.Viewer"))
-            c = findSystemClass(name);
-
-        if (c == null)
-            try {
-                byte[] b = fetchClass(name);
-                if (b != null)
-                    c = defineClass(name, b, 0, b.length);
-            }
-        catch (Exception e) {
-        }
-
-        return c;
-    }
-
-    /**
-     * Fetches the class file of the specified class from the http
-     * server.
-     */
-    protected byte[] fetchClass(String classname) throws Exception
-    {
-        byte[] b;
-        URL url = new URL("http", server, port,
-                          "/" + classname.replace('.', '/') + ".class");
-        URLConnection con = url.openConnection();
-        con.connect();
-        int size = con.getContentLength();
-        InputStream s = con.getInputStream();
-        if (size <= 0)
-            b = readStream(s);
-        else {
-            b = new byte[size];
-            int len = 0;
-            do {
-                int n = s.read(b, len, size - len);
-                if (n < 0) {
-                    s.close();
-                    throw new IOException("the stream was closed: "
-                                          + classname);
-                }
-                len += n;
-            } while (len < size);
-        }
-
-        s.close();
-        return b;
-    }
-
-    private byte[] readStream(InputStream fin) throws IOException {
-        byte[] buf = new byte[4096];
-        int size = 0;
-        int len = 0;
-        do {
-            size += len;
-            if (buf.length - size <= 0) {
-                byte[] newbuf = new byte[buf.length * 2];
-                System.arraycopy(buf, 0, newbuf, 0, size);
-                buf = newbuf;
-            }
-
-            len = fin.read(buf, size, buf.length - size);
-        } while (len >= 0);
-
-        byte[] result = new byte[size];
-        System.arraycopy(buf, 0, result, 0, size);
-        return result;
-    }
-}
diff --git a/src/main/javassist/web/Webserver.java b/src/main/javassist/web/Webserver.java
deleted file mode 100644 (file)
index 4da031d..0000000
+++ /dev/null
@@ -1,406 +0,0 @@
-/*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License.  Alternatively, the contents of this file may be used under
- * the terms of the GNU Lesser General Public License Version 2.1 or later.
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- */
-
-package javassist.web;
-
-import java.net.*;
-import java.io.*;
-import java.util.Date;
-import javassist.*;
-
-/**
- * A web server for running sample programs.
- *
- * <p>This enables a Java program to instrument class files loaded by
- * web browsers for applets.  Since the (standard) security manager
- * does not allow an applet to create and use a class loader,
- * instrumenting class files must be done by this web server.
- *
- * <p><b>Note:</b> although this class is included in the Javassist API,
- * it is provided as a sample implementation of the web server using
- * Javassist.  Especially, there might be security flaws in this server.
- * Please use this with YOUR OWN RISK.
- */
-public class Webserver {
-    private ServerSocket socket;
-    private ClassPool classPool;
-    protected Translator translator;
-
-    private final static byte[] endofline = { 0x0d, 0x0a };
-    private byte[] filebuffer = new byte[4096];
-
-    private final static int typeHtml = 1;
-    private final static int typeClass = 2;
-    private final static int typeGif = 3;
-    private final static int typeJpeg = 4;
-    private final static int typeText = 5;
-
-    /**
-     * If this field is not null, the class files taken from
-     * <code>ClassPool</code> are written out under the directory
-     * specified by this field.  The directory name must not end
-     * with a directory separator.
-     */
-    public String debugDir = null;
-
-    /**
-     * The top directory of html (and .gif, .class, ...) files.
-     * It must end with the directory separator such as "/".
-     * (For portability, "/" should be used as the directory separator.
-     * Javassist automatically translates "/" into a platform-dependent
-     * character.)
-     * If this field is null, the top directory is the current one where
-     * the JVM is running.
-     *
-     * <p>If the given URL indicates a class file and the class file
-     * is not found under the directory specified by this variable,
-     * then <code>Class.getResourceAsStream()</code> is called
-     * for searching the Java class paths.
-     */
-    public String htmlfileBase = null;
-
-    /**
-     * Starts a web server.
-     * The port number is specified by the first argument.
-     */
-    public static void main(String[] args) throws IOException {
-        if (args.length == 1) {
-            Webserver web = new Webserver(args[0]);
-            web.run();
-        }
-        else
-            System.err.println(
-                        "Usage: java javassist.web.Webserver <port number>");
-    }
-
-    /**
-     * Constructs a web server.
-     *
-     * @param port      port number
-     */
-    public Webserver(String port) throws IOException {
-        this(Integer.parseInt(port));
-    }
-
-    /**
-     * Constructs a web server.
-     *
-     * @param port      port number
-     */
-    public Webserver(int port) throws IOException {
-        socket = new ServerSocket(port);
-        classPool = null;
-        translator = null;
-    }
-
-    /**
-     * Requests the web server to use the specified
-     * <code>ClassPool</code> object for obtaining a class file.
-     */
-    public void setClassPool(ClassPool loader) {
-        classPool = loader;
-    }
-
-    /**
-     * Adds a translator, which is called whenever a client requests
-     * a class file.
-     *
-     * @param cp        the <code>ClassPool</code> object for obtaining
-     *                  a class file.
-     * @param t         a translator.
-     */
-    public void addTranslator(ClassPool cp, Translator t)
-        throws NotFoundException, CannotCompileException
-    {
-        classPool = cp;
-        translator = t;
-        t.start(classPool);
-    }
-
-    /**
-     * Closes the socket.
-     */
-    public void end() throws IOException {
-        socket.close();
-    }
-
-    /**
-     * Prints a log message.
-     */
-    public void logging(String msg) {
-        System.out.println(msg);
-    }
-
-    /**
-     * Prints a log message.
-     */
-    public void logging(String msg1, String msg2) {
-        System.out.print(msg1);
-        System.out.print(" ");
-        System.out.println(msg2);
-    }
-
-    /**
-     * Prints a log message.
-     */
-    public void logging(String msg1, String msg2, String msg3) {
-        System.out.print(msg1);
-        System.out.print(" ");
-        System.out.print(msg2);
-        System.out.print(" ");
-        System.out.println(msg3);
-    }
-
-    /**
-     * Prints a log message with indentation.
-     */
-    public void logging2(String msg) {
-        System.out.print("    ");
-        System.out.println(msg);
-    }
-
-    /**
-     * Begins the HTTP service.
-     */
-    public void run() {
-        System.err.println("ready to service...");
-        for (;;)
-            try {
-                ServiceThread th = new ServiceThread(this, socket.accept());
-                th.start();
-            }
-            catch (IOException e) {
-                logging(e.toString());
-            }
-    }
-
-    final void process(Socket clnt) throws IOException {
-        InputStream in = new BufferedInputStream(clnt.getInputStream());
-        String cmd = readLine(in);
-        logging(clnt.getInetAddress().getHostName(),
-                new Date().toString(), cmd);
-        while (skipLine(in) > 0){
-        }
-
-        OutputStream out = new BufferedOutputStream(clnt.getOutputStream());
-        try {
-            doReply(in, out, cmd);
-        }
-        catch (BadHttpRequest e) {
-            replyError(out, e);
-        }
-
-        out.flush();
-        in.close();
-        out.close();
-        clnt.close();
-    }
-
-    private String readLine(InputStream in) throws IOException {
-        StringBuffer buf = new StringBuffer();
-        int c;
-        while ((c = in.read()) >= 0 && c != 0x0d)
-            buf.append((char)c);
-
-        in.read();      /* skip 0x0a (LF) */
-        return buf.toString();
-    }
-
-    private int skipLine(InputStream in) throws IOException {
-        int c;
-        int len = 0;
-        while ((c = in.read()) >= 0 && c != 0x0d)
-            ++len;
-
-        in.read();      /* skip 0x0a (LF) */
-        return len;
-    }
-
-    /**
-     * Proceses a HTTP request from a client.
-     *
-     * @param out       the output stream to a client
-     * @param cmd       the command received from a client
-     */
-    public void doReply(InputStream in, OutputStream out, String cmd)
-        throws IOException, BadHttpRequest
-    {
-        int len;
-        int fileType;
-        String filename, urlName;
-
-        if (cmd.startsWith("GET /"))
-            filename = urlName = cmd.substring(5, cmd.indexOf(' ', 5));
-        else
-            throw new BadHttpRequest();
-
-        if (filename.endsWith(".class"))
-            fileType = typeClass;
-        else if (filename.endsWith(".html") || filename.endsWith(".htm"))
-            fileType = typeHtml;
-        else if (filename.endsWith(".gif"))
-            fileType = typeGif;
-        else if (filename.endsWith(".jpg"))
-            fileType = typeJpeg;
-        else
-            fileType = typeText;        // or textUnknown
-
-        len = filename.length();
-        if (fileType == typeClass
-            && letUsersSendClassfile(out, filename, len))
-            return;
-
-        checkFilename(filename, len);
-        if (htmlfileBase != null)
-            filename = htmlfileBase + filename;
-
-        if (File.separatorChar != '/')
-            filename = filename.replace('/', File.separatorChar);
-
-        File file = new File(filename);
-        if (file.canRead()) {
-            sendHeader(out, file.length(), fileType);
-            FileInputStream fin = new FileInputStream(file);
-            for (;;) {
-                len = fin.read(filebuffer);
-                if (len <= 0)
-                    break;
-                else
-                    out.write(filebuffer, 0, len);
-            }
-
-            fin.close();
-            return;
-        }
-
-        // If the file is not found under the html-file directory,
-        // then Class.getResourceAsStream() is tried.
-
-        if (fileType == typeClass) {
-            InputStream fin
-                = getClass().getResourceAsStream("/" + urlName);
-            if (fin != null) {
-                ByteArrayOutputStream barray = new ByteArrayOutputStream();
-                for (;;) {
-                    len = fin.read(filebuffer);
-                    if (len <= 0)
-                        break;
-                    else
-                        barray.write(filebuffer, 0, len);
-                }
-
-                byte[] classfile = barray.toByteArray();
-                sendHeader(out, classfile.length, typeClass);
-                out.write(classfile);
-                fin.close();
-                return;
-            }
-        }
-
-        throw new BadHttpRequest();
-    }
-
-    private void checkFilename(String filename, int len)
-        throws BadHttpRequest
-    {
-        for (int i = 0; i < len; ++i) {
-            char c = filename.charAt(i);
-            if (!Character.isJavaIdentifierPart(c) && c != '.' && c != '/')
-                throw new BadHttpRequest();
-        }
-
-        if (filename.indexOf("..") >= 0)
-            throw new BadHttpRequest();
-    }
-
-    private boolean letUsersSendClassfile(OutputStream out,
-                                          String filename, int length)
-        throws IOException, BadHttpRequest
-    {
-        if (classPool == null)
-            return false;
-
-        byte[] classfile;
-        String classname
-            = filename.substring(0, length - 6).replace('/', '.');
-        try {
-            if (translator != null)
-                translator.onLoad(classPool, classname);
-
-            CtClass c = classPool.get(classname);
-            classfile = c.toBytecode();
-            if (debugDir != null)
-                c.writeFile(debugDir);
-        }
-        catch (Exception e) {
-            throw new BadHttpRequest(e);
-        }
-
-        sendHeader(out, classfile.length, typeClass);
-        out.write(classfile);
-        return true;
-    }
-
-    private void sendHeader(OutputStream out, long dataLength, int filetype)
-        throws IOException
-    {
-        out.write("HTTP/1.0 200 OK".getBytes());
-        out.write(endofline);
-        out.write("Content-Length: ".getBytes());
-        out.write(Long.toString(dataLength).getBytes());
-        out.write(endofline);
-        if (filetype == typeClass)
-            out.write("Content-Type: application/octet-stream".getBytes());
-        else if (filetype == typeHtml)
-            out.write("Content-Type: text/html".getBytes());
-        else if (filetype == typeGif)
-            out.write("Content-Type: image/gif".getBytes());
-        else if (filetype == typeJpeg)
-            out.write("Content-Type: image/jpg".getBytes());
-        else if (filetype == typeText)
-            out.write("Content-Type: text/plain".getBytes());
-
-        out.write(endofline);
-        out.write(endofline);
-    }
-
-    private void replyError(OutputStream out, BadHttpRequest e)
-        throws IOException
-    {
-        logging2("bad request: " + e.toString());
-        out.write("HTTP/1.0 400 Bad Request".getBytes());
-        out.write(endofline);
-        out.write(endofline);
-        out.write("<H1>Bad Request</H1>".getBytes());
-    }
-}
-
-class ServiceThread extends Thread {
-    Webserver web;
-    Socket sock;
-
-    public ServiceThread(Webserver w, Socket s) {
-        web = w;
-        sock = s;
-    }
-
-    public void run() {
-        try {
-            web.process(sock);
-        }
-        catch (IOException e) {
-        }
-    }
-}
diff --git a/src/main/javassist/web/package.html b/src/main/javassist/web/package.html
deleted file mode 100644 (file)
index 0c7fb45..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<html>
-<body>
-Simple web server for running sample code.
-
-<p>This package provides a simple web server for sample packages.
-</body>
-</html>