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