store openstack request status in requestdb
[so.git] / adapters / mso-openstack-adapters / src / main / java / org / onap / so / adapters / vnf / VnfAdapterRest.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SO
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright (C) 2017 Huawei Technologies Co., Ltd. All rights reserved.
7  * ================================================================================
8  * Modifications Copyright (C) 2018 IBM.
9  * Modifications Copyright (c) 2019 Samsung
10  * ================================================================================
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  * ============LICENSE_END=========================================================
23  */
24
25 package org.onap.so.adapters.vnf;
26
27
28 import java.util.Map;
29 import javax.inject.Provider;
30 import javax.ws.rs.Consumes;
31 import javax.ws.rs.DELETE;
32 import javax.ws.rs.GET;
33 import javax.ws.rs.POST;
34 import javax.ws.rs.PUT;
35 import javax.ws.rs.Path;
36 import javax.ws.rs.PathParam;
37 import javax.ws.rs.Produces;
38 import javax.ws.rs.QueryParam;
39 import javax.ws.rs.core.GenericEntity;
40 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.Response;
42 import javax.xml.ws.Holder;
43 import org.apache.http.HttpStatus;
44 import org.onap.logging.ref.slf4j.ONAPLogConstants;
45 import org.onap.so.adapters.vnf.exceptions.VnfException;
46 import org.onap.so.adapters.vnfrest.CreateVfModuleRequest;
47 import org.onap.so.adapters.vnfrest.CreateVfModuleResponse;
48 import org.onap.so.adapters.vnfrest.DeleteVfModuleRequest;
49 import org.onap.so.adapters.vnfrest.DeleteVfModuleResponse;
50 import org.onap.so.adapters.vnfrest.QueryVfModuleResponse;
51 import org.onap.so.adapters.vnfrest.RollbackVfModuleRequest;
52 import org.onap.so.adapters.vnfrest.RollbackVfModuleResponse;
53 import org.onap.so.adapters.vnfrest.UpdateVfModuleRequest;
54 import org.onap.so.adapters.vnfrest.UpdateVfModuleResponse;
55 import org.onap.so.adapters.vnfrest.VfModuleExceptionResponse;
56 import org.onap.so.adapters.vnfrest.VfModuleRollback;
57 import org.onap.so.entity.MsoRequest;
58 import org.onap.so.logger.ErrorCode;
59 import org.onap.so.logger.MessageEnum;
60 import org.onap.so.openstack.beans.VnfRollback;
61 import org.onap.so.openstack.beans.VnfStatus;
62 import org.onap.so.openstack.exceptions.MsoExceptionCategory;
63 import org.slf4j.Logger;
64 import org.slf4j.LoggerFactory;
65 import org.slf4j.MDC;
66 import org.springframework.beans.factory.annotation.Autowired;
67 import org.springframework.stereotype.Component;
68 import org.springframework.transaction.annotation.Transactional;
69 import io.swagger.annotations.Api;
70 import io.swagger.annotations.ApiOperation;
71 import io.swagger.annotations.ApiParam;
72 import io.swagger.annotations.ApiResponse;
73 import io.swagger.annotations.ApiResponses;
74
75 /**
76  * This class services calls to the REST interface for VF Modules (http://host:port/vnfs/rest/v1/vnfs) Both XML and JSON
77  * can be produced/consumed. Set Accept: and Content-Type: headers appropriately. XML is the default. For testing, call
78  * with cloudSiteId = ___TESTING___ To test exceptions, also set tenantId = ___TESTING___
79  */
80 @Path("/v1/vnfs")
81 @Api(value = "/v1/vnfs", description = "root of vnf adapters restful web service")
82 @Transactional
83 @Component
84 public class VnfAdapterRest {
85     private static Logger logger = LoggerFactory.getLogger(VnfAdapterRest.class);
86     private static final String TESTING_KEYWORD = "___TESTING___";
87     private static final String RESP = ", resp=";
88
89     @Autowired
90     private MsoVnfAdapterImpl vnfAdapter;
91
92     @Autowired
93     private Provider<BpelRestClient> bpelRestClientProvider;
94
95     @DELETE
96     @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}")
97     @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
98     @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
99     @ApiOperation(value = "DeleteVfModule", response = Response.class,
100             notes = "Delete an existing vnfModule, DeleteVfModuleRequest JSON is required")
101     @ApiResponses({@ApiResponse(code = 200, message = "vnfModule has been successfully deleted"),
102             @ApiResponse(code = 202, message = "delete vnfModule request has been accepted (async only)"),
103             @ApiResponse(code = 500, message = "delete vnfModule failed, examine entity object for details")})
104     public Response deleteVfModule(
105             @ApiParam(value = "aaiVnfId", required = true) @PathParam("aaiVnfId") String aaiVnfId,
106             @ApiParam(value = "aaiVfModuleId", required = true) @PathParam("aaiVfModuleId") String aaiVfModuleId,
107             @ApiParam(value = "DeleteVfModuleRequest", required = true) final DeleteVfModuleRequest req) {
108         logger.debug("Delete VfModule enter: " + req.toJsonString());
109         if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) {
110             logger.debug("Req rejected - aaiVnfId not provided or doesn't match URL");
111             return Response.status(HttpStatus.SC_BAD_REQUEST).type(MediaType.TEXT_PLAIN)
112                     .entity("vnfid in URL does not match content").build();
113         }
114         if (aaiVfModuleId == null || !aaiVfModuleId.equals(req.getVfModuleId())) {
115             logger.debug("Req rejected - aaiVfModuleId not provided or doesn't match URL");
116             return Response.status(HttpStatus.SC_BAD_REQUEST).type(MediaType.TEXT_PLAIN)
117                     .entity("vfModuleId in URL does not match content").build();
118         }
119         DeleteVfModuleTask task = new DeleteVfModuleTask(req);
120         if (req.isSynchronous()) {
121             // This is a synchronous request
122             task.run();
123             return Response.status(task.getStatusCode()).entity(task.getGenericEntityResponse()).build();
124         } else {
125             // This is an asynchronous request
126             try {
127                 Thread t1 = new Thread(task);
128                 t1.start();
129             } catch (Exception e) {
130                 // problem handling delete, send generic failure as sync resp to caller
131                 logger.error("", MessageEnum.RA_DELETE_VNF_ERR.toString(), "deleteVfModule",
132                         ErrorCode.BusinessProcesssError.getValue(), "Exception in deleteVfModule", e);
133                 return Response.serverError().build();
134             }
135             // send sync response (ACK) to caller
136             logger.debug("deleteVNFVolumes exit");
137             return Response.status(HttpStatus.SC_ACCEPTED).build();
138         }
139     }
140
141     public class DeleteVfModuleTask implements Runnable {
142         private final DeleteVfModuleRequest req;
143         private DeleteVfModuleResponse response = null;
144         private VfModuleExceptionResponse eresp = null;
145         private boolean sendxml;
146
147         public DeleteVfModuleTask(DeleteVfModuleRequest req) {
148             this.req = req;
149             this.sendxml = true; // can be set with a field or header later
150         }
151
152         public int getStatusCode() {
153             return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
154         }
155
156         public Object getGenericEntityResponse() {
157             return (response != null) ? new GenericEntity<DeleteVfModuleResponse>(response) {}
158                     : new GenericEntity<VfModuleExceptionResponse>(eresp) {};
159         }
160
161         private String getResponse() {
162             if (response != null) {
163                 return sendxml ? response.toXmlString() : response.toJsonString();
164             } else {
165                 return sendxml ? eresp.toXmlString() : eresp.toJsonString();
166             }
167         }
168
169         @Override
170         public void run() {
171             try {
172                 try {
173                     MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, req.getMsoRequest().getRequestId());
174                 } catch (Exception e) {
175                     logger.error("Error adding RequestId to MDC", e);
176                 }
177                 String cloudsite = req.getCloudSiteId();
178                 Holder<Map<String, String>> outputs = new Holder<>();
179                 if (cloudsite != null && !cloudsite.equals(TESTING_KEYWORD)) {
180                     vnfAdapter.deleteVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(),
181                             req.getVfModuleStackId(), req.getMsoRequest(), outputs);
182                 }
183                 response = new DeleteVfModuleResponse(req.getVnfId(), req.getVfModuleId(), Boolean.TRUE,
184                         req.getMessageId(), outputs.value);
185             } catch (VnfException e) {
186                 logger.error("{} {} {}", MessageEnum.RA_DELETE_VNF_ERR.toString(),
187                         ErrorCode.BusinessProcesssError.getValue(), "VnfException - Delete VNF Module", e);
188                 eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE,
189                         req.getMessageId());
190             }
191             if (!req.isSynchronous()) {
192                 BpelRestClient bpelClient = bpelRestClientProvider.get();
193                 bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
194             }
195             logger.debug("Delete vfModule exit: code=" + getStatusCode() + RESP + getResponse());
196         }
197     }
198
199
200     @GET
201     @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}")
202     @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
203     @ApiOperation(value = "QueryVfModule", response = Response.class, notes = "Query an existing vnfModule")
204     @ApiResponses({@ApiResponse(code = 200, message = "vnfModule has been successfully queried"),
205             @ApiResponse(code = 500, message = "query vnfModule failed, examine entity object for details")})
206     public Response queryVfModule(@ApiParam(value = "aaiVnfId", required = true) @PathParam("aaiVnfId") String aaiVnfId,
207             @ApiParam(value = "aaiVfModuleId", required = true) @PathParam("aaiVfModuleId") String aaiVfModuleId,
208             @ApiParam(value = "cloudSiteId", required = true) @QueryParam("cloudSiteId") String cloudSiteId,
209             @ApiParam(value = "cloudOwner", required = true) @QueryParam("cloudOwner") String cloudOwner,
210             @ApiParam(value = "tenantId", required = true) @QueryParam("tenantId") String tenantId,
211             @ApiParam(value = "vfModuleName", required = true) @QueryParam("vfModuleName") String vfModuleName, // RAA?
212                                                                                                                 // Id in
213                                                                                                                 // doc
214             @ApiParam(value = "skipAAI", required = true) @QueryParam("skipAAI") Boolean skipAAI,
215             @ApiParam(value = "msoRequest.requestId",
216                     required = true) @QueryParam("msoRequest.requestId") String requestId,
217             @ApiParam(value = "msoRequest.serviceInstanceId",
218                     required = true) @QueryParam("msoRequest.serviceInstanceId") String serviceInstanceId) {
219         // This request responds synchronously only
220         logger.debug("Query vfModule enter:" + vfModuleName);
221         MsoRequest msoRequest = new MsoRequest(requestId, serviceInstanceId);
222
223         try {
224             int respStatus = HttpStatus.SC_OK;
225             QueryVfModuleResponse qryResp = new QueryVfModuleResponse(aaiVnfId, aaiVfModuleId, null, null, null);
226             Holder<Boolean> vnfExists = new Holder<>();
227             Holder<String> vfModuleId = new Holder<>();
228             Holder<VnfStatus> status = new Holder<>();
229             Holder<Map<String, String>> outputs = new Holder<>();
230             vnfAdapter.queryVnf(cloudSiteId, cloudOwner, tenantId, vfModuleName, msoRequest, vnfExists, vfModuleId,
231                     status, outputs);
232             if (!vnfExists.value) {
233                 logger.debug("vfModule not found");
234                 respStatus = HttpStatus.SC_NOT_FOUND;
235             } else {
236                 logger.debug("vfModule found" + vfModuleId.value + ", status=" + status.value);
237                 qryResp.setVfModuleId(vfModuleId.value);
238                 qryResp.setVnfStatus(status.value);
239                 qryResp.setVfModuleOutputs(outputs.value);
240             }
241             logger.debug("Query vfModule exit");
242             return Response.status(respStatus).entity(new GenericEntity<QueryVfModuleResponse>(qryResp) {}).build();
243         } catch (VnfException e) {
244             logger.error("{} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, "queryVfModule",
245                     ErrorCode.BusinessProcesssError.getValue(), "VnfException - queryVfModule", e);
246             VfModuleExceptionResponse excResp =
247                     new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.FALSE, null);
248             return Response.status(HttpStatus.SC_INTERNAL_SERVER_ERROR)
249                     .entity(new GenericEntity<VfModuleExceptionResponse>(excResp) {}).build();
250         }
251     }
252
253     /*
254      * URL: http://localhost:8080/vnfs/rest/v1/vnfs/<aaivnfid>/vf-modules REQUEST: {"createVfModuleRequest":
255      * {"cloudSiteId": "DAN", "tenantId": "214b428a1f554c02935e66330f6a5409", "vnfId": "somevnfid", "vfModuleId":
256      * "somemodid", "vfModuleName": "RaaVnf1", "vnfType": "ApacheVnf", "vfModuleParams": {"entry": [ {"key":
257      * "network_id", "value": "59ed7b41-2983-413f-ba93-e7d437433916"}, {"key": "subnet_id", "value":
258      * "086c9298-5c57-49b7-bb2b-6fd5730c5d92"}, {"key": "server_name_0", "value": "RaaVnf1"} ]}, "failIfExists": true,
259      * "messageId": "ra.1", "notificationUrl": "http://localhost:8089/vnfmock", "skipAAI": true, "msoRequest": {
260      * "requestId": "ra1", "serviceInstanceId": "sa1" }} }
261      */
262     @POST
263     @Path("{aaiVnfId}/vf-modules")
264     @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
265     @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
266     @ApiOperation(value = "CreateVfModule", response = Response.class, notes = "Create a vnfModule")
267     @ApiResponses({@ApiResponse(code = 200, message = "vnfModule has been successfully created"),
268             @ApiResponse(code = 202, message = "create vnfModule request has been successfully accepted (async only)"),
269             @ApiResponse(code = 500, message = "create vnfModule failed, examine entity object for details")})
270     public Response createVfModule(
271             @ApiParam(value = "aaiVnfId", required = true) @PathParam("aaiVnfId") String aaiVnfId,
272             @ApiParam(value = "CreateVfModuleRequest", required = true) final CreateVfModuleRequest req) {
273         logger.debug("Create VfModule enter inside VnfAdapterRest: " + req.toJsonString());
274         if (aaiVnfId == null || !aaiVnfId.equals(req.getVnfId())) {
275             logger.debug("Req rejected - aaiVnfId not provided or doesn't match URL");
276             return Response.status(HttpStatus.SC_BAD_REQUEST).type(MediaType.TEXT_PLAIN)
277                     .entity("vnfid in URL does not match content").build();
278         }
279         CreateVfModuleTask task = new CreateVfModuleTask(req);
280         if (req.isSynchronous()) {
281             // This is a synchronous request
282             task.run();
283             return Response.status(task.getStatusCode()).entity(task.getGenericEntityResponse()).build();
284         } else {
285             // This is an asynchronous request
286             try {
287                 Thread t1 = new Thread(task);
288                 t1.start();
289             } catch (Exception e) {
290                 // problem handling create, send generic failure as sync resp to caller
291                 logger.error("{} {} {} {}", MessageEnum.RA_CREATE_VNF_ERR, "createVfModule",
292                         ErrorCode.BusinessProcesssError, "Exception - createVfModule", e);
293                 return Response.serverError().build();
294             }
295             // send sync response (ACK) to caller
296             logger.debug("createVfModule exit");
297             return Response.status(HttpStatus.SC_ACCEPTED).build();
298         }
299     }
300
301     public class CreateVfModuleTask implements Runnable {
302         private final CreateVfModuleRequest req;
303         private CreateVfModuleResponse response = null;
304         private VfModuleExceptionResponse eresp = null;
305         private boolean sendxml;
306
307         public CreateVfModuleTask(CreateVfModuleRequest req) {
308             this.req = req;
309             this.sendxml = true; // can be set with a field or header later
310         }
311
312         public int getStatusCode() {
313             return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
314         }
315
316         public Object getGenericEntityResponse() {
317             return (response != null) ? new GenericEntity<CreateVfModuleResponse>(response) {}
318                     : new GenericEntity<VfModuleExceptionResponse>(eresp) {};
319         }
320
321         private String getResponse() {
322             if (response != null) {
323                 return sendxml ? response.toXmlString() : response.toJsonString();
324             } else {
325                 return sendxml ? eresp.toXmlString() : eresp.toJsonString();
326             }
327         }
328
329         @Override
330         public void run() {
331             logger.debug("CreateVfModuleTask start");
332             try {
333                 try {
334                     MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, req.getMsoRequest().getRequestId());
335                 } catch (Exception e) {
336                     logger.error("Error adding RequestId to MDC", e);
337                 }
338                 // Synchronous Web Service Outputs
339                 Holder<String> vfModuleStackId = new Holder<>();
340                 Holder<Map<String, String>> outputs = new Holder<>();
341                 Holder<VnfRollback> vnfRollback = new Holder<>();
342                 String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType();
343                 logger.debug("completeVnfVfModuleType=" + completeVnfVfModuleType);
344                 String cloudsite = req.getCloudSiteId();
345                 String cloudOwner = req.getCloudOwner();
346                 if (cloudsite != null && cloudsite.equals(TESTING_KEYWORD)) {
347                     String tenant = req.getTenantId();
348                     if (tenant != null && tenant.equals(TESTING_KEYWORD)) {
349                         throw new VnfException("testing.");
350                     }
351                     vnfRollback.value = new VnfRollback(req.getVnfId(), tenant, cloudOwner, cloudsite, true, false,
352                             new MsoRequest("reqid", "svcid"), req.getVolumeGroupId(), req.getVolumeGroupId(),
353                             req.getRequestType(), req.getModelCustomizationUuid());
354                     vfModuleStackId.value = "479D3D8B-6360-47BC-AB75-21CC91981484";
355                     outputs.value = VolumeAdapterRest.testMap();
356                 } else {
357                     vnfAdapter.createVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(),
358                             completeVnfVfModuleType, req.getVnfVersion(), req.getVnfId(), req.getVfModuleName(),
359                             req.getVfModuleId(), req.getRequestType(), req.getVolumeGroupStackId(),
360                             req.getBaseVfModuleStackId(), req.getModelCustomizationUuid(), req.getVfModuleParams(),
361                             req.getFailIfExists(), req.getBackout(), req.getEnableBridge(), req.getMsoRequest(),
362                             vfModuleStackId, outputs, vnfRollback);
363                 }
364                 VfModuleRollback modRollback = new VfModuleRollback(vnfRollback.value, req.getVfModuleId(),
365                         vfModuleStackId.value, req.getMessageId());
366                 response = new CreateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), vfModuleStackId.value,
367                         Boolean.TRUE, outputs.value, modRollback, req.getMessageId());
368             } catch (VnfException e) {
369                 logger.debug("Exception :", e);
370                 eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE,
371                         req.getMessageId());
372             }
373             if (!req.isSynchronous()) {
374                 BpelRestClient bpelClient = bpelRestClientProvider.get();
375                 bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
376             }
377             logger.debug("CreateVfModuleTask exit: code=" + getStatusCode());
378         }
379     }
380
381     @PUT
382     @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}")
383     @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
384     @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
385     @ApiOperation(value = "UpdateVfModule", response = Response.class, notes = "Update an existing vnfModule")
386     @ApiResponses({@ApiResponse(code = 200, message = "vnfModule has been successfully updated"),
387             @ApiResponse(code = 202, message = "update vnfModule request has been successfully accepted (async only)"),
388             @ApiResponse(code = 500, message = "update vnfModule failed, examine entity object for details")})
389     public Response updateVfModule(
390             @ApiParam(value = "aaiVnfId", required = true) @PathParam("aaiVnfId") String aaiVnfId,
391             @ApiParam(value = "aaiVfModuleId", required = true) @PathParam("aaiVfModuleId") String aaiVfModuleId,
392             @ApiParam(value = "UpdateVfModuleRequest", required = true) final UpdateVfModuleRequest req) {
393         logger.debug("Update VfModule enter: " + req.toJsonString());
394         UpdateVfModulesTask task = new UpdateVfModulesTask(req);
395         if (req.isSynchronous()) {
396             // This is a synchronous request
397             task.run();
398             return Response.status(task.getStatusCode()).entity(task.getGenericEntityResponse()).build();
399         } else {
400             // This is an asynchronous request
401             try {
402                 Thread t1 = new Thread(task);
403                 t1.start();
404             } catch (Exception e) {
405                 // problem handling create, send generic failure as sync resp to caller
406                 logger.error("{} {} {} {}", MessageEnum.RA_UPDATE_VNF_ERR.toString(), "updateVfModule",
407                         ErrorCode.BusinessProcesssError.getValue(), "Exception - updateVfModule", e);
408                 return Response.serverError().build();
409             }
410             // send sync response (ACK) to caller
411             logger.debug("updateVfModules exit");
412             return Response.status(HttpStatus.SC_ACCEPTED).build();
413         }
414     }
415
416     public class UpdateVfModulesTask implements Runnable {
417         private final UpdateVfModuleRequest req;
418         private UpdateVfModuleResponse response = null;
419         private VfModuleExceptionResponse eresp = null;
420         private boolean sendxml;
421
422         public UpdateVfModulesTask(UpdateVfModuleRequest req) {
423             this.req = req;
424             this.sendxml = true; // can be set with a field or header later
425         }
426
427         public int getStatusCode() {
428             return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
429         }
430
431         public Object getGenericEntityResponse() {
432             return (response != null) ? new GenericEntity<UpdateVfModuleResponse>(response) {}
433                     : new GenericEntity<VfModuleExceptionResponse>(eresp) {};
434         }
435
436         private String getResponse() {
437             if (response != null) {
438                 return sendxml ? response.toXmlString() : response.toJsonString();
439             } else {
440                 return sendxml ? eresp.toXmlString() : eresp.toJsonString();
441             }
442         }
443
444         @Override
445         public void run() {
446             try {
447                 try {
448                     MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, req.getMsoRequest().getRequestId());
449                 } catch (Exception e) {
450                     logger.error("Error adding RequestId to MDC", e);
451                 }
452                 Holder<String> vfModuleStackId = new Holder<>();
453                 Holder<Map<String, String>> outputs = new Holder<>();
454                 Holder<VnfRollback> vnfRollback = new Holder<>();
455                 String completeVnfVfModuleType = req.getVnfType() + "::" + req.getVfModuleType();
456                 logger.debug("in updateVf - completeVnfVfModuleType=" + completeVnfVfModuleType);
457
458                 vnfAdapter.updateVfModule(req.getCloudSiteId(), req.getCloudOwner(), req.getTenantId(),
459                         // req.getVnfType(),
460                         completeVnfVfModuleType, req.getVnfVersion(), req.getVfModuleName(), req.getRequestType(),
461                         req.getVolumeGroupStackId(), req.getBaseVfModuleStackId(), req.getVfModuleStackId(),
462                         req.getModelCustomizationUuid(), req.getVfModuleParams(), req.getMsoRequest(), outputs,
463                         vnfRollback);
464
465                 response = new UpdateVfModuleResponse(req.getVnfId(), req.getVfModuleId(), vfModuleStackId.value,
466                         outputs.value, req.getMessageId());
467             } catch (VnfException e) {
468                 logger.debug("Exception :", e);
469                 eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, Boolean.TRUE,
470                         req.getMessageId());
471             }
472             if (!req.isSynchronous()) {
473                 // This is asynch, so POST response back to caller
474                 BpelRestClient bpelClient = bpelRestClientProvider.get();
475                 bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
476             }
477             logger.debug("Update VfModule exit: code=" + getStatusCode() + RESP + getResponse());
478         }
479     }
480
481
482     @DELETE
483     @Path("{aaiVnfId}/vf-modules/{aaiVfModuleId}/rollback")
484     @Consumes({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
485     @Produces({MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON})
486     @ApiOperation(value = "RollbackVfModule", response = Response.class, notes = "Rollback an existing vnfModule")
487     @ApiResponses({@ApiResponse(code = 200, message = "vnfModule has been successfully rolled back"),
488             @ApiResponse(code = 202,
489                     message = "rollback vnfModule request has been successfully accepted (async only)"),
490             @ApiResponse(code = 500, message = "rollback vnfModule failed, examine entity object for details")})
491     public Response rollbackVfModule(
492             @ApiParam(value = "aaiVnfId", required = true) @PathParam("aaiVnfId") String aaiVnfId,
493             @ApiParam(value = "aaiVfModuleId", required = true) @PathParam("aaiVfModuleId") String aaiVfModuleId,
494             @ApiParam(value = "RollbackVfModuleRequest", required = true)
495             // @QueryParam("rollback") String rollback,
496             final RollbackVfModuleRequest req) {
497         logger.debug("Rollback VfModule enter: " + req.toJsonString());
498         RollbackVfModulesTask task = new RollbackVfModulesTask(req);
499         if (req.isSynchronous()) {
500             // This is a synchronous request
501             task.run();
502             return Response.status(task.getStatusCode()).entity(task.getGenericEntityResponse()).build();
503         } else {
504             // This is an asynchronous request
505             try {
506                 Thread t1 = new Thread(task);
507                 t1.start();
508             } catch (Exception e) {
509                 // problem handling create, send generic failure as sync resp to caller
510                 logger.error("{} {} {} {}", MessageEnum.RA_ROLLBACK_VNF_ERR.toString(), "rollbackVfModule",
511                         ErrorCode.BusinessProcesssError.getValue(), "Exception - rollbackVfModule", e);
512                 return Response.serverError().build();
513             }
514             // send sync response (ACK) to caller
515             logger.debug("rollbackVfModule exit");
516             return Response.status(HttpStatus.SC_ACCEPTED).build();
517         }
518     }
519
520     public class RollbackVfModulesTask implements Runnable {
521         private final RollbackVfModuleRequest req;
522         private RollbackVfModuleResponse response = null;
523         private VfModuleExceptionResponse eresp = null;
524         private boolean sendxml;
525
526         public RollbackVfModulesTask(RollbackVfModuleRequest req) {
527             this.req = req;
528             this.sendxml = true; // can be set with a field or header later
529         }
530
531         public int getStatusCode() {
532             return (response != null) ? HttpStatus.SC_OK : HttpStatus.SC_BAD_REQUEST;
533         }
534
535         public Object getGenericEntityResponse() {
536             return (response != null) ? new GenericEntity<RollbackVfModuleResponse>(response) {}
537                     : new GenericEntity<VfModuleExceptionResponse>(eresp) {};
538         }
539
540         private String getResponse() {
541             if (response != null) {
542                 return sendxml ? response.toXmlString() : response.toJsonString();
543             } else {
544                 return sendxml ? eresp.toXmlString() : eresp.toJsonString();
545             }
546         }
547
548         @Override
549         public void run() {
550             try {
551                 try {
552                     MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, req.getVfModuleRollback().getMsoRequest().getRequestId());
553                 } catch (Exception e) {
554                     logger.error("Error adding RequestId to MDC", e);
555                 }
556                 VfModuleRollback vmr = req.getVfModuleRollback();
557                 VnfRollback vrb = new VnfRollback(vmr.getVfModuleStackId(), vmr.getTenantId(), vmr.getCloudOwner(),
558                         vmr.getCloudSiteId(), true, true, vmr.getMsoRequest(), null, null, null, null);
559                 vnfAdapter.rollbackVnf(vrb);
560                 response = new RollbackVfModuleResponse(Boolean.TRUE, req.getMessageId());
561             } catch (VnfException e) {
562                 logger.error("{} {} {}", MessageEnum.RA_ROLLBACK_VNF_ERR, ErrorCode.BusinessProcesssError,
563                         "Exception" + " - " + "rollbackVfModule", e);
564                 eresp = new VfModuleExceptionResponse(e.getMessage(), MsoExceptionCategory.INTERNAL, false,
565                         req.getMessageId());
566             }
567             if (!req.isSynchronous()) {
568                 // This is asynch, so POST response back to caller
569                 BpelRestClient bpelClient = bpelRestClientProvider.get();
570                 bpelClient.bpelPost(getResponse(), req.getNotificationUrl(), sendxml);
571             }
572             logger.debug("RollbackVfModulesTask exit: code=" + getStatusCode() + RESP + getResponse());
573         }
574     }
575 }