Release version 1.13.7
[sdc.git] / openecomp-be / lib / openecomp-heat-lib / src / main / java / org / openecomp / sdc / heat / services / tree / HeatTreeManager.java
1 /*
2  * Copyright © 2018 European Support Limited
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package org.openecomp.sdc.heat.services.tree;
17
18 import java.io.InputStream;
19 import java.util.HashMap;
20 import java.util.HashSet;
21 import java.util.List;
22 import java.util.Map;
23 import java.util.Objects;
24 import java.util.Set;
25 import org.onap.sdc.tosca.services.YamlUtil;
26 import org.openecomp.core.utilities.file.FileContentHandler;
27 import org.openecomp.core.utilities.file.FileUtils;
28 import org.openecomp.core.utilities.json.JsonUtil;
29 import org.openecomp.core.validation.types.GlobalValidationContext;
30 import org.openecomp.sdc.common.utils.SdcCommon;
31 import org.openecomp.sdc.datatypes.error.ErrorMessage;
32 import org.openecomp.sdc.heat.datatypes.manifest.FileData;
33 import org.openecomp.sdc.heat.datatypes.manifest.ManifestContent;
34 import org.openecomp.sdc.heat.datatypes.model.HeatOrchestrationTemplate;
35 import org.openecomp.sdc.heat.datatypes.structure.Artifact;
36 import org.openecomp.sdc.heat.datatypes.structure.HeatStructureTree;
37 import org.openecomp.sdc.logging.api.Logger;
38 import org.openecomp.sdc.logging.api.LoggerFactory;
39
40 public class HeatTreeManager {
41
42     private static final Logger LOGGER = LoggerFactory.getLogger(HeatTreeManager.class);
43     private FileContentHandler heatContentMap = new FileContentHandler();
44     private byte[] manifest;
45     private HeatStructureTree tree = new HeatStructureTree();
46     private Map<String, HeatStructureTree> fileTreeRef = new HashMap<>();
47     private Map<String, Artifact> artifactRef = new HashMap<>();
48     private Map<String, Artifact> candidateOrphanArtifacts = new HashMap<>();
49     private Map<String, HeatStructureTree> nestedFiles = new HashMap<>();
50     private Map<HeatStructureTree, HeatStructureTree> volumeFileToParent = new HashMap<>();
51     private Map<HeatStructureTree, HeatStructureTree> networkFileToParent = new HashMap<>();
52     private Set<String> manifestFiles = new HashSet<>();
53
54     /**
55      * Add file.
56      *
57      * @param fileName the file name
58      * @param content  the content
59      */
60     public void addFile(String fileName, InputStream content) {
61         if (fileName.equals(SdcCommon.MANIFEST_NAME)) {
62             manifest = FileUtils.toByteArray(content);
63         } else {
64             heatContentMap.addFile(fileName, content);
65         }
66     }
67
68     /**
69      * Create tree.
70      */
71     public void createTree() {
72         if (manifest == null) {
73             LOGGER.error("Missing manifest file in the zip.");
74             return;
75         }
76         ManifestContent manifestData = JsonUtil.json2Object(new String(manifest), ManifestContent.class);
77         scanTree(null, manifestData.getData());
78         addNonNestedVolumeNetworkToTree(volumeFileToParent, nestedFiles.keySet(), true);
79         addNonNestedVolumeNetworkToTree(networkFileToParent, nestedFiles.keySet(), false);
80         handleOrphans();
81         tree = fileTreeRef.get(SdcCommon.PARENT);
82     }
83
84     private void handleOrphans() {
85         tree = fileTreeRef.get(SdcCommon.PARENT);
86         candidateOrphanArtifacts.forEach((key, value) -> tree.addArtifactToArtifactList(value));
87         nestedFiles.values().stream().filter(tree.getHeat()::contains).forEach(tree.getHeat()::remove);
88         heatContentMap.getFileList().stream().filter(this::isNotInManifestFiles).forEach(this::addTreeOther);
89     }
90
91     private boolean isNotInManifestFiles(String fileName) {
92         return !manifestFiles.contains(fileName);
93     }
94
95     private void addTreeOther(String fileName) {
96         if (tree.getOther() == null) {
97             tree.setOther(new HashSet<>());
98         }
99         HeatStructureTree other = new HeatStructureTree(fileName, false);
100         fileTreeRef.put(fileName, other);
101         tree.getOther().add(other);
102     }
103
104     private void handleHeatContentReference(HeatStructureTree fileHeatStructureTree, GlobalValidationContext globalContext) {
105         String fileName = fileHeatStructureTree.getFileName();
106         try (InputStream fileContent = this.heatContentMap.getFileContentAsStream(fileName)) {
107             HeatOrchestrationTemplate hot = new YamlUtil().yamlToObject(fileContent, HeatOrchestrationTemplate.class);
108             Set<String> nestedSet = HeatTreeManagerUtil.getNestedFiles(hot);
109             addHeatNestedFiles(fileHeatStructureTree, nestedSet);
110             Set<String> artifactSet = HeatTreeManagerUtil.getArtifactFiles(fileName, hot, globalContext);
111             addHeatArtifactFiles(fileHeatStructureTree, artifactSet);
112         } catch (Exception exp) {
113             LOGGER.debug("Invalid YAML received. No need to process content reference - ignoring", exp);
114         }
115     }
116
117     private void addHeatArtifactFiles(HeatStructureTree fileHeatStructureTree, Set<String> artifactSet) {
118         Artifact artifact;
119         for (String artifactName : artifactSet) {
120             FileData.Type type = candidateOrphanArtifacts.get(artifactName) != null ? candidateOrphanArtifacts.get(artifactName).getType() : null;
121             artifact = new Artifact(artifactName, type);
122             artifactRef.put(artifactName, artifact);
123             candidateOrphanArtifacts.remove(artifactName);
124             fileHeatStructureTree.addArtifactToArtifactList(artifact);
125         }
126     }
127
128     private void addHeatNestedFiles(HeatStructureTree fileHeatStructureTree, Set<String> nestedSet) {
129         HeatStructureTree childHeatStructureTree;
130         for (String nestedName : nestedSet) {
131             childHeatStructureTree = fileTreeRef.get(nestedName);
132             if (childHeatStructureTree == null) {
133                 childHeatStructureTree = new HeatStructureTree();
134                 childHeatStructureTree.setFileName(nestedName);
135                 fileTreeRef.put(nestedName, childHeatStructureTree);
136             }
137             fileHeatStructureTree.addHeatStructureTreeToNestedHeatList(childHeatStructureTree);
138             nestedFiles.put(childHeatStructureTree.getFileName(), childHeatStructureTree);
139         }
140     }
141
142     /**
143      * Add errors.
144      *
145      * @param validationErrors the validation errors
146      */
147     public void addErrors(Map<String, List<ErrorMessage>> validationErrors) {
148         validationErrors.entrySet().stream().filter(entry -> fileTreeRef.get(entry.getKey()) != null)
149             .forEach(entry -> entry.getValue().forEach(fileTreeRef.get(entry.getKey())::addErrorToErrorsList));
150         validationErrors.entrySet().stream().filter(entry -> artifactRef.get(entry.getKey()) != null)
151             .forEach(entry -> artifactRef.get(entry.getKey()).setErrors(entry.getValue()));
152     }
153
154     /**
155      * Scan tree.
156      *
157      * @param parent the parent
158      * @param data   the data
159      */
160     public void scanTree(String parent, List<FileData> data) {
161         String fileName;
162         FileData.Type type;
163         HeatStructureTree parentHeatStructureTree;
164         HeatStructureTree fileHeatStructureTree;
165         HeatStructureTree childHeatStructureTree;
166         Artifact artifact;
167         if (parent == null) {
168             parentHeatStructureTree = new HeatStructureTree();
169             fileTreeRef.put(SdcCommon.PARENT, parentHeatStructureTree);
170             fileTreeRef.put(SdcCommon.MANIFEST_NAME, parentHeatStructureTree);
171         } else {
172             parentHeatStructureTree = fileTreeRef.get(parent);
173         }
174         for (FileData fileData : data) {
175             fileName = fileData.getFile();
176             manifestFiles.add(fileName);
177             type = fileData.getType();
178             if (Objects.nonNull(type) && FileData.Type.HEAT.equals(type)) {
179                 fileHeatStructureTree = fileTreeRef.get(fileName);
180                 if (fileHeatStructureTree == null) {
181                     fileHeatStructureTree = new HeatStructureTree();
182                     fileTreeRef.put(fileName, fileHeatStructureTree);
183                 }
184                 fileHeatStructureTree.setFileName(fileName);
185                 fileHeatStructureTree.setBase(fileData.getBase());
186                 fileHeatStructureTree.setType(type);
187                 handleHeatContentReference(fileHeatStructureTree, null);
188                 parentHeatStructureTree.addHeatToHeatList(fileHeatStructureTree);
189                 if (fileData.getData() != null) {
190                     scanTree(fileName, fileData.getData());
191                 }
192             } else {
193                 childHeatStructureTree = new HeatStructureTree();
194                 childHeatStructureTree.setFileName(fileName);
195                 childHeatStructureTree.setBase(fileData.getBase());
196                 childHeatStructureTree.setType(type);
197                 fileTreeRef.put(childHeatStructureTree.getFileName(), childHeatStructureTree);
198                 if (type == null) {
199                     parentHeatStructureTree.addOtherToOtherList(childHeatStructureTree);
200                 } else if (FileData.Type.HEAT_NET.equals(type)) {
201                     networkFileToParent.put(childHeatStructureTree, parentHeatStructureTree);
202                     if (fileData.getData() != null) {
203                         scanTree(fileName, fileData.getData());
204                     }
205                     handleHeatContentReference(childHeatStructureTree, null);
206                 } else if (FileData.Type.HEAT_VOL.equals(type)) {
207                     volumeFileToParent.put(childHeatStructureTree, parentHeatStructureTree);
208                     if (fileData.getData() != null) {
209                         scanTree(fileName, fileData.getData());
210                     }
211                     handleHeatContentReference(childHeatStructureTree, null);
212                 } else if (FileData.Type.HEAT_ENV.equals(type)) {
213                     if (parentHeatStructureTree != null && parentHeatStructureTree.getFileName() != null) {
214                         parentHeatStructureTree.setEnv(childHeatStructureTree);
215                     } else {
216                         if (parentHeatStructureTree.getOther() == null) {
217                             parentHeatStructureTree.setOther(new HashSet<>());
218                         }
219                         parentHeatStructureTree.getOther().add(childHeatStructureTree);
220                     }
221                 } else if (FileData.Type.HELM.equals(type)) {
222                     parentHeatStructureTree.addToHelmList(childHeatStructureTree);
223                 } else {
224                     artifact = new Artifact(fileName, type);
225                     if (!artifactRef.keySet().contains(fileName)) {
226                         artifactRef.put(fileName, artifact);
227                         candidateOrphanArtifacts.put(fileName, artifact);
228                     }
229                 }
230             }
231         }
232     }
233
234     private void addNonNestedVolumeNetworkToTree(Map<HeatStructureTree, HeatStructureTree> netVolToParent, Set<String> nestedFileNames,
235                                                  boolean isVolume) {
236         for (Map.Entry<HeatStructureTree, HeatStructureTree> entry : netVolToParent.entrySet()) {
237             HeatStructureTree netOrVolNode = entry.getKey();
238             HeatStructureTree parent = entry.getValue();
239             if (!nestedFileNames.contains(netOrVolNode.getFileName())) {
240                 if (isVolume) {
241                     parent.addVolumeFileToVolumeList(netOrVolNode);
242                 } else {
243                     parent.addNetworkToNetworkList(netOrVolNode);
244                 }
245             }
246         }
247     }
248
249     public HeatStructureTree getTree() {
250         return tree;
251     }
252 }