/* * Copyright 2010 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.reteoo; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.drools.core.beliefsystem.ModedAssertion; import org.drools.core.beliefsystem.simple.SimpleMode; import org.drools.core.common.ActivationGroupNode; import org.drools.core.common.ActivationNode; import org.drools.core.common.AgendaItem; import org.drools.core.common.InternalAgenda; import org.drools.core.common.InternalAgendaGroup; import org.drools.core.common.InternalFactHandle; import org.drools.core.common.LogicalDependency; import org.drools.core.definitions.rule.impl.RuleImpl; import org.drools.core.phreak.RuleAgendaItem; import org.drools.core.rule.Declaration; import org.drools.core.rule.GroupElement; import org.drools.core.spi.Consequence; import org.drools.core.spi.PropagationContext; import org.drools.core.util.LinkedList; import org.kie.api.runtime.rule.FactHandle; public class RuleTerminalNodeLeftTuple<T extends ModedAssertion<T>> extends BaseLeftTuple implements AgendaItem<T> { private static final long serialVersionUID = 540l; /** * The salience */ private int salience; /** * The activation number */ private long activationNumber; private int queueIndex; private boolean queued; private LinkedList<LogicalDependency<T>> justified; private LinkedList<LogicalDependency<SimpleMode>> blocked; private LinkedList<SimpleMode> blockers; private InternalAgendaGroup agendaGroup; private ActivationGroupNode activationGroupNode; private ActivationNode activationNode; private InternalFactHandle activationFactHandle; private transient boolean canceled; private boolean matched; private boolean active; private RuleAgendaItem ruleAgendaItem; private Runnable callback; public RuleTerminalNodeLeftTuple() { // constructor needed for serialisation } // ------------------------------------------------------------ // Constructors // ------------------------------------------------------------ public RuleTerminalNodeLeftTuple(final InternalFactHandle factHandle, final Sink sink, final boolean leftTupleMemoryEnabled) { super(factHandle, sink, leftTupleMemoryEnabled); } public RuleTerminalNodeLeftTuple(final InternalFactHandle factHandle, final LeftTuple leftTuple, final Sink sink) { super(factHandle, leftTuple, sink); } public RuleTerminalNodeLeftTuple(final LeftTuple leftTuple, final Sink sink, final PropagationContext pctx, final boolean leftTupleMemoryEnabled) { super(leftTuple, sink, pctx, leftTupleMemoryEnabled); } public RuleTerminalNodeLeftTuple(final LeftTuple leftTuple, RightTuple rightTuple, Sink sink) { super(leftTuple, rightTuple, sink); } public RuleTerminalNodeLeftTuple(final LeftTuple leftTuple, final RightTuple rightTuple, final Sink sink, final boolean leftTupleMemoryEnabled) { this( leftTuple, rightTuple, null, null, sink, leftTupleMemoryEnabled ); } public RuleTerminalNodeLeftTuple(final LeftTuple leftTuple, final RightTuple rightTuple, final LeftTuple currentLeftChild, final LeftTuple currentRightChild, final Sink sink, final boolean leftTupleMemoryEnabled) { super(leftTuple, rightTuple, currentLeftChild, currentRightChild, sink, leftTupleMemoryEnabled); } public void init(final long activationNumber, final int salience, final PropagationContext pctx, final RuleAgendaItem ruleAgendaItem, InternalAgendaGroup agendaGroup) { setPropagationContext(pctx); this.salience = salience; this.activationNumber = activationNumber; this.queueIndex = -1; this.matched = true; this.ruleAgendaItem = ruleAgendaItem; this.agendaGroup = agendaGroup; } public void update(final int salience, final PropagationContext pctx) { setPropagationContext(pctx); this.salience = salience; this.matched = true; } /** * Retrieve the rule. * * @return The rule. */ public RuleImpl getRule() { return getTerminalNode().getRule(); } public Consequence getConsequence() { String consequenceName = ((RuleTerminalNode) getTerminalNode()).getConsequenceName(); return consequenceName.equals(RuleImpl.DEFAULT_CONSEQUENCE_NAME) ? getTerminalNode().getRule().getConsequence() : getTerminalNode().getRule().getNamedConsequence(consequenceName); } /** * Retrieve the tuple. * * @return The tuple. */ public LeftTuple getTuple() { return this; } public int getSalience() { return this.salience; } public void setSalience(int salience) { this.salience = salience; } public InternalFactHandle getActivationFactHandle() { return activationFactHandle; } public void setActivationFactHandle( InternalFactHandle factHandle ) { this.activationFactHandle = factHandle; } public RuleAgendaItem getRuleAgendaItem() { return ruleAgendaItem; } /* * (non-Javadoc) * * @see org.kie.spi.Activation#getActivationNumber() */ public long getActivationNumber() { return this.activationNumber; } public void addBlocked(final LogicalDependency<SimpleMode> dep) { // Adds the blocked to the blockers list if (this.blocked == null) { this.blocked = new LinkedList<LogicalDependency<SimpleMode>>(); } this.blocked.add(dep); // now ad the blocker to the blocked's list - we need to check that references are null first RuleTerminalNodeLeftTuple blocked = (RuleTerminalNodeLeftTuple) dep.getJustified(); if (blocked.blockers == null) { blocked.blockers = new LinkedList<SimpleMode>(); blocked.blockers.add(dep.getMode()); } else if (dep.getMode().getNext() == null && dep.getMode().getPrevious() == null && blocked.getBlockers().getFirst() != dep.getMode()) { blocked.blockers.add(dep.getMode()); } } public void removeAllBlockersAndBlocked(InternalAgenda agenda) { if (this.blockers != null) { // Iterate and remove this node's logical dependency list from each of it's blockers for (SimpleMode node = blockers.getFirst(); node != null; node = node.getNext()) { LogicalDependency dep = node.getObject(); dep.getJustifier().getBlocked().remove(dep); } } this.blockers = null; if (this.blocked != null) { // Iterate and remove this node's logical dependency list from each of it's blocked for (LogicalDependency<SimpleMode> dep = blocked.getFirst(); dep != null; ) { LogicalDependency<SimpleMode> tmp = dep.getNext(); removeBlocked(dep); RuleTerminalNodeLeftTuple justified = (RuleTerminalNodeLeftTuple) dep.getJustified(); if (justified.getBlockers().isEmpty() && justified.isActive()) { agenda.stageLeftTuple(ruleAgendaItem, justified); } dep = tmp; } } this.blocked = null; } public void removeBlocked(final LogicalDependency<SimpleMode> dep) { this.blocked.remove(dep); RuleTerminalNodeLeftTuple blocked = (RuleTerminalNodeLeftTuple) dep.getJustified(); blocked.blockers.remove(dep.getMode()); } public LinkedList<LogicalDependency<SimpleMode>> getBlocked() { return this.blocked; } public void setBlocked(LinkedList<LogicalDependency<SimpleMode>> justified) { this.blocked = justified; } public LinkedList<SimpleMode> getBlockers() { return this.blockers; } public void addLogicalDependency(final LogicalDependency<T> node) { if (this.justified == null) { this.justified = new LinkedList<LogicalDependency<T>>(); } this.justified.add(node); } public LinkedList<LogicalDependency<T>> getLogicalDependencies() { return this.justified; } public void setLogicalDependencies(LinkedList<LogicalDependency<T>> justified) { this.justified = justified; } public boolean isQueued() { return this.queued; } public void setQueued(final boolean queued) { this.queued = queued; if (queued) { setActive(true); } } public void setQueueIndex(final int queueIndex) { this.queueIndex = queueIndex; } public void dequeue() { if (this.agendaGroup != null) { this.agendaGroup.remove(this); } setQueued(false); } public int getQueueIndex() { return this.queueIndex; } public void remove() { dequeue(); } public ActivationGroupNode getActivationGroupNode() { return this.activationGroupNode; } public void setActivationGroupNode(final ActivationGroupNode activationNode) { this.activationGroupNode = activationNode; } public InternalAgendaGroup getAgendaGroup() { return this.agendaGroup; } public ActivationNode getActivationNode() { return this.activationNode; } public void setActivationNode(final ActivationNode activationNode) { this.activationNode = activationNode; } public GroupElement getSubRule() { return getTerminalNode().getSubRule(); } public TerminalNode getTerminalNode() { return (TerminalNode) getTupleSink(); } public List<FactHandle> getFactHandles() { return getFactHandles(this); } public String toExternalForm() { return "[ " + this.getRule().getName() + " active=" + this.queued + " ]"; } @Override public List<Object> getObjects() { return getObjects(this); } @Override public List<Object> getObjectsDeep() { return getObjectsDeep(this); } public Object getDeclarationValue(String variableName) { Declaration decl = getTerminalNode().getSubRule().getOuterDeclarations().get(variableName); InternalFactHandle handle = get(decl); // need to double check, but the working memory reference is only used for resolving globals, right? return decl.getValue(null, handle.getObject()); } public List<String> getDeclarationIds() { Declaration[] declArray = ((org.drools.core.reteoo.RuleTerminalNode) getTupleSink()).getAllDeclarations(); List<String> declarations = new ArrayList<String>(); for (Declaration decl : declArray) { declarations.add(decl.getIdentifier()); } return Collections.unmodifiableList(declarations); } public boolean isCanceled() { return canceled; } public void cancel() { this.canceled = true; } public boolean isMatched() { return matched; } public void setMatched(boolean matched) { this.matched = matched; } public boolean isActive() { return active; } public void setActive(boolean active) { this.active = active; } public boolean isRuleAgendaItem() { return false; } @Override public Runnable getCallback() { return callback; } @Override public void setCallback( Runnable callback ) { this.callback = callback; } @Override public String toString() { return "["+toExternalForm()+" [ " + super.toString()+ " ] ]"; } }