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