[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