Author: aadamchik
Date: Mon Oct  9 20:59:01 2006
New Revision: 454601

URL: http://svn.apache.org/viewvc?view=rev&rev=454601
Log:
working simple properties interceptor

Added:
    
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassVisitorHelper.java
      - copied, changed from r454593, 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
Removed:
    
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
Modified:
    
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
    
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentGetterVisitor.java
    
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentSetterVisitor.java
    
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/CayenneEnhancerTest.java
    
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/EnhancingClassLoader.java
    
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
    
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockObjectContext.java

Copied: 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassVisitorHelper.java
 (from r454593, 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java)
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassVisitorHelper.java?view=diff&rev=454601&p1=incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java&r1=454593&p2=incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassVisitorHelper.java&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassBuilder.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/ClassVisitorHelper.java
 Mon Oct  9 20:59:01 2006
@@ -26,20 +26,29 @@
 import org.objectweb.asm.Type;
 
 /**
- * A builder that encapsulates common class enhancement operations.
+ * A helper for the ASM ClassVisitor that encapsulates common class enhancement
+ * operations.
  * 
  * @author Andrus Adamchik
  */
-class ClassBuilder {
+class ClassVisitorHelper {
 
     private String fieldPrefix = "$cay_";
     private ClassVisitor classVisitor;
     private Type currentClass;
 
-    ClassBuilder(ClassVisitor classVisitor) {
+    ClassVisitorHelper(ClassVisitor classVisitor) {
         this.classVisitor = classVisitor;
     }
 
+    Type getCurrentClass() {
+        return currentClass;
+    }
+
+    String getPropertyField(String propertyName) {
+        return fieldPrefix + propertyName;
+    }
+
     void reset(String className) {
         // assuming no primitives or arrays
         this.currentClass = Type.getType("L" + className + ";");
@@ -93,7 +102,7 @@
         mv.visitLabel(l0);
         mv.visitVarInsn(Opcodes.ALOAD, 0);
 
-        // TODO: other opcodes
+        // TODO: andrus, 10/9/2006 other opcodes
         if ("I".equals(asmType.getDescriptor())) {
             mv.visitVarInsn(Opcodes.ILOAD, 1);
         }
@@ -101,8 +110,11 @@
             mv.visitVarInsn(Opcodes.ALOAD, 1);
         }
 
-        mv.visitFieldInsn(Opcodes.PUTFIELD, currentClass.getInternalName(), 
fieldPrefix
-                + propertyName, asmType.getDescriptor());
+        mv.visitFieldInsn(
+                Opcodes.PUTFIELD,
+                currentClass.getInternalName(),
+                getPropertyField(propertyName),
+                asmType.getDescriptor());
         mv.visitInsn(Opcodes.RETURN);
         Label l1 = new Label();
         mv.visitLabel(l1);
@@ -126,10 +138,13 @@
         Label l0 = new Label();
         mv.visitLabel(l0);
         mv.visitVarInsn(Opcodes.ALOAD, 0);
-        mv.visitFieldInsn(Opcodes.GETFIELD, currentClass.getInternalName(), 
fieldPrefix
-                + propertyName, asmType.getDescriptor());
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                currentClass.getInternalName(),
+                getPropertyField(propertyName),
+                asmType.getDescriptor());
 
-        // TODO: other return opcodes
+        // TODO: andrus, 10/9/2006 other return opcodes
         if ("I".equals(asmType.getDescriptor())) {
             mv.visitInsn(Opcodes.IRETURN);
         }
@@ -147,7 +162,7 @@
     private void createField(String propertyName, Type asmType, int access) {
         FieldVisitor fv = classVisitor.visitField(
                 access,
-                fieldPrefix + propertyName,
+                getPropertyField(propertyName),
                 asmType.getDescriptor(),
                 null,
                 null);

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentClassVisitor.java
 Mon Oct  9 20:59:01 2006
@@ -35,12 +35,12 @@
 class PersistentClassVisitor extends ClassAdapter {
 
     private Collection<String> enhancedProperties;
-    private ClassBuilder builder;
+    private ClassVisitorHelper helper;
 
     PersistentClassVisitor(ClassVisitor visitor, Collection<String> 
enhancedProperties) {
         super(visitor);
         this.enhancedProperties = enhancedProperties;
-        this.builder = new ClassBuilder(this);
+        this.helper = new ClassVisitorHelper(this);
     }
 
     /**
@@ -55,14 +55,14 @@
             String superName,
             String[] interfaces) {
 
-        builder.reset(name);
-        interfaces = builder.addInterface(interfaces, Persistent.class);
-        
+        helper.reset(name);
+        interfaces = helper.addInterface(interfaces, Persistent.class);
+
         super.visit(version, access, name, signature, superName, interfaces);
 
-        builder.createProperty(ObjectId.class, "objectId");
-        builder.createProperty(ObjectContext.class, "objectContext", true);
-        builder.createProperty(Integer.TYPE, "persistenceState");
+        helper.createProperty(ObjectId.class, "objectId");
+        helper.createProperty(ObjectContext.class, "objectContext", true);
+        helper.createProperty(Integer.TYPE, "persistenceState");
     }
 
     /**
@@ -81,15 +81,15 @@
         // TODO: andrus, 10/8/2006 - check method sig for real... just checking
         // the name is not enough
 
-        // String getProperty = EnhancerUtil.propertyNameForGetter(name);
-        // if (getProperty != null && 
enhancedProperties.contains(getProperty)) {
-        // return new PersistentGetterVisitor(mv, className, getProperty);
-        // }
-        //
-        // String setProperty = EnhancerUtil.propertyNameForSetter(name);
-        // if (setProperty != null && 
enhancedProperties.contains(setProperty)) {
-        // return new PersistentSetterVisitor(mv, className, setProperty);
-        // }
+        String getProperty = EnhancerUtil.propertyNameForGetter(name);
+        if (getProperty != null && enhancedProperties.contains(getProperty)) {
+            return new PersistentGetterVisitor(mv, helper, getProperty);
+        }
+
+        String setProperty = EnhancerUtil.propertyNameForSetter(name);
+        if (setProperty != null && enhancedProperties.contains(setProperty)) {
+            return new PersistentSetterVisitor(mv, helper, setProperty);
+        }
 
         return mv;
     }

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentGetterVisitor.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentGetterVisitor.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentGetterVisitor.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentGetterVisitor.java
 Mon Oct  9 20:59:01 2006
@@ -18,17 +18,22 @@
  ****************************************************************/
 package org.apache.cayenne.enhancer;
 
+import org.apache.cayenne.ObjectContext;
+import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodAdapter;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
 
 class PersistentGetterVisitor extends MethodAdapter {
 
-    private String className;
+    private ClassVisitorHelper helper;
     private String propertyName;
 
-    PersistentGetterVisitor(MethodVisitor mv, String className, String 
propertyName) {
+    PersistentGetterVisitor(MethodVisitor mv, ClassVisitorHelper helper,
+            String propertyName) {
         super(mv);
-        this.className = className;
+        this.helper = helper;
         this.propertyName = propertyName;
     }
 
@@ -36,20 +41,33 @@
     public void visitCode() {
         super.visitCode();
 
-        // mv.visitVarInsn(Opcodes.ALOAD, 0);
-        // mv.visitFieldInsn(Opcodes.GETFIELD, className,
-        // "$cayenne_persistenceDelegate",
-        // "Lorg/apache/cayenne/jpa/enhancer/PersistenceDelegate;");
-        // Label l1 = new Label();
-        // mv.visitJumpInsn(Opcodes.IFNULL, l1);
-        // mv.visitVarInsn(Opcodes.ALOAD, 0);
-        // mv.visitFieldInsn(Opcodes.GETFIELD, className,
-        // PojoAdapterFactory.PERSISTENCE_DELEGATE_FIELD,
-        // "Lorg/apache/cayenne/jpa/enhancer/PersistenceDelegate;");
-        // mv.visitLdcInsn(propertyName);
-        // mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
-        // "org/apache/cayenne/jpa/enhancer/PersistenceDelegate",
-        // "prepareForAccess", "(Ljava/lang/String;)V");
-        // mv.visitLabel(l1);
+        String field = helper.getPropertyField("objectContext");
+        Type objectContextType = Type.getType(ObjectContext.class);
+
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                helper.getCurrentClass().getInternalName(),
+                field,
+                objectContextType.getDescriptor());
+        Label l1 = new Label();
+        mv.visitJumpInsn(Opcodes.IFNULL, l1);
+        Label l2 = new Label();
+        mv.visitLabel(l2);
+        mv.visitLineNumber(42, l2);
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                helper.getCurrentClass().getInternalName(),
+                field,
+                objectContextType.getDescriptor());
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitLdcInsn(propertyName);
+        mv.visitMethodInsn(
+                Opcodes.INVOKEINTERFACE,
+                objectContextType.getInternalName(),
+                "prepareForAccess",
+                "(Lorg/apache/cayenne/Persistent;Ljava/lang/String;)V");
+        mv.visitLabel(l1);
     }
 }

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentSetterVisitor.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentSetterVisitor.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentSetterVisitor.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/main/java/org/apache/cayenne/enhancer/PersistentSetterVisitor.java
 Mon Oct  9 20:59:01 2006
@@ -18,17 +18,22 @@
  ****************************************************************/
 package org.apache.cayenne.enhancer;
 
+import org.apache.cayenne.ObjectContext;
+import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodAdapter;
 import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
 
 class PersistentSetterVisitor extends MethodAdapter {
 
-    private String className;
+    private ClassVisitorHelper helper;
     private String propertyName;
 
-    PersistentSetterVisitor(MethodVisitor mv, String className, String 
propertyName) {
+    PersistentSetterVisitor(MethodVisitor mv, ClassVisitorHelper helper,
+            String propertyName) {
         super(mv);
-        this.className = className;
+        this.helper = helper;
         this.propertyName = propertyName;
     }
 
@@ -36,20 +41,39 @@
     public void visitCode() {
         super.visitCode();
 
-        // mv.visitVarInsn(Opcodes.ALOAD, 0);
-        // mv.visitFieldInsn(Opcodes.GETFIELD, className,
-        // PojoAdapterFactory.PERSISTENCE_DELEGATE_FIELD,
-        // "Lorg/apache/cayenne/jpa/enhancer/PersistenceDelegate;");
-        // Label l1 = new Label();
-        // mv.visitJumpInsn(Opcodes.IFNULL, l1);
-        // mv.visitVarInsn(Opcodes.ALOAD, 0);
-        // mv.visitFieldInsn(Opcodes.GETFIELD, className,
-        // PojoAdapterFactory.PERSISTENCE_DELEGATE_FIELD,
-        // "Lorg/apache/cayenne/jpa/enhancer/PersistenceDelegate;");
-        // mv.visitLdcInsn(propertyName);
-        // mv.visitMethodInsn(Opcodes.INVOKEINTERFACE,
-        // "org/apache/cayenne/jpa/enhancer/PersistenceDelegate",
-        // "prepareForUpdate", "(Ljava/lang/String;)V");
-        // mv.visitLabel(l1);
+        String field = helper.getPropertyField("objectContext");
+        Type objectContextType = Type.getType(ObjectContext.class);
+
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                helper.getCurrentClass().getInternalName(),
+                field,
+                objectContextType.getDescriptor());
+        Label l1 = new Label();
+        mv.visitJumpInsn(Opcodes.IFNULL, l1);
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                helper.getCurrentClass().getInternalName(),
+                field,
+                objectContextType.getDescriptor());
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitLdcInsn("attribute1");
+        mv.visitVarInsn(Opcodes.ALOAD, 0);
+        mv.visitFieldInsn(
+                Opcodes.GETFIELD,
+                helper.getCurrentClass().getInternalName(),
+                propertyName,
+                "Ljava/lang/String;");
+        mv.visitVarInsn(Opcodes.ALOAD, 1);
+        mv
+                .visitMethodInsn(
+                        Opcodes.INVOKEINTERFACE,
+                        objectContextType.getInternalName(),
+                        "propertyChanged",
+                        
"(Lorg/apache/cayenne/Persistent;Ljava/lang/String;Ljava/lang/Object;Ljava/lang/Object;)V");
+        mv.visitLabel(l1);
+
     }
 }

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/CayenneEnhancerTest.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/CayenneEnhancerTest.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/CayenneEnhancerTest.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/CayenneEnhancerTest.java
 Mon Oct  9 20:59:01 2006
@@ -117,4 +117,100 @@
         Object state = getPersistenceState.invoke(o, (Object[]) null);
         assertEquals(PersistenceState.DELETED, state);
     }
+
+    public void testGetterIntercepted() throws Exception {
+
+        Class e1Class = Class.forName(C1, true, loader);
+        assertNotNull(e1Class);
+        assertEquals(C1, e1Class.getName());
+
+        Object o = e1Class.newInstance();
+
+        // attempt calling on detached object - must not fail
+        Method getAttribute1 = e1Class.getDeclaredMethod("getAttribute1", 
(Class[]) null);
+        assertEquals(null, getAttribute1.invoke(o, (Object[]) null));
+
+        // now call on attached object
+
+        final Object[] prepared = new Object[2];
+        ObjectContext context = new MockObjectContext() {
+
+            @Override
+            public void prepareForAccess(Persistent object, String property) {
+                prepared[0] = object;
+                prepared[1] = property;
+            }
+        };
+
+        Method setObjectContext = e1Class.getDeclaredMethod(
+                "setObjectContext",
+                new Class[] {
+                    ObjectContext.class
+                });
+
+        setObjectContext.invoke(o, new Object[] {
+            context
+        });
+
+        assertEquals(null, getAttribute1.invoke(o, (Object[]) null));
+        assertSame(o, prepared[0]);
+        assertEquals("attribute1", prepared[1]);
+    }
+
+    public void testSetterIntercepted() throws Exception {
+
+        Class e1Class = Class.forName(C1, true, loader);
+        assertNotNull(e1Class);
+        assertEquals(C1, e1Class.getName());
+
+        Object o = e1Class.newInstance();
+
+        // attempt calling on detached object - must not fail
+        Method getAttribute1 = e1Class.getDeclaredMethod("getAttribute1", 
(Class[]) null);
+        Method setAttribute1 = e1Class.getDeclaredMethod("setAttribute1", new 
Class[] {
+            String.class
+        });
+
+        assertEquals(null, getAttribute1.invoke(o, (Object[]) null));
+        setAttribute1.invoke(o, new Object[] {
+            "x"
+        });
+        assertEquals("x", getAttribute1.invoke(o, (Object[]) null));
+
+        // now call on attached object
+        final Object[] change = new Object[4];
+        ObjectContext context = new MockObjectContext() {
+
+            @Override
+            public void propertyChanged(
+                    Persistent object,
+                    String property,
+                    Object oldValue,
+                    Object newValue) {
+                change[0] = object;
+                change[1] = property;
+                change[2] = oldValue;
+                change[3] = newValue;
+            }
+        };
+
+        Method setObjectContext = e1Class.getDeclaredMethod(
+                "setObjectContext",
+                new Class[] {
+                    ObjectContext.class
+                });
+
+        setObjectContext.invoke(o, new Object[] {
+            context
+        });
+
+        setAttribute1.invoke(o, new Object[] {
+                "y"
+            });
+        assertEquals("y", getAttribute1.invoke(o, (Object[]) null));
+        assertSame(o, change[0]);
+        assertEquals("attribute1", change[1]);
+        assertEquals("x", change[2]);
+        assertEquals("y", change[3]);
+    }
 }

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/EnhancingClassLoader.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/EnhancingClassLoader.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/EnhancingClassLoader.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/EnhancingClassLoader.java
 Mon Oct  9 20:59:01 2006
