Hi drools team,

First of all, drools is a great product and saved us lots of time, effort and 
money. Thanks.

We have a web application in which drools is a key component. I have created a 
pool of WorkingMemories, since given any time, there could be multiple users 
requesting for the rules service. Whenever rules need to be run, a WorkingMemory
is pulled out of the pool used and returned back to the pool. After allocating 
the WorkingMemory, before using it, old facts are cleared. It is done by the 
following method:

public static void clearWorkingMemory(WorkingMemory wMem) {
        List factHandleList;

        factHahdleList=wMem.getFactHandles();
        for(FactHandle fh : factHandleList) {
                wMem.retractObject(fh);
        }
}


Now, when I assert a null fact the above method throws a 
NoSuchFactObjectException. 



Besides, some of my conditions actually check for the fact to be null and act 
appropriately. This is because a fact being null has a meaning by itself. These
conditions are not even evaluated when the fact is asserted as null. Without
understanding this behaviour, I got around it by creating FactWrapper bean.

After pondering little while I realized that when a null fact is asserted into
the working memory, there is no information to ascertain which fact is being
asserted. [when a fact is non-null, by reflection the class and the properties
can be ascertained. This can be compared against parameter declaration]. Which
actually means that asserting a null fact can have no effect on the rule
execution. If that is the case, I feel that it will be better to prevent
asserting null facts. This will save time for so many. Do I have a point here
or am I missing something??



Regarding the NoSuchFactObjectException, I dug into the code and found that
org.drools.reteoo.WorkingMemoryImpl.retractObject calls
WorkingMemoryImpl.getObject(). getObject() when it gets a null from the
PrimitiveLongMap assumes that the object is not found and throws the exception.
This should have been looking for objects.containsKey() and if this returns
false, then throw NoSuchFactObjectException. I checked PrimitiveLongMap and
found that even containsKey does [return get(key)!=null]. This can be fixed by
adding a getInternal() private method like this:

<<<<<PrimitiveLongMap change start>>>>>
Existing code: org.drools.util.PrimitiveLongMap.java
    public Object get(long key)
    {
        if ( key > this.maxKey || key < 0 )
        {
            return null;
        }

        Object value = findPage( key ).get( key );

        // NULL means the key exists, so return a real null
        if ( value == NULL )
        {
            value = null;
        }
        return value;
    }

    public boolean containsKey(long key)
    {
        if ( key < 0 ) return false;

        return get( key ) != null;
    }

Can be changed to:

    public Object get(long key)
    {
        Object value = getInternal(key);

        // NULL means the key exists, so return a real null
        if ( value == NULL )
        {
            value = null;
        }
        return value;
    }

    private Object getInternal(long key)
    {
        if ( key > this.maxKey || key < 0 )
        {
            return null;
        }

        return findPage( key ).get( key );
    }

    public boolean containsKey(long key)
    {
        if ( key < 0 ) return false;

        return getInternal( key ) != null;
    }
<<<<<PrimitiveLongMap change end>>>>>


<<<<<WorkingMemoryImpl change start>>>>>
Existing code: org.drools.reteoo.WorkingMemoryImpl.java
    public Object getObject(FactHandle handle) throws NoSuchFactObjectException
    {
        Object object = this.objects.get( ((FactHandleImpl) handle).getId( ) );

        if ( object == null )
        {
            throw new NoSuchFactObjectException( handle );
        }

        return object;
    }

can be changed to:
    public Object getObject(FactHandle handle) throws NoSuchFactObjectException
    {
        long key = ((FactHandleImpl) handle).getId( );

        if(! objects.containsKey(key))
        {
            throw new NoSuchFactObjectException( handle );
        }

        return this.objects.get(key);
    }
<<<<<WorkingMemoryImpl change end>>>>>



To put it different way, the above fix will prevent NoSuchFactObjectException
being thrown in the code below;

factHandle=wMem.assertObject(someFactObject); // someFactObject is null
wMem.retractObject(factHandle); // will throw NoSuchFactObjectException


Please check if this is making sense...

Thanks again and keep up the great work..
Cheers
prem


Reply via email to