[jboss-svn-commits] JBL Code SVN: r13591 - in labs/jbossrules/trunk/drools-core/src: main/java/org/drools/common and 7 other directories.
jboss-svn-commits at lists.jboss.org
jboss-svn-commits at lists.jboss.org
Tue Jul 17 22:15:24 EDT 2007
Author: tirelli
Date: 2007-07-17 22:15:24 -0400 (Tue, 17 Jul 2007)
New Revision: 13591
Added:
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/CheeseEqual.java
Modified:
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassObjectType.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/EqualityKey.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/facttemplates/FactTemplateObjectType.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/Rete.java
labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/ObjectType.java
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ObjectTypeNodeTest.java
labs/jbossrules/trunk/drools-core/src/test/java/org/drools/spi/MockObjectType.java
Log:
JBRULES-1014: fixing Shadow Proxy and working around some final classes
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassObjectType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassObjectType.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ClassObjectType.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -16,12 +16,6 @@
* limitations under the License.
*/
-import java.lang.reflect.Field;
-
-import org.drools.RuntimeDroolsException;
-import org.drools.objenesis.Objenesis;
-import org.drools.objenesis.ObjenesisStd;
-import org.drools.objenesis.instantiator.ObjectInstantiator;
import org.drools.spi.ObjectType;
/**
@@ -79,6 +73,20 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
+ * Determine if the passed <code>Class</code> matches to the object type
+ * defined by this <code>objectType</code> instance.
+ *
+ * @param clazz
+ * The <code>Class</code> to test.
+ *
+ * @return <code>true</code> if the <code>Class</code> matches this
+ * object type, else <code>false</code>.
+ */
+ public boolean matchesClass(final Class clazz) {
+ return getClassType().isAssignableFrom( clazz );
+ }
+
+ /**
* Determine if the passed <code>Object</code> belongs to the object type
* defined by this <code>objectType</code> instance.
*
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-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/base/ShadowProxyFactory.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -35,36 +35,35 @@
import org.drools.asm.MethodVisitor;
import org.drools.asm.Opcodes;
import org.drools.asm.Type;
-import org.drools.rule.MapBackedClassLoader;
import org.drools.util.ShadowProxyUtils;
/**
* A factory for ShadowProxy classes
*/
public class ShadowProxyFactory {
- private static final String UPDATE_PROXY = "updateProxy";
- private static final String SET_SHADOWED_OBJECT = "setShadowedObject";
- private static final String GET_SHADOWED_OBJECT = "getShadowedObject";
+ private static final String UPDATE_PROXY = "updateProxy";
+ private static final String SET_SHADOWED_OBJECT = "setShadowedObject";
+ private static final String GET_SHADOWED_OBJECT = "getShadowedObject";
- private static final String BASE_INTERFACE = Type.getInternalName( ShadowProxy.class );
+ private static final String BASE_INTERFACE = Type.getInternalName( ShadowProxy.class );
//private static final String FIELD_NAME_PREFIX = "__";
- public static final String FIELD_SET_FLAG = "IsSet";
+ public static final String FIELD_SET_FLAG = "IsSet";
- public static final String DELEGATE_FIELD_NAME = "delegate";
+ public static final String DELEGATE_FIELD_NAME = "delegate";
- public static final String HASHCACHE_FIELD_NAME = "__hashCache";
-
+ public static final String HASHCACHE_FIELD_NAME = "__hashCache";
+
private static final ProtectionDomain PROTECTION_DOMAIN;
-
+
static {
PROTECTION_DOMAIN = (ProtectionDomain) AccessController.doPrivileged( new PrivilegedAction() {
public Object run() {
return ShadowProxyFactory.class.getProtectionDomain();
}
} );
- }
+ }
public static Class getProxy(final Class clazz) {
try {
@@ -965,10 +964,17 @@
offset );
offset += type.getSize();
}
- mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
- Type.getInternalName( clazz ),
- method.getName(),
- Type.getMethodDescriptor( method ) );
+ 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.visitInsn( Type.getType( method.getReturnType() ).getOpcode( Opcodes.IRETURN ) );
final Label l1 = new Label();
mv.visitLabel( l1 );
@@ -1009,7 +1015,7 @@
final Label l0 = new Label();
mv.visitLabel( l0 );
- // if ( this == object || this.delegate == object )
+ // if ( this == object || this.delegate == object || this.delegate.equals( object ) ) {
mv.visitVarInsn( Opcodes.ALOAD,
0 );
mv.visitVarInsn( Opcodes.ALOAD,
@@ -1025,17 +1031,38 @@
Type.getDescriptor( clazz ) );
mv.visitVarInsn( Opcodes.ALOAD,
1 );
+ mv.visitJumpInsn( Opcodes.IF_ACMPEQ,
+ l1 );
+
+ mv.visitVarInsn(Opcodes.ALOAD, 0);
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+ mv.visitVarInsn(Opcodes.ALOAD, 1);
+ if ( clazz.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ }
Label l2 = new Label();
- mv.visitJumpInsn( Opcodes.IF_ACMPNE,
- l2 );
+ mv.visitJumpInsn(Opcodes.IFEQ, l2);
+
+ // return true;
mv.visitLabel( l1 );
-
- // return true;
mv.visitInsn( Opcodes.ICONST_1 );
mv.visitInsn( Opcodes.IRETURN );
+ mv.visitLabel( l2 );
// if (( object == null ) || ( ! ( object instanceof <class> ) ) )
- mv.visitLabel( l2 );
mv.visitVarInsn( Opcodes.ALOAD,
1 );
final Label l3 = new Label();
@@ -1053,9 +1080,75 @@
mv.visitLabel( l3 );
mv.visitInsn( Opcodes.ICONST_0 );
mv.visitInsn( Opcodes.IRETURN );
+ mv.visitLabel( l4 );
+ // if( object instanceof ShadowProxy &&
+ // ( this.delegate == ((ShadowProxy)object).delegate ||
+ // this.delegate.equals( ((ShadowProxy)object).delegate ) ) ) {
+ Label c0 = new Label();
+ mv.visitLabel( c0 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 1 );
+ mv.visitTypeInsn( Opcodes.INSTANCEOF,
+ className );
+ Label c1 = new Label();
+ mv.visitJumpInsn( Opcodes.IFEQ,
+ c1 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 1 );
+ mv.visitTypeInsn( Opcodes.CHECKCAST,
+ className );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+ Label c2 = new Label();
+ mv.visitJumpInsn( Opcodes.IF_ACMPEQ,
+ c2 );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 0 );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+ mv.visitVarInsn( Opcodes.ALOAD,
+ 1 );
+ mv.visitTypeInsn( Opcodes.CHECKCAST,
+ className );
+ mv.visitFieldInsn( Opcodes.GETFIELD,
+ className,
+ DELEGATE_FIELD_NAME,
+ Type.getDescriptor( clazz ) );
+ if ( clazz.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ }
+ mv.visitJumpInsn( Opcodes.IFEQ,
+ c1 );
+ mv.visitLabel( c2 );
+ // return true;
+ mv.visitInsn( Opcodes.ICONST_1 );
+ mv.visitInsn( Opcodes.IRETURN );
+ // }
+ mv.visitLabel( c1 );
+
+
// <class> other = (<class>) object;
- mv.visitLabel( l4 );
mv.visitVarInsn( Opcodes.ALOAD,
1 );
mv.visitTypeInsn( Opcodes.CHECKCAST,
@@ -1322,11 +1415,19 @@
Type.getDescriptor( clazz ) );
mv.visitVarInsn( Opcodes.ALOAD,
1 );
- mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
- Type.getInternalName( clazz ),
- "equals",
- Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
- new Type[]{Type.getType( Object.class )} ) );
+ if ( clazz.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName( clazz ),
+ "equals",
+ Type.getMethodDescriptor( Type.BOOLEAN_TYPE,
+ new Type[]{Type.getType( Object.class )} ) );
+ }
mv.visitInsn( Opcodes.IRETURN );
Label l3 = new Label();
mv.visitLabel( l3 );
@@ -1401,11 +1502,19 @@
className,
DELEGATE_FIELD_NAME,
Type.getDescriptor( clazz ) );
- mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
- Type.getInternalName( clazz ),
- "hashCode",
- Type.getMethodDescriptor( Type.INT_TYPE,
- new Type[0] ) );
+ if ( clazz.isInterface() ) {
+ mv.visitMethodInsn( Opcodes.INVOKEINTERFACE,
+ Type.getInternalName( clazz ),
+ "hashCode",
+ Type.getMethodDescriptor( Type.INT_TYPE,
+ new Type[0] ) );
+ } else {
+ mv.visitMethodInsn( Opcodes.INVOKEVIRTUAL,
+ Type.getInternalName( clazz ),
+ "hashCode",
+ Type.getMethodDescriptor( Type.INT_TYPE,
+ new Type[0] ) );
+ }
mv.visitFieldInsn( Opcodes.PUTFIELD,
className,
HASHCACHE_FIELD_NAME,
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/AbstractWorkingMemory.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -746,12 +746,22 @@
// we need to remove the handle from the map, before replacing the object
// and then re-add the handle. Otherwise we may end up with a leak.
this.assertMap.remove( handle );
- handle.setObject( object );
+ Object oldObject = handle.getObject();
+ if( oldObject instanceof ShadowProxy ) {
+ ((ShadowProxy) oldObject).setShadowedObject( object );
+ } else {
+ handle.setObject( object );
+ }
this.assertMap.put( handle,
handle,
false );
} else {
- handle.setObject( object );
+ Object oldObject = handle.getObject();
+ if( oldObject instanceof ShadowProxy ) {
+ ((ShadowProxy) oldObject).setShadowedObject( object );
+ } else {
+ handle.setObject( object );
+ }
}
return handle;
} else {
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/EqualityKey.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/EqualityKey.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/common/EqualityKey.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -20,6 +20,8 @@
import java.util.ArrayList;
import java.util.List;
+import org.drools.base.ShadowProxy;
+
/**
* Upon instantiation the EqualityKey caches the first Object's hashCode
* this can never change. The EqualityKey has an internal datastructure
@@ -153,7 +155,7 @@
if ( object instanceof EqualityKey ) {
return this == object;
}
-
+
return (this.handle.getObject().equals( object ));
}
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/facttemplates/FactTemplateObjectType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/facttemplates/FactTemplateObjectType.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/facttemplates/FactTemplateObjectType.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -73,6 +73,20 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
+ * Determine if the passed <code>Class</code> matches to the object type
+ * defined by this <code>objectType</code> instance.
+ *
+ * @param clazz
+ * The <code>Class</code> to test.
+ *
+ * @return <code>true</code> if the <code>Class</code> matches this
+ * object type, else <code>false</code>.
+ */
+ public boolean matchesClass(final Class clazz) {
+ return FactImpl.class.isAssignableFrom( clazz );
+ }
+
+ /**
* Determine if the passed <code>Object</code> belongs to the object type
* defined by this <code>objectType</code> instance.
*
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/ObjectTypeNode.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -128,6 +128,18 @@
}
/**
+ * Tests the provided class to see if this <code>ObjectTypeNode</code> can receive instances of that class
+ * for assertion and retraction propagations.
+ *
+ * @param object
+ * @return
+ * boolean value indicating whether the <code>ObjectTypeNode</code> can receive instances of the class.
+ */
+ public boolean matchesClass(final Class clazz) {
+ return this.objectType.matchesClass( clazz );
+ }
+
+ /**
* Propagate the <code>FactHandleimpl</code> through the <code>Rete</code> network. All
* <code>FactHandleImpl</code> should be remembered in the node memory, so that later runtime rule attachmnents
* can have the matched facts propagated to them.
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/Rete.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/Rete.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/reteoo/Rete.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -187,7 +187,7 @@
ObjectTypeConf objectTypeConf;
if ( object instanceof ShadowProxy ) {
- objectTypeConf = (ObjectTypeConf) memory.get( object.getClass().getSuperclass() );
+ objectTypeConf = (ObjectTypeConf) memory.get( ((ShadowProxy)object).getShadowedObject().getClass() );
} else {
objectTypeConf = (ObjectTypeConf) memory.get( object.getClass() );
}
@@ -310,49 +310,114 @@
//private final InternalRuleBase ruleBase;
- public ObjectTypeConf(Class cls,
+ public ObjectTypeConf(Class clazz,
InternalRuleBase ruleBase) {
- this.cls = cls;
+ this.cls = clazz;
this.ruleBase = ruleBase;
- Rete rete = ruleBase.getRete();
- if ( !ruleBase.getConfiguration().isShadowProxy() || cls == null || !ruleBase.getConfiguration().isShadowed( cls.getName() ) ) {
+ defineShadowProxyData( clazz );
+ }
+
+ private void defineShadowProxyData(Class clazz) {
+ Rete rete = this.ruleBase.getRete();
+
+ if ( !ruleBase.getConfiguration().isShadowProxy() || clazz == null || !ruleBase.getConfiguration().isShadowed( clazz.getName() ) ) {
+ this.shadowEnabled = false;
+ this.shadowClass = null;
+ this.instantiator = null;
return;
}
-
- Package pkg = cls.getPackage();
+
+ Package pkg = clazz.getPackage();
String pkgName = (pkg != null) ? pkg.getName() : "";
if ( "org.drools.reteoo".equals( pkgName ) || "org.drools.base".equals( pkgName ) ) {
// We don't shadow internal classes
this.shadowEnabled = false;
+ this.shadowClass = null;
+ this.instantiator = null;
return;
}
+ // try to generate proxy for the actual class
+ Class shadowClass = loadOrGenerateProxy( clazz,
+ rete );
+
+ if ( shadowClass == null ) {
+ // if it failed, try to find a parent class
+ ObjectTypeNode[] nodes = this.getMatchingObjectTypes( clazz );
+ Class shadowClassRoot = clazz;
+ while ( shadowClass == null && (shadowClassRoot = this.findAFeasibleSuperclassOrInterface( nodes,
+ shadowClassRoot )) != null ) {
+ shadowClass = loadOrGenerateProxy( shadowClassRoot,
+ rete );
+ }
+ }
+
+ if ( shadowClass != null ) {
+ this.shadowClass = shadowClass;
+ this.shadowEnabled = true;
+ setInstantiator();
+ }
+ }
+
+ private Class loadOrGenerateProxy(Class clazz,
+ Rete rete) {
Class shadowClass = null;
- final String shadowProxyName = ShadowProxyFactory.getProxyClassNameForClass( this.cls );
+ final String shadowProxyName = ShadowProxyFactory.getProxyClassNameForClass( clazz );
try {
// if already loaded
shadowClass = rete.getRuleBase().getMapBackedClassLoader().loadClass( shadowProxyName );
} catch ( final ClassNotFoundException cnfe ) {
// otherwise, create and load
- final byte[] proxyBytes = ShadowProxyFactory.getProxyBytes( cls );
+ final byte[] proxyBytes = ShadowProxyFactory.getProxyBytes( clazz );
if ( proxyBytes != null ) {
rete.getRuleBase().getMapBackedClassLoader().addClass( shadowProxyName,
proxyBytes );
try {
shadowClass = rete.getRuleBase().getMapBackedClassLoader().loadClass( shadowProxyName );
} catch ( ClassNotFoundException e ) {
- throw new RuntimeException( "Unable to find or generate the ShadowProxy implementation for '" + this.cls.getName() + "'" );
+ throw new RuntimeException( "Unable to find or generate the ShadowProxy implementation for '" + clazz + "'" );
}
}
}
+ return shadowClass;
+ }
- if ( shadowClass != null ) {
- this.shadowClass = shadowClass;
- this.shadowEnabled = true;
- setInstantiator();
+ private Class findAFeasibleSuperclassOrInterface(ObjectTypeNode[] nodes,
+ Class clazz) {
+
+ // check direct superclass
+ Class ret = clazz.getSuperclass();
+ boolean isOk = ret != null && ret != Object.class; // we don't want to shadow java.lang.Object
+ if ( isOk ) {
+ for ( int i = 0; isOk && ret != null && i < nodes.length; i++ ) {
+ isOk = nodes[i].matchesClass( ret );
+ }
}
+
+ if ( !isOk ) {
+ // try the interfaces now...
+ Class[] interfaces = clazz.getInterfaces();
+ boolean notFound = true;
+ isOk = interfaces.length > 0;
+ for ( int i = 0; notFound && i < interfaces.length; i++ ) {
+ ret = interfaces[i];
+ isOk = interfaces[i] != Serializable.class &&
+ interfaces[i] != Cloneable.class &&
+ interfaces[i] != Comparable.class;
+ for ( int j = 0; isOk && j < nodes.length; j++ ) {
+ isOk = nodes[j].matchesClass( ret );
+ }
+ notFound = !isOk;
+ }
+ if( notFound ) {
+ ret = null;
+ }
+ }
+
+ // ret now contains a superclass/interface that can be shadowed or null if none
+ return ret;
}
private void readObject(ObjectInputStream stream) throws IOException,
@@ -372,16 +437,15 @@
ShadowProxy proxy = null;
if ( isShadowEnabled() ) {
try {
- if( Collection.class.isAssignableFrom( this.shadowClass ) ||
- Map.class.isAssignableFrom( this.shadowClass ) ) {
+ if ( Collection.class.isAssignableFrom( this.shadowClass ) || Map.class.isAssignableFrom( this.shadowClass ) ) {
// if it is a collection, try to instantiate using constructor
try {
- proxy = (ShadowProxy) this.shadowClass.getConstructor( new Class[] { cls } ).newInstance( new Object[] { fact } );
+ proxy = (ShadowProxy) this.shadowClass.getConstructor( new Class[]{cls} ).newInstance( new Object[]{fact} );
} catch ( Exception e ) {
// not possible to instantiate using constructor
}
}
- if( proxy == null ) {
+ if ( proxy == null ) {
if ( this.instantiator == null ) {
this.setInstantiator();
}
@@ -402,6 +466,7 @@
public void resetCache() {
this.objectTypeNodes = null;
+ defineShadowProxyData( cls );
}
public ObjectTypeNode[] getObjectTypeNodes(final Object object) {
@@ -411,6 +476,20 @@
return this.objectTypeNodes;
}
+ private ObjectTypeNode[] getMatchingObjectTypes(final Class clazz) throws FactException {
+ final List cache = new ArrayList();
+
+ final Iterator it = ruleBase.getRete().getObjectTypeNodes().newIterator();
+ for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
+ final ObjectTypeNode node = (ObjectTypeNode) entry.getValue();
+ if ( node.matchesClass( clazz ) ) {
+ cache.add( node );
+ }
+ }
+
+ return (ObjectTypeNode[]) cache.toArray( new ObjectTypeNode[cache.size()] );
+ }
+
private void buildCache(final Object object) throws FactException {
final List cache = new ArrayList();
Modified: labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/ObjectType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/ObjectType.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/main/java/org/drools/spi/ObjectType.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -31,6 +31,18 @@
extends
Serializable {
/**
+ * Determine if the passed <code>Class</code> matches to the object type
+ * defined by this <code>objectType</code> instance.
+ *
+ * @param clazz
+ * The <code>Class</code> to test.
+ *
+ * @return <code>true</code> if the <code>Class</code> matches this
+ * object type, else <code>false</code>.
+ */
+ boolean matchesClass(Class clazz);
+
+ /**
* Determine if the passed <code>Object</code> belongs to the object type
* defined by this <code>objectType</code> instance.
*
Added: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/CheeseEqual.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/CheeseEqual.java (rev 0)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/CheeseEqual.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -0,0 +1,91 @@
+package org.drools;
+
+import java.io.Serializable;
+
+/*
+ * Copyright 2005 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.
+ */
+
+public class CheeseEqual
+ implements
+ Serializable {
+ /**
+ *
+ */
+ private static final long serialVersionUID = 400L;
+ protected String type;
+ protected int price;
+
+ public CheeseEqual() {
+
+ }
+
+ public CheeseEqual(final String type,
+ final int price) {
+ super();
+ this.type = type;
+ this.price = price;
+ }
+
+ public int getPrice() {
+ return this.price;
+ }
+
+ public String getType() {
+ return this.type;
+ }
+
+ public void setPrice(final int price) {
+ this.price = price;
+ }
+
+ public String toString() {
+ return "CheeseEqual( type='" + this.type + "', price=" + this.price + " )";
+ }
+
+ public boolean equals(final Object object) {
+ if ( this == object ) {
+ return true;
+ }
+
+ if ( (object == null) || (object.getClass() != this.getClass()) ) {
+ return false;
+ }
+
+ final CheeseEqual other = (CheeseEqual) object;
+
+ if ( !this.type.equals( other.type ) ) {
+ return false;
+ }
+
+ if ( this.price != other.price ) {
+ return false;
+ }
+
+ return true;
+ }
+
+ public int hashCode() {
+ //like org.apache.commons.lang.builder.HashCodeBuilder
+ int hashCode = 17;
+ hashCode = hashCode * 37 + this.price;
+ hashCode = hashCode * 37 + (this.type == null ? 0 : this.type.hashCode());
+ return hashCode;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+}
\ No newline at end of file
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-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/base/ShadowProxyFactoryTest.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -10,6 +10,7 @@
import org.drools.Address;
import org.drools.Cheese;
+import org.drools.CheeseEqual;
import org.drools.CheeseInterface;
import org.drools.Person;
@@ -201,9 +202,9 @@
Assert.assertEquals( cheeseHash,
cheeseProxy1.hashCode() );
- // now they are different
- Assert.assertFalse( cheeseProxy1.equals( cheeseProxy2 ) );
- Assert.assertFalse( cheeseProxy2.equals( cheeseProxy1 ) );
+ // they are still identity equals
+ Assert.assertTrue( cheeseProxy1.equals( cheeseProxy2 ) );
+ Assert.assertTrue( cheeseProxy2.equals( cheeseProxy1 ) );
// updating proxy2
((ShadowProxy) cheeseProxy2).updateProxy();
@@ -557,5 +558,98 @@
fail( "Error: " + e.getMessage() );
}
}
-
+
+ public void testProxyForInterface2() {
+ try {
+ // creating original object
+ final String original = "stilton";
+
+ // creating proxy
+ final Class proxy = ShadowProxyFactory.getProxy( Comparable.class );
+ final Comparable comparableProxy = (Comparable) proxy.getConstructor( new Class[]{Comparable.class} ).newInstance( new Object[]{original} );
+
+ // proxy is proxying the values
+ Assert.assertEquals( comparableProxy,
+ original );
+ Assert.assertSame( original,
+ ((ShadowProxy) comparableProxy).getShadowedObject() );
+ Assert.assertEquals( original.hashCode(),
+ comparableProxy.hashCode() );
+
+ } catch ( final Exception e ) {
+ fail( "Error: " + e.getMessage() );
+ }
+ }
+
+ public void testProxyForClassWithEquals() {
+ try {
+ // creating original object
+ final String originalType = "stilton";
+ final int originalPrice = 15;
+ final CheeseEqual cheese = new CheeseEqual( originalType,
+ originalPrice );
+
+ // creating proxy
+ final Class proxy = ShadowProxyFactory.getProxy( CheeseEqual.class );
+ final CheeseEqual cheeseProxy = (CheeseEqual) proxy.getConstructor( new Class[]{CheeseEqual.class} ).newInstance( new Object[]{cheese} );
+
+ // proxy is proxying the values
+ Assert.assertEquals( originalType,
+ cheeseProxy.getType() );
+ Assert.assertEquals( originalPrice,
+ cheeseProxy.getPrice() );
+ Assert.assertSame( cheese,
+ ((ShadowProxy) cheeseProxy).getShadowedObject() );
+
+ // proxy must recongnize the original object on equals()/hashcode() calls
+ //Assert.assertEquals( cheeseProxy.hashCode(), cheese.hashCode() );
+ Assert.assertEquals( cheeseProxy,
+ cheese );
+
+ // changing original values
+ final String actualType = "rotten stilton";
+ final 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() );
+
+ // Another cheese
+ final CheeseEqual cheese2 = new CheeseEqual( "brie",
+ 10 );
+
+ final CheeseEqual cheese2Proxy = (CheeseEqual) proxy.getConstructor( new Class[]{CheeseEqual.class} ).newInstance( new Object[]{cheese2} );
+ assertFalse( cheeseProxy.equals( cheese2Proxy ) );
+ assertFalse( cheese2Proxy.equals( cheeseProxy ) );
+
+ } catch ( final Exception e ) {
+ fail( "Error: " + e.getMessage() );
+ }
+ }
+
}
Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ObjectTypeNodeTest.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ObjectTypeNodeTest.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/reteoo/ObjectTypeNodeTest.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -320,10 +320,6 @@
}
public void testAssertObjectWithShadowEnabled() throws Exception {
- final PropagationContext context = new PropagationContextImpl( 0,
- PropagationContext.ASSERTION,
- null,
- null );
final ReteooRuleBase ruleBase = (ReteooRuleBase) RuleBaseFactory.newRuleBase();
final ReteooWorkingMemory workingMemory = new ReteooWorkingMemory( 1,
@@ -331,7 +327,6 @@
final Rete source = ruleBase.getRete();
- final Class shadowClass = ShadowProxyFactory.getProxy( Cheese.class );
final ObjectTypeNode objectTypeNode = new ObjectTypeNode( 1,
new ClassObjectType( Cheese.class ),
source,
@@ -339,17 +334,13 @@
final MockObjectSink sink = new MockObjectSink();
objectTypeNode.addObjectSink( sink );
+ source.addObjectSink( objectTypeNode );
final Object cheese = new Cheese( "muzzarela",
5 );
final InternalFactHandle handle1 = (InternalFactHandle) workingMemory.insert( cheese );
- // should assert as ObjectType matches
- objectTypeNode.assertObject( handle1,
- context,
- workingMemory );
-
// make sure just string1 was asserted
final List asserted = sink.getAsserted();
assertLength( 1,
Modified: labs/jbossrules/trunk/drools-core/src/test/java/org/drools/spi/MockObjectType.java
===================================================================
--- labs/jbossrules/trunk/drools-core/src/test/java/org/drools/spi/MockObjectType.java 2007-07-18 01:57:17 UTC (rev 13590)
+++ labs/jbossrules/trunk/drools-core/src/test/java/org/drools/spi/MockObjectType.java 2007-07-18 02:15:24 UTC (rev 13591)
@@ -62,6 +62,20 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
/**
+ * Determine if the passed <code>Class</code> matches to the object type
+ * defined by this <code>objectType</code> instance.
+ *
+ * @param clazz
+ * The <code>Class</code> to test.
+ *
+ * @return <code>true</code> if the <code>Class</code> matches this
+ * object type, else <code>false</code>.
+ */
+ public boolean matchesClass(final Class clazz) {
+ return this.matches;
+ }
+
+ /**
* Determine if the passed <code>Object</code> belongs to the object type
* defined by this <code>objectType</code> instance.
*
More information about the jboss-svn-commits
mailing list