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