Add winery source code
[vfc/nfvo/wfengine.git] / winery / org.eclipse.winery.topologymodeler / src / main / java / org / eclipse / winery / topologymodeler / addons / topologycompleter / topologycompletion / completer / DeferredCompleter.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.completer;
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.Set;
20
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;
34
35 /**
36  * This class serves the completion of a topology containing Deferred {@link TRelationshipTemplate}s.
37  */
38 public class DeferredCompleter {
39
40         /**
41          * The TOSCA {@link TTopologyTemplate} document
42          */
43         TTopologyTemplate topology;
44
45         /**
46          * A Map containing the requirements removed during the algorithm and their corresponding {@link TNodeTemplate}.
47          */
48         Map<TRequirement, TNodeTemplate> removedRequirements;
49
50         /**
51          * Constructor of the class.
52          *
53          * @param topology
54          *            the {@link TTopologyTemplate} to be completed
55          */
56         public DeferredCompleter(TTopologyTemplate topology) {
57                 this.topology = topology;
58                 removedRequirements = new HashMap<TRequirement, TNodeTemplate>();
59         }
60
61         /**
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.
64          *
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
69          *
70          * @return the completed topology
71          */
72         public List<TTopologyTemplate> completeDeferredTopology(TRelationshipTemplate deferredRelation, TOSCAAnalyzer toscaAnalyzer) {
73
74                 List<TTopologyTemplate> solutions = new ArrayList<TTopologyTemplate>();
75
76                 TNodeTemplate source = (TNodeTemplate) deferredRelation.getSourceElement().getRef();
77                 TNodeTemplate target = (TNodeTemplate) deferredRelation.getTargetElement().getRef();
78
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);
84                 }
85
86                 /**
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.
89                  *
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.
92                  */
93                 Set<TRequirement> keySet = removedRequirements.keySet();
94
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();
107                                                                         }
108                                                                 }
109                                                                 if (capability.getName().equals(reqCapaType)) {
110                                                                         fulfilled = true;
111                                                                 }
112                                                         }
113                                                 }
114                                         }
115                                 }
116                                 if (!fulfilled) {
117                                         for (TEntityTemplate entity: topologyTemplate.getNodeTemplateOrRelationshipTemplate()) {
118                                                 if (entity.equals(removedRequirements.get(requirement))) {
119                                                         TNodeTemplate foundNT = (TNodeTemplate) entity;
120                                                         foundNT.getRequirements().getRequirement().add(requirement);
121                                                 }
122                                         }
123                                 }
124                         }
125                 }
126
127                 return solutions;
128         }
129
130         /**
131          * Runs a recursive depth search to find the path to the target NodeTemplate.
132          *
133          * @param source
134          *            the source node of a given {@link TRelationshipTemplate}
135          * @param target
136          *            the target node of a given {@link TRelationshipTemplate}
137          * @param path
138          *            the current path to the target (can be incomplete)
139          * @param solutions
140          *                        list containing all possible solutions of the completion
141          * @param toscaAnalyzer
142          *                the {@link TOSCAAnalyzer} object to access the data model
143          *
144          * @return the path to the target NodeTemplate
145          */
146         private void runDepthFirstSearch(TNodeTemplate source, TNodeTemplate target, List<TEntityTemplate> path, List<TTopologyTemplate> solutions, TOSCAAnalyzer toscaAnalyzer) {
147
148                 List<TNodeType> matchingNodeTypes = new ArrayList<TNodeType>();
149
150                 if (source.getRequirements() != null) {
151
152                         List<TRequirement> requirementsOfTemplate = new ArrayList<>();
153                         for (TRequirement requirement : source.getRequirements().getRequirement()) {
154                                 requirementsOfTemplate.add(requirement);
155                         }
156
157                         for (TRequirement requirement : requirementsOfTemplate) {
158
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());
164
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);
168
169                                 // search for matching NodeTypes for the requirement
170                                 matchingNodeTypes.addAll(Utils.matchRequirementAndCapability(requirement, toscaAnalyzer));
171
172                                 // remove the requirement so it is not handled again during the algorithm
173                                 source.getRequirements().getRequirement().remove(requirement);
174                         }
175                 }
176                 for (TNodeType match : matchingNodeTypes) {
177
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);
181
182                                 for (TRelationshipType rt : suitableRTs) {
183                                         TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, target);
184                                         path.add(relationship);
185                                 }
186
187                                 TTopologyTemplate possiblePath = new TTopologyTemplate();
188                                 possiblePath.getNodeTemplateOrRelationshipTemplate().addAll(topology.getNodeTemplateOrRelationshipTemplate());
189
190                                 // add the path to the topology
191                                 for (TEntityTemplate pathTemplate : path) {
192                                         possiblePath.getNodeTemplateOrRelationshipTemplate().add(pathTemplate);
193                                 }
194
195                                 possiblePath.getNodeTemplateOrRelationshipTemplate().remove(target);
196
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);
200                                 path.clear();
201                         } else {
202
203                                 // the end of the path is not reached, add the found NodeTemplate and continue the depth search
204                                 TNodeTemplate instantiatedNodeTemplate = ModelUtilities.instantiateNodeTemplate(match);
205
206                                 List<TRelationshipType> suitableRTs = NodeTemplateConnector.findRelationshipType(source, instantiatedNodeTemplate, toscaAnalyzer, null);
207
208                                 for (TRelationshipType rt : suitableRTs) {
209                                         TRelationshipTemplate relationship = ModelUtilities.instantiateRelationshipTemplate(rt, source, instantiatedNodeTemplate);
210                                         path.add(relationship);
211                                 }
212                                 path.add(instantiatedNodeTemplate);
213                                 runDepthFirstSearch(instantiatedNodeTemplate, target, path, solutions, toscaAnalyzer);
214
215                         }
216                 }
217         }
218 }