/* * Copyright 2005 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. * 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 org.drools.core.impl.InternalKnowledgeBase; import org.drools.core.marshalling.impl.MarshallerReaderContext; import org.drools.core.marshalling.impl.MarshallerWriteContext; import org.drools.core.marshalling.impl.ProtobufMessages; import org.drools.core.phreak.PropagationEntry; import org.drools.core.spi.Activation; import org.drools.core.spi.PropagationContext; import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** * Implementation of a <code>RuleFlowGroup</code> that collects activations * of rules of this ruleflow-group. * If this group is activated, all its activations are added to the agenda. * As long as this group is active, its activations are added to the agenda. * Deactivating the group removes all its activations from the agenda and * collects them until it is activated again. * By default, <code>RuleFlowGroups</code> are automatically deactivated when there are no more * activations in the <code>RuleFlowGroup</code>. However, this can be configured. */ public class RuleFlowGroupImpl implements InternalRuleFlowGroup, InternalAgendaGroup { private static final long serialVersionUID = 510l; private InternalWorkingMemory workingMemory; // private String name; // private boolean active = false; private boolean autoDeactivate = true; // private LinkedList<ActivationNode> list; private List<RuleFlowGroupListener> listeners; private Map<Long, String> nodeInstances = new HashMap<Long, String>(); // private long activatedForRecency; // private long clearedForRecency; private final InternalAgendaGroup agendaGroup; public RuleFlowGroupImpl() { agendaGroup = null; } /** * Construct a <code>RuleFlowGroupImpl</code> with the given name. * * @param name * The RuleFlowGroup name. */ public RuleFlowGroupImpl(final String name, InternalKnowledgeBase kBase) { //this.name = name; //this.list = new LinkedList(); agendaGroup = new AgendaGroupQueueImpl(name, kBase); } public RuleFlowGroupImpl(final String name, final boolean active, final boolean autoDeactivate) { agendaGroup = null; // this.name = name; // this.active = active; // this.autoDeactivate = autoDeactivate; // this.list = new LinkedList(); // this.clearedForRecency = -1; } public String getName() { return agendaGroup.getName(); } public void setWorkingMemory(InternalWorkingMemory workingMemory) { this.workingMemory = workingMemory; } public InternalWorkingMemory getWorkingMemory() { return this.workingMemory; } @Override public void hasRuleFlowListener(boolean hasRuleFlowLister) { //To change body of implemented methods use File | Settings | File Templates. } @Override public boolean isRuleFlowListener() { return false; //To change body of implemented methods use File | Settings | File Templates. } public Activation remove() { return agendaGroup.remove(); } public Activation peek() { return agendaGroup.peek(); } public void setActive(final boolean active) { this.agendaGroup.setActive( active ); // if ( this.active == active ) { // return; // } // this.active = active; // synchronized ( list ) { // if ( active ) { // setActivatedForRecency( this.workingMemory.getFactHandleFactory().getRecency() ); // ((EventSupport) this.workingMemory).getAgendaEventSupport().fireBeforeRuleFlowGroupActivated( this, // this.workingMemory ); // if ( this.list.isEmpty() ) { // if ( this.autoDeactivate ) { // // if the list of activations is empty and // // auto-deactivate is on, deactivate this group // WorkingMemoryAction action = new DeactivateCallback( this ); // this.workingMemory.queueWorkingMemoryAction( action ); // } // } else { // triggerActivations(); // } // ((EventSupport) this.workingMemory).getAgendaEventSupport().fireAfterRuleFlowGroupActivated( this, // this.workingMemory ); // } else { // ((EventSupport) this.workingMemory).getAgendaEventSupport().fireBeforeRuleFlowGroupDeactivated( this, // this.workingMemory ); // // FastIterator it = list.fastIterator(); // for ( ActivationNode entry = list.getFirst(); entry != null; entry = (ActivationNode) it.next( entry ) ) { // final Activation activation = entry.getActivation(); // activation.remove(); // if ( activation.getActivationGroupNode() != null ) { // activation.getActivationGroupNode().getActivationGroup().removeActivation( activation ); // } // } // // nodeInstances.clear(); // notifyRuleFlowGroupListeners(); // ((EventSupport) this.workingMemory).getAgendaEventSupport().fireAfterRuleFlowGroupDeactivated( this, // this.workingMemory ); // } // } } public boolean isActive() { return agendaGroup.isActive(); } @Override public void setAutoFocusActivator(PropagationContext ctx) { //To change body of implemented methods use File | Settings | File Templates. } @Override public PropagationContext getAutoFocusActivator() { return null; //To change body of implemented methods use File | Settings | File Templates. } public boolean isAutoDeactivate() { return this.autoDeactivate; } public void setAutoDeactivate(final boolean autoDeactivate) { this.autoDeactivate = autoDeactivate; synchronized ( agendaGroup ) { if ( autoDeactivate && agendaGroup.isActive() && agendaGroup.isEmpty() ) { this.agendaGroup.setActive( false ); } } } // private void triggerActivations() { // // // iterate all activations adding them to their AgendaGroups // synchronized ( this.list ) { // FastIterator it = list.fastIterator(); // for ( ActivationNode entry = list.getFirst(); entry != null; entry = (ActivationNode) it.next( entry ) ) { // final Activation activation = entry.getActivation(); // ((InternalAgendaGroup) activation.getAgendaGroup()).add( activation ); // } // } // // // making sure we re-evaluate agenda in case we are waiting for activations // ((InternalAgenda) workingMemory.getAgenda()).notifyWaitOnRest(); // } public void clear() { synchronized ( agendaGroup ) { agendaGroup.clear(); } } public void reset() { synchronized ( agendaGroup ) { agendaGroup.reset(); } } @Override public void setFocus() { //agendaGroup.setFocus(); } @Override public Activation[] getAndClear() { return new Activation[0]; //To change body of implemented methods use File | Settings | File Templates. } @Override public void add(Activation activation) { addActivation( activation ); } public void addActivation(final Activation activation) { synchronized ( agendaGroup ) { agendaGroup.add(activation); } // assert activation.getActivationNode() == null; // final ActivationNode node = new ActivationNode( activation, // this ); // activation.setActivationNode( node ); // synchronized ( this.list ) { // this.list.add( node ); // } // // if ( this.active ) { // ((InternalAgendaGroup) activation.getAgendaGroup()).add( activation ); // } } @Override public void remove(Activation activation) { removeActivation( activation ); } public void removeActivation(final Activation activation) { synchronized ( agendaGroup ) { agendaGroup.remove(activation); } // synchronized ( this.list ) { // final ActivationNode node = activation.getActivationNode(); // this.list.remove( node ); // activation.setActivationNode( null ); // } } /** * Checks if this ruleflow group is active and should automatically deactivate. * If the queue is empty, it deactivates the group. */ public void deactivateIfEmpty() { // synchronized ( this.list ) { // if ( this.active && this.autoDeactivate && this.list.isEmpty() ) { // // deactivate callback // WorkingMemoryAction action = new DeactivateCallback( this ); // this.workingMemory.queueWorkingMemoryAction( action ); // } // } } public void addRuleFlowGroupListener(RuleFlowGroupListener listener) { if ( listeners == null ) { listeners = new CopyOnWriteArrayList<RuleFlowGroupListener>(); } listeners.add( listener ); } public void removeRuleFlowGroupListener(RuleFlowGroupListener listener) { if ( listeners != null ) { listeners.remove( listener ); } } public void notifyRuleFlowGroupListeners() { if ( listeners != null ) { for ( java.util.Iterator<RuleFlowGroupListener> iterator = listeners.iterator(); iterator.hasNext(); ) { iterator.next().ruleFlowGroupDeactivated(); } } } public boolean isEmpty() { synchronized ( agendaGroup ) { return agendaGroup.isEmpty(); } } public Activation[] getActivations() { synchronized ( agendaGroup ) { //return agendaGroup.getActivations(); return null; } } public java.util.Iterator iterator() { //return agendaGroup.it return null; } public void addNodeInstance(Long processInstanceId, String nodeInstanceId) { nodeInstances.put( processInstanceId, nodeInstanceId ); } public void removeNodeInstance(Long processInstanceId, String nodeInstanceId) { nodeInstances.put( processInstanceId, nodeInstanceId ); } public Map<Long, String> getNodeInstances() { return nodeInstances; } public void setActivatedForRecency(long recency) { agendaGroup.setActivatedForRecency( recency ); } public long getActivatedForRecency() { return agendaGroup.getActivatedForRecency(); } public void setClearedForRecency(long recency) { agendaGroup.setClearedForRecency( recency ); } public long getClearedForRecency() { return agendaGroup.getClearedForRecency(); } public String toString() { return "RuleFlowGroup '" + this.agendaGroup.remove() + "'"; } @Override public void visited() { agendaGroup.visited(); } public int size() { synchronized ( agendaGroup ) { return agendaGroup.size(); } } public boolean equals(final Object object) { if ( (object == null) || !(object instanceof RuleFlowGroupImpl) ) { return false; } if ( ((RuleFlowGroupImpl) object).getName().equals( getName() ) ) { return true; } return false; } public int hashCode() { return getName().hashCode(); } public static class DeactivateCallback extends PropagationEntry.AbstractPropagationEntry implements WorkingMemoryAction { private static final long serialVersionUID = 510l; private InternalRuleFlowGroup ruleFlowGroup; public DeactivateCallback(InternalRuleFlowGroup ruleFlowGroup) { this.ruleFlowGroup = ruleFlowGroup; } public DeactivateCallback(MarshallerReaderContext context) throws IOException { this.ruleFlowGroup = (InternalRuleFlowGroup) context.wm.getAgenda().getRuleFlowGroup( context.readUTF() ); } public DeactivateCallback(MarshallerReaderContext context, ProtobufMessages.ActionQueue.Action _action) { this.ruleFlowGroup = (InternalRuleFlowGroup) context.wm.getAgenda().getRuleFlowGroup( _action.getDeactivateCallback().getRuleflowGroup() ); } public ProtobufMessages.ActionQueue.Action serialize(MarshallerWriteContext context) { return ProtobufMessages.ActionQueue.Action.newBuilder() .setType( ProtobufMessages.ActionQueue.ActionType.DEACTIVATE_CALLBACK ) .setDeactivateCallback( ProtobufMessages.ActionQueue.DeactivateCallback.newBuilder() .setRuleflowGroup( ruleFlowGroup.getName() ) .build() ) .build(); } public void execute(InternalWorkingMemory workingMemory) { // check whether ruleflow group is still empty first if ( this.ruleFlowGroup.isEmpty() ) { // deactivate ruleflow group this.ruleFlowGroup.setActive( false ); } } } @Override public boolean isSequential() { return agendaGroup.isSequential(); } }