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
10 * Pascal Hirmer - initial API and implementation
11 *******************************************************************************/
13 package org.eclipse.winery.topologymodeler.addons.topologycompleter.topologycompletion;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
19 import java.util.logging.Logger;
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;
36 * This class manages the completion of a TOSCA {@link TTopologyTemplate}.
38 public class CompletionManager {
40 private static final Logger logger = Logger.getLogger(CompletionManager.class.getName());
43 * {@link TOSCAAnalyzer} object to access the JAXB data model
45 TOSCAAnalyzer toscaAnalyzer;
48 * Map containing the topology solutions.
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.
54 Map<Integer, Map<TTopologyTemplate, Boolean>> solutions;
57 * Whether a step-by-step or an one-step approach is conducted
62 * Map containing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s to be chosen by the user in the step-by-step approach.
64 private Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> templateChoices;
67 * Whether a user interaction for choosing inserted {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not.
69 private boolean nodeTemplateUserInteraction = false;
72 * List containing {@link TRelationshipTemplate} to be chosen by the user.
74 private List<TEntityTemplate> choices;
77 * Whether a user interaction for choosing inserted {@link TRelationshipTemplate}s is necessary or not.
79 boolean userInteraction = false;
82 * The index of the topology solutions map.
87 * The class constructor.
89 * @param toscaAnalyzer
90 * the {@link TOSCAAnalyzer} object to access the data model
92 * whether the topology completion is processed step-by-step or not
94 public CompletionManager(TOSCAAnalyzer toscaAnalyzer, boolean stepByStep) {
95 this.toscaAnalyzer = toscaAnalyzer;
96 this.stepByStep = stepByStep;
99 // instantiate the solution map
100 solutions = new HashMap<Integer, Map<TTopologyTemplate, Boolean>>();
104 * This recursive method analyzes and completes a TOSCA {@link TTopologyTemplate}.
107 * the TOSCA {@link TTopologyTemplate} to be completed
109 * @return the complete TOSCA {@link TTopologyTemplate} object
111 public List<TTopologyTemplate> manageCompletion(TTopologyTemplate topology) {
113 // -------------------------
114 // Analyze topology template
115 // -------------------------
117 // the data model must be cleared before analyzing the topology
118 toscaAnalyzer.clear();
120 // analyze the content of the topology template
121 toscaAnalyzer.analyzeTOSCATopology(topology);
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
126 // --------------------------------
127 // Analyze unfulfilled requirements
128 // --------------------------------
129 Map<TRequirement, TNodeTemplate> unfulfilledRequirements = RequirementAnalyzer.analyzeRequirements(toscaAnalyzer);
131 // ---------------------------------------
132 // Analyze the occurrence of place holders
133 // ---------------------------------------
134 List<TNodeTemplate> placeHolders = PlaceHolderAnalyzer.analyzePlaceHolders(toscaAnalyzer);
136 // --------------------------------------------------------
137 // Analyze the occurrence of deferred RelationshipTemplates
138 // --------------------------------------------------------
139 List<TRelationshipTemplate> deferredRelations = DeferredAnalyzer.analyzeDeferredRelations(toscaAnalyzer);
141 // ---------------------
142 // Complete the topology
143 // ---------------------
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.");
151 List<TTopologyTemplate> solutionList = new ArrayList<TTopologyTemplate>();
153 if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty()) {
155 // complete a topology containing requirements step by step using the StepByStepCompleter class
156 StepByStepCompleter stepByStepCompleter = new StepByStepCompleter(topology);
157 stepByStepCompleter.completeTopologyStepByStep(unfulfilledRequirements, toscaAnalyzer);
159 // get the NodeTemplate choices for the user
160 templateChoices = stepByStepCompleter.getTemplateChoices();
161 nodeTemplateUserInteraction = true;
163 solutionList.add(topology);
165 logger.info("Returning topology for user interaction");
169 } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) {
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);
175 // get the NodeTemplate selection for the user to choose
176 templateChoices = stepByStepCompleter.getTemplateChoices();
177 nodeTemplateUserInteraction = true;
179 TNodeTemplate toBeRemoved = stepByStepCompleter.getPlaceHolder();
180 topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved);
181 topology.getNodeTemplateOrRelationshipTemplate().remove(genericRelationship);
183 solutionList.add(topology);
184 logger.info("Returning topology for user interaction");
187 } else if (unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) {
189 // the topology is complete, return it to Winery
191 logger.info("The topology is complete.");
193 nodeTemplateUserInteraction = false;
194 solutionList.add(topology);
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>();
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);
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>();
221 for (Integer i : solutions.keySet()) {
222 sol.addAll(solutions.get(i).keySet());
227 } else if (!unfulfilledRequirements.isEmpty() && placeHolders.isEmpty() && deferredRelations.isEmpty()) {
229 logger.info("The topology contains Requirements, but no Place Holders.");
231 // complete a topology containing Requirements in one step using the RequirementCompleter class
232 RequirementCompleter requirementCompleter = new RequirementCompleter(topology);
234 List<TTopologyTemplate> completeTopology = requirementCompleter.completeRequirementTopology(unfulfilledRequirements, toscaAnalyzer);
236 for (TTopologyTemplate topologySolution : completeTopology) {
237 Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
238 topologyMap.put(topologySolution, false);
239 solutions.put(index, topologyMap);
242 // complete all topology solutions recursively
243 for (TTopologyTemplate topologySolution : completeTopology) {
244 manageCompletion(topologySolution);
248 } else if (unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty() || !unfulfilledRequirements.isEmpty() && !placeHolders.isEmpty()) {
250 logger.info("The topology contains one or more PlaceHolders.");
252 // complete a topology containing place holders in one step using the PlaceHolderCompleter class
253 PlaceHolderCompleter placeHolderCompleter = new PlaceHolderCompleter(topology);
255 List<TTopologyTemplate> completeTopology = placeHolderCompleter.completePlaceholderTopology(placeHolders, toscaAnalyzer);
257 if (placeHolderCompleter.getUserInteraction()) {
258 choices = placeHolderCompleter.getChoices();
259 userInteraction = true;
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;
273 topology.getNodeTemplateOrRelationshipTemplate().remove(toBeRemoved);
274 topology.getNodeTemplateOrRelationshipTemplate().remove(placeHolderCompleter.getPlaceHolder());
276 intermediateSolutions.add(topology);
277 return intermediateSolutions;
282 for (TTopologyTemplate topologySolution : completeTopology) {
283 Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
284 topologyMap.put(topologySolution, false);
285 solutions.put(i, topologyMap);
289 for (TTopologyTemplate topologySolution : completeTopology) {
290 manageCompletion(topologySolution);
292 } else if (!deferredRelations.isEmpty()) {
294 logger.info("The topology contains deferred RelationshipTemplates.");
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);
301 for (TTopologyTemplate solutionTemplate : completeTopology) {
302 Map<TTopologyTemplate, Boolean> topologyMap = new HashMap<TTopologyTemplate, Boolean>();
303 topologyMap.put(solutionTemplate, false);
304 solutions.put(i, topologyMap);
308 for (TTopologyTemplate topologySolution : completeTopology) {
309 manageCompletion(topologySolution);
312 List<TTopologyTemplate> sol = new ArrayList<TTopologyTemplate>();
313 for (Integer i : solutions.keySet()) {
314 sol.addAll(solutions.get(i).keySet());
319 return new ArrayList<TTopologyTemplate>();
323 * Returns whether an user interaction is necessary or not
325 * @return the field userInteraction
327 public boolean getUserInteraction() {
328 return userInteraction;
332 * The possible {@link TRelationshipTemplate} choices
334 * @return the field choices
336 public List<TEntityTemplate> getChoices() {
341 * A map of {@link TNodeTemplate}s and {@link TRelationshipTemplate}s when completing a topology step by step
343 * @return the field nodeTemplateChoices
345 public Map<TNodeTemplate, Map<TNodeTemplate, List<TEntityTemplate>>> getTemplateChoices() {
346 return templateChoices;
350 * Returns whether user interaction by choosing {@link TNodeTemplate}s and {@link TRelationshipTemplate}s is necessary or not
352 * @return the field nodeTemplateUserInteraction
354 public boolean getNodeTemplateUserInteraction() {
355 return nodeTemplateUserInteraction;