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 * ================================================================================
23 package org.openecomp.sdc.be.distribution.servlet;
25 import com.jcabi.aspects.Loggable;
26 import io.swagger.v3.oas.annotations.OpenAPIDefinition;
27 import io.swagger.v3.oas.annotations.Operation;
28 import io.swagger.v3.oas.annotations.Parameter;
29 import io.swagger.v3.oas.annotations.info.Info;
30 import io.swagger.v3.oas.annotations.media.ArraySchema;
31 import io.swagger.v3.oas.annotations.media.Content;
32 import io.swagger.v3.oas.annotations.media.Schema;
33 import io.swagger.v3.oas.annotations.responses.ApiResponse;
34 import io.swagger.v3.oas.annotations.responses.ApiResponses;
35 import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic;
36 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
37 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
38 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
39 import org.openecomp.sdc.be.config.BeEcompErrorManager;
40 import org.openecomp.sdc.be.dao.api.ActionStatus;
41 import org.openecomp.sdc.be.impl.ComponentsUtils;
42 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
43 import org.openecomp.sdc.be.servlets.BeGenericServlet;
44 import org.openecomp.sdc.be.user.UserBusinessLogic;
45 import org.openecomp.sdc.common.api.Constants;
46 import org.openecomp.sdc.common.datastructure.Wrapper;
47 import org.openecomp.sdc.common.log.wrappers.Logger;
48 import org.openecomp.sdc.exception.ResponseFormat;
50 import javax.inject.Inject;
51 import javax.inject.Singleton;
52 import javax.servlet.http.HttpServletRequest;
53 import javax.ws.rs.Consumes;
54 import javax.ws.rs.GET;
55 import javax.ws.rs.HeaderParam;
56 import javax.ws.rs.Path;
57 import javax.ws.rs.PathParam;
58 import javax.ws.rs.Produces;
59 import javax.ws.rs.core.Context;
60 import javax.ws.rs.core.MediaType;
61 import javax.ws.rs.core.Response;
62 import java.io.ByteArrayInputStream;
63 import java.io.InputStream;
64 import java.util.HashMap;
68 * This Servlet serves external users to download artifacts.
74 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
76 @OpenAPIDefinition(info = @Info(title = "Distribution Catalog Servlet",description = "This Servlet serves external users to download artifacts."))
78 public class DistributionCatalogServlet extends BeGenericServlet {
80 private static final String DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION = "download artifact failed with exception";
81 private static final String MISSING_X_ECOMP_INSTANCE_ID_HEADER = "Missing X-ECOMP-InstanceID header";
82 private static final Logger log = Logger.getLogger(DistributionCatalogServlet.class);
83 private final ArtifactsBusinessLogic artifactsBusinessLogic;
86 public DistributionCatalogServlet(UserBusinessLogic userBusinessLogic,
87 ComponentsUtils componentsUtils,
88 ArtifactsBusinessLogic artifactsBusinessLogic) {
89 super(userBusinessLogic, componentsUtils);
90 this.artifactsBusinessLogic = artifactsBusinessLogic;
94 private HttpServletRequest request;
96 // *******************************************************
97 // Download (GET) artifacts
98 // **********************************************************/
102 * @param instanceIdHeader
104 * @param authorization
106 * @param serviceVersion
107 * @param artifactName
111 @Path("/services/{serviceName}/{serviceVersion}/artifacts/{artifactName}")
112 @Consumes(MediaType.APPLICATION_JSON)
113 @Produces(MediaType.APPLICATION_OCTET_STREAM)
114 @Operation(description = "Download service artifact", method = "GET", summary = "Returns downloaded artifact",
115 responses = @ApiResponse(
116 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))))
117 @ApiResponses(value = {
118 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
119 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
120 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
121 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
122 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
123 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
124 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
125 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
126 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
127 @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")})
128 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
129 public Response downloadServiceArtifact(
130 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
131 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
132 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
133 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
134 @PathParam("serviceName") final String serviceName,
135 @PathParam("serviceVersion") final String serviceVersion,
136 @PathParam("artifactName") final String artifactName) {
138 String requestURI = request.getRequestURI();
139 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
140 if(!responseWrapper.isEmpty()) {
141 return responseWrapper.getInnerElement();
145 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName);
146 byte[] value = downloadRsrcArtifactEither;
147 InputStream is = new ByteArrayInputStream(value);
149 Map<String, String> headers = new HashMap<>();
150 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
151 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
152 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
153 return buildOkResponse(responseFormat, is, headers);
155 } catch (ComponentException e) {
156 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
157 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download Murano package artifact for service - external API");
158 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
159 return buildErrorResponse(e.getResponseFormat());
163 private Wrapper<Response> validateInstanceIdHeader(Wrapper<Response> responseWrapper, String instanceIdHeader, String requestURI) {
164 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
165 log.debug(MISSING_X_ECOMP_INSTANCE_ID_HEADER);
166 ResponseFormat errorResponseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
167 getComponentsUtils().auditDistributionDownload(errorResponseFormat, new DistributionData(instanceIdHeader, requestURI));
168 responseWrapper.setInnerElement(buildErrorResponse(errorResponseFormat));
170 return responseWrapper;
176 * @param instanceIdHeader
178 * @param authorization
180 * @param serviceVersion
181 * @param resourceName
182 * @param resourceVersion
183 * @param artifactName
187 @Path("/services/{serviceName}/{serviceVersion}/resources/{resourceName}/{resourceVersion}/artifacts/{artifactName}")
188 @Consumes(MediaType.APPLICATION_JSON)
189 @Produces(MediaType.APPLICATION_OCTET_STREAM)
190 @Operation(description = "Download resource artifact", method = "GET", summary = "Returns downloaded artifact", responses = @ApiResponse(
191 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))))
192 @ApiResponses(value = {
193 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
194 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
195 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
196 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
197 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
198 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
199 @ApiResponse(responseCode = "404", description = "Specified Resource Instance is not found - SVC4526"),
200 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
201 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
202 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
203 @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")})
204 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
205 public Response downloadResourceArtifact(
206 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
207 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
208 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
209 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
210 @PathParam("serviceName") final String serviceName,
211 @PathParam("serviceVersion") final String serviceVersion,
212 @PathParam("resourceName") final String resourceName,
213 @PathParam("resourceVersion") final String resourceVersion,
214 @PathParam("artifactName") final String artifactName) {
216 String requestURI = request.getRequestURI();
217 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
219 if(!responseWrapper.isEmpty()) {
220 return responseWrapper.getInnerElement();
224 ArtifactsBusinessLogic artifactsLogic = getArtifactBL(request.getSession().getServletContext());
225 byte[] downloadRsrcArtifactEither = artifactsLogic.downloadRsrcArtifactByNames(serviceName, serviceVersion, resourceName, resourceVersion, artifactName);
226 byte[] value = downloadRsrcArtifactEither;
227 // Returning 64-encoded as it was received during upload
228 InputStream is = new ByteArrayInputStream(value);
229 Map<String, String> headers = new HashMap<>();
230 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
231 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
232 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
233 return buildOkResponse(responseFormat, is, headers);
235 } catch (ComponentException e) {
236 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
237 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
238 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
239 return buildErrorResponse(e.getResponseFormat());
246 * @param instanceIdHeader
248 * @param authorization
250 * @param serviceVersion
251 * @param resourceInstanceName
252 * @param artifactName
256 @Path("/services/{serviceName}/{serviceVersion}/resourceInstances/{resourceInstanceName}/artifacts/{artifactName}")
257 @Consumes(MediaType.APPLICATION_JSON)
258 @Produces(MediaType.APPLICATION_OCTET_STREAM)
259 @Operation(description = "Download resource instance artifact", method = "GET", summary = "Returns downloaded artifact", responses = @ApiResponse(
260 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))))
261 @ApiResponses(value = {
262 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
263 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
264 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
265 @ApiResponse(responseCode = "401", description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
266 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
267 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
268 @ApiResponse(responseCode = "404", description = "Specified Resource Instance is not found - SVC4526"),
269 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
270 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
271 @ApiResponse(responseCode = "405", description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
272 @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")})
273 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
274 public Response downloadResourceInstanceArtifactByName(
275 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
276 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
277 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
278 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
279 @PathParam("serviceName") final String serviceName,
280 @PathParam("serviceVersion") final String serviceVersion,
281 @PathParam("resourceInstanceName") final String resourceInstanceName,
282 @PathParam("artifactName") final String artifactName) {
284 String requestURI = request.getRequestURI();
285 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
287 if(!responseWrapper.isEmpty()) {
288 return responseWrapper.getInnerElement();
292 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadRsrcInstArtifactByNames(serviceName, serviceVersion, resourceInstanceName, artifactName);
293 byte[] value = downloadRsrcArtifactEither;
294 // Returning 64-encoded as it was received during upload
295 InputStream is = new ByteArrayInputStream(value);
296 Map<String, String> headers = new HashMap<>();
297 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
298 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
299 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
300 return buildOkResponse(responseFormat, is, headers);
302 } catch (ComponentException e) {
303 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
304 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
305 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
306 return buildErrorResponse(e.getResponseFormat());