catalog-be servlets refactoring
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / distribution / servlet / DistributionServlet.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  */
20
21 package org.openecomp.sdc.be.distribution.servlet;
22
23 import com.jcabi.aspects.Loggable;
24 import fj.data.Either;
25 import io.swagger.annotations.*;
26 import javax.inject.Inject;
27 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
28 import org.openecomp.sdc.be.components.impl.GroupBusinessLogic;
29 import org.openecomp.sdc.be.config.BeEcompErrorManager;
30 import org.openecomp.sdc.be.dao.api.ActionStatus;
31 import org.openecomp.sdc.be.distribution.AuditHandler;
32 import org.openecomp.sdc.be.distribution.DistributionBusinessLogic;
33 import org.openecomp.sdc.be.distribution.api.client.RegistrationRequest;
34 import org.openecomp.sdc.be.distribution.api.client.ServerListResponse;
35 import org.openecomp.sdc.be.distribution.api.client.TopicRegistrationResponse;
36 import org.openecomp.sdc.be.distribution.api.client.TopicUnregistrationResponse;
37 import org.openecomp.sdc.be.impl.ComponentsUtils;
38 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
39 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
40 import org.openecomp.sdc.be.servlets.BeGenericServlet;
41 import org.openecomp.sdc.be.user.UserBusinessLogic;
42 import org.openecomp.sdc.common.api.ArtifactTypeEnum;
43 import org.openecomp.sdc.common.api.Constants;
44 import org.openecomp.sdc.common.datastructure.Wrapper;
45 import org.openecomp.sdc.common.log.wrappers.Logger;
46 import org.openecomp.sdc.common.util.HttpUtil;
47 import org.openecomp.sdc.exception.ResponseFormat;
48
49 import javax.inject.Singleton;
50 import javax.servlet.http.HttpServletRequest;
51 import javax.ws.rs.*;
52 import javax.ws.rs.core.Context;
53 import javax.ws.rs.core.MediaType;
54 import javax.ws.rs.core.Response;
55
56 /**
57  * This Servlet serves external users for distribution purposes.
58  * 
59  * @author tgitelman
60  *
61  */
62
63 @Loggable(prepend = true, value = Loggable.DEBUG, trim = false)
64 @Path("/v1")
65 @Api(value = "Distribution Servlet", description = "This Servlet serves external users for distribution purposes.")
66 @Singleton
67 public class DistributionServlet extends BeGenericServlet {
68
69     private static final String START_HANDLE_REQUEST_OF = "Start handle request of {}";
70         private static final Logger log = Logger.getLogger(DistributionServlet.class);
71     private final DistributionBusinessLogic distributionLogic;
72     @Context
73     private HttpServletRequest request;
74
75     @Inject
76     public DistributionServlet(UserBusinessLogic userBusinessLogic,
77         ComponentsUtils componentsUtils, DistributionBusinessLogic distributionLogic) {
78         super(userBusinessLogic, componentsUtils);
79         this.distributionLogic = distributionLogic;
80     }
81
82     /**
83      *
84      * @param requestId
85      * @param instanceId
86      * @param accept
87      * @param authorization
88      * @return
89      */
90     @GET
91     @Path("/distributionUebCluster")
92     @Consumes(MediaType.APPLICATION_JSON)
93     @Produces(MediaType.APPLICATION_JSON)
94     @ApiOperation(value = "UEB Server List", httpMethod = "GET", notes = "return the available UEB Server List",
95     //TODO Tal G fix response headers
96     responseHeaders = {
97             @ResponseHeader(name = Constants.CONTENT_TYPE_HEADER, description = "Determines the format of the response body", response = String.class),
98             @ResponseHeader(name = "Content-Length", description = "Length of  the response body", response = String.class)})
99     @ApiResponses(value = {
100             @ApiResponse(code = 200, message = "ECOMP component is authenticated and list of Cambria API server’s FQDNs is returned", response = ServerListResponse.class),
101             @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
102             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its credentials  for  Basic Authentication - POL5002"),
103             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
104             @ApiResponse(code = 405, message = "Method  Not Allowed: Invalid HTTP method type used ( PUT,DELETE,POST will be rejected) - POL4050"),
105             @ApiResponse(code = 500, message = "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")})
106     public Response getUebServerList(
107             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
108             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId,
109             @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
110             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization) {
111
112         String url = request.getMethod() + " " + request.getRequestURI();
113         log.debug(START_HANDLE_REQUEST_OF, url);
114         Response response = null;
115         ResponseFormat responseFormat = null;
116
117         if (instanceId == null) {
118             responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
119             response = buildErrorResponse(responseFormat);
120             getComponentsUtils().auditGetUebCluster(null, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage());
121             return response;
122         }
123
124         try {
125             Either<ServerListResponse, ResponseFormat> actionResponse = distributionLogic.getUebServerList();
126
127             if (actionResponse.isRight()) {
128                 responseFormat = actionResponse.right().value();
129                 response = buildErrorResponse(responseFormat);
130             } else {
131                 responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.OK);
132                 response = buildOkResponse(responseFormat, actionResponse.left().value());
133             }
134
135             getComponentsUtils().auditGetUebCluster(instanceId, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage());
136             return response;
137
138         } catch (Exception e) {
139             BeEcompErrorManager.getInstance().logBeRestApiGeneralError("failed to get ueb serbver list from cofiguration");
140             log.debug("failed to get ueb serbver list from cofiguration", e);
141             responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.GENERAL_ERROR);
142             getComponentsUtils().auditGetUebCluster(instanceId, responseFormat.getStatus().toString(), responseFormat.getFormattedMessage());
143             response = buildErrorResponse(responseFormat);
144             return response;
145         }
146
147     }
148
149     /**
150      *
151      * @param requestId
152      * @param instanceId
153      * @param accept
154      * @param contentType
155      * @param contenLength
156      * @param authorization
157      * @param requestJson
158      * @return
159      */
160     @POST
161     @Path("/registerForDistribution")
162     @Consumes(MediaType.APPLICATION_JSON)
163     @Produces(MediaType.APPLICATION_JSON)
164     @ApiOperation(value = "Subscription status", httpMethod = "POST", notes = "Subscribes for distribution notifications")
165     @ApiResponses(value = {
166             @ApiResponse(code = 200, message = "ECOMP component is successfully registered for distribution", response = TopicRegistrationResponse.class),
167             @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
168             @ApiResponse(code = 400, message = "Missing  Body - POL4500"),
169             @ApiResponse(code = 400, message = "Invalid  Body  : missing mandatory parameter 'apiPublicKey' - POL4501"),
170             @ApiResponse(code = 400, message = "Invalid  Body  : missing mandatory parameter 'distrEnvName' - POL4502"),
171             @ApiResponse(code = 400, message = "Invalid Body :  Specified 'distrEnvName' doesn’t exist - POL4137"),
172             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
173             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
174             @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used to  register for  distribution ( PUT,DELETE,GET  will be rejected) - POL4050"),
175             @ApiResponse(code = 500, message = "The registration failed due to internal SDC problem or Cambria Service failure ECOMP Component  should  continue the attempts to  register for  distribution - POL5000")})
176     @ApiImplicitParams({@ApiImplicitParam(name = "requestJson", required = true, dataType = "org.openecomp.sdc.be.distribution.api.client.RegistrationRequest", paramType = "body", value = "json describe the artifact")})
177     public Response registerForDistribution(
178             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
179             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId,
180             @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
181             @ApiParam(value = "Determines the format of the body of the request", required = true)@HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
182             @ApiParam(value = "Length  of  the request body", required = true)@HeaderParam(value = Constants.CONTENT_LENGTH_HEADER) String contenLength,
183             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
184             @ApiParam( hidden = true) String requestJson) {
185         String url = request.getMethod() + " " + request.getRequestURI();
186         log.debug(START_HANDLE_REQUEST_OF, url);
187
188         Wrapper<Response> responseWrapper = new Wrapper<>();
189         Wrapper<RegistrationRequest> registrationRequestWrapper = new Wrapper<>();
190
191         validateHeaders(responseWrapper, request, AuditingActionEnum.ADD_KEY_TO_TOPIC_ACL);
192
193         if (responseWrapper.isEmpty()) {
194             validateJson(responseWrapper, registrationRequestWrapper, requestJson);
195         }
196         if (responseWrapper.isEmpty()) {
197             validateEnv(responseWrapper);
198         }
199
200         if (responseWrapper.isEmpty()) {
201             distributionLogic.handleRegistration(responseWrapper, registrationRequestWrapper.getInnerElement(), buildAuditHandler(request, registrationRequestWrapper.getInnerElement()));
202         } else {
203             BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionBusinessLogic.REGISTER_IN_DISTRIBUTION_ENGINE, "registration validation failed");
204         }
205
206         return responseWrapper.getInnerElement();
207     }
208
209     /**
210      * Returns list of valid artifact types for validation done in the distribution client.<br>
211      * The list is the representation of the values of the enum ArtifactTypeEnum.
212      *
213      * @param requestId
214      * @param instanceId
215      * @param authorization
216      * @param accept
217      * @return
218      */
219     @GET
220     @Path("/artifactTypes")
221     @Consumes(MediaType.APPLICATION_JSON)
222     @Produces(MediaType.APPLICATION_JSON)
223     @ApiOperation(value = "Artifact types list", httpMethod = "GET", notes = "Fetches available artifact types list")
224     @ApiResponses(value = {
225             @ApiResponse(code = 200, message = "Artifact types list fetched successfully", response = String.class),
226             @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
227             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
228             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
229             @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used to  register for  distribution ( POST,PUT,DELETE  will be rejected) - POL4050"),
230             @ApiResponse(code = 500, message = "The registration failed due to internal SDC problem or Cambria Service failure ECOMP Component  should  continue the attempts to  register for  distribution - POL5000")})
231     public Response getValidArtifactTypes(
232             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
233             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId,
234             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
235             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept) {
236         String url = request.getMethod() + " " + request.getRequestURI();
237         log.debug(START_HANDLE_REQUEST_OF, url);
238         Response response = null;
239
240         Wrapper<Response> responseWrapper = new Wrapper<>();
241
242         //TODO check if in use
243         validateHeaders(responseWrapper, request, AuditingActionEnum.GET_VALID_ARTIFACT_TYPES);
244         if (responseWrapper.isEmpty()) {
245             response = buildOkResponse(getComponentsUtils().getResponseFormat(ActionStatus.OK), ArtifactTypeEnum.values());
246         } else {
247             response = responseWrapper.getInnerElement();
248         }
249         return response;
250     }
251
252     /**
253      * Removes from subscription for distribution notifications
254      *
255      * @param requestId
256      * @param instanceId
257      * @param accept
258      * @param contentType
259      * @param contenLength
260      * @param authorization
261      * @param requestJson
262      * @return
263      */
264     @POST
265     @Path("/unRegisterForDistribution")
266     @Consumes(MediaType.APPLICATION_JSON)
267     @Produces(MediaType.APPLICATION_JSON)
268     @ApiOperation(value = "Subscription status", httpMethod = "POST", notes = "Removes from subscription for distribution notifications")
269     //TODO Edit the responses
270     @ApiResponses(value = {
271             @ApiResponse(code = 204, message = "ECOMP component is successfully unregistered", response = TopicUnregistrationResponse.class),
272             @ApiResponse(code = 400, message = "Missing  'X-ECOMP-InstanceID'  HTTP header - POL5001"),
273             @ApiResponse(code = 400, message = "Missing  Body - POL4500"),
274             @ApiResponse(code = 400, message = "Invalid  Body  : missing mandatory parameter 'apiPublicKey' - POL4501"),
275             @ApiResponse(code = 400, message = "Invalid  Body  : missing mandatory parameter 'distrEnvName' - SVC4506"),
276             @ApiResponse(code = 400, message = "Invalid Body :  Specified 'distrEnvName' doesn’t exist - POL4137"),
277             @ApiResponse(code = 401, message = "ECOMP component  should authenticate itself  and  to  re-send  again  HTTP  request  with its Basic Authentication credentials - POL5002"),
278             @ApiResponse(code = 403, message = "ECOMP component is not authorized - POL5003"),
279             @ApiResponse(code = 405, message = "Method  Not Allowed  :  Invalid HTTP method type used to  register for  distribution ( PUT,DELETE,GET will be rejected) - POL4050"),
280             @ApiResponse(code = 500, message = "The registration failed due to internal SDC problem or Cambria Service failure ECOMP Component  should  continue the attempts to  register for  distribution - POL5000")})
281     @ApiImplicitParams({@ApiImplicitParam(name = "requestJson", required = true, dataType = "org.openecomp.sdc.be.distribution.api.client.RegistrationRequest", paramType = "body", value = "json describe the artifact")})
282     public Response unRegisterForDistribution(
283             @ApiParam(value = "X-ECOMP-RequestID header", required = false)@HeaderParam(value = Constants.X_ECOMP_REQUEST_ID_HEADER) String requestId,
284             @ApiParam(value = "X-ECOMP-InstanceID header", required = true)@HeaderParam(value = Constants.X_ECOMP_INSTANCE_ID_HEADER) String instanceId,
285             @ApiParam(value = "Determines the format of the body of the response", required = false)@HeaderParam(value = Constants.ACCEPT_HEADER) String accept,
286             @ApiParam(value = "Determines the format of the body of the request", required = true)@HeaderParam(value = Constants.CONTENT_TYPE_HEADER) String contentType,
287             @ApiParam(value = "Length  of  the request body", required = true)@HeaderParam(value = Constants.CONTENT_LENGTH_HEADER) String contenLength,
288             @ApiParam(value = "The username and password", required = true)@HeaderParam(value = Constants.AUTHORIZATION_HEADER) String authorization,
289             @ApiParam( hidden = true) String requestJson) {
290
291         String url = request.getMethod() + " " + request.getRequestURI();
292         log.debug(START_HANDLE_REQUEST_OF, url);
293
294         Wrapper<Response> responseWrapper = new Wrapper<>();
295         Wrapper<RegistrationRequest> unRegistrationRequestWrapper = new Wrapper<>();
296
297         validateHeaders(responseWrapper, request, AuditingActionEnum.REMOVE_KEY_FROM_TOPIC_ACL);
298
299         if (responseWrapper.isEmpty()) {
300             validateJson(responseWrapper, unRegistrationRequestWrapper, requestJson);
301         }
302         if (responseWrapper.isEmpty()) {
303             validateEnv(responseWrapper);
304         }
305         if (responseWrapper.isEmpty()) {
306             distributionLogic.handleUnRegistration(responseWrapper, unRegistrationRequestWrapper.getInnerElement(), buildAuditHandler(request, unRegistrationRequestWrapper.getInnerElement()));
307         } else {
308             BeEcompErrorManager.getInstance().logBeDistributionEngineSystemError(DistributionBusinessLogic.UN_REGISTER_IN_DISTRIBUTION_ENGINE, "unregistration validation failed");
309         }
310
311         return responseWrapper.getInnerElement();
312     }
313
314     private void validateEnv(Wrapper<Response> responseWrapper) {
315
316         // DE194021
317         StorageOperationStatus environmentStatus = distributionLogic.getDistributionEngine().isEnvironmentAvailable();
318         if (environmentStatus != StorageOperationStatus.OK) {
319             if (environmentStatus == StorageOperationStatus.DISTR_ENVIRONMENT_NOT_FOUND) {
320                 Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.DISTRIBUTION_ENV_DOES_NOT_EXIST));
321                 responseWrapper.setInnerElement(missingHeaderResponse);
322             } else {
323                 Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.GENERAL_ERROR));
324                 responseWrapper.setInnerElement(missingHeaderResponse);
325             }
326         }
327
328     }
329
330     private void validateHeaders(Wrapper<Response> responseWrapper, HttpServletRequest request, AuditingActionEnum auditingAction) {
331         if (request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER) == null) {
332             Response missingHeaderResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID));
333             responseWrapper.setInnerElement(missingHeaderResponse);
334             ResponseFormat responseFormat = getComponentsUtils().getResponseFormat(ActionStatus.MISSING_X_ECOMP_INSTANCE_ID);
335             getComponentsUtils().auditMissingInstanceIdAsDistributionEngineEvent(auditingAction, responseFormat.getStatus().toString());
336
337         }
338
339     }
340
341     private void validateJson(Wrapper<Response> responseWrapper, Wrapper<RegistrationRequest> registrationRequestWrapper, String requestJson) {
342         if (requestJson == null || requestJson.isEmpty()) {
343             Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_BODY));
344             responseWrapper.setInnerElement(missingBodyResponse);
345         } else {
346             Either<RegistrationRequest, Exception> eitherRegistration = HttpUtil.convertJsonStringToObject(requestJson, RegistrationRequest.class);
347             if (eitherRegistration.isLeft()) {
348                 RegistrationRequest registrationRequest = eitherRegistration.left().value();
349                 if (registrationRequest.getApiPublicKey() == null) {
350                     Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_PUBLIC_KEY));
351                     responseWrapper.setInnerElement(missingBodyResponse);
352
353                 } else if (registrationRequest.getDistrEnvName() == null) {
354                     Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_ENV_NAME));
355                     responseWrapper.setInnerElement(missingBodyResponse);
356                 } else {
357                     registrationRequestWrapper.setInnerElement(registrationRequest);
358                 }
359             } else {
360                 Response missingBodyResponse = buildErrorResponse(distributionLogic.getResponseFormatManager().getResponseFormat(ActionStatus.MISSING_BODY));
361                 responseWrapper.setInnerElement(missingBodyResponse);
362             }
363         }
364
365     }
366
367     private AuditHandler buildAuditHandler(HttpServletRequest request, RegistrationRequest registrationRequest) {
368         return new AuditHandler(getComponentsUtils(), request.getHeader(Constants.X_ECOMP_INSTANCE_ID_HEADER), registrationRequest);
369     }
370 }