8f97dec9c59a9049cc73d1156bb7dca90a34e0ba
[sdnc/apps.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP - SDNC
4  * ================================================================================
5  * Copyright (C) 2020 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.onap.sdnc.apps.ms.gra.controllers;
22
23 import com.fasterxml.jackson.annotation.JsonInclude;
24 import com.fasterxml.jackson.core.JsonProcessingException;
25 import com.fasterxml.jackson.databind.JsonMappingException;
26 import com.fasterxml.jackson.databind.ObjectMapper;
27 import com.google.gson.JsonParser;
28
29 import org.onap.ccsdk.apps.services.RestException;
30 import org.onap.ccsdk.apps.services.SvcLogicFactory;
31 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
32 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
33 import org.onap.ccsdk.sli.core.sli.provider.base.SvcLogicServiceBase;
34 import org.onap.sdnc.apps.ms.gra.data.ConfigPreloadData;
35 import org.onap.sdnc.apps.ms.gra.data.ConfigPreloadDataRepository;
36 import org.onap.sdnc.apps.ms.gra.data.ConfigServices;
37 import org.onap.sdnc.apps.ms.gra.data.ConfigServicesRepository;
38 import org.onap.sdnc.apps.ms.gra.data.OperationalPreloadData;
39 import org.onap.sdnc.apps.ms.gra.data.OperationalPreloadDataRepository;
40 import org.onap.sdnc.apps.ms.gra.data.OperationalServices;
41 import org.onap.sdnc.apps.ms.gra.data.OperationalServicesRepository;
42 import org.onap.sdnc.apps.ms.gra.swagger.OperationsApi;
43 import org.onap.sdnc.apps.ms.gra.swagger.model.*;
44 import org.springframework.beans.factory.annotation.Autowired;
45 import org.springframework.boot.autoconfigure.domain.EntityScan;
46 import org.springframework.context.annotation.ComponentScan;
47 import org.springframework.context.annotation.Import;
48 import org.springframework.http.HttpStatus;
49 import org.springframework.http.ResponseEntity;
50 import org.springframework.stereotype.Controller;
51
52 import javax.servlet.http.HttpServletRequest;
53 import javax.validation.Valid;
54
55 import java.text.DateFormat;
56 import java.text.SimpleDateFormat;
57 import java.util.*;
58 import java.util.concurrent.atomic.AtomicBoolean;
59
60 @Controller
61 @ComponentScan(basePackages = { "org.onap.sdnc.apps.ms.gra.*", "org.onap.ccsdk.apps.services" })
62 @EntityScan("org.onap.sdnc.apps.ms.gra.*")
63 @Import(value = SvcLogicFactory.class)
64 public class OperationsApiController implements OperationsApi {
65
66     private static final String CALLED_STR = "{} called.";
67     private static final String MODULE_NAME = "GENERIC-RESOURCE-API";
68
69     private final ObjectMapper objectMapper;
70
71     private final HttpServletRequest request;
72
73     @Autowired
74     protected SvcLogicServiceBase svc;
75
76     @Autowired
77     private ConfigPreloadDataRepository configPreloadDataRepository;
78
79     @Autowired
80     private OperationalPreloadDataRepository operationalPreloadDataRepository;
81
82     @Autowired
83     private ConfigServicesRepository configServicesRepository;
84
85     @Autowired
86     private OperationalServicesRepository operationalServicesRepository;
87
88     private static class Iso8601Util {
89
90         private static TimeZone timeZone = TimeZone.getTimeZone("UTC");
91         private static DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
92
93         private Iso8601Util() {
94         }
95
96         static {
97             dateFormat.setTimeZone(timeZone);
98         }
99
100         private static String now() {
101             return dateFormat.format(new Date());
102         }
103     }
104
105     @org.springframework.beans.factory.annotation.Autowired
106     public OperationsApiController(ObjectMapper objectMapper, HttpServletRequest request) {
107         objectMapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
108         objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
109         this.objectMapper = objectMapper;
110         this.request = request;
111     }
112
113     @Override
114     public Optional<ObjectMapper> getObjectMapper() {
115         return Optional.ofNullable(objectMapper);
116     }
117
118     @Override
119     public Optional<HttpServletRequest> getRequest() {
120         return Optional.ofNullable(request);
121     }
122
123     @Override
124     public ResponseEntity<GenericResourceApiPreloadNetworkTopologyOperation> operationsGENERICRESOURCEAPIpreloadNetworkTopologyOperationPost(
125             @Valid GenericResourceApiPreloadnetworktopologyoperationInputBodyparam graInput) {
126         final String svcOperation = "preload-network-topology-operation";
127         GenericResourceApiPreloadNetworkTopologyOperation retval = new GenericResourceApiPreloadNetworkTopologyOperation();
128         GenericResourceApiPreloadTopologyResponseBody resp = new GenericResourceApiPreloadTopologyResponseBody();
129
130         log.info(CALLED_STR, svcOperation);
131         if (hasInvalidPreloadNetwork(graInput)) {
132             log.debug("exiting {} because of null or empty preload-network-topology-information", svcOperation);
133
134             resp.setResponseCode("403");
135             resp.setResponseMessage("invalid input, null or empty preload-network-topology-information");
136             resp.setAckFinalIndicator("Y");
137
138             retval.setOutput(resp);
139
140             return new ResponseEntity<>(retval, HttpStatus.FORBIDDEN);
141         }
142
143         String preloadId = graInput.getInput().getPreloadNetworkTopologyInformation()
144                 .getNetworkTopologyIdentifierStructure().getNetworkId();
145         String preloadType = "network";
146
147         resp.setSvcRequestId(graInput.getInput().getSdncRequestHeader().getSvcRequestId());
148
149         SvcLogicContext ctxIn = new SvcLogicContext();
150
151         GenericResourceApiPreloaddataPreloadData preloadData = null;
152
153         // Add input to SvcLogicContext
154         try {
155             ctxIn.mergeJson(svcOperation + "-input", objectMapper.writeValueAsString(graInput.getInput()));
156         } catch (JsonProcessingException e) {
157             log.error("exiting {} due to parse error on input preload data", svcOperation);
158             resp.setResponseCode("500");
159             resp.setResponseMessage("internal error");
160             resp.setAckFinalIndicator("Y");
161             retval.setOutput(resp);
162             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
163         }
164
165         // Add config tree data to SvcLogicContext
166         try {
167             preloadData = getConfigPreloadData(preloadId, preloadType);
168             ctxIn.mergeJson("preload-data", objectMapper.writeValueAsString(preloadData));
169         } catch (JsonProcessingException e) {
170             log.error("exiting {} due to parse error on saved config preload data", svcOperation);
171             resp.setResponseCode("500");
172             resp.setResponseMessage("internal error");
173             resp.setAckFinalIndicator("Y");
174             retval.setOutput(resp);
175             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
176         }
177
178         // Add operational tree data to SvcLogicContext
179         try {
180             preloadData = getOperationalPreloadData(preloadId, preloadType);
181             ctxIn.mergeJson("operational-data", objectMapper.writeValueAsString(preloadData));
182         } catch (JsonProcessingException e) {
183             log.error("exiting {} due to parse error on saved operational preload data", svcOperation);
184             resp.setResponseCode("500");
185             resp.setResponseMessage("internal error");
186             resp.setAckFinalIndicator("Y");
187             retval.setOutput(resp);
188             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
189         }
190
191         // Call DG
192         try {
193             // Any of these can throw a nullpointer exception
194             // execute should only throw a SvcLogicException
195             SvcLogicContext ctxOut = svc.execute(MODULE_NAME, svcOperation, null, "sync", ctxIn);
196             Properties respProps = ctxOut.toProperties();
197
198             resp.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
199             resp.setResponseCode(respProps.getProperty("error-code", "200"));
200             resp.setResponseMessage(respProps.getProperty("error-message", "SUCCESS"));
201
202             if ("200".equals(resp.getResponseCode())) {
203                 // If DG returns success, update database
204                 String ctxJson = ctxOut.toJsonString("preload-data");
205                 log.info("DG preload-data is {}", ctxJson);
206                 GenericResourceApiPreloaddataPreloadData preloadToLoad = objectMapper.readValue(ctxJson,
207                         GenericResourceApiPreloaddataPreloadData.class);
208                 saveConfigPreloadData(preloadId, preloadType, preloadToLoad);
209                 saveOperationalPreloadData(preloadId, preloadType, preloadToLoad);
210             }
211
212         } catch (NullPointerException npe) {
213             log.error("Caught NPE", npe);
214             resp.setAckFinalIndicator("true");
215             resp.setResponseCode("500");
216             resp.setResponseMessage("Check that you populated module, rpc and or mode correctly.");
217         } catch (SvcLogicException e) {
218             log.error("Caught SvcLogicException", e);
219             resp.setAckFinalIndicator("true");
220             resp.setResponseCode("500");
221             resp.setResponseMessage(e.getMessage());
222         } catch (JsonMappingException e) {
223             log.error("Caught JsonMappingException", e);
224             resp.setAckFinalIndicator("true");
225             resp.setResponseCode("500");
226             resp.setResponseMessage(e.getMessage());
227         } catch (JsonProcessingException e) {
228             log.error("Caught JsonProcessingException", e);
229             resp.setAckFinalIndicator("true");
230             resp.setResponseCode("500");
231             resp.setResponseMessage(e.getMessage());
232         }
233
234         retval.setOutput(resp);
235         return (new ResponseEntity<>(retval, HttpStatus.valueOf(Integer.parseInt(resp.getResponseCode()))));
236     }
237
238     @Override
239     public ResponseEntity<GenericResourceApiPreloadVfModuleTopologyOperation> operationsGENERICRESOURCEAPIpreloadVfModuleTopologyOperationPost(
240             @Valid GenericResourceApiPreloadvfmoduletopologyoperationInputBodyparam graInput) {
241         final String svcOperation = "preload-vf-module-topology-operation";
242         GenericResourceApiPreloadVfModuleTopologyOperation retval = new GenericResourceApiPreloadVfModuleTopologyOperation();
243         GenericResourceApiPreloadTopologyResponseBody resp = new GenericResourceApiPreloadTopologyResponseBody();
244
245         log.info(CALLED_STR, svcOperation);
246         if (hasInvalidPreloadNetwork(graInput)) {
247             log.debug("exiting {} because of null or empty preload-network-topology-information", svcOperation);
248
249             resp.setResponseCode("403");
250             resp.setResponseMessage("invalid input, null or empty preload-network-topology-information");
251             resp.setAckFinalIndicator("Y");
252
253             retval.setOutput(resp);
254
255             return new ResponseEntity<>(retval, HttpStatus.FORBIDDEN);
256         }
257
258         String preloadId = graInput.getInput().getPreloadVfModuleTopologyInformation().getVfModuleTopology()
259                 .getVfModuleTopologyIdentifier().getVfModuleName();
260         String preloadType = "vf-module";
261
262         resp.setSvcRequestId(graInput.getInput().getSdncRequestHeader().getSvcRequestId());
263
264         SvcLogicContext ctxIn = new SvcLogicContext();
265
266         GenericResourceApiPreloaddataPreloadData preloadData = null;
267
268         // Add input to SvcLogicContext
269         try {
270             ctxIn.mergeJson(svcOperation + "-input", objectMapper.writeValueAsString(graInput.getInput()));
271         } catch (JsonProcessingException e) {
272             log.error("exiting {} due to parse error on input preload data", svcOperation);
273             resp.setResponseCode("500");
274             resp.setResponseMessage("internal error");
275             resp.setAckFinalIndicator("Y");
276             retval.setOutput(resp);
277             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
278         }
279
280         // Add config tree data to SvcLogicContext
281         try {
282             preloadData = getConfigPreloadData(preloadId, preloadType);
283             ctxIn.mergeJson("preload-data", objectMapper.writeValueAsString(preloadData));
284         } catch (JsonProcessingException e) {
285             log.error("exiting {} due to parse error on saved config preload data", svcOperation);
286             resp.setResponseCode("500");
287             resp.setResponseMessage("internal error");
288             resp.setAckFinalIndicator("Y");
289             retval.setOutput(resp);
290             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
291         }
292
293         // Add operational tree data to SvcLogicContext
294         try {
295             preloadData = getOperationalPreloadData(preloadId, preloadType);
296             ctxIn.mergeJson("operational-data", objectMapper.writeValueAsString(preloadData));
297         } catch (JsonProcessingException e) {
298             log.error("exiting {} due to parse error on saved operational preload data", svcOperation);
299             resp.setResponseCode("500");
300             resp.setResponseMessage("internal error");
301             resp.setAckFinalIndicator("Y");
302             retval.setOutput(resp);
303             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
304         }
305
306         // Call DG
307         try {
308             // Any of these can throw a nullpointer exception
309             // execute should only throw a SvcLogicException
310             SvcLogicContext ctxOut = svc.execute(MODULE_NAME, svcOperation, null, "sync", ctxIn);
311             Properties respProps = ctxOut.toProperties();
312
313             resp.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
314             resp.setResponseCode(respProps.getProperty("error-code", "200"));
315             resp.setResponseMessage(respProps.getProperty("error-message", "SUCCESS"));
316
317             if ("200".equals(resp.getResponseCode())) {
318                 // If DG returns success, update database
319                 String ctxJson = ctxOut.toJsonString("preload-data");
320                 GenericResourceApiPreloaddataPreloadData preloadToLoad = objectMapper.readValue(ctxJson,
321                         GenericResourceApiPreloaddataPreloadData.class);
322                 saveConfigPreloadData(preloadId, preloadType, preloadToLoad);
323                 saveOperationalPreloadData(preloadId, preloadType, preloadToLoad);
324             }
325
326         } catch (NullPointerException npe) {
327             resp.setAckFinalIndicator("true");
328             resp.setResponseCode("500");
329             resp.setResponseMessage("Check that you populated module, rpc and or mode correctly.");
330         } catch (SvcLogicException e) {
331             resp.setAckFinalIndicator("true");
332             resp.setResponseCode("500");
333             resp.setResponseMessage(e.getMessage());
334         } catch (JsonMappingException e) {
335             resp.setAckFinalIndicator("true");
336             resp.setResponseCode("500");
337             resp.setResponseMessage(e.getMessage());
338         } catch (JsonProcessingException e) {
339             resp.setAckFinalIndicator("true");
340             resp.setResponseCode("500");
341             resp.setResponseMessage(e.getMessage());
342         }
343
344         retval.setOutput(resp);
345         return (new ResponseEntity<>(retval, HttpStatus.valueOf(Integer.parseInt(resp.getResponseCode()))));
346     }
347
348     private boolean hasInvalidPreloadNetwork(
349             GenericResourceApiPreloadnetworktopologyoperationInputBodyparam preloadData) {
350         return ((preloadData == null) || (preloadData.getInput() == null)
351                 || (preloadData.getInput().getPreloadNetworkTopologyInformation() == null));
352     }
353
354     private boolean hasInvalidPreloadNetwork(
355             GenericResourceApiPreloadvfmoduletopologyoperationInputBodyparam preloadData) {
356         return ((preloadData == null) || (preloadData.getInput() == null)
357                 || (preloadData.getInput().getPreloadVfModuleTopologyInformation() == null));
358     }
359
360     private boolean hasInvalidServiceId(GenericResourceApiServiceOperationInformation input) {
361
362         return input == null || input.getServiceInformation() == null
363                 || input.getServiceInformation().getServiceInstanceId() == null
364                 || input.getServiceInformation().getServiceInstanceId().length() == 0;
365     }
366
367     private boolean hasInvalidServiceId(GenericResourceApiNetworkOperationInformation input) {
368
369         return input == null || input.getServiceInformation() == null
370                 || input.getServiceInformation().getServiceInstanceId() == null
371                 || input.getServiceInformation().getServiceInstanceId().length() == 0;
372     }
373
374     private GenericResourceApiPreloaddataPreloadData getConfigPreloadData(String preloadId, String preloadType)
375             throws JsonProcessingException {
376
377         List<ConfigPreloadData> configPreloadData = configPreloadDataRepository.findByPreloadIdAndPreloadType(preloadId,
378                 preloadType);
379
380         if (configPreloadData.isEmpty()) {
381             return (null);
382         } else {
383             return (objectMapper.readValue(configPreloadData.get(0).getPreloadData(),
384                     GenericResourceApiPreloaddataPreloadData.class));
385         }
386     }
387
388     private GenericResourceApiPreloaddataPreloadData getOperationalPreloadData(String preloadId, String preloadType)
389             throws JsonProcessingException {
390
391         List<OperationalPreloadData> configPreloadData = operationalPreloadDataRepository
392                 .findByPreloadIdAndPreloadType(preloadId, preloadType);
393
394         if (configPreloadData.isEmpty()) {
395             return (null);
396         } else {
397             return (objectMapper.readValue(configPreloadData.get(0).getPreloadData(),
398                     GenericResourceApiPreloaddataPreloadData.class));
399         }
400     }
401
402     private void saveConfigPreloadData(String preloadId, String preloadType,
403             GenericResourceApiPreloaddataPreloadData preloadData) throws JsonProcessingException {
404
405         configPreloadDataRepository.deleteByPreloadIdAndPreloadType(preloadId, preloadType);
406         configPreloadDataRepository
407                 .save(new ConfigPreloadData(preloadId, preloadType, objectMapper.writeValueAsString(preloadData)));
408
409     }
410
411     private void saveOperationalPreloadData(String preloadId, String preloadType,
412             GenericResourceApiPreloaddataPreloadData preloadData) throws JsonProcessingException {
413
414         operationalPreloadDataRepository.deleteByPreloadIdAndPreloadType(preloadId, preloadType);
415         operationalPreloadDataRepository
416                 .save(new OperationalPreloadData(preloadId, preloadType, objectMapper.writeValueAsString(preloadData)));
417
418     }
419
420     private GenericResourceApiServicedataServiceData getConfigServiceData(String svcInstanceId) throws JsonProcessingException {
421
422         List<ConfigServices> configServices = configServicesRepository.findBySvcInstanceId(svcInstanceId);
423
424         if (configServices.isEmpty()) {
425             return (null);
426         } else {
427             return (objectMapper.readValue(configServices.get(0).getSvcData(),
428                     GenericResourceApiServicedataServiceData.class));
429         }
430     }
431
432
433     @Override
434     public ResponseEntity<GenericResourceApiNetworkTopologyOperation> operationsGENERICRESOURCEAPInetworkTopologyOperationPost(
435             @Valid GenericResourceApiNetworkOperationInformationBodyparam input)
436             throws RestException {
437         final String svcOperation = "network-topology-operation";
438         GenericResourceApiNetworkTopologyOperation retval = new GenericResourceApiNetworkTopologyOperation();
439         GenericResourceApiNetworktopologyoperationOutput resp = new GenericResourceApiNetworktopologyoperationOutput();
440
441         log.info(CALLED_STR, svcOperation);
442         // Verify input contains service instance id
443         if (hasInvalidServiceId(input.getInput())) {
444             log.debug("exiting {} because of null or empty service-instance-id", svcOperation);
445
446             resp.setResponseCode("404");
447             resp.setResponseMessage("null or empty service-instance-id");
448             resp.setAckFinalIndicator("Y");
449
450             retval.setOutput(resp);
451
452             return new ResponseEntity<>(retval, HttpStatus.OK);
453         }
454
455         String svcInstanceId = input.getInput().getServiceInformation().getServiceInstanceId();
456
457         SvcLogicContext ctxIn = new SvcLogicContext();
458
459         // Add input to SvcLogicContext
460         try {
461             ctxIn.mergeJson(svcOperation + "-input", objectMapper.writeValueAsString(input.getInput()));
462         } catch (JsonProcessingException e) {
463             log.error("exiting {} due to parse error on input data", svcOperation);
464             resp.setResponseCode("500");
465             resp.setResponseMessage("internal error");
466             resp.setAckFinalIndicator("Y");
467             retval.setOutput(resp);
468             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
469         }
470
471         // Add config tree data to SvcLogicContext
472         List<ConfigServices> configServices = configServicesRepository.findBySvcInstanceId(svcInstanceId);
473         ConfigServices configService = null;
474         if (configServices != null && !configServices.isEmpty()) {
475             configService = configServices.get(0);
476             ctxIn.mergeJson("service-data", configService.getSvcData());
477         } else {
478             log.debug("exiting {} because the service-instance does not have any service data in SDN", svcOperation);
479
480             resp.setResponseCode("404");
481             resp.setResponseMessage("invalid input: the service-instance does not have any service data in SDNC");
482             resp.setAckFinalIndicator("Y");
483
484             retval.setOutput(resp);
485
486             return new ResponseEntity<>(retval, HttpStatus.OK);
487         }
488
489         // Add operational tree data to SvcLogicContext
490         List<OperationalServices> operServices = operationalServicesRepository.findBySvcInstanceId(svcInstanceId);
491         OperationalServices operService = null;
492         boolean saveOperationalData = false;
493
494         if (operServices != null && !operServices.isEmpty()) {
495             operService = operServices.get(0);
496             ctxIn.mergeJson("operational-data", operService.getSvcData());
497         } else {
498             operService = new OperationalServices(svcInstanceId, null, null);
499         }
500
501         // Update service status info in config entry from input
502         configService.setServiceStatusAction(input.getInput().getRequestInformation().getRequestAction().toString());
503         configService.setServiceStatusRpcAction(input.getInput().getSdncRequestHeader().getSvcAction().toString());
504         configService.setServiceStatusRpcName(svcOperation);
505
506         // Call DG
507         try {
508             // Any of these can throw a nullpointer exception
509             // execute should only throw a SvcLogicException
510             SvcLogicContext ctxOut = svc.execute(MODULE_NAME, svcOperation, null, "sync", ctxIn);
511             Properties respProps = ctxOut.toProperties();
512
513             resp.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
514             resp.setResponseCode(respProps.getProperty("error-code", "200"));
515             resp.setResponseMessage(respProps.getProperty("error-message", "SUCCESS"));
516             configService.setServiceStatusRequestStatus(GenericResourceApiRequestStatusEnumeration.SYNCCOMPLETE.toString());
517
518             if ("200".equals(resp.getResponseCode())) {
519                 // If DG returns success, update svcData in config and operational trees
520                 // and remember to save operational data.
521                 String ctxJson = ctxOut.toJsonString("service-data");
522                 configService.setSvcData(ctxJson);
523                 operService.setSvcData(ctxJson);
524                 saveOperationalData = true;
525             }
526
527         } catch (NullPointerException npe) {
528             resp.setAckFinalIndicator("true");
529             resp.setResponseCode("500");
530             resp.setResponseMessage("Check that you populated module, rpc and or mode correctly.");
531         } catch (SvcLogicException e) {
532             resp.setAckFinalIndicator("true");
533             resp.setResponseCode("500");
534             resp.setResponseMessage(e.getMessage());
535         }
536
537         // Update status in config services entry
538         
539         configService.setServiceStatusFinalIndicator(resp.getAckFinalIndicator());
540         configService.setServiceStatusResponseCode(resp.getResponseCode());
541         configService.setServiceStatusResponseMessage(resp.getResponseMessage());
542         configService.setServiceStatusResponseTimestamp(Iso8601Util.now());
543
544         // Update config tree
545         configServicesRepository.save(configService);
546
547         // If necessary, sync status to operation service entry and save
548         if (saveOperationalData) {
549             operService.setServiceStatus(configService.getServiceStatus());
550             operationalServicesRepository.save(operService);
551         }
552         retval.setOutput(resp);
553         return (new ResponseEntity<>(retval, HttpStatus.OK));
554     }
555
556     @Override
557     public ResponseEntity<GenericResourceApiServiceTopologyOperation> operationsGENERICRESOURCEAPIserviceTopologyOperationPost(
558             @Valid GenericResourceApiServiceOperationInformationBodyparam input) throws RestException {
559         final String svcOperation = "service-topology-operation";
560         GenericResourceApiServiceTopologyOperation retval = new GenericResourceApiServiceTopologyOperation();
561         GenericResourceApiServicetopologyoperationOutput resp = new GenericResourceApiServicetopologyoperationOutput();
562
563         log.info(CALLED_STR, svcOperation);
564
565         // Verify input contains service instance id
566         if (hasInvalidServiceId(input.getInput())) {
567             log.debug("exiting {} because of null or empty service-instance-id", svcOperation);
568
569             resp.setResponseCode("404");
570             resp.setResponseMessage("null or empty service-instance-id");
571             resp.setAckFinalIndicator("Y");
572
573             retval.setOutput(resp);
574
575             return new ResponseEntity<>(retval, HttpStatus.OK);
576         }
577
578         String svcInstanceId = input.getInput().getServiceInformation().getServiceInstanceId();
579
580         SvcLogicContext ctxIn = new SvcLogicContext();
581
582         // Add input to SvcLogicContext
583         try {
584             ctxIn.mergeJson(svcOperation + "-input", objectMapper.writeValueAsString(input.getInput()));
585         } catch (JsonProcessingException e) {
586             log.error("exiting {} due to parse error on input data", svcOperation);
587             resp.setResponseCode("500");
588             resp.setResponseMessage("internal error");
589             resp.setAckFinalIndicator("Y");
590             retval.setOutput(resp);
591             return new ResponseEntity<>(retval, HttpStatus.INTERNAL_SERVER_ERROR);
592         }
593
594         // Add config tree data to SvcLogicContext
595         List<ConfigServices> configServices = configServicesRepository.findBySvcInstanceId(svcInstanceId);
596         ConfigServices configService = null;
597         if (configServices != null && !configServices.isEmpty()) {
598             configService = configServices.get(0);
599             if (configService.getSvcData() != null) {
600                 ctxIn.mergeJson("service-data", configService.getSvcData());
601             }
602         } else {
603             configService = new ConfigServices(svcInstanceId, null);
604         }
605
606         // Add operational tree data to SvcLogicContext
607         List<OperationalServices> operServices = operationalServicesRepository.findBySvcInstanceId(svcInstanceId);
608         OperationalServices operService = null;
609         boolean saveOperationalData = false;
610
611         if (operServices != null && !operServices.isEmpty()) {
612             operService = operServices.get(0);
613             ctxIn.mergeJson("operational-data", operService.getSvcData());
614         } else {
615             operService = new OperationalServices(svcInstanceId, null, null);
616         }
617
618         // Update service status info in config entry from input
619         configService.setServiceStatusAction(input.getInput().getRequestInformation().getRequestAction().toString());
620         configService.setServiceStatusRpcAction(input.getInput().getSdncRequestHeader().getSvcAction().toString());
621         configService.setServiceStatusRpcName(svcOperation);
622
623
624         // Call DG
625         try {
626             // Any of these can throw a nullpointer exception
627             // execute should only throw a SvcLogicException
628             SvcLogicContext ctxOut = svc.execute(MODULE_NAME, svcOperation, null, "sync", ctxIn);
629             Properties respProps = ctxOut.toProperties();
630
631             resp.setAckFinalIndicator(respProps.getProperty("ack-final-indicator", "Y"));
632             resp.setResponseCode(respProps.getProperty("error-code", "200"));
633             resp.setResponseMessage(respProps.getProperty("error-message", "SUCCESS"));
634             configService.setServiceStatusRequestStatus(GenericResourceApiRequestStatusEnumeration.SYNCCOMPLETE.toString());
635
636             if ("200".equals(resp.getResponseCode())) {
637                 // If DG returns success, update svcData in config and operational trees
638                 // and remember to save operational data.
639                 String ctxJson = ctxOut.toJsonString("service-data");
640                 configService.setSvcData(ctxJson);
641                 operService.setSvcData(ctxJson);
642                 saveOperationalData = true;
643             }
644
645         } catch (NullPointerException npe) {
646             resp.setAckFinalIndicator("true");
647             resp.setResponseCode("500");
648             resp.setResponseMessage("Check that you populated module, rpc and or mode correctly.");
649         } catch (SvcLogicException e) {
650             resp.setAckFinalIndicator("true");
651             resp.setResponseCode("500");
652             resp.setResponseMessage(e.getMessage());
653         }
654
655         // Update status in config services entry
656         
657         configService.setServiceStatusFinalIndicator(resp.getAckFinalIndicator());
658         configService.setServiceStatusResponseCode(resp.getResponseCode());
659         configService.setServiceStatusResponseMessage(resp.getResponseMessage());
660         configService.setServiceStatusResponseTimestamp(Iso8601Util.now());
661
662         // Update config tree
663         configServicesRepository.save(configService);
664
665         // If necessary, sync status to operation service entry and save
666         if (saveOperationalData) {
667             operService.setServiceStatus(configService.getServiceStatus());
668             operationalServicesRepository.save(operService);
669         }
670         retval.setOutput(resp);
671         return (new ResponseEntity<>(retval, HttpStatus.OK));
672
673     }
674
675 }