2 * Copyright 2017 Huawei Technologies Co., Ltd.
3 * Modifications Copyright 2018 European Support Limited
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
18 package org.openecomp.sdcrests.vsp.rest.services;
20 import static javax.ws.rs.core.HttpHeaders.CONTENT_DISPOSITION;
21 import static org.openecomp.core.utilities.file.FileUtils.getFileExtension;
22 import static org.openecomp.core.utilities.file.FileUtils.getNetworkPackageName;
24 import java.io.BufferedInputStream;
25 import java.io.ByteArrayInputStream;
26 import java.io.InputStream;
28 import java.nio.charset.StandardCharsets;
29 import java.util.List;
31 import java.util.Objects;
32 import java.util.Optional;
33 import javax.inject.Named;
34 import javax.net.ssl.HostnameVerifier;
35 import javax.net.ssl.SSLContext;
36 import javax.ws.rs.client.Client;
37 import javax.ws.rs.client.ClientBuilder;
38 import javax.ws.rs.client.Invocation;
39 import javax.ws.rs.client.WebTarget;
40 import javax.ws.rs.core.Link;
41 import javax.ws.rs.core.Response;
42 import javax.ws.rs.core.UriBuilder;
43 import org.onap.config.api.ConfigurationManager;
44 import org.openecomp.sdc.common.errors.CoreException;
45 import org.openecomp.sdc.common.errors.ErrorCode;
46 import org.openecomp.sdc.common.errors.ErrorCodeAndMessage;
47 import org.openecomp.sdc.common.errors.GeneralErrorBuilder;
48 import org.openecomp.sdc.logging.api.Logger;
49 import org.openecomp.sdc.logging.api.LoggerFactory;
50 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManager;
51 import org.openecomp.sdc.vendorsoftwareproduct.OrchestrationTemplateCandidateManagerFactory;
52 import org.openecomp.sdc.vendorsoftwareproduct.types.UploadFileResponse;
53 import org.openecomp.sdc.versioning.VersioningManager;
54 import org.openecomp.sdc.versioning.VersioningManagerFactory;
55 import org.openecomp.sdc.versioning.dao.types.Version;
56 import org.openecomp.sdcrests.vendorsoftwareproducts.types.UploadFileResponseDto;
57 import org.openecomp.sdcrests.vsp.rest.VnfPackageRepository;
58 import org.openecomp.sdcrests.vsp.rest.mapping.MapUploadFileResponseToUploadFileResponseDto;
59 import org.springframework.context.annotation.Scope;
60 import org.springframework.stereotype.Service;
63 * Enables integration API interface with VNF Repository (VNFSDK).
65 * <li>Get all the VNF Package Meta-data.</li>
66 * <li>Download a VNF Package.</li>
67 * <li>Import a VNF package to SDC catalog (Download & validate).</li>
70 * @version Amsterdam release (ONAP 1.0)
73 @Service("vnfPackageRepository")
74 @Scope(value = "prototype")
75 public class VnfPackageRepositoryImpl implements VnfPackageRepository {
77 private static final Logger LOGGER = LoggerFactory.getLogger(VnfPackageRepositoryImpl.class);
79 private final Configuration config;
81 public VnfPackageRepositoryImpl(Configuration config) {
85 public VnfPackageRepositoryImpl() {
86 this(new FileConfiguration());
90 public Response getVnfPackages(String vspId, String versionId, String user) {
92 LOGGER.debug("Get VNF Packages from Repository: {}", vspId);
94 Client client = new SharedClient();
96 final String getVnfPackageUri = config.getGetUri();
100 Response remoteResponse = client.target(getVnfPackageUri).request().get();
101 if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
102 return handleUnexpectedStatus("querying VNF package metadata", getVnfPackageUri, remoteResponse);
105 LOGGER.debug("Response from VNF Repository: {}", remoteResponse);
106 return Response.ok(remoteResponse.readEntity(String.class)).build();
114 public Response importVnfPackage(String vspId, String versionId, String csarId, String user) {
116 LOGGER.debug("Import VNF Packages from Repository: {}", csarId);
118 final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
120 Client client = new SharedClient();
124 Response remoteResponse = client.target(downloadPackageUri).request().get();
125 if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
126 return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
129 LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
130 byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
131 return uploadVnfPackage(vspId, versionId, csarId, payload);
138 private Response uploadVnfPackage(String vspId, String versionId, String csarId, byte[] payload) {
140 try (InputStream fileStream = new BufferedInputStream(new ByteArrayInputStream(payload))) {
142 OrchestrationTemplateCandidateManager candidateManager =
143 OrchestrationTemplateCandidateManagerFactory.getInstance().createInterface();
145 String filename = formatFilename(csarId);
146 Version version = getVersion(vspId, versionId);
147 UploadFileResponse response = candidateManager.upload(vspId, version, fileStream,
148 getFileExtension(filename), getNetworkPackageName(filename));
150 UploadFileResponseDto uploadFileResponse = new MapUploadFileResponseToUploadFileResponseDto()
151 .applyMapping(response, UploadFileResponseDto.class);
153 return Response.ok(uploadFileResponse).build();
155 } catch (Exception e) {
156 ErrorCode error = new GeneralErrorBuilder().build();
157 LOGGER.error("Exception while uploading package received from VNF Repository", new CoreException(error, e));
158 return generateInternalServerError(error);
163 public Response downloadVnfPackage(String vspId, String versionId, String csarId, String user) {
165 LOGGER.debug("Download VNF package from repository: csarId={}", csarId);
167 final String downloadPackageUri = String.format(config.getDownloadUri(), csarId);
169 Client client = new SharedClient();
173 Response remoteResponse = client.target(downloadPackageUri).request().get();
174 if (remoteResponse.getStatus() != Response.Status.OK.getStatusCode()) {
175 return handleUnexpectedStatus("downloading VNF package", downloadPackageUri, remoteResponse);
178 byte[] payload = remoteResponse.readEntity(String.class).getBytes(StandardCharsets.ISO_8859_1);
179 Response.ResponseBuilder response = Response.ok(payload);
180 response.header(CONTENT_DISPOSITION, "attachment; filename=" + formatFilename(csarId));
182 LOGGER.debug("Response from VNF Repository for download package is success. URI={}", downloadPackageUri);
183 return response.build();
190 private Version getVersion(String vspId, String versionId) {
191 VersioningManager versioningManager = VersioningManagerFactory.getInstance().createInterface();
192 return findVersion(versioningManager.list(vspId), versionId).orElse(new Version(versionId));
195 Optional<Version> findVersion(List<Version> versions, String requestedVersion) {
196 return versions.stream().filter(ver -> Objects.equals(ver.getId(), requestedVersion)).findAny();
199 private static Response handleUnexpectedStatus(String action, String uri, Response response) {
200 ErrorCode error = new GeneralErrorBuilder().build();
201 LOGGER.error("Unexpected response status while {}: URI={}, Response={}", action, uri, response,
202 new CoreException(error));
203 return generateInternalServerError(error);
206 private static Response generateInternalServerError(ErrorCode error) {
207 ErrorCodeAndMessage payload = new ErrorCodeAndMessage(Response.Status.INTERNAL_SERVER_ERROR, error);
208 return Response.serverError().entity(payload).build();
211 private static String formatFilename(String csarId) {
212 return "temp_" + csarId + ".csar";
215 interface Configuration {
219 String getDownloadUri();
222 private static class SharedClient implements Client {
224 private static final Client CLIENT = ClientBuilder.newClient();
227 public void close() {
228 // do not close the shared client
232 public WebTarget target(String uri) {
233 return CLIENT.target(uri);
237 public WebTarget target(URI uri) {
238 return CLIENT.target(uri);
242 public WebTarget target(UriBuilder uriBuilder) {
243 return CLIENT.target(uriBuilder);
247 public WebTarget target(Link link) {
248 return CLIENT.target(link);
252 public Invocation.Builder invocation(Link link) {
253 return CLIENT.invocation(link);
257 public SSLContext getSslContext() {
258 return CLIENT.getSslContext();
262 public HostnameVerifier getHostnameVerifier() {
263 return CLIENT.getHostnameVerifier();
267 public javax.ws.rs.core.Configuration getConfiguration() {
268 return CLIENT.getConfiguration();
272 public Client property(String name, Object value) {
273 return CLIENT.property(name, value);
277 public Client register(Class<?> componentClass) {
278 return CLIENT.register(componentClass);
282 public Client register(Class<?> componentClass, int priority) {
283 return CLIENT.register(componentClass, priority);
287 public Client register(Class<?> componentClass, Class<?>... contracts) {
288 return CLIENT.register(componentClass, contracts);
292 public Client register(Class<?> componentClass, Map<Class<?>, Integer> contracts) {
293 return CLIENT.register(componentClass, contracts);
297 public Client register(Object component) {
298 return CLIENT.register(component);
302 public Client register(Object component, int priority) {
303 return CLIENT.register(component, priority);
307 public Client register(Object component, Class<?>... contracts) {
308 return CLIENT.register(component, contracts);
312 public Client register(Object component, Map<Class<?>, Integer> contracts) {
313 return CLIENT.register(component, contracts);
317 static class FileConfiguration implements Configuration {
320 public String getGetUri() {
321 return LazyFileConfiguration.INSTANCE.getGetUri();
325 public String getDownloadUri() {
326 return LazyFileConfiguration.INSTANCE.getDownloadUri();
329 private static class LazyFileConfiguration implements Configuration {
331 private static final String CONFIG_NAMESPACE = "vnfrepo";
333 private static final String DEFAULT_HOST = "localhost";
334 private static final String DEFAULT_PORT = "8702";
336 private static final String DEFAULT_URI_PREFIX = "/onapapi/vnfsdk-marketplace/v1/PackageResource/csars";
337 private static final String DEFAULT_LIST_URI = DEFAULT_URI_PREFIX + "/";
338 private static final String DEFAULT_DOWNLOAD_URI = DEFAULT_URI_PREFIX + "/%s/files";
340 private static final LazyFileConfiguration INSTANCE = new LazyFileConfiguration();
342 private final String getUri;
343 private final String downloadUri;
345 private LazyFileConfiguration() {
346 org.onap.config.api.Configuration config = ConfigurationManager.lookup();
347 String host = readConfig(config, "vnfRepoHost", DEFAULT_HOST);
348 String port = readConfig(config, "vnfRepoPort", DEFAULT_PORT);
349 String listPackagesUri = readConfig(config, "getVnfUri", DEFAULT_LIST_URI);
350 String downloadPackageUri = readConfig(config, "downloadVnfUri", DEFAULT_DOWNLOAD_URI);
351 this.getUri = formatUri(host, port, listPackagesUri);
352 this.downloadUri = formatUri(host, port, downloadPackageUri);
355 private String readConfig(org.onap.config.api.Configuration config, String key, String defaultValue) {
358 String value = config.getAsString(CONFIG_NAMESPACE, key);
359 return (value == null) ? defaultValue : value;
360 } catch (Exception e) {
362 "Failed to read VNF repository configuration key '{}', default value '{}' will be used",
363 key, defaultValue, e);
368 private static String formatUri(String host, String port, String path) {
369 return "http://" + host + ":" + port + (path.startsWith("/") ? path : "/" + path);
372 public String getGetUri() {
376 public String getDownloadUri() {