/*
* 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.builder;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Stack;
import org.drools.core.common.BaseNode;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.NetworkNode;
import org.drools.core.common.RuleBasePartitionId;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.reteoo.KieComponentFactory;
import org.drools.core.reteoo.LeftTupleSource;
import org.drools.core.reteoo.ObjectSource;
import org.drools.core.reteoo.ObjectTypeNode;
import org.drools.core.reteoo.PathEndNode;
import org.drools.core.rule.EntryPointId;
import org.drools.core.rule.GroupElement;
import org.drools.core.rule.Pattern;
import org.drools.core.rule.RuleConditionElement;
import org.drools.core.rule.constraint.XpathConstraint;
import org.drools.core.spi.AlphaNodeFieldConstraint;
import org.drools.core.spi.BetaNodeFieldConstraint;
import org.drools.core.spi.RuleComponent;
import org.drools.core.time.TemporalDependencyMatrix;
import static org.drools.core.rule.TypeDeclaration.NEVER_EXPIRES;
/**
* A build context for Reteoo Builder
*/
public class BuildContext {
// tuple source to attach next node to
private LeftTupleSource tupleSource;
// object source to attach next node to
private ObjectSource objectSource;
// object type cache to check for cross products
private LinkedList<Pattern> objectType;
// offset of the pattern
private int currentPatternOffset;
// rule base to add rules to
private InternalKnowledgeBase kBase;
// rule being added at this moment
private RuleImpl rule;
private GroupElement subRule;
// the rule component being processed at the moment
private Stack<RuleComponent> ruleComponent;
// working memories attached to the given rulebase
private InternalWorkingMemory[] workingMemories;
// a build stack to track nested elements
private LinkedList<RuleConditionElement> buildstack;
// beta constraints from the last pattern attached
private List<BetaNodeFieldConstraint> betaconstraints;
// alpha constraints from the last pattern attached
private List<AlphaNodeFieldConstraint> alphaConstraints;
// xpath constraints from the last pattern attached
private List<XpathConstraint> xpathConstraints;
// the current entry point
private EntryPointId currentEntryPoint;
private boolean tupleMemoryEnabled;
private boolean objectTypeNodeMemoryEnabled;
private boolean query;
private List<PathEndNode> pathEndNodes = new ArrayList<>();
/**
* Stores the list of nodes being added that require partitionIds
*/
private List<BaseNode> nodes;
/**
* Stores the id of the partition this rule will be added to
*/
private RuleBasePartitionId partitionId;
/**
* the calculate temporal distance matrix
*/
private TemporalDependencyMatrix temporal;
private ObjectTypeNode rootObjectTypeNode;
private Pattern[] lastBuiltPatterns;
// The reason why this is here is because forall can inject a
// "this == " + BASE_IDENTIFIER $__forallBaseIdentifier
// Which we don't want to actually count in the case of forall node linking
private boolean emptyForAllBetaConstraints;
private boolean attachPQN;
private boolean terminated;
private final KieComponentFactory componentFactory;
private String consequenceName;
public BuildContext(final InternalKnowledgeBase kBase) {
this.kBase = kBase;
this.workingMemories = null;
this.objectType = null;
this.buildstack = null;
this.tupleSource = null;
this.objectSource = null;
this.currentPatternOffset = 0;
this.tupleMemoryEnabled = true;
this.objectTypeNodeMemoryEnabled = true;
this.currentEntryPoint = EntryPointId.DEFAULT;
this.nodes = new LinkedList<>();
this.partitionId = null;
this.ruleComponent = new Stack<>();
this.attachPQN = true;
this.componentFactory = kBase.getConfiguration().getComponentFactory();
this.emptyForAllBetaConstraints = false;
}
public boolean isEmptyForAllBetaConstraints() {
return emptyForAllBetaConstraints;
}
void setEmptyForAllBetaConstraints() {
this.emptyForAllBetaConstraints = true;
}
/**
* @return the currentPatternOffset
*/
public int getCurrentPatternOffset() {
return this.currentPatternOffset;
}
/**
* @param currentPatternIndex the currentPatternOffset to set
*/
void setCurrentPatternOffset(final int currentPatternIndex) {
this.currentPatternOffset = currentPatternIndex;
this.syncObjectTypesWithPatternOffset();
}
private void syncObjectTypesWithPatternOffset() {
if (this.objectType == null) {
this.objectType = new LinkedList<>();
}
while (this.objectType.size() > this.currentPatternOffset) {
this.objectType.removeLast();
}
}
/**
* @return the objectSource
*/
public ObjectSource getObjectSource() {
return this.objectSource;
}
/**
* @param objectSource the objectSource to set
*/
public void setObjectSource(final ObjectSource objectSource) {
this.objectSource = objectSource;
}
/**
* @return the objectType
*/
public LinkedList<Pattern> getObjectType() {
if (this.objectType == null) {
this.objectType = new LinkedList<>();
}
return this.objectType;
}
/**
* @param objectType the objectType to set
*/
public void setObjectType(final LinkedList<Pattern> objectType) {
if (this.objectType == null) {
this.objectType = new LinkedList<>();
}
this.objectType = objectType;
}
/**
* @return the tupleSource
*/
public LeftTupleSource getTupleSource() {
return this.tupleSource;
}
/**
* @param tupleSource the tupleSource to set
*/
public void setTupleSource(final LeftTupleSource tupleSource) {
this.tupleSource = tupleSource;
}
public void incrementCurrentPatternOffset() {
this.currentPatternOffset++;
}
public void decrementCurrentPatternOffset() {
this.currentPatternOffset--;
this.syncObjectTypesWithPatternOffset();
}
/**
* Returns context rulebase
*/
public InternalKnowledgeBase getKnowledgeBase() {
return this.kBase;
}
/**
* Return the array of working memories associated with the given
* rulebase.
*/
public InternalWorkingMemory[] getWorkingMemories() {
if (this.workingMemories == null) {
this.workingMemories = this.kBase.getWorkingMemories();
}
return this.workingMemories;
}
/**
* Returns an Id for the next node
*/
public int getNextId() {
return kBase.getReteooBuilder().getIdGenerator().getNextId();
}
public int getNextId(String topic) {
return kBase.getReteooBuilder().getIdGenerator().getNextId(topic);
}
/**
* Method used to undo previous id assignment
*/
public void releaseId(NetworkNode node) {
kBase.getReteooBuilder().getIdGenerator().releaseId(rule, node);
}
/**
* Adds the rce to the build stack
*/
public void push(final RuleConditionElement rce) {
if (this.buildstack == null) {
this.buildstack = new LinkedList<>();
}
this.buildstack.addLast(rce);
}
/**
* Removes the top stack element
*/
public RuleConditionElement pop() {
if (this.buildstack == null) {
this.buildstack = new LinkedList<>();
}
return this.buildstack.removeLast();
}
/**
* Returns the top stack element without removing it
*/
public RuleConditionElement peek() {
if (this.buildstack == null) {
this.buildstack = new LinkedList<>();
}
return this.buildstack.getLast();
}
/**
* Returns a list iterator to iterate over the stacked elements
*/
ListIterator<RuleConditionElement> stackIterator() {
if (this.buildstack == null) {
this.buildstack = new LinkedList<>();
}
return this.buildstack.listIterator(this.buildstack.size());
}
public List<BetaNodeFieldConstraint> getBetaconstraints() {
return this.betaconstraints;
}
public void setBetaconstraints(final List<BetaNodeFieldConstraint> betaconstraints) {
this.betaconstraints = betaconstraints;
}
public List<AlphaNodeFieldConstraint> getAlphaConstraints() {
return alphaConstraints;
}
void setAlphaConstraints(List<AlphaNodeFieldConstraint> alphaConstraints) {
this.alphaConstraints = alphaConstraints;
}
List<XpathConstraint> getXpathConstraints() {
return xpathConstraints;
}
List<PathEndNode> getPathEndNodes() {
return pathEndNodes;
}
public void addPathEndNode(PathEndNode node) {
pathEndNodes.add(node);
}
void setXpathConstraints(List<XpathConstraint> xpathConstraints) {
this.xpathConstraints = xpathConstraints;
}
public boolean isTupleMemoryEnabled() {
return this.tupleMemoryEnabled;
}
public void setTupleMemoryEnabled(boolean hasLeftMemory) {
this.tupleMemoryEnabled = hasLeftMemory;
}
public boolean isObjectTypeNodeMemoryEnabled() {
return objectTypeNodeMemoryEnabled;
}
public void setObjectTypeNodeMemoryEnabled(boolean hasObjectTypeMemory) {
this.objectTypeNodeMemoryEnabled = hasObjectTypeMemory;
}
public boolean isQuery() {
return query;
}
/**
* @return the currentEntryPoint
*/
public EntryPointId getCurrentEntryPoint() {
return currentEntryPoint;
}
/**
* @param currentEntryPoint the currentEntryPoint to set
*/
public void setCurrentEntryPoint(EntryPointId currentEntryPoint) {
this.currentEntryPoint = currentEntryPoint;
}
/**
* @return the nodes
*/
public List<BaseNode> getNodes() {
return nodes;
}
BaseNode getLastNode() {
return nodes.get(nodes.size()-1);
}
/**
* @param nodes the nodes to set
*/
public void setNodes(List<BaseNode> nodes) {
this.nodes = nodes;
}
/**
* @return the partitionId
*/
public RuleBasePartitionId getPartitionId() {
return partitionId;
}
/**
* @param partitionId the partitionId to set
*/
public void setPartitionId(RuleBasePartitionId partitionId) {
this.partitionId = partitionId;
}
public boolean isStreamMode() {
// eager rules don't need to use the event queue
return this.temporal != null && !rule.isEager();
}
public long getExpirationOffset(Pattern pattern) {
return temporal != null ? temporal.getExpirationOffset( pattern ) : NEVER_EXPIRES;
}
void setTemporalDistance(TemporalDependencyMatrix temporal) {
this.temporal = temporal;
}
public RuleImpl getRule() {
return rule;
}
public void setRule(RuleImpl rule) {
this.rule = rule;
if (rule.isQuery()) {
this.query = true;
}
}
public GroupElement getSubRule() {
return subRule;
}
void setSubRule(GroupElement subRule) {
this.subRule = subRule;
}
/**
* Removes the top element from the rule component stack.
* The rule component stack is used to add trackability to
* the ReteOO nodes so that they can be linked to the rule
* components that originated them.
*/
public RuleComponent popRuleComponent() {
return this.ruleComponent.pop();
}
/**
* Peeks at the top element from the rule component stack.
* The rule component stack is used to add trackability to
* the ReteOO nodes so that they can be linked to the rule
* components that originated them.
*/
public RuleComponent peekRuleComponent() {
return this.ruleComponent.isEmpty() ? null : this.ruleComponent.peek();
}
/**
* Adds the ruleComponent to the top of the rule component stack.
* The rule component stack is used to add trackability to
* the ReteOO nodes so that they can be linked to the rule
* components that originated them.
*/
public void pushRuleComponent(RuleComponent ruleComponent) {
this.ruleComponent.push(ruleComponent);
}
public ObjectTypeNode getRootObjectTypeNode() {
return rootObjectTypeNode;
}
public void setRootObjectTypeNode(ObjectTypeNode source) {
rootObjectTypeNode = source;
}
public Pattern[] getLastBuiltPatterns() {
return lastBuiltPatterns;
}
public void setLastBuiltPattern(Pattern lastBuiltPattern) {
if (this.lastBuiltPatterns == null) {
this.lastBuiltPatterns = new Pattern[]{lastBuiltPattern, null};
} else {
this.lastBuiltPatterns[1] = this.lastBuiltPatterns[0];
this.lastBuiltPatterns[0] = lastBuiltPattern;
}
}
boolean isAttachPQN() {
return attachPQN;
}
void setAttachPQN(final boolean attachPQN) {
this.attachPQN = attachPQN;
}
public KieComponentFactory getComponentFactory() {
return componentFactory;
}
boolean isTerminated() {
return terminated;
}
void setTerminated(boolean terminated) {
this.terminated = terminated;
}
public String getConsequenceName() {
return consequenceName;
}
public void setConsequenceName( String consequenceName ) {
this.consequenceName = consequenceName;
}
}