Migrated VNF to JAX-RS HTTP client 25/56925/6
authorvempo <vitaliy.emporopulo@amdocs.com>
Thu, 19 Jul 2018 15:46:10 +0000 (18:46 +0300)
committervempo <vitaliy.emporopulo@amdocs.com>
Mon, 30 Jul 2018 16:19:45 +0000 (19:19 +0300)
Change-Id: I8735839aeffe89c191df562732b8f5ab30a81444
Issue-ID: SDC-1278
Signed-off-by: vempo <vitaliy.emporopulo@amdocs.com>
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/pom.xml
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/VnfPackageRepository.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/main/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImpl.java
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImplTest.java [new file with mode: 0644]
openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/resources/config-vnfrepo.yaml [new file with mode: 0644]

index edc7b8b..d504f70 100644 (file)
@@ -1,4 +1,21 @@
 <?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2017 Huawei Technologies Co., Ltd.
+  ~ Modifications Copyright 2018 European Support Limited
+  ~
+  ~ 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.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
     <modelVersion>4.0.0</modelVersion>
 
     <dependencies>
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-core</artifactId>
-            <version>${spring.framework.version}</version>
-        </dependency>
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-context</artifactId>
-            <version>${spring.framework.version}</version>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>javax.ws.rs-api</artifactId>
+            <version>${ws.rs.version}</version>
+            <scope>provided</scope>
         </dependency>
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-context-support</artifactId>
-            <version>${spring.framework.version}</version>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>${swagger.version}</version>
         </dependency>
         <dependency>
             <groupId>org.springframework</groupId>
