Catalog alignment
[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
23 package org.openecomp.sdc.be.distribution.servlet;
24
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;
49
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;
65 import java.util.Map;
66
67 /**
68  * This Servlet serves external users to download artifacts.
69  * 
70  * @author tgitelman
71  *
72  */
73
74 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
75 @Path("/v1/catalog")
76 @OpenAPIDefinition(info =  @Info(title = "Distribution Catalog Servlet",description = "This Servlet serves external users to download artifacts."))
77 @Singleton
78 public class DistributionCatalogServlet extends BeGenericServlet {
79
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;
84
85         @Inject
86     public DistributionCatalogServlet(UserBusinessLogic userBusinessLogic,
87         ComponentsUtils componentsUtils,
88         ArtifactsBusinessLogic artifactsBusinessLogic) {
89         super(userBusinessLogic, componentsUtils);
90         this.artifactsBusinessLogic = artifactsBusinessLogic;
91     }
92
93     @Context
94     private HttpServletRequest request;
95
96     // *******************************************************
97     // Download (GET) artifacts
98     // **********************************************************/
99     /**
100      *
101      * @param requestId
102      * @param instanceIdHeader
103      * @param accept
104      * @param authorization
105      * @param serviceName
106      * @param serviceVersion
107      * @param artifactName
108      * @return
109      */
110     @GET
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) {
137
138         String requestURI = request.getRequestURI();
139         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
140         if(!responseWrapper.isEmpty()) {
141             return responseWrapper.getInnerElement();
142         }
143
144         try {
145             byte[] downloadRsrcArtifactEither = artifactsBusinessLogic.downloadServiceArtifactByNames(serviceName, serviceVersion, artifactName);
146             byte[] value = downloadRsrcArtifactEither;
147             InputStream is = new ByteArrayInputStream(value);
148
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);
154
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());
160         }
161     }
162
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));
169         }
170         return responseWrapper;
171     }
172
173     /**
174      *
175      * @param requestId
176      * @param instanceIdHeader
177      * @param accept
178      * @param authorization
179      * @param serviceName
180      * @param serviceVersion
181      * @param resourceName
182      * @param resourceVersion
183      * @param artifactName
184      * @return
185      */
186     @GET
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) {
215
216         String requestURI = request.getRequestURI();
217         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
218
219         if(!responseWrapper.isEmpty()) {
220             return responseWrapper.getInnerElement();
221         }
222
223         try {
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);
234
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());
240         }
241     }
242
243     /**
244      *
245      * @param requestId
246      * @param instanceIdHeader
247      * @param accept
248      * @param authorization
249      * @param serviceName
250      * @param serviceVersion
251      * @param resourceInstanceName
252      * @param artifactName
253      * @return
254      */
255     @GET
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) {
283
284         String requestURI = request.getRequestURI();
285         Wrapper<Response> responseWrapper = validateInstanceIdHeader(new Wrapper<>(), instanceIdHeader, requestURI);
286
287         if(!responseWrapper.isEmpty()) {
288             return responseWrapper.getInnerElement();
289         }
290
291         try {
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);
301
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());
307         }
308     }
309 }