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.completer;
15 import java.util.ArrayList;
16 import java.util.HashMap;
17 import java.util.List;
21 import org.eclipse.winery.common.ModelUtilities;
22 import org.eclipse.winery.model.tosca.TCapability;
23 import org.eclipse.winery.model.tosca.TEntityTemplate;
24 import org.eclipse.winery.model.tosca.TNodeTemplate;
25 import org.eclipse.winery.model.tosca.TNodeType;
26 import org.eclipse.winery.model.tosca.TRelationshipTemplate;
27 import org.eclipse.winery.model.tosca.TRelationshipType;
28 import org.eclipse.winery.model.tosca.TRequirement;
29 import org.eclipse.winery.model.tosca.TRequirementType;
30 import org.eclipse.winery.model.tosca.TTopologyTemplate;
31 import org.eclipse.winery.topologymodeler.addons.topologycompleter.analyzer.TOSCAAnalyzer;
32 import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.NodeTemplateConnector;
33 import org.eclipse.winery.topologymodeler.addons.topologycompleter.helper.Utils;
36 * This class serves the completion of a topology containing Deferred {@link TRelationshipTemplate}s.
38 public class DeferredCompleter {
41 * The TOSCA {@link TTopologyTemplate} document
43 TTopologyTemplate topology;
46 * A Map containing the requirements removed during the algorithm and their corresponding {@link TNodeTemplate}.
48 Map<TRequirement, TNodeTemplate> removedRequirements;
51 * Constructor of the class.
54 * the {@link TTopologyTemplate} to be completed
56 public DeferredCompleter(TTopologyTemplate topology) {
57 this.topology = topology;
58 removedRequirements = new HashMap<TRequirement, TNodeTemplate>();
62 * Completes a {@link TTopologyTemplate} that contains deferred {@link TRelationshipTemplate}s with a depth search algorithm. A deferred {@link TRelationshipTemplate} serves as place holder for a
63 * number of {@link TNodeTemplate}s and {@link TRelationshipTemplate}s.
65 * @param deferredRelation
66 * all found deferred {@link TRelationshipTemplate}s in the topology
67 * @param toscaAnalyzer
68 * the {@link TOSCAAnalyzer} object to access the data model
70 * @return the completed topology
72 public List<TTopologyTemplate> completeDeferredTopology(TRelationshipTemplate deferredRelation, TOSCAAnalyzer toscaAnalyzer) {
74 List<TTopologyTemplate> solutions = new ArrayList<TTopologyTemplate>();
76 TNodeTemplate source = (TNodeTemplate) deferredRelation.getSourceElement().getRef();
77 TNodeTemplate target = (TNodeTemplate) deferredRelation.getTargetElement().getRef();
79 // TODO Remove this "if clause" after the Provisioning-API is implemented. At the moment Deferred RelationshipTemplates can't be completed
80 // without the existence of Requirements
81 if (source.getRequirements() != null && !source.getRequirements().getRequirement().isEmpty()) {
82 topology.getNodeTemplateOrRelationshipTemplate().remove(deferredRelation);
83 runDepthFirstSearch(source, target, new ArrayList<TEntityTemplate>(), solutions, toscaAnalyzer);
87 * Note: This code adds Requirements to NodeTemplates that has been removed during the algorithm but could not
88 * be used to replace the Deferred-RelationshipTemplates. If this step is not done, requirements could get lost.
90 * Therefore all removed Requirements are checked for fulfillment in the topology. If they have not been fulfilled
91 * they are re-added to the topology.
93 Set<TRequirement> keySet = removedRequirements.keySet();
95 for (TTopologyTemplate topologyTemplate: solutions) {
96 boolean fulfilled = false;
97 for (TRequirement requirement: keySet) {
98 for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
99 if (entity instanceof TNodeTemplate) {
100 TNodeTemplate nodeTemplate = (TNodeTemplate) entity;
101 if (nodeTemplate.getCapabilities() != null) {
102 for (TCapability capability: nodeTemplate.getCapabilities().getCapability()) {
103 String reqCapaType = "";
104 for (TRequirementType reqType: toscaAnalyzer.getRequirementTypes()) {
105 if (reqType.getName().equals(requirement.getType().getLocalPart())) {
106 reqCapaType = reqType.getRequiredCapabilityType().getLocalPart();
109 if (capability.getName().equals(reqCapaType)) {
117 for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
118 if (entity.equals(removedRequirements.get(requirement))) {
119 TNodeTemplate foundNT = (TNodeTemplate) entity;
120 foundNT.getRequirements().getRequirement().add(requirement);
131 * Runs a recursive depth search to find the path to the target NodeTemplate.
134 * the source node of a given {@link TRelationshipTemplate}
136 * the target node of a given {@link TRelationshipTemplate}
138 * the current path to the target (can be incomplete)
140 * list containing all possible solutions of the completion
141 * @param toscaAnalyzer
142 * the {@link TOSCAAnalyzer} object to access the data model
144 * @return the path to the target NodeTemplate
146 private void runDepthFirstSearch(TNodeTemplate source, TNodeTemplate target, List<TEntityTemplate> path, List<TTopologyTemplate> solutions, TOSCAAnalyzer toscaAnalyzer) {
148 List<TNodeType> matchingNodeTypes = new ArrayList<TNodeType>();
150 if (source.getRequirements() != null) {
152 List<TRequirement> requirementsOfTemplate = new ArrayList<>();
153 for (TRequirement requirement : source.getRequirements().getRequirement()) {
154 requirementsOfTemplate.add(requirement);
157 for (TRequirement requirement : requirementsOfTemplate) {
159 // save the requirement to a list to avoid losing requirements (see line 83)
160 TRequirement sourceRequirement = new TRequirement();
161 sourceRequirement.setId(requirement.getId());
162 sourceRequirement.setName(requirement.getName());
163 sourceRequirement.setType(requirement.getType());
165 // Remember the removed requirements. In case a requirement
166 // can't be used for completing the deferred RelationshipTemplate it has to be re-added to the topology.
167 removedRequirements.put(sourceRequirement, source);
169 // search for matching NodeTypes for the requirement
170 matchingNodeTypes.addAll(Utils.matchRequirementAndCapability(requirement, toscaAnalyzer));
172 // remove the requirement so it is not handled again during the algorithm
173 source.getRequirements().getRequirement().remove(requirement);
176 for (TNodeType match : matchingNodeTypes) {
178 if (match.getName().equals(target.getType().getLocalPart()) && match.getTargetNamespace().equals(target.getType().getNamespaceURI())) {
179 // the search was successful connect the target
180 List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(source, target, toscaAnalyzer, null);
182 for (TRelationshipType rt : suitableRTs) {
183 TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, target);
184 path.add(relationship);
187 TTopologyTemplate possiblePath = new TTopologyTemplate();
188 possiblePath.getNodeTemplateOrRelationshipTemplate().addAll(topology.getNodeTemplateOrRelationshipTemplate());
190 // add the path to the topology
191 for (TEntityTemplate pathTemplate : path) {
192 possiblePath.getNodeTemplateOrRelationshipTemplate().add(pathTemplate);
195 possiblePath.getNodeTemplateOrRelationshipTemplate().remove(target);
197 // this is no good style, however the target has to be the last item in the list for a proper stack layouting
198 possiblePath.getNodeTemplateOrRelationshipTemplate().add(target);
199 solutions.add(possiblePath);
203 // the end of the path is not reached, add the found NodeTemplate and continue the depth search
204 TNodeTemplate instantiatedNodeTemplate = ModelUtilities.instantiateNodeTemplate(match);
206 List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(source, instantiatedNodeTemplate, toscaAnalyzer, null);
208 for (TRelationshipType rt : suitableRTs) {
209 TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, instantiatedNodeTemplate);
210 path.add(relationship);
212 path.add(instantiatedNodeTemplate);
213 runDepthFirstSearch(instantiatedNodeTemplate, target, path, solutions, toscaAnalyzer);