2  * ============LICENSE_START=======================================================
 
   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
 
  13  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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.
 
  21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
 
  22  * ============LICENSE_END=========================================================
 
  25 package org.openecomp.sdnc.config.params.transformer.tosca;
 
  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;
 
  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;
 
  43 import java.io.IOException;
 
  44 import java.io.OutputStream;
 
  45 import java.io.OutputStreamWriter;
 
  47 import java.util.regex.Matcher;
 
  48 import java.util.regex.Pattern;
 
  50 import static com.att.eelf.configuration.Configuration.MDC_SERVICE_NAME;
 
  52 public class ArtifactProcessorImpl implements ArtifactProcessor
 
  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 = "<";
 
  63     public void generateArtifact(PropertyDefinition artifact, OutputStream stream) throws ArtifactProcessorException
 
  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();
 
  72             addNodeType(artifact, serviceTemplate);
 
  74             TopologyTemplate topologyTemplate = new TopologyTemplate();
 
  75             serviceTemplate.setTopology_template(topologyTemplate);
 
  76             addNodeTemplate(artifact, serviceTemplate);
 
  78             String tosca = new YamlUtil().objectToYaml(serviceTemplate);
 
  79             OutputStreamWriter writer = new OutputStreamWriter(stream);
 
  83             } catch (IOException e) {
 
  84                 Log.error("Error writing to outputstream", e);
 
  85                 throw new ArtifactProcessorException(e);
 
  89                 } catch (IOException e) {
 
  90                     Log.error("Error while closing outputstream writer", e);
 
  97             Log.error("Kind in PropertyDefinition is blank or null");
 
  98             throw new ArtifactProcessorException("Kind in PropertyDefinition is blank or null");
 
 103     public void generateArtifact(String artifact, OutputStream stream) throws ArtifactProcessorException
 
 105         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
 
 107             PropertyDefinition pd = mapper.readValue(artifact, PropertyDefinition.class);
 
 108             generateArtifact(pd, stream);
 
 110         catch (IOException e)
 
 112             Log.error("Error parsing property definition content = "+ artifact,e);
 
 113             throw new ArtifactProcessorException(e);
 
 118     public PropertyDefinition readArtifact(String toscaArtifact) throws ArtifactProcessorException{
 
 119         Log.info("Entered into readArtifact.");
 
 120         Log.info("Received ToscaArtifact:\n" + toscaArtifact);
 
 122         PropertyDefinition propertyDefinitionObj = new PropertyDefinition();
 
 123         ServiceTemplate serviceTemplate = new YamlUtil().yamlToObject(toscaArtifact, ServiceTemplate.class);
 
 126         Map<String, NodeType> nodeTypeMap = serviceTemplate.getNode_types();
 
 127         Map<String, NodeTemplate> nodeTemplateMap = serviceTemplate.getTopology_template().getNode_templates();
 
 129         String nodeTemplateName = nodeTemplateMap.keySet().toArray(new String[0])[0];
 
 130         NodeTemplate nodeTemplate = nodeTemplateMap.get(nodeTemplateName);
 
 131         Map<String, Object> nodeTemplateProperties = nodeTemplate.getProperties();
 
 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);
 
 140         List<Parameter> parameterList = new LinkedList<>();
 
 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);
 
 147                 Parameter parameter = new Parameter();
 
 148                 parameter.setName(propertyName);
 
 150                 if (propertyDefinition.get_default() != null) {
 
 151                     parameter.setDefaultValue(propertyDefinition.get_default().toString());
 
 153                 parameter.setDescription(propertyDefinition.getDescription());
 
 154                 if (null != propertyDefinition.getRequired()) {
 
 155                     parameter.setRequired(propertyDefinition.getRequired());
 
 157                     parameter.setRequired(false);
 
 160                 if (StringUtils.isNotEmpty(propertyDefinition.getType())) {
 
 161                     parameter.setType(propertyDefinition.getType());
 
 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());
 
 171                 List<RequestKey> requestKeys = readRequestKeys(requestExpression);
 
 172                 List<ResponseKey> responseKeys = readResponseKeys(responseExpression);
 
 174                 parameter.setRuleType(ruleType);
 
 175                 parameter.setSource(source);
 
 176                 parameter.setRequestKeys(requestKeys);
 
 177                 parameter.setResponseKeys(responseKeys);
 
 179                 parameterList.add(parameter);
 
 183         propertyDefinitionObj.setParameters(parameterList);
 
 184         Log.info("Exiting from readArtifact. ");
 
 185         return propertyDefinitionObj;
 
 188     private List<ResponseKey> readResponseKeys(String responseExpression) throws ArtifactProcessorException {
 
 189         Log.info("Entered into readResponseKeys.");
 
 190         List<ResponseKey> responseKeyList = null;
 
 192         expression = responseExpression.replaceAll("<", "").replaceAll(">", "").trim();
 
 193         if (StringUtils.isNotEmpty(expression)) {
 
 194             responseKeyList = new ArrayList<>();
 
 196             String[] responseKeys = expression.split(",");
 
 197             for (String responseKeyStr : responseKeys) {
 
 198                 ResponseKey responseKey = new ResponseKey();
 
 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);
 
 207                 responseKeyList.add(responseKey);
 
 210         Log.info("Exiting from readResponseKeys.");
 
 211         return responseKeyList;
 
 214     private List<RequestKey> readRequestKeys(String requestExpression) {
 
 215         Log.info("Entered into readRequestKeys.");
 
 216         List<RequestKey> requestKeyList = null;
 
 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);
 
 229         Log.info("Exiting from readRequestKeys.");
 
 230         return requestKeyList;
 
 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));
 
 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);
 
 247         Log.info("Exiting from parsePropertyValueExpression.");
 
 248         return propertiesArr;
 
 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);
 
 261             //Add properties from parameters of PD
 
 262             for (Parameter pdParameter : artifact.getParameters()) {
 
 263                 addProperty(toscaNodeType, pdParameter);
 
 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);
 
 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();
 
 278             toscaProperty.setType(StringUtils.isBlank(pdParameter.getType()) ? "string" : pdParameter.getType());
 
 279             toscaProperty.set_default(pdParameter.getDefaultValue());
 
 281             toscaProperty.setDescription(pdParameter.getDescription());
 
 282             toscaProperty.setRequired(pdParameter.isRequired());
 
 284             toscaNodeType.getProperties().put(pdParameter.getName(), toscaProperty);
 
 288             String message ="Parameter name is empty,null or contains whitespace";
 
 290             throw new ArtifactProcessorException(message);
 
 294     private void addNodeTemplate(PropertyDefinition artifact, ServiceTemplate toscaTemplate)
 
 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);
 
 304             nodeTemplate.setProperties(templateProperties);
 
 306         Map<String,NodeTemplate> nodeTemplateMap = new HashMap<>();
 
 307         nodeTemplateMap.put(artifact.getKind()+"_Template",nodeTemplate);
 
 308         toscaTemplate.getTopology_template().setNode_templates(nodeTemplateMap);
 
 311     private void addTemplateProperty(Map<String,Object> templateProperties, Parameter pdParameter)
 
 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);
 
 322     protected String buildResponseKeyExpression(List<ResponseKey> responseKeys)
 
 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();
 
 331                     propertyBuilder.append(encode(res.getUniqueKeyName()) + ":" + encode(res.getUniqueKeyValue()) + ":" + encode(res.getFieldKeyName()));
 
 333                     propertyBuilder.append(" , ");
 
 336         propertyBuilder.append(">");
 
 337         return propertyBuilder.toString();
 
 340     protected String buildRequestKeyExpression(List<RequestKey> requestKeys)
 
 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();
 
 349                     propertyBuilder.append(encode(res.getKeyName()) + ":" + encode(res.getKeyValue()));
 
 351                     propertyBuilder.append(" , ");
 
 354         propertyBuilder.append(">");
 
 355         return propertyBuilder.toString();
 
 358     protected String buildRuleType(String classType)
 
 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();
 
 368     protected String buildSourceSystem(String source)
 
 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();
 
 377     protected String encode(String string)
 
 379         String encodedString = null;
 
 381             encodedString = string.trim().replaceAll("<", "<").replaceAll(">", ">").replaceAll(":",":").replaceAll(",",",").replaceAll("=","=");
 
 383         return encodedString;
 
 386     private void logArtifact(PropertyDefinition artifact)
 
 388         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
 
 389         String stringArtifact=null;
 
 392             stringArtifact = mapper.writeValueAsString(artifact);
 
 393             Log.info("Received PropertyDefinition:\n" + stringArtifact);
 
 395         catch (JsonProcessingException e)
 
 397             Log.error("Exception while logging artifact:",e);