/*
* Initial version copyright 2008 Lockheed Martin Corporation, except
* as stated in the file entitled Licensing-Information.
*
* All modifications copyright 2009-2012 Data Access Technologies, Inc.
*
* Licensed under the Academic Free License version 3.0
* (http://www.opensource.org/licenses/afl-3.0.php), except as stated
* in the file entitled Licensing-Information.
*/
package fUML.Semantics.Activities.IntermediateActivities;
import fUML.Debug;
import UMLPrimitiveTypes.*;
import fUML.Syntax.*;
import fUML.Syntax.Classes.Kernel.*;
import fUML.Syntax.CommonBehaviors.BasicBehaviors.*;
import fUML.Syntax.CommonBehaviors.Communications.*;
import fUML.Syntax.Activities.IntermediateActivities.*;
import fUML.Syntax.Actions.BasicActions.*;
import fUML.Semantics.*;
import fUML.Semantics.Classes.Kernel.*;
import fUML.Semantics.CommonBehaviors.BasicBehaviors.*;
import fUML.Semantics.Actions.BasicActions.*;
import fUML.Semantics.Loci.*;
public class DecisionNodeActivation extends
fUML.Semantics.Activities.IntermediateActivities.ControlNodeActivation {
public fUML.Semantics.CommonBehaviors.BasicBehaviors.Execution decisionInputExecution = null;
public void fire(
fUML.Semantics.Activities.IntermediateActivities.TokenList incomingTokens) {
// Get the decision values and test them on each guard.
// Forward the offer over the edges for which the test succeeds.
Debug.println("[fire] Decision node " + this.node.name + "...");
// TokenList incomingTokens = this.takeOfferedTokens();
TokenList removedControlTokens = this
.removeJoinedControlTokens(incomingTokens);
ValueList decisionValues = this.getDecisionValues(incomingTokens);
ActivityEdgeInstanceList outgoingEdges = this.outgoingEdges;
for (int i = 0; i < outgoingEdges.size(); i++) {
ActivityEdgeInstance edgeInstance = outgoingEdges.getValue(i);
ValueSpecification guard = edgeInstance.edge.guard;
TokenList offeredTokens = new TokenList();
for (int j = 0; j < incomingTokens.size(); j++) {
Token incomingToken = incomingTokens.getValue(j);
Value decisionValue = decisionValues.getValue(j);
if (this.test(guard, decisionValue)) {
offeredTokens.addValue(incomingToken);
}
}
if (offeredTokens.size() > 0) {
for (int j = 0; j < removedControlTokens.size(); j++) {
Token removedControlToken = removedControlTokens
.getValue(j);
offeredTokens.addValue(removedControlToken);
}
edgeInstance.sendOffer(offeredTokens);
}
}
} // fire
public fUML.Semantics.Classes.Kernel.ValueList getDecisionValues(
fUML.Semantics.Activities.IntermediateActivities.TokenList incomingTokens) {
// If there is neither a decision input flow nor a decision input
// behavior, then return the set of values from the incoming tokens.
// [In this case, the single incoming edge must be an object flow.]
// If there is a decision input flow, but no decision input behavior,
// then return a list of the decision input values equal in size to the
// number of incoming tokens.
// If there is both a decision input flow and a decision input behavior,
// then execute the decision input behavior once for each incoming token
// and return the set of resulting values.
// If the primary incoming edge is an object flow, then the value on
// each object token is passed to the decision input behavior, along
// with the decision input flow value, if any.
// If the primary incoming edge is a control flow, then the decision
// input behavior only receives the decision input flow, if any.
Value decisionInputValue = this.getDecisionInputFlowValue();
ValueList decisionValues = new ValueList();
for (int i = 0; i < incomingTokens.size(); i++) {
Token incomingToken = incomingTokens.getValue(i);
Value value = this.executeDecisionInputBehavior(incomingToken
.getValue(), decisionInputValue);
decisionValues.addValue(value);
}
// Debug.println("[getDecisionValues] " + decisionValues.size() +
// " decision value(s):");
for (int i = 0; i < decisionValues.size(); i++) {
Value decisionValue = decisionValues.getValue(i);
Debug.println("[getDecisionValues] decisionValues[" + i + "] = " + decisionValue);
}
return decisionValues;
} // getDecisionValues
public fUML.Semantics.Classes.Kernel.Value executeDecisionInputBehavior(
fUML.Semantics.Classes.Kernel.Value inputValue,
fUML.Semantics.Classes.Kernel.Value decisionInputValue) {
// Create the decision input execution from the decision input behavior.
// If the behavior has input parameter(s), set the input parameter(s) of
// the execution to the given value(s).
// Execute the decision input execution and then remove it.
// Return the value of the output parameter of the execution.
// If there is no decision input behavior, the decision input value is
// returned, if one is given, otherwise the input value is used as the
// decision value.
Debug.println("[executeDecisionBehavior] inputValue = " + inputValue);
Behavior decisionInputBehavior = ((DecisionNode) (this.node)).decisionInput;
Value decisionInputResult = null;
if (decisionInputBehavior == null) {
if (decisionInputValue != null) {
decisionInputResult = decisionInputValue;
} else {
decisionInputResult = inputValue;
}
} else {
this.decisionInputExecution = this.getExecutionLocus().factory
.createExecution(decisionInputBehavior, this
.getExecutionContext());
int i = 1;
int j = 0;
while ((j == 0 | (j == 1 & decisionInputValue != null))
& i <= decisionInputBehavior.ownedParameter.size()) {
Parameter parameter = decisionInputBehavior.ownedParameter
.getValue(i - 1);
if (parameter.direction.equals(ParameterDirectionKind.in)
| parameter.direction
.equals(ParameterDirectionKind.inout)) {
ParameterValue inputParameterValue = new ParameterValue();
inputParameterValue.parameter = parameter;
j = j + 1;
if (j == 1 && inputValue != null) {
inputParameterValue.values.addValue(inputValue);
} else {
inputParameterValue.values.addValue(decisionInputValue);
}
this.decisionInputExecution
.setParameterValue(inputParameterValue);
}
i = i + 1;
}
this.decisionInputExecution.execute();
ParameterValueList outputParameterValues = this.decisionInputExecution
.getOutputParameterValues();
decisionInputExecution.destroy();
decisionInputResult = outputParameterValues.getValue(0).values
.getValue(0);
}
return decisionInputResult;
} // executeDecisionInputBehavior
public void terminate() {
// Terminate the decision input execution, if any, and then terminate
// this activation.
if (this.decisionInputExecution != null) {
this.decisionInputExecution.terminate();
}
super.terminate();
} // terminate
public boolean isReady() {
// Check that all incoming edges have sources that are offering tokens.
// [This should be at most two incoming edges, if there is a decision
// input flow.]
int i = 1;
boolean ready = true;
while (ready & i <= this.incomingEdges.size()) {
ready = this.incomingEdges.getValue(i - 1).hasOffer();
i = i + 1;
}
return ready;
} // isReady
public fUML.Semantics.Activities.IntermediateActivities.TokenList takeOfferedTokens() {
// Get tokens from the incoming edge that is not the decision input
// flow.
ObjectFlow decisionInputFlow = ((DecisionNode) (this.node)).decisionInputFlow;
TokenList allTokens = new TokenList();
ActivityEdgeInstanceList incomingEdges = this.incomingEdges;
for (int i = 0; i < incomingEdges.size(); i++) {
ActivityEdgeInstance edgeInstance = incomingEdges.getValue(i);
if (edgeInstance.edge != decisionInputFlow) {
TokenList tokens = edgeInstance.takeOfferedTokens();
for (int j = 0; j < tokens.size(); j++) {
allTokens.addValue(tokens.getValue(j));
}
}
}
return allTokens;
} // takeOfferedTokens
public fUML.Semantics.Classes.Kernel.Value getDecisionInputFlowValue() {
// Take the next token available on the decision input flow, if any, and
// return its value.
ActivityEdgeInstance decisionInputFlowInstance = this
.getDecisionInputFlowInstance();
Value value = null;
if (decisionInputFlowInstance != null) {
TokenList tokens = decisionInputFlowInstance.takeOfferedTokens();
if (tokens.size() > 0) {
value = tokens.getValue(0).getValue();
}
}
return value;
} // getDecisionInputFlowValue
public fUML.Semantics.Activities.IntermediateActivities.ActivityEdgeInstance getDecisionInputFlowInstance() {
// Get the activity edge instance for the decision input flow, if any.
ActivityEdge decisionInputFlow = ((DecisionNode) (this.node)).decisionInputFlow;
ActivityEdgeInstance edgeInstance = null;
if (decisionInputFlow != null) {
int i = 1;
while (edgeInstance == null & i <= this.incomingEdges.size()) {
ActivityEdgeInstance incomingEdge = this.incomingEdges
.getValue(i - 1);
if (incomingEdge.edge == decisionInputFlow) {
edgeInstance = incomingEdge;
}
i = i + 1;
}
}
return edgeInstance;
} // getDecisionInputFlowInstance
public boolean test(fUML.Syntax.Classes.Kernel.ValueSpecification guard,
fUML.Semantics.Classes.Kernel.Value value) {
// Test if the given value matches the guard. If there is no guard,
// return true.
boolean guardResult = true;
if (guard != null) {
Value guardValue = this.getExecutionLocus().executor
.evaluate(guard);
guardResult = guardValue.equals(value);
}
return guardResult;
} // test
public fUML.Semantics.Activities.IntermediateActivities.TokenList removeJoinedControlTokens(
fUML.Semantics.Activities.IntermediateActivities.TokenList incomingTokens) {
// If the primary incoming edge is an object flow, then remove any
// control tokens from the incoming tokens and return them.
// [Control tokens may effectively be offered on an object flow outgoing
// from a join node that has both control and object flows incoming.]
TokenList removedControlTokens = new TokenList();
if (this.hasObjectFlowInput()) {
int i = 1;
while (i <= incomingTokens.size()) {
Token token = incomingTokens.getValue(i - 1);
if (token.isControl()) {
removedControlTokens.addValue(token);
incomingTokens.removeValue(i - 1);
i = i - 1;
}
i = i + 1;
}
}
return removedControlTokens;
} // removeJoinedControlTokens
public boolean hasObjectFlowInput() {
// Check that the primary incoming edge is an object flow.
ActivityEdge decisionInputFlow = ((DecisionNode) (this.node)).decisionInputFlow;
boolean isObjectFlow = false;
int i = 1;
while (!isObjectFlow & i <= this.incomingEdges.size()) {
ActivityEdge edge = this.incomingEdges.getValue(i - 1).edge;
isObjectFlow = edge != decisionInputFlow
& edge instanceof ObjectFlow;
i = i + 1;
}
return isObjectFlow;
} // hasObjectFlowInput
} // DecisionNodeActivation