/* * Javassist, a Java-bytecode translator toolkit. * Copyright (C) 1999- 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, * or the Apache License Version 2.0. * * 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.lang.reflect.Method; import java.util.Hashtable; import java.util.Map; import javassist.CannotCompileException; import javassist.ClassPool; import javassist.CtClass; import javassist.CtConstructor; import javassist.CtField; import javassist.CtMethod; import javassist.CtMethod.ConstParameter; import javassist.CtNewConstructor; import javassist.CtNewMethod; import javassist.Modifier; import javassist.NotFoundException; import javassist.Translator; /** * A stub-code generator. It is used for producing a proxy class. * *
The proxy class for class A is as follows: * *
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 ... * }* *
Instances of the proxy class is created by an
* ObjectImporter
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 Maptrue
if the specified class is a proxy class
* recorded by makeProxyClass()
.
*
* @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 false
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;
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 {
StringBuilder sbuf = new StringBuilder();
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));
}
}
}