Add winery source code
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.topologymodeler / src / main / java / org / eclipse / winery / topologymodeler / addons / topologycompleter / topologycompletion / CompletionManager.java
1 /*******************************************************************************
2  * Copyright (c) 2013 Pascal Hirmer.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * and the Apache License 2.0 which both accompany this distribution,
6  * and are available at http://www.eclipse.org/legal/epl-v10.html
7  * and http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Contributors:
10  *    Pascal Hirmer - initial API and implementation
11  *******************************************************************************/
12
13 package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion;
14
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.logging.Logger;
20
21 import org.eclipse.winery.model.tosca.TEntityTemplate;
22 import org.eclipse.winery.model.tosca.TNodeTemplate;
23 import org.eclipse.winery.model.tosca.TRelationshipTemplate;
24 import org.eclipse.winery.model.tosca.TRequirement;
25 import org.eclipse.winery.model.tosca.TTopologyTemplate;
26 import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.DeferredAnalyzer;
27 import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.PlaceHolderAnalyzer;
28 import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.RequirementAnalyzer;
29 import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer;
30 import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.DeferredCompleter;
31 import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.PlaceHolderCompleter;
32 import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.RequirementCompleter;
33 import org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion.completer.StepByStepCompleter;
34
35 /**
36  * This class manages the completion of a TOSCA {@link TTopologyTemplate}.
37  */
38 public class CompletionManager {
39
40         private static final Logger logger = Logger.getLogger(CompletionManager.class.getName());
41
42         /**
43          * {@link TOSCAAnalyzer} object to access the JAXB data model
44          */
45         TOSCAAnalyzer toscaAnalyzer;
46
47         /**
48          * Map containing the topology solutions.
49          *
50          * The first parameter of the map is an index used to traverse the map easily. The second parameter of the solutions map
51          * is another map containing a possible topology solution and a boolean value that determines if the topology is complete.
52          * When all topologies of the solution map are complete, it will be returned to Winery.
53          */
54         Map<Integer, Map<TTopologyTemplate, Boolean>> solutions;
55
56         /**
57          * Whether a step-by-step or an one-step approach is conducted
58          */
59         boolean stepByStep;
60
61         /**
62          * Map containing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s to be chosen by the user in the step-by-step approach.
63          */
64         private Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> templateChoices;
65
66         /**
67          * Whether a user interaction for choosing inserted {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not.
68          */
69         private boolean nodeTemplateUserInteraction = false;
70
71         /**
72          * List containing {@link TRelationshipTemplate} to be chosen by the user.
73          */
74         private List<TEntityTemplate> choices;
75
76         /**
77          * Whether a user interaction for choosing inserted {@link TRelationshipTemplate}s is necessary or not.
78          */
79         boolean userInteraction = false;
80
81         /**
82          * The index of the topology solutions map.
83          */
84         int index;
85
86         /**
87          * The class constructor.
88          *
89          * @param toscaAnalyzer
90          *            the {@link TOSCAAnalyzer} object to access the data model
91          * @param stepByStep
92          *            whether the topology completion is processed step-by-step or not
93          */
94         public CompletionManager(TOSCAAnalyzer toscaAnalyzer, boolean stepByStep) {
95                 this.toscaAnalyzer = toscaAnalyzer;
96                 this.stepByStep = stepByStep;
97                 this.index = 0;
98
99                 // instantiate the solution map
100                 solutions = new HashMap<Integer, Map<TTopologyTemplate, Boolean>>();
101         }
102
103         /**
104          * This recursive method analyzes and completes a TOSCA {@link TTopologyTemplate}.
105          *
106          * @param topology
107          *            the TOSCA {@link TTopologyTemplate} to be completed
108          *
109          * @return the complete TOSCA {@link TTopologyTemplate} object
110          */
111         public List<TTopologyTemplate> manageCompletion(TTopologyTemplate topology) {
112
113                 // -------------------------
114                 // Analyze topology template
115                 // -------------------------
116
117                 // the data model must be cleared before analyzing the topology
118                 toscaAnalyzer.clear();
119
120                 // analyze the content of the topology template
121                 toscaAnalyzer.analyzeTOSCATopology(topology);
122
123                 // Note: The TOSCAAnalyzer object is used for the analysis to access the NodeTemplates or RelationshipTemplates directly,
124                 // so no cast from the parent type TEntityTemplate is required
125
126                 // --------------------------------
127                 // Analyze unfulfilled requirements
128                 // --------------------------------
129                 Map<TRequirement, TNodeTemplate> unfulfilledRequirements = RequirementAnalyzer.analyzeRequirements(toscaAnalyzer);
130
131                 // ---------------------------------------
132                 // Analyze the occurrence of place holders
133                 // ---------------------------------------
134                 List<TNodeTemplate> placeHolders = PlaceHolderAnalyzer.analyzePlaceHolders(toscaAnalyzer);
135
136                 // --------------------------------------------------------
137                 // Analyze the occurrence of deferred RelationshipTemplates
138                 // --------------------------------------------------------
139                 List<TRelationshipTemplate> deferredRelations = DeferredAnalyzer.analyzeDeferredRelations(toscaAnalyzer);
140
141                 // ---------------------
142                 // Complete the topology
143                 // ---------------------
144
145                 // with the step by step approach, a user interaction is always necessary. So the topology and
146                 // the choices will be returned in every step. A combination of the step-by-step approach and a deferred topology is not
147                 // possible because every path of the depth search can lead to a dead end.
148                 if (stepByStep && deferredRelations.isEmpty()) {
149                         logger.info("Completing topology step by step.");
150
151                         List<TTopologyTemplate> solutionList = new ArrayList<TTopologyTemplate>();
152
153                         if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty()) {
154
155                                 // complete a topology containing requirements step by step using the StepByStepCompleter class
156                                 StepByStepCompleter stepByStepCompleter = new StepByStepCompleter(topology);
157                                 stepByStepCompleter.completeTopologyStepByStep(unfulfilledRequirements, toscaAnalyzer);
158
159                                 // get the NodeTemplate choices for the user
160                                 templateChoices = stepByStepCompleter.getTemplateChoices();
161                                 nodeTemplateUserInteraction = true;
162
163                                 solutionList.add(topology);
164
165                                 logger.info("Returning topology for user interaction");
166
167                                 return solutionList;
168
169                         } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) {
170
171                                 // complete a topology containing place holders step by step using the StepByStepCompleter class
172                                 StepByStepCompleter stepByStepCompleter = new StepByStepCompleter(topology);
173                                 TRelationshipTemplate genericRelationship = stepByStepCompleter.completeWildcardTopologyStepByStep(placeHolders, toscaAnalyzer);
174
175                                 // get the NodeTemplate selection for the user to choose
176                                 templateChoices = stepByStepCompleter.getTemplateChoices();
177                                 nodeTemplateUserInteraction = true;
178
179                                 TNodeTemplate toBeRemoved = stepByStepCompleter.getPlaceHolder();
180                                 topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved);
181                                 topology.getNodeTemplateOrRelationshipTemplate().remove(genericRelationship);
182
183                                 solutionList.add(topology);
184                                 logger.info("Returning topology for user interaction");
185
186                                 return solutionList;
187                         } else if (unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) {
188
189                                 // the topology is complete, return it to Winery
190
191                                 logger.info("The topology is complete.");
192
193                                 nodeTemplateUserInteraction = false;
194                                 solutionList.add(topology);
195                                 return solutionList;
196                         }
197                 } else {
198                         // the one-step approach is chosen or the topology contains deferred-RelationshipTemplates
199                         if (unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) {
200                                 // the topology does not contain any elements that have to completed, it can be defined as complete
201                                 if (solutions.isEmpty()) {
202                                         // no topology solutions found, topology could not be completed due to missing types.
203                                         // Return an empty list, an error message will be shown in Winery.
204                                         return new ArrayList<TTopologyTemplate>();
205                                 } else {
206                                         // this topology is complete, set its boolean value in the map to true
207                                         for (Integer i : solutions.keySet()) {
208                                                 for (TTopologyTemplate t : solutions.get(i).keySet()) {
209                                                         if (t.equals(topology)) {
210                                                                 solutions.get(i).put(topology, true);
211                                                         }
212                                                 }
213                                         }
214
215                                         // check if the map still contains any incomplete topologies. If this is the case, the recursion will continue.
216                                         // Otherwise the solutions map is returned.
217                                         if (!solutions.values().contains(false)) {
218                                                 logger.info("The topology is complete.");
219                                                 List<TTopologyTemplate> sol = new ArrayList<TTopologyTemplate>();
220
221                                                 for (Integer i : solutions.keySet()) {
222                                                         sol.addAll(solutions.get(i).keySet());
223                                                 }
224                                                 return sol;
225                                         }
226                                 }
227                         } else if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) {
228
229                                 logger.info("The topology contains Requirements, but no Place Holders.");
230
231                                 // complete a topology containing Requirements in one step using the RequirementCompleter class
232                                 RequirementCompleter requirementCompleter = new RequirementCompleter(topology);
233
234                                 List<TTopologyTemplate> completeTopology = requirementCompleter.completeRequirementTopology(unfulfilledRequirements, toscaAnalyzer);
235
236                                 for (TTopologyTemplate topologySolution : completeTopology) {
237                                         Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
238                                         topologyMap.put(topologySolution, false);
239                                         solutions.put(index, topologyMap);
240                                 }
241
242                                 // complete all topology solutions recursively
243                                 for (TTopologyTemplate topologySolution : completeTopology) {
244                                         manageCompletion(topologySolution);
245                                         index++;
246                                 }
247
248                         } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty() || !unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) {
249
250                                 logger.info("The topology contains one or more PlaceHolders.");
251
252                                 // complete a topology containing place holders in one step using the PlaceHolderCompleter class
253                                 PlaceHolderCompleter placeHolderCompleter = new PlaceHolderCompleter(topology);
254
255                                 List<TTopologyTemplate> completeTopology = placeHolderCompleter.completePlaceholderTopology(placeHolders, toscaAnalyzer);
256
257                                 if (placeHolderCompleter.getUserInteraction()) {
258                                         choices = placeHolderCompleter.getChoices();
259                                         userInteraction = true;
260
261                                         // user interaction is necessary to choose a inserted Relationship Template, return the topology to winery
262                                         List<TTopologyTemplate> intermediateSolutions = new ArrayList<>();
263                                         TRelationshipTemplate toBeRemoved = null;
264                                         for (TEntityTemplate entityTemplate : topology.getNodeTemplateOrRelationshipTemplate()) {
265                                                 if (entityTemplate instanceof TRelationshipTemplate) {
266                                                         TRelationshipTemplate relationshipTemplate = (TRelationshipTemplate) entityTemplate;
267                                                         if (relationshipTemplate.getTargetElement().getRef().equals(placeHolderCompleter.getPlaceHolder())) {
268                                                                 toBeRemoved = relationshipTemplate;
269                                                         }
270                                                 }
271                                         }
272
273                                         topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved);
274                                         topology.getNodeTemplateOrRelationshipTemplate().remove(placeHolderCompleter.getPlaceHolder());
275
276                                         intermediateSolutions.add(topology);
277                                         return intermediateSolutions;
278                                 }
279
280                                 int i = 0;
281
282                                 for (TTopologyTemplate topologySolution : completeTopology) {
283                                         Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
284                                         topologyMap.put(topologySolution, false);
285                                         solutions.put(i, topologyMap);
286                                         i++;
287                                 }
288
289                                 for (TTopologyTemplate topologySolution : completeTopology) {
290                                         manageCompletion(topologySolution);
291                                 }
292                         } else if (!deferredRelations.isEmpty()) {
293
294                                 logger.info("The topology contains deferred RelationshipTemplates.");
295
296                                 // complete a topology containing deferred Relationship Templates in one step using the DeferredCompleter class
297                                 DeferredCompleter deferredCompleter = new DeferredCompleter(topology);
298                                 List<TTopologyTemplate> completeTopology = deferredCompleter.completeDeferredTopology(deferredRelations.get(0), toscaAnalyzer);
299
300                                 int i = 0;
301                                 for (TTopologyTemplate solutionTemplate : completeTopology) {
302                                         Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
303                                         topologyMap.put(solutionTemplate, false);
304                                         solutions.put(i, topologyMap);
305                                         i++;
306                                 }
307
308                                 for (TTopologyTemplate topologySolution : completeTopology) {
309                                         manageCompletion(topologySolution);
310                                 }
311                         }
312                         List<TTopologyTemplate> sol = new ArrayList<TTopologyTemplate>();
313                         for (Integer i : solutions.keySet()) {
314                                 sol.addAll(solutions.get(i).keySet());
315                         }
316                         return sol;
317                 }
318
319                 return new ArrayList<TTopologyTemplate>();
320         }
321
322         /**
323          * Returns whether an user interaction is necessary or not
324          *
325          * @return the field userInteraction
326          */
327         public boolean getUserInteraction() {
328                 return userInteraction;
329         }
330
331         /**
332          * The possible {@link TRelationshipTemplate} choices
333          *
334          * @return the field choices
335          */
336         public List<TEntityTemplate> getChoices() {
337                 return choices;
338         }
339
340         /**
341          * A map of {@link TNodeTemplate}s and {@link TRelationshipTemplate}s when completing a topology step by step
342          *
343          * @return the field nodeTemplateChoices
344          */
345         public Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> getTemplateChoices() {
346                 return templateChoices;
347         }
348
349         /**
350          * Returns whether user interaction by choosing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not
351          *
352          * @return the field nodeTemplateUserInteraction
353          */
354         public boolean getNodeTemplateUserInteraction() {
355                 return nodeTemplateUserInteraction;
356         }
357
358 }