Package org.drools.core.common

Source Code of org.drools.core.common.NamedEntryPoint

/*
* Copyright 2010 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.
*/

package org.drools.core.common;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

import org.drools.core.FactException;
import org.drools.core.FactHandle;
import org.drools.core.RuleBase;
import org.drools.core.RuleBaseConfiguration.AssertBehaviour;
import org.drools.core.RuntimeDroolsException;
import org.drools.core.WorkingMemoryEntryPoint;
import org.drools.core.base.ClassObjectType;
import org.drools.core.factmodel.traits.TraitProxy;
import org.drools.core.factmodel.traits.TraitableBean;
import org.drools.core.util.Iterator;
import org.drools.core.util.ObjectHashSet;
import org.drools.core.util.ObjectHashSet.ObjectEntry;
import org.drools.core.impl.StatefulKnowledgeSessionImpl.ObjectStoreWrapper;
import org.drools.core.reteoo.EntryPointNode;
import org.drools.core.reteoo.ObjectTypeConf;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.ObjectTypeNode.ObjectTypeNodeMemory;
import org.drools.core.reteoo.Rete;
import org.drools.core.rule.EntryPointId;
import org.drools.core.rule.Rule;
import org.drools.core.spi.Activation;
import org.drools.core.spi.FactHandleFactory;
import org.drools.core.spi.ObjectType;
import org.drools.core.spi.PropagationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class NamedEntryPoint
    implements
    InternalWorkingMemoryEntryPoint,
    WorkingMemoryEntryPoint,
    PropertyChangeListener  {

    protected static transient Logger log = LoggerFactory.getLogger(NamedEntryPoint.class);

    protected static final Class<?>[] ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES = new Class[]{PropertyChangeListener.class};

    /** The arguments used when adding/removing a property change listener. */
    protected final Object[] addRemovePropertyChangeListenerArgs = new Object[]{this};

    private TruthMaintenanceSystem tms;

    protected ObjectStore objectStore;

    protected transient InternalRuleBase ruleBase;

    protected EntryPointId     entryPoint;
    protected EntryPointNode entryPointNode;

    private ObjectTypeConfigurationRegistry typeConfReg;

    private final AbstractWorkingMemory wm;

    private FactHandleFactory         handleFactory;
    private PropagationContextFactory pctxFactory;

    protected final ReentrantLock lock;

    protected Set<InternalFactHandle> dynamicFacts = null;

    public NamedEntryPoint(EntryPointId entryPoint,
                           EntryPointNode entryPointNode,
                           AbstractWorkingMemory wm) {
        this(entryPoint,
             entryPointNode,
             wm,
             new ReentrantLock());
    }

    public NamedEntryPoint(EntryPointId entryPoint,
                           EntryPointNode entryPointNode,
                           AbstractWorkingMemory wm,
                           ReentrantLock lock) {
        this.entryPoint = entryPoint;
        this.entryPointNode = entryPointNode;
        this.wm = wm;
        this.ruleBase = (InternalRuleBase) this.wm.getRuleBase();
        this.lock = lock;
        this.typeConfReg = new ObjectTypeConfigurationRegistry(this.ruleBase);
        this.handleFactory = this.wm.getFactHandleFactory();
        this.pctxFactory = ruleBase.getConfiguration().getComponentFactory().getPropagationContextFactory();
        this.objectStore = new SingleThreadedObjectStore(this.ruleBase.getConfiguration(),
                                                         this.lock);
    }

    public void reset() {
        this.objectStore.clear();
    }

    public ObjectStore getObjectStore() {
        return this.objectStore;
    }

    public EntryPointNode getEntryPointNode() {
        return this.entryPointNode;
    }


    /**
     * @see org.drools.core.WorkingMemory
     */
    public FactHandle insert(final Object object) throws FactException {
        return insert(object, /* Not-Dynamic */
                      null,
                      false,
                      false,
                      null,
                      null);
    }

    public FactHandle insert(final Object object,
                             final boolean dynamic) throws FactException {
        return insert(object,
                      null,
                      dynamic,
                      false,
                      null,
                      null);
    }

    protected FactHandle insert(final Object object,
                                final Object tmsValue,
                                final boolean dynamic,
                                boolean logical,
                                final Rule rule,
                                final Activation activation) throws FactException {
        if ( object == null ) {
            // you cannot assert a null object
            return null;
        }

        try {
            this.wm.startOperation();

            ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
                                                                          object );
            if ( logical && !typeConf.isTMSEnabled()) {
                enableTMS(object, typeConf);
            }

            InternalFactHandle handle = null;
            final PropagationContext propagationContext = this.pctxFactory.createPropagationContext(this.wm.getNextPropagationIdCounter(), PropagationContext.INSERTION, rule,
                                                                                                    (activation == null) ? null : activation.getTuple(), handle, entryPoint);

            if ( this.wm.isSequential() ) {
                handle = createHandle( object,
                                       typeConf );
                propagationContext.setFactHandle(handle);
                insert( handle,
                        object,
                        rule,
                        activation,
                        typeConf,
                        propagationContext );
                return handle;
            }

           
            try {
                this.lock.lock();
                this.ruleBase.readLock();
                // check if the object already exists in the WM
                handle = this.objectStore.getHandleForObject( object );

                if ( typeConf.isTMSEnabled() ) {
                    TruthMaintenanceSystem tms = getTruthMaintenanceSystem();
                   
                    if ( handle != null ) {
                        propagationContext.setFactHandle(handle);
                        insertWhenHandleExists( object, tmsValue, logical, rule, activation, typeConf, handle, tms, propagationContext );
                        return handle;
                    }

                    // get the key for other "equal" objects, returns null if none exist
                    EqualityKey key = tms.get( object );
                   
                    if ( logical ) { 
                        if ( key != null && key.getStatus() == EqualityKey.STATED ) {
                            // You cannot logically insert a previously stated equality equal object, so return null                           
                            return null;
                        }
                       

                       
                        if ( key == null ) {
                            handle = createHandle( object,
                                                   typeConf ); // we know the handle is null
                           
                            key = new EqualityKey( handle );
                            handle.setEqualityKey( key );
                            tms.put( key );                          
                            key.setStatus( EqualityKey.JUSTIFIED ); // new Key, so we know it's JUSTIFIED                
                        } else {
                            handle = key.getFactHandle();
                        }
                       
                       // Any logical propagations are handled via the TMS.addLogicalDependency
                       tms.addLogicalDependency( handle,
                                                 object,
                                                 tmsValue,
                                                 activation,
                                                 activation.getPropagationContext(),
                                                 rule,
                                                 typeConf );
                       
                        return key.getFactHandle();
                                                   
                    } else { // !logical                    
                        if ( key == null ) {
                            handle = createHandle( object,
                                                   typeConf ); // we know the handle is null                           
                            key = new EqualityKey( handle );                       
                            handle.setEqualityKey( key );                           
                            tms.put( key );                 
                        } else if ( key.getStatus() == EqualityKey.JUSTIFIED ) {
                                // Its previous justified, so switch to stated
                                key.setStatus( EqualityKey.STATED ); // must be done before the justifiedHandle retract 
                               
                                // remove logical dependencies
                                final InternalFactHandle justifiedHandle = key.getFactHandle();
                                propagationContext.setFactHandle( justifiedHandle ); // necessary to stop recursive retractions
                                TruthMaintenanceSystemHelper.clearLogicalDependencies( justifiedHandle, propagationContext );
                               
                                // now update existing handle to new value
                                return update( justifiedHandle, true, object, Long.MAX_VALUE, Object.class, activation );
                        } else   // STATED
                            handle = createHandle( object,
                                                   typeConf ); // we know the handle is null                                                   
                            handle.setEqualityKey( key );                                                   
                            key.addFactHandle( handle );
                        }
                        key.setStatus( EqualityKey.STATED ); // KEY is always stated
                    }                   
                } else {
                    // TMS not enabled for this object type
                    if ( handle != null ) {
                        return handle;
                    }
                    handle = createHandle( object,
                                           typeConf );
                }
                propagationContext.setFactHandle(handle);

                // if the dynamic parameter is true or if the user declared the fact type with the meta tag:
                // @propertyChangeSupport
                if ( dynamic || typeConf.isDynamic() ) {
                    addPropertyChangeListener( handle, dynamic );
                }

                insert( handle,
                        object,
                        rule,
                        activation,
                        typeConf,
                        propagationContext );

            } finally {
                this.ruleBase.readUnlock();
                this.lock.unlock();
            }
            return handle;
        } finally {
            this.wm.endOperation();
        }

    }

    private void insertWhenHandleExists(final Object object,
                                              final Object tmsValue,
                                              boolean logical,
                                              final Rule rule,
                                              final Activation activation,
                                              ObjectTypeConf typeConf,
                                              InternalFactHandle handle,
                                              TruthMaintenanceSystem tms,
                                              final PropagationContext propagationContext ) {
        // Object is already asserted, so check and possibly correct its
        // status and then return the handle
        EqualityKey key = handle.getEqualityKey();

        if ( key == null ) {
            // Edge case: another object X, equivalent (equals+hashcode) to "object" Y
            // has been previously stated. However, if X is a subclass of Y, TMS
            // may have not been enabled yet, and key would be null.
            ObjectTypeConf typeC = this.typeConfReg.getObjectTypeConf( this.entryPoint, handle.getObject() );
            enableTMS( handle.getObject(), typeC );
            key = handle.getEqualityKey();
        }

        if ( key.getStatus() == EqualityKey.STATED ) {
            // return null as you cannot justify a stated object.
            return;
        }

        if ( !logical ) {
            // this object was previously justified, so we have to override it to stated
            key.setStatus( EqualityKey.STATED );
            TruthMaintenanceSystemHelper.removeLogicalDependencies( handle, propagationContext );
        } else {                                       
            // this was object is already justified, so just add new logical dependency
            tms.addLogicalDependency( handle,
                                      object,
                                      tmsValue,
                                      activation,
                                      activation.getPropagationContext(),
                                      rule,
                                      typeConf );
        }
    }

    public void insert(final InternalFactHandle handle,
                       final Object object,
                       final Rule rule,
                       final Activation activation,
                       ObjectTypeConf typeConf,
                       PropagationContext pctx) {
        this.ruleBase.executeQueuedActions();

        this.wm.executeQueuedActions();

        if ( activation != null ) {
            // release resources so that they can be GC'ed
            activation.getPropagationContext().releaseResources();
        }
        PropagationContext propagationContext = pctx;
        if ( pctx == null ) {
            propagationContext = pctxFactory.createPropagationContext(this.wm.getNextPropagationIdCounter(), PropagationContext.INSERTION,
                                                                      rule, (activation == null) ? null : activation.getTuple(), handle, entryPoint);
        }

        this.entryPointNode.assertObject( handle,
                                          propagationContext,
                                          typeConf,
                                          this.wm );
       
        propagationContext.evaluateActionQueue( this.wm );

        this.wm.workingMemoryEventSupport.fireObjectInserted( propagationContext,
                                                              handle,
                                                              object,
                                                              this.wm );
       
        this.wm.executeQueuedActions();       
       
        if ( rule == null ) {
            // This is not needed for internal WM actions as the firing rule will unstage
            this.wm.getAgenda().unstageActivations();
        }       
    }

    public void update(final org.kie.api.runtime.rule.FactHandle factHandle,
                       final Object object) throws FactException {
        InternalFactHandle handle = (InternalFactHandle) factHandle;
        update( handle,
                false,
                object,
                Long.MAX_VALUE,
                Object.class,
                null );
    }
   
    public void update(final org.kie.api.runtime.rule.FactHandle factHandle,
                       final Object object,
                       final long mask,
                       final Class<?> modifiedClass,
                       final Activation activation) throws FactException {
        InternalFactHandle handle = (InternalFactHandle) factHandle;
        update( handle,
                false,
                object,
                mask,
                modifiedClass,
                activation );
    }

    public InternalFactHandle update(InternalFactHandle handle,
                                     final boolean updateLogical,
                                     final Object object,
                                     final long mask,
                                     final Class<?> modifiedClass,
                                     final Activation activation) throws FactException {
        try {
            this.lock.lock();
            this.ruleBase.readLock();
            this.wm.startOperation();
            this.ruleBase.executeQueuedActions();


            // the handle might have been disconnected, so reconnect if it has
            if ( handle.isDisconnected() ) {
                handle = this.objectStore.reconnect( handle );
            }

            final Object originalObject = handle.getObject();
           
            if ( handle.getEntryPoint() != this ) {
                throw new IllegalArgumentException( "Invalid Entry Point. You updated the FactHandle on entry point '" + handle.getEntryPoint().getEntryPointId() + "' instead of '" + getEntryPointId() + "'" );
            }
           
            final ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
                                                                                object );

            // only needed if we maintain tms, but either way we must get it before we do the update
            int status = -1;
            if ( typeConf.isTMSEnabled() ) {
                status = handle.getEqualityKey().getStatus();
            }


            if ( handle.getId() == -1 || object == null || (handle.isEvent() && ((EventFactHandle) handle).isExpired()) ) {
                // the handle is invalid, most likely already retracted, so return and we cannot assert a null object
                return handle;
            }

            if ( activation != null ) {
                // release resources so that they can be GC'ed
                activation.getPropagationContext().releaseResources();
            }

            if ( originalObject != object || !AssertBehaviour.IDENTITY.equals( this.ruleBase.getConfiguration().getAssertBehaviour() ) ) {
                this.objectStore.removeHandle( handle );

                // set anyway, so that it updates the hashCodes
                handle.setObject( object );
                this.objectStore.addHandle( handle,
                                            object );
            }

            this.handleFactory.increaseFactHandleRecency( handle );
            Rule rule = activation == null ? null : activation.getRule();

            final PropagationContext propagationContext = pctxFactory.createPropagationContext(this.wm.getNextPropagationIdCounter(), PropagationContext.MODIFICATION,
                                                                                               rule, (activation == null) ? null : activation.getTuple(),
                                                                                               handle, entryPoint, mask, modifiedClass, null);
           
            if ( typeConf.isTMSEnabled() ) {
                EqualityKey newKey = tms.get( object );
                EqualityKey oldKey = handle.getEqualityKey();
                if ( newKey == null ) {                   
                    if ( oldKey.getStatus() == EqualityKey.JUSTIFIED ) {
                        // new target key is JUSTFIED, updates are always STATED
                        TruthMaintenanceSystemHelper.removeLogicalDependencies( oldKey.getFactHandle(), propagationContext );
                    }
                   
                    oldKey.removeFactHandle( handle );
                    // If the equality key is now empty, then remove it
                    if ( oldKey.isEmpty() ) {
                        getTruthMaintenanceSystem().remove( oldKey );
                    }                   
                   
                    newKey = new EqualityKey( handle,
                                              EqualityKey.STATED ); // updates are always stated
                    handle.setEqualityKey( newKey );
                    getTruthMaintenanceSystem().put( newKey );
                } else if ( newKey != oldKey ) {
                    oldKey.removeFactHandle( handle );
                    // If the equality key is now empty, then remove it
                    if ( oldKey.isEmpty() ) {
                        getTruthMaintenanceSystem().remove( oldKey );
                   
                   
                    if ( newKey.getStatus() == EqualityKey.JUSTIFIED ) {
                        // new target key is JUSTITIED, updates are always STATED
                        TruthMaintenanceSystemHelper.removeLogicalDependencies( newKey.getFactHandle(), propagationContext );
                        newKey.setStatus( EqualityKey.STATED );
                    }
                    // the caller needs the new handle
                    handle = newKey.getFactHandle();
                } else if ( !updateLogical &&  oldKey.getStatus() == EqualityKey.JUSTIFIED  ) {
                    // new target key is JUSTIFIED, updates are always STATED
                    TruthMaintenanceSystemHelper.removeLogicalDependencies( oldKey.getFactHandle(), propagationContext );                    
                }
            }

            this.entryPointNode.modifyObject( handle,
                                              propagationContext,
                                              typeConf,
                                              this.wm );
           
            propagationContext.evaluateActionQueue( this.wm );

            this.wm.workingMemoryEventSupport.fireObjectUpdated( propagationContext,
                                                                 handle,
                                                                 originalObject,
                                                                 object,
                                                                 this.wm );

           this.wm.executeQueuedActions();
          
           if ( rule == null ) {
               // This is not needed for internal WM actions as the firing rule will unstage
               this.wm.getAgenda().unstageActivations();
           }          
        } finally {
            this.wm.endOperation();
            this.ruleBase.readUnlock();
            this.lock.unlock();
        }
        return handle;
    }

    public void retract(final org.kie.api.runtime.rule.FactHandle handle) throws FactException {
        delete( (FactHandle) handle,
                 null,
                 null );
    }

    public void delete(final org.kie.api.runtime.rule.FactHandle handle) throws FactException {
        delete( (FactHandle) handle,
                 null,
                 null );
    }

    public void delete(final FactHandle factHandle,
                       final Rule rule,
                       final Activation activation) throws FactException {
        if ( factHandle == null ) {
            throw new IllegalArgumentException( "FactHandle cannot be null " );
        }
        try {
            this.lock.lock();
            this.ruleBase.readLock();
            this.wm.startOperation();
            this.ruleBase.executeQueuedActions();

            InternalFactHandle handle = (InternalFactHandle) factHandle;
            if ( handle.getId() == -1 ) {
                // can't retract an already retracted handle
                return;
            }

            // the handle might have been disconnected, so reconnect if it has
            if ( handle.isDisconnected() ) {
                handle = this.objectStore.reconnect( handle );
            }

            if ( handle.isTraitable() ) {
                TraitableBean traitableBean = (TraitableBean) handle.getObject();
                if( traitableBean.hasTraits() ){
                    PriorityQueue<TraitProxy> removedTypes =
                            new PriorityQueue<TraitProxy>( traitableBean._getTraitMap().values().size() );
                    removedTypes.addAll( traitableBean._getTraitMap().values() );

                    while ( ! removedTypes.isEmpty() ) {
                        TraitProxy proxy = removedTypes.poll();
                        if ( ! proxy.isVirtual() ) {
                            delete( getFactHandle( proxy ),
                                    rule,
                                    activation );
                        }
                    }
                }
            }

            if ( handle.getEntryPoint() != this ) {
                throw new IllegalArgumentException( "Invalid Entry Point. You updated the FactHandle on entry point '" + handle.getEntryPoint().getEntryPointId() + "' instead of '" + getEntryPointId() + "'" );
            }           

            final Object object = handle.getObject();
           
            final ObjectTypeConf typeConf = this.typeConfReg.getObjectTypeConf( this.entryPoint,
                                                                                object );

            if( typeConf.isSupportsPropertyChangeListeners() ) {
                removePropertyChangeListener( handle, true );
            }         
           
            if ( activation != null ) {
                // release resources so that they can be GC'ed
                activation.getPropagationContext().releaseResources();
            }
            final PropagationContext propagationContext = pctxFactory.createPropagationContext(this.wm.getNextPropagationIdCounter(), PropagationContext.DELETION,
                                                                                               rule, (activation == null) ? null : activation.getTuple(),
                                                                                               handle, this.entryPoint);

            this.entryPointNode.retractObject( handle,
                                               propagationContext,
                                               typeConf,
                                               this.wm );

            if ( typeConf.isTMSEnabled() ) {
                TruthMaintenanceSystem tms = getTruthMaintenanceSystem();

                // TMS.removeLogicalDependency also cleans up Handles from the EqualityKey
                // This can happen on the logical retraction of the last FH, where it's cleaned up in the TMS and also in the main network.
                // However when the user retracts the FH to a logical set of insertions, then we need to clean up the TMS here.
                                                  
                // Update the equality key, which maintains a list of stated FactHandles
                final EqualityKey key = handle.getEqualityKey();

                // Its justified so attempt to remove any logical dependencies for the handle
                if ( key.getStatus() == EqualityKey.JUSTIFIED ) {
                    TruthMaintenanceSystemHelper.removeLogicalDependencies( handle, propagationContext );
                }
                key.removeFactHandle( handle );
                handle.setEqualityKey( null );
               
                // If the equality key is now empty, then remove it
                if ( key.isEmpty() ) {
                    tms.remove( key );
                }
            }

            if ( handle.isTraiting() && handle.getObject() instanceof TraitProxy ) {
                (( (TraitProxy) handle.getObject() ).getObject()).removeTrait( ( (TraitProxy) handle.getObject() ).getTypeCode() );
            }

            propagationContext.evaluateActionQueue( this.wm );
           

            this.wm.workingMemoryEventSupport.fireObjectRetracted( propagationContext,
                                                                   handle,
                                                                   object,
                                                                   this.wm );

            this.wm.executeQueuedActions();
           
            this.objectStore.removeHandle( handle );
            this.handleFactory.destroyFactHandle( handle );           
           
            if ( rule == null ) {
                // This is not needed for internal WM actions as the firing rule will unstage
                this.wm.getAgenda().unstageActivations();
            }           
        } finally {
            this.wm.endOperation();
            this.ruleBase.readUnlock();
            this.lock.unlock();
        }
    }
   
    protected void addPropertyChangeListener(final InternalFactHandle handle, final boolean dynamicFlag ) {
        Object object = handle.getObject();
        try {
            final Method method = object.getClass().getMethod( "addPropertyChangeListener",
                                                               NamedEntryPoint.ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES );

            method.invoke( object,
                           this.addRemovePropertyChangeListenerArgs );
           
            if( dynamicFlag ) {
                if( dynamicFacts == null ) {
                    dynamicFacts = new HashSet<InternalFactHandle>();
                }
                dynamicFacts.add( handle );
            }
        } catch ( final NoSuchMethodException e ) {
            log.error( "Warning: Method addPropertyChangeListener not found" + " on the class " + object.getClass() + " so Drools will be unable to process JavaBean" + " PropertyChangeEvents on the asserted Object" );
        } catch ( final IllegalArgumentException e ) {
            log.error( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass() + " does not take" + " a simple PropertyChangeListener argument" + " so Drools will be unable to process JavaBean"
                                + " PropertyChangeEvents on the asserted Object" );
        } catch ( final IllegalAccessException e ) {
            log.error( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass() + " is not public" + " so Drools will be unable to process JavaBean" + " PropertyChangeEvents on the asserted Object" );
        } catch ( final InvocationTargetException e ) {
            log.error( "Warning: The addPropertyChangeListener method" + " on the class " + object.getClass() + " threw an InvocationTargetException" + " so Drools will be unable to process JavaBean"
                                + " PropertyChangeEvents on the asserted Object: " + e.getMessage() );
        } catch ( final SecurityException e ) {
            log.error( "Warning: The SecurityManager controlling the class " + object.getClass() + " did not allow the lookup of a" + " addPropertyChangeListener method" + " so Drools will be unable to process JavaBean"
                                + " PropertyChangeEvents on the asserted Object: " + e.getMessage() );
        }
    }

    protected void removePropertyChangeListener(final FactHandle handle, final boolean removeFromSet ) {
        Object object = null;
        try {
            object = ((InternalFactHandle) handle).getObject();
           
            if ( dynamicFacts != null && removeFromSet ) {
                dynamicFacts.remove( object );
            }

            if ( object != null ) {
                final Method mehod = object.getClass().getMethod( "removePropertyChangeListener",
                                                                  NamedEntryPoint.ADD_REMOVE_PROPERTY_CHANGE_LISTENER_ARG_TYPES );

                mehod.invoke( object,
                              this.addRemovePropertyChangeListenerArgs );
            }
        } catch ( final NoSuchMethodException e ) {
            // The removePropertyChangeListener method on the class
            // was not found so Drools will be unable to
            // stop processing JavaBean PropertyChangeEvents
            // on the retracted Object
        } catch ( final IllegalArgumentException e ) {
            throw new RuntimeDroolsException( "Warning: The removePropertyChangeListener method on the class " + object.getClass() + " does not take a simple PropertyChangeListener argument so Drools will be unable to stop processing JavaBean"
                                              + " PropertyChangeEvents on the retracted Object" );
        } catch ( final IllegalAccessException e ) {
            throw new RuntimeDroolsException( "Warning: The removePropertyChangeListener method on the class " + object.getClass() + " is not public so Drools will be unable to stop processing JavaBean PropertyChangeEvents on the retracted Object" );
        } catch ( final InvocationTargetException e ) {
            throw new RuntimeDroolsException( "Warning: The removePropertyChangeL istener method on the class " + object.getClass() + " threw an InvocationTargetException so Drools will be unable to stop processing JavaBean"
                                              + " PropertyChangeEvents on the retracted Object: " + e.getMessage() );
        } catch ( final SecurityException e ) {
            throw new RuntimeDroolsException( "Warning: The SecurityManager controlling the class " + object.getClass() + " did not allow the lookup of a removePropertyChangeListener method so Drools will be unable to stop processing JavaBean"
                                              + " PropertyChangeEvents on the retracted Object: " + e.getMessage() );
        }
    }

    public WorkingMemoryEntryPoint getWorkingMemoryEntryPoint(String name) {
        return this.wm.getWorkingMemoryEntryPoint( name );
    }

    public ObjectTypeConfigurationRegistry getObjectTypeConfigurationRegistry() {
        return this.typeConfReg;
    }

    public RuleBase getRuleBase() {
        return this.ruleBase;
    }

    public FactHandle getFactHandle(Object object) {
        return this.objectStore.getHandleForObject( object );
    }

    public EntryPointId getEntryPoint() {
        return this.entryPoint;
    }

    public InternalWorkingMemory getInternalWorkingMemory() {
        return this.wm;
    }

    public FactHandle getFactHandleByIdentity(final Object object) {
        return this.objectStore.getHandleForObjectIdentity( object );
    }

    public Object getObject(org.kie.api.runtime.rule.FactHandle factHandle) {
        return this.objectStore.getObjectForHandle(factHandle);
    }

    @SuppressWarnings("unchecked")
    public <T extends org.kie.api.runtime.rule.FactHandle> Collection<T> getFactHandles() {
        return new ObjectStoreWrapper( this.objectStore,
                                       null,
                                       ObjectStoreWrapper.FACT_HANDLE );
    }

    @SuppressWarnings("unchecked")
    public <T extends org.kie.api.runtime.rule.FactHandle> Collection<T> getFactHandles(org.kie.api.runtime.ObjectFilter filter) {
        return new ObjectStoreWrapper( this.objectStore,
                                       filter,
                                       ObjectStoreWrapper.FACT_HANDLE );
    }

    @SuppressWarnings("unchecked")
    public Collection<? extends Object> getObjects() {
        return new ObjectStoreWrapper( this.objectStore,
                                       null,
                                       ObjectStoreWrapper.OBJECT );
    }

    @SuppressWarnings("unchecked")
    public Collection<? extends Object> getObjects(org.kie.api.runtime.ObjectFilter filter) {
        return new ObjectStoreWrapper( this.objectStore,
                                       filter,
                                       ObjectStoreWrapper.OBJECT );
    }

    public String getEntryPointId() {
        return this.entryPoint.getEntryPointId();
    }

    public long getFactCount() {
        return this.objectStore.size();
    }
   
    private InternalFactHandle createHandle(final Object object,
                                            ObjectTypeConf typeConf) {
        InternalFactHandle handle;
        handle = this.handleFactory.newFactHandle( object,
                                                   typeConf,
                                                   this.wm,
                                                   this );
        this.objectStore.addHandle( handle,
                                    object );
        return handle;
    }   
   
    /**
     * TMS will be automatically enabled when the first logical insert happens.
     *
     * We will take all the already asserted objects of the same type and initialize
     * the equality map.
     * 
     * @param object the logically inserted object.
     * @param conf the type's configuration.
     */
    private void enableTMS(Object object, ObjectTypeConf conf) {
        final Rete source = this.ruleBase.getRete();
        final ClassObjectType cot = new ClassObjectType( object.getClass() );
        final Map<ObjectType, ObjectTypeNode> map = source.getObjectTypeNodes( EntryPointId.DEFAULT );
        final ObjectTypeNode node = map.get( cot );
        final ObjectHashSet memory = ((ObjectTypeNodeMemory) this.wm.getNodeMemory( node )).memory;
     
        // All objects of this type that are already there were certainly stated,
        // since this method call happens at the first logical insert, for any given type.
        org.drools.core.util.Iterator it = memory.iterator();

        for ( Object obj = it.next(); obj != null; obj = it.next() ) {
         
            org.drools.core.util.ObjectHashSet.ObjectEntry holder = (org.drools.core.util.ObjectHashSet.ObjectEntry) obj;
   
            InternalFactHandle handle = (InternalFactHandle) holder.getValue();
           
            if ( handle != null ) {
                EqualityKey key = new EqualityKey( handle );
                handle.setEqualityKey( key );
                key.setStatus(EqualityKey.STATED);
                getTruthMaintenanceSystem().put(key);
            }
        }
     
        // Enable TMS for this type.
        conf.enableTMS();
     
    }
   
    public void propertyChange(final PropertyChangeEvent event) {
        final Object object = event.getSource();

        try {
            FactHandle handle = getFactHandle( object );
            if ( handle == null ) {
                throw new FactException( "Update error: handle not found for object: " + object + ". Is it in the working memory?" );
            }
            update( handle,
                    object );
        } catch ( final FactException e ) {
            throw new RuntimeDroolsException( e.getMessage() );
        }
    }

    public void dispose() {
        if( dynamicFacts != null ) {
            // first we check for facts that were inserted into the working memory
            // using the old API and setting a per instance dynamic flag and remove the
            // session from the listeners list in the bean
            for( InternalFactHandle handle : dynamicFacts ) {
                removePropertyChangeListener( handle, false );
            }
            dynamicFacts = null;
        }
        for( ObjectTypeConf conf : this.typeConfReg.values() ) {
            // then, we check if any of the object types were configured using the
            // @propertyChangeSupport annotation, and clean them up
            if( conf.isDynamic() && conf.isSupportsPropertyChangeListeners() ) {
                // it is enough to iterate the facts on the concrete object type nodes
                // only, as the facts will always be in their concrete object type nodes
                // even if they were also asserted into higher level OTNs as well
                ObjectTypeNode otn = conf.getConcreteObjectTypeNode();
                final ObjectHashSet memory = ((ObjectTypeNodeMemory) this.getInternalWorkingMemory().getNodeMemory( otn )).memory;
                Iterator it = memory.iterator();
                for ( ObjectEntry entry = (ObjectEntry) it.next(); entry != null; entry = (ObjectEntry) it.next() ) {
                    InternalFactHandle handle = (InternalFactHandle) entry.getValue();
                    removePropertyChangeListener( handle, false );
                }
            }
        }
    }

    public void enQueueWorkingMemoryAction(WorkingMemoryAction action) {
        wm.queueWorkingMemoryAction( action );
   

    public TruthMaintenanceSystem getTruthMaintenanceSystem() {
        if (tms == null) {
            tms = new TruthMaintenanceSystem(wm, this);
        }
        return tms;
    }
}
TOP

Related Classes of org.drools.core.common.NamedEntryPoint

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.