Fix persistence when karaf is restarted
[transportpce.git] / servicehandler / src / main / java / org / opendaylight / transportpce / servicehandler / service / ServiceDataStoreOperationsImpl.java
1 /*
2  * Copyright © 2017 Orange, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.transportpce.servicehandler.service;
9
10 import com.google.common.util.concurrent.FluentFuture;
11 import java.util.Optional;
12 import java.util.concurrent.ExecutionException;
13 import java.util.concurrent.TimeUnit;
14 import java.util.concurrent.TimeoutException;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.mdsal.binding.api.DataBroker;
17 import org.opendaylight.mdsal.binding.api.WriteTransaction;
18 import org.opendaylight.mdsal.common.api.CommitInfo;
19 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
20 import org.opendaylight.transportpce.common.OperationResult;
21 import org.opendaylight.transportpce.common.Timeouts;
22 import org.opendaylight.transportpce.servicehandler.ModelMappingUtils;
23 import org.opendaylight.transportpce.servicehandler.ServiceInput;
24 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925.PathComputationRequestOutput;
25 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.state.types.rev191129.State;
26 import org.opendaylight.yang.gen.v1.http.org.openroadm.equipment.states.types.rev191129.AdminStates;
27 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceCreateInput;
28 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceList;
29 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.ServiceListBuilder;
30 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.TempServiceCreateInput;
31 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.TempServiceList;
32 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.TempServiceListBuilder;
33 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.Services;
34 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.ServicesBuilder;
35 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526.service.list.ServicesKey;
36 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service.path.PathDescription;
37 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
38 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
39 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsBuilder;
40 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
41 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
42 import org.osgi.service.component.annotations.Activate;
43 import org.osgi.service.component.annotations.Component;
44 import org.osgi.service.component.annotations.Reference;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48 @Component(immediate = true)
49 public class ServiceDataStoreOperationsImpl implements ServiceDataStoreOperations {
50     private static final Logger LOG = LoggerFactory.getLogger(ServiceDataStoreOperationsImpl.class);
51     private static final String CREATE_MSG = "create";
52     private static final String DELETING_SERVICE_MSG = "Deleting '{}' Service";
53     private DataBroker dataBroker;
54
55     // This is class is public so that these messages can be accessed from Junit (avoid duplications).
56     public static final class LogMessages {
57
58         public static final String SUCCESSFUL_MESSAGE;
59         public static final String SERVICE_NOT_FOUND;
60         public static final String SERVICE_PATH_NOT_FOUND;
61
62         // Static blocks are generated once and spare memory.
63         static {
64             SUCCESSFUL_MESSAGE = "Successful";
65             SERVICE_NOT_FOUND = "Service not found";
66             SERVICE_PATH_NOT_FOUND = "Service path not found";
67         }
68
69         public static String failedTo(String action, String serviceName) {
70             return  "Failed to " + action + " service " + serviceName;
71         }
72
73         private LogMessages() {
74         }
75     }
76
77
78     @Activate
79     public ServiceDataStoreOperationsImpl(@Reference DataBroker dataBroker) {
80         this.dataBroker = dataBroker;
81     }
82
83     @Override
84     public void initialize() {
85         initializeServiceList();
86         initializeTempServiceList();
87     }
88
89     private void initializeServiceList() {
90         try {
91             LOG.info("initializing service registry");
92             WriteTransaction transaction = this.dataBroker.newWriteOnlyTransaction();
93             transaction.merge(
94                 LogicalDatastoreType.OPERATIONAL,
95                 InstanceIdentifier.create(ServiceList.class),
96                 new ServiceListBuilder().build());
97             FluentFuture<? extends @NonNull CommitInfo> future = transaction.commit();
98             future.get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
99         } catch (InterruptedException | ExecutionException | TimeoutException e) {
100             LOG.error("init failed: ", e);
101         }
102     }
103
104     private void initializeTempServiceList() {
105         try {
106             LOG.info("initializing temp service registry");
107             WriteTransaction transaction = this.dataBroker.newWriteOnlyTransaction();
108             transaction.merge(
109                 LogicalDatastoreType.OPERATIONAL,
110                 InstanceIdentifier.create(TempServiceList.class),
111                 new TempServiceListBuilder().build());
112             FluentFuture<? extends @NonNull CommitInfo> future = transaction.commit();
113             future.get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
114         } catch (InterruptedException | ExecutionException | TimeoutException e) {
115             LOG.error("init failed: ", e);
116         }
117     }
118
119     @Override
120     public Optional<Services> getService(String serviceName) {
121         try {
122             return this.dataBroker.newReadOnlyTransaction()
123                     .read(
124                         LogicalDatastoreType.OPERATIONAL,
125                         InstanceIdentifier.create(ServiceList.class)
126                             .child(Services.class, new ServicesKey(serviceName))
127                         )
128                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
129         } catch (InterruptedException | ExecutionException | TimeoutException e) {
130             LOG.warn("Reading service {} failed:", serviceName, e);
131         }
132         return Optional.empty();
133     }
134
135     @Override
136     public Optional<ServiceList> getServices() {
137         try {
138             return this.dataBroker.newReadOnlyTransaction()
139                     .read(
140                         LogicalDatastoreType.OPERATIONAL,
141                         InstanceIdentifier.create(ServiceList.class))
142                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
143         } catch (InterruptedException | ExecutionException | TimeoutException e) {
144             LOG.warn("Reading services failed:", e);
145         }
146         return Optional.empty();
147     }
148
149     @Override
150     public Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
151             .temp.service.list.Services> getTempService(String serviceName) {
152         try {
153             return this.dataBroker.newReadOnlyTransaction()
154                     .read(
155                         LogicalDatastoreType.OPERATIONAL,
156                         InstanceIdentifier.create(TempServiceList.class)
157                             .child(
158                                 org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
159                                     .temp.service.list.Services.class,
160                                 new org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
161                                     .temp.service.list.ServicesKey(serviceName)))
162                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
163         } catch (InterruptedException | ExecutionException | TimeoutException e) {
164             LOG.warn("Reading service {} failed:", serviceName, e);
165         }
166         return Optional.empty();
167     }
168
169     @Override
170     public OperationResult deleteService(String serviceName) {
171         LOG.debug(DELETING_SERVICE_MSG, serviceName);
172         try {
173             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
174             writeTx.delete(
175                 LogicalDatastoreType.OPERATIONAL,
176                 InstanceIdentifier.create(ServiceList.class)
177                     .child(Services.class, new ServicesKey(serviceName)));
178             writeTx.commit().get(Timeouts.DATASTORE_DELETE, TimeUnit.MILLISECONDS);
179             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
180         } catch (TimeoutException | InterruptedException | ExecutionException e) {
181             LOG.warn("deleteService : {}", LogMessages.failedTo("delete", serviceName), e);
182             return OperationResult.failed(LogMessages.failedTo("delete", serviceName));
183         }
184     }
185
186     @Override
187     public OperationResult deleteTempService(String commonId) {
188         LOG.debug(DELETING_SERVICE_MSG, commonId);
189         try {
190             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
191             writeTx.delete(
192                 LogicalDatastoreType.OPERATIONAL,
193                 InstanceIdentifier.create(TempServiceList.class)
194                     .child(
195                         org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
196                             .temp.service.list.Services.class,
197                         new org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
198                             .temp.service.list.ServicesKey(commonId)));
199             writeTx.commit().get(Timeouts.DATASTORE_DELETE, TimeUnit.MILLISECONDS);
200             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
201         } catch (TimeoutException | InterruptedException | ExecutionException e) {
202             LOG.warn("deleteTempService : {}", LogMessages.failedTo("delete Temp", commonId), e);
203             return OperationResult.failed(LogMessages.failedTo("delete Temp", commonId));
204         }
205     }
206
207     @Override
208     public OperationResult modifyService(String serviceName, State operationalState, AdminStates administrativeState) {
209         LOG.debug("Modifying '{}' Service", serviceName);
210         Optional<Services> readService = getService(serviceName);
211         if (readService.isEmpty()) {
212             LOG.warn("modifyService: {}", LogMessages.SERVICE_NOT_FOUND);
213             return OperationResult.failed(LogMessages.SERVICE_NOT_FOUND);
214         }
215         try {
216             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
217             writeTx.merge(
218                 LogicalDatastoreType.OPERATIONAL,
219                 InstanceIdentifier.create(ServiceList.class)
220                     .child(Services.class, new ServicesKey(serviceName)),
221                 new ServicesBuilder(readService.orElseThrow())
222                     .setOperationalState(operationalState)
223                     .setAdministrativeState(administrativeState)
224                     .build());
225             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
226             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
227         } catch (TimeoutException | InterruptedException | ExecutionException e) {
228             LOG.warn("modifyService : {}", LogMessages.failedTo("modify", serviceName), e);
229             return OperationResult.failed(LogMessages.failedTo("modify", serviceName));
230         }
231     }
232
233     @Override
234     public OperationResult modifyTempService(
235             String serviceName, State operationalState, AdminStates administrativeState) {
236         LOG.debug("Modifying '{}' Temp Service", serviceName);
237         Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
238                 .temp.service.list.Services> readService = getTempService(serviceName);
239         if (readService.isEmpty()) {
240             LOG.warn("modifyTempService: {}", LogMessages.SERVICE_NOT_FOUND);
241             return OperationResult.failed(LogMessages.SERVICE_NOT_FOUND);
242         }
243         try {
244             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
245             writeTx.merge(
246                 LogicalDatastoreType.OPERATIONAL,
247                 InstanceIdentifier.create(TempServiceList.class)
248                     .child(
249                         org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
250                             .temp.service.list.Services.class,
251                         new org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
252                             .temp.service.list.ServicesKey(serviceName)),
253                 new org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
254                         .temp.service.list.ServicesBuilder(readService.orElseThrow())
255                     .setOperationalState(operationalState)
256                     .setAdministrativeState(administrativeState)
257                     .build());
258             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
259             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
260         } catch (TimeoutException | InterruptedException | ExecutionException e) {
261             LOG.warn("modifyTempService : {}", LogMessages.failedTo("modify Temp", serviceName), e);
262             return OperationResult.failed(LogMessages.failedTo("modify Temp", serviceName));
263         }
264     }
265
266     @Override
267     public OperationResult createService(ServiceCreateInput serviceCreateInput) {
268         LOG.debug("Writing '{}' Service", serviceCreateInput.getServiceName());
269         try {
270             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
271             writeTx.put(
272                 LogicalDatastoreType.OPERATIONAL,
273                 InstanceIdentifier.create(ServiceList.class)
274                     .child(Services.class, new ServicesKey(serviceCreateInput.getServiceName())),
275                 ModelMappingUtils.mappingServices(serviceCreateInput, null));
276             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
277             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
278         } catch (TimeoutException | InterruptedException | ExecutionException e) {
279             LOG.warn("createService : {}", LogMessages.failedTo(CREATE_MSG, serviceCreateInput.getServiceName()), e);
280             return OperationResult.failed(LogMessages.failedTo(CREATE_MSG, serviceCreateInput.getServiceName()));
281         }
282     }
283
284     @Override
285     public OperationResult createTempService(
286             TempServiceCreateInput tempServiceCreateInput,
287             org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.pce.rev230925
288                     .service.path.rpc.result.PathDescription pathDescription) {
289         LOG.debug("Writing '{}' Temp Service", tempServiceCreateInput.getCommonId());
290         try {
291             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
292             writeTx.put(
293                 LogicalDatastoreType.OPERATIONAL,
294                 InstanceIdentifier.create(TempServiceList.class)
295                     .child(org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
296                             .temp.service.list.Services.class,
297                         new org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev230526
298                             .temp.service.list.ServicesKey(tempServiceCreateInput.getCommonId())),
299                 ModelMappingUtils.mappingServices(tempServiceCreateInput, pathDescription));
300             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
301             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
302         } catch (TimeoutException | InterruptedException | ExecutionException e) {
303             LOG.warn("createTempService : {}",
304                     LogMessages.failedTo("create Temp", tempServiceCreateInput.getCommonId()), e);
305             return OperationResult.failed(LogMessages.failedTo("create Temp", tempServiceCreateInput.getCommonId()));
306         }
307     }
308
309     @Override
310     public Optional<ServicePathList> getServicePaths() {
311         LOG.debug("Retrieving list of ServicePath...");
312         try {
313             return this.dataBroker.newReadOnlyTransaction()
314                     .read(
315                         LogicalDatastoreType.OPERATIONAL,
316                         InstanceIdentifier.create(ServicePathList.class))
317                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
318         } catch (InterruptedException | ExecutionException | TimeoutException e) {
319             LOG.error("Reading service path list failed. Error={}", e.getMessage());
320         }
321         return Optional.empty();
322     }
323
324     @Override
325     public Optional<ServicePaths> getServicePath(String serviceName) {
326         LOG.debug("Retrieving service path of service {}", serviceName);
327         try {
328             return this.dataBroker.newReadOnlyTransaction()
329                     .read(
330                         LogicalDatastoreType.OPERATIONAL,
331                         InstanceIdentifier.create(ServicePathList.class)
332                             .child(ServicePaths.class, new ServicePathsKey(serviceName)))
333                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
334         } catch (InterruptedException | ExecutionException | TimeoutException e) {
335             LOG.error("Reading service path failed. Error={}", e.getMessage());
336         }
337         return Optional.empty();
338     }
339
340     @Override
341     public OperationResult createServicePath(ServiceInput serviceInput, PathComputationRequestOutput outputFromPce) {
342         LOG.debug("Writing '{}' ServicePath ", serviceInput.getServiceName());
343         try {
344             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
345             writeTx.put(
346                 LogicalDatastoreType.OPERATIONAL,
347                 InstanceIdentifier.create(ServicePathList.class)
348                     .child(ServicePaths.class, new ServicePathsKey(serviceInput.getServiceName())),
349                 ModelMappingUtils.mappingServicePaths(serviceInput, outputFromPce));
350             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
351             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
352         } catch (TimeoutException | InterruptedException | ExecutionException e) {
353             LOG.warn("createServicePath : {}",
354                     LogMessages.failedTo("create servicePath", serviceInput.getCommonId()), e);
355             return OperationResult.failed(LogMessages.failedTo("create servicePath", serviceInput.getCommonId()));
356         }
357     }
358
359     @Override
360     public OperationResult modifyServicePath(PathDescription pathDescription, String serviceName) {
361         LOG.debug("Updating servicePath because of a change in the openroadm-topology");
362         Optional<ServicePaths> readServicePath = getServicePath(serviceName);
363         if (readServicePath.isEmpty()) {
364             LOG.warn("modifyServicePath: {}", LogMessages.SERVICE_PATH_NOT_FOUND);
365             return OperationResult.failed(LogMessages.SERVICE_PATH_NOT_FOUND);
366         }
367         try {
368             WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
369             writeTx.merge(
370                 LogicalDatastoreType.OPERATIONAL,
371                 InstanceIdentifier.create(ServicePathList.class)
372                     .child(ServicePaths.class, new ServicePathsKey(serviceName)),
373                 new ServicePathsBuilder()
374                     .setServiceAEnd(readServicePath.orElseThrow().getServiceAEnd())
375                     .setServiceHandlerHeader(readServicePath.orElseThrow().getServiceHandlerHeader())
376                     .setServicePathName(readServicePath.orElseThrow().getServicePathName())
377                     .setServiceZEnd(readServicePath.orElseThrow().getServiceZEnd())
378                     .setSupportingServiceName(readServicePath.orElseThrow().getSupportingServiceName())
379                     .setEquipmentSrgs(readServicePath.orElseThrow().getEquipmentSrgs())
380                     .setFiberSpanSrlgs(readServicePath.orElseThrow().getFiberSpanSrlgs())
381                     .setHardConstraints(readServicePath.orElseThrow().getHardConstraints())
382                     .setLatency(readServicePath.orElseThrow().getLatency())
383                     .setPathDescription(pathDescription)
384                     .setPceRoutingMetric(readServicePath.orElseThrow().getPceRoutingMetric())
385                     .setSoftConstraints(readServicePath.orElseThrow().getSoftConstraints())
386                     .build());
387             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
388             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
389         } catch (TimeoutException | InterruptedException | ExecutionException e) {
390             LOG.warn("modifyServicePath : {}", LogMessages.failedTo("modify service path", serviceName), e);
391             return OperationResult.failed(LogMessages.failedTo("modify service path", serviceName));
392         }
393     }
394
395     @Override
396     public OperationResult deleteServicePath(String serviceName) {
397         InstanceIdentifier<ServicePaths> servicePathsIID =
398             InstanceIdentifier.create(ServicePathList.class)
399                 .child(ServicePaths.class, new ServicePathsKey(serviceName));
400         LOG.debug("Deleting service from {}", servicePathsIID);
401         WriteTransaction servicePathsWriteTx = this.dataBroker.newWriteOnlyTransaction();
402         servicePathsWriteTx.delete(LogicalDatastoreType.OPERATIONAL, servicePathsIID);
403         try {
404             servicePathsWriteTx.commit().get(Timeouts.DATASTORE_DELETE, TimeUnit.MILLISECONDS);
405             return OperationResult.ok(LogMessages.SUCCESSFUL_MESSAGE);
406         } catch (InterruptedException | ExecutionException | TimeoutException e) {
407             LOG.error("deleteServicePath : {}", LogMessages.failedTo("delete servicePath", serviceName), e);
408             return OperationResult.failed(LogMessages.failedTo("delete servicePath", serviceName));
409         }
410     }
411
412     /*
413      * Write or Modify or Delete Service from/to SreviceList.
414      *
415      * @param serviceName Name of service
416      *
417      * @param input ServiceCreateInput
418      *
419      * @param output PathComputationRequestOutput
420      *
421      * @param choice 0 - Modify 1 - Delete 2 - Write
422      *
423      * @return String operations result, null if ok or not otherwise
424      */
425     @Deprecated
426     @Override
427     public String writeOrModifyOrDeleteServiceList(
428             String serviceName, ServiceCreateInput input, PathComputationRequestOutput output, int choice) {
429         LOG.debug("WriteOrModifyOrDeleting '{}' Service", serviceName);
430         WriteTransaction writeTx = this.dataBroker.newWriteOnlyTransaction();
431         Optional<Services> readService = getService(serviceName);
432         /*
433          * Write Service.
434          */
435         if (readService.isEmpty()) {
436             if (choice != 2) {
437                 LOG.warn("writeOrModifyOrDeleteServiceList: {}", LogMessages.SERVICE_NOT_FOUND);
438                 return LogMessages.SERVICE_NOT_FOUND;
439             }
440             LOG.debug("Writing '{}' Service", serviceName);
441             writeTx.put(
442                 LogicalDatastoreType.OPERATIONAL,
443                 InstanceIdentifier.create(ServiceList.class)
444                     .child(Services.class, new ServicesKey(serviceName)),
445                 ModelMappingUtils.mappingServices(input, null));
446             try {
447                 writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
448                 return null;
449             } catch (InterruptedException | TimeoutException | ExecutionException e) {
450                 LOG.error("writeOrModifyOrDeleteServiceList : {}", LogMessages.failedTo(CREATE_MSG, serviceName), e);
451                 return LogMessages.failedTo(CREATE_MSG, serviceName);
452             }
453         }
454
455         /*
456          * Modify / Delete Service.
457          */
458         InstanceIdentifier<Services> iid =
459             InstanceIdentifier.create(ServiceList.class).child(Services.class, new ServicesKey(serviceName));
460         String action = null;
461         switch (choice) {
462             case 0 : /* Modify. */
463                 LOG.debug("Modifying '{}' Service", serviceName);
464                 writeTx.merge(
465                     LogicalDatastoreType.OPERATIONAL,
466                     iid,
467                     new ServicesBuilder(readService.orElseThrow())
468                         .setOperationalState(State.InService)
469                         .setAdministrativeState(AdminStates.InService)
470                         .build());
471                 action = "modifyService";
472                 break;
473             case 1 : /* Delete */
474                 LOG.debug(DELETING_SERVICE_MSG, serviceName);
475                 writeTx.delete(LogicalDatastoreType.OPERATIONAL, iid);
476                 action = "deleteService";
477                 break;
478             default:
479                 LOG.debug("No choice found");
480                 break;
481         }
482         try {
483             writeTx.commit().get(Timeouts.DATASTORE_WRITE, TimeUnit.MILLISECONDS);
484         } catch (InterruptedException | ExecutionException | TimeoutException e) {
485             LOG.error("writeOrModifyOrDeleteServiceList : {}", LogMessages.failedTo(action, serviceName), e);
486             return LogMessages.failedTo(action, serviceName);
487         }
488
489         return null;
490     }
491 }