Add junit coverage to TimedOutException class
[appc.git] / appc-config / appc-config-params / provider / src / main / java / org / onap / sdnc / config / params / transformer / tosca / ArtifactProcessorImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * =============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * 
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.sdnc.config.params.transformer.tosca;
26
27 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
28 import java.io.IOException;
29 import java.io.OutputStream;
30 import java.io.OutputStreamWriter;
31 import java.util.ArrayList;
32 import java.util.HashMap;
33 import java.util.Iterator;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39 import org.apache.commons.lang.StringUtils;
40 import org.onap.sdnc.config.params.data.Parameter;
41 import org.onap.sdnc.config.params.data.PropertyDefinition;
42 import org.onap.sdnc.config.params.data.RequestKey;
43 import org.onap.sdnc.config.params.data.ResponseKey;
44 import org.onap.sdnc.config.params.transformer.tosca.exceptions.ArtifactProcessorException;
45 import org.openecomp.sdc.tosca.datatypes.model.NodeTemplate;
46 import org.openecomp.sdc.tosca.datatypes.model.NodeType;
47 import org.openecomp.sdc.tosca.datatypes.model.ServiceTemplate;
48 import org.openecomp.sdc.tosca.datatypes.model.TopologyTemplate;
49 import org.openecomp.sdc.tosca.services.YamlUtil;
50 import org.slf4j.MDC;
51 import com.att.eelf.configuration.EELFLogger;
52 import com.att.eelf.configuration.EELFManager;
53 import com.fasterxml.jackson.core.JsonProcessingException;
54 import com.fasterxml.jackson.databind.ObjectMapper;
55 import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
56
57 public class ArtifactProcessorImpl implements ArtifactProcessor {
58     private static final String DERIVEDFROM = "org.openecomp.genericvnf";
59     private static final EELFLogger Log =
60             EELFManager.getInstance().getLogger(ArtifactProcessorImpl.class);
61     private static final String EQUALSENCODING = "=";
62     private static final String COLONENCODING = ":";
63     private static final String COMMAENCODING = ",";
64     private static final String GREATERTHANENCODING = ">";
65     private static final String LESSTHANENCODING = "<";
66
67     @Override
68     public void generateArtifact(PropertyDefinition artifact, OutputStream stream)
69             throws ArtifactProcessorException {
70         MDC.clear();
71         MDC.put(MDC_SERVICE_NAME, "ArtifactGenerator");
72         Log.info("Entered into generateArtifact");
73         if (!StringUtils.isBlank(artifact.getKind())) {
74             logArtifact(artifact);
75             ServiceTemplate serviceTemplate = new ServiceTemplate();
76
77             addNodeType(artifact, serviceTemplate);
78
79             TopologyTemplate topologyTemplate = new TopologyTemplate();
80             serviceTemplate.setTopology_template(topologyTemplate);
81             addNodeTemplate(artifact, serviceTemplate);
82
83             String tosca = new YamlUtil().objectToYaml(serviceTemplate);
84             OutputStreamWriter writer = new OutputStreamWriter(stream);
85             try {
86                 writer.write(tosca);
87                 writer.flush();
88             } catch (IOException e) {
89                 Log.error("Error writing to outputstream", e);
90                 throw new ArtifactProcessorException(e);
91             } finally {
92                 try {
93                     writer.close();
94                 } catch (IOException e) {
95                     Log.error("Error while closing outputstream writer", e);
96                 }
97                 MDC.clear();
98             }
99         } else {
100             Log.error("Kind in PropertyDefinition is blank or null");
101             throw new ArtifactProcessorException("Kind in PropertyDefinition is blank or null");
102         }
103     }
104
105     @Override
106     public void generateArtifact(String artifact, OutputStream stream)
107             throws ArtifactProcessorException {
108         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
109         try {
110             PropertyDefinition pd = mapper.readValue(artifact, PropertyDefinition.class);
111             generateArtifact(pd, stream);
112         } catch (IOException e) {
113             Log.error("Error parsing property definition content = " + artifact, e);
114             throw new ArtifactProcessorException(e);
115         }
116     }
117
118     @Override
119     public PropertyDefinition readArtifact(String toscaArtifact) throws ArtifactProcessorException {
120         Log.info("Entered into readArtifact.");
121         Log.info("Received ToscaArtifact:\n" + toscaArtifact);
122
123         PropertyDefinition propertyDefinitionObj = new PropertyDefinition();
124         ServiceTemplate serviceTemplate =
125                 new YamlUtil().yamlToObject(toscaArtifact, ServiceTemplate.class);
126
127         // mapping parameters
128         Map<String, NodeType> nodeTypeMap = serviceTemplate.getNode_types();
129         Map<String, NodeTemplate> nodeTemplateMap =
130                 serviceTemplate.getTopology_template().getNode_templates();
131
132         String nodeTemplateName = nodeTemplateMap.keySet().toArray(new String[0])[0];
133         NodeTemplate nodeTemplate = nodeTemplateMap.get(nodeTemplateName);
134         Map<String, Object> nodeTemplateProperties = nodeTemplate.getProperties();
135
136         String kind = nodeTypeMap.keySet().toArray(new String[0])[0];
137         NodeType nodeType = nodeTypeMap.get(kind);
138         String version = nodeType.getVersion();
139         Log.info("ReadArtifact for " + kind + " with version " + version);
140         propertyDefinitionObj.setKind(kind);
141         propertyDefinitionObj.setVersion(version);
142
143         List<Parameter> parameterList = new LinkedList<>();
144
145         Map<String, org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition> propertyDefinitionFromTOSCA =
146                 nodeType.getProperties();
147         if (null != propertyDefinitionFromTOSCA) {
148             for (String propertyName : propertyDefinitionFromTOSCA.keySet()) {
149                 org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition propertyDefinition =
150                         propertyDefinitionFromTOSCA.get(propertyName);
151
152                 Parameter parameter = new Parameter();
153                 parameter.setName(propertyName);
154
155                 if (propertyDefinition.get_default() != null) {
156                     parameter.setDefaultValue(propertyDefinition.get_default().toString());
157                 }
158                 parameter.setDescription(propertyDefinition.getDescription());
159                 if (null != propertyDefinition.getRequired()) {
160                     parameter.setRequired(propertyDefinition.getRequired());
161                 } else {
162                     parameter.setRequired(false);
163                 }
164
165                 if (StringUtils.isNotEmpty(propertyDefinition.getType())) {
166                     parameter.setType(propertyDefinition.getType());
167                 }
168
169                 String propertValueExpr = (String) nodeTemplateProperties.get(propertyName);
170                 String[] stringTokens = parsePropertyValueExpression(propertValueExpr);
171                 String ruleType = stringTokens[0]
172                         .substring(stringTokens[0].indexOf('=') + 1, stringTokens[0].length())
173                         .replaceAll(">", "").trim();
174                 String responseExpression = stringTokens[1]
175                         .substring(stringTokens[1].indexOf('=') + 1, stringTokens[1].length());
176                 String source = stringTokens[2]
177                         .substring(stringTokens[2].indexOf('=') + 1, stringTokens[2].length())
178                         .replaceAll(">", "").trim();
179                 String requestExpression = stringTokens[3]
180                         .substring(stringTokens[3].indexOf('=') + 1, stringTokens[3].length());
181
182                 List<RequestKey> requestKeys = readRequestKeys(requestExpression);
183                 List<ResponseKey> responseKeys = readResponseKeys(responseExpression);
184
185                 parameter.setRuleType(ruleType);
186                 parameter.setSource(source);
187                 parameter.setRequestKeys(requestKeys);
188                 parameter.setResponseKeys(responseKeys);
189
190                 parameterList.add(parameter);
191
192             }
193         }
194         propertyDefinitionObj.setParameters(parameterList);
195         Log.info("Exiting from readArtifact. ");
196         return propertyDefinitionObj;
197     }
198
199     private List<ResponseKey> readResponseKeys(String responseExpression)
200             throws ArtifactProcessorException {
201         Log.info("Entered into readResponseKeys.");
202         List<ResponseKey> responseKeyList = null;
203         String expression;
204         expression = responseExpression.replaceAll("<", "").replaceAll(">", "").trim();
205         if (StringUtils.isNotEmpty(expression)) {
206             responseKeyList = new ArrayList<>();
207
208             String[] responseKeys = expression.split(",");
209             for (String responseKeyStr : responseKeys) {
210                 ResponseKey responseKey = new ResponseKey();
211                 try {
212                     responseKey.setUniqueKeyName(responseKeyStr.split(":")[0]
213                             .replaceAll(LESSTHANENCODING, "<").replaceAll(GREATERTHANENCODING, ">")
214                             .replaceAll(COLONENCODING, ":").replaceAll(COMMAENCODING, ",")
215                             .replaceAll(EQUALSENCODING, "=").trim());
216                     responseKey.setUniqueKeyValue(responseKeyStr.split(":")[1]
217                             .replaceAll(LESSTHANENCODING, "<").replaceAll(GREATERTHANENCODING, ">")
218                             .replaceAll(COLONENCODING, ":").replaceAll(COMMAENCODING, ",")
219                             .replaceAll(EQUALSENCODING, "=").trim());
220                     responseKey.setFieldKeyName(responseKeyStr.split(":")[2]
221                             .replaceAll(LESSTHANENCODING, "<").replaceAll(GREATERTHANENCODING, ">")
222                             .replaceAll(COLONENCODING, ":").replaceAll(COMMAENCODING, ",")
223                             .replaceAll(EQUALSENCODING, "=").trim());
224                 } catch (ArrayIndexOutOfBoundsException e) {
225                     Log.error(
226                             "Invalid response attribute found :" + responseKeyStr + "due to " + e);
227                     throw new ArtifactProcessorException(
228                             "Invalid response attribute found :" + responseKeyStr);
229                 }
230                 responseKeyList.add(responseKey);
231             }
232         }
233         Log.info("Exiting from readResponseKeys.");
234         return responseKeyList;
235     }
236
237     private List<RequestKey> readRequestKeys(String requestExpression) {
238         Log.info("Entered into readRequestKeys.");
239         List<RequestKey> requestKeyList = null;
240         String expression;
241         expression = requestExpression.replaceAll("<", "").replaceAll(">", "").trim();
242         if (StringUtils.isNotEmpty(expression)) {
243             requestKeyList = new ArrayList<>();
244             String[] requestKeys = expression.split(",");
245             for (String responseKeyStr : requestKeys) {
246                 RequestKey requestKey = new RequestKey();
247                 requestKey.setKeyName(responseKeyStr.split(":")[0].replaceAll(LESSTHANENCODING, "<")
248                         .replaceAll(GREATERTHANENCODING, ">").replaceAll(COLONENCODING, ":")
249                         .replaceAll(COMMAENCODING, ",").replaceAll(EQUALSENCODING, "=").trim());
250                 requestKey.setKeyValue(responseKeyStr.split(":")[1]
251                         .replaceAll(LESSTHANENCODING, "<").replaceAll(GREATERTHANENCODING, ">")
252                         .replaceAll(COLONENCODING, ":").replaceAll(COMMAENCODING, ",")
253                         .replaceAll(EQUALSENCODING, "=").trim());
254                 requestKeyList.add(requestKey);
255             }
256         }
257         Log.info("Exiting from readRequestKeys.");
258         return requestKeyList;
259     }
260
261     private String[] parsePropertyValueExpression(String propertValueExpr)
262             throws ArtifactProcessorException {
263         Log.info("Entered into parsePropertyValueExpression.");
264         String nodeRegex = "<(.*?)>";
265         Pattern pattern = Pattern.compile(nodeRegex, Pattern.CASE_INSENSITIVE);
266         Matcher matcher = pattern.matcher(propertValueExpr);
267         List<String> stringTokens = new ArrayList<>();
268         while (matcher.find()) {
269             stringTokens.add(matcher.group(0));
270         }
271         String[] propertiesArr = new String[stringTokens.size()];
272         propertiesArr = stringTokens.toArray(propertiesArr);
273         if (propertiesArr.length != 4) {
274             throw new ArtifactProcessorException("Invalid input found " + propertValueExpr);
275         }
276         Log.info("Exiting from parsePropertyValueExpression.");
277         return propertiesArr;
278     }
279
280     private void addNodeType(PropertyDefinition artifact, ServiceTemplate toscaTemplate)
281             throws ArtifactProcessorException {
282         // Add basic fields for the node
283         NodeType toscaNodeType = new NodeType();
284         toscaNodeType.setDerived_from(DERIVEDFROM);
285         toscaNodeType.setVersion(artifact.getVersion());
286         toscaNodeType.setDescription("");
287         if (artifact.getParameters() != null) {
288             Map<String, org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition> toscaPropertyMap =
289                     new HashMap<>();
290             toscaNodeType.setProperties(toscaPropertyMap);
291
292             // Add properties from parameters of PD
293             for (Parameter pdParameter : artifact.getParameters()) {
294                 addProperty(toscaNodeType, pdParameter);
295             }
296         }
297
298         // This is where it adds node in node Map and adds the map in tosca template
299         Map<String, NodeType> toscaNodeMap = new HashMap<>();
300         toscaNodeMap.put(artifact.getKind(), toscaNodeType);
301         toscaTemplate.setNode_types(toscaNodeMap);
302     }
303
304     private void addProperty(NodeType toscaNodeType, Parameter pdParameter)
305             throws ArtifactProcessorException {
306         if (!StringUtils.isBlank(pdParameter.getName())
307                 && !pdParameter.getName().matches(".*\\s+.*")) {
308             Log.info("Adding parameter " + pdParameter.getName() + " in node type");
309             org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition toscaProperty =
310                     new org.openecomp.sdc.tosca.datatypes.model.PropertyDefinition();
311
312             toscaProperty.setType(
313                     StringUtils.isBlank(pdParameter.getType()) ? "string" : pdParameter.getType());
314             toscaProperty.set_default(pdParameter.getDefaultValue());
315
316             toscaProperty.setDescription(pdParameter.getDescription());
317             toscaProperty.setRequired(pdParameter.isRequired());
318
319             toscaNodeType.getProperties().put(pdParameter.getName(), toscaProperty);
320         } else {
321             String message = "Parameter name is empty,null or contains whitespace";
322             Log.error(message);
323             throw new ArtifactProcessorException(message);
324         }
325     }
326
327     private void addNodeTemplate(PropertyDefinition artifact, ServiceTemplate toscaTemplate) {
328         NodeTemplate nodeTemplate = new NodeTemplate();
329         nodeTemplate.setType(artifact.getKind());
330         Map<String, Object> templateProperties = new HashMap<>();
331         // Add properties from parameters of PD
332         if (artifact.getParameters() != null) {
333             for (Parameter pdParameter : artifact.getParameters()) {
334                 addTemplateProperty(templateProperties, pdParameter);
335             }
336             nodeTemplate.setProperties(templateProperties);
337         }
338         Map<String, NodeTemplate> nodeTemplateMap = new HashMap<>();
339         nodeTemplateMap.put(artifact.getKind() + "_Template", nodeTemplate);
340         toscaTemplate.getTopology_template().setNode_templates(nodeTemplateMap);
341     }
342
343     private void addTemplateProperty(Map<String, Object> templateProperties,
344             Parameter pdParameter) {
345         Log.info("Adding parameter " + pdParameter.getName() + " in node templates");
346         String responseKeys = buildResponseKeyExpression(pdParameter.getResponseKeys());
347         String requestKeys = buildRequestKeyExpression(pdParameter.getRequestKeys());
348         String ruleType = buildRuleType(pdParameter.getRuleType());
349         String source = buildSourceSystem(pdParameter.getSource());
350         String properties = ruleType + " " + responseKeys + " " + source + " " + requestKeys;
351         templateProperties.put(pdParameter.getName(), properties);
352     }
353
354     protected String buildResponseKeyExpression(List<ResponseKey> responseKeys) {
355         StringBuilder propertyBuilder = new StringBuilder();
356         propertyBuilder.append("<response-keys = ");
357         if (responseKeys != null) {
358             Iterator<ResponseKey> itr = responseKeys.iterator();
359             while (itr.hasNext()) {
360                 ResponseKey res = itr.next();
361                 if (res != null)
362                     propertyBuilder.append(
363                             encode(res.getUniqueKeyName()) + ":" + encode(res.getUniqueKeyValue())
364                                     + ":" + encode(res.getFieldKeyName()));
365                 if (itr.hasNext())
366                     propertyBuilder.append(" , ");
367             }
368         }
369         propertyBuilder.append(">");
370         return propertyBuilder.toString();
371     }
372
373     protected String buildRequestKeyExpression(List<RequestKey> requestKeys) {
374         StringBuilder propertyBuilder = new StringBuilder();
375         propertyBuilder.append("<request-keys = ");
376         if (requestKeys != null) {
377             Iterator<RequestKey> itr = requestKeys.iterator();
378             while (itr.hasNext()) {
379                 RequestKey res = itr.next();
380                 if (res != null)
381                     propertyBuilder
382                             .append(encode(res.getKeyName()) + ":" + encode(res.getKeyValue()));
383                 if (itr.hasNext())
384                     propertyBuilder.append(" , ");
385             }
386         }
387         propertyBuilder.append(">");
388         return propertyBuilder.toString();
389     }
390
391     protected String buildRuleType(String classType) {
392         StringBuilder propertyBuilder = new StringBuilder();
393         String encodedClassType = StringUtils.isBlank(encode(classType)) ? "" : encode(classType);
394         propertyBuilder.append("<");
395         propertyBuilder.append("rule-type = " + encodedClassType);
396         propertyBuilder.append(">");
397         return propertyBuilder.toString();
398     }
399
400     protected String buildSourceSystem(String source) {
401         StringBuilder sourceBuilder = new StringBuilder();
402         sourceBuilder.append("<source-system = ");
403         sourceBuilder.append(StringUtils.isBlank(encode(source)) ? "" : encode(source));
404         sourceBuilder.append(">");
405         return sourceBuilder.toString();
406     }
407
408     protected String encode(String string) {
409         String encodedString = null;
410         if (string != null) {
411             encodedString = string.trim().replaceAll("<", "&lt;").replaceAll(">", "&gt;")
412                     .replaceAll(":", "&colon;").replaceAll(",", "&comma;")
413                     .replaceAll("=", "&equals;");
414         }
415         return encodedString;
416     }
417
418     private void logArtifact(PropertyDefinition artifact) {
419         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
420         String stringArtifact = null;
421         try {
422             stringArtifact = mapper.writeValueAsString(artifact);
423             Log.info("Received PropertyDefinition:\n" + stringArtifact);
424         } catch (JsonProcessingException e) {
425             Log.error("Exception while logging artifact:", e);
426         }
427
428     }
429 }