package hep.io.root.core;
import hep.io.root.RootClass;
import hep.io.root.RootMember;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import org.apache.bcel.Constants;
import org.apache.bcel.Repository;
import org.apache.bcel.classfile.Constant;
import org.apache.bcel.classfile.Field;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.CPInstruction;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionHandle;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;
/**
*
* @author tonyj
* @version $Id: ProxyBuilder.java 13618 2009-04-10 00:02:54Z tonyj $
*/
class ProxyBuilder implements ClassBuilder, Constants
{
private static boolean debugRoot = System.getProperty("debugRoot") != null;
private static NameMangler nameMangler = NameMangler.instance();
private boolean hasHeader;
public ProxyBuilder()
{
this(true);
}
protected ProxyBuilder(boolean hasHeader)
{
this.hasHeader = hasHeader;
}
public String getStem()
{
return "hep.io.root.proxy";
}
public JavaClass build(GenericRootClass klass)
{
String className = nameMangler.mangleFullClassName(getStem(),klass.getClassName());
ClassGen cg = new ClassGen(className, "hep/io/root/core/AbstractRootObject", "<generated>", ACC_PUBLIC | ACC_SUPER, new String[]
{
nameMangler.mangleInterfaceName(klass.getClassName())
});
ConstantPoolGen cp = cg.getConstantPool();
InstructionList il = new InstructionList();
InstructionFactory factory = new InstructionFactory(cg);
cg.addEmptyConstructor(ACC_PUBLIC);
// Build the complete list of superclasses
List sup = new ArrayList();
RootClass[] superClasses = klass.getSuperClasses();
iterativelyAdd(sup, superClasses);
sup.add(klass);
// Look for any representations
for (ListIterator i = sup.listIterator(sup.size()); i.hasPrevious();)
{
BasicRootClass rc = (BasicRootClass) i.previous();
String repName = "hep.io.root.reps." + rc.getClassName() + "Rep";
try
{
Class repClass = Class.forName(repName);
JavaClass rep = Repository.lookupClass(repClass);
if (rep != null)
{
Field[] repFields = rep.getFields();
ConstantPoolGen oldCp = new ConstantPoolGen(rep.getConstantPool().copy());
for (int j = 0; j < repFields.length; j++)
{
if (repFields[j].isStatic())
continue;
else if (cg.containsField(repFields[j].getName()) == null)
cg.addField(new FieldGen(repFields[j], cp).getField());
}
Method[] repMethods = rep.getMethods();
for (int j = 0; j < repMethods.length; j++)
{
if (repMethods[j].isAbstract())
continue;
if (repMethods[j].getName().equals("<init>"))
continue;
if (cg.containsMethod(repMethods[j].getName(), repMethods[j].getSignature()) != null)
continue;
MethodGen mg = new MethodGen(repMethods[j], className, cp);
// We need to convert any constant pool references from the old CP to the new
CPFixup fixup = new CPFixup(oldCp, cp, repName, className);
for (Iterator it = mg.getInstructionList().iterator();
it.hasNext();)
((InstructionHandle) it.next()).accept(fixup);
cg.addMethod(mg.getMethod());
}
}
}
catch (ClassNotFoundException x)
{}
}
// Generate the fields
for (Iterator i = sup.iterator(); i.hasNext();)
generateFields((RootClass) i.next(), cp, cg);
Class implementedInterface = null;
try
{
implementedInterface = Class.forName(nameMangler.mangleInterfaceName(klass.getClassName()));
}
catch (ClassNotFoundException x)
{
//if (debugRoot) throw new RuntimeException("Unable to load interface "+klass.getClassName(),x);
if (debugRoot) System.out.println("Warning, could not load interface "+klass.getClassName());
}
// Generate the accessor methods
for (Iterator i = sup.iterator(); i.hasNext();)
generateMethods((RootClass) i.next(), cp, il, factory, cg, className,implementedInterface);
// Generate the streamer method
if (cg.containsMethod("readMembers", "(Lhep/io/root/core/RootInput;)V") == null)
{
MethodGen mg = new MethodGen(ACC_PUBLIC, Type.VOID, new Type[]
{
new ObjectType("hep/io/root/core/RootInput")
}, new String[] { "in" }, "readMembers", null, il, cp);
mg.addException("java/io/IOException");
klass.generateStreamer(cp, il, factory, className, hasHeader);
il.append(InstructionConstants.RETURN);
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
il.dispose();
}
return cg.getJavaClass();
}
private void generateFields(RootClass k, ConstantPoolGen cp, ClassGen cg)
{
RootMember[] members = k.getMembers();
for (int i = 0; i < members.length; i++)
{
if (cg.containsField(members[i].getName()) == null)
{
Type type = ((BasicMember) members[i]).getJavaType();
if (type != null)
{
FieldGen fg = new FieldGen(ACC_PRIVATE, type, members[i].getName(), cp);
cg.addField(fg.getField());
}
}
}
}
private static void generateMethods(RootClass k, ConstantPoolGen cp, InstructionList il, InstructionFactory factory, ClassGen cg, String className, Class implementedInterface)
{
RootMember[] members = k.getMembers();
for (int i = 0; i < members.length; i++)
{
Type type = ((BasicMember) members[i]).getJavaType();
Type returnType = type;
try
{
if (implementedInterface != null) returnType = Type.getType(implementedInterface.getMethod(nameMangler.mangleMember(members[i].getName()),(Class[]) null).getReturnType());
if (!returnType.equals(type) && debugRoot)
{
System.err.println("Warning: Interface type mismatch "+implementedInterface.getName()+"."+nameMangler.mangleMember(members[i].getName())+" "+returnType+" "+type);
}
}
catch (NoSuchMethodException x)
{
}
if (cg.containsMethod(nameMangler.mangleMember(members[i].getName()), "()" + returnType.getSignature()) == null)
{
MethodGen mg = new MethodGen(ACC_PUBLIC, returnType, null, null, nameMangler.mangleMember(members[i].getName()), null, il, cp);
if (members[i].getType() == null) // Dummy object
{
il.append(new PUSH(cp, "<<Unreadable>>"));
}
else
{
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField(className, members[i].getName(), type));
}
if (!returnType.equals(type)) il.append(factory.createCast(type,returnType));
il.append(InstructionFactory.createReturn(returnType));
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
il.dispose();
}
}
}
private void iterativelyAdd(List list, RootClass[] superClasses)
{
for (int i = 0; i < superClasses.length; i++)
{
RootClass[] supsup = superClasses[i].getSuperClasses();
iterativelyAdd(list, supsup);
list.add(superClasses[i]);
}
}
private static class CPFixup extends org.apache.bcel.generic.EmptyVisitor
{
private ConstantPoolGen newCP;
private ConstantPoolGen oldCP;
private String newClass;
private String oldClass;
CPFixup(ConstantPoolGen oldCP, ConstantPoolGen newCP, String oldClass, String newClass)
{
this.oldCP = oldCP;
this.newCP = newCP;
this.oldClass = oldClass;
this.newClass = newClass;
}
public void visitCPInstruction(CPInstruction cpi)
{
int index = cpi.getIndex();
Constant oldConstant = oldCP.getConstant(index);
if (oldConstant instanceof org.apache.bcel.classfile.ConstantCP)
{
org.apache.bcel.classfile.ConstantCP fr = (org.apache.bcel.classfile.ConstantCP) oldConstant;
if (fr.getClass(oldCP.getConstantPool()).equals(oldClass))
fr.setClassIndex(oldCP.addClass(newClass));
}
index = newCP.addConstant(oldConstant, oldCP);
cpi.setIndex(index);
}
}
}