blob: ef14c650e53d8c7cee7e86b070aa467be9e9cacf [file] [log] [blame]
/*****************************************************************************
* Copyright (c) 2013 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.cosimulation.semantics;
// Imports
import java.util.ArrayList;
import java.util.List;
import org.eclipse.papyrus.moka.composites.Semantics.impl.Actions.IntermediateActions.CS_AddStructuralFeatureValueActionActivation;
import org.eclipse.papyrus.moka.composites.Semantics.impl.CompositeStructures.StructuredClasses.CS_InteractionPoint;
import org.eclipse.papyrus.moka.composites.Semantics.impl.CompositeStructures.StructuredClasses.CS_Link;
import org.eclipse.papyrus.moka.composites.interfaces.Semantics.CompositeStructures.StructuredClasses.ICS_InteractionPoint;
import org.eclipse.papyrus.moka.composites.interfaces.Semantics.CompositeStructures.StructuredClasses.ICS_Link;
import org.eclipse.papyrus.moka.composites.interfaces.Semantics.CompositeStructures.StructuredClasses.ICS_Reference;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.IFeatureValue;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.ILink;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.IReference;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.IStructuredValue;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.IUnlimitedNaturalValue;
import org.eclipse.papyrus.moka.fuml.Semantics.Classes.Kernel.IValue;
import org.eclipse.papyrus.moka.fuml.Semantics.impl.Loci.LociL1.ChoiceStrategy;
import org.eclipse.uml2.uml.AddStructuralFeatureValueAction;
import org.eclipse.uml2.uml.Association;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.StructuralFeature;
public class CosimulationAddStructuralFeatureValueActionActivation extends CS_AddStructuralFeatureValueActionActivation {
@Override
public void doAction() {
// If the feature is a port and the input value to be added is a
// Reference,
// Replaces this Reference by an InteractionPoint, and then behaves
// as usual.
// If the feature is not a port, behaves as usual
AddStructuralFeatureValueAction action = (AddStructuralFeatureValueAction) (this.node);
StructuralFeature feature = action.getStructuralFeature();
if ((!(feature instanceof Port)) || isCosimulationPort(feature)) {
// Behaves as usual
this.doActionDefault();
} else {
List<IValue> inputValues = this.takeTokens(action.getValue());
// NOTE: Multiplicity of the value input pin is required to be 1..1.
IValue inputValue = inputValues.get(0);
if (inputValue instanceof IReference) {
// First constructs an InteractionPoint from the inputValue
IReference reference = (IReference) inputValue;
ICS_InteractionPoint interactionPoint = new CS_InteractionPoint();
interactionPoint.setReferent(reference.getReferent());
interactionPoint.setDefiningPort((Port) feature);
// The value on action.object is necessarily instanceof
// ReferenceToCompositeStructure (otherwise, the feature cannot
// be a port)
ICS_Reference owner = (ICS_Reference) this.takeTokens(action.getObject()).get(0);
interactionPoint.setOwner(owner);
// Then replaces the Reference by an InteractionPoint
// in the inputValues
inputValues.remove(0);
inputValues.add(0, interactionPoint);
// Finally concludes with usual fUML behavior of
// AddStructuralFeatureValueAction (i.e., the usual behavior
// when
// the value on action.object pin is a StructuredValue)
Integer insertAt = 0;
if (action.getInsertAt() != null) {
insertAt = ((IUnlimitedNaturalValue) this.takeTokens(action.getInsertAt()).get(0)).getValue();
}
if (action.isReplaceAll()) {
owner.setFeatureValue(feature, inputValues, 0);
} else {
IFeatureValue featureValue = owner.getFeatureValue(feature);
if (featureValue.getValues().size() > 0 & insertAt == 0) {
// If there is no insertAt pin, then the structural
// feature must
// be unordered, and the insertion position is
// immaterial.
insertAt = ((ChoiceStrategy) this.getExecutionLocus().getFactory().getStrategy("choice")).choose(featureValue.getValues().size());
}
if (feature.isUnique()) {
// Remove any existing value that duplicates the input
// value
Integer j = position(interactionPoint, featureValue.getValues(), 1);
if (j > 0) {
featureValue.getValues().remove(j - 1);
if (insertAt > 0 & j < insertAt) {
insertAt = insertAt - 1;
}
}
}
if (insertAt <= 0) {
// Note: insertAt = -1 indicates an unlimited value of
// "*"
featureValue.getValues().add(interactionPoint);
} else {
featureValue.getValues().add(insertAt - 1, interactionPoint);
}
}
if (action.getResult() != null) {
this.putToken(action.getResult(), owner);
}
} else {
// behaves as usual
this.doActionDefault();
}
}
}
protected boolean isCosimulationPort(StructuralFeature property) {
return property.getAppliedStereotype("FmiMLProfile::UML_port") != null;
}
public void doActionDefault() {
// Get the values of the object and value input pins.
// If the given feature is an association end, then create a link
// between the object and value inputs.
// Otherwise, if the object input is a structural value, then add a
// value to the values for the feature.
// If isReplaceAll is true, first remove all current matching links or
// feature values.
// If isReplaceAll is false and there is an insertAt pin, insert the
// value at the appropriate position.
// This operation captures same semantics as fUML
// AddStructuralFeatureValueActionActivation.doAction(), except that
// when the feature is an association end, a CS_Link will be created instead
// of a Link
AddStructuralFeatureValueAction action = (AddStructuralFeatureValueAction) (this.node);
StructuralFeature feature = action.getStructuralFeature();
Association association = this.getAssociation(feature);
IValue value = this.takeTokens(action.getObject()).get(0);
List<IValue> inputValues = this.takeTokens(action.getValue());
// NOTE: Multiplicity of the value input pin is required to be 1..1.
IValue inputValue = inputValues.get(0);
int insertAt = 0;
if (action.getInsertAt() != null) {
insertAt = ((IUnlimitedNaturalValue) this.takeTokens(action.getInsertAt()).get(0)).getValue();
}
if (association != null) {
List<ILink> links = this.getMatchingLinks(association, feature, value);
Property oppositeEnd = this.getOppositeEnd(association, feature);
int position = 0;
if (oppositeEnd.isOrdered()) {
position = -1;
}
if (action.isReplaceAll()) {
for (int i = 0; i < links.size(); i++) {
ILink link = links.get(i);
link.destroy();
}
} else if (feature.isUnique()) {
for (int i = 0; i < links.size(); i++) {
ILink link = links.get(i);
IFeatureValue featureValue = link.getFeatureValue(feature);
if (featureValue.getValues().get(0).equals(inputValue)) {
position = link.getFeatureValue(oppositeEnd).getPosition();
if (insertAt > 0 & featureValue.getPosition() < insertAt) {
insertAt = insertAt - 1;
}
link.destroy();
}
}
}
ICS_Link newLink = new CS_Link();
newLink.setType(association);
// This necessary when setting a feature value with an insertAt
// position
newLink.setLocus(this.getExecutionLocus());
newLink.setFeatureValue(feature, inputValues, insertAt);
List<IValue> oppositeValues = new ArrayList<IValue>();
oppositeValues.add(value);
newLink.setFeatureValue(oppositeEnd, oppositeValues, position);
newLink.getLocus().add(newLink);
} else if (value instanceof IStructuredValue) {
IStructuredValue structuredValue = (IStructuredValue) value;
if (action.isReplaceAll()) {
structuredValue.setFeatureValue(feature, inputValues, 0);
} else {
IFeatureValue featureValue = structuredValue.getFeatureValue(feature);
if (featureValue.getValues().size() > 0 & insertAt == 0) {
// *** If there is no insertAt pin, then the structural
// feature must be unordered, and the insertion position is
// immaterial. ***
insertAt = ((ChoiceStrategy) this.getExecutionLocus().getFactory().getStrategy("choice")).choose(featureValue.getValues().size());
}
if (feature.isUnique()) {
// Remove any existing value that duplicates the input value
int j = position(inputValue, featureValue.getValues(), 1);
if (j > 0) {
featureValue.getValues().remove(j - 1);
if (insertAt > 0 & j < insertAt) {
insertAt = insertAt - 1;
}
}
}
if (insertAt <= 0) { // Note: insertAt = -1 indicates an
// unlimited value of "*"
featureValue.getValues().add(inputValue);
} else {
featureValue.getValues().add(insertAt - 1, inputValue);
}
}
}
if (action.getResult() != null) {
this.putToken(action.getResult(), value);
}
}
}