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.onap.sdnc.config.params.transformer.tosca;
 
  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;
 
  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;
 
  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;
 
  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 = "<";
 
  68     public void generateArtifact(PropertyDefinition artifact, OutputStream stream)
 
  69             throws ArtifactProcessorException {
 
  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();
 
  77             addNodeType(artifact, serviceTemplate);
 
  79             TopologyTemplate topologyTemplate = new TopologyTemplate();
 
  80             serviceTemplate.setTopology_template(topologyTemplate);
 
  81             addNodeTemplate(artifact, serviceTemplate);
 
  83             String tosca = new YamlUtil().objectToYaml(serviceTemplate);
 
  84             OutputStreamWriter writer = new OutputStreamWriter(stream);
 
  88             } catch (IOException e) {
 
  89                 Log.error("Error writing to outputstream", e);
 
  90                 throw new ArtifactProcessorException(e);
 
  94                 } catch (IOException e) {
 
  95                     Log.error("Error while closing outputstream writer", e);
 
 100             Log.error("Kind in PropertyDefinition is blank or null");
 
 101             throw new ArtifactProcessorException("Kind in PropertyDefinition is blank or null");
 
 106     public void generateArtifact(String artifact, OutputStream stream)
 
 107             throws ArtifactProcessorException {
 
 108         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
 
 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);
 
 119     public PropertyDefinition readArtifact(String toscaArtifact) throws ArtifactProcessorException {
 
 120         Log.info("Entered into readArtifact.");
 
 121         Log.info("Received ToscaArtifact:\n" + toscaArtifact);
 
 123         PropertyDefinition propertyDefinitionObj = new PropertyDefinition();
 
 124         ServiceTemplate serviceTemplate =
 
 125                 new YamlUtil().yamlToObject(toscaArtifact, ServiceTemplate.class);
 
 127         // mapping parameters
 
 128         Map<String, NodeType> nodeTypeMap = serviceTemplate.getNode_types();
 
 129         Map<String, NodeTemplate> nodeTemplateMap =
 
 130                 serviceTemplate.getTopology_template().getNode_templates();
 
 132         String nodeTemplateName = nodeTemplateMap.keySet().toArray(new String[0])[0];
 
 133         NodeTemplate nodeTemplate = nodeTemplateMap.get(nodeTemplateName);
 
 134         Map<String, Object> nodeTemplateProperties = nodeTemplate.getProperties();
 
 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);
 
 143         List<Parameter> parameterList = new LinkedList<>();
 
 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);
 
 152                 Parameter parameter = new Parameter();
 
 153                 parameter.setName(propertyName);
 
 155                 if (propertyDefinition.get_default() != null) {
 
 156                     parameter.setDefaultValue(propertyDefinition.get_default().toString());
 
 158                 parameter.setDescription(propertyDefinition.getDescription());
 
 159                 if (null != propertyDefinition.getRequired()) {
 
 160                     parameter.setRequired(propertyDefinition.getRequired());
 
 162                     parameter.setRequired(false);
 
 165                 if (StringUtils.isNotEmpty(propertyDefinition.getType())) {
 
 166                     parameter.setType(propertyDefinition.getType());
 
 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());
 
 182                 List<RequestKey> requestKeys = readRequestKeys(requestExpression);
 
 183                 List<ResponseKey> responseKeys = readResponseKeys(responseExpression);
 
 185                 parameter.setRuleType(ruleType);
 
 186                 parameter.setSource(source);
 
 187                 parameter.setRequestKeys(requestKeys);
 
 188                 parameter.setResponseKeys(responseKeys);
 
 190                 parameterList.add(parameter);
 
 194         propertyDefinitionObj.setParameters(parameterList);
 
 195         Log.info("Exiting from readArtifact. ");
 
 196         return propertyDefinitionObj;
 
 199     private List<ResponseKey> readResponseKeys(String responseExpression)
 
 200             throws ArtifactProcessorException {
 
 201         Log.info("Entered into readResponseKeys.");
 
 202         List<ResponseKey> responseKeyList = null;
 
 204         expression = responseExpression.replaceAll("<", "").replaceAll(">", "").trim();
 
 205         if (StringUtils.isNotEmpty(expression)) {
 
 206             responseKeyList = new ArrayList<>();
 
 208             String[] responseKeys = expression.split(",");
 
 209             for (String responseKeyStr : responseKeys) {
 
 210                 ResponseKey responseKey = new ResponseKey();
 
 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) {
 
 226                             "Invalid response attribute found :" + responseKeyStr + "due to " + e);
 
 227                     throw new ArtifactProcessorException(
 
 228                             "Invalid response attribute found :" + responseKeyStr);
 
 230                 responseKeyList.add(responseKey);
 
 233         Log.info("Exiting from readResponseKeys.");
 
 234         return responseKeyList;
 
 237     private List<RequestKey> readRequestKeys(String requestExpression) {
 
 238         Log.info("Entered into readRequestKeys.");
 
 239         List<RequestKey> requestKeyList = null;
 
 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);
 
 257         Log.info("Exiting from readRequestKeys.");
 
 258         return requestKeyList;
 
 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));
 
 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);
 
 276         Log.info("Exiting from parsePropertyValueExpression.");
 
 277         return propertiesArr;
 
 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 =
 
 290             toscaNodeType.setProperties(toscaPropertyMap);
 
 292             // Add properties from parameters of PD
 
 293             for (Parameter pdParameter : artifact.getParameters()) {
 
 294                 addProperty(toscaNodeType, pdParameter);
 
 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);
 
 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();
 
 312             toscaProperty.setType(
 
 313                     StringUtils.isBlank(pdParameter.getType()) ? "string" : pdParameter.getType());
 
 314             toscaProperty.set_default(pdParameter.getDefaultValue());
 
 316             toscaProperty.setDescription(pdParameter.getDescription());
 
 317             toscaProperty.setRequired(pdParameter.isRequired());
 
 319             toscaNodeType.getProperties().put(pdParameter.getName(), toscaProperty);
 
 321             String message = "Parameter name is empty,null or contains whitespace";
 
 323             throw new ArtifactProcessorException(message);
 
 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);
 
 336             nodeTemplate.setProperties(templateProperties);
 
 338         Map<String, NodeTemplate> nodeTemplateMap = new HashMap<>();
 
 339         nodeTemplateMap.put(artifact.getKind() + "_Template", nodeTemplate);
 
 340         toscaTemplate.getTopology_template().setNode_templates(nodeTemplateMap);
 
 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);
 
 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();
 
 362                     propertyBuilder.append(
 
 363                             encode(res.getUniqueKeyName()) + ":" + encode(res.getUniqueKeyValue())
 
 364                                     + ":" + encode(res.getFieldKeyName()));
 
 366                     propertyBuilder.append(" , ");
 
 369         propertyBuilder.append(">");
 
 370         return propertyBuilder.toString();
 
 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();
 
 382                             .append(encode(res.getKeyName()) + ":" + encode(res.getKeyValue()));
 
 384                     propertyBuilder.append(" , ");
 
 387         propertyBuilder.append(">");
 
 388         return propertyBuilder.toString();
 
 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();
 
 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();
 
 408     protected String encode(String string) {
 
 409         String encodedString = null;
 
 410         if (string != null) {
 
 411             encodedString = string.trim().replaceAll("<", "<").replaceAll(">", ">")
 
 412                     .replaceAll(":", ":").replaceAll(",", ",")
 
 413                     .replaceAll("=", "=");
 
 415         return encodedString;
 
 418     private void logArtifact(PropertyDefinition artifact) {
 
 419         ObjectMapper mapper = new ObjectMapper(new YAMLFactory());
 
 420         String stringArtifact = null;
 
 422             stringArtifact = mapper.writeValueAsString(artifact);
 
 423             Log.info("Received PropertyDefinition:\n" + stringArtifact);
 
 424         } catch (JsonProcessingException e) {
 
 425             Log.error("Exception while logging artifact:", e);