Enhanced logic for multilevel list input reading from UUI
[so.git] / bpmn / MSOCommonBPMN / src / main / java / org / onap / so / bpmn / common / resource / ResourceRequestBuilder.java
index 35bd25f..58f775c 100644 (file)
@@ -4,12 +4,14 @@
  * ================================================================================
  * Copyright (C) 2018 Huawei Intellectual Property. All rights reserved.
  * ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
 package org.onap.so.bpmn.common.resource;
 
-import java.io.File;
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
 import java.io.IOException;
+import java.lang.reflect.Type;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Optional;
-
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
-
+import org.apache.commons.lang.StringUtils;
 import org.camunda.bpm.engine.runtime.Execution;
-import org.onap.sdc.tosca.parser.api.ISdcCsarHelper;
-import org.onap.sdc.tosca.parser.exceptions.SdcToscaParserException;
-import org.onap.sdc.tosca.parser.impl.SdcToscaParserFactory;
-import org.onap.sdc.toscaparser.api.NodeTemplate;
-import org.onap.sdc.toscaparser.api.Property;
-import org.onap.sdc.toscaparser.api.functions.GetInput;
-import org.onap.sdc.toscaparser.api.parameters.Input;
 import org.onap.so.bpmn.core.UrnPropertiesReader;
 import org.onap.so.bpmn.core.json.JsonUtils;
 import org.onap.so.client.HttpClient;
-import org.onap.so.logger.MessageEnum;
-import org.onap.so.logger.MsoLogger;
+import org.onap.so.client.HttpClientFactory;
 import org.onap.so.utils.TargetEntity;
