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