/*
* Initial version copyright 2008 Lockheed Martin Corporation, except
* as stated in the file entitled Licensing-Information.
*
* All modifications copyright 2009-2017 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.Actions.BasicActions;
import fUML.Debug;
import UMLPrimitiveTypes.*;
import java.util.*;
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.Activities.IntermediateActivities.*;
import fUML.Semantics.Loci.*;
public abstract class ActionActivation extends
fUML.Semantics.Activities.IntermediateActivities.ActivityNodeActivation {
public fUML.Semantics.Actions.BasicActions.PinActivationList pinActivations = new fUML.Semantics.Actions.BasicActions.PinActivationList();
public boolean firing = false;
public void initialize(ActivityNode node, ActivityNodeActivationGroup group) {
// Initialize this action activation to be not firing.
super.initialize(node, group);
this.firing = false;
}
public void run() {
// Run this action activation and any outoging fork node attached to it.
super.run();
if (this.outgoingEdges.size() > 0) {
this.outgoingEdges.getValue(0).target.run();
}
this.firing = false;
} // run
public fUML.Semantics.Activities.IntermediateActivities.TokenList takeOfferedTokens() {
// If the action is not locally reentrant, then mark this activation as
// firing.
// Take any incoming offers of control tokens, then concurrently fire
// all input pin activations.
// Note: This is included here to happen in the same isolation scope as
// the isReady test.
this.firing = !((Action) this.node).isLocallyReentrant;
TokenList offeredTokens = new TokenList();
ActivityEdgeInstanceList incomingEdges = this.incomingEdges;
for (int i = 0; i < incomingEdges.size(); i++) {
ActivityEdgeInstance incomingEdge = incomingEdges.getValue(i);
TokenList tokens = incomingEdge.takeOfferedTokens();
for (int j = 0; j < tokens.size(); j++) {
Token token = tokens.getValue(j);
token.withdraw();
offeredTokens.addValue(token);
}
}
Action action = (Action) (this.node);
// *** Fire all input pins concurrently. ***
InputPinList inputPins = action.input;
for (Iterator i = inputPins.iterator(); i.hasNext();) {
InputPin pin = (InputPin) (i.next());
PinActivation pinActivation = this.getPinActivation(pin);
TokenList tokens = pinActivation.takeOfferedTokens();
pinActivation.fire(tokens);
for (int j = 0; j < tokens.size(); j++) {
Token token = tokens.getValue(j);
offeredTokens.addValue(token);
}
}
return offeredTokens;
} // takeOfferedTokens
public void fire(
fUML.Semantics.Activities.IntermediateActivities.TokenList incomingTokens) {
// Do the main action behavior then concurrently fire all output pin
// activations
// and offer a single control token. Then activate the action again,
// if it is still ready to fire and has at least one token actually
// being
// offered to it.
do {
Debug.println("[fire] Action " + this.node.name + "...");
Debug.println("[event] Fire activity="
+ this.getActivityExecution().getBehavior().name
+ " action=" + this.node.name);
this.doAction();
incomingTokens = this.completeAction();
} while (incomingTokens.size() > 0);
} // fire
public void terminate() {
// Terminate this action activation and any outgoing fork node attached
// to it.
super.terminate();
if (this.outgoingEdges.size() > 0) {
this.outgoingEdges.getValue(0).target.terminate();
}
} // terminate
public fUML.Semantics.Activities.IntermediateActivities.TokenList completeAction() {
// Concurrently fire all output pin activations and offer a single
// control token. Then check if the action should fire again
// and, if so, return additional incoming tokens for this.
this.sendOffers();
Debug.println("[fire] Checking if " + this.node.name + " should fire again...");
_beginIsolation();
TokenList incomingTokens = new TokenList();
this.firing = false;
if (this.isReady()) {
incomingTokens = this.takeOfferedTokens();
this.firing = this.isFiring() & incomingTokens.size() > 0;
}
_endIsolation();
return incomingTokens;
} // completeAction
public boolean isReady() {
// In addition to the default condition, check that, if the action has
// isLocallyReentrant=false, then the activation is not currently
// firing,
// and that the sources of all incoming edges (control flows) have
// offers and all input pin activations are ready.
// [This assumes that all edges directly incoming to the action are
// control flows.]
boolean ready = super.isReady()
& (((Action) this.node).isLocallyReentrant | !this.isFiring());
int i = 1;
while (ready & i <= this.incomingEdges.size()) {
ready = this.incomingEdges.getValue(i - 1).hasOffer();
i = i + 1;
}
InputPinList inputPins = ((Action) (this.node)).input;
int j = 1;
while (ready & j <= inputPins.size()) {
ready = this.getPinActivation(inputPins.getValue(j - 1)).isReady();
j = j + 1;
}
return ready;
} // isReady
public boolean isFiring() {
// Indicate whether this action activation is currently firing or not.
return firing;
} // isFiring
public abstract void doAction();
public void sendOffers() {
// Fire all output pins and send offers on all outgoing control flows.
Action action = (Action) (this.node);
// *** Send offers from all output pins concurrently. ***
OutputPinList outputPins = action.output;
for (Iterator i = outputPins.iterator(); i.hasNext();) {
OutputPin outputPin = (OutputPin) i.next();
PinActivation pinActivation = this.getPinActivation(outputPin);
pinActivation.sendUnofferedTokens();
}
// Send offers on all outgoing control flows.
if (this.outgoingEdges.size() > 0) {
TokenList tokens = new TokenList();
tokens.addValue(new ControlToken());
this.addTokens(tokens);
this.outgoingEdges.getValue(0).sendOffer(tokens);
}
} // sendOffers
public void createNodeActivations() {
// Create node activations for the input and output pins of the action
// for this activation.
// [Note: Pins are owned by their actions, not by the enclosing activity
// (or group), so they must be activated through the action activation.]
Action action = (Action) (this.node);
ActivityNodeList inputPinNodes = new ActivityNodeList();
InputPinList inputPins = action.input;
for (int i = 0; i < inputPins.size(); i++) {
InputPin inputPin = inputPins.getValue(i);
inputPinNodes.addValue(inputPin);
}
this.group.createNodeActivations(inputPinNodes);
for (int i = 0; i < inputPinNodes.size(); i++) {
ActivityNode node = inputPinNodes.getValue(i);
this.addPinActivation((PinActivation) (this.group
.getNodeActivation(node)));
}
ActivityNodeList outputPinNodes = new ActivityNodeList();
OutputPinList outputPins = action.output;
for (int i = 0; i < outputPins.size(); i++) {
OutputPin outputPin = outputPins.getValue(i);
outputPinNodes.addValue(outputPin);
}
this.group.createNodeActivations(outputPinNodes);
for (int i = 0; i < outputPinNodes.size(); i++) {
ActivityNode node = outputPinNodes.getValue(i);
this.addPinActivation((PinActivation) (this.group
.getNodeActivation(node)));
}
} // createNodeActivations
public void addOutgoingEdge(
fUML.Semantics.Activities.IntermediateActivities.ActivityEdgeInstance edge) {
// If there are no outgoing activity edge instances, create a single
// activity edge instance with a fork node execution at the other end.
// Add the give edge to the fork node execution that is the target of
// the activity edge instance out of this action execution.
// [This assumes that all edges directly outgoing from the action are
// control flows, with an implicit fork for offers out of the action.]
ActivityNodeActivation forkNodeActivation;
if (this.outgoingEdges.size() == 0) {
forkNodeActivation = new ForkNodeActivation();
forkNodeActivation.running = false;
ActivityEdgeInstance newEdge = new ActivityEdgeInstance();
super.addOutgoingEdge(newEdge);
forkNodeActivation.addIncomingEdge(newEdge);
} else {
forkNodeActivation = this.outgoingEdges.getValue(0).target;
}
forkNodeActivation.addOutgoingEdge(edge);
} // addOutgoingEdge
public void addPinActivation(
fUML.Semantics.Actions.BasicActions.PinActivation pinActivation) {
// Add a pin activation to this action activation.
this.pinActivations.addValue(pinActivation);
pinActivation.actionActivation = this;
} // addPinActivation
public fUML.Semantics.Actions.BasicActions.PinActivation getPinActivation(
fUML.Syntax.Actions.BasicActions.Pin pin) {
// Precondition: The given pin is owned by the action of the action
// activation.
// Return the pin activation corresponding to the given pin.
PinActivation pinActivation = null;
int i = 1;
while (pinActivation == null & i <= this.pinActivations.size()) {
PinActivation thisPinActivation = this.pinActivations
.getValue(i - 1);
if (thisPinActivation.node == pin) {
pinActivation = thisPinActivation;
}
i = i + 1;
}
return pinActivation;
} // getPinActivation
public void putToken(fUML.Syntax.Actions.BasicActions.OutputPin pin,
fUML.Semantics.Classes.Kernel.Value value) {
// Precondition: The action execution has fired and the given pin is
// owned by the action of the action execution.
// Place a token for the given value on the pin activation corresponding
// to the given output pin.
Debug.println("[putToken] node = " + this.node.name);
ObjectToken token = new ObjectToken();
token.value = value;
PinActivation pinActivation = this.getPinActivation(pin);
pinActivation.addToken(token);
} // putToken
public void putTokens(fUML.Syntax.Actions.BasicActions.OutputPin pin,
fUML.Semantics.Classes.Kernel.ValueList values) {
// Precondition: The action execution has fired and the given pin is
// owned by the action of the action execution.
// Place tokens for the given values on the pin activation corresponding
// to the given output pin.
// Debug.println("[putTokens] node = " + this.node.name);
for (int i = 0; i < values.size(); i++) {
Value value = values.getValue(i);
this.putToken(pin, value);
}
} // putTokens
public fUML.Semantics.Classes.Kernel.ValueList getTokens(
fUML.Syntax.Actions.BasicActions.InputPin pin) {
// Precondition: The action execution has fired and the given pin is
// owned by the action of the action execution.
// Get any tokens held by the pin activation corresponding to the given
// input pin and return them
// (but leave the tokens on the pin).
Debug.println("[getTokens] node = " + this.node.name + ", pin = " + pin.name);
PinActivation pinActivation = this.getPinActivation(pin);
TokenList tokens = pinActivation.getUnofferedTokens();
ValueList values = new ValueList();
for (int i = 0; i < tokens.size(); i++) {
Token token = tokens.getValue(i);
Value value = ((ObjectToken) token).value;
if (value != null) {
values.addValue(value);
}
}
return values;
} // getTokens
public fUML.Semantics.Classes.Kernel.ValueList takeTokens(
fUML.Syntax.Actions.BasicActions.InputPin pin) {
// Precondition: The action execution has fired and the given pin is
// owned by the action of the action execution.
// Take any tokens held by the pin activation corresponding to the given
// input pin and return them.
Debug.println("[takeTokens] node = " + this.node.name + ", pin = " + pin.name);
PinActivation pinActivation = this.getPinActivation(pin);
TokenList tokens = pinActivation.takeUnofferedTokens();
ValueList values = new ValueList();
for (int i = 0; i < tokens.size(); i++) {
Token token = tokens.getValue(i);
Value value = ((ObjectToken) token).value;
if (value != null) {
values.addValue(value);
}
}
return values;
} // takeTokens
public boolean isSourceFor(
fUML.Semantics.Activities.IntermediateActivities.ActivityEdgeInstance edgeInstance) {
// If this action has an outgoing fork node, check that the fork node is
// the source of the given edge instance.
boolean isSource = false;
if (this.outgoingEdges.size() > 0) {
isSource = this.outgoingEdges.getValue(0).target
.isSourceFor(edgeInstance);
}
return isSource;
} // isSourceFor
public boolean valueParticipatesInLink(
fUML.Semantics.Classes.Kernel.Value value,
fUML.Semantics.Classes.Kernel.Link link) {
// Test if the given value participates in the given link.
FeatureValueList linkFeatureValues = link.getFeatureValues();
boolean participates = false;
int i = 1;
while (!participates & i <= linkFeatureValues.size()) {
participates = linkFeatureValues.getValue(i - 1).values.getValue(0)
.equals(value);
i = i + 1;
}
return participates;
} // valueParticipatesInLink
public fUML.Semantics.Classes.Kernel.BooleanValue makeBooleanValue(
boolean value) {
// Make a Boolean value using the built-in Boolean primitive type.
// [This ensures that Boolean values created internally are the same as
// the default used for evaluating Boolean literals.]
LiteralBoolean booleanLiteral = new LiteralBoolean();
booleanLiteral.value = value;
return (BooleanValue) (this.getExecutionLocus().executor
.evaluate(booleanLiteral));
} // makeBooleanValue
} // ActionActivation