-            <artifactId>spring-web</artifactId>
+            <artifactId>spring-context</artifactId>
             <version>${spring.framework.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-beans</artifactId>
-            <version>${spring.framework.version}</version>
+            <groupId>org.openecomp.sdc.onboarding</groupId>
+            <artifactId>vendor-software-products-rest-services</artifactId>
+            <version>${project.version}</version>
         </dependency>
-
-        <!-- CXF -->
         <dependency>
-            <groupId>org.apache.cxf</groupId>
-            <artifactId>cxf-rt-frontend-jaxrs</artifactId>
-            <version>${cxf.version}</version>
+            <groupId>org.onap.sdc.common</groupId>
+            <artifactId>onap-configuration-management-api</artifactId>
+            <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.httpcomponents</groupId>
-            <artifactId>httpclient</artifactId>
-            <version>${http.client.version}</version>
-        </dependency>
-
-
-        <!-- Java Stuff -->
-        <dependency>
-            <groupId>javax.inject</groupId>
-            <artifactId>javax.inject</artifactId>
-            <version>${javax.inject.version}</version>
-            <scope>provided</scope>
+            <groupId>org.onap.sdc.common</groupId>
+            <artifactId>onap-configuration-management-core</artifactId>
+            <version>${project.version}</version>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
             <groupId>org.openecomp.sdc</groupId>
-            <artifactId>openecomp-sdc-common-rest</artifactId>
+            <artifactId>openecomp-sdc-logging-api</artifactId>
             <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.openecomp.sdc</groupId>
-            <artifactId>common-app-api</artifactId>
+            <artifactId>openecomp-sdc-logging-core</artifactId>
             <version>${project.version}</version>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
-            <groupId>org.onap.sdc.common</groupId>
-            <artifactId>onap-configuration-management-api</artifactId>
-            <version>${project.version}</version>
+            <groupId>org.apache.cxf</groupId>
+            <artifactId>cxf-rt-rs-client</artifactId>
+            <version>${cxf.version}</version>
+            <scope>runtime</scope>
         </dependency>
         <dependency>
-            <groupId>org.onap.sdc.common</groupId>
-            <artifactId>onap-configuration-management-core</artifactId>
-            <version>${project.version}</version>
-            <scope>runtime</scope>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+            <version>${slf4j.version}</version>
+            <scope>test</scope>
         </dependency>
         <dependency>
-            <groupId>org.openecomp.sdc.onboarding</groupId>
-            <artifactId>vendor-software-products-rest-services</artifactId>
-            <version>${project.version}</version>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.tomakehurst</groupId>
+            <artifactId>wiremock</artifactId>
+            <version>2.18.0</version>
+            <scope>test</scope>
         </dependency>
-
     </dependencies>
 
     <build>
index 32a2ef5..8723bf2 100644 (file)
 
 package org.openecomp.sdcrests.vsp.rest;
 
+import static org.openecomp.sdcrests.common.RestConstants.USER_ID_HEADER_PARAM;
+import static org.openecomp.sdcrests.common.RestConstants.USER_MISSING_ERROR_MSG;
+
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
-import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
-import org.springframework.validation.annotation.Validated;
-
+import java.io.File;
 import javax.validation.constraints.NotNull;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.io.File;
-
-import static org.openecomp.sdcrests.common.RestConstants.USER_ID_HEADER_PARAM;
-import static org.openecomp.sdcrests.common.RestConstants.USER_MISSING_ERROR_MSG;
+import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
+import org.springframework.validation.annotation.Validated;
 
 @Path("/v1.0/vendor-software-products/{vspId}/versions/{versionId}/vnfrepository")
 @Produces(MediaType.APPLICATION_JSON)
@@ -41,7 +46,8 @@ public interface VnfPackageRepository extends VspEntities {
     @GET
     @Path("/vnfpackages")
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    @ApiOperation(value = "Get VNF packages from VNF Repository", notes = "Call VNF Repostory to get VNF package details", response = File.class)
+    @ApiOperation(value = "Get VNF packages from VNF Repository",
+            notes = "Call VNF Repository to get VNF package details", response = File.class)
     Response getVnfPackages(@PathParam("vspId") String vspId,
             @ApiParam(value = "Version Id") @PathParam("versionId") String versionId,
             @NotNull(message = USER_MISSING_ERROR_MSG) @HeaderParam(USER_ID_HEADER_PARAM) String user) throws Exception;
@@ -49,7 +55,8 @@ public interface VnfPackageRepository extends VspEntities {
     @GET
     @Path("/vnfpackage/{csarId}/download")
     @Produces(MediaType.APPLICATION_OCTET_STREAM)
-    @ApiOperation(value = "Download VNF package from VNF Repository", notes = "Download VNF package from VNF repository and send to client", response = File.class)
+    @ApiOperation(value = "Download VNF package from VNF Repository",
+            notes = "Download VNF package from VNF repository and send to client", response = File.class)
     Response downloadVnfPackage(@PathParam("vspId") String vspId,
             @ApiParam(value = "Version Id") @PathParam("versionId") String versionId,
             @PathParam("csarId") String csarId,
@@ -58,7 +65,9 @@ public interface VnfPackageRepository extends VspEntities {
     @POST
     @Path("/vnfpackage/{csarId}/import")
     @Produces(MediaType.APPLICATION_JSON)
-    @ApiOperation(value = "Import VNF package from VNF Repository", notes = "Call VNF Repostory to download VNF package, validate it and send the response", response = UploadFileResponseDto.class)
+    @ApiOperation(value = "Import VNF package from VNF Repository",
+            notes = "Call VNF Repository to download VNF package, validate it and send the response",
+            response = UploadFileResponseDto.class)
     Response importVnfPackage(@PathParam("vspId") String vspId,
             @ApiParam(value = "Version Id") @PathParam("versionId") String versionId,
             @PathParam("csarId") String csarId,
index 7905417..be14c45 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright 2017 Huawei Technologies Co., Ltd.
+ * Modifications Copyright 2018 European Support Limited
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.openecomp.sdcrests.vsp.rest.services;
 
-import org.apache.http.HttpStatus;
-import org.onap.config.api.Configuration;
+import static javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION;
+import static org.openecomp.core.utilities.file.FileUtils.getFileExtension;
+import static org.openecomp.core.utilities.file.FileUtils.getNetworkPackageName;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import javax.inject.Named;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.SSLContext;
+import javax.ws.rs.client.Client;
+import javax.ws.rs.client.ClientBuilder;
+import javax.ws.rs.client.Invocation;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.Link;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.UriBuilder;
 import org.onap.config.api.ConfigurationManager;
-import org.openecomp.sdc.common.http.client.api.HttpRequest;
-import org.openecomp.sdc.common.http.client.api.HttpResponse;
+import org.openecomp.sdc.common.errors.CoreException;
+import org.openecomp.sdc.common.errors.ErrorCode;
+import org.openecomp.sdc.common.errors.ErrorCodeAndMessage;
+import org.openecomp.sdc.common.errors.GeneralErrorBuilder;
 import org.openecomp.sdc.logging.api.Logger;
 import org.openecomp.sdc.logging.api.LoggerFactory;
 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
@@ -35,22 +59,14 @@ import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFile
 import org.springframework.context.annotation.Scope;
 import org.springframework.stereotype.Service;
 
-import javax.inject.Named;
-import javax.ws.rs.core.Response;
-import java.io.BufferedInputStream;
-import java.io.ByteArrayInputStream;
-import java.io.InputStream;
-import java.nio.charset.StandardCharsets;
-
-import static javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION;
-import static org.openecomp.core.utilities.file.FileUtils.getFileExtension;
-import static org.openecomp.core.utilities.file.FileUtils.getNetworkPackageName;
-
 /**
- * The class implements the API interface with VNF Repository (VNFSDK) such as
- * i) Get all the VNF Package Meta-data ii) Download the VNF Package iii) Import
- * VNF package to SDC catalog (Download & validate)
- * 
+ * Enables integration API interface with VNF Repository (VNFSDK).
+ * <ol>
+ *     <li>Get all the VNF Package Meta-data.</li>
+ *     <li>Download a VNF Package.</li>
+ *     <li>Import a VNF package to SDC catalog (Download & validate).</li>
+ * </ol>
+ *
  * @version Amsterdam release (ONAP 1.0)
  */
 @Named
@@ -60,163 +76,306 @@ public class VnfPackageRepositoryImpl implements VnfPackageRepository {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(VnfPackageRepositoryImpl.class);
 
-    private static boolean initFlag = false;
+    private final Configuration config;
 
-    // Default VNF Repository configuration
-    private static final String CONFIG_NAMESPACE = "vnfrepo";
+    public VnfPackageRepositoryImpl(Configuration config) {
+        this.config = config;
+    }
 
-    // Default address for VNF repository docker
-    private static final String DEF_DOCKER_COMPOSE_ADDR = "127.0.0.1";
+    public VnfPackageRepositoryImpl() {
+        this(new FileConfiguration());
+    }
 
-    private static String ipAddress = DEF_DOCKER_COMPOSE_ADDR;
+    @Override
+    public Response getVnfPackages(String vspId, String versionId, String user) {
 
-    // Default Download package URI and Get VNF package meta-data URI -
-    // configurable
-    private static String getVnfPkgUri = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars";
+        LOGGER.debug("Get VNF Packages from Repository: {}", vspId);
 
-    private static String downldPkgUri = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars/%s/files";
+        Client client = new SharedClient();
 
-    // Default port for VNF Repository
-    private static String port = "8702";
+        final String getVnfPackageUri = config.getGetUri();
 
-    @Override
-    public Response getVnfPackages(String vspId, String versionId, String user) throws Exception {
+        try {
 
-        LOGGER.debug("Get VNF Packages from Repository:{}", vspId);
+            Response remoteResponse = client.target(getVnfPackageUri).request().get();
+            if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
+                return handleUnexpectedStatus("querying VNF package metadata", getVnfPackageUri, remoteResponse);
+            }
 
-        // Step 1: Create REST client and configuration and prepare URI
-        init();
+            LOGGER.debug("Response from VNF Repository: {}", remoteResponse);
+            return Response.ok(remoteResponse.readEntity(String.class)).build();
 
-        // Step 2: Build URI based on the IP address and port allocated
-        HttpResponse<String> rsp = HttpRequest.get(getVnfPkgUri);
-        if(HttpStatus.SC_OK != rsp.getStatusCode()) {
-            LOGGER.error("Failed to query VNF package metadata:uri={}, Response={}", getVnfPkgUri, rsp);
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        } finally {
+            client.close();
         }
-
-        // Step 3: Send the response to the client
-        LOGGER.debug("Response from VNF Repository: {}", rsp.getResponse());
-
-        return Response.ok(rsp.getResponse()).build();
     }
 
     @Override
-    public Response importVnfPackage(String vspId, String versionId, String csarId, String user) throws Exception {
+    public Response importVnfPackage(String vspId, String versionId, String csarId, String user) {
+
+        LOGGER.debug("Import VNF Packages from Repository: {}", csarId);
+
+        final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
+
+        Client client = new SharedClient();
+
+        try {
 
-        LOGGER.debug("Import VNF Packages from Repository:{}", csarId);
+            Response remoteResponse = client.target(downloadPackageUri).request().get();
+            if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
+                return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
+            }
 
-        // Step 1: Create REST client and configuration and prepare URI
-        init();
+            LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
+            byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
+            return uploadVnfPackage(vspId, versionId, csarId, payload);
 
-        // Step 2: Build URI based on the IP address and port allocated
-        String uri = String.format(downldPkgUri, csarId);
-        HttpResponse<String> rsp = HttpRequest.get(uri);
-        if(HttpStatus.SC_OK != rsp.getStatusCode()) {
-            LOGGER.error("Failed to download package from VNF Repository:uri={}, Response={}", uri, rsp);
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+        } finally {
+            client.close();
         }
-        LOGGER.debug("Response from VNF Repository for download package is success ");
+    }
+
+    private Response uploadVnfPackage(String vspId, String versionId, String csarId, byte[] payload) {
 
-        // Step 3: Import the file to SDC and validate and send the response
-        try (InputStream fileStream = new BufferedInputStream(
-                new ByteArrayInputStream(rsp.getResponse().getBytes(StandardCharsets.ISO_8859_1)))) {
+        try (InputStream fileStream = new BufferedInputStream(new ByteArrayInputStream(payload))) {
 
-            String filename = "temp_" + csarId + ".csar";
             OrchestrationTemplateCandidateManager candidateManager =
                     OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
-            UploadFileResponse uploadFileResponse = candidateManager.upload(vspId, getVersion(vspId, versionId),
-                    fileStream, getFileExtension(filename), getNetworkPackageName(filename));
 
-            UploadFileResponseDto uploadFileResponseDto = new MapUploadFileResponseToUploadFileResponseDto()
-                    .applyMapping(uploadFileResponse, UploadFileResponseDto.class);
+            String filename = formatFilename(csarId);
+            Version version = getVersion(vspId, versionId);
+            UploadFileResponse response = candidateManager.upload(vspId, version, fileStream,
+                    getFileExtension(filename), getNetworkPackageName(filename));
 
-            return Response.ok(uploadFileResponseDto).build();
-        } catch(Exception e) {
-            // Exception while uploading file
+            UploadFileResponseDto uploadFileResponse = new MapUploadFileResponseToUploadFileResponseDto()
+                                                               .applyMapping(response, UploadFileResponseDto.class);
 
-            LOGGER.error("Exception while uploading VNF package received from VNF Repository:", e);
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
+            return Response.ok(uploadFileResponse).build();
+
+        } catch (Exception e) {
+            ErrorCode error = new GeneralErrorBuilder().build();
+            LOGGER.error("Exception while uploading package received from VNF Repository", new CoreException(error, e));
+            return generateInternalServerError(error);
         }
     }
 
     @Override
-    public Response downloadVnfPackage(String vspId, String versionId, String csarId, String user) throws Exception {
+    public Response downloadVnfPackage(String vspId, String versionId, String csarId, String user) {
 
-        LOGGER.debug("Download VNF Packages from Repository:csarId={}", csarId);
+        LOGGER.debug("Download VNF package from repository: csarId={}", csarId);
 
-        // Step 1: Create REST client and configuration and prepare URI
-        init();
+        final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
 
-        // Step 2: Build URI based on the IP address and port allocated
-        String uri = String.format(downldPkgUri, csarId);
-        HttpResponse<String> rsp = HttpRequest.get(uri);
-        if(HttpStatus.SC_OK != rsp.getStatusCode()) {
-            LOGGER.error("Failed to download package from VNF Repository:uri={}, Response={}", uri, rsp);
-            return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
-        }
+        Client client = new SharedClient();
 
-        // Step 3:Send response to the client
-        String filename = "temp_" + csarId + ".csar";
-        Response.ResponseBuilder response = Response.ok(rsp.getResponse().getBytes(StandardCharsets.ISO_8859_1));
-        response.header(CONTENT_DISPOSITION, "attachment; filename=" + filename);
+        try {
 
-        LOGGER.debug("Response from VNF Repository for download package is success ");
+            Response remoteResponse = client.target(downloadPackageUri).request().get();
+            if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
+                return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
+            }
+
+            byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
+            Response.ResponseBuilder response = Response.ok(payload);
+            response.header(CONTENT_DISPOSITION, "attachment; filename=" + formatFilename(csarId));
 
-        return response.build();
+            LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
+            return response.build();
+
+        } finally {
+            client.close();
+        }
     }
 
     private Version getVersion(String vspId, String versionId) {
-        // Get list of Versions from the rest call
         VersioningManager versioningManager = VersioningManagerFactory.getInstance().createInterface();
+        return findVersion(versioningManager.list(vspId), versionId).orElse(new Version(versionId));
+    }
 
-        // Find the corresponding version from versionId
-        return versioningManager.list(vspId).stream().filter(ver -> ver.getId() != versionId).findAny()
-                .orElse(new Version(versionId));
+    Optional<Version> findVersion(List<Version> versions, String requestedVersion) {
+        return versions.stream().filter(ver -> Objects.equals(ver.getId(), requestedVersion)).findAny();
     }
 
-    private static void setVnfRepoConfig() {
+    private static Response handleUnexpectedStatus(String action, String uri, Response response) {
+        ErrorCode error = new GeneralErrorBuilder().build();
+        LOGGER.error("Unexpected response status while {}: URI={}, Response={}", action, uri, response,
+                new CoreException(error));
+        return generateInternalServerError(error);
+    }
 
-        try {
-            // Step 1: Fetch the on-boarding configuration
-            Configuration config = ConfigurationManager.lookup();
+    private static Response generateInternalServerError(ErrorCode error) {
+        ErrorCodeAndMessage payload = new ErrorCodeAndMessage(Response.Status.INTERNAL_SERVER_ERROR, error);
+        return Response.serverError().entity(payload).build();
+    }
 
-            String vnfRepoHost = config.getAsString(CONFIG_NAMESPACE, "vnfRepoHost");
-            if(null != vnfRepoHost) {
-                ipAddress = vnfRepoHost;
-            }
+    private static String formatFilename(String csarId) {
+        return "temp_" + csarId + ".csar";
+    }
 
-            String vnfRepoPort = config.getAsString(CONFIG_NAMESPACE, "vnfRepoPort");
-            if(null != vnfRepoPort) {
-                port = vnfRepoPort;
-            }
+    interface Configuration {
 
-            String getVnfUri = config.getAsString(CONFIG_NAMESPACE, "getVnfUri");
-            if(null != getVnfUri) {
-                getVnfPkgUri = getVnfUri;
-            }
+        String getGetUri();
 
-            String downloadVnfUri = config.getAsString(CONFIG_NAMESPACE, "downloadVnfUri");
-            if(null != downloadVnfUri) {
-                downldPkgUri = downloadVnfUri;
-            }
+        String getDownloadUri();
+    }
+
+    private static class SharedClient implements Client {
+
+        private static final Client CLIENT = ClientBuilder.newClient();
+
+        @Override
+        public void close() {
+            // do not close the shared client
+        }
+
+        @Override
+        public WebTarget target(String uri) {
+            return CLIENT.target(uri);
+        }
+
+        @Override
+        public WebTarget target(URI uri) {
+            return CLIENT.target(uri);
+        }
+
+        @Override
+        public WebTarget target(UriBuilder uriBuilder) {
+            return CLIENT.target(uriBuilder);
+        }
+
+        @Override
+        public WebTarget target(Link link) {
+            return CLIENT.target(link);
+        }
+
+        @Override
+        public Invocation.Builder invocation(Link link) {
+            return CLIENT.invocation(link);
+        }
+
+        @Override
+        public SSLContext getSslContext() {
+            return CLIENT.getSslContext();
+        }
+
+        @Override
+        public HostnameVerifier getHostnameVerifier() {
+            return CLIENT.getHostnameVerifier();
+        }
+
+        @Override
+        public javax.ws.rs.core.Configuration getConfiguration() {
+            return CLIENT.getConfiguration();
+        }
+
+        @Override
+        public Client property(String name, Object value) {
+            return CLIENT.property(name, value);
+        }
+
+        @Override
+        public Client register(Class<?> componentClass) {
+            return CLIENT.register(componentClass);
+        }
+
+        @Override
+        public Client register(Class<?> componentClass, int priority) {
+            return CLIENT.register(componentClass, priority);
+        }
 
-        } catch(Exception e) {
-            LOGGER.error("Failed to load configuration, Exception caught, using default configuration", e);
+        @Override
+        public Client register(Class<?> componentClass, Class<?>... contracts) {
+            return CLIENT.register(componentClass, contracts);
         }
 
-        getVnfPkgUri =
-                new StringBuilder("http://").append(ipAddress).append(":").append(port).append(getVnfPkgUri).toString();
+        @Override
+        public Client register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
+            return CLIENT.register(componentClass, contracts);
+        }
+
+        @Override
+        public Client register(Object component) {
+            return CLIENT.register(component);
+        }
+
+        @Override
+        public Client register(Object component, int priority) {
+            return CLIENT.register(component, priority);
+        }
+
+        @Override
+        public Client register(Object component, Class<?>... contracts) {
+            return CLIENT.register(component, contracts);
+        }
 
-        downldPkgUri =
-                new StringBuilder("http://").append(ipAddress).append(":").append(port).append(downldPkgUri).toString();
+        @Override
+        public Client register(Object component, Map<Class<?>, Integer> contracts) {
+            return CLIENT.register(component, contracts);
+        }
     }
 
-    private static synchronized void init() throws Exception {
-        if(!initFlag) {
-            // Step 1: Initialize configuration
-            setVnfRepoConfig();
+    static class FileConfiguration implements Configuration {
+
+        @Override
+        public String getGetUri() {
+            return LazyFileConfiguration.INSTANCE.getGetUri();
+        }
+
+        @Override
+        public String getDownloadUri() {
+            return LazyFileConfiguration.INSTANCE.getDownloadUri();
+        }
+
+        private static class LazyFileConfiguration implements Configuration {
+
+            private static final String CONFIG_NAMESPACE = "vnfrepo";
 
-            initFlag = true;
+            private static final String DEFAULT_HOST = "localhost";
+            private static final String DEFAULT_PORT = "8702";
+
+            private static final String DEFAULT_URI_PREFIX = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars";
+            private static final String DEFAULT_LIST_URI = DEFAULT_URI_PREFIX + "/";
+            private static final String DEFAULT_DOWNLOAD_URI = DEFAULT_URI_PREFIX + "/%s/files";
+
+            private static final LazyFileConfiguration INSTANCE = new LazyFileConfiguration();
+
+            private final String getUri;
+            private final String downloadUri;
+
+            private LazyFileConfiguration() {
+                org.onap.config.api.Configuration config = ConfigurationManager.lookup();
+                String host = readConfig(config, "vnfRepoHost", DEFAULT_HOST);
+                String port = readConfig(config, "vnfRepoPort", DEFAULT_PORT);
+                String listPackagesUri = readConfig(config, "getVnfUri", DEFAULT_LIST_URI);
+                String downloadPackageUri = readConfig(config, "downloadVnfUri", DEFAULT_DOWNLOAD_URI);
+                this.getUri = formatUri(host, port, listPackagesUri);
+                this.downloadUri = formatUri(host, port, downloadPackageUri);
+            }
+
+            private String readConfig(org.onap.config.api.Configuration config, String key, String defaultValue) {
+
+                try {
+                    String value = config.getAsString(CONFIG_NAMESPACE, key);
+                    return (value == null) ? defaultValue : value;
+                } catch (Exception e) {
+                    LOGGER.error(
+                            "Failed to read VNF repository configuration key '{}', default value '{}' will be used",
+                            key, defaultValue, e);
+                    return defaultValue;
+                }
+            }
+
+            private static String formatUri(String host, String port, String path) {
+                return "http://" + host + ":" + port + (path.startsWith("/") ? path : "/" + path);
+            }
+
+            public String getGetUri() {
+                return getUri;
+            }
+
+            public String getDownloadUri() {
+                return downloadUri;
+            }
         }
     }
 }
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImplTest.java b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/java/org/openecomp/sdcrests/vsp/rest/services/VnfPackageRepositoryImplTest.java
new file mode 100644 (file)
index 0000000..b0f53ba
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * Copyright © 2016-2018 European Support Limited
+ *
+ * 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.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.openecomp.sdcrests.vsp.rest.services;
+
+import static com.github.tomakehurst.wiremock.client.WireMock.aResponse;
+import static com.github.tomakehurst.wiremock.client.WireMock.get;
+import static com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.stubFor;
+import static com.github.tomakehurst.wiremock.client.WireMock.urlEqualTo;
+import static com.github.tomakehurst.wiremock.client.WireMock.verify;
+import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.github.tomakehurst.wiremock.junit.WireMockRule;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import javax.ws.rs.core.Response;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.openecomp.sdc.versioning.dao.types.Version;
+
+/**
+ * Configuration testing.
+ * WireMock testing of remote calls.
+ *
+ * @author evitaliy
+ * @since 19 Jul 2018
+ */
+public class VnfPackageRepositoryImplTest {
+
+    private static final String GET_PATH = "/get";
+    private static final String DOWNLOAD_PATH = "/download";
+
+    @ClassRule
+    public static final WireMockRule wireMockRule = new WireMockRule(wireMockConfig().dynamicPort());
+    private static final String VSP = "anyVsp";
+    private static final String VERSION = "anyVersion";
+    private static final String USER = "anyUser";
+    private static final String CSAR = "anyCsar";
+
+    private static VnfPackageRepositoryImpl.Configuration config;
+
+    @BeforeClass
+    public static void initConfiguration() {
+        config = new DynamicConfiguration(wireMockRule.port());
+    }
+
+    @Test
+    public void versionFoundWhenInList() {
+        VnfPackageRepositoryImpl vnfRepository = new VnfPackageRepositoryImpl();
+        List<Version> versions = Arrays.asList(new Version("1243"), new Version("3434"), new Version("398"));
+        assertTrue("Expected to find the version", vnfRepository.findVersion(versions, "3434").isPresent());
+    }
+
+    @Test
+    public void versionNotFoundWhenInList() {
+        VnfPackageRepositoryImpl vnfRepository = new VnfPackageRepositoryImpl();
+        List<Version> versions = Collections.singletonList(new Version("1243"));
+        assertFalse("Did not expect to find the version", vnfRepository.findVersion(versions, "3434").isPresent());
+    }
+
+    @Test
+    public void configurationLoadedFromFile() {
+        final String prefix = "http://10.57.30.20:1111/";
+        assertEquals(prefix + "download-vnf-31", new VnfPackageRepositoryImpl.FileConfiguration().getDownloadUri());
+        assertEquals(prefix + "get-vnf-13", new VnfPackageRepositoryImpl.FileConfiguration().getGetUri());
+    }
+
+    @Test
+    public void listVnfsReturnsInternalServerErrorWhenRemoteClientError() {
+        stubFor(get(GET_PATH).willReturn(aResponse().withStatus(403)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.getVnfPackages(VSP, VERSION, USER);
+        assertEquals(500, response.getStatus());
+        verify(getRequestedFor(urlEqualTo(GET_PATH)));
+    }
+
+    @Test
+    public void listVnfsReturnsInternalServerErrorWhenRemoteReturnsNotOk() {
+        stubFor(get(GET_PATH).willReturn(aResponse().withStatus(204)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.getVnfPackages(VSP, VERSION, USER);
+        assertEquals(500, response.getStatus());
+        verify(getRequestedFor(urlEqualTo(GET_PATH)));
+    }
+
+    @Test
+    public void listVnfsReturnsUnchangedResponse() {
+        final String vnfList = "this is a response body for list of VNFs";
+        stubFor(get(GET_PATH).willReturn(aResponse().withStatus(200).withBody(vnfList)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.getVnfPackages(VSP, VERSION, USER);
+        assertEquals(200, response.getStatus());
+        assertEquals(vnfList, response.getEntity());
+        verify(getRequestedFor(urlEqualTo(GET_PATH)));
+    }
+
+    @Test
+    public void downloadVnfsReturnsInternalServerErrorWhenRemoteClientError() {
+        stubFor(get(DOWNLOAD_PATH).willReturn(aResponse().withStatus(403)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.downloadVnfPackage(VSP, VERSION, CSAR, USER);
+        assertEquals(500, response.getStatus());
+        verify(getRequestedFor(urlEqualTo(DOWNLOAD_PATH)));
+    }
+
+    @Test
+    public void downloadVnfsReturnsInternalServerErrorWhenRemoteReturnsNotOk() {
+        stubFor(get(DOWNLOAD_PATH).willReturn(aResponse().withStatus(204)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.downloadVnfPackage(VSP, VERSION, CSAR, USER);
+        assertEquals(500, response.getStatus());
+        verify(getRequestedFor(urlEqualTo(DOWNLOAD_PATH)));
+    }
+
+    @Test
+    public void downloadVnfsReturnsUnchangedBytes() {
+        final byte[] body = "this is the content of a VNF archive (.csar) file".getBytes(StandardCharsets.ISO_8859_1);
+        stubFor(get(DOWNLOAD_PATH).willReturn(aResponse().withStatus(200).withBody(body)));
+        VnfPackageRepositoryImpl repository = new VnfPackageRepositoryImpl(config);
+        Response response = repository.downloadVnfPackage(VSP, VERSION, CSAR, USER);
+        assertEquals(200, response.getStatus());
+        assertTrue(Arrays.equals(body, response.readEntity(byte[].class)));
+        assertNotNull(response.getHeaderString("Content-Disposition"));
+        verify(getRequestedFor(urlEqualTo(DOWNLOAD_PATH)));
+    }
+
+    private static class DynamicConfiguration implements VnfPackageRepositoryImpl.Configuration {
+
+        private final int port;
+
+        private DynamicConfiguration(int port) {
+            this.port = port;
+        }
+
+        @Override
+        public String getGetUri() {
+            return toUri(GET_PATH);
+        }
+
+        @Override
+        public String getDownloadUri() {
+            return toUri(DOWNLOAD_PATH);
+        }
+
+        private String toUri(String path) {
+            return "http://localhost:" + port + path;
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/resources/config-vnfrepo.yaml b/openecomp-be/api/openecomp-sdc-rest-webapp/vendor-software-products-rest/vnf-repository-rest-services/src/test/resources/config-vnfrepo.yaml
new file mode 100644 (file)
index 0000000..8057053
--- /dev/null
@@ -0,0 +1,4 @@
+vnfRepoPort: 1111
+vnfRepoHost: 10.57.30.20
+getVnfUri: get-vnf-13
+downloadVnfUri: download-vnf-31
\ No newline at end of file