NPE in parse tosca file
[externalapi/nbi.git] / src / main / java / org / onap / nbi / apis / servicecatalog / ToscaInfosProcessor.java
1 /**
2  * Copyright (c) 2018 Orange
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
5  * the License. You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
10  * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
11  * specific language governing permissions and limitations under the License.
12  */
13 package org.onap.nbi.apis.servicecatalog;
14
15 import java.io.File;
16 import java.io.FileInputStream;
17 import java.io.FileOutputStream;
18 import java.io.IOException;
19 import java.sql.Timestamp;
20 import java.util.ArrayList;
21 import java.util.LinkedHashMap;
22 import java.util.List;
23 import java.util.zip.ZipEntry;
24 import java.util.zip.ZipInputStream;
25 import org.apache.commons.collections.CollectionUtils;
26 import org.apache.commons.io.FileUtils;
27 import org.onap.nbi.exceptions.TechnicalException;
28 import org.slf4j.Logger;
29 import org.slf4j.LoggerFactory;
30 import org.springframework.beans.factory.annotation.Autowired;
31 import org.springframework.stereotype.Service;
32 import com.fasterxml.jackson.databind.ObjectMapper;
33 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
34
35 @Service
36 public class ToscaInfosProcessor {
37
38     @Autowired
39     SdcClient sdcClient;
40
41     final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); // jackson databind
42
43     private static final Logger LOGGER = LoggerFactory.getLogger(ToscaInfosProcessor.class);
44
45     public void buildResponseWithToscaInfos(LinkedHashMap toscaInfosTopologyTemplate,
46         LinkedHashMap serviceCatalogResponse) {
47         if (toscaInfosTopologyTemplate.get("inputs") != null) {
48             ArrayList serviceSpecCharacteristic = new ArrayList();
49             LinkedHashMap toscaInfos = (LinkedHashMap) toscaInfosTopologyTemplate.get("inputs");
50             for (Object key : toscaInfos.keySet()) {
51                 String keyString = (String) key;
52                 LinkedHashMap inputParameter = (LinkedHashMap) toscaInfos.get(key);
53                 LinkedHashMap mapParameter = new LinkedHashMap();
54                 String parameterType = (String) inputParameter.get("type");
55                 mapParameter.put("name", keyString);
56                 mapParameter.put("description", inputParameter.get("description"));
57                 mapParameter.put("valueType", parameterType);
58                 mapParameter.put("@type", "ONAPserviceCharacteristic");
59                 mapParameter.put("required", inputParameter.get("required"));
60                 mapParameter.put("status", inputParameter.get("status"));
61                 List<LinkedHashMap> serviceSpecCharacteristicValues =
62                     buildServiceSpecCharacteristicsValues(inputParameter, parameterType);
63                 mapParameter.put("serviceSpecCharacteristicValue", serviceSpecCharacteristicValues);
64                 serviceSpecCharacteristic.add(mapParameter);
65             }
66
67             serviceCatalogResponse.put("serviceSpecCharacteristic", serviceSpecCharacteristic);
68         }
69         LinkedHashMap nodeTemplate = (LinkedHashMap) toscaInfosTopologyTemplate.get("node_templates");
70
71         List<LinkedHashMap> resourceSpecifications =
72             (List<LinkedHashMap>) serviceCatalogResponse.get("resourceSpecification");
73         for (LinkedHashMap resourceSpecification : resourceSpecifications) {
74             String id = (String) resourceSpecification.get("id");
75             LOGGER.debug("get tosca infos for service id: " + id);
76             LinkedHashMap toscaInfosFromResourceId = getToscaInfosFromResourceUUID(nodeTemplate, id);
77             if (toscaInfosFromResourceId != null) {
78                 resourceSpecification.put("modelCustomizationId", toscaInfosFromResourceId.get("customizationUUID"));
79                 resourceSpecification.put("modelCustomizationName", toscaInfosFromResourceId.get("name"));
80             }
81
82         }
83     }
84
85     private List<LinkedHashMap> buildServiceSpecCharacteristicsValues(LinkedHashMap parameter, String parameterType) {
86         List<LinkedHashMap> serviceSpecCharacteristicValues = new ArrayList<>();
87         if (!"map".equalsIgnoreCase(parameterType) && !"list".equalsIgnoreCase(parameterType)) {
88             LOGGER.debug("get tosca infos for serviceSpecCharacteristicValues of type map or string : " + parameter);
89             Object aDefault = parameter.get("default");
90             if (parameter.get("entry_schema") != null) {
91                 ArrayList entrySchema = (ArrayList) parameter.get("entry_schema");
92                 if (CollectionUtils.isNotEmpty(entrySchema)) {
93                     buildCharacteristicValuesFormShema(parameterType, serviceSpecCharacteristicValues, aDefault,
94                         entrySchema);
95                 }
96             }
97         }
98         return serviceSpecCharacteristicValues;
99     }
100
101     private void buildCharacteristicValuesFormShema(String parameterType,
102         List<LinkedHashMap> serviceSpecCharacteristicValues, Object aDefault, ArrayList entry_schema) {
103         LinkedHashMap constraints = (LinkedHashMap) entry_schema.get(0);
104         if (constraints != null) {
105             ArrayList constraintsList = (ArrayList) constraints.get("constraints");
106             if (CollectionUtils.isNotEmpty(constraintsList)) {
107                 LinkedHashMap valuesMap = (LinkedHashMap) constraintsList.get(0);
108                 if (valuesMap != null) {
109                     List<Object> values = (List<Object>) valuesMap.get("valid_values");
110                     for (Object value : values) {
111                         String stringValue = value.toString();
112                         LinkedHashMap serviceSpecCharacteristicValue = new LinkedHashMap();
113                         serviceSpecCharacteristicValue.put("isDefault",
114                             aDefault != null && aDefault.toString().equals(stringValue));
115                         serviceSpecCharacteristicValue.put("value", stringValue);
116                         serviceSpecCharacteristicValue.put("valueType", parameterType);
117                         serviceSpecCharacteristicValues.add(serviceSpecCharacteristicValue);
118                     }
119                 }
120             }
121         }
122     }
123
124
125     private LinkedHashMap getToscaInfosFromResourceUUID(LinkedHashMap node_templates, String name) {
126         if (node_templates != null) {
127             for (Object nodeTemplateObject : node_templates.values()) {
128                 LinkedHashMap nodeTemplate = (LinkedHashMap) nodeTemplateObject;
129                 LinkedHashMap metadata = (LinkedHashMap) nodeTemplate.get("metadata");
130                 String metadataUUID = (String) metadata.get("UUID");
131                 String metadataType = (String) metadata.get("type");
132                 if ("VF".equalsIgnoreCase(metadataType) && name.equalsIgnoreCase(metadataUUID)) {
133                     return metadata;
134                 }
135             }
136         }
137
138         return null;
139     }
140
141
142     public LinkedHashMap getToscaInfos(LinkedHashMap sdcResponse) {
143
144         LinkedHashMap topologyTemplate = null;
145
146         String toscaModelUrl = (String) sdcResponse.get("toscaModelURL");
147         String serviceId = (String) sdcResponse.get("uuid");
148         File toscaFile = sdcClient.callGetWithAttachment(toscaModelUrl);
149         Timestamp timestamp = new Timestamp(System.currentTimeMillis());
150         String tempFolderName = serviceId + timestamp;
151         File folderTemp = null;
152
153         try {
154             unZipArchive(toscaFile.getName(), tempFolderName);
155             folderTemp = new File(tempFolderName);
156             LOGGER.debug("temp folder for tosca files : " + folderTemp.getName());
157
158             LinkedHashMap toscaMetaFileHashMap = parseToscaFile(tempFolderName + "/TOSCA-Metadata/TOSCA.meta");
159             if (toscaMetaFileHashMap.get("Entry-Definitions") == null) {
160                 throw new NullPointerException("no Entry-Definitions node in TOSCA.meta");
161             }
162             String toscaFilePath = (String) toscaMetaFileHashMap.get("Entry-Definitions");
163             LinkedHashMap toscaFileHashMap = parseToscaFile(tempFolderName + "/" + toscaFilePath);
164
165             if (toscaFileHashMap.get("topology_template") == null) {
166                 throw new NullPointerException("no topology_template node in tosca file");
167             }
168             topologyTemplate = (LinkedHashMap) toscaFileHashMap.get("topology_template");
169
170         }  catch (NullPointerException e) {
171             LOGGER.warn("unable to parse tosca file for id : " + serviceId, e);
172             return null;
173
174         }finally {
175
176             try {
177                 LOGGER.debug("deleting temp folder for tosca files : " + folderTemp.getName());
178                 FileUtils.deleteDirectory(folderTemp);
179                 LOGGER.debug("deleting tosca archive : " + toscaFile.getName());
180                 FileUtils.forceDelete(toscaFile);
181                 return topologyTemplate;
182
183             } catch (IOException e) {
184                 LOGGER.error("unable to delete temp directory tosca file for id : " + serviceId, e);
185                 return null;
186             }
187         }
188
189     }
190
191
192     private LinkedHashMap parseToscaFile(String fileName) {
193
194         File toscaFile = new File(fileName);
195         if (!toscaFile.exists()) {
196             throw new TechnicalException("unable to find  file : " + fileName);
197         }
198         try {
199             return (LinkedHashMap) mapper.readValue(toscaFile, Object.class);
200         } catch (IOException e) {
201             LOGGER.warn("unable to parse tosca file : " + fileName, e);
202             throw new TechnicalException("Unable to parse tosca file : " + fileName);
203
204         } catch (NullPointerException e) {
205             LOGGER.warn("unable to find tosca file : " + fileName, e);
206             throw new TechnicalException("unable to find tosca file : " + fileName);
207         }
208     }
209
210
211     /**
212      * Unzip it
213      *
214      * @param zipFile input zip file
215      * @param outputFolder zip file output folder
216      */
217     private void unZipArchive(String zipFile, String outputFolder) {
218
219         byte[] buffer = new byte[1024];
220
221         try {
222
223             // create output directory is not exists
224             File folder = new File(outputFolder);
225             if (!folder.exists()) {
226                 folder.mkdir();
227             }
228
229             // get the zip file content
230             try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
231                 // get the zipped file list entry
232                 ZipEntry ze = zis.getNextEntry();
233
234                 while (ze != null) {
235
236                     String fileName = ze.getName();
237                     File newFile = new File(outputFolder + File.separator + fileName);
238
239                     LOGGER.debug("File to unzip : " + newFile.getAbsoluteFile());
240
241                     // create all non exists folders
242                     // else you will hit FileNotFoundException for compressed folder
243                     new File(newFile.getParent()).mkdirs();
244
245                     try (FileOutputStream fos = new FileOutputStream(newFile)) {
246
247                         int len;
248                         while ((len = zis.read(buffer)) > 0) {
249                             fos.write(buffer, 0, len);
250                         }
251
252                         fos.close();
253                     }
254                     ze = zis.getNextEntry();
255                 }
256
257                 zis.closeEntry();
258                 zis.close();
259             }
260
261             LOGGER.debug("Done");
262
263         } catch (IOException ex) {
264             LOGGER.error("Error while unzipping ToscaModel archive from ONAP", ex);
265             throw new TechnicalException("Error while unzipping ToscaModel archive from ONAP");
266         }
267     }
268
269
270 }