2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
19 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
22 package org.openecomp.sdc.be.distribution.servlet;
24 import com.jcabi.aspects.Loggable;
25 import io.swagger.v3.oas.annotations.Operation;
26 import io.swagger.v3.oas.annotations.Parameter;
27 import io.swagger.v3.oas.annotations.media.ArraySchema;
28 import io.swagger.v3.oas.annotations.media.Content;
29 import io.swagger.v3.oas.annotations.media.Schema;
30 import io.swagger.v3.oas.annotations.responses.ApiResponse;
31 import io.swagger.v3.oas.annotations.servers.Server;
32 import io.swagger.v3.oas.annotations.servers.Servers;
33 import io.swagger.v3.oas.annotations.tags.Tag;
34 import io.swagger.v3.oas.annotations.tags.Tags;
35 import java.io.ByteArrayInputStream;
36 import java.io.InputStream;
37 import java.util.HashMap;
39 import javax.inject.Inject;
40 import javax.inject.Singleton;
41 import javax.servlet.http.HttpServletRequest;
42 import javax.ws.rs.Consumes;
43 import javax.ws.rs.GET;
44 import javax.ws.rs.HeaderParam;
45 import javax.ws.rs.Path;
46 import javax.ws.rs.PathParam;
47 import javax.ws.rs.Produces;
48 import javax.ws.rs.core.Context;
49 import javax.ws.rs.core.MediaType;
50 import javax.ws.rs.core.Response;
51 import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic;
52 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
53 import org.openecomp.sdc.be.config.BeEcompErrorManager;
54 import org.openecomp.sdc.be.dao.api.ActionStatus;
55 import org.openecomp.sdc.be.impl.ComponentsUtils;
56 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
57 import org.openecomp.sdc.be.servlets.BeGenericServlet;
58 import org.openecomp.sdc.common.api.Constants;
59 import org.openecomp.sdc.common.datastructure.Wrapper;
60 import org.openecomp.sdc.common.log.wrappers.Logger;
61 import org.openecomp.sdc.exception.ResponseFormat;
64 * This Servlet serves external users to download artifacts.
68 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
70 @Tags({@Tag(name = "SDCE-7 APIs")})
71 @Servers({@Server(url = "/sdc")})
73 public class DistributionCatalogServlet extends BeGenericServlet {
75 private static final String DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION = "download artifact failed with exception";
76 private static final String MISSING_X_ECOMP_INSTANCE_ID_HEADER = "Missing X-ECOMP-InstanceID header";
77 private static final Logger log = Logger.getLogger(DistributionCatalogServlet.class);
78 private final ArtifactsBusinessLogic artifactsBusinessLogic;
80 private HttpServletRequest request;
83 public DistributionCatalogServlet(ComponentsUtils componentsUtils,
84 ArtifactsBusinessLogic artifactsBusinessLogic) {
85 super(componentsUtils);
86 this.artifactsBusinessLogic = artifactsBusinessLogic;
88 // *******************************************************
89 // Download (GET) artifacts
90 // **********************************************************/
94 * @param instanceIdHeader
96 * @param authorization
98 * @param serviceVersion
103 @Path("/services/{serviceName}/{serviceVersion}/artifacts/{artifactName}")
104 @Consumes(MediaType.APPLICATION_JSON)
105 @Produces(MediaType.APPLICATION_OCTET_STREAM)
106 @Operation(description = "Download service artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
107 @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
108 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
109 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
110 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
111 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
112 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
113 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
114 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
115 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
116 @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem or Cambria Service failure. ECOMP Component should continue the attempts to get the needed information - POL5000")})
117 public Response downloadServiceArtifact(
118 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
119 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
120 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
121 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
122 @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
123 @PathParam("artifactName") final String artifactName) {
124 String requestURI = request.getRequestURI();
125 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
126 if (!responseWrapper.isEmpty()) {
127 return responseWrapper.getInnerElement();
130 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName);
131 byte[] value = downloadRsrcArtifactEither;
132 InputStream is = new ByteArrayInputStream(value);
133 Map<String, String> headers = new HashMap<>();
134 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
135 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
136 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
137 return buildOkResponse(responseFormat, is, headers);
138 } catch (ComponentException e) {
139 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
140 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download Murano package artifact for service - external API");
141 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
142 return buildErrorResponse(e.getResponseFormat());
146 private Wrapper<Response> validateInstanceIdHeader(Wrapper<Response> responseWrapper, String instanceIdHeader, String requestURI) {
147 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
148 log.debug(MISSING_X_ECOMP_INSTANCE_ID_HEADER);
149 ResponseFormat errorResponseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
150 getComponentsUtils().auditDistributionDownload(errorResponseFormat, new DistributionData(instanceIdHeader, requestURI));
151 responseWrapper.setInnerElement(buildErrorResponse(errorResponseFormat));
153 return responseWrapper;
158 * @param instanceIdHeader
160 * @param authorization
162 * @param serviceVersion
163 * @param resourceName
164 * @param resourceVersion
165 * @param artifactName
169 @Path("/services/{serviceName}/{serviceVersion}/resources/{resourceName}/{resourceVersion}/artifacts/{artifactName}")
170 @Consumes(MediaType.APPLICATION_JSON)
171 @Produces(MediaType.APPLICATION_OCTET_STREAM)
172 @Operation(description = "Download resource artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
173 @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
174 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
175 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
176 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
177 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
178 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
179 @ApiResponse(responseCode = "404", description = "Specified Resource Instance is not found - SVC4526"),
180 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
181 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
182 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
183 @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem or Cambria Service failure. ECOMP Component should continue the attempts to get the needed information - POL5000")})
184 public Response downloadResourceArtifact(
185 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
186 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
187 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
188 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
189 @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
190 @PathParam("resourceName") final String resourceName, @PathParam("resourceVersion") final String resourceVersion,
191 @PathParam("artifactName") final String artifactName) {
192 String requestURI = request.getRequestURI();
193 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
194 if (!responseWrapper.isEmpty()) {
195 return responseWrapper.getInnerElement();
198 ArtifactsBusinessLogic artifactsLogic = getArtifactBL(request.getSession().getServletContext());
199 byte[] downloadRsrcArtifactEither = artifactsLogic
200 .downloadRsrcArtifactByNames(serviceName, serviceVersion, resourceName, resourceVersion, artifactName);
201 byte[] value = downloadRsrcArtifactEither;
202 // Returning 64-encoded as it was received during upload
203 InputStream is = new ByteArrayInputStream(value);
204 Map<String, String> headers = new HashMap<>();
205 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
206 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
207 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
208 return buildOkResponse(responseFormat, is, headers);
209 } catch (ComponentException e) {
210 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
211 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
212 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
213 return buildErrorResponse(e.getResponseFormat());
219 * @param instanceIdHeader
221 * @param authorization
223 * @param serviceVersion
224 * @param resourceInstanceName
225 * @param artifactName
229 @Path("/services/{serviceName}/{serviceVersion}/resourceInstances/{resourceInstanceName}/artifacts/{artifactName}")
230 @Consumes(MediaType.APPLICATION_JSON)
231 @Produces(MediaType.APPLICATION_OCTET_STREAM)
232 @Operation(description = "Download resource instance artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
233 @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
234 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
235 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
236 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
237 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
238 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
239 @ApiResponse(responseCode = "404", description = "Specified Resource Instance is not found - SVC4526"),
240 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
241 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
242 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
243 @ApiResponse(responseCode = "500", description = "The GET request failed either due to internal SDC problem or Cambria Service failure. ECOMP Component should continue the attempts to get the needed information - POL5000")})
244 public Response downloadResourceInstanceArtifactByName(
245 @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
246 @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
247 @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
248 @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
249 @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
250 @PathParam("resourceInstanceName") final String resourceInstanceName, @PathParam("artifactName") final String artifactName) {
251 String requestURI = request.getRequestURI();
252 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
253 if (!responseWrapper.isEmpty()) {
254 return responseWrapper.getInnerElement();
257 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic
258 .downloadRsrcInstArtifactByNames(serviceName, serviceVersion, resourceInstanceName, artifactName);
259 byte[] value = downloadRsrcArtifactEither;
260 // Returning 64-encoded as it was received during upload
261 InputStream is = new ByteArrayInputStream(value);
262 Map<String, String> headers = new HashMap<>();
263 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
264 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
265 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
266 return buildOkResponse(responseFormat, is, headers);
267 } catch (ComponentException e) {
268 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
269 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
270 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
271 return buildErrorResponse(e.getResponseFormat());