}
//we only have to clone the head fact to make sure the graph is not affected during consequence reads after a modify
final ReteTuple cloned = new ReteTuple( tuple );
final InternalAgenda agenda = (InternalAgenda) workingMemory.getAgenda();
final Duration dur = this.rule.getDuration();
if ( dur != null && dur.getDuration( tuple ) > 0 ) {
final ScheduledAgendaItem item = new ScheduledAgendaItem( context.getPropagationNumber(),
cloned,
agenda,
context,
this.rule,
this.subrule );
final TerminalNodeMemory memory = (TerminalNodeMemory) workingMemory.getNodeMemory( this );
if ( this.rule.getActivationGroup() != null ) {
// Lazy cache activationGroup
if ( memory.getActivationGroup() == null ) {
memory.setActivationGroup( workingMemory.getAgenda().getActivationGroup( this.rule.getActivationGroup() ) );
}
memory.getActivationGroup().addActivation( item );
}
agenda.scheduleItem( item );
tuple.setActivation( item );
if ( this.tupleMemoryEnabled ) {
memory.getTupleMemory().add( tuple );
}
item.setActivated( true );
((EventSupport) workingMemory).getAgendaEventSupport().fireActivationCreated( item,
workingMemory );
} else {
// -----------------
// Lazy instantiation and addition to the Agenda of AgendGroup
// implementations
// ----------------
final TerminalNodeMemory memory = (TerminalNodeMemory) workingMemory.getNodeMemory( this );
InternalAgendaGroup agendaGroup = memory.getAgendaGroup();
if ( agendaGroup == null ) {
// @todo: this logic really should be encapsulated inside the Agenda
if ( this.rule.getAgendaGroup() == null || this.rule.getAgendaGroup().equals( "" ) || this.rule.getAgendaGroup().equals( AgendaGroup.MAIN ) ) {
// Is the Rule AgendaGroup undefined? If it is use MAIN,
// which is added to the Agenda by default
agendaGroup = (InternalAgendaGroup) agenda.getAgendaGroup( AgendaGroup.MAIN );
} else {
// AgendaGroup is defined, so try and get the AgendaGroup
// from the Agenda
agendaGroup = (InternalAgendaGroup) agenda.getAgendaGroup( this.rule.getAgendaGroup() );
}
memory.setAgendaGroup( agendaGroup );
}
// set the focus if rule autoFocus is true
if ( this.rule.getAutoFocus() ) {
agenda.setFocus( agendaGroup );
}
final AgendaItem item = new AgendaItem( context.getPropagationNumber(),
cloned,
rule.getSalience().getValue( tuple, workingMemory ),
context,
this.rule,
this.subrule );
if ( this.tupleMemoryEnabled ) {
item.setSequenence( this.sequence );
}
if ( this.rule.getActivationGroup() != null ) {
// Lazy cache activationGroup
if ( memory.getActivationGroup() == null ) {
memory.setActivationGroup( workingMemory.getAgenda().getActivationGroup( this.rule.getActivationGroup() ) );
}
memory.getActivationGroup().addActivation( item );
}
item.setAgendaGroup( agendaGroup );
if ( this.rule.getRuleFlowGroup() == null ) {
// No RuleFlowNode so add it directly to the Agenda
// do not add the activation if the rule is "lock-on-active" and the AgendaGroup is active
// we must check the context to determine if its a new tuple or an exist re-activated tuple as part of the retract
if ( context.getType() == PropagationContext.MODIFICATION ) {
if ( this.rule.isLockOnActive() && agendaGroup.isActive() ) {
Activation justifier = context.removeRetractedTuple( this.rule,
tuple );
if ( justifier == null ) {
// This rule is locked and active, do not allow new tuples to activate
return;
} else if ( this.rule.hasLogicalDependency() ) {
copyLogicalDependencies( context,
workingMemory,
item,
justifier );
}
} else if ( this.rule.hasLogicalDependency() ) {
Activation justifier = context.removeRetractedTuple( this.rule,
tuple );
copyLogicalDependencies( context,
workingMemory,
item,
justifier );
}
} else if ( this.rule.isLockOnActive() && agendaGroup.isActive() ) {
return;
}
agendaGroup.add( item );
} else {
//There is a RuleFlowNode so add it there, instead of the Agenda
RuleFlowGroup rfg = memory.getRuleFlowGroup();
// Lazy cache ruleFlowGroup
if ( rfg == null ) {
rfg = workingMemory.getAgenda().getRuleFlowGroup( this.rule.getRuleFlowGroup() );
memory.setRuleFlowGroup( rfg );
}
// do not add the activation if the rule is "lock-on-active" and the RuleFlowGroup is active
// we must check the context to determine if its a new tuple or an exist re-activated tuple as part of the retract
if ( context.getType() == PropagationContext.MODIFICATION ) {
if ( this.rule.isLockOnActive() && rfg.isActive() ) {
Activation justifier = context.removeRetractedTuple( this.rule,
tuple );
if ( justifier == null ) {
// This rule is locked and active, do not allow new tuples to activate
return;
} else if ( this.rule.hasLogicalDependency() ) {
copyLogicalDependencies( context,
workingMemory,
item,
justifier );
}
} else if ( this.rule.hasLogicalDependency() ) {
Activation justifier = context.removeRetractedTuple( this.rule,
tuple );
copyLogicalDependencies( context,
workingMemory,
item,
justifier );
}
} else if ( this.rule.isLockOnActive() && rfg.isActive() ) {
return;
}
((InternalRuleFlowGroup) memory.getRuleFlowGroup()).addActivation( item );
}
tuple.setActivation( item );
memory.getTupleMemory().add( tuple );
item.setActivated( true );
// We only want to fire an event on a truly new Activation and not on an Activation as a result of a modify
if ( fireActivationCreated ) {
((EventSupport) workingMemory).getAgendaEventSupport().fireActivationCreated( item,
workingMemory );
}
}
agenda.increaseActiveActivations();
}