| /***************************************************************************** |
| * 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; |
| } |
| } |