Skip to content

Commit

Permalink
[DROOLS-154] Improve the isA trait evaluator to work with literals
Browse files Browse the repository at this point in the history
  • Loading branch information
sotty authored and mariofusco committed Jun 11, 2013
1 parent fbc9b8b commit bccaa92
Show file tree
Hide file tree
Showing 7 changed files with 223 additions and 33 deletions.
Expand Up @@ -146,7 +146,7 @@ public BitSet getBottomTypeCode() {
}

public BitSet getCurrentTypeCode() {
return new BitSet();
return null;
}

public BitSet getTypeCode() {
Expand Down
Expand Up @@ -2703,6 +2703,7 @@ public void testTraitModifyCore() {
"end \n" +
"" +
"rule \"Don\" \n" +
"no-loop\n " +
"when \n" +
" $p : Person( name == \"john\" ) \n" +
"then \n" +
Expand Down Expand Up @@ -2772,11 +2773,11 @@ public void testTraitModifyCore2() {
String s1 = "package test;\n" +
"import org.drools.factmodel.traits.*;\n" +
"" +
"declare trait Student name : String end\n" +
"declare trait Worker name : String end\n" +
"declare trait StudentWorker extends Student, Worker name : String end\n" +
"declare trait Assistant extends Student, Worker name : String end\n" +
"declare Person @Traitable name : String end\n" +
"declare trait Student @propertyReactive name : String end\n" +
"declare trait Worker @propertyReactive name : String end\n" +
"declare trait StudentWorker extends Student, Worker @propertyReactive name : String end\n" +
"declare trait Assistant extends Student, Worker @propertyReactive name : String end\n" +
"declare Person @Traitable @propertyReactive name : String end\n" +
"" +
"rule \"Init\" \n" +
"when \n" +
Expand All @@ -2796,31 +2797,31 @@ public void testTraitModifyCore2() {
"" +
"rule \"Log S\" \n" +
"when \n" +
" $t : Student() \n" +
" $t : Student() @watch( name ) \n" +
"then \n" +
" System.out.println( \"Student >> \" + $t ); \n" +
"end \n" +
"rule \"Log W\" \n" +
"when \n" +
" $t : Worker() \n" +
" $t : Worker() @watch( name ) \n" +
"then \n" +
" System.out.println( \"Worker >> \" + $t ); \n" +
"end \n" +
"rule \"Log SW\" \n" +
"when \n" +
" $t : StudentWorker() \n" +
" $t : StudentWorker() @watch( name ) \n" +
"then \n" +
" System.out.println( \"StudentWorker >> \" + $t ); \n" +
"end \n" +
"rule \"Log RA\" \n" +
"when \n" +
" $t : Assistant() \n" +
" $t : Assistant() @watch( name ) \n" +
"then \n" +
" System.out.println( \"Assistant >> \" + $t ); \n" +
"end \n" +
"rule \"Log Px\" \n" +
"when \n" +
" $p : Person() \n" +
" $p : Person() @watch( name ) \n" +
"then \n" +
" System.out.println( \"Poor Core Person >> \" + $p ); \n" +
"end \n" +
Expand Down Expand Up @@ -3576,4 +3577,65 @@ public void unTraitedBean( TraitFactory.VirtualPropertyMode mode ) {




@Test
public void testIsAOptimization( ) {
String source = "package t.x \n" +
"import java.util.*; \n" +
"import org.drools.factmodel.traits.Thing \n" +
"import org.drools.factmodel.traits.Traitable \n" +
"\n" +
"global java.util.List list; \n" +
"\n" +
"" +
"declare trait A end\n" +
"declare trait B extends A end\n" +
"declare trait C extends B end\n" +
"declare trait D extends A end\n" +
"declare trait E extends C, D end\n" +
"declare trait F extends E end\n" +
"" +
"declare Kore\n" +
" @Traitable\n" +
"end\n" +
"" +
"rule Init when\n" +
"then\n" +
" Kore k = new Kore();\n" +
" don( k, E.class ); \n" +
"end\n" +
"" +
"rule Check_1 when\n" +
" $x : Kore( this isA [ B, D ] ) \n" +
"then \n" +
" list.add( \" B+D \" ); \n" +
"end\n" +
"" +
"rule Check_2 when\n" +
" $x : Kore( this isA [ A ] ) \n" +
"then \n" +
" list.add( \" A \" ); \n" +
"end\n" +

"rule Check_3 when\n" +
" $x : Kore( this not isA [ F ] ) \n" +
"then \n" +
" list.add( \" F \" ); \n" +
"end\n" +
"";


StatefulKnowledgeSession ks = getSessionFromString( source );

List list = new ArrayList();
ks.setGlobal( "list", list );
ks.fireAllRules();

assertEquals( 3, list.size() );

}




}
Expand Up @@ -297,7 +297,21 @@ public void cancelActivation(org.drools.runtime.rule.Activation act) {
leftTuple.getLeftTupleSink().retractLeftTuple( leftTuple, (PropagationContext) act.getPropagationContext(), workingMemory );
}
}


public FactHandle lookupFactHandle(Object object) {
FactHandle handle = null;
if ( identityMap != null ) {
handle = identityMap.get( object );
}

if ( handle != null ) {
return handle;
}

handle = getFactHandleFromWM( object );
return handle;
}

public FactHandle getFactHandle(Object object) {
FactHandle handle = null;
if ( identityMap != null ) {
Expand Down Expand Up @@ -386,12 +400,14 @@ private void updateTraits( Object object, long mask, Thing originator, Class<?>
TraitProxy proxy = (TraitProxy) t;

proxy.setTypeFilter( veto );
InternalFactHandle h = (InternalFactHandle) getFactHandle( t );
((InternalWorkingMemoryEntryPoint) h.getEntryPoint()).update( h,
t,
mask,
modifiedClass,
this.activation );
InternalFactHandle h = (InternalFactHandle) lookupFactHandle( t );
if ( h != null ) {
((InternalWorkingMemoryEntryPoint) h.getEntryPoint()).update( h,
t,
mask,
modifiedClass,
this.activation );
}
proxy.setTypeFilter( null );

BitSet tc = proxy.getTypeCode();
Expand Down Expand Up @@ -646,6 +662,7 @@ protected <T,K> T processTraits( K core,
TraitableBean<K,? extends TraitableBean> inner,
boolean logical ) throws LogicalTypeInconsistencyException {
T thing;
boolean refresh = false;
if ( trait.isAssignableFrom( inner.getClass() ) ) {
thing = (T) inner;
inner.addTrait( trait.getName(), (Thing<K>) core );
Expand All @@ -654,6 +671,7 @@ protected <T,K> T processTraits( K core,
return (T) inner.getTrait( trait.getName() );
} else {
thing = (T) builder.getProxy( inner, trait );
refresh = Thing.class != trait;
}

if ( needsUpdate ) {
Expand All @@ -664,6 +682,24 @@ protected <T,K> T processTraits( K core,
don( inner, Thing.class, logical );
}

if ( refresh ) {
FactHandle handle = lookupFactHandle( inner );
if ( handle != null ) {
update( handle, 0L, core.getClass() );
} else {
handle = this.workingMemory.insert( inner,
null,
false,
false,
this.activation.getRule(),
this.activation );
if ( this.identityMap != null ) {
this.getIdentityMap().put( inner,
handle );
}
}
}

return thing;
}

Expand Down
Expand Up @@ -141,12 +141,15 @@ public void writeExternal(ObjectOutput out) throws IOException {

public static class IsAEvaluator extends BaseEvaluator {

private BitSet cachedLiteral;
private Object cachedValue;

public void setParameterText(String parameterText) {

}

public IsAEvaluator(final ValueType type, final boolean isNegated) {
super(type, isNegated ? NOT_ISA : ISA );
super( type, isNegated ? NOT_ISA : ISA );
}

/**
Expand All @@ -155,27 +158,84 @@ public IsAEvaluator(final ValueType type, final boolean isNegated) {
public boolean evaluate( InternalWorkingMemory workingMemory,
InternalReadAccessor extractor, InternalFactHandle handle, FieldValue value ) {
final Object objectValue = extractor.getValue( workingMemory, handle.getObject() );

Object typeName = value.getValue();
if ( typeName instanceof Class ) {
typeName = ((Class) typeName).getName();
final Object literal = value.getValue();
if ( cachedValue != literal) {
cachedValue = literal;
cacheLiteral( literal, workingMemory );
}

TraitableBean core = null;
TraitableBean core;
if ( objectValue instanceof Thing ) {
Thing thing = (Thing) objectValue;
core = (TraitableBean) thing.getCore();
return this.getOperator().isNegated() ^ core.hasTrait( typeName.toString() );
BitSet code = core.getCurrentTypeCode();
if ( code != null ) {
return this.getOperator().isNegated() ^ isA( code, cachedLiteral );
} else {
return this.getOperator().isNegated() ^ hasTrait( core, literal );
}
} else if ( objectValue instanceof TraitableBean ) {
core = (TraitableBean) objectValue;
return this.getOperator().isNegated() ^ core.hasTrait( typeName.toString() );
BitSet code = core.getCurrentTypeCode();
if ( code != null ) {
return this.getOperator().isNegated() ^ isA( code, cachedLiteral );
} else {
return this.getOperator().isNegated() ^ hasTrait( core, literal );
}
} else {
core = lookForWrapper( objectValue, workingMemory );
return ( core == null && this.getOperator().isNegated() )
|| ( core != null && this.getOperator().isNegated() ^ core.hasTrait( typeName.toString() ) );
if ( core == null ) {
return this.getOperator().isNegated();
}
BitSet code = core.getCurrentTypeCode();
if ( code != null ) {
return this.getOperator().isNegated() ^ isA( code, cachedLiteral );
} else {
return this.getOperator().isNegated() ^ hasTrait( core, literal );
}
}
}

private boolean hasTrait( TraitableBean core, Object value ) {
if ( value instanceof Class ) {
return core.hasTrait( ( (Class) value ).getName() );
} else if ( value instanceof String ) {
return core.hasTrait( (String) value );
} else if ( value instanceof Collection ) {
for ( Object o : (Collection) value ) {
if ( ! hasTrait( core, o ) ) {
return false;
}
}
return true;
}
throw new UnsupportedOperationException( " IsA Operator : Unsupported literal " + value );
}

private void cacheLiteral( Object value, InternalWorkingMemory workingMemory ) {
CodedHierarchy x = ((ReteooRuleBase) workingMemory.getRuleBase()).getConfiguration().getComponentFactory().getTraitRegistry().getHierarchy();
cachedLiteral = getCode( value, x );
}

private BitSet getCode( Object value, CodedHierarchy x ) {
if ( value instanceof Class ) {
String typeName = ((Class) value).getName();
return x.getCode( typeName );
} else if ( value instanceof String ) {
return x.getCode( value );
} else if ( value instanceof Collection ) {
BitSet code = null;
for ( Object o : ( (Collection) value ) ) {
if ( code == null ) {
code = (BitSet) getCode( o, x ).clone();
} else {
code.and( getCode( o, x ) );
}
}
return code;
}
throw new UnsupportedOperationException( " IsA Operator : Unsupported literal " + value );
}


protected TraitableBean lookForWrapper( final Object objectValue, InternalWorkingMemory workingMemory) {
Expand Down Expand Up @@ -269,7 +329,17 @@ private boolean compare( Object source, Object target, InternalWorkingMemory wor
return getOperator().isNegated();
}

return HierarchyEncoderImpl.supersetOrEqualset(sourceTraits, targetTraits) ^ getOperator().isNegated();
return isA(sourceTraits, targetTraits) ^ getOperator().isNegated();
}

private boolean isA( BitSet sourceTraits, BitSet targetTraits ) {
if ( sourceTraits == null ) {
return false;
}
if ( targetTraits == null ) {
return true;
}
return HierarchyEncoderImpl.supersetOrEqualset( sourceTraits, targetTraits );
}

@Override
Expand Down
Expand Up @@ -533,6 +533,16 @@ protected void buildTraitMap(ClassWriter cw, ClassDefinition classDef) {

mv = cw.visitMethod( ACC_PUBLIC, "getCurrentTypeCode", Type.getMethodDescriptor( Type.getType( BitSet.class ), new Type[] { } ) , null, null );
mv.visitCode();
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD,
BuildUtils.getInternalType( classDef.getName() ),
TraitableBean.TRAITSET_FIELD_NAME,
Type.getDescriptor( Map.class ) );
Label l3 = new Label();
mv.visitJumpInsn( IFNONNULL, l3 );
mv.visitInsn( ACONST_NULL );
mv.visitInsn( ARETURN );
mv.visitLabel( l3 );
mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD,
BuildUtils.getInternalType( classDef.getName() ),
Expand Down
Expand Up @@ -317,6 +317,18 @@ public byte[] buildClass( ClassDefinition core ) throws IOException,
{
mv = cw.visitMethod( ACC_PUBLIC, "getCurrentTypeCode", "()" + Type.getDescriptor( BitSet.class ), null, null );
mv.visitCode();

mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD,
BuildUtils.getInternalType( wrapperName ),
TraitableBean.TRAITSET_FIELD_NAME,
Type.getDescriptor( Map.class ) );
Label l3 = new Label();
mv.visitJumpInsn( IFNONNULL, l3 );
mv.visitInsn( ACONST_NULL );
mv.visitInsn( ARETURN );
mv.visitLabel( l3 );

mv.visitVarInsn( ALOAD, 0 );
mv.visitFieldInsn( GETFIELD,
BuildUtils.getInternalType( wrapperName ),
Expand Down

0 comments on commit bccaa92

Please sign in to comment.