@@ -26,107 +26,111 @@
 import java.lang.instrument.IllegalClassFormatException;
 import java.security.SecureClassLoader;
 
-public class EnhancingClassLoader extends SecureClassLoader {
+class EnhancingClassLoader extends SecureClassLoader {
 
-       protected ClassFileTransformer transformer;
+    protected ClassFileTransformer transformer;
 
-       public EnhancingClassLoader(ClassFileTransformer transformer) {
-               super(Thread.currentThread().getContextClassLoader());
-               this.transformer = transformer;
-       }
-
-       /**
-        * Returns true if the class does not need to be enhanced.
-        */
-       protected boolean skipClassEnhancement(String className) {
-               return transformer == null;
-       }
-
-       @Override
-       protected synchronized Class<?> loadClass(String name, boolean resolve)
-                       throws ClassNotFoundException {
-
-               if (skipClassEnhancement(name)) {
-                       return super.loadClass(name, resolve);
-               }
-
-               Class c = findLoadedClass(name);
-
-               if (c == null) {
-                       c = findClass(name);
-               }
-
-               if (resolve) {
-                       resolveClass(c);
-               }
-
-               return c;
-       }
-
-       /**
-        * If a class name is one of the managed classes, loads it
-        */
-       @Override
-       protected Class<?> findClass(String name) throws ClassNotFoundException 
{
-               if (skipClassEnhancement(name)) {
-                       return Class.forName(name, true, getParent());
-               } else {
-                       return findEnhancedClass(name);
-               }
-       }
-
-       /**
-        * Loads class bytes, and passes them through the registered
-        * ClassTransformers.
-        */
-       protected Class<?> findEnhancedClass(String name)
-                       throws ClassNotFoundException {
-               String path = name.replace('.', '/') + ".class";
-
-               InputStream in = getResourceAsStream(path);
-               if (in == null) {
-                       return Class.forName(name, true, getParent());
-               }
-
-               try {
-
-                       ByteArrayOutputStream out = new 
ByteArrayOutputStream(1024);
-                       byte[] buffer = new byte[1024];
-                       int read;
-
-                       while ((read = in.read(buffer, 0, 1024)) > 0) {
-                               out.write(buffer, 0, read);
-                       }
-
-                       out.close();
-                       byte[] classBytes = out.toByteArray();
-
-                       byte[] bytes;
-                       try {
-                               bytes = transformer.transform(getParent(), 
name, null, null,
-                                               classBytes);
-                       } catch (IllegalClassFormatException e) {
-                               throw new ClassNotFoundException("Could not 
transform class '"
-                                               + name + "' due to invalid 
format", e);
-                       }
-
-                       if (bytes != null) {
-                               classBytes = bytes;
-                       } else {
-                               // if transformer didn't transform ... this is 
suboptimal as
-                               // we've already read the bytes from 
classfile...
-                               return Class.forName(name, true, getParent());
-                       }
-
-                       return defineClass(name, classBytes, 0, 
classBytes.length);
-               } catch (IOException e) {
-                       throw new ClassNotFoundException(name, e);
-               } finally {
-                       try {
-                               in.close();
-                       } catch (IOException e) {
-                               // ignore close exceptions...
-                       }
-               }
-       }
+    public EnhancingClassLoader(ClassFileTransformer transformer) {
+        super(Thread.currentThread().getContextClassLoader());
+        this.transformer = transformer;
+    }
+
+    /**
+     * Returns true if the class does not need to be enhanced.
+     */
+    protected boolean skipClassEnhancement(String className) {
+        return transformer == null;
+    }
+
+    @Override
+    protected synchronized Class<?> loadClass(String name, boolean resolve)
+            throws ClassNotFoundException {
+
+        if (skipClassEnhancement(name)) {
+            return super.loadClass(name, resolve);
+        }
+
+        Class c = findLoadedClass(name);
+
+        if (c == null) {
+            c = findClass(name);
+        }
+
+        if (resolve) {
+            resolveClass(c);
+        }
+
+        return c;
+    }
+
+    /**
+     * If a class name is one of the managed classes, loads it
+     */
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        if (skipClassEnhancement(name)) {
+            return Class.forName(name, true, getParent());
+        }
+        else {
+            return findEnhancedClass(name);
+        }
+    }
+
+    /**
+     * Loads class bytes, and passes them through the registered 
ClassTransformers.
+     */
+    protected Class<?> findEnhancedClass(String name) throws 
ClassNotFoundException {
+        String path = name.replace('.', '/') + ".class";
+
+        InputStream in = getResourceAsStream(path);
+        if (in == null) {
+            return Class.forName(name, true, getParent());
+        }
+
+        try {
+
+            ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+            byte[] buffer = new byte[1024];
+            int read;
+
+            while ((read = in.read(buffer, 0, 1024)) > 0) {
+                out.write(buffer, 0, read);
+            }
+
+            out.close();
+            byte[] classBytes = out.toByteArray();
+
+            byte[] bytes;
+            try {
+                bytes = transformer.transform(getParent(), name, null, null, 
classBytes);
+            }
+            catch (IllegalClassFormatException e) {
+                throw new ClassNotFoundException("Could not transform class '"
+                        + name
+                        + "' due to invalid format", e);
+            }
+
+            if (bytes != null) {
+                classBytes = bytes;
+            }
+            else {
+                // if transformer didn't transform ... this is suboptimal as
+                // we've already read the bytes from classfile...
+                return Class.forName(name, true, getParent());
+            }
+
+            return defineClass(name, classBytes, 0, classBytes.length);
+        }
+        catch (IOException e) {
+            throw new ClassNotFoundException(name, e);
+        }
+        finally {
+            try {
+                in.close();
+            }
+            catch (IOException e) {
+                // ignore close exceptions...
+            }
+        }
+    }
 }

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockEnhancedPojo.java
 Mon Oct  9 20:59:01 2006
@@ -25,7 +25,8 @@
 
 /**
  * This class in combination with the ASM Eclipse plugin is used as a 
reference for
- * building parts of the ASM enhancer.
+ * building parts of the ASM enhancer. It demonstrates how a pojo should look 
like after
+ * the enhancement.
  * 
  * @author Andrus Adamchik
  */

Modified: 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockObjectContext.java
URL: 
http://svn.apache.org/viewvc/incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockObjectContext.java?view=diff&rev=454601&r1=454600&r2=454601
==============================================================================
--- 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockObjectContext.java
 (original)
+++ 
incubator/cayenne/sandbox/asm-enhancer/src/test/java/org/apache/cayenne/enhancer/MockObjectContext.java
 Mon Oct  9 20:59:01 2006
@@ -32,8 +32,6 @@
 import org.apache.cayenne.query.Query;
 
 public class MockObjectContext implements ObjectContext {
-    
-    protected boolean preparedForAccess;
 
     public void prepareForAccess(Persistent object, String property) {
     }


Reply via email to