-
Notifications
You must be signed in to change notification settings - Fork 85
/
AbstractFunctionExt.java
570 lines (516 loc) · 22 KB
/
AbstractFunctionExt.java
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
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
/*******************************************************************************
* Copyright (c) 2006, 2020 THALES GLOBAL SERVICES.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Thales - initial API and implementation
*******************************************************************************/
package org.polarsys.capella.core.model.helpers;
import static org.polarsys.capella.common.helpers.cache.ModelCache.getCache;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.polarsys.capella.common.data.activity.ActivityNode;
import org.polarsys.capella.common.data.activity.InputPin;
import org.polarsys.capella.common.data.activity.OutputPin;
import org.polarsys.capella.common.data.modellingcore.AbstractExchangeItem;
import org.polarsys.capella.common.data.modellingcore.AbstractTrace;
import org.polarsys.capella.core.data.capellacore.CapellaElement;
import org.polarsys.capella.core.data.capellacore.GeneralizableElement;
import org.polarsys.capella.core.data.cs.Component;
import org.polarsys.capella.core.data.cs.Part;
import org.polarsys.capella.core.data.cs.PhysicalLink;
import org.polarsys.capella.core.data.fa.AbstractFunction;
import org.polarsys.capella.core.data.fa.AbstractFunctionalBlock;
import org.polarsys.capella.core.data.fa.ComponentExchange;
import org.polarsys.capella.core.data.fa.ComponentExchangeAllocation;
import org.polarsys.capella.core.data.fa.ComponentExchangeAllocator;
import org.polarsys.capella.core.data.fa.ComponentFunctionalAllocation;
import org.polarsys.capella.core.data.fa.FunctionInputPort;
import org.polarsys.capella.core.data.fa.FunctionOutputPort;
import org.polarsys.capella.core.data.fa.FunctionPort;
import org.polarsys.capella.core.data.fa.FunctionalExchange;
import org.polarsys.capella.core.data.helpers.capellacore.services.GeneralizableElementExt;
import org.polarsys.capella.core.data.helpers.fa.services.FunctionExt;
import org.polarsys.capella.core.data.information.ExchangeItem;
import org.polarsys.capella.core.data.oa.ActivityAllocation;
import org.polarsys.capella.core.data.oa.OperationalActivity;
import org.polarsys.capella.core.data.oa.Role;
/**
*/
public class AbstractFunctionExt {
/**
* @param component
* @param allocatedFunctions
* (first call : all leaves functions allocated to component)
* @param functionsToCheck
* (first call : all leaves functions allocated to component
* @return recursively all functions (and function containers) allocated to component
*/
public static Set<AbstractFunction> getRecursiveAllocatedFunctions(Set<AbstractFunction> allocatedFunctions,
final Set<AbstractFunction> functionsToCheck) {
Set<AbstractFunction> newfunctionsToCheck = new HashSet<AbstractFunction>();
Set<AbstractFunction> returnedAllocatedFunctions = new HashSet<AbstractFunction>(allocatedFunctions);
for (AbstractFunction aFunction : functionsToCheck) {
EObject container = aFunction.eContainer();
if (container instanceof AbstractFunction) {
boolean toAdd = true;
for (AbstractFunction aSubFunction : ((AbstractFunction) container).getSubFunctions()) {
if (!allocatedFunctions.contains(aSubFunction)) {
toAdd = false;
newfunctionsToCheck.add(aFunction);
break;
}
}
if (toAdd) {
returnedAllocatedFunctions.add((AbstractFunction) container);
newfunctionsToCheck.add((AbstractFunction) container);
}
}
}
boolean checkParents = false;
for (AbstractFunction aFunction : returnedAllocatedFunctions) {
if (!allocatedFunctions.contains(aFunction)) {
checkParents = true;
break;
}
}
// if the returned list is the same as the list given in parameter =>
// stop
if (checkParents) {
return getRecursiveAllocatedFunctions(returnedAllocatedFunctions, newfunctionsToCheck);
}
return returnedAllocatedFunctions;
}
/**
* @param component
* @return all functions (leaves and parents) allocated to component
*/
public static List<AbstractFunction> getAllocatedFunctions(Component component) {
List<AbstractFunction> returnedList = new ArrayList<AbstractFunction>();
Set<AbstractFunction> allocatedFunctions = new HashSet<AbstractFunction>();
allocatedFunctions.addAll(component.getAllocatedFunctions());
returnedList.addAll(getRecursiveAllocatedFunctions(allocatedFunctions, allocatedFunctions));
return returnedList;
}
/**
* @param role
* @return all operational activities (leaves and parents) allocated to role
*/
public static List<AbstractFunction> getAllocatedOperationalActivities(Role role) {
List<AbstractFunction> returnedList = new ArrayList<AbstractFunction>();
Set<AbstractFunction> allocatedFunctions = new HashSet<AbstractFunction>();
for (ActivityAllocation anAllocation : role.getOwnedActivityAllocations()) {
if ((anAllocation.getTargetElement() != null)
&& (anAllocation.getTargetElement() instanceof OperationalActivity)) {
allocatedFunctions.add((OperationalActivity) anAllocation.getTargetElement());
}
}
returnedList.addAll(getRecursiveAllocatedFunctions(allocatedFunctions, allocatedFunctions));
return returnedList;
}
/**
* Gets the allocated functional exchange filtered for current and all its sub partitions and deployed elements
* recursively
*
* @param sourceBlock
* the given abstractFunctionalBlock
* @param targetBlock
* the given abstractFunctionalBlock
* @return the allocated functional exchange filtered
*/
public static List<CapellaElement> getAllAllocatedFunctionalExchangeFiltered(AbstractFunctionalBlock sourceBlock,
AbstractFunctionalBlock targetBlock) {
List<CapellaElement> list = new ArrayList<CapellaElement>(1);
List<AbstractFunction> srcAllocatedFuns = new ArrayList<AbstractFunction>(1);
List<AbstractFunction> tarAllocatedFuns = new ArrayList<AbstractFunction>(1);
if ((sourceBlock instanceof Component) && (targetBlock instanceof Component)) {
// get allocated function for current source and target
srcAllocatedFuns.addAll(sourceBlock.getAllocatedFunctions());
tarAllocatedFuns.addAll(targetBlock.getAllocatedFunctions());
// get all recursive sub Components
// in this process the sourceBlock and targetBlock are also
// added to the lists
Collection<Component> allSourceRelatedEles = ComponentExt.getAllSubUsedComponents((Component) sourceBlock);
Collection<Component> allTargetRelatedEles = ComponentExt.getAllSubUsedComponents((Component) targetBlock);
// get All Super GeneralizableElement of both sourceBlock and
// targetBlock
if (sourceBlock instanceof GeneralizableElement) {
getSuperGElesFilterAsComponent(sourceBlock, allSourceRelatedEles);
getSuperGElesFilterAsComponent(targetBlock, allTargetRelatedEles);
}
// get all deployedElement
allSourceRelatedEles.addAll(PartExt.getAllDeployableComponents((Component) sourceBlock));
allTargetRelatedEles.addAll(PartExt.getAllDeployableComponents((Component) targetBlock));
// get allocated function of recursive sub sourcePartition
for (Component partitionableElement : allSourceRelatedEles) {
srcAllocatedFuns.addAll(partitionableElement.getAllocatedFunctions());
}
// get allocated function of recursive sub targetPartition
for (Component partitionableElement : allTargetRelatedEles) {
tarAllocatedFuns.addAll(partitionableElement.getAllocatedFunctions());
}
// now find the exchanges and add to result list [making sure
// that the target is contained in 'tarAllocatedFuns']
for (AbstractFunction abstractFunction : srcAllocatedFuns) {
List<FunctionalExchange> outGoingExchange = FunctionExt.getOutGoingExchange(abstractFunction);
for (FunctionalExchange functionalExchange : outGoingExchange) {
AbstractFunction outGoingAbstractFunction = FunctionExt.getOutGoingAbstractFunction(functionalExchange);
if (null != outGoingAbstractFunction) {
if (tarAllocatedFuns.contains(outGoingAbstractFunction)) {
list.add(functionalExchange);
}
}
}
}
}
return list;
}
private static void getSuperGElesFilterAsComponent(AbstractFunctionalBlock sourceBlock,
Collection<Component> allSourceRelatedEles) {
List<GeneralizableElement> allSuperGEs = GeneralizableElementExt
.getAllSuperGeneralizableElements((GeneralizableElement) sourceBlock);
for (GeneralizableElement generalizableElement : allSuperGEs) {
if (generalizableElement instanceof Component) {
allSourceRelatedEles.add((Component) generalizableElement);
}
}
}
/**
* Return all the allocation blocks of the current and roles of the current function.
*
* @param object
* the target function
* @return all the allocation blocks of the current and roles of the current function.
*
* TODO This function should return a Set and have a more meaningful name such as getAllocationBlocksAndRoles,
* this should be fixed in a non-patch version.
*/
public static List<Object> getAllocationBlocks(Object object) {
if (null == object) {
return Collections.emptyList();
}
List<Object> result = new ArrayList<>();
if (object instanceof AbstractFunction) {
AbstractFunction abstractFunction = (AbstractFunction) object;
EList<AbstractFunctionalBlock> allocationBlocks = abstractFunction.getAllocationBlocks();
if (allocationBlocks != null) {
result.addAll(allocationBlocks);
}
}
// On top of what is done before, you have to check the entities where
// roles are allocated for
// operational activities:
if (object instanceof OperationalActivity) {
OperationalActivity operationActivity = (OperationalActivity) object;
List<Role> allocatingRoles = operationActivity.getAllocatingRoles();
if (allocatingRoles != null) {
result.addAll(allocatingRoles);
}
}
return result;
}
/**
* Checks if is leaf.
*
* @param function
* the given abstract function
* @return true, if is leaf
*/
public static final boolean isLeaf(AbstractFunction function) {
if (function == null) {
return false;
}
return FunctionExt.isLeaf(function);
}
/**
* check if available for allocation
*
* @param element
* a model element
* @return true, if available for allocation
*/
public static boolean isAbstractFunctionAvailableForAllocation(EObject element) {
boolean isAllocated = false;
if ((element == null) || !(element instanceof AbstractFunction)) {
return false;
}
AbstractFunction fun = (AbstractFunction) element;
EList<AbstractTrace> incomingTraces = fun.getIncomingTraces();
for (AbstractTrace abstractTrace : incomingTraces) {
if ((abstractTrace instanceof ComponentFunctionalAllocation) || (abstractTrace instanceof ActivityAllocation)) {
isAllocated = true;
break;
}
}
if (!isAllocated && isLeaf(fun)) {
return true;
}
return false;
}
/**
* check if available for allocation
*
* @param element
* a model element
* @return true, if available for allocation
*/
public static boolean isFunctionExchangeAvailableForAllocation(EObject element) {
if ((element == null) || !(element instanceof FunctionalExchange)) {
return false;
}
FunctionalExchange funExc = (FunctionalExchange) element;
if (funExc.getAllocatingComponentExchanges().size() == 0) {
return true;
}
return false;
}
/**
* check if available for allocation
*
* @param element
* a model element
* @return true, if available for allocation
*/
public static boolean isComponentExchangeAvailableForAllocation(EObject element) {
if ((element == null) || !(element instanceof ComponentExchange)) {
return false;
}
ComponentExchange compExc = (ComponentExchange) element;
EList<AbstractTrace> incomingTraces = compExc.getIncomingTraces();
if (incomingTraces.isEmpty()) {
return true;
}
for (AbstractTrace abstractTrace : incomingTraces) {
if (abstractTrace instanceof ComponentExchangeAllocation) {
ComponentExchangeAllocation allocation = (ComponentExchangeAllocation) abstractTrace;
ComponentExchangeAllocator allocator = allocation.getComponentExchangeAllocator();
if ((null != allocator) && (allocator instanceof PhysicalLink)) {
return false;
}
}
}
return true;
}
/**
* @param object
* @return
*/
public static boolean isPCPartAvailableForDeployment(EObject object) {
if ((null != object) && (object instanceof Part)) {
Part part = (Part) object;
if (part.getDeployingLinks().size() == 0) {
return true;
}
}
return false;
}
public static List<CapellaElement> getExchangeSourceAndTargetPorts(FunctionalExchange exchange) {
List<CapellaElement> result = new ArrayList<CapellaElement>(0);
if (exchange != null) {
ActivityNode source = exchange.getSource();
if ((source != null) && (source instanceof FunctionPort)) {
result.add((CapellaElement) source);
}
ActivityNode target = exchange.getTarget();
if ((target != null) && (target instanceof FunctionPort)) {
result.add((CapellaElement) target);
}
}
return result;
}
/**
* @param abstractFunction
* a Capella Element
* @return all the exchange items contained in the the given Function
*/
public static Collection<AbstractExchangeItem> getAllExchangeItems(final AbstractFunction abstractFunction) {
Set<AbstractExchangeItem> returnedItems = new HashSet<AbstractExchangeItem>();
EList<InputPin> inputs = abstractFunction.getInputs();
EList<OutputPin> outputs = abstractFunction.getOutputs();
for (Iterator<InputPin> iterator = inputs.iterator(); iterator.hasNext();) {
FunctionInputPort inputPin = (FunctionInputPort) iterator.next();
EList<ExchangeItem> exchangeItems = inputPin.getIncomingExchangeItems();
returnedItems.addAll(exchangeItems);
}
for (Iterator<OutputPin> iterator = outputs.iterator(); iterator.hasNext();) {
FunctionOutputPort outputPin = (FunctionOutputPort) iterator.next();
EList<ExchangeItem> exchangeItems = outputPin.getOutgoingExchangeItems();
returnedItems.addAll(exchangeItems);
}
return returnedItems;
}
/**
* Given a function, returns the components it is allocated to.
*
* @param function
* the function considered
* @return the components the function is allocated to
*/
public static List<Component> getAllocatingComponents(AbstractFunction function) {
List<Component> result = new ArrayList<>();
if (null != function.getAllocationBlocks()) {
for (AbstractFunctionalBlock block : function.getAllocationBlocks()) {
if (block instanceof Component) {
result.add((Component) block);
}
}
}
return result;
}
/**
* Given an activity, returns the roles it is allocated to.
*
* @param function
* the function considered
* @return the components the function is allocated to
*/
protected static Collection<Role> getAllocatingRoles(OperationalActivity activity) {
Collection<Role> result = new ArrayList<Role>();
EList<Role> roles = activity.getAllocatingRoles();
if (null != roles && !roles.isEmpty()) {
result.addAll(roles);
}
return result;
}
/**
* Given a mother function/activity that has sub functions, this method <b>calculates</b> the allocation of the mother
* function to a component/actor/entity.
*
* The rule is that <b>a mother function/activity is allocated to a component/actor/entity if and only if all of its
* leaf functions are allocated to this component/actor/entity or children of them</b>.
*
* <b>Note</b> that in case the mother function/activity is already allocated to a component/actor/entity or in case
* the mother function/activity is a leaf function, the method returns its allocation(s).
*
* <b>Note</b> also that the helper works also in the case the sub functions are allocated to different children of
* the same component/actor/entity.
*
* @param motherFunction
* the mother function/activity to calculate component/actor/entity allocation on.
* @return the <b>calculated</b> list of components/actors/entities the mother function is allocated to.
*/
public static List<Component> getMotherFunctionAllocation(AbstractFunction motherFunction) {
// If motherFunction is already allocated to a component/actor
List<Component> motherFunctionAllocatingComponents = getAllocatingComponents(motherFunction);
if (!motherFunctionAllocatingComponents.isEmpty()) {
return motherFunctionAllocatingComponents;
}
// Get all leaves functions of the motherFunction
List<AbstractFunction> leaves = getCache(FunctionExt::getAllLeafAbstractFunctions, motherFunction);
if (null == leaves || leaves.isEmpty()) {
return Collections.emptyList();
}
// Gather all allocating Components of all leaves
List<Component> allAllocatingComponents = new ArrayList<>();
for (AbstractFunction leaf : leaves) {
Collection<Component> allocatingComponents = getAllocatingComponents(leaf);
if (allocatingComponents.isEmpty()) {
// A leaf is not allocated -> stop here
return Collections.emptyList();
}
allAllocatingComponents.addAll(allocatingComponents);
}
// Get common ancestor of all Components allocation leaves.
Component commonAncestor = ComponentExt.getFirstCommonComponentAncestor(allAllocatingComponents);
if (commonAncestor == null) {
return Collections.emptyList();
}
return Collections.singletonList(commonAncestor);
}
/**
* Returns all components that have as allocated functions the given function or to its sub-functions
*
* @param motherFunction
* the parent function
*/
public static List<Component> getMotherAllFunctionAllocation(AbstractFunction motherFunction) {
// If motherFunction is already allocated to a component/actor
List<Component> motherFunctionAllocatingComponents = getAllocatingComponents(motherFunction);
if (!motherFunctionAllocatingComponents.isEmpty()) {
return motherFunctionAllocatingComponents;
}
// Get all owned functions of the motherFunction
List<AbstractFunction> owned = getCache(FunctionExt::getAllAbstractFunctions, motherFunction);
if (null == owned || owned.isEmpty()) {
return Collections.emptyList();
}
// Gather all allocating Components of all owned functions
List<Component> allAllocatingComponents = new ArrayList<>();
for (AbstractFunction func : owned) {
Collection<Component> allocatingComponents = getAllocatingComponents(func);
if (!allocatingComponents.isEmpty()) {
allAllocatingComponents.addAll(allocatingComponents);
}
}
return allAllocatingComponents;
}
/**
* Given a mother activity that has sub activities, this method <b>calculates</b> the allocation of the mother
* activity to a role.
*
* The rule is that <b>a mother activity is allocated to a role if and only if all of its sub activities are allocated
* to this role</b>.
*
* Note that in case the mother activity is already allocated to a role or in case the mother activity is a leaf
* activity, the method returns its allocation(s).
*
* @param motherFunction
* the mother activity to calculate role allocation on
* @return the <b>calculated</b> list of roles the mother activity is allocated to
*/
public static List<Role> getMotherActivityRoleAllocation(AbstractFunction motherFunction) {
List<Role> result = new ArrayList<Role>();
// Consider only Operational Activity
if (motherFunction instanceof OperationalActivity) {
OperationalActivity motherActivity = (OperationalActivity) motherFunction;
// If motherActivity is already allocated to a role
Collection<Role> roles = getAllocatingRoles(motherActivity);
if (!roles.isEmpty()) {
result.addAll(roles);
} else {
// Get all leaves activities of the motherActivity
List<OperationalActivity> leaves = getAllLeafOperationalActivities(motherActivity);
if (null != leaves && !leaves.isEmpty()) {
Iterator<OperationalActivity> it = leaves.iterator();
// Get first leaf role allocation to initialize the
// result
result.addAll(getAllocatingRoles(it.next()));
// Iterate over leaves and do the intersection with result
while (it.hasNext()) {
result.retainAll(getAllocatingRoles(it.next()));
}
}
}
}
return result;
}
/**
* Given an Operational Activity, returns all leaves of type Operational Activity
*
* @param activity
* The mother Operational Activity
* @return the list of leaves of type Operational Activity
*/
public static List<OperationalActivity> getAllLeafOperationalActivities(OperationalActivity activity) {
List<OperationalActivity> result = new ArrayList<>();
for (AbstractFunction abstractFunction : getCache(FunctionExt::getAllAbstractFunctions, activity)) {
if (org.polarsys.capella.core.data.helpers.fa.services.FunctionExt.isLeaf(abstractFunction)
&& (abstractFunction instanceof OperationalActivity)) {
result.add((OperationalActivity) abstractFunction);
}
}
return result;
}
}