package org.jboss.proxy.compiler;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.rmi.RemoteException;
import org.jboss.iiop.rmi.AttributeAnalysis;
import org.jboss.iiop.rmi.ExceptionAnalysis;
import org.jboss.iiop.rmi.InterfaceAnalysis;
import org.jboss.iiop.rmi.OperationAnalysis;
import org.jboss.iiop.rmi.RMIIIOPViolationException;
import org.jboss.iiop.rmi.marshal.CDRStream;
import org.jboss.iiop.rmi.marshal.strategy.StubStrategy;
import org.jboss.proxy.ejb.DynamicIIOPStub;
public class IIOPStubCompiler
{
private static final Class[] stubStrategyParams = {
String[].class, String[].class, String[].class, String.class,
ClassLoader.class
};
private static final Class[] invokeParams = {
String.class, StubStrategy.class, Object[].class
};
private static final Class[] corbaObjectParam = {
org.omg.CORBA.Object.class
};
private static final Class[] stringParam = {
String.class
};
private static final Class[] noParams = { };
private static String strategy(int methodIndex) {
return "$s" + methodIndex;
}
private static String init(int methodIndex) {
return "$i" + methodIndex;
}
private static void generateMethodCode(ProxyAssembler asm,
Class superclass,
Method m,
String idlName,
String strategyField,
String initMethod)
{
String methodName = m.getName();
Class returnType = m.getReturnType();
Class[] paramTypes = m.getParameterTypes();
Class[] exceptions = m.getExceptionTypes();
asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
StubStrategy.class, null, strategyField);
asm.addMember(Modifier.PUBLIC + Modifier.FINAL,
returnType, methodName, paramTypes, exceptions);
{
asm.pushLocal(0); asm.pushConstant(idlName);
asm.pushField(asm, strategyField);
if (paramTypes.length == 0) {
asm.pushField(Util.class, "NOARGS");
} else {
asm.pushConstant(paramTypes.length);
asm.pushNewArray(Object.class);
for (int j = 0; j < paramTypes.length; j++) {
Class t = paramTypes[j];
asm.dup();
asm.pushConstant(j);
asm.pushLocal(1 + j);
if (t.isPrimitive()) {
asm.invoke(Util.class, "wrap", new Class[]{ t });
}
asm.setElement(Object.class);
}
}
String invoke = "invoke";
if (returnType.isPrimitive() && returnType != Void.TYPE) {
String typeName = returnType.getName();
invoke += (Character.toUpperCase(typeName.charAt(0))
+ typeName.substring(1));
}
asm.invoke(superclass, invoke, invokeParams);
if (!returnType.isPrimitive() && returnType != Object.class) {
asm.checkCast(returnType);
}
asm.ret();
}
asm.addMember(Modifier.PRIVATE + Modifier.STATIC,
Void.TYPE, initMethod, noParams, null);
{
int i;
int len;
len = paramTypes.length;
asm.pushConstant(len);
asm.pushNewArray(String.class);
for (i = 0; i < len; i++) {
asm.dup();
asm.pushConstant(i);
asm.pushConstant(CDRStream.abbrevFor(paramTypes[i]));
asm.setElement(String.class);
}
len = exceptions.length;
int n = 0;
for (i = 0; i < len; i++) {
if (!RemoteException.class.isAssignableFrom(exceptions[i])) {
n++;
}
}
asm.pushConstant(n);
asm.pushNewArray(String.class);
try {
int j = 0;
for (i = 0; i < len; i++) {
if (!RemoteException.class.isAssignableFrom(exceptions[i])) {
asm.dup();
asm.pushConstant(j);
asm.pushConstant(
ExceptionAnalysis.getExceptionAnalysis(exceptions[i])
.getExceptionRepositoryId());
asm.setElement(String.class);
j++;
}
}
}
catch (RMIIIOPViolationException e) {
throw new RuntimeException("Cannot obtain "
+ "exception repository id for "
+ exceptions[i].getName() + ":\n" + e);
}
asm.pushConstant(n);
asm.pushNewArray(String.class);
int j = 0;
for (i = 0; i < len; i++) {
if (!RemoteException.class.isAssignableFrom(exceptions[i])) {
asm.dup();
asm.pushConstant(j);
asm.pushConstant(exceptions[i].getName());
asm.setElement(String.class);
j++;
}
}
asm.pushConstant(CDRStream.abbrevFor(returnType));
asm.pushField(Util.class, "NULLCL");
asm.invoke(StubStrategy.class, "forMethod", stubStrategyParams);
asm.setField(asm, strategyField);
asm.ret();
}
}
private static byte[] generateCode(InterfaceAnalysis interfaceAnalysis,
Class superclass, String stubClassName)
{
ProxyAssembler asm =
new ProxyAssembler(stubClassName,
Modifier.PUBLIC | Modifier.FINAL,
superclass,
new Class[] { interfaceAnalysis.getCls() });
int methodIndex = 0;
AttributeAnalysis[] attrs = interfaceAnalysis.getAttributes();
for (int i = 0; i < attrs.length; i++) {
OperationAnalysis op = attrs[i].getAccessorAnalysis();
generateMethodCode(asm, superclass, op.getMethod(), op.getIDLName(),
strategy(methodIndex), init(methodIndex));
methodIndex++;
op = attrs[i].getMutatorAnalysis();
if (op != null) {
generateMethodCode(asm, superclass,
op.getMethod(), op.getIDLName(),
strategy(methodIndex), init(methodIndex));
methodIndex++;
}
}
OperationAnalysis[] ops = interfaceAnalysis.getOperations();
for (int i = 0; i < ops.length; i++) {
generateMethodCode(asm, superclass,
ops[i].getMethod(), ops[i].getIDLName(),
strategy(methodIndex), init(methodIndex));
methodIndex++;
}
asm.addMember(Modifier.PUBLIC, Void.TYPE, "<init>", noParams, null);
{
asm.pushLocal(0);
asm.invoke(superclass, "<init>", noParams);
asm.ret();
}
asm.addMember(Modifier.PUBLIC, String.class, "toString", noParams, null);
{
{
asm.pushConstant("JBossDynStub["
+ interfaceAnalysis.getCls().getName() + ", ");
{
{
asm.pushLocal(0);
asm.invoke(superclass, "_orb", noParams);
}
asm.pushLocal(0);
asm.invoke(org.omg.CORBA.ORB.class,
"object_to_string", corbaObjectParam);
}
asm.invoke(String.class, "concat", stringParam);
}
asm.pushConstant("]");
asm.invoke(String.class, "concat", stringParam);
asm.ret();
}
String[] ids = interfaceAnalysis.getAllTypeIds();
asm.addMember(Modifier.PRIVATE + Modifier.STATIC, String[].class,
null, "$ids");
asm.addMember(Modifier.PUBLIC + Modifier.FINAL,
String[].class, "_ids", noParams, null);
{
asm.pushField(asm, "$ids");
asm.ret();
}
asm.addMember(Modifier.STATIC, Void.TYPE, "<clinit>", noParams, null);
{
asm.pushConstant(ids.length);
asm.pushNewArray(String.class);
for (int i = 0; i < ids.length; i++) {
asm.dup();
asm.pushConstant(i);
asm.pushConstant(ids[i]);
asm.setElement(String.class);
}
asm.setField(asm, "$ids");
int n = methodIndex; for (methodIndex = 0; methodIndex < n; methodIndex++) {
asm.invoke(asm, init(methodIndex), noParams);
}
asm.ret();
}
return asm.getCode();
}
private static byte[] makeCode(InterfaceAnalysis interfaceAnalysis,
Class superclass, String stubClassName)
{
byte code[] = generateCode(interfaceAnalysis, superclass, stubClassName);
return code;
}
public static byte[] compile(Class intf, String stubClassName)
{
InterfaceAnalysis interfaceAnalysis = null;
try {
interfaceAnalysis = InterfaceAnalysis.getInterfaceAnalysis(intf);
}
catch (RMIIIOPViolationException e) {
throw new RuntimeException("RMI/IIOP Violation:\n" + e);
}
return makeCode(interfaceAnalysis, DynamicIIOPStub.class, stubClassName);
}
}