All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.drools.reteoo.common.ReteWorkingMemory Maven / Gradle / Ivy

/*
 * Copyright 2015 Red Hat, Inc. and/or its affiliates.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * 
 *      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.reteoo.common;

import org.drools.core.SessionConfiguration;
import org.drools.core.WorkingMemoryEntryPoint;
import org.drools.core.base.DroolsQuery;
import org.drools.core.common.BaseNode;
import org.drools.core.common.InternalAgenda;
import org.drools.core.common.InternalFactHandle;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.WorkingMemoryAction;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.event.AgendaEventSupport;
import org.drools.core.event.RuleEventListenerSupport;
import org.drools.core.event.RuleRuntimeEventSupport;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.StatefulKnowledgeSessionImpl;
import org.drools.core.phreak.PropagationEntry;
import org.drools.core.reteoo.LIANodePropagation;
import org.drools.core.spi.Activation;
import org.drools.core.spi.FactHandleFactory;
import org.drools.core.spi.PropagationContext;
import org.drools.core.util.bitmask.BitMask;
import org.kie.api.runtime.Environment;
import org.kie.api.runtime.rule.AgendaFilter;
import org.kie.api.runtime.rule.FactHandle;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

public class ReteWorkingMemory extends StatefulKnowledgeSessionImpl {

    private List liaPropagations;

    private Queue actionQueue = new ConcurrentLinkedQueue();

    private AtomicBoolean evaluatingActionQueue = new AtomicBoolean(false);

    /** Flag to determine if a rule is currently being fired. */
    private volatile AtomicBoolean firing = new AtomicBoolean(false);

    public ReteWorkingMemory() {
    }

    public ReteWorkingMemory(long id, InternalKnowledgeBase kBase) {
        super(id, kBase);
    }

    public ReteWorkingMemory(long id, InternalKnowledgeBase kBase, boolean initInitFactHandle, SessionConfiguration config, Environment environment) {
        super(id, kBase, initInitFactHandle, config, environment);
    }

    public ReteWorkingMemory(long id, InternalKnowledgeBase kBase, FactHandleFactory handleFactory, long propagationContext, SessionConfiguration config, InternalAgenda agenda, Environment environment) {
        super(id, kBase, handleFactory, propagationContext, config, agenda, environment);
    }

    public ReteWorkingMemory(long id, InternalKnowledgeBase kBase, FactHandleFactory handleFactory, InternalFactHandle initialFactHandle, long propagationContext, SessionConfiguration config, Environment environment, RuleRuntimeEventSupport workingMemoryEventSupport, AgendaEventSupport agendaEventSupport, RuleEventListenerSupport ruleEventListenerSupport, InternalAgenda agenda) {
        super(id, kBase, handleFactory, false, propagationContext, config, environment, workingMemoryEventSupport, agendaEventSupport, ruleEventListenerSupport, agenda);
    }

    @Override
    public void reset() {
        super.reset();
        actionQueue.clear();
    }

    @Override
    public void reset(int handleId,
                      long handleCounter,
                      long propagationCounter) {
        super.reset(handleId, handleCounter, propagationCounter );
        if (liaPropagations != null) liaPropagations.clear();
        actionQueue.clear();
    }

    @Override
    public WorkingMemoryEntryPoint getWorkingMemoryEntryPoint(String name) {
        WorkingMemoryEntryPoint ep = this.entryPoints.get(name);
        return ep != null ? new ReteWorkingMemoryEntryPoint( this, ep ) : null;
    }

    public void addLIANodePropagation(LIANodePropagation liaNodePropagation) {
        if (liaPropagations == null) liaPropagations = new ArrayList();
        liaPropagations.add( liaNodePropagation );
    }

    private final Object syncLock = new Object();
    public void initInitialFact() {
        if ( initialFactHandle == null ) {
            synchronized ( syncLock ) {
                if ( initialFactHandle == null ) {
                    // double check, inside of sync point incase some other thread beat us to it.
                    initInitialFact(kBase, null);
                }
            }
        }
    }

    @Override
    public void fireUntilHalt(final AgendaFilter agendaFilter) {
        initInitialFact();
        super.fireUntilHalt( agendaFilter );
    }

    @Override
    public int fireAllRules(final AgendaFilter agendaFilter,
                            int fireLimit) {
        checkAlive();
        if ( this.firing.compareAndSet( false,
                                        true ) ) {
            initInitialFact();

            try {
                startOperation();

                return internalFireAllRules(agendaFilter, fireLimit);
            } finally {
                endOperation();
                this.firing.set( false );
            }
        }
        return 0;
    }

    private int internalFireAllRules(AgendaFilter agendaFilter, int fireLimit) {
        int fireCount = 0;
        try {
            kBase.readLock();

            // If we're already firing a rule, then it'll pick up the firing for any other assertObject(..) that get
            // nested inside, avoiding concurrent-modification exceptions, depending on code paths of the actions.
            if ( liaPropagations != null && isSequential() ) {
                for ( LIANodePropagation liaPropagation : liaPropagations ) {
                    ( liaPropagation ).doPropagation( this );
                }
            }

            // do we need to call this in advance?
            executeQueuedActionsForRete();

            fireCount = this.agenda.fireAllRules( agendaFilter,
                                                  fireLimit );
        } finally {
            kBase.readUnlock();
            if (kBase.flushModifications()) {
                fireCount += internalFireAllRules(agendaFilter, fireLimit);
            }
        }
        return fireCount;
    }

    @Override
    public void closeLiveQuery(final InternalFactHandle factHandle) {

        try {
            startOperation();
            this.kBase.readLock();
            this.lock.lock();

            final PropagationContext pCtx = pctxFactory.createPropagationContext(getNextPropagationIdCounter(), PropagationContext.Type.INSERTION,
                                                                                 null, null, factHandle, getEntryPoint());

            getEntryPointNode().retractQuery( factHandle,
                                              pCtx,
                                              this );

            pCtx.evaluateActionQueue(this);

            getFactHandleFactory().destroyFactHandle( factHandle );

        } finally {
            this.lock.unlock();
            this.kBase.readUnlock();
            endOperation();
        }
    }

    @Override
    protected BaseNode[] evalQuery(final String queryName, final DroolsQuery queryObject, final InternalFactHandle handle, final PropagationContext pCtx, final boolean isCalledFromRHS) {
        initInitialFact();

        BaseNode[] tnodes = kBase.getReteooBuilder().getTerminalNodesForQuery( queryName );
        // no need to call retract, as no leftmemory used.
        getEntryPointNode().assertQuery( handle,
                                         pCtx,
                                         this );

        pCtx.evaluateActionQueue( this );
        return tnodes;
    }

    public Collection getActionQueue() {
        return actionQueue;
    }

    @Override
    public void queueWorkingMemoryAction(final WorkingMemoryAction action) {
        try {
            startOperation();
            actionQueue.add(action);
            notifyWaitOnRest();
        } finally {
            endOperation();
        }
    }

    public void addPropagation(PropagationEntry propagationEntry) {
        if (propagationEntry instanceof WorkingMemoryAction) {
            actionQueue.add((WorkingMemoryAction) propagationEntry);
        } else {
            super.addPropagation(propagationEntry);
        }
    }

    @Override
    public void executeQueuedActionsForRete() {
        try {
            startOperation();
            if ( evaluatingActionQueue.compareAndSet( false,
                                                      true ) ) {
                try {
                    if ( actionQueue!= null && !actionQueue.isEmpty() ) {
                        WorkingMemoryAction action;

                        while ( (action = actionQueue.poll()) != null ) {
                            try {
                                action.execute( (InternalWorkingMemory) this );
                            } catch ( Exception e ) {
                                throw new RuntimeException( "Unexpected exception executing action " + action.toString(),
                                                            e );
                            }
                        }
                    }
                } finally {
                    evaluatingActionQueue.compareAndSet( true,
                                                         false );
                }
            }
        } finally {
            endOperation();
        }
    }

    @Override
    public Iterator getActionsIterator() {
        return actionQueue.iterator();
    }

    @Override
    public FactHandle insert( final Object object,
                              final boolean dynamic,
                              final RuleImpl rule,
                              final Activation activation ) {
        try {
            kBase.readLock();
            return super.insert( object, dynamic, rule, activation );
        } finally {
            kBase.readUnlock();
        }
    }

    @Override
    public void delete(FactHandle factHandle,
                       RuleImpl rule,
                       Activation activation,
                       FactHandle.State fhState ) {
        try {
            kBase.readLock();
            super.delete( factHandle, rule, activation, fhState );
        } finally {
            kBase.readUnlock();
        }
    }

    @Override
    public void update(FactHandle factHandle,
                       final Object object,
                       final BitMask mask,
                       Class modifiedClass,
                       final Activation activation) {
        try {
            kBase.readLock();
            super.update( factHandle, object, mask, modifiedClass, activation );
        } finally {
            kBase.readUnlock();
        }
    }

    @Override
    public void startBatchExecution() {
        kBase.readLock();
        super.startBatchExecution();
    }

    @Override
    public void endBatchExecution() {
        super.endBatchExecution();
        kBase.readUnlock();
    }

    @Override
    public void activate() { }

    @Override
    public void deactivate() { }

    @Override
    public boolean tryDeactivate() {
        return true;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy