package org.eclipse.uml2.diagram.sequence.edit.commands;
import java.text.MessageFormat;
import java.util.ListIterator;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.gmf.runtime.common.core.command.CommandResult;
import org.eclipse.gmf.runtime.common.core.command.ICommand;
import org.eclipse.gmf.runtime.diagram.core.services.ViewService;
import org.eclipse.gmf.runtime.diagram.core.util.ViewUtil;
import org.eclipse.gmf.runtime.emf.core.util.EObjectAdapter;
import org.eclipse.gmf.runtime.emf.type.core.IElementType;
import org.eclipse.gmf.runtime.emf.type.core.commands.EditElementCommand;
import org.eclipse.gmf.runtime.emf.type.core.requests.ConfigureRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateElementRequest;
import org.eclipse.gmf.runtime.emf.type.core.requests.CreateRelationshipRequest;
import org.eclipse.gmf.runtime.notation.Diagram;
import org.eclipse.gmf.runtime.notation.Node;
import org.eclipse.gmf.runtime.notation.NotationFactory;
import org.eclipse.gmf.runtime.notation.NotationPackage;
import org.eclipse.gmf.runtime.notation.View;
import org.eclipse.uml2.diagram.common.editpolicies.U2TCreateLinkCommand;
import org.eclipse.uml2.diagram.common.editpolicies.U2TCreateParameters;
import org.eclipse.uml2.diagram.sequence.edit.policies.UMLBaseItemSemanticEditPolicy;
import org.eclipse.uml2.diagram.sequence.model.SDModelAccess;
import org.eclipse.uml2.diagram.sequence.model.builder.SDBuilder;
import org.eclipse.uml2.diagram.sequence.model.sdnotation.SDModelStorageStyle;
import org.eclipse.uml2.diagram.sequence.model.sequenced.SDBehaviorSpec;
import org.eclipse.uml2.diagram.sequence.model.sequenced.SDExecution;
import org.eclipse.uml2.diagram.sequence.model.sequenced.SDInvocation;
import org.eclipse.uml2.diagram.sequence.model.sequenced.SDTrace;
import org.eclipse.uml2.diagram.sequence.part.UMLDiagramEditorPlugin;
import org.eclipse.uml2.diagram.sequence.part.UMLVisualIDRegistry;
import org.eclipse.uml2.diagram.sequence.providers.ElementInitializers;
import org.eclipse.uml2.diagram.sequence.providers.UMLElementTypes;
import org.eclipse.uml2.uml.BehaviorExecutionSpecification;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Gate;
import org.eclipse.uml2.uml.Interaction;
import org.eclipse.uml2.uml.InteractionFragment;
import org.eclipse.uml2.uml.InteractionOperand;
import org.eclipse.uml2.uml.Lifeline;
import org.eclipse.uml2.uml.Message;
import org.eclipse.uml2.uml.MessageEnd;
import org.eclipse.uml2.uml.MessageOccurrenceSpecification;
import org.eclipse.uml2.uml.UMLFactory;
/**
* @generated
*/
public class MessageCreateCommand extends EditElementCommand {
/**
* @generated
*/
private final EObject source;
/**
* @generated
*/
private final EObject target;
/**
* @generated
*/
private final Interaction container;
/**
* @generated
*/
public MessageCreateCommand(CreateRelationshipRequest request, EObject source, EObject target) {
super(request.getLabel(), null, request);
this.source = source;
this.target = target;
container = deduceContainer(source, target);
}
/**
* @generated NOT
*/
public boolean canExecute() {
if (source == null && target == null) {
return false;
}
if (source != null && !isValidEnd(source)) {
return false;
}
if (target != null && !isValidEnd(target)) {
return false;
}
if (getSource() == null) {
return true; // link creation is in progress; source is not defined yet
}
// target may be null here but it's possible to check constraint
if (null == getContainer()) {
return false;
}
if (source instanceof InteractionOperand && target instanceof InteractionOperand) {
if (source != target) {
return false;
}
U2TCreateLinkCommand linkCreationPack = U2TCreateLinkCommand.getFromRequest(getRequest());
if (linkCreationPack == null || linkCreationPack.getSourceParameters() == null || linkCreationPack.getTargetParameters() == null) {
return false;
}
Lifeline sourceLL = findEnclosedDiagramLifeLine(linkCreationPack.getSourceParameters().getParentView());
Lifeline targetLL = findEnclosedDiagramLifeLine(linkCreationPack.getTargetParameters().getParentView());
if (sourceLL == targetLL) {
return false;
}
}
if (source == target) {
return source instanceof InteractionOperand; //self links don't supported for now
}
return UMLBaseItemSemanticEditPolicy.LinkConstraints.canCreateMessage_4001(getContainer(), getSource(), getTarget());
}
private BehaviorExecutionSpecification createBehaviorExecutionSpecification(Interaction interaction, Lifeline lifeline, int nameIndex, boolean forSource) {
String prefix = forSource ? "invocation-" : "execution-";
String withIndex = prefix + nameIndex + "-";
ThePastImpl thePast = new ThePastImpl(U2TCreateLinkCommand.getFromRequest(getRequest()));
ListIterator<InteractionFragment> listPosition = thePast.getAfterThePastPosition(interaction);
MessageOccurrenceSpecification start = doCreateMessageOccurrence(listPosition, withIndex + "start");
BehaviorExecutionSpecification result = doCreateBehaviorExecution(listPosition, withIndex + "body");
MessageOccurrenceSpecification finish = doCreateMessageOccurrence(listPosition, withIndex + "finish");
setupBehaviorSpec(result, start, finish, lifeline);
return result;
}
private BehaviorExecutionSpecification[] createBehaviorExecutionSpecificationsPair(Interaction interaction, Lifeline sourceLL, Lifeline targetLL, int messageIndex,
ListIterator<InteractionFragment> listPosition) {
String invocationPrefix = "invocation-" + messageIndex + "-";
String executionPrefix = "execution-" + messageIndex + "-";
MessageOccurrenceSpecification invocationStart = doCreateMessageOccurrence(listPosition, invocationPrefix + "start");
MessageOccurrenceSpecification executionStart = doCreateMessageOccurrence(listPosition, executionPrefix + "start");
BehaviorExecutionSpecification invocation = doCreateBehaviorExecution(listPosition, invocationPrefix + "body");
BehaviorExecutionSpecification execution = doCreateBehaviorExecution(listPosition, executionPrefix + "body");
MessageOccurrenceSpecification executionFinish = doCreateMessageOccurrence(listPosition, executionPrefix + "finish");
MessageOccurrenceSpecification invocationFinish = doCreateMessageOccurrence(listPosition, invocationPrefix + "finish");
setupBehaviorSpec(invocation, invocationStart, invocationFinish, sourceLL);
setupBehaviorSpec(execution, executionStart, executionFinish, targetLL);
return new BehaviorExecutionSpecification[] { invocation, execution };
}
private void setupBehaviorSpec(BehaviorExecutionSpecification spec, MessageOccurrenceSpecification start, MessageOccurrenceSpecification finish, Lifeline lifeline) {
setSingleCovered(spec, lifeline);
setSingleCovered(start, lifeline);
setSingleCovered(finish, lifeline);
spec.setStart(start);
spec.setFinish(finish);
}
private void setSingleCovered(InteractionFragment fragment, Lifeline lifeline) {
if (!fragment.getCovereds().contains(lifeline)) {
fragment.getCovereds().add(lifeline);
}
}
/**
* @generated NOT
*/
protected CommandResult doExecuteWithResult(IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
if (!canExecute()) {
throw new ExecutionException("Invalid arguments in create link command"); //$NON-NLS-1$
}
Interaction interaction = getContainer();
int count = interaction.getMessages().size() + 1;
Element diagramSource = getSource();
Element diagramTarget = getTarget();
MessageEnd domainSource;
MessageEnd domainTarget;
BehaviorExecutionSpecification sourceInvocation = null;
BehaviorExecutionSpecification targetExecution = null;
if (diagramSource instanceof Gate && diagramTarget instanceof Lifeline) {
domainSource = (Gate) diagramSource;
targetExecution = createBehaviorExecutionSpecification(interaction, (Lifeline) diagramTarget, count, false);
domainTarget = (MessageOccurrenceSpecification) targetExecution.getStart();
} else if (diagramTarget instanceof Gate && diagramSource instanceof Lifeline) {
domainTarget = (Gate) diagramTarget;
sourceInvocation = createBehaviorExecutionSpecification(interaction, (Lifeline) diagramSource, count, true);
domainSource = (MessageOccurrenceSpecification) sourceInvocation.getStart();
} else if (diagramTarget instanceof Lifeline && diagramSource instanceof Lifeline) {
Lifeline sourceLL = (Lifeline) diagramSource;
Lifeline targetLL = (Lifeline) diagramTarget;
ThePastImpl thePast = createThePast();
ListIterator<InteractionFragment> position = thePast.getAfterThePastPosition(interaction);
BehaviorExecutionSpecification[] pair = createBehaviorExecutionSpecificationsPair(interaction, sourceLL, targetLL, count, position);
sourceInvocation = pair[0];
targetExecution = pair[1];
domainSource = (MessageOccurrenceSpecification) sourceInvocation.getStart();
domainTarget = (MessageOccurrenceSpecification) targetExecution.getStart();
} else if (diagramSource instanceof BehaviorExecutionSpecification && diagramTarget instanceof Lifeline) {
BehaviorExecutionSpecification parentExecution = (BehaviorExecutionSpecification) diagramSource;
Lifeline sourceLL = parentExecution.getCovereds().get(0);
Lifeline targetLL = (Lifeline) diagramTarget;
SDBuilder sdBuilder = new SDBuilder(sourceLL.getInteraction());
SDBehaviorSpec sdExecution = sdBuilder.getSDModel().getUMLTracing().findBehaviorSpec(parentExecution);
if (false == sdExecution instanceof SDExecution) {
//XXX : canExecute!
throw new IllegalArgumentException("SDExecution expected: " + sdExecution);
}
ThePastImpl thePast = createThePast();
thePast.executionStarted((SDExecution) sdExecution);
ListIterator<InteractionFragment> position = thePast.getAfterThePastPosition(interaction);
BehaviorExecutionSpecification[] pair = createBehaviorExecutionSpecificationsPair(interaction, sourceLL, targetLL, count, position);
sourceInvocation = pair[0];
targetExecution = pair[1];
domainSource = (MessageOccurrenceSpecification) sourceInvocation.getStart();
domainTarget = (MessageOccurrenceSpecification) targetExecution.getStart();
} else if (diagramSource instanceof BehaviorExecutionSpecification && diagramTarget instanceof BehaviorExecutionSpecification) {
BehaviorExecutionSpecification parentExecution = (BehaviorExecutionSpecification) diagramSource;
BehaviorExecutionSpecification diagramTargetImpl = (BehaviorExecutionSpecification) diagramTarget;
Lifeline sourceLL = parentExecution.getCovereds().get(0);
Lifeline targetLL = diagramTargetImpl.getCovereds().get(0);
SDTrace sdTracing = new SDBuilder(sourceLL.getInteraction()).getSDModel().getUMLTracing();
SDBehaviorSpec sdSourceExecution = sdTracing.findBehaviorSpec(parentExecution);
if (false == sdSourceExecution instanceof SDExecution) {
//XXX
throw new IllegalArgumentException("SDExecution expected as source: " + sdSourceExecution);
}
SDBehaviorSpec sdTargetInvocation = sdTracing.findBehaviorSpec(diagramTargetImpl);
if (false == sdTargetInvocation instanceof SDInvocation) {
throw new IllegalArgumentException("SDInvocation expected as target: " + sdSourceExecution);
}
ThePastImpl thePast = createThePast();
thePast.executionStarted((SDExecution) sdSourceExecution);
ListIterator<InteractionFragment> position = thePast.getAfterThePastPosition(interaction);
BehaviorExecutionSpecification[] pair = createBehaviorExecutionSpecificationsPair(interaction, sourceLL, targetLL, count, position);
sourceInvocation = pair[0];
targetExecution = pair[1];
domainSource = (MessageOccurrenceSpecification) sourceInvocation.getStart();
domainTarget = (MessageOccurrenceSpecification) targetExecution.getStart();
} else if (diagramSource instanceof InteractionOperand && diagramTarget == diagramSource) {
InteractionOperand operand = (InteractionOperand) diagramSource;
U2TCreateLinkCommand linkCreationPack = U2TCreateLinkCommand.getFromRequest(getRequest());
if (linkCreationPack == null || linkCreationPack.getSourceParameters() == null || linkCreationPack.getTargetParameters() == null) {
throw new UnsupportedOperationException("I need extended creation parameters");
}
Lifeline sourceLL = findEnclosedDiagramLifeLine(linkCreationPack.getSourceParameters().getParentView());
Lifeline targetLL = findEnclosedDiagramLifeLine(linkCreationPack.getTargetParameters().getParentView());
ThePastImpl thePast = createThePast();
ListIterator<InteractionFragment> position = thePast.getAfterThePastPosition(operand.getFragments());
BehaviorExecutionSpecification[] pair = createBehaviorExecutionSpecificationsPair(interaction, sourceLL, targetLL, count, position);
sourceInvocation = pair[0];
targetExecution = pair[1];
domainSource = (MessageOccurrenceSpecification) sourceInvocation.getStart();
domainTarget = (MessageOccurrenceSpecification) targetExecution.getStart();
} else {
throw new UnsupportedOperationException("Message between this elements can't be created: from: " + getSource() + " to: " + getTarget());
}
Message newElement = null;
if (domainSource != null && domainTarget != null) {
newElement = interaction.createMessage("");
interaction.getMessages().add(newElement);
newElement.setSendEvent(domainSource);
newElement.setReceiveEvent(domainTarget);
domainSource.setMessage(newElement);
domainTarget.setMessage(newElement);
}
ElementInitializers.init_Message_4001(newElement);
doConfigure(newElement, monitor, info);
((CreateElementRequest) getRequest()).setNewElement(newElement);
createAdditionalViews(sourceInvocation, targetExecution, newElement);
return CommandResult.newOKCommandResult(newElement);
}
private static Lifeline findEnclosedDiagramLifeLine(View view) {
if (view instanceof Diagram) {
return null;
}
if (!view.isSetElement()) {
return null;
}
if (view.getElement() instanceof Lifeline) {
return (Lifeline) view.getElement();
}
EObject container = view.eContainer();
if (false == container instanceof View) {
return null;
}
return findEnclosedDiagramLifeLine((View) container);
}
private View createBehaviorExecutionView(View sourceView, EObject behaviorExecution, int position, Point relativeLocation) {
int visualID = UMLVisualIDRegistry.getNodeVisualID(sourceView, behaviorExecution);
Node result = ViewService.getInstance().createNode(//
new EObjectAdapter(behaviorExecution), sourceView, UMLVisualIDRegistry.getType(visualID), position, UMLDiagramEditorPlugin.DIAGRAM_PREFERENCES_HINT);
if (relativeLocation != null) {
if (result.getLayoutConstraint() == null) {
result.setLayoutConstraint(NotationFactory.eINSTANCE.createBounds());
}
ViewUtil.setStructuralFeatureValue(result, NotationPackage.eINSTANCE.getLocation_Y(), Integer.valueOf(relativeLocation.y));
ViewUtil.setStructuralFeatureValue(result, NotationPackage.eINSTANCE.getLocation_X(), Integer.valueOf(10));
}
return result;
}
private View createBehaviorExecutionView(U2TCreateParameters createParams, EObject behaviorExecution, int position) {
return createBehaviorExecutionView(createParams.getParentView(), behaviorExecution, position, createParams.getRelativeLocation());
}
private void createAdditionalViews(BehaviorExecutionSpecification sourceInvocation, BehaviorExecutionSpecification targetExecution, Message message) {
if (message == null) {
return;
}
U2TCreateLinkCommand linkCreationPack = U2TCreateLinkCommand.getFromRequest(getRequest());
if (linkCreationPack == null || linkCreationPack.getSourceParameters() == null || linkCreationPack.getTargetParameters() == null) {
return;
}
SDModelStorageStyle sdModelAccessor = SDModelAccess.findSDModelAccessor(linkCreationPack.getSourceParameters().getParentView());
if (sdModelAccessor != null) {
sdModelAccessor.invalidateModel();
}
assert sourceInvocation == null || message.getSendEvent() == sourceInvocation.getStart();
assert targetExecution == null || message.getReceiveEvent() == targetExecution.getStart();
View invocationView = null;
if (sourceInvocation != null) {
if (message.getSendEvent() != sourceInvocation.getStart()) {
throw new IllegalStateException(MessageFormat.format(//
"Invocation: {0}, \n start: {1}, message: {2}, sendEvent {3}", //
new Object[] { sourceInvocation, sourceInvocation.getStart(), message, message.getSendEvent() }));
}
U2TCreateParameters sourceParams = linkCreationPack.getSourceParameters();
int sourceViewIndex = findAnchoredViewPosition(sourceParams);
invocationView = createBehaviorExecutionView(sourceParams, sourceInvocation, sourceViewIndex);
linkCreationPack.getSetConnectionEndsCommand().setNewSourceAdaptor(new EObjectAdapter(invocationView));
}
if (targetExecution != null) {
if (message.getReceiveEvent() != targetExecution.getStart()) {
throw new IllegalStateException(MessageFormat.format(//
"Execution: {0}, \n start: {1}, message: {2}, receiveEvent {3}", //
new Object[] { targetExecution, targetExecution.getStart(), message, message.getReceiveEvent() }));
}
U2TCreateParameters targetParams = linkCreationPack.getTargetParameters();
final View executionView;
if (sourceInvocation.getCovereds().get(0) == targetExecution.getCovereds().get(0)) {
//for self message the target should be create inside the just created source, and ViewUtil.APPEND is good enough position
executionView = createBehaviorExecutionView(invocationView, targetExecution, ViewUtil.APPEND, new Point(10, 10));
} else {
int targetViewIndex = findAnchoredViewPosition(targetParams);
executionView = createBehaviorExecutionView(targetParams, targetExecution, targetViewIndex);
}
linkCreationPack.getSetConnectionEndsCommand().setNewTargetAdaptor(new EObjectAdapter(executionView));
}
}
/**
* @generated
*/
protected void doConfigure(Message newElement, IProgressMonitor monitor, IAdaptable info) throws ExecutionException {
IElementType elementType = ((CreateElementRequest) getRequest()).getElementType();
ConfigureRequest configureRequest = new ConfigureRequest(getEditingDomain(), newElement, elementType);
configureRequest.setClientContext(((CreateElementRequest) getRequest()).getClientContext());
configureRequest.addParameters(getRequest().getParameters());
configureRequest.setParameter(CreateRelationshipRequest.SOURCE, getSource());
configureRequest.setParameter(CreateRelationshipRequest.TARGET, getTarget());
ICommand configureCommand = elementType.getEditCommand(configureRequest);
if (configureCommand != null && configureCommand.canExecute()) {
configureCommand.execute(monitor, info);
}
}
/**
* @generated
*/
protected void setElementToEdit(EObject element) {
throw new UnsupportedOperationException();
}
/**
* @generated
*/
protected Element getSource() {
return (Element) source;
}
/**
* @generated
*/
protected Element getTarget() {
return (Element) target;
}
/**
* @generated
*/
public Interaction getContainer() {
return container;
}
/**
* Default approach is to traverse ancestors of the source to find instance of container.
* Modify with appropriate logic.
* @generated
*/
private static Interaction deduceContainer(EObject source, EObject target) {
// Find container element for the new link.
// Climb up by containment hierarchy starting from the source
// and return the first element that is instance of the container class.
for (EObject element = source; element != null; element = element.eContainer()) {
if (element instanceof Interaction) {
return (Interaction) element;
}
}
return null;
}
private boolean isValidEnd(EObject diagramEnd) {
if (diagramEnd instanceof Gate) {
return true;
}
if (diagramEnd instanceof Lifeline) {
return true;
}
if (diagramEnd instanceof BehaviorExecutionSpecification) {
return ((BehaviorExecutionSpecification) diagramEnd).getCovereds().size() == 1;
}
if (diagramEnd instanceof InteractionOperand) {
return true;
}
return false;
}
private static MessageOccurrenceSpecification doCreateMessageOccurrence(ListIterator<InteractionFragment> position, String name) {
MessageOccurrenceSpecification result = UMLFactory.eINSTANCE.createMessageOccurrenceSpecification();
if (name != null) {
result.setName(name);
}
position.add(result);
return result;
}
private static BehaviorExecutionSpecification doCreateBehaviorExecution(ListIterator<InteractionFragment> position, String name) {
BehaviorExecutionSpecification result = UMLFactory.eINSTANCE.createBehaviorExecutionSpecification();
if (name != null) {
result.setName(name);
}
position.add(result);
return result;
}
private int findAnchoredViewPosition(U2TCreateParameters sourceParams) {
int viewPosition = ViewUtil.APPEND;
if (sourceParams.getAnchorSibling() != null) {
View anchor = sourceParams.getAnchorSibling();
int anchorPos = sourceParams.getParentView().getChildren().indexOf(anchor);
if (anchorPos > 0) {
viewPosition = anchorPos;
if (!sourceParams.isBeforeNotAfterAnchor()) {
viewPosition++;
}
}
}
return viewPosition;
}
private ThePastImpl createThePast() {
return new ThePastImpl(U2TCreateLinkCommand.getFromRequest(getRequest()));
}
}