blob: 09998aa2286b6065949d8d03286cb4a695c83dd8 [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.pscs.actions;
// Imports
import java.util.ArrayList;
import java.util.List;
import org.eclipse.papyrus.moka.fuml.actions.CallOperationActionActivation;
import org.eclipse.papyrus.moka.fuml.commonbehavior.IExecution;
import org.eclipse.papyrus.moka.fuml.loci.ILocus;
import org.eclipse.papyrus.moka.fuml.simpleclassifiers.IValue;
import org.eclipse.papyrus.moka.fuml.structuredclassifiers.IObject_;
import org.eclipse.papyrus.moka.pscs.actions.ICS_CallOperationActionActivation;
import org.eclipse.papyrus.moka.pscs.structuredclassifiers.CS_Reference;
import org.eclipse.papyrus.moka.pscs.structuredclassifiers.ICS_Reference;
import org.eclipse.uml2.uml.CallOperationAction;
import org.eclipse.uml2.uml.Interface;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Operation;
import org.eclipse.uml2.uml.OutputPin;
import org.eclipse.uml2.uml.Parameter;
import org.eclipse.uml2.uml.ParameterDirectionKind;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Stereotype;
public class CS_CallOperationActionActivation extends CallOperationActionActivation implements ICS_CallOperationActionActivation {
@Override
public void doAction() {
CallOperationAction action = (CallOperationAction) (this.node);
// First determines if this is a call to a constructor and if a default
// construction strategy needs to be applied.
// This is a call to a constructor if the called operation has
// stereotype <<Create>> applied.
// The default construction strategy is used if no method is associated with the
// <<Create>> operation.
// Otherwise, behaves as in fUML.
if (action.getOnPort() == null && this.isCreate(action.getOperation()) && action.getOperation().getMethods().size() == 0) {
ILocus locus = this.getExecutionLocus();
CS_ConstructStrategy strategy = ((CS_ConstructStrategy) locus.getFactory().getStrategy("constructStrategy"));
IValue target = this.takeTokens(action.getTarget()).get(0);
if (target instanceof CS_Reference) {
strategy.construct(action.getOperation(), ((CS_Reference) target).compositeReferent);
List<Parameter> parameters = action.getOperation().getOwnedParameters();
List<OutputPin> resultPins = action.getResults();
List<IValue> values = new ArrayList<IValue>();
values.add(target);
int i = 1;
while (i <= parameters.size()) {
Parameter parameter = parameters.get(i - 1);
if (parameter.getDirection() == ParameterDirectionKind.RETURN_LITERAL) {
OutputPin resultPin = resultPins.get(0);
this.putTokens(resultPin, values);
}
i = i + 1;
}
}
} else {
super.doAction();
}
}
@Override
public IExecution getCallExecution() {
// If onPort is not specified, behaves like in fUML
// If onPort is specified, and if the value on the target input pin is a
// reference, dispatch the operation
// to it and return the resulting execution object.
// As compared to fUML, instead of dispatching directly to target reference
// by calling operation dispatch:
// - If the invoked BehavioralFeature is on a provided Interface but not on any required Interface,
// then, when the InvocationAction is executed, the invocation is made into the object given on
// the target InputPin through the given Port
// - If the invoked BehavioralFeature is on a required Interface but not on any provided Interface,
// then, if the InvocationAction is being executed inside the object given on the target InputPin,
// the invocation is forwarded out of the target object through the given Port.
// - If the invoked BehavioralFeature is on both a provided and a required Interface,
// then, if the InvocationAction is being executed inside the object given on the target InputPin,
// the invocation is made out of the target object through the given Port.
// Otherwise the invocation is made into the target object through the given Port.
CallOperationAction action = (CallOperationAction) (this.node);
IExecution execution = null;
if (action.getOnPort() == null) {
execution = super.getCallExecution();
} else {
IValue target = this.takeTokens(action.getTarget()).get(0);
if (target instanceof CS_Reference) {
// Tries to determine if the operation call has to be
// dispatched to the environment or to the internals of
// target, through onPort
ICS_Reference targetReference = (CS_Reference) target;
IObject_ executionContext = this.group.getActivityExecution().getContext();
boolean operationIsOnProvidedInterface = this.isOperationProvided(action.getOnPort(), action.getOperation());
boolean operationIsOnRequiredInterface = this.isOperationRequired(action.getOnPort(), action.getOperation());
// Operation on a provided interface only
if (operationIsOnProvidedInterface && !operationIsOnRequiredInterface) {
execution = targetReference.dispatchIn(action.getOperation(), action.getOnPort());
}
// Operation is on a required interface only
else if (!operationIsOnProvidedInterface && operationIsOnRequiredInterface) {
// If not executing in the context of the target,
// Semantics are undefined.
// Otherwise, dispatch outside.
if (executionContext == targetReference.getReferent() || targetReference.getCompositeReferent().contains(executionContext)) {
execution = targetReference.dispatchOut(action.getOperation(), action.getOnPort());
}
}
// Operation is both on a provided and a required interface
else if (operationIsOnProvidedInterface && operationIsOnRequiredInterface) {
if (executionContext == targetReference.getReferent() || targetReference.getCompositeReferent().contains(executionContext)) {
execution = targetReference.dispatchOut(action.getOperation(), action.getOnPort());
} else {
execution = targetReference.dispatchIn(action.getOperation(), action.getOnPort());
}
}
}
}
return execution;
}
public boolean isOperationProvided(Port port, Operation operation) {
boolean isProvided = false;
if (operation.getOwner() instanceof Interface) {
// We have to look in provided interfaces of the port if
// they define directly or indirectly the Operation
Integer interfaceIndex = 1;
// Iterates on provided interfaces of the port
List<Interface> providedInterfaces = port.getProvideds();
while (interfaceIndex <= providedInterfaces.size() && !isProvided) {
Interface interface_ = providedInterfaces.get(interfaceIndex - 1);
// Iterates on members of the current Interface
Integer memberIndex = 1;
while (memberIndex <= interface_.getMembers().size() && !isProvided) {
NamedElement cddOperation = interface_.getMembers().get(memberIndex - 1);
if (cddOperation instanceof Operation) {
isProvided = operation == cddOperation;
}
memberIndex = memberIndex + 1;
}
interfaceIndex = interfaceIndex + 1;
}
}
return isProvided;
}
public boolean isOperationRequired(Port port, Operation operation) {
boolean isRequired = false;
Integer interfaceIndex = 1;
// Iterates on provided interfaces of the port
List<Interface> requiredInterfaces = port.getRequireds();
while (interfaceIndex <= requiredInterfaces.size() && !isRequired) {
Interface interface_ = requiredInterfaces.get(interfaceIndex - 1);
// Iterates on members of the current Interface
Integer memberIndex = 1;
while (memberIndex <= interface_.getMembers().size() && !isRequired) {
NamedElement cddOperation = interface_.getMembers().get(memberIndex - 1);
if (cddOperation instanceof Operation) {
isRequired = operation == cddOperation;
}
memberIndex = memberIndex + 1;
}
interfaceIndex = interfaceIndex + 1;
}
return isRequired;
}
public boolean isCreate(Operation o) {
// FIXME This code is Eclipse specific
// How to handle this in the spec?
List<Stereotype> appliedStereotypes = o.getAppliedStereotypes();
int i = 0;
boolean isCreate = false;
while (i < appliedStereotypes.size() && !isCreate) {
Stereotype s = appliedStereotypes.get(i);
if (s.getName().equals("Create")) {
isCreate = true;
}
}
return isCreate;
}
}