[jboss-svn-commits] JBL Code SVN: r6714 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/base test/java/org/drools/base

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Oct 9 17:22:55 EDT 2006


Author: tirelli
Date: 2006-10-09 17:22:37 -0400 (Mon, 09 Oct 2006)
New Revision: 6714

Modified:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
Log:
Adding eager proxy creating support

Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java	2006-10-09 20:51:28 UTC (rev 6713)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java	2006-10-09 21:22:37 UTC (rev 6714)
@@ -34,6 +34,8 @@
  * A factory for ShadowProxy classes
  */
 public class ShadowProxyFactory {
+    private static final String UPDATE_PROXY = "updateProxy";
+
     private static final String BASE_INTERFACE      = Type.getInternalName( ShadowProxy.class );
 
     private static final String FIELD_NAME_PREFIX   = "__";
@@ -45,9 +47,8 @@
     public static Class getProxy(final Class clazz) {
         try {
             String className = null;
-            if( clazz.getPackage().getName().startsWith( "java." ) ||
-                clazz.getPackage().getName().startsWith( "javax." )) {
-                className = "org/drools/shadow/"+Type.getInternalName( clazz )+"ShadowProxy";
+            if ( clazz.getPackage().getName().startsWith( "java." ) || clazz.getPackage().getName().startsWith( "javax." ) ) {
+                className = "org/drools/shadow/" + Type.getInternalName( clazz ) + "ShadowProxy";
             } else {
                 className = Type.getInternalName( clazz ) + "ShadowProxy";
             }
@@ -65,6 +66,28 @@
         }
     }
 
+    public static Class getEagerProxy(final Class clazz) {
+        try {
+            String className = null;
+            if ( clazz.getPackage().getName().startsWith( "java." ) || clazz.getPackage().getName().startsWith( "javax." ) ) {
+                className = "org/drools/shadow/" + Type.getInternalName( clazz ) + "EagerShadowProxy";
+            } else {
+                className = Type.getInternalName( clazz ) + "EagerShadowProxy";
+            }
+            // generating byte array to create target class
+            final byte[] bytes = dumpEager( clazz,
+                                            className );
+            // use bytes to get a class 
+            final ByteArrayClassLoader classLoader = new ByteArrayClassLoader( Thread.currentThread().getContextClassLoader() );
+            final Class newClass = classLoader.defineClass( className.replace( '/',
+                                                                               '.' ),
+                                                            bytes );
+            return newClass;
+        } catch ( final Exception e ) {
+            throw new RuntimeDroolsException( e );
+        }
+    }
+
     protected static byte[] dump(final Class clazz,
                                  final String className) throws Exception {
 
@@ -79,11 +102,9 @@
                     cw );
 
         Map fieldTypes = new HashMap();
-
         Method[] methods = clazz.getMethods();
         for ( int i = 0; i < methods.length; i++ ) {
-            if ( (! Modifier.isFinal( methods[i].getModifiers() )) &&
-                 Modifier.isPublic( methods[i].getModifiers() )) {
+            if ( (!Modifier.isFinal( methods[i].getModifiers() )) && Modifier.isPublic( methods[i].getModifiers() ) ) {
                 if ( (!methods[i].getReturnType().equals( Void.TYPE )) && (methods[i].getParameterTypes().length == 0) ) {
                     String fieldName = methods[i].getName();
 
@@ -117,9 +138,69 @@
                           cw );
 
         buildUpdateProxyMethod( fieldTypes,
+                                className,
+                                cw );
+
+        return cw.toByteArray();
+    }
+
+    protected static byte[] dumpEager(final Class clazz,
+                                      final String className) throws Exception {
+
+        final ClassWriter cw = new ClassWriter( true );
+
+        buildClassHeader( clazz,
+                          className,
+                          cw );
+
+        buildField( DELEGATE_FIELD_NAME,
+                    Type.getDescriptor( clazz ),
+                    cw );
+
+        Map fieldTypes = new HashMap();
+        Map fieldMethods = new HashMap();
+
+        Method[] methods = clazz.getMethods();
+        for ( int i = 0; i < methods.length; i++ ) {
+            if ( (!Modifier.isFinal( methods[i].getModifiers() )) && Modifier.isPublic( methods[i].getModifiers() ) ) {
+                if ( (!methods[i].getReturnType().equals( Void.TYPE )) && (methods[i].getParameterTypes().length == 0) &&
+                        ((methods[i].getName().startsWith( "get" )) || (methods[i].getName().startsWith( "is" )))) {
+                    String fieldName = methods[i].getName();
+
+                    buildField( FIELD_NAME_PREFIX + fieldName,
+                                Type.getDescriptor( methods[i].getReturnType() ),
+                                cw );
+                    fieldMethods.put( FIELD_NAME_PREFIX + fieldName,
+                                      methods[i] );
+                    fieldTypes.put( FIELD_NAME_PREFIX + fieldName,
+                                    methods[i].getReturnType() );
+
+                    buildSimpleGetMethod( FIELD_NAME_PREFIX + fieldName,
+                                          methods[i].getReturnType(),
+                                          FIELD_NAME_PREFIX + fieldName + FIELD_SET_FLAG,
+                                          methods[i],
+                                          className,
+                                          clazz,
+                                          cw );
+                } else {
+                    buildDelegateMethod( methods[i],
+                                         clazz,
+                                         className,
+                                         cw );
+                }
+            }
+        }
+
+        buildEagerConstructor( clazz,
                                className,
                                cw );
 
+        buildEagerUpdateProxyMethod( clazz,
+                                     fieldTypes,
+                                     fieldMethods,
+                                     className,
+                                     cw );
+
         return cw.toByteArray();
     }
 
@@ -255,6 +336,97 @@
     }
 
     /**
+     * Creates a constructor for the shadow proxy receiving
+     * the actual delegate class as parameter
+     * 
+     * @param originalClassName
+     * @param className
+     * @param cw
+     */
+    private static void buildEagerConstructor(final Class clazz,
+                                              final String className,
+                                              final ClassWriter cw) {
+        MethodVisitor mv;
+        {
+            mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+                                 "<init>",
+                                 Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                           new Type[]{Type.getType( clazz )} ),
+                                 null,
+                                 null );
+            mv.visitCode();
+
+            // super();
+            Label l0 = new Label();
+            mv.visitLabel( l0 );
+            mv.visitLineNumber( 41,
+                                l0 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            if ( clazz.isInterface() ) {
+                mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
+                                    Type.getInternalName( Object.class ),
+                                    "<init>",
+                                    Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                              new Type[]{} ) );
+            } else {
+                mv.visitMethodInsn( Opcodes.INVOKESPECIAL,
+                                    Type.getInternalName( clazz ),
+                                    "<init>",
+                                    Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                              new Type[]{} ) );
+            }
+
+            // this.delegate = delegate
+            Label l1 = new Label();
+            mv.visitLabel( l1 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             1 );
+            mv.visitFieldInsn( Opcodes.PUTFIELD,
+                               className,
+                               DELEGATE_FIELD_NAME,
+                               Type.getDescriptor( clazz ) );
+            
+            // this.updateProxy();
+            Label l4 = new Label();
+            mv.visitLabel( l4 );
+            mv.visitVarInsn( Opcodes.ALOAD, 0 );
+            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+                                className,
+                                UPDATE_PROXY,
+                                Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                          new Type[]{} ) );
+
+            // return
+            Label l2 = new Label();
+            mv.visitLabel( l2 );
+            mv.visitLineNumber( 43,
+                                l2 );
+            mv.visitInsn( Opcodes.RETURN );
+
+            Label l3 = new Label();
+            mv.visitLabel( l3 );
+            mv.visitLocalVariable( "this",
+                                   "L" + className + ";",
+                                   null,
+                                   l0,
+                                   l3,
+                                   0 );
+            mv.visitLocalVariable( DELEGATE_FIELD_NAME,
+                                   Type.getDescriptor( clazz ),
+                                   null,
+                                   l0,
+                                   l3,
+                                   1 );
+            mv.visitMaxs( 0,
+                          0 );
+            mv.visitEnd();
+        }
+    }
+
+    /**
      * Creates the proxy reader method for the given method
      * 
      * @param fieldName
@@ -355,11 +527,125 @@
         mv.visitEnd();
     }
 
+    /**
+     * Creates the proxy reader method for the given method
+     * 
+     * @param fieldName
+     * @param fieldFlag
+     * @param method
+     * @param cw
+     */
+    protected static void buildSimpleGetMethod(String fieldName,
+                                               Class fieldType,
+                                               String fieldFlag,
+                                               Method method,
+                                               String className,
+                                               Class clazz,
+                                               ClassWriter cw) {
+        // method signature 
+        Class[] exceptionTypes = method.getExceptionTypes();
+        String[] exceptions = getExceptionArrayAsString( exceptionTypes );
+        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+                                           method.getName(),
+                                           Type.getMethodDescriptor( method ),
+                                           null,
+                                           exceptions );
+        mv.visitCode();
+
+        // return __field;
+        Label l0 = new Label();
+        mv.visitLabel( l0 );
+        mv.visitVarInsn( Opcodes.ALOAD,
+                         0 );
+        mv.visitFieldInsn( Opcodes.GETFIELD,
+                           className,
+                           fieldName,
+                           Type.getDescriptor( fieldType ) );
+        mv.visitInsn( Type.getType( fieldType ).getOpcode( Opcodes.IRETURN ) );
+
+        // local variables table
+        Label l4 = new Label();
+        mv.visitLabel( l4 );
+        mv.visitLocalVariable( "this",
+                               "L" + className + ";",
+                               null,
+                               l0,
+                               l4,
+                               0 );
+        mv.visitMaxs( 0,
+                      0 );
+        mv.visitEnd();
+    }
+
+    protected static void buildEagerUpdateProxyMethod(Class delegate,
+                                                      Map fieldTypes,
+                                                      Map fieldMethods,
+                                                      String className,
+                                                      ClassWriter cw) {
+        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
+                                           UPDATE_PROXY,
+                                           Type.getMethodDescriptor( Type.VOID_TYPE,
+                                                                     new Type[]{} ),
+                                           null,
+                                           null );
+        mv.visitCode();
+        Label l0 = new Label();
+        mv.visitLabel( l0 );
+        for ( Iterator it = fieldTypes.entrySet().iterator(); it.hasNext(); ) {
+            Map.Entry entry = (Map.Entry) it.next();
+            String fieldName = (String) entry.getKey();
+            Class fieldType = (Class) entry.getValue();
+            Method method = (Method) fieldMethods.get( fieldName );
+
+            // __field = this.delegate.getField()
+            Label l1 = new Label();
+            mv.visitLabel( l1 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitFieldInsn( Opcodes.GETFIELD,
+                               className,
+                               DELEGATE_FIELD_NAME,
+                               Type.getDescriptor( delegate ) );
+            if ( delegate.isInterface() ) {
+                mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+                                    Type.getInternalName( delegate ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            } else {
+                mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+                                    Type.getInternalName( delegate ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            }
+            mv.visitFieldInsn( Opcodes.PUTFIELD,
+                               className,
+                               fieldName,
+                               Type.getDescriptor( fieldType ) );
+
+        }
+        Label l4 = new Label();
+        mv.visitLabel( l4 );
+        mv.visitInsn( Opcodes.RETURN );
+        Label l5 = new Label();
+        mv.visitLabel( l5 );
+        mv.visitLocalVariable( "this",
+                               "L" + className + ";",
+                               null,
+                               l0,
+                               l5,
+                               0 );
+        mv.visitMaxs( 0,
+                      0 );
+        mv.visitEnd();
+    }
+
     protected static void buildUpdateProxyMethod(Map fieldTypes,
-                                                String className,
-                                                ClassWriter cw) {
+                                                 String className,
+                                                 ClassWriter cw) {
         MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
-                                           "updateProxy",
+                                           UPDATE_PROXY,
                                            Type.getMethodDescriptor( Type.VOID_TYPE,
                                                                      new Type[]{} ),
                                            null,
@@ -419,49 +705,6 @@
         mv.visitEnd();
     }
 
-    //    protected static void buildEqualsMethod(Class clazz,
-    //                                            String className,
-    //                                            ClassWriter cw) {
-    //        MethodVisitor mv = cw.visitMethod( Opcodes.ACC_PUBLIC,
-    //                                           "equals",
-    //                                           "(Ljava/lang/Object;)Z",
-    //                                           null,
-    //                                           null );
-    //        mv.visitCode();
-    //        Label l0 = new Label();
-    //        mv.visitLabel( l0 );
-    //        mv.visitVarInsn( Opcodes.ALOAD,
-    //                         0 );
-    //        mv.visitFieldInsn( Opcodes.GETFIELD,
-    //                           className,
-    //                           DELEGATE_FIELD_NAME,
-    //                           Type.getDescriptor( clazz ) );
-    //        mv.visitVarInsn( Opcodes.ALOAD,
-    //                         1 );
-    //        mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
-    //                            Type.getInternalName( clazz ),
-    //                            "equals",
-    //                            "(Ljava/lang/Object;)Z" );
-    //        mv.visitInsn( Opcodes.IRETURN );
-    //        Label l1 = new Label();
-    //        mv.visitLabel( l1 );
-    //        mv.visitLocalVariable( "this",
-    //                               "L"+className+";",
-    //                               null,
-    //                               l0,
-    //                               l1,
-    //                               0 );
-    //        mv.visitLocalVariable( "object",
-    //                               Type.getDescriptor( Object.class ),
-    //                               null,
-    //                               l0,
-    //                               l1,
-    //                               1 );
-    //        mv.visitMaxs( 0,
-    //                      0 );
-    //        mv.visitEnd();
-    //    }
-
     protected static void buildDelegateMethod(Method method,
                                               Class clazz,
                                               String className,

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java	2006-10-09 20:51:28 UTC (rev 6713)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java	2006-10-09 21:22:37 UTC (rev 6714)
@@ -126,4 +126,111 @@
         }
     }
     
+    public void testEagerProxyForClass() {
+        try {
+            // creating original object
+            String originalType = "stilton";
+            int originalPrice = 15;
+            Cheese cheese = new Cheese(originalType, originalPrice);
+            
+            // creating proxy
+            Class proxy = ShadowProxyFactory.getEagerProxy( Cheese.class );
+            Cheese cheeseProxy = (Cheese) proxy.getConstructor( new Class[] { Cheese.class } ).newInstance( new Object[] { cheese } );
+
+            // proxy is proxying the values
+            Assert.assertEquals( originalType, cheeseProxy.getType() );
+            Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+            
+            // changing original values
+            String actualType = "rotten stilton";
+            int actualPrice = 1;
+            cheese.setType( actualType );
+            cheese.setPrice( actualPrice );
+            
+            // proxy does not see changes
+            Assert.assertEquals( actualType, cheese.getType() );
+            Assert.assertFalse( actualType.equals( cheeseProxy.getType() ) );
+            Assert.assertEquals( originalType, cheeseProxy.getType() );
+            Assert.assertEquals( actualPrice, cheese.getPrice() );
+            Assert.assertFalse( actualPrice == cheeseProxy.getPrice() );
+            Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+            
+            // reseting proxy
+            ((ShadowProxy) cheeseProxy).updateProxy();
+            
+            // now proxy see changes
+            Assert.assertEquals( actualType, cheese.getType() );
+            Assert.assertEquals( actualType, cheeseProxy.getType() );
+            Assert.assertFalse( originalType.equals( cheeseProxy.getType() ) );
+            Assert.assertEquals( actualPrice, cheese.getPrice() );
+            Assert.assertEquals( actualPrice, cheeseProxy.getPrice() );
+            Assert.assertFalse( originalPrice == cheeseProxy.getPrice() );
+            
+        } catch ( Exception e ) {
+            fail("Error: "+e.getMessage());
+        }
+    }
+    
+    public void testEagerProxyForInterface() {
+        try {
+            // creating original object
+            String originalType = "stilton";
+            int originalPrice = 15;
+            Cheese cheese = new Cheese(originalType, originalPrice);
+            
+            // creating proxy
+            Class proxy = ShadowProxyFactory.getEagerProxy( CheeseInterface.class );
+            CheeseInterface cheeseProxy = (CheeseInterface) proxy.getConstructor( new Class[] { CheeseInterface.class } ).newInstance( new Object[] { cheese } );
+
+            // proxy is proxying the values
+            Assert.assertEquals( originalType, cheeseProxy.getType() );
+            Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+            
+            // changing original values
+            String actualType = "rotten stilton";
+            int actualPrice = 1;
+            cheese.setType( actualType );
+            cheese.setPrice( actualPrice );
+            
+            // proxy does not see changes
+            Assert.assertEquals( actualType, cheese.getType() );
+            Assert.assertFalse( actualType.equals( cheeseProxy.getType() ) );
+            Assert.assertEquals( originalType, cheeseProxy.getType() );
+            Assert.assertEquals( actualPrice, cheese.getPrice() );
+            Assert.assertFalse( actualPrice == cheeseProxy.getPrice() );
+            Assert.assertEquals( originalPrice, cheeseProxy.getPrice() );
+            
+            // reseting proxy
+            ((ShadowProxy) cheeseProxy).updateProxy();
+            
+            // now proxy see changes
+            Assert.assertEquals( actualType, cheese.getType() );
+            Assert.assertEquals( actualType, cheeseProxy.getType() );
+            Assert.assertFalse( originalType.equals( cheeseProxy.getType() ) );
+            Assert.assertEquals( actualPrice, cheese.getPrice() );
+            Assert.assertEquals( actualPrice, cheeseProxy.getPrice() );
+            Assert.assertFalse( originalPrice == cheeseProxy.getPrice() );
+            
+        } catch ( Exception e ) {
+            fail("Error: "+e.getMessage());
+        }
+    }
+    
+    public void testEagerProxyForAPIClass() {
+        try {
+            // creating original object
+            List list = new ArrayList();
+            
+            // creating proxy
+            Class proxy = ShadowProxyFactory.getEagerProxy( ArrayList.class );
+            List listProxy = (List) proxy.getConstructor( new Class[] { ArrayList.class } ).newInstance( new Object[] { list } );
+
+            // proxy is proxying the values
+            Assert.assertEquals( list, listProxy );
+            
+        } catch ( Exception e ) {
+            fail("Error: "+e.getMessage());
+        }
+    }
+    
 }




More information about the jboss-svn-commits mailing list