blob: e4e5bfa858b8e417626bb2e2079e321d9c1b0838 [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2012 CEA LIST.
*
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* CEA LIST - Initial API and implementation
*
*****************************************************************************/
package org.eclipse.papyrus.moka.fuml.actions;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.papyrus.moka.fuml.activities.IActivityNodeActivationGroup;
import org.eclipse.papyrus.moka.fuml.activities.IToken;
import org.eclipse.papyrus.moka.fuml.debug.Debug;
import org.eclipse.uml2.uml.ExpansionKind;
import org.eclipse.uml2.uml.ExpansionNode;
import org.eclipse.uml2.uml.ExpansionRegion;
import org.eclipse.uml2.uml.InputPin;
import org.eclipse.uml2.uml.StructuredActivityNode;
public class ExpansionRegionActivation extends ActionActivation implements IExpansionRegionActivation {
/*
* The set of expansion activation groups for this expansion region activation.
* One activation group is created corresponding to each token held by the first
* input expansion node activation for the expansion region.
*/
public List<IExpansionActivationGroup> activationGroups = new ArrayList<IExpansionActivationGroup>();
/*
* The tokens taken from each of the input pin activations for this expansion
* region activation. These are preserved for initializing the region inputs of
* each of the activation groups.
*/
public List<TokenSet> inputTokens = new ArrayList<TokenSet>();
/*
* The tokens taken from each of the input expansion node activations for this
* expansion region activation. These are preserved for initializing the group
* input of each of the activation groups.
*/
public List<TokenSet> inputExpansionTokens = new ArrayList<TokenSet>();
public Integer next;
@Override
public List<IToken> takeOfferedTokens() {
// Take the tokens from the input pin and input expansion node
// activations and save them.
super.takeOfferedTokens();
ExpansionRegion region = (ExpansionRegion) (this.node);
List<InputPin> inputPins = region.getInputs();
List<ExpansionNode> inputElements = region.getInputElements();
this.inputTokens.clear();
this.inputExpansionTokens.clear();
for (int i = 0; i < inputPins.size(); i++) {
InputPin inputPin = inputPins.get(i);
TokenSet tokenSet = new TokenSet();
tokenSet.tokens = this.getPinActivation(inputPin).takeTokens();
this.inputTokens.add(tokenSet);
}
int n = this.numberOfValues();
for (int i = 0; i < inputElements.size(); i++) {
ExpansionNode inputElement = inputElements.get(i);
ExpansionNodeActivation expansionNodeActivation = this.getExpansionNodeActivation(inputElement);
expansionNodeActivation.fire(expansionNodeActivation.takeOfferedTokens());
List<IToken> tokens = expansionNodeActivation.takeTokens();
TokenSet tokenSet = new TokenSet();
int j = 1;
while (j <= n) {
tokenSet.tokens.add(tokens.get(j - 1));
j = j + 1;
}
this.inputExpansionTokens.add(tokenSet);
}
return new ArrayList<IToken>();
}
@Override
public void doAction() {
// If the expansion region has mustIsolate=true, then carry out its
// behavior with isolation.
// Otherwise just activate it normally.
if (((StructuredActivityNode) (this.node)).isMustIsolate()) {
_beginIsolation();
this.doStructuredActivity();
_endIsolation();
} else {
this.doStructuredActivity();
}
}
public void doStructuredActivity() {
// Create a number of expansion region activation groups equal to the
// number of values expanded in the region,
// setting the region inputs and group inputs for each group.
// Run the body of the region in each group, either iteratively or in
// parallel.
// Add the outputs of each activation group to the corresonding output
// expansion node activations.
ExpansionRegion region = (ExpansionRegion) this.node;
List<InputPin> inputPins = region.getInputs();
List<ExpansionNode> inputElements = region.getInputElements();
List<ExpansionNode> outputElements = region.getOutputElements();
this.activationGroups.clear();
int n = this.inputExpansionTokens.get(0).tokens.size();
int k = 1;
while (k <= n) {
IExpansionActivationGroup activationGroup = new ExpansionActivationGroup();
activationGroup.setRegionActivation(this);
activationGroup.setIndex(k);
int j = 1;
while (j <= inputPins.size()) {
OutputPinActivation regionInput = new OutputPinActivation();
regionInput.run();
activationGroup.getRegionInputs().add(regionInput);
j = j + 1;
}
j = 1;
while (j <= inputElements.size()) {
OutputPinActivation groupInput = new OutputPinActivation();
groupInput.run();
activationGroup.getGroupInputs().add(groupInput);
j = j + 1;
}
j = 1;
while (j <= outputElements.size()) {
OutputPinActivation groupOutput = new OutputPinActivation();
groupOutput.run();
activationGroup.getGroupOutputs().add(groupOutput); // fUML12-10 certain boolean flags are not properly
// initialized in come cases
j = j + 1;
}
activationGroup.createNodeActivations(region.getNodes());
activationGroup.createEdgeInstances(region.getEdges());
this.activationGroups.add(activationGroup);
k = k + 1;
}
// List<ExpansionActivationGroup> activationGroups =
// this.activationGroups;
if (region.getMode() == ExpansionKind.ITERATIVE_LITERAL) {
Debug.println("[doStructuredActivity] Expansion mode = iterative");
this.next = 1;
this.runIterative();
} else if (region.getMode() == ExpansionKind.PARALLEL_LITERAL) {
Debug.println("[doStructuredActivity] Expansion mode = parallel");
this.runParallel();
}
this.doOutput();
}
public void runIterative() {
// Run the body of the region iteratively, either until all activation
// groups have run or until the region is suspended.
List<IExpansionActivationGroup> activationGroups = this.activationGroups;
while (this.next <= activationGroups.size() & !this.isSuspended()) {
IExpansionActivationGroup activationGroup = activationGroups.get(this.next - 1);
this.runGroup(activationGroup);
this.next = this.next + 1;
}
}
public void runParallel() {
// Run the body of the region concurrently.
List<IExpansionActivationGroup> activationGroups = this.activationGroups;
// *** Activate all groups concurrently. ***
for (Iterator<IExpansionActivationGroup> i = activationGroups.iterator(); i.hasNext();) {
IExpansionActivationGroup activationGroup = i.next();
this.runGroup(activationGroup);
}
}
public void doOutput() {
// Place tokens on the output expansion nodes.
ExpansionRegion region = (ExpansionRegion) this.node;
List<ExpansionNode> outputElements = region.getOutputElements();
Debug.println("[doOutput] Expansion region " + region.getName() + " is "
+ (this.isSuspended() ? "suspended." : "completed."));
if (!this.isSuspended()) {
for (int i = 0; i < activationGroups.size(); i++) {
IExpansionActivationGroup activationGroup = activationGroups.get(i);
List<IOutputPinActivation> groupOutputs = activationGroup.getGroupOutputs();
for (int j = 0; j < groupOutputs.size(); j++) {
IOutputPinActivation groupOutput = groupOutputs.get(j);
ExpansionNode outputElement = outputElements.get(j);
this.getExpansionNodeActivation(outputElement).addTokens(groupOutput.takeTokens());
}
}
}
}
@Override
public void terminate() {
// Terminate the execution of all contained node activations (which
// completes the performance of the expansion region activation).
List<IExpansionActivationGroup> activationGroups = this.activationGroups;
for (int i = 0; i < activationGroups.size(); i++) {
IExpansionActivationGroup activationGroup = this.activationGroups.get(i);
List<IOutputPinActivation> groupOutputs = activationGroup.getGroupOutputs();
_beginIsolation();
for (int j = 0; j < groupOutputs.size(); j++) {
IOutputPinActivation groupOutput = groupOutputs.get(j);
groupOutput.fire(groupOutput.takeOfferedTokens());
}
activationGroup.terminateAll();
_endIsolation();
}
super.terminate();
}
@Override
public void sendOffers() {
// Fire all output expansion nodes and send offers on all outgoing
// control flows.
ExpansionRegion region = (ExpansionRegion) (this.node);
// *** Send offers from all output expansion nodes concurrently. ***
List<ExpansionNode> outputElements = region.getOutputElements();
for (Iterator<ExpansionNode> i = outputElements.iterator(); i.hasNext();) {
ExpansionNode outputElement = i.next();
this.getExpansionNodeActivation(outputElement).sendUnofferedTokens();
}
// Send offers on all outgoing control flows.
super.sendOffers();
}
public void runGroup(IExpansionActivationGroup activationGroup) {
// Set up the inputs for the group with the given index, run the group
// and then fire the group outputs.
if (this.isRunning()) {
Debug.println("[runGroup] groupInput[0] = "
+ this.inputExpansionTokens.get(0).tokens.get(activationGroup.getIndex() - 1).getValue());
List<TokenSet> inputTokens = this.inputTokens;
for (int j = 0; j < inputTokens.size(); j++) {
TokenSet tokenSet = inputTokens.get(j);
IOutputPinActivation regionInput = activationGroup.getRegionInputs().get(j);
regionInput.clearTokens();
regionInput.addTokens(tokenSet.tokens);
regionInput.sendUnofferedTokens();
}
List<TokenSet> inputExpansionTokens = this.inputExpansionTokens;
for (int j = 0; j < inputExpansionTokens.size(); j++) {
TokenSet tokenSet = inputExpansionTokens.get(j);
IOutputPinActivation groupInput = activationGroup.getGroupInputs().get(j);
groupInput.clearTokens();
if (tokenSet.tokens.size() >= activationGroup.getIndex()) {
groupInput.addToken(tokenSet.tokens.get(activationGroup.getIndex() - 1));
}
groupInput.sendUnofferedTokens();
}
activationGroup.run(activationGroup.getActivityNodeActivations());
this.terminateGroup(activationGroup);
}
}
public void terminateGroup(IExpansionActivationGroup activationGroup) {
// Terminate the given activation group, after preserving any group
// outputs.
if (this.isRunning() & !this.isSuspended()) {
List<IOutputPinActivation> groupOutputs = activationGroup.getGroupOutputs();
for (int i = 0; i < groupOutputs.size(); i++) {
IOutputPinActivation groupOutput = groupOutputs.get(i);
groupOutput.fire(groupOutput.takeOfferedTokens());
}
activationGroup.terminateAll();
}
}
public ExpansionNodeActivation getExpansionNodeActivation(ExpansionNode node) {
// Return the expansion node activation corresponding to the given
// expansion node, in the context of the activity node activation group
// this expansion region activation is in.
// [Note: Expansion regions do not own their expansion nodes. Instead,
// they are own as object nodes by the enclosing activity or group.
// Therefore, they will already be activated along with their expansion
// region.]
return (ExpansionNodeActivation) (this.group.getNodeActivation(node));
}
public Integer numberOfValues() {
// Return the number of values to be acted on by the expansion region of
// this activation, which is the minimum of the number of values offered
// to each of the input expansion nodes of the activation.
ExpansionRegion region = (ExpansionRegion) (this.node);
List<ExpansionNode> inputElements = region.getInputElements();
int n = this.getExpansionNodeActivation(inputElements.get(0)).countOfferedValues();
int i = 2;
while (i <= inputElements.size()) {
int count = this.getExpansionNodeActivation(inputElements.get(i - 1)).countOfferedValues();
if (count < n) {
n = count;
}
i = i + 1;
}
return n;
}
public Boolean isSuspended() {
// Check if the activation group for this node is suspended.
boolean suspended = false;
int i = 1;
while (i <= this.activationGroups.size() & !suspended) {
IActivityNodeActivationGroup group = this.activationGroups.get(i - 1);
suspended = group.isSuspended();
i = i + 1;
}
return suspended;
}
public void resume(IExpansionActivationGroup activationGroup) {
// Resume an expansion region after the suspension of the given
// activation group. If the region is iterative, then continue with the
// iteration. If the region is parallel, and there are no more suspended
// activation groups, then generate the expansion node output.
ExpansionRegion region = (ExpansionRegion) this.node;
this.resume();
this.terminateGroup(activationGroup);
if (region.getMode() == ExpansionKind.ITERATIVE_LITERAL) {
this.runIterative();
}
this.doOutput();
}
public List<IExpansionActivationGroup> getExpansionActivationGroups() {
return this.activationGroups;
}
}