ffe9bb698b668097995b3cbbef0a24a030a454d1
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / distribution / servlet / DistributionCatalogServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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  * ================================================================================
21  */
22 package org.openecomp.sdc.be.distribution.servlet;
23
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;
38 import java.util.Map;
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.aaf.AafPermission;
53 import org.openecomp.sdc.be.components.impl.aaf.PermissionAllowed;
54 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
55 import org.openecomp.sdc.be.config.BeEcompErrorManager;
56 import org.openecomp.sdc.be.dao.api.ActionStatus;
57 import org.openecomp.sdc.be.impl.ComponentsUtils;
58 import org.openecomp.sdc.be.resources.data.auditing.model.DistributionData;
59 import org.openecomp.sdc.be.servlets.BeGenericServlet;
60 import org.openecomp.sdc.common.api.Constants;
61 import org.openecomp.sdc.common.datastructure.Wrapper;
62 import org.openecomp.sdc.common.log.wrappers.Logger;
63 import org.openecomp.sdc.exception.ResponseFormat;
64
65 /**
66  * This Servlet serves external users to download artifacts.
67  *
68  * @author tgitelman
69  */
70 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
71 @Path("/v1/catalog")
72 @Tags({@Tag(name = "SDCE-7 APIs")})
73 @Servers({@Server(url = "/sdc")})
74 @Singleton
75 public class DistributionCatalogServlet extends BeGenericServlet {
76
77     private static final String DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION = "download artifact failed with exception";
78     private static final String MISSING_X_ECOMP_INSTANCE_ID_HEADER = "Missing X-ECOMP-InstanceID header";
79     private static final Logger log = Logger.getLogger(DistributionCatalogServlet.class);
80     private final ArtifactsBusinessLogic artifactsBusinessLogic;
81     @Context
82     private HttpServletRequest request;
83
84     @Inject
85     public DistributionCatalogServlet(ComponentsUtils componentsUtils,
86                                       ArtifactsBusinessLogic artifactsBusinessLogic) {
87         super(componentsUtils);
88         this.artifactsBusinessLogic = artifactsBusinessLogic;
89     }
90     // *******************************************************
91     // Download (GET) artifacts
92     // **********************************************************/
93
94     /**
95      * @param requestId
96      * @param instanceIdHeader
97      * @param accept
98      * @param authorization
99      * @param serviceName
100      * @param serviceVersion
101      * @param artifactName
102      * @return
103      */
104     @GET
105     @Path("/services/{serviceName}/{serviceVersion}/artifacts/{artifactName}")
106     @Consumes(MediaType.APPLICATION_JSON)
107     @Produces(MediaType.APPLICATION_OCTET_STREAM)
108     @Operation(description = "Download service artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
109         @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
110         @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
111         @ApiResponse(responseCode = "400", description = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
112         @ApiResponse(responseCode = "401", description = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic  Authentication credentials - POL5002"),
113         @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
114         @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
115         @ApiResponse(responseCode = "404", description = "Specified Service Version is  not  found - SVC4504"),
116         @ApiResponse(responseCode = "404", description = "Specified artifact is  not found - SVC4505"),
117         @ApiResponse(responseCode = "405", description = "Method  Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
118         @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")})
119     @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
120     public Response downloadServiceArtifact(
121         @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
122         @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
123         @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
124         @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
125         @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
126         @PathParam("artifactName") final String artifactName) {
127         String requestURI = request.getRequestURI();
128         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
129         if (!responseWrapper.isEmpty()) {
130             return responseWrapper.getInnerElement();
131         }
132         try {
133             byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName);
134             byte[] value = downloadRsrcArtifactEither;
135             InputStream is = new ByteArrayInputStream(value);
136             Map<String, String> headers = new HashMap<>();
137             headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
138             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
139             getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
140             return buildOkResponse(responseFormat, is, headers);
141         } catch (ComponentException e) {
142             getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
143             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download Murano package artifact for service - external API");
144             log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
145             return buildErrorResponse(e.getResponseFormat());
146         }
147     }
148
149     private Wrapper<Response> validateInstanceIdHeader(Wrapper<Response> responseWrapper, String instanceIdHeader, String requestURI) {
150         if (instanceIdHeader == null || instanceIdHeader.isEmpty()) {
151             log.debug(MISSING_X_ECOMP_INSTANCE_ID_HEADER);
152             ResponseFormat errorResponseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
153             getComponentsUtils().auditDistributionDownload(errorResponseFormat, new DistributionData(instanceIdHeader, requestURI));
154             responseWrapper.setInnerElement(buildErrorResponse(errorResponseFormat));
155         }
156         return responseWrapper;
157     }
158
159     /**
160      * @param requestId
161      * @param instanceIdHeader
162      * @param accept
163      * @param authorization
164      * @param serviceName
165      * @param serviceVersion
166      * @param resourceName
167      * @param resourceVersion
168      * @param artifactName
169      * @return
170      */
171     @GET
172     @Path("/services/{serviceName}/{serviceVersion}/resources/{resourceName}/{resourceVersion}/artifacts/{artifactName}")
173     @Consumes(MediaType.APPLICATION_JSON)
174     @Produces(MediaType.APPLICATION_OCTET_STREAM)
175     @Operation(description = "Download resource artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
176         @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
177         @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
178         @ApiResponse(responseCode = "400", description = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
179         @ApiResponse(responseCode = "401", description = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic  Authentication credentials - POL5002"),
180         @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
181         @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
182         @ApiResponse(responseCode = "404", description = "Specified Resource Instance  is not found - SVC4526"),
183         @ApiResponse(responseCode = "404", description = "Specified Service Version is  not  found - SVC4504"),
184         @ApiResponse(responseCode = "404", description = "Specified artifact is  not found - SVC4505"),
185         @ApiResponse(responseCode = "405", description = "Method  Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
186         @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")})
187     @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
188     public Response downloadResourceArtifact(
189         @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
190         @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
191         @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
192         @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
193         @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
194         @PathParam("resourceName") final String resourceName, @PathParam("resourceVersion") final String resourceVersion,
195         @PathParam("artifactName") final String artifactName) {
196         String requestURI = request.getRequestURI();
197         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
198         if (!responseWrapper.isEmpty()) {
199             return responseWrapper.getInnerElement();
200         }
201         try {
202             ArtifactsBusinessLogic artifactsLogic = getArtifactBL(request.getSession().getServletContext());
203             byte[] downloadRsrcArtifactEither = artifactsLogic
204                 .downloadRsrcArtifactByNames(serviceName, serviceVersion, resourceName, resourceVersion, artifactName);
205             byte[] value = downloadRsrcArtifactEither;
206             // Returning 64-encoded as it was received during upload
207             InputStream is = new ByteArrayInputStream(value);
208             Map<String, String> headers = new HashMap<>();
209             headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
210             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
211             getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
212             return buildOkResponse(responseFormat, is, headers);
213         } catch (ComponentException e) {
214             getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
215             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
216             log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
217             return buildErrorResponse(e.getResponseFormat());
218         }
219     }
220
221     /**
222      * @param requestId
223      * @param instanceIdHeader
224      * @param accept
225      * @param authorization
226      * @param serviceName
227      * @param serviceVersion
228      * @param resourceInstanceName
229      * @param artifactName
230      * @return
231      */
232     @GET
233     @Path("/services/{serviceName}/{serviceVersion}/resourceInstances/{resourceInstanceName}/artifacts/{artifactName}")
234     @Consumes(MediaType.APPLICATION_JSON)
235     @Produces(MediaType.APPLICATION_OCTET_STREAM)
236     @Operation(description = "Download resource instance artifact", method = "GET", summary = "Returns downloaded artifact", responses = {
237         @ApiResponse(description = "default response", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
238         @ApiResponse(responseCode = "200", description = "The artifact is found and streamed.", content = @Content(array = @ArraySchema(schema = @Schema(implementation = String.class)))),
239         @ApiResponse(responseCode = "400", description = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
240         @ApiResponse(responseCode = "401", description = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic  Authentication credentials - POL5002"),
241         @ApiResponse(responseCode = "403", description = "ECOMP component is not authorized - POL5003"),
242         @ApiResponse(responseCode = "404", description = "Specified Service is not found - SVC4503"),
243         @ApiResponse(responseCode = "404", description = "Specified Resource Instance  is not found - SVC4526"),
244         @ApiResponse(responseCode = "404", description = "Specified Service Version is  not  found - SVC4504"),
245         @ApiResponse(responseCode = "404", description = "Specified artifact is  not found - SVC4505"),
246         @ApiResponse(responseCode = "405", description = "Method  Not Allowed: Invalid HTTP method type used (PUT,DELETE,POST will be rejected) - POL4050"),
247         @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")})
248     @PermissionAllowed({AafPermission.PermNames.READ_VALUE})
249     public Response downloadResourceInstanceArtifactByName(
250         @Parameter(description = "X-ECOMP-RequestID header", required = false) @HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
251         @Parameter(description = "X-ECOMP-InstanceID header", required = true) @HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) final String instanceIdHeader,
252         @Parameter(description = "Determines the format of the body of the response", required = false) @HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
253         @Parameter(description = "The username and password", required = true) @HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
254         @PathParam("serviceName") final String serviceName, @PathParam("serviceVersion") final String serviceVersion,
255         @PathParam("resourceInstanceName") final String resourceInstanceName, @PathParam("artifactName") final String artifactName) {
256         String requestURI = request.getRequestURI();
257         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
258         if (!responseWrapper.isEmpty()) {
259             return responseWrapper.getInnerElement();
260         }
261         try {
262             byte[] downloadRsrcArtifactEither = artifactsBusinessLogic
263                 .downloadRsrcInstArtifactByNames(serviceName, serviceVersion, resourceInstanceName, artifactName);
264             byte[] value = downloadRsrcArtifactEither;
265             // Returning 64-encoded as it was received during upload
266             InputStream is = new ByteArrayInputStream(value);
267             Map<String, String> headers = new HashMap<>();
268             headers.put(Constants.CONTENT_DISPOSITION_HEADER, getContentDispositionValue(artifactName));
269             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
270             getComponentsUtils().auditDistributionDownload(responseFormat, new DistributionData(instanceIdHeader, requestURI));
271             return buildOkResponse(responseFormat, is, headers);
272         } catch (ComponentException e) {
273             getComponentsUtils().auditDistributionDownload(e.getResponseFormat(), new DistributionData(instanceIdHeader, requestURI));
274             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("download interface artifact for resource - external API");
275             log.debug(DOWNLOAD_ARTIFACT_FAILED_WITH_EXCEPTION, e);
276             return buildErrorResponse(e.getResponseFormat());
277         }
278     }
279 }