Package org.drools.common

Source Code of org.drools.common.DefaultAgenda

package org.drools.common;

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

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.drools.WorkingMemory;
import org.drools.base.DefaultKnowledgeHelper;
import org.drools.base.SequentialKnowledgeHelper;
import org.drools.common.RuleFlowGroupImpl.DeactivateCallback;
import org.drools.spi.Activation;
import org.drools.spi.ActivationGroup;
import org.drools.spi.AgendaFilter;
import org.drools.spi.AgendaGroup;
import org.drools.spi.ConflictResolver;
import org.drools.spi.ConsequenceException;
import org.drools.spi.ConsequenceExceptionHandler;
import org.drools.spi.KnowledgeHelper;
import org.drools.spi.RuleFlowGroup;
import org.drools.util.LinkedListNode;
import org.drools.util.Queueable;

/**
* Rule-firing Agenda.
*
* <p>
* Since many rules may be matched by a single assertObject(...) all scheduled
* actions are placed into the <code>Agenda</code>.
* </p>
*
* <p>
* While processing a scheduled action, it may update or retract objects in
* other scheduled actions, which must then be removed from the agenda.
* Non-invalidated actions are left on the agenda, and are executed in turn.
* </p>
*
* @author <a href="mailto:bob@eng.werken.com">bob mcwhirter </a>
* @author <a href="mailto:simon@redhillconsulting.com.au">Simon Harris </a>
*/
public class DefaultAgenda
    implements
    Serializable,
    InternalAgenda {
    // ------------------------------------------------------------
    // Instance members
    // ------------------------------------------------------------

    /**
     *
     */
    private static final long           serialVersionUID = 400L;

    /** Working memory of this Agenda. */
    private final InternalWorkingMemory workingMemory;

    private org.drools.util.LinkedList  scheduledActivations;

    /** Items time-delayed. */

    private final Map                   agendaGroups;

    private final Map                   activationGroups;

    private final Map                   ruleFlowGroups;

    private final LinkedList            focusStack;

    private AgendaGroup                 currentModule;

    private final AgendaGroup           main;

    private AgendaGroupFactory          agendaGroupFactory;

    private KnowledgeHelper             knowledgeHelper;

    public int                          activeActivations;

    public int                          dormantActivations;
   
    private ConsequenceExceptionHandler consequenceExceptionHandler;

    // ------------------------------------------------------------
    // Constructors
    // ------------------------------------------------------------

    /**
     * Construct.
     *
     * @param workingMemory
     *            The <code>WorkingMemory</code> of this agenda.
     * @param conflictResolver
     *            The conflict resolver.
     */
    public DefaultAgenda(final InternalWorkingMemory workingMemory) {
        this.workingMemory = workingMemory;
        if ( ((InternalRuleBase) this.workingMemory.getRuleBase()).getConfiguration().isSequential() ) {
            this.knowledgeHelper = new SequentialKnowledgeHelper( this.workingMemory );
        } else {
            this.knowledgeHelper = new DefaultKnowledgeHelper( this.workingMemory );
        }
        this.agendaGroups = new HashMap();
        this.activationGroups = new HashMap();
        this.ruleFlowGroups = new HashMap();
        this.focusStack = new LinkedList();

        this.agendaGroupFactory = ((InternalRuleBase) this.workingMemory.getRuleBase()).getConfiguration().getAgendaGroupFactory();

        // MAIN should always be the first AgendaGroup and can never be removed
        this.main = agendaGroupFactory.createAgendaGroup( AgendaGroup.MAIN,
                                                          ((InternalRuleBase) this.workingMemory.getRuleBase()) );

        this.agendaGroups.put( AgendaGroup.MAIN,
                               this.main );

        this.focusStack.add( this.main );
       
        this.consequenceExceptionHandler = ((InternalRuleBase) workingMemory.getRuleBase()).getConfiguration().getConsequenceExceptionHandler();

    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getWorkingMemory()
     */
    public WorkingMemory getWorkingMemory() {
        return this.workingMemory;
    }

    /**
     * Schedule an agenda item for delayed firing.
     *
     * @param item
     *            The item to schedule.
     */
    public void scheduleItem(final ScheduledAgendaItem item) {
        Scheduler.getInstance().scheduleAgendaItem( item );

        if ( this.scheduledActivations == null ) {
            this.scheduledActivations = new org.drools.util.LinkedList();
        }

        this.scheduledActivations.add( item );
    }

    public void removeScheduleItem(final ScheduledAgendaItem item) {
        this.scheduledActivations.remove( item );
        item.cancel();
    }

    public void addAgendaGroup(final AgendaGroup agendaGroup) {
        this.agendaGroups.put( agendaGroup.getName(),
                               agendaGroup );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#setFocus(org.drools.spi.AgendaGroup)
     */
    public boolean setFocus(final AgendaGroup agendaGroup) {
        // Set the focus to the agendaGroup if it doesn't already have the focus
        if ( this.focusStack.getLast() != agendaGroup ) {
            ((InternalAgendaGroup) this.focusStack.getLast()).setActive( false );
            this.focusStack.add( agendaGroup );
            ((InternalAgendaGroup) agendaGroup).setActive( true );
            final EventSupport eventsupport = (EventSupport) this.workingMemory;
            eventsupport.getAgendaEventSupport().fireAgendaGroupPushed( agendaGroup, this.workingMemory );
            return true;
        } else {
            return false;
        }
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#setFocus(java.lang.String)
     */
    public void setFocus(final String name) {
        AgendaGroup agendaGroup = getAgendaGroup( name );
        setFocus( agendaGroup );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getFocus()
     */
    public AgendaGroup getFocus() {
        return (AgendaGroup) this.focusStack.getLast();
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getNextFocus()
     */
    public AgendaGroup getNextFocus() {
        InternalAgendaGroup agendaGroup = null;
        // Iterate untill we find a populate AgendaModule or we reach the MAIN, default, AgendaGroup
        while ( true ) {
            agendaGroup = (InternalAgendaGroup) this.focusStack.getLast();

            final boolean empty = agendaGroup.isEmpty();

            // No populated queus found so pop the focusStack and repeat           
            if ( empty && (this.focusStack.size() > 1) ) {
                agendaGroup.setActive( false );
                this.focusStack.removeLast();
                final EventSupport eventsupport = (EventSupport) this.workingMemory;
                eventsupport.getAgendaEventSupport().fireAgendaGroupPopped( agendaGroup, this.workingMemory );
            } else {
                agendaGroup = (empty) ? null : agendaGroup;
                break;
            }
        }

        if ( agendaGroup != null ) {
            agendaGroup.setActive( true );
        }
        return agendaGroup;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#setCurrentAgendaGroup(org.drools.spi.AgendaGroup)
     */
    public void setCurrentAgendaGroup(final AgendaGroup agendaGroup) {
        this.currentModule = agendaGroup;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getCurrentAgendaGroup()
     */
    public AgendaGroup getCurrentAgendaGroup() {
        return this.currentModule;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getAgendaGroup(java.lang.String)
     */
    public AgendaGroup getAgendaGroup(final String name) {
        AgendaGroup agendaGroup = (AgendaGroup) this.agendaGroups.get( name );
        if ( agendaGroup == null ) {
            // The AgendaGroup is defined but not yet added to the
            // Agenda, so create the AgendaGroup and add to the Agenda.
            agendaGroup = agendaGroupFactory.createAgendaGroup( name,
                                                                ((InternalRuleBase) this.workingMemory.getRuleBase()) );
            addAgendaGroup( agendaGroup );
        }
        return agendaGroup;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getAgendaGroups()
     */
    public AgendaGroup[] getAgendaGroups() {
        return (AgendaGroup[]) this.agendaGroups.values().toArray( new AgendaGroup[this.agendaGroups.size()] );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getStack()
     */
    public AgendaGroup[] getStack() {
        return (AgendaGroup[]) this.focusStack.toArray( new AgendaGroup[this.focusStack.size()] );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getActivationGroup(java.lang.String)
     */
    public ActivationGroup getActivationGroup(final String name) {
        ActivationGroupImpl activationGroup = (ActivationGroupImpl) this.activationGroups.get( name );
        if ( activationGroup == null ) {
            activationGroup = new ActivationGroupImpl( name );
            this.activationGroups.put( name,
                                       activationGroup );
        }
        return activationGroup;
    }

    public RuleFlowGroup getRuleFlowGroup(final String name) {
        RuleFlowGroup ruleFlowGroup = (RuleFlowGroup) this.ruleFlowGroups.get( name );
        if ( ruleFlowGroup == null ) {
            ruleFlowGroup = new RuleFlowGroupImpl( name );
            ((InternalRuleFlowGroup) ruleFlowGroup).setWorkingMemory( (InternalWorkingMemory) getWorkingMemory() );
            this.ruleFlowGroups.put( name,
                                     ruleFlowGroup );
        }
        return ruleFlowGroup;
    }

    public void activateRuleFlowGroup(final String name) {
        ((InternalRuleFlowGroup) getRuleFlowGroup( name )).setActive( true );
    }

    public void deactivateRuleFlowGroup(final String name) {
        ((InternalRuleFlowGroup) getRuleFlowGroup( name )).setActive( false );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#focusStackSize()
     */
    public int focusStackSize() {
        int size = 0;
        for ( final java.util.Iterator iterator = this.focusStack.iterator(); iterator.hasNext(); ) {
            final AgendaGroup group = (AgendaGroup) iterator.next();
            size += group.size();
        }
        return size;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#agendaSize()
     */
    public int agendaSize() {
        int size = 0;
        for ( final java.util.Iterator iterator = this.agendaGroups.values().iterator(); iterator.hasNext(); ) {
            final AgendaGroup group = (AgendaGroup) iterator.next();
            size += group.size();
        }
        return size;
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getActivations()
     */
    public Activation[] getActivations() {
        final List list = new ArrayList();
        for ( final java.util.Iterator it = this.agendaGroups.values().iterator(); it.hasNext(); ) {
            final AgendaGroup group = (AgendaGroup) it.next();
            list.addAll( Arrays.asList( group.getActivations() ) );
        }
        return (Activation[]) list.toArray( new Activation[list.size()] );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#getScheduledActivations()
     */
    public Activation[] getScheduledActivations() {
        final List list = new ArrayList( this.scheduledActivations.size() );
        for ( LinkedListNode node = this.scheduledActivations.getFirst(); node != null; node = node.getNext() ) {
            list.add( node );
        }
        return (Activation[]) list.toArray( new Activation[list.size()] );
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#clearAgenda()
     */
    public void clearAgenda() {
        // Cancel all items and fire a Cancelled event for each Activation
        for ( final java.util.Iterator agendaGroupIterator = this.agendaGroups.values().iterator(); agendaGroupIterator.hasNext(); ) {
            final AgendaGroup group = (AgendaGroup) agendaGroupIterator.next();
            clearAgendaGroup( group );
        }

        final EventSupport eventsupport = (EventSupport) this.workingMemory;
        if ( this.scheduledActivations != null && !this.scheduledActivations.isEmpty() ) {
            for ( ScheduledAgendaItem item = (ScheduledAgendaItem) this.scheduledActivations.removeFirst(); item != null; item = (ScheduledAgendaItem) this.scheduledActivations.removeFirst() ) {
                item.cancel();               
                eventsupport.getAgendaEventSupport().fireActivationCancelled( item,
                                                                              this.workingMemory );
            }
        }
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#clearAgendaGroup(java.lang.String)
     */
    public void clearAgendaGroup(final String name) {
        final AgendaGroup agendaGroup = (AgendaGroup) this.agendaGroups.get( name );
        if ( agendaGroup != null ) {
            clearAgendaGroup( agendaGroup );
        }
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#clearAgendaGroup(org.drools.common.AgendaGroupImpl)
     */
    public void clearAgendaGroup(final AgendaGroup agendaGroup) {
        final EventSupport eventsupport = (EventSupport) this.workingMemory;

        final Activation[] queueable = ((InternalAgendaGroup) agendaGroup).getQueue();
        for ( int i = 0, length = queueable.length; i < length; i++ ) {
            final AgendaItem item = (AgendaItem) queueable[i];
            if ( item == null ) {
                continue;
            }

            // this must be set false before removal from the activationGroup. Otherwise the activationGroup will also try to cancel the Actvation
            item.setActivated( false );

            if ( item.getActivationGroupNode() != null ) {
                item.getActivationGroupNode().getActivationGroup().removeActivation( item );
            }

            if ( item.getRuleFlowGroupNode() != null ) {
                final InternalRuleFlowGroup ruleFlowGroup = item.getRuleFlowGroupNode().getRuleFlowGroup();
                ruleFlowGroup.removeActivation( item );
            }

            eventsupport.getAgendaEventSupport().fireActivationCancelled( item,
                                                                          this.workingMemory );
        }
        ((InternalAgendaGroup) agendaGroup).clear();
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#clearActivationGroup(java.lang.String)
     */
    public void clearActivationGroup(final String name) {
        final ActivationGroup activationGroup = (ActivationGroup) this.activationGroups.get( name );
        if ( activationGroup != null ) {
            clearActivationGroup( activationGroup );
        }
    }

    /* (non-Javadoc)
     * @see org.drools.common.AgendaI#clearActivationGroup(org.drools.spi.ActivationGroup)
     */
    public void clearActivationGroup(final ActivationGroup activationGroup) {
        final EventSupport eventsupport = (EventSupport) this.workingMemory;

        for ( final Iterator it = activationGroup.iterator(); it.hasNext(); ) {
            final ActivationGroupNode node = (ActivationGroupNode) it.next();
            final Activation activation = node.getActivation();
            activation.setActivationGroupNode( null );

            if ( activation.isActivated() ) {
                activation.setActivated( false );
                activation.remove();

                if ( activation.getRuleFlowGroupNode() != null ) {
                    final InternalRuleFlowGroup ruleFlowGroup = activation.getRuleFlowGroupNode().getRuleFlowGroup();
                    ruleFlowGroup.removeActivation( activation );
                }

                eventsupport.getAgendaEventSupport().fireActivationCancelled( activation,
                                                                              this.workingMemory );
            }
        }
        activationGroup.clear();
    }
   
    public void clearRuleFlowGroup(final String name) {
        final RuleFlowGroup ruleFlowGrlup = (RuleFlowGroup) this.ruleFlowGroups.get( name );
        if ( ruleFlowGrlup != null ) {
            clearRuleFlowGroup( ruleFlowGrlup );
        }
    }   
   
    public void clearRuleFlowGroup(final RuleFlowGroup ruleFlowGroup) {
        final EventSupport eventsupport = (EventSupport) this.workingMemory;

       
        for ( Iterator it = ruleFlowGroup.iterator(); it.hasNext(); ) {
            RuleFlowGroupNode node = ( RuleFlowGroupNode ) it.next();
            AgendaItem item = ( AgendaItem ) node.getActivation();           
            if ( item != null ) {
                item.setActivated( false );
                item.remove();
               
                if ( item.getActivationGroupNode() != null ) {
                    item.getActivationGroupNode().getActivationGroup().removeActivation( item );
                }               
            }
           
       
           
            eventsupport.getAgendaEventSupport().fireActivationCancelled( item,
                                                                          this.workingMemory );                       
        }
       
        ((InternalRuleFlowGroup) ruleFlowGroup).clear();      
       
        if ( ruleFlowGroup.isActive() && ruleFlowGroup.isAutoDeactivate() ) {
                // deactivate callback
                WorkingMemoryAction action = new DeactivateCallback( (InternalRuleFlowGroup) ruleFlowGroup );
                this.workingMemory.queueWorkingMemoryAction( action );
        }       
    }   

    /**
     * Fire the next scheduled <code>Agenda</code> item.
     *
     * @throws ConsequenceException
     *             If an error occurs while firing an agenda item.
     */
    public boolean fireNextItem(final AgendaFilter filter) throws ConsequenceException {
        final InternalAgendaGroup group = (InternalAgendaGroup) getNextFocus();

        // return if there are no Activations to fire
        if ( group == null ) {
            return false;
        }

        final AgendaItem item = (AgendaItem) group.getNext();
        if ( item == null ) {
            return false;
        }

        if ( filter == null || filter.accept( item ) ) {
            fireActivation( item );
        }

        return true;
    }

    /**
     * Fire this item.
     *
     * @param workingMemory
     *            The working memory context.
     *
     * @throws ConsequenceException
     *             If an error occurs while attempting to fire the consequence.
     */
    public synchronized void fireActivation(final Activation activation) throws ConsequenceException {
        // We do this first as if a node modifies a fact that causes a recursion on an empty pattern
        // we need to make sure it re-activates
        increaseDormantActivations();

        final EventSupport eventsupport = (EventSupport) this.workingMemory;

        eventsupport.getAgendaEventSupport().fireBeforeActivationFired( activation,
                                                                        this.workingMemory );

        if ( activation.getActivationGroupNode() != null ) {
            // We know that this rule will cancel all other activatiosn in the group
            // so lets remove the information now, before the consequence fires
            final ActivationGroup activationGroup = activation.getActivationGroupNode().getActivationGroup();
            activationGroup.removeActivation( activation );
            clearActivationGroup( activationGroup );
        }
        activation.setActivated( false );

        try {
            this.knowledgeHelper.setActivation( activation );
            activation.getRule().getConsequence().evaluate( this.knowledgeHelper,
                                                            this.workingMemory );
        } catch ( final Exception e ) {
            this.consequenceExceptionHandler.handleException( activation, this.workingMemory, e );
        }

        if ( activation.getRuleFlowGroupNode() != null ) {
            final InternalRuleFlowGroup ruleFlowGroup = activation.getRuleFlowGroupNode().getRuleFlowGroup();
            ruleFlowGroup.removeActivation( activation );
        }

        eventsupport.getAgendaEventSupport().fireAfterActivationFired( activation, this.workingMemory );
    }

    public void increaseActiveActivations() {
        this.activeActivations++;
    }

    public void decreaseActiveActivations() {
        this.activeActivations--;
    }

    public void increaseDormantActivations() {
        this.activeActivations--;
        this.dormantActivations++;
    }

    public void decreaseDormantActivations() {
        this.dormantActivations--;
    }

    public int getActiveActivations() {
        return this.activeActivations;
    }

    public int getDormantActivations() {
        return this.dormantActivations;
    }

}
TOP

Related Classes of org.drools.common.DefaultAgenda

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.