[jboss-svn-commits] JBL Code SVN: r13115 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/util and 2 other directories.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Thu Jul 5 15:58:35 EDT 2007


Author: tirelli
Date: 2007-07-05 15:58:35 -0400 (Thu, 05 Jul 2007)
New Revision: 13115

Added:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ShadowProxyUtils.java
Modified:
   labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Address.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Person.java
   labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
Log:
JBRULES-972: Adding support to shallow shadowing of array, collection and map attributes

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	2007-07-05 19:39:49 UTC (rev 13114)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java	2007-07-05 19:58:35 UTC (rev 13115)
@@ -32,6 +32,7 @@
 import org.drools.asm.MethodVisitor;
 import org.drools.asm.Opcodes;
 import org.drools.asm.Type;
+import org.drools.util.ShadowProxyUtils;
 
 /**
  * A factory for ShadowProxy classes
@@ -511,42 +512,79 @@
                            fieldFlag,
                            Type.BOOLEAN_TYPE.getDescriptor() );
 
-        //     __field = this.delegate.method();
-        final Label l2 = new Label();
-        mv.visitLabel( l2 );
-        mv.visitVarInsn( Opcodes.ALOAD,
-                         0 );
-        mv.visitVarInsn( Opcodes.ALOAD,
-                         0 );
-        mv.visitFieldInsn( Opcodes.GETFIELD,
-                           className,
-                           ShadowProxyFactory.DELEGATE_FIELD_NAME,
-                           Type.getDescriptor( clazz ) );
-        if ( clazz.isInterface() ) {
-            mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
-                                Type.getInternalName( clazz ),
-                                method.getName(),
-                                Type.getMethodDescriptor( method ) );
+        if ( Map.class.isAssignableFrom( fieldType ) || Collection.class.isAssignableFrom( fieldType ) || fieldType.isArray() ) {
+
+            // FieldType aux = this.delegate.getField();
+            Label l01 = new Label();
+            mv.visitLabel( l01 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitFieldInsn( Opcodes.GETFIELD,
+                               className,
+                               DELEGATE_FIELD_NAME,
+                               Type.getDescriptor( clazz ) );
+            if ( clazz.isInterface() ) {
+                mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+                                    Type.getInternalName( clazz ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            } else {
+                mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+                                    Type.getInternalName( clazz ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            }
+            mv.visitVarInsn( Opcodes.ASTORE,
+                             1 );
+
+            // this.field = (FieldType) ShadoProxyUtils.clone( aux );
+            Label l11 = new Label();
+            mv.visitLabel( l11 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             1 );
+            mv.visitMethodInsn( Opcodes.INVOKESTATIC,
+                                Type.getInternalName( ShadowProxyUtils.class ),
+                                "cloneObject",
+                                "(Ljava/lang/Object;)Ljava/lang/Object;" );
+            mv.visitTypeInsn( Opcodes.CHECKCAST,
+                              Type.getInternalName( fieldType ) );
+            mv.visitFieldInsn( Opcodes.PUTFIELD,
+                               className,
+                               fieldName,
+                               Type.getDescriptor( fieldType ) );
+
         } else {
-            mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
-                                Type.getInternalName( clazz ),
-                                method.getName(),
-                                Type.getMethodDescriptor( method ) );
+            //     __field = this.delegate.method();
+            final Label l2 = new Label();
+            mv.visitLabel( l2 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitVarInsn( Opcodes.ALOAD,
+                             0 );
+            mv.visitFieldInsn( Opcodes.GETFIELD,
+                               className,
+                               ShadowProxyFactory.DELEGATE_FIELD_NAME,
+                               Type.getDescriptor( clazz ) );
+            if ( clazz.isInterface() ) {
+                mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+                                    Type.getInternalName( clazz ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            } else {
+                mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+                                    Type.getInternalName( clazz ),
+                                    method.getName(),
+                                    Type.getMethodDescriptor( method ) );
+            }
+            mv.visitFieldInsn( Opcodes.PUTFIELD,
+                               className,
+                               fieldName,
+                               Type.getDescriptor( fieldType ) );
+
         }
-        mv.visitFieldInsn( Opcodes.PUTFIELD,
-                           className,
-                           fieldName,
-                           Type.getDescriptor( fieldType ) );
 
-        //    this.__hashCache = 0;
-        mv.visitVarInsn( Opcodes.ALOAD,
-                         0 );
-        mv.visitInsn( Opcodes.ICONST_0 );
-        mv.visitFieldInsn( Opcodes.PUTFIELD,
-                           className,
-                           ShadowProxyFactory.HASHCACHE_FIELD_NAME,
-                           Type.getDescriptor( int.class ) );
-
         // }
         // return __field;
         mv.visitLabel( l1 );
@@ -719,8 +757,7 @@
                            className,
                            DELEGATE_FIELD_NAME,
                            Type.getDescriptor( clazz ) );
-        if ( Collection.class.isAssignableFrom( clazz ) ||
-             Map.class.isAssignableFrom( clazz ) ) {
+        if ( Collection.class.isAssignableFrom( clazz ) || Map.class.isAssignableFrom( clazz ) ) {
             Label l1 = new Label();
             mv.visitLabel( l1 );
             mv.visitVarInsn( Opcodes.ALOAD,

Added: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ShadowProxyUtils.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ShadowProxyUtils.java	                        (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/util/ShadowProxyUtils.java	2007-07-05 19:58:35 UTC (rev 13115)
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2007 JBoss Inc
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Created on Jul 5, 2007
+ */
+package org.drools.util;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A class with simple utility methods for shadowing
+ * 
+ * @author etirelli
+ */
+public class ShadowProxyUtils {
+
+    private ShadowProxyUtils() {
+    }
+
+    public static Object cloneObject(Object original) {
+        Object clone = null;
+        if ( original instanceof Cloneable ) {
+            try {
+                Method cloneMethod = original.getClass().getMethod( "clone",
+                                                                    new Class[0] );
+                clone = cloneMethod.invoke( original,
+                                            new Object[0] );
+            } catch ( Exception e ) {
+                // Nothing to do
+            }
+        }
+
+        if ( clone == null ) {
+            try {
+                if ( original instanceof Map ) {
+                    clone = original.getClass().newInstance();
+                    ((Map) clone).putAll( (Map) original );
+                } else if ( original instanceof Collection ) {
+                    clone = original.getClass().newInstance();
+                    ((Collection) clone).addAll( (Collection) original );
+                } else if ( original.getClass().isArray() ) {
+                    clone = cloneArray( original );
+                }
+            } catch ( Exception e ) {
+                e.printStackTrace();
+                // nothing to do
+            }
+        }
+
+        if ( clone == null ) {
+            clone = original;
+        }
+
+        return clone;
+    }
+
+    public static Object cloneArray(Object original) {
+        Object result = null;
+
+        if ( original.getClass().isArray() ) {
+            final int arrayLength = Array.getLength( original );
+
+            if ( arrayLength == 0 ) {
+                // empty arrays are immutable
+                result = original;
+            } else {
+                final Class componentType = original.getClass().getComponentType();
+
+                // Even though arrays implicitly have a public clone(), it
+                // cannot be invoked reflectively, so need to do copy construction:
+                result = Array.newInstance( componentType,
+                                            arrayLength );
+                
+                if( componentType.isArray() ) {
+                    for( int i = 0; i < arrayLength; i++ ) {
+                        Array.set( result, i, cloneArray( Array.get( original, i ) ) );
+                    }
+                } else {
+                    System.arraycopy( original,
+                                      0,
+                                      result,
+                                      0,
+                                      arrayLength );
+                }
+            }
+        }
+        return result;
+    }
+
+}

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Address.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Address.java	2007-07-05 19:39:49 UTC (rev 13114)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Address.java	2007-07-05 19:58:35 UTC (rev 13115)
@@ -32,5 +32,9 @@
     public void setStreet(String street) {
         this.street = street;
     }
+    
+    public String toString() {
+        return "Address( "+this.street+", "+this.number+" - phone: "+this.phone+" )";
+    }
 
 }

Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Person.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Person.java	2007-07-05 19:39:49 UTC (rev 13114)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/Person.java	2007-07-05 19:58:35 UTC (rev 13115)
@@ -1,6 +1,8 @@
 package org.drools;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 
 public class Person {
@@ -14,12 +16,21 @@
     private String country;
     
     private Map addresses;
+    
+    private List addressList;
+    
+    private Address[] addressArray;
 
+    public Person() {
+    }
+    
     public Person(final String name,
                   final int age) {
         this.name = name;
         this.age = age;
         this.addresses = new HashMap();
+        this.addressList = new ArrayList();
+        this.addressArray = new Address[10];
     }
 
     /**
@@ -90,4 +101,20 @@
         this.addresses = addresses;
     }
 
+    public List getAddressList() {
+        return addressList;
+    }
+
+    public void setAddressList(List addressList) {
+        this.addressList = addressList;
+    }
+
+    public Address[] getAddressArray() {
+        return addressArray;
+    }
+
+    public void setAddressArray(Address[] addressArray) {
+        this.addressArray = addressArray;
+    }
+    
 }

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	2007-07-05 19:39:49 UTC (rev 13114)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java	2007-07-05 19:58:35 UTC (rev 13115)
@@ -8,8 +8,10 @@
 import junit.framework.Assert;
 import junit.framework.TestCase;
 
+import org.drools.Address;
 import org.drools.Cheese;
 import org.drools.CheeseInterface;
+import org.drools.Person;
 
 public class ShadowProxyFactoryTest extends TestCase {
 
@@ -237,13 +239,13 @@
     //        }
     //    }
 
-//    private int cheeseHashCode(final Cheese cheese) {
-//        final int PRIME = 31;
-//        int result = 1;
-//        result = PRIME * result + ((cheese.getType() == null) ? 0 : cheese.getType().hashCode());
-//        result = PRIME * result + cheese.getPrice();
-//        return result;
-//    }
+    //    private int cheeseHashCode(final Cheese cheese) {
+    //        final int PRIME = 31;
+    //        int result = 1;
+    //        result = PRIME * result + ((cheese.getType() == null) ? 0 : cheese.getType().hashCode());
+    //        result = PRIME * result + cheese.getPrice();
+    //        return result;
+    //    }
 
     public void testClassWithStaticMethod() {
         try {
@@ -307,11 +309,11 @@
             originalList.add( "b" );
             originalList.add( "c" );
             originalList.add( "d" );
-            
+
             // creating proxy
             final Class proxy = ShadowProxyFactory.getProxy( originalList.getClass() );
             final List listProxy = (List) proxy.getConstructor( new Class[]{originalList.getClass()} ).newInstance( new Object[]{originalList} );
-            ((ShadowProxy)listProxy).setShadowedObject( originalList );
+            ((ShadowProxy) listProxy).setShadowedObject( originalList );
 
             // proxy is proxying the values
             Assert.assertEquals( "a",
@@ -323,16 +325,16 @@
             // proxy must recongnize the original object on equals() calls
             Assert.assertEquals( listProxy,
                                  originalList );
-            
+
             originalList.remove( "c" );
             originalList.add( "e" );
             Assert.assertTrue( listProxy.contains( "c" ) );
             Assert.assertFalse( listProxy.contains( "e" ) );
-            
-            ((ShadowProxy)listProxy).updateProxy();
+
+            ((ShadowProxy) listProxy).updateProxy();
             Assert.assertFalse( listProxy.contains( "c" ) );
             Assert.assertTrue( listProxy.contains( "e" ) );
-            
+
             // proxy must recongnize the original object on equals() calls
             Assert.assertEquals( listProxy,
                                  originalList );
@@ -346,14 +348,17 @@
         try {
             // creating original object
             Map originalMap = new HashMap();
-            originalMap.put( "name", "Edson" );
-            originalMap.put( "surname", "Tirelli" );
-            originalMap.put( "age", "28" );
-            
+            originalMap.put( "name",
+                             "Edson" );
+            originalMap.put( "surname",
+                             "Tirelli" );
+            originalMap.put( "age",
+                             "28" );
+
             // creating proxy
             final Class proxy = ShadowProxyFactory.getProxy( originalMap.getClass() );
             final Map mapProxy = (Map) proxy.getConstructor( new Class[]{originalMap.getClass()} ).newInstance( new Object[]{originalMap} );
-            ((ShadowProxy)mapProxy).setShadowedObject( originalMap );
+            ((ShadowProxy) mapProxy).setShadowedObject( originalMap );
 
             // proxy is proxying the values
             Assert.assertEquals( "Edson",
@@ -365,16 +370,17 @@
             // proxy must recongnize the original object on equals() calls
             Assert.assertEquals( mapProxy,
                                  originalMap );
-            
+
             originalMap.remove( "age" );
-            originalMap.put( "hair", "brown" );
+            originalMap.put( "hair",
+                             "brown" );
             Assert.assertTrue( mapProxy.containsKey( "age" ) );
             Assert.assertFalse( mapProxy.containsKey( "hair" ) );
-            
-            ((ShadowProxy)mapProxy).updateProxy();
+
+            ((ShadowProxy) mapProxy).updateProxy();
             Assert.assertFalse( mapProxy.containsKey( "age" ) );
             Assert.assertTrue( mapProxy.containsKey( "hair" ) );
-            
+
             // proxy must recongnize the original object on equals() calls
             Assert.assertEquals( mapProxy,
                                  originalMap );
@@ -384,4 +390,172 @@
         }
     }
 
+    public void testProxyForMapsAttributes() {
+        try {
+            Person bob = new Person( "bob",
+                                     30 );
+            Address addr1 = new Address( "street 1",
+                                         "111",
+                                         "11-1111-1111" );
+            Address addr2 = new Address( "street 2",
+                                         "222",
+                                         "22-2222-2222" );
+            Address addr3 = new Address( "street 3",
+                                         "333",
+                                         "33-3333-3333" );
+            Address addr4 = new Address( "street 4",
+                                         "444",
+                                         "44-4444-4444" );
+            Map addresses = new HashMap();
+            addresses.put( "home",
+                           addr1 );
+            addresses.put( "business",
+                           addr2 );
+            bob.setAddresses( addresses );
+
+            // creating proxy
+            final Class proxy = ShadowProxyFactory.getProxy( bob.getClass() );
+            final Person bobProxy = (Person) proxy.getConstructor( new Class[]{bob.getClass()} ).newInstance( new Object[]{bob} );
+            ((ShadowProxy) bobProxy).setShadowedObject( bob );
+
+            // proxy is proxying the values
+            Assert.assertEquals( bob.getAddresses().get( "business" ),
+                                 bobProxy.getAddresses().get( "business" ) );
+            Assert.assertSame( bob,
+                               ((ShadowProxy) bobProxy).getShadowedObject() );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+
+            bob.getAddresses().remove( "business" );
+            bob.getAddresses().put( "parents",
+                                    addr3 );
+            bob.getAddresses().put( "home",
+                                    addr4 );
+            Assert.assertTrue( bobProxy.getAddresses().containsKey( "business" ) );
+            Assert.assertFalse( bobProxy.getAddresses().containsKey( "parents" ) );
+            Assert.assertEquals( addr1,
+                                 bobProxy.getAddresses().get( "home" ) );
+
+            ((ShadowProxy) bobProxy).updateProxy();
+            Assert.assertFalse( bobProxy.getAddresses().containsKey( "business" ) );
+            Assert.assertTrue( bobProxy.getAddresses().containsKey( "parents" ) );
+            Assert.assertEquals( addr4,
+                                 bobProxy.getAddresses().get( "home" ) );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+        } catch ( final Exception e ) {
+            e.printStackTrace();
+            fail( "Error: " + e.getMessage() );
+        }
+    }
+
+    public void testProxyForCollectionAttributes() {
+        try {
+            Person bob = new Person( "bob",
+                                     30 );
+            Address addr1 = new Address( "street 1",
+                                         "111",
+                                         "11-1111-1111" );
+            Address addr2 = new Address( "street 2",
+                                         "222",
+                                         "22-2222-2222" );
+            Address addr3 = new Address( "street 3",
+                                         "333",
+                                         "33-3333-3333" );
+            bob.getAddressList().add( addr1 );
+            bob.getAddressList().add( addr2 );
+
+            // creating proxy
+            final Class proxy = ShadowProxyFactory.getProxy( bob.getClass() );
+            final Person bobProxy = (Person) proxy.getConstructor( new Class[]{bob.getClass()} ).newInstance( new Object[]{bob} );
+            ((ShadowProxy) bobProxy).setShadowedObject( bob );
+
+            // proxy is proxying the values
+            Assert.assertEquals( 2,
+                                 bobProxy.getAddressList().size() );
+            Assert.assertSame( bob,
+                               ((ShadowProxy) bobProxy).getShadowedObject() );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+
+            bob.getAddressList().remove( addr2 );
+            bob.getAddressList().add( addr3 );
+
+            Assert.assertTrue( bobProxy.getAddressList().contains( addr2 ) );
+            Assert.assertFalse( bobProxy.getAddressList().contains( addr3 ) );
+
+            ((ShadowProxy) bobProxy).updateProxy();
+            Assert.assertFalse( bobProxy.getAddressList().contains( addr2 ) );
+            Assert.assertTrue( bobProxy.getAddressList().contains( addr3 ) );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+        } catch ( final Exception e ) {
+            e.printStackTrace();
+            fail( "Error: " + e.getMessage() );
+        }
+    }
+
+    public void testProxyForArrayAttributes() {
+        try {
+            Person bob = new Person( "bob",
+                                     30 );
+            Address addr1 = new Address( "street 1",
+                                         "111",
+                                         "11-1111-1111" );
+            Address addr2 = new Address( "street 2",
+                                         "222",
+                                         "22-2222-2222" );
+            Address addr3 = new Address( "street 3",
+                                         "333",
+                                         "33-3333-3333" );
+            bob.getAddressArray()[0] = addr1;
+            bob.getAddressArray()[1] = addr2;
+
+            // creating proxy
+            final Class proxy = ShadowProxyFactory.getProxy( bob.getClass() );
+            final Person bobProxy = (Person) proxy.getConstructor( new Class[]{bob.getClass()} ).newInstance( new Object[]{bob} );
+            ((ShadowProxy) bobProxy).setShadowedObject( bob );
+
+            // proxy is proxying the values
+            Assert.assertEquals( addr1,
+                                 bobProxy.getAddressArray()[0] );
+            Assert.assertEquals( addr2,
+                                 bobProxy.getAddressArray()[1] );
+            Assert.assertSame( bob,
+                               ((ShadowProxy) bobProxy).getShadowedObject() );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+
+            bob.getAddressArray()[1] = addr3;
+
+            Assert.assertEquals( addr1,
+                                 bobProxy.getAddressArray()[0] );
+            Assert.assertEquals( addr2,
+                                 bobProxy.getAddressArray()[1] );
+
+            ((ShadowProxy) bobProxy).updateProxy();
+            Assert.assertEquals( addr1,
+                                 bobProxy.getAddressArray()[0] );
+            Assert.assertEquals( addr3,
+                                 bobProxy.getAddressArray()[1] );
+
+            // proxy must recongnize the original object on equals() calls
+            Assert.assertEquals( bobProxy,
+                                 bob );
+        } catch ( final Exception e ) {
+            e.printStackTrace();
+            fail( "Error: " + e.getMessage() );
+        }
+    }
+    
 }




More information about the jboss-svn-commits mailing list