Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: ef288caaf17173f5eca208c1bee5ff61a48027b6 (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
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
/*****************************************************************************
 * 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 v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *  Ansgar Radermacher  ansgar.radermacher@cea.fr  
 *
 *****************************************************************************/

package org.eclipse.papyrus.qompass.designer.core.deployment;

import java.util.Iterator;

import org.eclipse.core.runtime.Status;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.UniqueEList;
import org.eclipse.papyrus.FCM.Fragment;
import org.eclipse.papyrus.MARTE.MARTE_DesignModel.SRM.SW_Concurrency.SwSchedulableResource;
import org.eclipse.papyrus.MARTE.MARTE_Foundations.Alloc.Allocate;
import org.eclipse.papyrus.qompass.designer.core.ConnectorUtils;
import org.eclipse.papyrus.qompass.designer.core.Log;
import org.eclipse.papyrus.qompass.designer.core.Utils;
import org.eclipse.papyrus.uml.tools.utils.StereotypeUtil;
import org.eclipse.uml2.uml.Abstraction;
import org.eclipse.uml2.uml.Class;
import org.eclipse.uml2.uml.Classifier;
import org.eclipse.uml2.uml.Connector;
import org.eclipse.uml2.uml.ConnectorEnd;
import org.eclipse.uml2.uml.DirectedRelationship;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.InstanceSpecification;
import org.eclipse.uml2.uml.NamedElement;
import org.eclipse.uml2.uml.Node;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.Port;
import org.eclipse.uml2.uml.Property;
import org.eclipse.uml2.uml.Slot;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.util.UMLUtil;

public class AllocUtils {

	public static final String startPortName = "start"; //$NON-NLS-1$
	
	public static final String startPortType = "IStart"; //$NON-NLS-1$
	
	/**
	 * Retrieve a list of nodes to which the instance is allocated to *or*
	 * to which one of the contained instances is allocated to (recursively)
	 * 
	 * @param instance
	 * @return a list of nodes
	 */
	public static EList<InstanceSpecification> getAllNodes(InstanceSpecification instance) {
		EList<InstanceSpecification> nodeList = getNodes(instance);
		for(InstanceSpecification containedInstance : DepUtils.getContainedInstances(instance)) {
			nodeList.addAll(getAllNodes(containedInstance));
		}
		return nodeList;
	}
	
	/**
	 * Retrieve a list of nodes to which the instance is allocated to *or*
	 * to which one of the contained instances is allocated to (recursively)
	 * 
	 * @param instanceAttribute an attribute within a composite that represents a component instance
	 *       or a set thereof, if the composite itself is instantiated multiple times)
	 * @return a list of nodes
	 */
	public static Property getThreadAlloc(Property instanceAttribute) {
		for (DirectedRelationship relation : instanceAttribute.getSourceDirectedRelationships()) {
			if (StereotypeUtil.isApplied(relation, Allocate.class)) {
				if (relation.getTargets().size() != 1) continue;
				Element targetElem = relation.getTargets().get(0);
				if (!(targetElem instanceof Property)) continue;
				Property target = (Property) targetElem;
				if (StereotypeUtil.isApplied(target.getType(), SwSchedulableResource.class)) {
					return target;
				}
			}
		}
		return null;
	}


	/**
	 * Retrieve a list of nodes to which the instance is allocated to *or*
	 * to which one of the containing instances is explicitly allocated
	 * 
	 * @param instance
	 * @return a list of nodes
	 */
	public static EList<InstanceSpecification> getAllNodesOrThreadsParent(InstanceSpecification instance) {
		EList<InstanceSpecification> nodeList = getNodesOrThreads(instance);
		Package cdp = instance.getNearestPackage();
		// TODO: not very efficient: loop each time over all instance specifications
		for(NamedElement parentNE : cdp.getMembers()) {
			if(parentNE instanceof InstanceSpecification) {
				// possible parent instance specification
				InstanceSpecification parentIS = (InstanceSpecification)parentNE;
				if(DepUtils.getContainedInstances(parentIS).contains(instance)) {
					nodeList.addAll(getAllNodesOrThreadsParent(parentIS));
				}
			}
		}
		return nodeList;
	}

	public static InstanceSpecification getNode(InstanceSpecification instance) {
		EList<InstanceSpecification> nodeList = getNodes(instance);
		if(nodeList.size() != 0) {
			return nodeList.get(0);
		}
		return null;
	}

	public static InstanceSpecification getNodeOrThread(InstanceSpecification instanceOrThread) {
		EList<InstanceSpecification> nodeList = getNodesOrThreads(instanceOrThread);
		if(nodeList.size() != 0) {
			return nodeList.get(0);
		}
		return null;
	}

	/**
	 * This method returns a list of nodes (or threads) to which the passed instance is allocated.
	 * It is based on MARTE Allocation (a stereotyped abstraction) which is a generic
	 * mechanism to deploy UML elements to nodes.
	 * 
	 * @param instanceOrThread
	 *        The instance for which we like to know the allocation information
	 * @return
	 */
	public static EList<InstanceSpecification> getNodesOrThreads(InstanceSpecification instanceOrThread) {
		EList<InstanceSpecification> nodeList = new UniqueEList<InstanceSpecification>();

		for(DirectedRelationship relationship : instanceOrThread.getSourceDirectedRelationships(UMLPackage.eINSTANCE.getAbstraction())) {
			Abstraction abstraction = (Abstraction)relationship;
			if(StereotypeUtil.isApplied(abstraction, Allocate.class)) {
				for(Element target : abstraction.getTargets()) {
					if(target instanceof InstanceSpecification) {
						nodeList.add((InstanceSpecification)target);
					}
				}
			}
		}
		return nodeList;
	}

	/**
	 * This method returns a list of nodes to which the passed instance is allocated. If
	 * the instance is allocated directly to a node, this node is returned. If the instance
	 * is allocated to a thread, the allocation of the thread to a node is returned.
	 *
	 * @param instanceOrThread
	 *        The instance that should be deployed
	 * @return
	 */
	public static EList<InstanceSpecification> getNodes(InstanceSpecification instanceOrThread) {
		EList<InstanceSpecification> nodeList = new UniqueEList<InstanceSpecification>();
		EList<InstanceSpecification> nodeOrThreads = getNodesOrThreads(instanceOrThread);
		for(InstanceSpecification nodeOrThread : nodeOrThreads)
		{
			Classifier nodeOrThreadC = DepUtils.getClassifier(nodeOrThread);
			if(StereotypeUtil.isApplied(nodeOrThreadC, SwSchedulableResource.class)) {
				// treat case that instance is allocated to a thread
				// follow allocation of Thread
				nodeList.add(getNode(nodeOrThread));
			}
			else {
				nodeList.add(nodeOrThread);
			}
		}
		return nodeList;
	}

	/**
	 * This method updates (and optionally removes) the allocations of an instance
	 * 
	 * @param instance
	 *        The instance that should be deployed
	 * @param oldNode
	 *        the old node allocation
	 * @param newNode
	 *        the new node allocation, may be null to indicate removal
	 * @return
	 */
	public static EList<Node> updateAllocation(InstanceSpecification instance, InstanceSpecification oldNode, InstanceSpecification newNode) {
		EList<Node> nodeList = new UniqueEList<Node>();

		Iterator<DirectedRelationship> relShipIt =
			instance.getSourceDirectedRelationships(UMLPackage.eINSTANCE.getAbstraction()).iterator();

		while(relShipIt.hasNext()) {
			Abstraction abstraction = (Abstraction)relShipIt.next();
			if(StereotypeUtil.isApplied(abstraction, Allocate.class)) {
				EList<NamedElement> suppliers = abstraction.getSuppliers(); // use suppliers instead of targets (derived)
				for(int index = 0; index < suppliers.size(); index++) {
					if(suppliers.get(index) == oldNode) {
						if(newNode == null) {
							// remove relationship completely, since we assume a single target
							// (cannot call remove on relShipIt, since list is derived)
							abstraction.destroy();
						} else {
							suppliers.set(index, newNode);
						}
						break;
					}
				}
			}
		}
		return nodeList;
	}

	/**
	 * Retrieve a list of nodes to which the instance is allocated to *or*
	 * to which one of the contained instances is allocated to (recursively)
	 * 
	 * @param instance
	 * @param A
	 *        port of the composite. Contained instances are examined only if
	 *        they have a connection with this port.
	 * @return a list of nodes
	 */
	public static EList<InstanceSpecification> getAllNodesForPort(InstanceSpecification instance, Port port) {
		EList<InstanceSpecification> nodeList = getNodes(instance);
		Classifier composite = DepUtils.getClassifier(instance);
		if(composite instanceof Class) {
			Class compositeCL = (Class)composite;
			for(Slot slot : instance.getSlots()) {
				Property containedProperty = (Property)slot.getDefiningFeature();

				for(Connector connection : compositeCL.getOwnedConnectors()) {
					// is one connector end targeted at the containedProperty ?
					ConnectorEnd end = ConnectorUtils.connEndForPart(connection, containedProperty);
					if(end == null)
						continue;

					// does the connector at the same connect the composite's port?
					if(ConnectorUtils.connectsPort(connection, port)) {
						Port containedPort = (Port)end.getRole();
						nodeList.addAll(getAllNodesForPort(DepUtils.getInstance(slot), containedPort));
					}
				}
			}
		}
		return nodeList;
	}

	public static boolean allocate(InstanceSpecification instance, InstanceSpecification node) {
		Package cdp = (Package)instance.getOwner();
		Abstraction allocation = (Abstraction)
			cdp.createPackagedElement("allocate " + instance.getName() + //$NON-NLS-1$
				" to " + node.getName(), UMLPackage.eINSTANCE.getAbstraction()); //$NON-NLS-1$
		if(StereotypeUtil.apply(allocation, Allocate.class) == null) {
			// stereotype application failed
			allocation.destroy();
			return false;
		}
		allocation.getClients().add(instance);
		allocation.getSuppliers().add(node);
		return true;
	}

	/**
	 * Assign node name to leafs
	 * 
	 * @param instance
	 * @param A
	 *        port of the composite. Contained instances are examined only if the
	 *        have a connection with this port. If null, no sub-instances are examined
	 * @param nodes
	 *        A list of nodes to which leafs are allocated
	 */
	public static void propagateNodesViaPort(InstanceSpecification instance, Port port, EList<InstanceSpecification> nodes) {
		if(instance == null) {
			return;
		}
		EList<Slot> slots = instance.getSlots();
		Class composite = DepUtils.getImplementation(instance);

		// Only set allocation on leafs (TODO: assure that components with configuration attributes are not considered as leafs)
		// if(composite.getParts().size() == 0) {
		for(InstanceSpecification node : nodes) {
			AllocUtils.allocate(instance, node);
		}

		if((composite != null) && (port != null)) {
		Class compositeCL = (Class)composite;
			for(Slot slot : slots) {
				Property containedProperty = (Property)slot.getDefiningFeature();

				Fragment fragment = UMLUtil.getStereotypeApplication(containedProperty, Fragment.class);
				if(fragment != null) {
					// TODO
					/*
					EList<Port> colocateWithPort = fragment.getColocateWithPort();
					// is the port within the list?
					if(Utils.getNamedElementFromList(colocateWithPort, port.getName()) != null) {
						// compare qualified name, since containedPort (stereotype attribute)
						// points to a source model element
						propagateNodesViaPort(DepUtils.getInstance(slot), port, nodes);
						continue;
					}
					*/
				}
				for(Connector connection : compositeCL.getOwnedConnectors()) {
					if(ConnectorUtils.connectsPort(connection, port)) {
						Log.log(Status.INFO, Log.TRAFO_CONNECTOR, "connector: " + connection.getName()); //$NON-NLS-1$
						Log.log(Status.INFO, Log.TRAFO_CONNECTOR, "end1: " + connection.getEnds().get(0).getPartWithPort()); //$NON-NLS-1$
						Log.log(Status.INFO, Log.TRAFO_CONNECTOR, "end2: " + connection.getEnds().get(1).getPartWithPort()); //$NON-NLS-1$
						ConnectorEnd end = ConnectorUtils.connEndForPart(connection, containedProperty);
						// other connector end targeted at containedProperty?
						if(end != null) {
							Port containedPort = (Port)end.getRole();
							propagateNodesViaPort(DepUtils.getInstance(slot), containedPort, nodes);
						}
					}
				}
			}
		}
	}

	/**
	 * Return the start Port of a component, i.e. a port that corresponds to the "magic" port name
	 * start and is typed with the interface IStart
	 * 
	 * @param component a component implementation
	 * @return The start port or null
	 */
	public static Port getStartPort(Class component) {
		Element startPortElem = Utils.getNamedElementFromList(component.getAllAttributes(), startPortName);
		if (startPortElem instanceof Port) {
			Port startPort = (Port) startPortElem;
			if(startPort.getType().getName().equals(startPortType)) {
				return startPort;
			}
		}
		return null;
	}
}

Back to the top