package hep.io.root.core;
import hep.io.root.RootClass;
import hep.io.root.RootMember;
import hep.io.root.interfaces.TBranch;
import hep.io.root.interfaces.TLeaf;
import hep.io.root.interfaces.TObjArray;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ArrayType;
import org.apache.bcel.generic.BasicType;
import org.apache.bcel.generic.BranchHandle;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.FieldGen;
import org.apache.bcel.generic.IFNONNULL;
import org.apache.bcel.generic.Instruction;
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: HollowBuilder.java 13618 2009-04-10 00:02:54Z tonyj $
*/
public class HollowBuilder implements ClassBuilder, Constants
{
private static boolean debugRoot = System.getProperty("debugRoot") != null;
private static NameMangler nameMangler = NameMangler.instance();
private static final Object SUBOBJECT = new Object();
private Map lMap;
private String prefix;
private TBranch branch;
private boolean hasSubIndex = false;
public HollowBuilder(TBranch branch)
{
this.branch = branch;
}
public HollowBuilder(TBranch branch, boolean hasSubIndex)
{
this.branch = branch;
this.hasSubIndex = hasSubIndex;
}
public HollowBuilder(TBranch branch, String prefix)
{
this.branch = branch;
this.prefix = prefix;
}
public HollowBuilder(TBranch branch, String prefix, boolean hasSubIndex)
{
this.branch = branch;
this.prefix = prefix;
this.hasSubIndex = hasSubIndex;
}
public String getStem()
{
return "hep.io.root.hollow";
}
public JavaClass build(GenericRootClass klass)
{
String className =nameMangler.mangleFullClassName(getStem(),klass.getClassName());
ClassGen cg = new ClassGen(className, "hep/io/root/core/Hollow", "<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);
// Loop over all the leafs, and build a hashtable from name->leaf
Map nameMap = new HashMap();
TObjArray branches = branch.getBranches();
for (Iterator j = branches.iterator(); j.hasNext();)
{
TBranch br = (TBranch) j.next();
TObjArray leaves = br.getLeaves();
branch: for (Iterator i = leaves.iterator(); i.hasNext();)
{
Object leaf = i.next();
String name = ((TLeaf) leaf).getName();
int pos = name.indexOf('[');
if (pos > 0)
name = name.substring(0, pos);
if (name.endsWith("_"))
name = name.substring(0, name.length() - 1);
if (prefix != null)
{
if (!name.startsWith(prefix))
continue;
name = name.substring(prefix.length());
}
pos = name.indexOf('.');
if (pos > 0)
{
name = name.substring(0, pos);
leaf = SUBOBJECT;
}
nameMap.put(name, leaf);
}
}
lMap = new HashMap();
// Loop over the members and try to find the matching leaf
for (Iterator j = sup.iterator(); j.hasNext();)
{
RootClass k = (RootClass) j.next();
RootMember[] members = k.getMembers();
for (int i = 0; i < members.length; i++)
{
BasicMember member = (BasicMember) members[i];
String name = member.getName();
if (name.endsWith("_"))
name = name.substring(0, name.length() - 1);
Object leaf = nameMap.remove(name);
if (leaf == null)
{
if (debugRoot) System.err.println("Warning: no leaf for " + member.getName());
}
else
{
lMap.put(member, leaf);
}
}
}
// Check for any left over leafs
if (debugRoot)
{
for (Iterator i = nameMap.keySet().iterator(); i.hasNext();)
{
System.err.println("Warning: unused leaf " + i.next());
}
}
// Generate the fields
for (Iterator i = sup.iterator(); i.hasNext();)
generateFields((RootClass) i.next(), cp, cg);
// Generate the accessor methods
for (Iterator i = sup.iterator(); i.hasNext();)
generateMethods((RootClass) i.next(), cp, il, factory, cg, className);
return cg.getJavaClass();
}
public void populateStatics(Class hollowClass, RootClassFactory factory)
{
try
{
// Loop over the leaves
for (Iterator i = lMap.entrySet().iterator(); i.hasNext();)
{
Map.Entry entry = (Map.Entry) i.next();
BasicMember member = (BasicMember) entry.getKey();
Object l = entry.getValue();
if (l == SUBOBJECT)
{
HollowBuilder builder = new HollowBuilder(branch, member.getName() + ".");
String name = "hep.io.root.hollow." + member.getType().getClassName();
GenericRootClass gc = (GenericRootClass) factory.create(member.getType().getClassName());
Class subHollowClass = factory.getLoader().loadSpecial(builder, name, gc);
builder.populateStatics(subHollowClass, factory);
java.lang.reflect.Field field = hollowClass.getField(member.getName() + "Class");
field.set(null, subHollowClass);
}
else
{
java.lang.reflect.Field field = hollowClass.getField(member.getName());
field.set(null, l);
}
}
}
catch (Exception x)
{
throw new RuntimeException("Error while populating statics",x);
}
}
private void generateFields(RootClass k, ConstantPoolGen cp, ClassGen cg)
{
RootMember[] members = k.getMembers();
for (int i = 0; i < members.length; i++)
{
BasicMember member = (BasicMember) members[i];
Object l = lMap.get(member);
if (l == SUBOBJECT)
{
Type type = new ObjectType("java.lang.Class");
FieldGen fg = new FieldGen(ACC_PUBLIC | ACC_STATIC, type, member.getName() + "Class", cp);
cg.addField(fg.getField());
type = member.getJavaType();
fg = new FieldGen(ACC_PRIVATE, type, member.getName(), cp);
cg.addField(fg.getField());
}
else if (l != null)
{
TLeaf leaf = (TLeaf) l;
Type type = new ObjectType(leaf.getClass().getName());
FieldGen fg = new FieldGen(ACC_PUBLIC | ACC_STATIC, type, member.getName(), cp);
cg.addField(fg.getField());
}
}
}
private void generateMethods(RootClass k, ConstantPoolGen cp, InstructionList il, InstructionFactory factory, ClassGen cg, String className)
{
RootMember[] members = k.getMembers();
for (int i = 0; i < members.length; i++)
{
BasicMember member = (BasicMember) members[i];
Type type = member.getJavaType();
Object l = lMap.get(member);
if (l == SUBOBJECT)
{
MethodGen mg = new MethodGen(ACC_PUBLIC, type, null, null, nameMangler.mangleMember(member.getName()), className, il, cp);
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField(className, member.getName(), type));
il.append(InstructionConstants.DUP);
BranchHandle bh = il.append(new IFNONNULL(null));
il.append(InstructionConstants.POP);
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetStatic(className, member.getName() + "Class", new ObjectType("java.lang.Class")));
il.append(factory.createInvoke("java.lang.Class", "newInstance", new ObjectType("java.lang.Object"), Type.NO_ARGS, INVOKEVIRTUAL));
il.append(InstructionConstants.DUP);
il.append(factory.createCast(new ObjectType("java,lang.Object"), new ObjectType("hep.io.root.core.Hollow")));
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField("hep.io.root.core.Hollow", "index", Type.LONG));
il.append(factory.createInvoke("hep.io.root.core.Hollow", "setHollowIndex", Type.VOID, new Type[]
{
Type.LONG
}, INVOKEVIRTUAL));
il.append(factory.createCast(new ObjectType("java,lang.Object"), type));
il.append(InstructionConstants.DUP_X1);
il.append(factory.createPutField(className, member.getName(), type));
bh.setTarget(il.append(InstructionFactory.createReturn(type)));
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
il.dispose();
}
else if (l == null)
{
MethodGen mg = new MethodGen(ACC_PUBLIC, type, null, null, nameMangler.mangleMember(member.getName()), className, il, cp);
il.append(InstructionFactory.createNull(type));
il.append(InstructionFactory.createReturn(type));
mg.setMaxStack();
mg.setMaxLocals();
cg.addMethod(mg.getMethod());
il.dispose();
}
else
{
TLeaf leaf = (TLeaf) l;
String leafClassName = leaf.getClass().getName();
MethodGen mg = new MethodGen(ACC_PUBLIC, type, null, null, nameMangler.mangleMember(member.getName()), className, il, cp);
InstructionHandle try_start = il.append(factory.createGetStatic(className, member.getName(), new ObjectType(leafClassName)));
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField("hep.io.root.core.Hollow", "index", Type.LONG));
Type sType = hasSubIndex ? new ArrayType(type, (short) 1) : type;
Type rType = (sType instanceof BasicType) ? sType : Type.OBJECT;
leaf.generateReadCode(il, factory, cp, className);
if (rType != sType)
il.append(factory.createCast(rType, sType));
if (hasSubIndex)
{
il.append(InstructionConstants.ALOAD_0);
il.append(factory.createGetField("hep.io.root.core.Hollow", "subIndex", Type.INT));
il.append(InstructionFactory.createArrayLoad(type));
}
InstructionHandle try_end = il.append(InstructionFactory.createReturn(type));
InstructionHandle handler = il.append((Instruction) factory.createNew(new ObjectType("java.lang.RuntimeException")));
il.append(InstructionConstants.DUP);
il.append(new PUSH(cp, "IOError while accessing value"));
il.append(factory.createInvoke("java.lang.RuntimeException", "<init>", Type.VOID, new Type[]
{
Type.STRING
}, INVOKESPECIAL));
if (System.getProperty("java.version").compareTo("1.4") >= 0)
{
il.append(InstructionConstants.DUP_X1);
il.append(InstructionConstants.SWAP);
Type throwableType = new ObjectType("java.lang.Throwable");
il.append(factory.createInvoke("java.lang.Throwable", "initCause", throwableType, new Type[]
{
throwableType
}, INVOKEVIRTUAL));
}
il.append(InstructionConstants.ATHROW);
mg.addExceptionHandler(try_start, try_end, handler, new ObjectType("java.io.IOException"));
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]);
}
}
}