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.Operation;
27 import io.swagger.v3.oas.annotations.Parameter;
28 import io.swagger.v3.oas.annotations.media.ArraySchema;
29 import io.swagger.v3.oas.annotations.media.Content;
30 import io.swagger.v3.oas.annotations.media.Schema;
31 import io.swagger.v3.oas.annotations.responses.ApiResponse;
32 import io.swagger.v3.oas.annotations.servers.Server;
33 import io.swagger.v3.oas.annotations.servers.Servers;
34 import io.swagger.v3.oas.annotations.tags.Tag;
35 import io.swagger.v3.oas.annotations.tags.Tags;
36 import org.openecomp.sdc.be.components.impl.ArtifactsBusinessLogic;
37 import org.openecomp.sdc.be.components.impl.aaf.AafPermission;
38 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
39 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
40 import org.openecomp.sdc.be.config.BeEcompErrorManager;
41 import org.openecomp.sdc.be.dao.api.ActionStatus;
42 import org.openecomp.sdc.be.impl.ComponentsUtils;
43 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
44 import org.openecomp.sdc.be.servlets.BeGenericServlet;
45 import org.openecomp.sdc.be.user.UserBusinessLogic;
46 import org.openecomp.sdc.common.api.Constants;
47 import org.openecomp.sdc.common.datastructure.Wrapper;
48 import org.openecomp.sdc.common.log.wrappers.Logger;
49 import org.openecomp.sdc.exception.ResponseFormat;
51 import javax.inject.Inject;
52 import javax.inject.Singleton;
53 import javax.servlet.http.HttpServletRequest;
54 import javax.ws.rs.Consumes;
55 import javax.ws.rs.GET;
56 import javax.ws.rs.HeaderParam;
57 import javax.ws.rs.Path;
58 import javax.ws.rs.PathParam;
59 import javax.ws.rs.Produces;
60 import javax.ws.rs.core.Context;
61 import javax.ws.rs.core.MediaType;
62 import javax.ws.rs.core.Response;
63 import java.io.ByteArrayInputStream;
64 import java.io.InputStream;
65 import java.util.HashMap;
69 * This Servlet serves external users to download artifacts.
75 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
77 @Tags({@Tag(name = "SDCE-7 APIs")})
78 @Servers({@Server(url = "/sdc")})
80 public class DistributionCatalogServlet extends BeGenericServlet {
82 private static final String DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION = "download artifact failed with exception";
83 private static final String MISSING_X_ECOMP_INSTANCE_ID_HEADER = "Missing X-ECOMP-InstanceID header";
84 private static final Logger log = Logger.getLogger(DistributionCatalogServlet.class);
85 private final ArtifactsBusinessLogic artifactsBusinessLogic;
88 public DistributionCatalogServlet(UserBusinessLogic userBusinessLogic,
89 ComponentsUtils componentsUtils,
90 ArtifactsBusinessLogic artifactsBusinessLogic) {
91 super(userBusinessLogic, componentsUtils);
92 this.artifactsBusinessLogic = artifactsBusinessLogic;
96 private HttpServletRequest request;
98 // *******************************************************
99 // Download (GET) artifacts
100 // **********************************************************/
104 * @param instanceIdHeader
106 * @param authorization
108 * @param serviceVersion
109 * @param artifactName
113 @Path("/services/{serviceName}/{serviceVersion}/artifacts/{artifactName}")
114 @Consumes(MediaType.APPLICATION_JSON)
115 @Produces(MediaType.APPLICATION_OCTET_STREAM)
116 @Operation(description = "Download service artifact", method = "GET", summary = "Returns downloaded artifact",
117 responses = {@ApiResponse(
118 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
119 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
120 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
121 @ApiResponse(responseCode = "400",
122 description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
123 @ApiResponse(responseCode = "401",
124 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
125 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
126 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
127 @ApiResponse(responseCode = "404",
128 description = "Specified Service Version is not found - SVC4504"),
129 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
130 @ApiResponse(responseCode = "405",
131 description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
132 @ApiResponse(responseCode = "500",
133 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")})
134 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
135 public Response downloadServiceArtifact(
136 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
137 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
138 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
139 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
140 @PathParam("serviceName") final String serviceName,
141 @PathParam("serviceVersion") final String serviceVersion,
142 @PathParam("artifactName") final String artifactName) {
144 String requestURI = request.getRequestURI();
145 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
146 if(!responseWrapper.isEmpty()) {
147 return responseWrapper.getInnerElement();
151 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName);
152 byte[] value = downloadRsrcArtifactEither;
153 InputStream is = new ByteArrayInputStream(value);
155 Map<String, String> headers = new HashMap<>();
156 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
157 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
158 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
159 return buildOkResponse(responseFormat, is, headers);
161 } catch (ComponentException e) {
162 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
163 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download Murano package artifact for service - external API");
164 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
165 return buildErrorResponse(e.getResponseFormat());
169 private Wrapper<Response> validateInstanceIdHeader(Wrapper<Response> responseWrapper, String instanceIdHeader, String requestURI) {
170 if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
171 log.debug(MISSING_X_ECOMP_INSTANCE_ID_HEADER);
172 ResponseFormat errorResponseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
173 getComponentsUtils().auditDistributionDownload(errorResponseFormat, new DistributionData(instanceIdHeader, requestURI));
174 responseWrapper.setInnerElement(buildErrorResponse(errorResponseFormat));
176 return responseWrapper;
182 * @param instanceIdHeader
184 * @param authorization
186 * @param serviceVersion
187 * @param resourceName
188 * @param resourceVersion
189 * @param artifactName
193 @Path("/services/{serviceName}/{serviceVersion}/resources/{resourceName}/{resourceVersion}/artifacts/{artifactName}")
194 @Consumes(MediaType.APPLICATION_JSON)
195 @Produces(MediaType.APPLICATION_OCTET_STREAM)
196 @Operation(description = "Download resource artifact", method = "GET", summary = "Returns downloaded artifact",
197 responses = {@ApiResponse(
198 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
199 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
200 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
201 @ApiResponse(responseCode = "400",
202 description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
203 @ApiResponse(responseCode = "401",
204 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
205 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
206 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
207 @ApiResponse(responseCode = "404",
208 description = "Specified Resource Instance is not found - SVC4526"),
209 @ApiResponse(responseCode = "404",
210 description = "Specified Service Version is not found - SVC4504"),
211 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
212 @ApiResponse(responseCode = "405",
213 description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
214 @ApiResponse(responseCode = "500",
215 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")})
216 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
217 public Response downloadResourceArtifact(
218 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
219 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
220 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
221 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
222 @PathParam("serviceName") final String serviceName,
223 @PathParam("serviceVersion") final String serviceVersion,
224 @PathParam("resourceName") final String resourceName,
225 @PathParam("resourceVersion") final String resourceVersion,
226 @PathParam("artifactName") final String artifactName) {
228 String requestURI = request.getRequestURI();
229 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
231 if(!responseWrapper.isEmpty()) {
232 return responseWrapper.getInnerElement();
236 ArtifactsBusinessLogic artifactsLogic = getArtifactBL(request.getSession().getServletContext());
237 byte[] downloadRsrcArtifactEither = artifactsLogic.downloadRsrcArtifactByNames(serviceName, serviceVersion, resourceName, resourceVersion, artifactName);
238 byte[] value = downloadRsrcArtifactEither;
239 // Returning 64-encoded as it was received during upload
240 InputStream is = new ByteArrayInputStream(value);
241 Map<String, String> headers = new HashMap<>();
242 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
243 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
244 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
245 return buildOkResponse(responseFormat, is, headers);
247 } catch (ComponentException e) {
248 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
249 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
250 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
251 return buildErrorResponse(e.getResponseFormat());
258 * @param instanceIdHeader
260 * @param authorization
262 * @param serviceVersion
263 * @param resourceInstanceName
264 * @param artifactName
268 @Path("/services/{serviceName}/{serviceVersion}/resourceInstances/{resourceInstanceName}/artifacts/{artifactName}")
269 @Consumes(MediaType.APPLICATION_JSON)
270 @Produces(MediaType.APPLICATION_OCTET_STREAM)
271 @Operation(description = "Download resource instance artifact", method = "GET",
272 summary = "Returns downloaded artifact", responses = {
273 @ApiResponse(content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
274 @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.",
275 content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
276 @ApiResponse(responseCode = "400", description = "Missing 'X-ECOMP-InstanceID' HTTP header - POL5001"),
277 @ApiResponse(responseCode = "401",
278 description = "ECOMP component should authenticate itself and to re-send again HTTP request with its Basic Authentication credentials - POL5002"),
279 @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
280 @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
281 @ApiResponse(responseCode = "404", description = "Specified Resource Instance is not found - SVC4526"),
282 @ApiResponse(responseCode = "404", description = "Specified Service Version is not found - SVC4504"),
283 @ApiResponse(responseCode = "404", description = "Specified artifact is not found - SVC4505"),
284 @ApiResponse(responseCode = "405",
285 description = "Method Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
286 @ApiResponse(responseCode = "500",
287 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")})
288 @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
289 public Response downloadResourceInstanceArtifactByName(
290 @Parameter(description = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
291 @Parameter(description = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
292 @Parameter(description = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
293 @Parameter(description = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
294 @PathParam("serviceName") final String serviceName,
295 @PathParam("serviceVersion") final String serviceVersion,
296 @PathParam("resourceInstanceName") final String resourceInstanceName,
297 @PathParam("artifactName") final String artifactName) {
299 String requestURI = request.getRequestURI();
300 Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
302 if(!responseWrapper.isEmpty()) {
303 return responseWrapper.getInnerElement();
307 byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadRsrcInstArtifactByNames(serviceName, serviceVersion, resourceInstanceName, artifactName);
308 byte[] value = downloadRsrcArtifactEither;
309 // Returning 64-encoded as it was received during upload
310 InputStream is = new ByteArrayInputStream(value);
311 Map<String, String> headers = new HashMap<>();
312 headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
313 ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
314 getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
315 return buildOkResponse(responseFormat, is, headers);
317 } catch (ComponentException e) {
318 getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
319 BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
320 log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
321 return buildErrorResponse(e.getResponseFormat());