Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: ce0664ce2bc87e43b21573c96fd88dec93548fef (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
/*****************************************************************************
 * Copyright (c) 2016 CEA LIST and others.
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Jérémie TATIBOUET (CEA LIST) - Initial API and implementation
 *   Sébastien REVOL (CEA LIST) - Initial API and implementation
 *   
 *****************************************************************************/

package org.eclipse.papyrus.uml.diagram.activity.edit.utils.updater;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.uml2.uml.Activity;
import org.eclipse.uml2.uml.ActivityEdge;
import org.eclipse.uml2.uml.ActivityPartition;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InputPin;
import org.eclipse.uml2.uml.InvocationAction;
import org.eclipse.uml2.uml.Pin;
import org.eclipse.uml2.uml.StructuredActivityNode;

public abstract class AbstractInvocationActionPinUpdater<NodeType extends InvocationAction> implements IPinUpdater<NodeType> {

	/**
	 * The derived target is always named 'target'.
	 */
	protected static final String TARGET_NAME = "target";

	/**
	 * Update the original pins with newly derived pins. If it is possible to preserve
	 * existing pins then this action is preferred to replacement.
	 * 
	 * @param originPins
	 *            the list of pins already existing for the node
	 * @param newPins
	 *            the list of pins newly computed for the node
	 */
	protected <P extends Pin> void update(List<P> originPins, List<P> newPins) {
		List<P> orderedPinsList = new ArrayList<P>();
		Iterator<P> newPinsIterator = newPins.iterator();
		while (newPinsIterator.hasNext()) {
			P newPin = newPinsIterator.next();
			Iterator<P> originPinsIterator = originPins.iterator();
			P preservedPin = null;
			while (originPinsIterator.hasNext() && preservedPin == null) {
				// Search an existing pin in the 'originPins' which can be
				// preserved and updated with the data of the new pin under
				// consideration
				P originPin = originPinsIterator.next();
				if (!orderedPinsList.contains(originPin) && isReusable(newPin, originPin)) {
					preservedPin = originPin;
					update(preservedPin, newPin);
					orderedPinsList.add(preservedPin);
				}
			}
			if (preservedPin == null) {
				// No original pin could be preserved.
				orderedPinsList.add(newPin);
			}
		}
		// 2 - Propagate deletion of unpreserved pins to edges
		// that may use them either as source or target
		for (P pin : originPins) {
			if (!orderedPinsList.contains(pin)) {
				delete(pin);
			}
		}
		// 3 - Update the originPins list with the content of the orderedPinList
		originPins.clear();
		originPins.addAll(orderedPinsList);
	}

	/**
	 * An existing pin can only be reused under the following conditions:
	 * 1] Original type conforms to the new type (i.e. the new type is a super type of the original type or the original type itself)
	 * 2] The multiplicity of the new pin is wider than, or the same as, self
	 * 
	 * @param new_
	 *            the new pin
	 * @param origin
	 *            the original pin
	 * @return true of it can be reused, false otherwise
	 */
	private static boolean isReusable(Pin new_, Pin origin) {
		boolean reuse = true;
		if (new_.getType() != null && origin.getType() != null) {
			reuse = origin.getType().conformsTo(new_.getType());
		}
		if (reuse) {
			reuse = origin.compatibleWith(new_);
		}
		return reuse;
	}

	/**
	 * Update multiplicity, type and name of origin pin with the new pin
	 * 
	 * @param origin
	 *            the original pin
	 * @param new_
	 *            the new pin
	 */
	protected static void update(Pin origin, Pin new_) {
		origin.setLower(new_.getLower());
		origin.setUpper(new_.getUpper());
		origin.setType(new_.getType());
		origin.setName(new_.getName());
	}

	/**
	 * The deletion of a pin has an impact on edges that are using as a source or a target.
	 * To ensure model consistency, the deletion of a pin implies deletion of edges referencing
	 * this pin either as a source or a target.
	 * 
	 * @param pin
	 */
	protected static void delete(Pin pin) {
		List<ActivityEdge> edgeToDelete = new ArrayList<ActivityEdge>(pin.getIncomings());
		edgeToDelete.addAll(pin.getOutgoings());
		Iterator<ActivityEdge> edgeToDeleteIterator = edgeToDelete.iterator();
		while (edgeToDeleteIterator.hasNext()) {
			ActivityEdge edge = edgeToDeleteIterator.next();
			Element owner = edge.getOwner();
			if (owner != null) {
				if (owner instanceof StructuredActivityNode) {
					((StructuredActivityNode) owner).getEdges().remove(edge);
				} else if (owner instanceof Activity) {
					((Activity) owner).getEdges().remove(edge);
				} else if (owner instanceof ActivityPartition) {
					((ActivityPartition) owner).getEdges().remove(edge);
				}
			}
		}
	}


	/**
	 * @see org.eclipse.papyrus.uml.diagram.activity.edit.utils.updater.IPinUpdater#updatePin(org.eclipse.uml2.uml.ActivityNode)
	 *
	 * @param node
	 */
	@Override
	public void updatePins(NodeType node) {
		this.update(node.getArguments(), this.deriveArguments(node));
	}

	/**
	 * Derive the argument pins of the invocation action
	 * 
	 * @param node
	 *            the invocation action for which the arguments pin are derived
	 * @return the list of derived arguments pin
	 */
	public abstract List<InputPin> deriveArguments(NodeType node);

	/**
	 * Derive the target used for the invocation action
	 * 
	 * @param node
	 *            the invocation action for which the target is derived
	 * @return the input pin corresponding to the derived target
	 */
	public InputPin deriveTarget(NodeType node) {
		return null; // By default do nothing
	}

}

Back to the top