Hi,
 
Using Apache BCEL (Byte Code Engineering Library), I create a BeanFactory that 
wraps node with classes that can be evaluated using jxpath or EL. (I removed 
the DynClass dependency in favor of BCEL, because BCEL is more actively 
maintained and lots of project use and test it with the latest JDK features).
 
Below is the code of the BeanFactory class. Comments welcome.
 
------------------------------ Code below -------------------------------------
 
package org.mmbase.bridge.beans;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.apache.bcel.Constants;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.Type;
import org.mmbase.bridge.Field;
import org.mmbase.bridge.FieldList;
import org.mmbase.bridge.Node;
import org.mmbase.bridge.NodeManager;
/**
 * Usage: Object nodeBean = BeanFactory.createBean(n);
 * 
 * 
 * TODO: Use the right property type for the getter/setter methods, now string
 * Add methods for other part of the objectmodel, maybe even to retrieve the
 * node and nodeManager
 */
public class BeanFactory {
 private static class MMBeanClassLoader extends
   org.apache.bcel.util.ClassLoader implements Constants {
  public static final String SUFFIX = "$$BCEL$$";
  private NodeManager mgr;
  public MMBeanClassLoader(ClassLoader parent) {
   super(parent);
  }
  /** 
   * Method to inject the node manager into the classloader to construct the 
bean.
   * @param nodeMgr
   * @TODO Once related nodes are wrapped automatically, the classloader
   * should be able to retrieve the nodemanagers itself.
   */
  public void defineManager(NodeManager nodeMgr) {
   this.mgr = nodeMgr;
  }
  /**
   * Derive the java class from the node manager
   */
  protected JavaClass createClass(String className) {
   ClassGen cg = new ClassGen(className, "java.lang.Object", null,
     ACC_PUBLIC | ACC_INTERFACE | ACC_ABSTRACT, new String[] {});
   ConstantPoolGen cp = cg.getConstantPool();
   FieldList fl = mgr.getFields();
   for (int i = 0; i < fl.size(); i++) {
    Field f = fl.getField(i);
    String methodName = "get"
      + Character.toUpperCase(f.getName().charAt(0))
      + f.getName().substring(1);
    // TODO: get the appropriate property/field type
    String type = "Ljava/lang/String;";
    Type t = Type.STRING;
    InstructionList il = new InstructionList();
    MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT, t,
      Type.NO_ARGS, new String[] {}, methodName, className,
      il, cp);
    method.setMaxStack();
    method.setMaxLocals();
    cg.addMethod(method.getMethod());
    il.dispose();
   }
   for (int i = 0; i < fl.size(); i++) {
    Field f = fl.getField(i);
    String methodName = "set"
      + Character.toUpperCase(f.getName().charAt(0))
      + f.getName().substring(1);
    String type = "Ljava/lang/String;";
    Type t = Type.STRING;
    InstructionList il = new InstructionList();
    MethodGen method = new MethodGen(ACC_PUBLIC | ACC_ABSTRACT,
      Type.VOID, new Type[] { t }, new String[] { "arg" },
      methodName, className, il, cp);
    method.setMaxStack();
    method.setMaxLocals();
    System.out.println("Method : " + method.toString());
    cg.addMethod(method.getMethod());
    il.dispose();
   }
   return cg.getJavaClass();
  }
 }
 /**
  * The invocationhandler that handles the actual method
  * calls on the bean.
  */
 private static class MMBeanInvocationHandler implements InvocationHandler {
  private final Node adapter;
  public MMBeanInvocationHandler(Node adapter) {
   this.adapter = adapter;
  }
  public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
   String methodName = method.getName();
   if (methodName.startsWith("set")) {
    String propName = Character.toLowerCase(methodName.charAt(3))
      + methodName.substring(4);
    adapter.setObjectValue(propName, args[0]);
    return null;
   } else if (methodName.startsWith("get")) {
    String propName = Character.toLowerCase(methodName.charAt(3))
      + methodName.substring(4);
    return adapter.getObjectValue(propName);
   }
   throw new RuntimeException("No such method : " + method.toString());
  }
 }
 private static MMBeanClassLoader loader = new MMBeanClassLoader(
   BeanFactory.class.getClassLoader());
 public static Object createBean(Node node) {
  try {
   NodeManager mgr = node.getNodeManager();
   String className = mgr.getName() + MMBeanClassLoader.SUFFIX;
   // Inject the nodemanager before loading the class
   loader.defineManager(node.getNodeManager());
   Class ifcClass = loader.loadClass(className);
   
   // Implement proxy
   return Proxy.newProxyInstance(loader, new Class[] { ifcClass },
     new MMBeanInvocationHandler(node));
  } catch (ClassNotFoundException e) {
   throw new RuntimeException(e);
  }
 }
}
 

Disclaimer

Dit bericht met eventuele bijlagen is vertrouwelijk en uitsluitend bestemd voor 
de geadresseerde. Indien u niet de bedoelde ontvanger bent, wordt u verzocht de 
afzender te waarschuwen en dit bericht met eventuele bijlagen direct te 
verwijderen en/of te vernietigen. Het is niet toegestaan dit bericht en 
eventuele bijlagen te vermenigvuldigen, door te sturen, openbaar te maken, op 
te slaan of op andere wijze te gebruiken. Ordina N.V. en/of haar 
groepsmaatschappijen accepteren geen verantwoordelijkheid of aansprakelijkheid 
voor schade die voortvloeit uit (de inhoud van) de verzending van dit bericht.

This e-mail and any attachments are confidential and is solely intended for the 
addressee only. If you are not the intended recipient, please notify the sender 
and delete and/or destroy this message and any attachments immediately. It is 
prohibited to copy, to distribute, to disclose or to use this e-mail and any 
attachments in any other way. Ordina N.V. and/or its group companies do not 
accept any responsibility nor liability for any damage resulting from (the 
content of) the transmission of this message.

_______________________________________________
Developers mailing list
[email protected]
http://lists.mmbase.org/mailman/listinfo/developers

Reply via email to