public void retract( final org.drools.FactHandle factHandle, final boolean removeLogical, final boolean updateEqualsMap, final Rule rule, final Activation activation) throws FactException { if (factHandle == null) { throw new IllegalArgumentException("FactHandle cannot be null "); } try { this.ruleBase.readLock(); this.lock.lock(); 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.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 = new PropagationContextImpl( this.wm.getNextPropagationIdCounter(), PropagationContext.RETRACTION, rule, (activation == null) ? null : activation.getTuple(), handle, this.wm.agenda.getActiveActivations(), this.wm.agenda.getDormantActivations(), this.entryPoint); this.entryPointNode.retractObject(handle, propagationContext, typeConf, this.wm); if (typeConf.isTMSEnabled()) { TruthMaintenanceSystem tms = wm.getTruthMaintenanceSystem(); // 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) { tms.removeLogicalDependencies(handle); } key.removeFactHandle(handle); handle.setEqualityKey(null); // If the equality key is now empty, then remove it if (key.isEmpty()) { tms.remove(key); } } propagationContext.evaluateActionQueue(this.wm); this.wm.workingMemoryEventSupport.fireObjectRetracted( propagationContext, handle, object, this.wm); this.objectStore.removeHandle(handle); this.handleFactory.destroyFactHandle(handle); 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.lock.unlock(); this.ruleBase.readUnlock(); } }
public void update( org.drools.FactHandle factHandle, final Object object, final long mask, final Activation activation) throws FactException { try { this.ruleBase.readLock(); this.lock.lock(); this.wm.startOperation(); this.ruleBase.executeQueuedActions(); InternalFactHandle handle = (InternalFactHandle) factHandle; // the handle might have been disconnected, so reconnect if it has if (handle.isDisconnected()) { handle = this.objectStore.reconnect(factHandle); } 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 retract 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; } 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); } if (typeConf.isTMSEnabled()) { // the hashCode and equality has changed, so we must update the // EqualityKey EqualityKey key = handle.getEqualityKey(); key.removeFactHandle(handle); TruthMaintenanceSystem tms = wm.getTruthMaintenanceSystem(); // If the equality key is now empty, then remove it if (key.isEmpty()) { tms.remove(key); } // now use an existing EqualityKey, if it exists, else create a new one key = tms.get(object); if (key == null) { key = new EqualityKey(handle, status); tms.put(key); } else { key.addFactHandle(handle); } handle.setEqualityKey(key); } this.handleFactory.increaseFactHandleRecency(handle); Rule rule = activation == null ? null : activation.getRule(); final PropagationContext propagationContext = new PropagationContextImpl( this.wm.getNextPropagationIdCounter(), PropagationContext.MODIFICATION, rule, (activation == null) ? null : activation.getTuple(), handle, this.wm.agenda.getActiveActivations(), this.wm.agenda.getDormantActivations(), entryPoint, mask); this.entryPointNode.modifyObject(handle, propagationContext, typeConf, this.wm); propagationContext.evaluateActionQueue(this.wm); this.wm.workingMemoryEventSupport.fireObjectUpdated( propagationContext, factHandle, 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.lock.unlock(); this.ruleBase.readUnlock(); } }