<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:
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,
<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
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>
<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" >
</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>
<!-- 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"/>
<!-- 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"/>
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
/*\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
% 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
package sample.evolve;\r
\r
-import javassist.web.*;\r
+import javassist.tools.web.*;\r
import java.io.*;\r
\r
/**\r
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
\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
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
import java.io.*;
-import javassist.tools.HotSwapper;
+import javassist.util.HotSwapper;
public class Test {
public static void main(String[] args) throws Exception {
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
\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
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
\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
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
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
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
\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
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
<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
}\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
<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
*
* @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)
*
* @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
* 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) {
/**
* Returns the first character of the current element.
- * @return
*/
public char currentChar() { return desc.charAt(curPos); }
<html>
<body>
-Annotations API.
+Bytecode-level Annotations API.
<p>This package provides low-level API for editing annotations attributes.
* 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
*/
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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");
- }
-}
+++ /dev/null
-/*
- * 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>])+");
- }
-}
+++ /dev/null
-/*
- * 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);
- }
-}
+++ /dev/null
-/*
- * 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);
-}
+++ /dev/null
-/*
- * 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);
- }
- }
-}
+++ /dev/null
-/*
- * 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);
- }
- }
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-<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>
+++ /dev/null
-/*
- * 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;
-}
+++ /dev/null
-/*
- * 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]);
- }
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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();
-}
+++ /dev/null
-/*
- * 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());
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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.");
- }
-}
+++ /dev/null
-/*
- * 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));
- }
- }
-}
+++ /dev/null
-<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>
+++ /dev/null
-/*
- * 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;
- }
-}
<html>
<body>
-Utility classes.
+Covenient tools.
</body>
</html>
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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");
+ }
+}
--- /dev/null
+/*
+ * 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>])+");
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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;
+}
--- /dev/null
+/*
+ * 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]);
+ }
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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();
+}
--- /dev/null
+/*
+ * 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());
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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.");
+ }
+}
--- /dev/null
+/*
+ * 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));
+ }
+ }
+}
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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();
+ }
+}
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+/*
+ * 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) {
+ }
+ }
+}
--- /dev/null
+<html>
+<body>
+Simple web server for running sample code.
+
+<p>This package provides a simple web server for sample packages.
+</body>
+</html>
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+<html>
+<body>
+Utility classes.
+</body>
+</html>
--- /dev/null
+/*
+ * 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();
+ }
+ }
+}
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*\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
--- /dev/null
+<html>
+<body>
+Dynamic proxy (similar to <code>Enhancer</code> of <a href="http://cglib.sourceforge.net/">cglib</a>).
+</body>
+</html>
+++ /dev/null
-/*
- * 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();
- }
-}
+++ /dev/null
-/*
- * 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;
- }
-}
+++ /dev/null
-/*
- * 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) {
- }
- }
-}
+++ /dev/null
-<html>
-<body>
-Simple web server for running sample code.
-
-<p>This package provides a simple web server for sample packages.
-</body>
-</html>