-
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.SerializationFeature;
 import com.google.gson.Gson;
 import com.google.gson.reflect.TypeToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public class ResourceRequestBuilder {
 
-    private static String CUSTOMIZATION_UUID = "customizationUUID";
+    private static String CUSTOMIZATION_UUID = "cuserviceResourcesstomizationUUID";
 
-    private static String SERVICE_URL_TOSCA_CSAR = "/v3/serviceToscaCsar";
+    private static String SERVICE_URL_SERVICE_INSTANCE = "/v2/serviceResources";
 
-    private static MsoLogger LOGGER = MsoLogger.getMsoLogger(MsoLogger.Catalog.RA, ResourceRequestBuilder.class);
+    private static Logger logger = LoggerFactory.getLogger(ResourceRequestBuilder.class);
 
     static JsonUtils jsonUtil = new JsonUtils();
 
-        /**
-     * build the resource Parameters detail.
-     * It's a json string for resource instantiant
-     * {
-     *     "locationConstraints":[...]
-     *     "requestInputs":{K,V}
-     * }
-     * <br>
-     * 
+    public static List<String> getResourceSequence(String serviceUuid) {
+
+        List<String> resourceSequence = new ArrayList();
+        try {
+            Map<String, Object> serviceResponse = getServiceInstnace(serviceUuid);
+
+            if (serviceResponse.containsKey("serviceResources")) {
+                Map<String, Object> serviceResources = (Map<String, Object>) serviceResponse.get("serviceResources");
+
+                if (serviceResources.containsKey("resourceOrder")) {
+                    String resourceOrder = (String) serviceResources.get("resourceOrder");
+                    if (resourceOrder != null) {
+                        resourceSequence.addAll(Arrays.asList(resourceOrder.split(",")));
+                    }
+                }
+            }
+        } catch (Exception e) {
+            logger.error("not able to retrieve service order.");
+        }
+        return resourceSequence;
+    }
+
+    /*
+     * build the resource Parameters detail. It's a json string for resource instantiant { "locationConstraints":[...]
+     * "requestInputs":{K,V} } <br>
+     *
      * @param execution Execution context
+     *
      * @param serviceUuid The service template uuid
+     *
      * @param resourceCustomizationUuid The resource customization uuid
+     *
      * @param serviceParameters the service parameters passed from the API
+     *
      * @return the resource instantiate parameters
+     *
      * @since ONAP Beijing Release
      */
     @SuppressWarnings("unchecked")
-    public static String buildResourceRequestParameters(Execution execution, String serviceUuid, String resourceCustomizationUuid, String serviceParameters) {
-        List<String> resourceList = jsonUtil.StringArrayToList(execution, (String)JsonUtils.getJsonValue(serviceParameters, "resources"));
-        //Get the right location str for resource. default is an empty array.
-        String locationConstraints ="[]";
+    public static String buildResourceRequestParameters(Execution execution, String serviceUuid,
+            String resourceCustomizationUuid, String serviceParameters, Map<String, Object> currentVFData) {
+        List<String> resourceList =
+                jsonUtil.StringArrayToList(execution, (String) JsonUtils.getJsonValue(serviceParameters, "resources"));
+        // Get the right location str for resource. default is an empty array.
+        String locationConstraints = "[]";
         String resourceInputsFromUui = "";
-        for(String resource: resourceList){
-            String resCusUuid = (String)JsonUtils.getJsonValue(resource, "resourceCustomizationUuid");
-            if(resourceCustomizationUuid.equals(resCusUuid)){
+        for (String resource : resourceList) {
+            String resCusUuid = (String) JsonUtils.getJsonValue(resource, "resourceCustomizationUuid");
+            if (resourceCustomizationUuid.equals(resCusUuid)) {
                 String resourceParameters = JsonUtils.getJsonValue(resource, "parameters");
                 locationConstraints = JsonUtils.getJsonValue(resourceParameters, "locationConstraints");
                 resourceInputsFromUui = JsonUtils.getJsonValue(resourceParameters, "requestInputs");
@@ -95,7 +115,8 @@ public class ResourceRequestBuilder {
         }
         Map<String, Object> serviceInput = null;
         if (JsonUtils.getJsonValue(serviceParameters, "requestInputs") != null) {
-            serviceInput = getJsonObject((String)JsonUtils.getJsonValue(serviceParameters, "requestInputs"), Map.class);
+            serviceInput =
+                    getJsonObject((String) JsonUtils.getJsonValue(serviceParameters, "requestInputs"), Map.class);
         }
 
         Map<String, Object> resourceInputsFromUuiMap = getJsonObject(resourceInputsFromUui, Map.class);
@@ -108,119 +129,306 @@ public class ResourceRequestBuilder {
             resourceInputsFromUuiMap = new HashMap();
         }
 
-        try {
-            Map<String, Object> resourceInputsFromServiceDeclaredLevel = buildResouceRequest(serviceUuid, resourceCustomizationUuid, serviceInput);
-            resourceInputsFromUuiMap.putAll(resourceInputsFromServiceDeclaredLevel);
-        } catch(SdcToscaParserException e) {
-               LOGGER.error("SdcToscaParserException", e);
-        }
+        Map<String, Object> resourceInputsFromServiceDeclaredLevel =
+                buildResouceRequest(serviceUuid, resourceCustomizationUuid, serviceInput, currentVFData);
+        resourceInputsFromUuiMap.putAll(resourceInputsFromServiceDeclaredLevel);
         String resourceInputsStr = getJsonString(resourceInputsFromUuiMap);
-        String result = "{\n"
-                + "\"locationConstraints\":" + locationConstraints +",\n"
-                + "\"requestInputs\":" + resourceInputsStr +"\n"
-                +"}";
+        String result = "{\n" + "\"locationConstraints\":" + locationConstraints + ",\n" + "\"requestInputs\":"
+                + resourceInputsStr + "\n" + "}";
         return result;
     }
 
-    public static Map<String, Object> buildResouceRequest(String serviceUuid, String resourceCustomizationUuid, Map<String, Object> serviceInputs)
-            throws SdcToscaParserException {
+    @SuppressWarnings("unchecked")
+    public static Map<String, Object> buildResouceRequest(String serviceUuid, String resourceCustomizationUuid,
+            Map<String, Object> serviceInputs, Map<String, Object> currentVFData) {
+        try {
+            Map<String, Object> serviceInstnace = getServiceInstnace(serviceUuid);
+            // find match of customization uuid in vnf
+            Map<String, Map<String, Object>> serviceResources =
+                    (Map<String, Map<String, Object>>) serviceInstnace.get("serviceResources");
+
+            List<Map<String, Object>> serviceVnfCust = (List<Map<String, Object>>) serviceResources.get("serviceVnfs");
+            Map<String, String> resourceInputData = getResourceInputStr(serviceVnfCust, resourceCustomizationUuid);
+
+            // find match in network resource
+            if (resourceInputData.size() == 0) {
+                List<Map<String, Object>> serviceNetworkCust =
+                        (List<Map<String, Object>>) serviceResources.get("serviceNetworks");
+                resourceInputData = getResourceInputStr(serviceNetworkCust, resourceCustomizationUuid);
+
+                // find match in AR resource
+                if (resourceInputData == null) {
+                    List<Map<String, Object>> serviceArCust =
+                            (List<Map<String, Object>>) serviceResources.get("serviceAllottedResources");
+                    resourceInputData = getResourceInputStr(serviceArCust, resourceCustomizationUuid);
+                }
+            }
+
+            String resourceInputStr = resourceInputData.get("resourceInput");
+            ResourceLevel resourceLevel = ResourceLevel.valueOf(resourceInputData.get("nodeType"));
 
-        Map<String, Object> resouceRequest = new HashMap<>();
+            if (resourceInputStr != null && !resourceInputStr.isEmpty()) {
+                return getResourceInput(resourceInputStr, serviceInputs, resourceLevel, currentVFData);
+            }
 
-        String csarpath = null;
-        try {
-            csarpath = getCsarFromUuid(serviceUuid);
-        } catch(Exception e) {
-            LOGGER.debug("csar file is not available for service uuid:" + serviceUuid, e);
-            return resouceRequest;
+        } catch (Exception e) {
+            logger.error("not able to retrieve service instance");
         }
+        return new HashMap();
+    }
 
-        SdcToscaParserFactory toscaParser = SdcToscaParserFactory.getInstance();
-        ISdcCsarHelper iSdcCsarHelper = toscaParser.getSdcCsarHelper(csarpath, false);
+    private static Map<String, String> getResourceInputStr(List<Map<String, Object>> resources,
+            String resCustomizationUuid) {
 
-        List<Input> serInput = iSdcCsarHelper.getServiceInputs();
-        Optional<NodeTemplate> nodeTemplateOpt = iSdcCsarHelper.getServiceNodeTemplates().stream()
-                .filter(e -> e.getMetaData().getValue(CUSTOMIZATION_UUID).equals(resourceCustomizationUuid)).findFirst();
+        Map<String, String> resourceInputMap = new HashMap<>(2);
+        for (Map<String, Object> resource : resources) {
+            Map<String, String> modelInfo = (Map<String, String>) resource.get("modelInfo");
 
-        if(nodeTemplateOpt.isPresent()) {
-            NodeTemplate nodeTemplate = nodeTemplateOpt.get();
-            LinkedHashMap<String, Property> resourceProperties = nodeTemplate.getProperties();
+            if (modelInfo.get("modelCustomizationUuid").equalsIgnoreCase(resCustomizationUuid)) {
+                resourceInputMap.put("resourceInput", (String) resource.get("resourceInput"));
+                String nodeType = ResourceLevel.FIRST.toString();
+                if (((String) resource.get("toscaNodeType")).contains(".vf.")) {
+                    nodeType = ResourceLevel.FIRST.toString();
+                } else if (((String) resource.get("toscaNodeType")).contains(".vfc.")) {
+                    nodeType = ResourceLevel.SECOND.toString();
+                }
+                resourceInputMap.put("nodeType", nodeType);
+                return resourceInputMap;
+            }
+        }
+        return null;
+    }
 
-            for(String key : resourceProperties.keySet()) {
-                Property property = resourceProperties.get(key);
+    // this method combines resource input with service input
+    private static Map<String, Object> getResourceInput(String resourceInputStr, Map<String, Object> serviceInputs,
+            ResourceLevel resourceLevel, Map<String, Object> currentVFData) {
+        Gson gson = new Gson();
+        Type type = new TypeToken<Map<String, String>>() {}.getType();
+        Map<String, Object> resourceInput = gson.fromJson(resourceInputStr, type);
+        JsonParser parser = new JsonParser();
+
+        Map<String, Object> uuiServiceInput = serviceInputs;
+
+        int firstLevelIndex = 0;
+        int secondLevelIndex = 0;
+        String firstLevelKey = null;
+        String secondLevelKey = null;
+        boolean levelKeyNameUpdated = false;
+        int indexToPick = 0;
+
+        if (null != currentVFData) {
+            firstLevelIndex = getIntValue(currentVFData.get("currentFirstLevelIndex"), 0);
+            secondLevelIndex = getIntValue(currentVFData.get("currentSecondLevelIndex"), 0);
+            final String lastFirstLevelKey = firstLevelKey = (String) currentVFData.get("currentFirstLevelKey");
+            final String lastSecondLevelKey = secondLevelKey = (String) currentVFData.get("currentSecondLevelKey");
+
+            if (null != currentVFData.get("lastNodeTypeProcessed")) {
+                ResourceLevel lastResourceLevel =
+                        ResourceLevel.valueOf(currentVFData.get("lastNodeTypeProcessed").toString());
+                switch (resourceLevel) {
+                    case FIRST:
+                        // if it is next request for same group then increment first level index
+                        switch (lastResourceLevel) {
+                            case FIRST:
+                                boolean isSameLevelRequest = resourceInput.values().stream().anyMatch(item -> {
+                                    JsonElement tree = parser.parse(((String) item).split("\\|")[0]);
+                                    return tree.isJsonArray() && tree.getAsJsonArray().get(0).getAsString()
+                                            .equalsIgnoreCase(lastFirstLevelKey);
+                                });
+                                if (isSameLevelRequest) {
+                                    firstLevelIndex++;
+                                }
+                                break;
+                            case SECOND:
+                                firstLevelIndex = 0;
+                                secondLevelKey = null;
+                                break;
+
+                        }
+                        indexToPick = firstLevelIndex;
+                        break;
+                    case SECOND:
+                        // if it is next request for same group then increment second level index
+                        switch (lastResourceLevel) {
+                            case FIRST:
+                                secondLevelIndex = 0;
+                                break;
+                            case SECOND:
+                                boolean isSameLevelRequest = resourceInput.values().stream().anyMatch(item -> {
+                                    JsonElement tree = parser.parse(((String) item).split("\\|")[0]);
+                                    return tree.isJsonArray() && tree.getAsJsonArray().get(0).getAsString()
+                                            .equalsIgnoreCase(lastSecondLevelKey);
+                                });
+                                if (isSameLevelRequest) {
+                                    secondLevelIndex++;
+                                }
+                                break;
+                        }
+                        // get actual parent object to search for second level objects
+                        if (null != lastFirstLevelKey) {
+                            Object currentObject = serviceInputs.get(lastFirstLevelKey);
+                            if ((null != currentObject) && (currentObject instanceof List)) {
+                                List currentFirstLevelList = (List) currentObject;
+                                if (currentFirstLevelList.size() > firstLevelIndex) {
+                                    uuiServiceInput = (Map<String, Object>) currentFirstLevelList.get(firstLevelIndex);
+                                }
+
+                            }
+                        }
+                        indexToPick = secondLevelIndex;
+                        break;
 
-                Object value = getValue(property.getValue(), serviceInputs, serInput);
-                resouceRequest.put(key, value);
+                }
             }
+
+
         }
-        return resouceRequest;
-    }
 
-    private static Object getValue(Object value, Map<String, Object> serviceInputs, List<Input> servInputs) {
-        if(value instanceof Map) {
-            Map<String, Object> valueMap = new HashMap<>();
+        // replace value if key is available in service input
+        for (String key : resourceInput.keySet()) {
+            String value = (String) resourceInput.get(key);
+
+            if (value.contains("|")) {
+
+                // check which level
+
+                // node it type of getinput
+                String[] split = value.split("\\|");
+                String tmpKey = split[0];
+
+                JsonElement jsonTree = parser.parse(tmpKey);
+
+                // check if it is a list type
+                if (jsonTree.isJsonArray()) {
+                    JsonArray jsonArray = jsonTree.getAsJsonArray();
+                    boolean matchFound = false;
+                    if (jsonArray.size() == 3) {
+                        String keyName = jsonArray.get(0).getAsString();
+                        String keyType = jsonArray.get(2).getAsString();
+                        if (!levelKeyNameUpdated) {
+                            switch (resourceLevel) {
+                                case FIRST:
+                                    firstLevelKey = keyName;
+                                    break;
+                                case SECOND:
+                                    secondLevelKey = keyName;
+                                    break;
+                            }
+                            levelKeyNameUpdated = true;
+                        }
+
+                        if (uuiServiceInput.containsKey(keyName)) {
+                            Object vfcLevelObject = uuiServiceInput.get(keyName);
+                            // it will be always list
+                            if (vfcLevelObject instanceof List) {
+                                List vfcObject = (List) vfcLevelObject;
+                                if (vfcObject.size() > indexToPick) {
+                                    Map<String, Object> vfMap = (Map<String, Object>) vfcObject.get(indexToPick);
+                                    if (vfMap.containsKey(keyType)) {
+                                        if (vfMap.get(keyType) instanceof String) {
+                                            value = (String) vfMap.get(keyType);
+                                        } else {
+                                            value = getJsonString(vfMap.get(keyType));
+                                        }
+                                        matchFound = true;
+                                    }
+                                }
+                            }
+                        }
+                    }
 
-            Map<String, Object> propertyMap = (Map<String, Object>)value;
+                    if (!matchFound) {
+                        if (split.length == 1) { // means value is empty e.g. "a":"key1|"
+                            value = "";
+                        } else {
+                            value = split[1];
+                        }
+                    }
 
-            for(String key : propertyMap.keySet()) {
-                valueMap.put(key, getValue(propertyMap.get(key), serviceInputs, servInputs));
-            }
-            return valueMap; // return if the value is nested hashmap
-        } else if(value instanceof GetInput) {
-            String inputName = ((GetInput)value).getInputName();
-
-            if(serviceInputs.get(inputName) != null) {
-                value = serviceInputs.get(inputName);
-            } else {
-                for(Input input : servInputs) {
-                    if(input.getName().equals(inputName)) {
-                        return input.getDefault(); // return default value
+                } else {
+
+                    // if not a list type
+                    if (uuiServiceInput.containsKey(tmpKey)) {
+                        value = (String) uuiServiceInput.get(tmpKey);
+                    } else {
+                        if (split.length == 1) { // means value is empty e.g. "a":"key1|"
+                            value = "";
+                        } else {
+                            value = split[1];
+                        }
                     }
                 }
+
             }
+            resourceInput.put(key, value);
+        }
+        // store current processed details into map
+        if (null != currentVFData) {
+            currentVFData.put("currentFirstLevelKey", firstLevelKey);
+            currentVFData.put("currentFirstLevelIndex", firstLevelIndex);
+            currentVFData.put("currentSecondLevelKey", secondLevelKey);
+            currentVFData.put("currentSecondLevelIndex", secondLevelIndex);
+            currentVFData.put("lastNodeTypeProcessed", resourceLevel.toString());
         }
-        return value; // return property value
+
+        return resourceInput;
     }
 
-    private static String getCsarFromUuid(String uuid) throws Exception {
-               String catalogEndPoint = UrnPropertiesReader.getVariable("mso.catalog.db.endpoint");
-       HttpClient client = new HttpClient(UriBuilder.fromUri(catalogEndPoint).path(SERVICE_URL_TOSCA_CSAR).queryParam("serviceModelUuid", uuid).build().toURL(), "application/json", TargetEntity.CATALOG_DB);
-       
-        Response response = client.get();
-        String value = response.readEntity(String.class);
+    private static int getIntValue(Object inputObj, int defaultValue) {
+        if (null != inputObj) {
+            if (inputObj instanceof Integer) {
+                return ((Integer) inputObj).intValue();
+            }
+            if (StringUtils.isNotEmpty(inputObj.toString())) {
+                try {
+                    int val = Integer.parseInt(inputObj.toString());
+                    return val;
+                } catch (NumberFormatException e) {
+                    logger.warn("Unable to parse to int", e.getMessage());
+                }
+            }
+        }
+        return defaultValue;
+    }
 
-        HashMap<String, String> map = new Gson().fromJson(value, new TypeToken<HashMap<String, String>>() {}.getType());
+    public static Map<String, Object> getServiceInstnace(String uuid) throws Exception {
+        String catalogEndPoint = UrnPropertiesReader.getVariable("mso.catalog.db.endpoint");
 
-        String filePath = System.getProperty("mso.config.path") + "ASDC/" +  map.get("version") + "/" + map.get("name");
+        HttpClient client = new HttpClientFactory().newJsonClient(UriBuilder.fromUri(catalogEndPoint)
+                .path(SERVICE_URL_SERVICE_INSTANCE).queryParam("serviceModelUuid", uuid).build().toURL(),
+                TargetEntity.CATALOG_DB);
 
-        File csarFile = new File(filePath);
+        client.addAdditionalHeader("Accept", "application/json");
+        client.addAdditionalHeader("Authorization", UrnPropertiesReader.getVariable("mso.db.auth"));
 
-        if(!csarFile.exists()) {
-            throw new Exception("csar file does not exist.");
-        }
+        Response apiResponse = client.get();
 
-        return csarFile.getAbsolutePath();
+        String value = apiResponse.readEntity(String.class);
+
+        ObjectMapper objectMapper = new ObjectMapper();
+        HashMap<String, Object> map = objectMapper.readValue(value, HashMap.class);
+        return map;
     }
-    
+
     public static <T> T getJsonObject(String jsonstr, Class<T> type) {
         ObjectMapper mapper = new ObjectMapper();
         mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, true);
         try {
             return mapper.readValue(jsonstr, type);
-        } catch(IOException e) {
-            LOGGER.error(MessageEnum.RA_NS_EXC, "", "", MsoLogger.ErrorCode.BusinessProcesssError, "fail to unMarshal json", e);
+        } catch (IOException e) {
+            logger.error("fail to unMarshal json {}", e.getMessage());
         }
         return null;
     }
 
-    public static String getJsonString(Object srcObj)  {
+    public static String getJsonString(Object srcObj) {
         ObjectMapper mapper = new ObjectMapper();
         mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
         String jsonStr = null;
         try {
             jsonStr = mapper.writeValueAsString(srcObj);
-        } catch(JsonProcessingException e) {
-               LOGGER.error("SdcToscaParserException", e);
+        } catch (JsonProcessingException e) {
+            logger.error("SdcToscaParserException", e);
         }
         return jsonStr;
     }