diff options
Diffstat (limited to 'src/main/java/org/onap/nbi/apis')
7 files changed, 582 insertions, 0 deletions
diff --git a/src/main/java/org/onap/nbi/apis/RestConfiguration.java b/src/main/java/org/onap/nbi/apis/RestConfiguration.java new file mode 100644 index 0000000..8152d6f --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/RestConfiguration.java @@ -0,0 +1,18 @@ +package org.onap.nbi.apis; + +import org.onap.nbi.exceptions.BackendErrorHandler; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestConfiguration { + + @Bean + public RestTemplate restTemplate(RestTemplateBuilder builder) { + RestTemplate restTemplate = builder.build(); + restTemplate.setErrorHandler(new BackendErrorHandler()); + return restTemplate; + } +} diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/SdcClient.java b/src/main/java/org/onap/nbi/apis/servicecatalog/SdcClient.java new file mode 100644 index 0000000..abc8bda --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/SdcClient.java @@ -0,0 +1,145 @@ +package org.onap.nbi.apis.servicecatalog; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.apache.commons.io.IOUtils; +import org.onap.nbi.OnapComponentsUrlPaths; +import org.onap.nbi.exceptions.BackendFunctionalException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; +import org.springframework.web.util.UriComponentsBuilder; + +/** + * @author user + * + */ +@Service +public class SdcClient { + + public static final String HTTP_CALL_SDC_ON = "HTTP call SDC on "; + @Autowired + private RestTemplate restTemplate; + + @Value("${sdc.host}") + private String sdcHost; + + @Value("${sdc.header.ecompInstanceId}") + private String ecompInstanceId; + + @Value("${sdc.header.authorization}") + private String sdcHeaderAuthorization; + + private static final String HEADER_ECOMP_INSTANCE_ID = "x-ecomp-instanceid"; + private static final String HEADER_AUTHORIZATION = "Authorization"; + + private static final Logger LOGGER = LoggerFactory.getLogger(SdcClient.class); + + + public LinkedHashMap callGet(String id) { + StringBuilder callURL = new StringBuilder().append(sdcHost).append(OnapComponentsUrlPaths.SDC_ROOT_URL).append(id) + .append(OnapComponentsUrlPaths.SDC_GET_PATH); + + ResponseEntity<Object> response = callSdc(callURL.toString()); + return (LinkedHashMap) response.getBody(); + + } + + public List<LinkedHashMap> callFind(MultiValueMap<String, String> parametersMap) { + + UriComponentsBuilder callURL = UriComponentsBuilder.fromHttpUrl(sdcHost + OnapComponentsUrlPaths.SDC_ROOT_URL); + if (parametersMap != null) { + Map<String, String> stringStringMap = parametersMap.toSingleValueMap(); + for (String key : stringStringMap.keySet()) { + if (!key.equals("fields")) { + callURL.queryParam(key, stringStringMap.get(key)); + } + } + } + + ResponseEntity<Object> response = callSdc(callURL.build().encode().toUri().toString()); + return (List<LinkedHashMap>) response.getBody(); + + } + + + public File callGetWithAttachment(String toscaModelUrl) { + StringBuilder callURL = new StringBuilder().append(sdcHost).append(toscaModelUrl); + + String fileName = System.currentTimeMillis() + "tosca.csar"; + ResponseEntity<byte[]> response = callSdcWithAttachment(callURL.toString()); + File toscaFile = new File(fileName); + try { + FileOutputStream toscaFileStream = new FileOutputStream(toscaFile); + if (response != null) { + IOUtils.write(response.getBody(), toscaFileStream); + } + toscaFileStream.close(); + } catch (IOException e) { + LOGGER.error("cannot get TOSCA File for url " + toscaModelUrl); + } + return toscaFile; + + } + + private HttpEntity<String> buildRequestHeader() { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.add(HEADER_ECOMP_INSTANCE_ID, ecompInstanceId); + httpHeaders.add(HEADER_AUTHORIZATION, sdcHeaderAuthorization); + HttpEntity<String> entity = new HttpEntity<>("parameters", httpHeaders); + + return entity; + } + + + private ResponseEntity<Object> callSdc(String callURL) { + ResponseEntity<Object> response = + restTemplate.exchange(callURL, HttpMethod.GET, buildRequestHeader(), Object.class); + LOGGER.debug("response body : " + response.getBody().toString()); + LOGGER.info("response status : " + response.getStatusCodeValue()); + loggDebugIfResponseKo(callURL, response); + return response; + } + + private void loggDebugIfResponseKo(String callURL, ResponseEntity<Object> response) { + if (!response.getStatusCode().equals(HttpStatus.OK)) { + LOGGER.warn(HTTP_CALL_SDC_ON + callURL + " returns " + response.getStatusCodeValue() + ", " + + response.getBody().toString()); + } + } + + private ResponseEntity<byte[]> callSdcWithAttachment(String callURL) { + try { + ResponseEntity<byte[]> response = + restTemplate.exchange(callURL.toString(), HttpMethod.GET, buildRequestHeader(), byte[].class); + LOGGER.info("response status : " + response.getStatusCodeValue()); + if (!response.getStatusCode().equals(HttpStatus.OK)) { + LOGGER.warn(HTTP_CALL_SDC_ON + callURL.toString() + " returns " + response.getStatusCodeValue() + ", " + + response.getBody().toString()); + } + return response; + + } catch (BackendFunctionalException e) { + LOGGER.error(HTTP_CALL_SDC_ON + callURL.toString() + " error " + e); + + return null; + } + } + + +} + + diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationResource.java b/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationResource.java new file mode 100644 index 0000000..512b088 --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationResource.java @@ -0,0 +1,46 @@ +package org.onap.nbi.apis.servicecatalog; + +import java.util.LinkedHashMap; +import java.util.List; +import org.onap.nbi.commons.JsonRepresentation; +import org.onap.nbi.commons.Resource; +import org.onap.nbi.commons.ResourceManagement; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/serviceSpecification") +public class ServiceSpecificationResource extends ResourceManagement<Resource> { + + + @Autowired + ServiceSpecificationService serviceSpecificationService; + + @GetMapping(value = "/{serviceSpecId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Object> getServiceSpecification(@PathVariable String serviceSpecId, + @RequestParam MultiValueMap<String, String> params) { + LinkedHashMap response = serviceSpecificationService.get(serviceSpecId); + JsonRepresentation filter = new JsonRepresentation(params); + if (response.get("serviceSpecCharacteristic") != null) { + return this.getResponse(response, filter); + } else { + return this.getPartialResponse(response, filter); + + } + } + + @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Object> findServiceSpecification(@RequestParam MultiValueMap<String, String> params) { + List<LinkedHashMap> response = serviceSpecificationService.find(params); + JsonRepresentation filter = new JsonRepresentation(params); + return this.findResponse(response, filter, null); + } + +} diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationService.java b/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationService.java new file mode 100644 index 0000000..3b56819 --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/ServiceSpecificationService.java @@ -0,0 +1,51 @@ +package org.onap.nbi.apis.servicecatalog; + +import java.util.LinkedHashMap; +import java.util.List; +import org.onap.nbi.apis.servicecatalog.jolt.FindServiceSpecJsonTransformer; +import org.onap.nbi.apis.servicecatalog.jolt.GetServiceSpecJsonTransformer; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.MultiValueMap; + +@Service +public class ServiceSpecificationService { + + @Autowired + SdcClient sdcClient; + + @Autowired + GetServiceSpecJsonTransformer getServiceSpecJsonTransformer; + + @Autowired + FindServiceSpecJsonTransformer findServiceSpecJsonTransformer; + + @Autowired + ToscaInfosProcessor toscaInfosProcessor; + + private static final Logger LOGGER = LoggerFactory.getLogger(ServiceSpecificationService.class); + + + public LinkedHashMap get(String serviceSpecId) { + LinkedHashMap sdcResponse = sdcClient.callGet(serviceSpecId); + LinkedHashMap serviceCatalogResponse = (LinkedHashMap) getServiceSpecJsonTransformer.transform(sdcResponse); + LinkedHashMap toscaInfosTopologyTemplate = toscaInfosProcessor.getToscaInfos(serviceCatalogResponse); + if (toscaInfosTopologyTemplate != null) { + LOGGER.debug("tosca file found, retrieving informations"); + toscaInfosProcessor.buildResponseWithToscaInfos(toscaInfosTopologyTemplate, serviceCatalogResponse); + } else { + LOGGER.debug("no tosca file found, partial response"); + } + return serviceCatalogResponse; + } + + + public List<LinkedHashMap> find(MultiValueMap<String, String> parametersMap) { + List<LinkedHashMap> sdcResponse = sdcClient.callFind(parametersMap); + List<LinkedHashMap> serviceCatalogResponse = + (List<LinkedHashMap>) findServiceSpecJsonTransformer.transform(sdcResponse); + return serviceCatalogResponse; + } +} diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/ToscaInfosProcessor.java b/src/main/java/org/onap/nbi/apis/servicecatalog/ToscaInfosProcessor.java new file mode 100644 index 0000000..4bfbd7b --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/ToscaInfosProcessor.java @@ -0,0 +1,249 @@ +package org.onap.nbi.apis.servicecatalog; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import org.apache.commons.collections.CollectionUtils; +import org.apache.commons.io.FileUtils; +import org.onap.nbi.exceptions.TechnicalException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; + +@Service +public class ToscaInfosProcessor { + + @Autowired + SdcClient sdcClient; + + final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); // jackson databind + + private static final Logger LOGGER = LoggerFactory.getLogger(ToscaInfosProcessor.class); + + public void buildResponseWithToscaInfos(LinkedHashMap toscaInfosTopologyTemplate, + LinkedHashMap serviceCatalogResponse) { + if (toscaInfosTopologyTemplate.get("inputs") != null) { + ArrayList serviceSpecCharacteristic = new ArrayList(); + LinkedHashMap toscaInfos = (LinkedHashMap) toscaInfosTopologyTemplate.get("inputs"); + for (Object key : toscaInfos.keySet()) { + String keyString = (String) key; + LinkedHashMap inputParameter = (LinkedHashMap) toscaInfos.get(key); + LinkedHashMap mapParameter = new LinkedHashMap(); + String parameterType = (String) inputParameter.get("type"); + mapParameter.put("name", keyString); + mapParameter.put("description", inputParameter.get("description")); + mapParameter.put("valueType", parameterType); + mapParameter.put("@type", "ONAPserviceCharacteristic"); + mapParameter.put("required", inputParameter.get("required")); + mapParameter.put("status", inputParameter.get("status")); + List<LinkedHashMap> serviceSpecCharacteristicValues = + buildServiceSpecCharacteristicsValues(inputParameter, parameterType); + mapParameter.put("serviceSpecCharacteristicValue", serviceSpecCharacteristicValues); + serviceSpecCharacteristic.add(mapParameter); + } + + serviceCatalogResponse.put("serviceSpecCharacteristic", serviceSpecCharacteristic); + } + LinkedHashMap node_templates = (LinkedHashMap) toscaInfosTopologyTemplate.get("node_templates"); + + List<LinkedHashMap> resourceSpecifications = + (List<LinkedHashMap>) serviceCatalogResponse.get("resourceSpecification"); + for (LinkedHashMap resourceSpecification : resourceSpecifications) { + String id = (String) resourceSpecification.get("id"); + LOGGER.debug("get tosca infos for service id: " + id); + LinkedHashMap toscaInfosFromResourceId = getToscaInfosFromResourceUUID(node_templates, id); + resourceSpecification.put("modelCustomizationId", toscaInfosFromResourceId.get("customizationUUID")); + resourceSpecification.put("modelCustomizationName", toscaInfosFromResourceId.get("name")); + + } + } + + private List<LinkedHashMap> buildServiceSpecCharacteristicsValues(LinkedHashMap parameter, String parameterType) { + List<LinkedHashMap> serviceSpecCharacteristicValues = new ArrayList<>(); + if (!"map".equalsIgnoreCase(parameterType) && !"list".equalsIgnoreCase(parameterType)) { + LOGGER.debug("get tosca infos for serviceSpecCharacteristicValues of type map or string : " + parameter); + Object aDefault = parameter.get("default"); + if (parameter.get("entry_schema") != null) { + ArrayList entry_schema = (ArrayList) parameter.get("entry_schema"); + if (CollectionUtils.isNotEmpty(entry_schema)) { + buildCharacteristicValuesFormShema(parameterType, serviceSpecCharacteristicValues, aDefault, + entry_schema); + } + } + } + return serviceSpecCharacteristicValues; + } + + private void buildCharacteristicValuesFormShema(String parameterType, + List<LinkedHashMap> serviceSpecCharacteristicValues, Object aDefault, ArrayList entry_schema) { + LinkedHashMap constraints = (LinkedHashMap) entry_schema.get(0); + if (constraints != null) { + ArrayList constraintsList = (ArrayList) constraints.get("constraints"); + if (CollectionUtils.isNotEmpty(constraintsList)) { + LinkedHashMap valuesMap = (LinkedHashMap) constraintsList.get(0); + if (valuesMap != null) { + List<Object> values = (List<Object>) valuesMap.get("valid_values"); + for (Object value : values) { + String stringValue = value.toString(); + LinkedHashMap serviceSpecCharacteristicValue = new LinkedHashMap(); + serviceSpecCharacteristicValue.put("isDefault", + aDefault != null && aDefault.toString().equals(stringValue)); + serviceSpecCharacteristicValue.put("value", stringValue); + serviceSpecCharacteristicValue.put("valueType", parameterType); + serviceSpecCharacteristicValues.add(serviceSpecCharacteristicValue); + } + } + } + } + } + + + private LinkedHashMap getToscaInfosFromResourceUUID(LinkedHashMap node_templates, String name) { + for (Object nodeTemplateObject : node_templates.values()) { + LinkedHashMap nodeTemplate = (LinkedHashMap) nodeTemplateObject; + LinkedHashMap metadata = (LinkedHashMap) nodeTemplate.get("metadata"); + String metadataUUID = (String) metadata.get("UUID"); + String metadataType = (String) metadata.get("type"); + if ("VF".equalsIgnoreCase(metadataType) && name.equalsIgnoreCase(metadataUUID)) { + return metadata; + } + } + return null; + } + + + public LinkedHashMap getToscaInfos(LinkedHashMap sdcResponse) { + String toscaModelUrl = (String) sdcResponse.get("toscaModelURL"); + String serviceId = (String) sdcResponse.get("uuid"); + File toscaFile = sdcClient.callGetWithAttachment(toscaModelUrl); + Timestamp timestamp = new Timestamp(System.currentTimeMillis()); + String tempFolderName = serviceId + timestamp; + File folderTemp = null; + LinkedHashMap topology_template = null; + try { + unZipArchive(toscaFile.getName(), tempFolderName); + folderTemp = new File(tempFolderName); + LOGGER.debug("temp folder for tosca files : " + folderTemp.getName()); + + LinkedHashMap toscaMetaFileHashMap = parseToscaFile(tempFolderName + "/TOSCA-Metadata/TOSCA.meta"); + if (toscaMetaFileHashMap.get("Entry-Definitions") == null) { + throw new NullPointerException("no Entry-Definitions node in TOSCA.meta"); + } + String toscaFilePath = (String) toscaMetaFileHashMap.get("Entry-Definitions"); + LinkedHashMap toscaFileHashMap = parseToscaFile(tempFolderName + "/" + toscaFilePath); + + if (toscaFileHashMap.get("topology_template") == null) { + throw new NullPointerException("no topology_template node in tosca file"); + } + topology_template = (LinkedHashMap) toscaFileHashMap.get("topology_template"); + + } catch (NullPointerException e) { + LOGGER.error("unable to parse tosca file for id : " + serviceId + ", " + e.getMessage()); + return null; + } finally { + try { + LOGGER.debug("deleting temp folder for tosca files : " + folderTemp.getName()); + FileUtils.deleteDirectory(folderTemp); + LOGGER.debug("deleting tosca archive : " + toscaFile.getName()); + FileUtils.forceDelete(toscaFile); + return topology_template; + } catch (IOException e) { + LOGGER.error("unable to delete temp directory tosca file for id : " + serviceId); + return null; + + } + } + } + + + private LinkedHashMap parseToscaFile(String fileName) { + + File toscaFile = new File(fileName); + if (toscaFile == null) { + throw new TechnicalException("unable to find file : " + fileName); + } + try { + return (LinkedHashMap) mapper.readValue(toscaFile, Object.class); + } catch (IOException e) { + LOGGER.error("unable to parse tosca file : " + fileName); + LOGGER.error(e.getMessage()); + throw new TechnicalException("Unable to parse tosca file : " + fileName); + + } catch (NullPointerException e) { + LOGGER.error("unable to find tosca file : " + fileName); + LOGGER.error(e.getMessage()); + throw new TechnicalException("unable to find tosca file : " + fileName); + } + } + + + /** + * Unzip it + * + * @param zipFile input zip file + * @param outputFolder zip file output folder + */ + private void unZipArchive(String zipFile, String outputFolder) { + + byte[] buffer = new byte[1024]; + + try { + + // create output directory is not exists + File folder = new File(outputFolder); + if (!folder.exists()) { + folder.mkdir(); + } + + // get the zip file content + try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) { + // get the zipped file list entry + ZipEntry ze = zis.getNextEntry(); + + while (ze != null) { + + String fileName = ze.getName(); + File newFile = new File(outputFolder + File.separator + fileName); + + LOGGER.debug("File to unzip : " + newFile.getAbsoluteFile()); + + // create all non exists folders + // else you will hit FileNotFoundException for compressed folder + new File(newFile.getParent()).mkdirs(); + + try (FileOutputStream fos = new FileOutputStream(newFile)) { + + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + + fos.close(); + } + ze = zis.getNextEntry(); + } + + zis.closeEntry(); + zis.close(); + } + + LOGGER.debug("Done"); + + } catch (IOException ex) { + LOGGER.error("Error while unzipping ToscaModel archive from ONAP : " + ex.getMessage()); + throw new TechnicalException("Error while unzipping ToscaModel archive from ONAP"); + } + } + + +} diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/FindServiceSpecJsonTransformer.java b/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/FindServiceSpecJsonTransformer.java new file mode 100644 index 0000000..b32f9fc --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/FindServiceSpecJsonTransformer.java @@ -0,0 +1,36 @@ +package org.onap.nbi.apis.servicecatalog.jolt; + +import com.bazaarvoice.jolt.Chainr; +import com.bazaarvoice.jolt.JsonUtils; +import com.bazaarvoice.jolt.exception.JoltException; +import org.onap.nbi.exceptions.TechnicalException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class FindServiceSpecJsonTransformer { + + private Chainr chainr; + + private static final Logger LOGGER = LoggerFactory.getLogger(FindServiceSpecJsonTransformer.class); + + public FindServiceSpecJsonTransformer() { + List<Object> specs = JsonUtils.classpathToList("/jolt/findServiceCatalog.json"); + this.chainr = Chainr.fromSpec(specs); + } + + public Object transform(Object serviceSpec) { + Object output = null; + try { + output = chainr.transform(serviceSpec); + } catch (JoltException joE) { + LOGGER.error("Unable to transform SDC response with JOLT Transformer : " + joE.getMessage()); + throw new TechnicalException("Error while parsing ONAP response"); + } + return output; + } + +} diff --git a/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/GetServiceSpecJsonTransformer.java b/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/GetServiceSpecJsonTransformer.java new file mode 100644 index 0000000..784ed6f --- /dev/null +++ b/src/main/java/org/onap/nbi/apis/servicecatalog/jolt/GetServiceSpecJsonTransformer.java @@ -0,0 +1,37 @@ +package org.onap.nbi.apis.servicecatalog.jolt; + +import com.bazaarvoice.jolt.Chainr; +import com.bazaarvoice.jolt.JsonUtils; +import com.bazaarvoice.jolt.exception.JoltException; +import org.onap.nbi.exceptions.TechnicalException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class GetServiceSpecJsonTransformer { + + private Chainr chainr; + + private static final Logger LOGGER = LoggerFactory.getLogger(GetServiceSpecJsonTransformer.class); + + + public GetServiceSpecJsonTransformer() { + List<Object> specs = JsonUtils.classpathToList("/jolt/getServiceCatalog.json"); + this.chainr = Chainr.fromSpec(specs); + } + + public Object transform(Object serviceSpec) { + Object output = null; + try { + output = chainr.transform(serviceSpec); + } catch (JoltException joE) { + LOGGER.error("Unable to transform SDC response with JOLT Transformer : " + joE.getMessage()); + throw new TechnicalException("Error while parsing ONAP response"); + } + return output; + } + +} |