/*
* 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.core.reteoo;
import org.drools.core.base.mvel.MVELSalienceExpression;
import org.drools.core.common.ActivationsFilter;
import org.drools.core.common.CompositeDefaultAgenda;
import org.drools.core.common.InternalAgenda;
import org.drools.core.common.InternalAgendaGroup;
import org.drools.core.common.InternalWorkingMemory;
import org.drools.core.common.Memory;
import org.drools.core.definitions.rule.impl.RuleImpl;
import org.drools.core.phreak.RuleAgendaItem;
import org.drools.core.util.AbstractBaseLinkedListNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class PathMemory extends AbstractBaseLinkedListNode<Memory>
implements
Memory {
protected static final Logger log = LoggerFactory.getLogger(PathMemory.class);
protected static final boolean isLogTraceEnabled = log.isTraceEnabled();
private long linkedSegmentMask;
private long allLinkedMaskTest;
private final PathEndNode pathEndNode;
private RuleAgendaItem agendaItem;
private SegmentMemory[] segmentMemories;
private SegmentMemory segmentMemory;
public final boolean dataDriven;
public PathMemory(PathEndNode pathEndNode, InternalWorkingMemory wm) {
this.pathEndNode = pathEndNode;
this.linkedSegmentMask = 0L;
this.dataDriven = initDataDriven( wm );
}
protected boolean initDataDriven( InternalWorkingMemory wm ) {
return isRuleDataDriven( wm, getRule() );
}
protected boolean isRuleDataDriven( InternalWorkingMemory wm, RuleImpl rule ) {
return rule != null &&
( rule.isDataDriven() ||
( wm != null &&
wm.getSessionConfiguration().getForceEagerActivationFilter().accept(rule) ));
}
public PathEndNode getPathEndNode() {
return pathEndNode;
}
public RuleImpl getRule() {
return pathEndNode instanceof TerminalNode ? ((TerminalNode) pathEndNode).getRule() : null;
}
public RuleAgendaItem getRuleAgendaItem() {
return agendaItem;
}
public long getLinkedSegmentMask() {
return linkedSegmentMask;
}
public long getAllLinkedMaskTest() {
return allLinkedMaskTest;
}
public void setAllLinkedMaskTest(long allLinkedTestMask) {
this.allLinkedMaskTest = allLinkedTestMask;
}
public void linkNodeWithoutRuleNotify(long mask) {
linkedSegmentMask |= mask;
}
public void linkSegment(long mask, InternalWorkingMemory wm) {
linkedSegmentMask |= mask;
if (isLogTraceEnabled) {
if (NodeTypeEnums.isTerminalNode(getPathEndNode())) {
TerminalNode rtn = (TerminalNode) getPathEndNode();
log.trace(" LinkSegment smask={} rmask={} name={}", mask, linkedSegmentMask, rtn.getRule().getName());
} else {
log.trace(" LinkSegment smask={} rmask={} name={}", mask, "RiaNode");
}
}
if (isRuleLinked()) {
doLinkRule(wm);
}
}
public RuleAgendaItem getOrCreateRuleAgendaItem(InternalAgenda agenda) {
ensureAgendaItemCreated(agenda);
return agendaItem;
}
private TerminalNode ensureAgendaItemCreated(InternalAgenda agenda) {
TerminalNode rtn = (TerminalNode) getPathEndNode();
if (agendaItem == null) {
int salience = ( rtn.getRule().getSalience() instanceof MVELSalienceExpression)
? 0
: rtn.getRule().getSalience().getValue(null, rtn.getRule(), agenda.getWorkingMemory());
agendaItem = agenda.createRuleAgendaItem(salience, this, rtn);
}
return rtn;
}
public void doLinkRule(InternalWorkingMemory wm) {
doLinkRule( getActualAgenda( wm ) );
}
public void doLinkRule(InternalAgenda agenda) {
TerminalNode rtn = ensureAgendaItemCreated(agenda);
if (isLogTraceEnabled) {
log.trace(" LinkRule name={}", rtn.getRule().getName());
}
queueRuleAgendaItem(agenda);
}
public void doUnlinkRule(InternalWorkingMemory wm) {
doUnlinkRule( getActualAgenda( wm ) );
}
public void doUnlinkRule(InternalAgenda agenda) {
TerminalNode rtn = ensureAgendaItemCreated(agenda);
if (isLogTraceEnabled) {
log.trace(" UnlinkRule name={}", rtn.getRule().getName());
}
agendaItem.getRuleExecutor().setDirty(true);
if ( !agendaItem.isQueued() ) {
if ( isLogTraceEnabled ) {
log.trace("Queue RuleAgendaItem {}", agendaItem);
}
InternalAgendaGroup ag = agendaItem.getAgendaGroup();
ag.add( agendaItem );
}
}
public void queueRuleAgendaItem(InternalAgenda agenda) {
agendaItem.getRuleExecutor().setDirty(true);
ActivationsFilter activationFilter = agenda.getActivationsFilter();
if ( activationFilter != null && !activationFilter.accept( agendaItem,
agenda.getWorkingMemory(),
agendaItem.getTerminalNode() ) ) {
return;
}
if ( !agendaItem.isQueued() ) {
if ( isLogTraceEnabled ) {
log.trace("Queue RuleAgendaItem {}", agendaItem);
}
InternalAgendaGroup ag = agendaItem.getAgendaGroup();
ag.add( agendaItem );
}
if ( agendaItem.getRule().isQuery() ) {
agenda.addQueryAgendaItem( agendaItem );
} else if ( agendaItem.getRule().isEager() ) {
agenda.addEagerRuleAgendaItem( agendaItem );
}
}
public void unlinkedSegment(long mask, InternalWorkingMemory wm) {
boolean linkedRule = isRuleLinked();
linkedSegmentMask ^= mask;
if (isLogTraceEnabled) {
log.trace(" UnlinkSegment smask={} rmask={} name={}", mask, linkedSegmentMask, this);
}
if (linkedRule && !isRuleLinked()) {
doUnlinkRule(wm);
}
}
public boolean isRuleLinked() {
return (linkedSegmentMask & allLinkedMaskTest) == allLinkedMaskTest;
}
public boolean isDataDriven() {
return dataDriven;
}
public short getNodeType() {
return NodeTypeEnums.RuleTerminalNode;
}
public boolean isInitialized() {
return agendaItem != null && segmentMemories[0] != null;
}
public SegmentMemory[] getSegmentMemories() {
return segmentMemories;
}
public void setSegmentMemory(int index, SegmentMemory sm) {
this.segmentMemories[index] = sm;
}
public void setSegmentMemories(SegmentMemory[] segmentMemories) {
this.segmentMemories = segmentMemories;
}
public SegmentMemory getSegmentMemory() {
return this.segmentMemory;
}
public void setSegmentMemory(SegmentMemory sm) {
this.segmentMemory = sm;
}
public String toString() {
return "[RuleMem " + getRule().getName() + "]";
}
public void reset() {
this.linkedSegmentMask = 0L;
}
public InternalAgenda getActualAgenda(InternalWorkingMemory wm) {
InternalAgenda agenda = wm.getAgenda();
return agenda instanceof CompositeDefaultAgenda ?
( (CompositeDefaultAgenda) agenda ).getPartitionedAgendaForNode( getPathEndNode() ) :
agenda;
}
}