remove dead code pointed out by sonar
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
1 /*
2  * Copyright © 2017 AT&T 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.renderer.provisiondevice;
9
10 import com.google.common.base.Optional;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.ListeningExecutorService;
14 import com.google.common.util.concurrent.MoreExecutors;
15
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.concurrent.Callable;
19 import java.util.concurrent.ExecutionException;
20 import java.util.concurrent.Executors;
21 import java.util.concurrent.Future;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24
25 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
26 import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
27 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
28 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
29 import org.opendaylight.transportpce.common.OperationResult;
30 import org.opendaylight.transportpce.common.ResponseCodes;
31 import org.opendaylight.transportpce.common.StringConstants;
32 import org.opendaylight.transportpce.common.Timeouts;
33 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
34 import org.opendaylight.transportpce.renderer.NetworkModelWavelengthService;
35 import org.opendaylight.transportpce.renderer.ServicePathInputData;
36 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceDeleteInput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceDeleteOutput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceImplementationRequestInput;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceImplementationRequestOutput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceRpcResultSp;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev171017.ServiceRpcResultSpBuilder;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
57 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.RpcStatusEx;
58 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.ServicePathNotificationTypes;
59 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev171016.service.path.PathDescription;
60 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
61 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
62 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev170907.olm.get.pm.input.ResourceIdentifierBuilder;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev170907.olm.renderer.input.Nodes;
65 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
66 import org.opendaylight.yangtools.yang.common.RpcResult;
67 import org.slf4j.Logger;
68 import org.slf4j.LoggerFactory;
69
70
71 public class RendererServiceOperationsImpl implements RendererServiceOperations {
72
73     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
74     private static final String FAILED = "Failed";
75     private static final String OPERATION_FAILED = "Operation Failed";
76     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
77     private static final int NUMBER_OF_THREADS = 4;
78
79     private final DeviceRendererService deviceRenderer;
80     private final TransportpceOlmService olmService;
81     private final DataBroker dataBroker;
82     private final NotificationPublishService notificationPublishService;
83     private ListeningExecutorService executor;
84     private NetworkModelWavelengthService networkModelWavelengthService;
85     private ServiceRpcResultSp notification = null;
86
87     public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer, TransportpceOlmService olmService,
88             DataBroker dataBroker, NetworkModelWavelengthService networkModelWavelengthService,
89             NotificationPublishService notificationPublishService) {
90         this.deviceRenderer = deviceRenderer;
91         this.olmService = olmService;
92         this.dataBroker = dataBroker;
93         this.networkModelWavelengthService = networkModelWavelengthService;
94         this.notificationPublishService = notificationPublishService;
95         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
96     }
97
98     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
99             RpcStatusEx rpcStatusEx, String message) {
100         this.notification = new ServiceRpcResultSpBuilder()
101                 .setNotificationType(servicePathNotificationTypes)
102                 .setServiceName(serviceName)
103                 .setStatus(rpcStatusEx)
104                 .setStatusMessage(message)
105                 .build();
106         try {
107             notificationPublishService.putNotification(this.notification);
108         } catch (InterruptedException e) {
109             LOG.info("notification offer rejected : ", e.getMessage());
110         }
111     }
112
113     @Override
114     public ListenableFuture<ServiceImplementationRequestOutput>
115             serviceImplementation(ServiceImplementationRequestInput input) {
116         LOG.info("Calling service impl request {} {}", input.getServiceName());
117         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
118
119             @Override
120             public ServiceImplementationRequestOutput call() throws Exception {
121                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
122                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
123                 RollbackProcessor rollbackProcessor = new RollbackProcessor();
124                 ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
125                         .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
126                 ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
127                         .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
128                 List<DeviceRenderingResult> renderingResults =
129                         deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
130                 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
131                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
132                             RpcStatusEx.Failed, "Device rendering was not successful! Rendering will be rolled back.");
133                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
134                 }
135                 ServicePowerSetupInput olmPowerSetupInputAtoZ =
136                         ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
137                 ServicePowerSetupInput olmPowerSetupInputZtoA =
138                         ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
139                 olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
140                 if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
141                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
142                             RpcStatusEx.Failed,
143                             "OLM power setup was not successful! Rendering and OLM will be rolled back.");
144                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
145                 }
146                 // run service activation test twice - once on source node and once on
147                 // destination node
148                 List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
149                 Nodes sourceNode = nodes.get(0);
150                 Nodes destNode = nodes.get(nodes.size() - 1);
151                 String srcNetworkTp;
152                 String dstNetowrkTp;
153                 if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
154                     srcNetworkTp = sourceNode.getDestTp();
155                 } else {
156                     srcNetworkTp = sourceNode.getSrcTp();
157                 }
158                 if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
159                     dstNetowrkTp = destNode.getDestTp();
160                 } else {
161                     dstNetowrkTp = destNode.getSrcTp();
162                 }
163                 if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
164                         || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
165                     rollbackProcessor.rollbackAll();
166                     sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
167                             RpcStatusEx.Failed, "Service activation test failed.");
168                     return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
169                 }
170                 // If Service activation is success update Network ModelMappingUtils
171                 networkModelWavelengthService.useWavelengths(input.getPathDescription());
172                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
173                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
174                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
175             }
176         });
177
178     }
179
180     @SuppressWarnings("checkstyle:IllegalCatch")
181     public OperationResult reserveResource(PathDescription pathDescription) {
182
183         try {
184             LOG.info("Reserving resources in network model");
185             networkModelWavelengthService.useWavelengths(pathDescription);
186         } catch (Exception e) {
187             LOG.warn("Reserving resources in network model failed");
188             return OperationResult.failed("Resources reserve failed in network model");
189         }
190         return OperationResult.ok("Resources reserved successfully in network model");
191     }
192
193     @SuppressWarnings("checkstyle:IllegalCatch")
194     public OperationResult freeResource(PathDescription pathDescription) {
195
196         try {
197             networkModelWavelengthService.freeWavelengths(pathDescription);
198         } catch (Exception e) {
199             return OperationResult.failed("Resources reserve failed in network model");
200         }
201         return OperationResult.ok("Resources reserved successfully in network model");
202     }
203
204     @Override
205     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input) {
206         String serviceName = input.getServiceName();
207         LOG.info("Calling service delete request {} {}", input.getServiceName());
208         return executor.submit(new Callable<ServiceDeleteOutput>() {
209
210             @Override
211             public ServiceDeleteOutput call() throws Exception {
212                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
213                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
214                 // Obtain path description
215                 Optional<PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
216                 PathDescription pathDescription;
217                 if (pathDescriptionOpt.isPresent()) {
218                     pathDescription = pathDescriptionOpt.get();
219                 } else {
220                     LOG.error("Unable to get path description for service {}!", serviceName);
221                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
222                             RpcStatusEx.Failed, "Unable to get path description for service");
223                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
224                             OPERATION_FAILED);
225                 }
226                 ServicePathInputData servicePathInputDataAtoZ =
227                         ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
228                 ServicePathInputData servicePathInputDataZtoA =
229                         ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
230                 // OLM turn down power
231                 try {
232                     LOG.debug("Turning down power on A-to-Z path");
233                     sendNotifications(ServicePathNotificationTypes.ServiceDelete,
234                             input.getServiceName(), RpcStatusEx.Pending, "Turning down power on A-to-Z path");
235                     ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
236                     // TODO add some flag rather than string
237                     if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
238                         LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
239                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
240                                 input.getServiceName(), RpcStatusEx.Failed,
241                                 "Service power turndown failed on A-to-Z path for service");
242                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
243                                 OPERATION_FAILED);
244                     }
245                     LOG.debug("Turning down power on Z-to-A path");
246                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
247                             RpcStatusEx.Pending, "Turning down power on Z-to-A path");
248                     ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
249                     // TODO add some flag rather than string
250                     if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
251                         LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
252                         sendNotifications(ServicePathNotificationTypes.ServiceDelete,
253                                 input.getServiceName(), RpcStatusEx.Failed,
254                                 "Service power turndown failed on Z-to-A path for service");
255                         return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
256                                 OPERATION_FAILED);
257                     }
258                 } catch (InterruptedException | ExecutionException | TimeoutException e) {
259                     LOG.error("Error while turning down power!", e);
260                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
261                             OPERATION_FAILED);
262                 }
263                 // delete service path with renderer
264                 LOG.debug("Deleting service path via renderer");
265                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
266                         RpcStatusEx.Pending, "Deleting service path via renderer");
267                 deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
268                 deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
269                 networkModelWavelengthService.freeWavelengths(pathDescription);
270                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, input.getServiceName(),
271                         RpcStatusEx.Successful, OPERATION_SUCCESSFUL);
272                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
273             }
274         });
275
276
277     }
278
279     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
280             throws InterruptedException, ExecutionException, TimeoutException {
281         LOG.debug("Turning down power on A-to-Z path");
282         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
283                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
284         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
285     }
286
287     private Optional<PathDescription> getPathDescriptionFromDatastore(String serviceName) {
288         InstanceIdentifier<PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
289                 .child(ServicePaths.class, new ServicePathsKey(serviceName)).child(PathDescription.class);
290         ReadOnlyTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
291         try {
292             LOG.debug("Getting path description for service {}", serviceName);
293             return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
294                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
295         } catch (InterruptedException | ExecutionException | TimeoutException e) {
296             LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
297                     serviceName, e);
298             return Optional.absent();
299         }
300     }
301
302     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
303             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
304         LOG.info("Rendering devices A-Z");
305         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
306                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
307                 "Rendering devices A-Z");
308         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
309                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
310                         ServicePathDirection.A_TO_Z));
311
312         LOG.info("Rendering devices Z-A");
313         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
314                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
315                 "Rendering devices A-Z");
316         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
317                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
318                         ServicePathDirection.Z_TO_A));
319         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
320                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
321
322         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
323         try {
324             LOG.info("Waiting for A-Z and Z-A device renderers ...");
325             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
326         } catch (InterruptedException | ExecutionException | TimeoutException e) {
327             LOG.warn("Device rendering was not successful! Rendering will be rolled back.", e);
328             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
329                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
330                     "Device rendering was not successful! Rendering will be rolled back.");
331             //FIXME we can't do rollback here, because we don't have rendering results.
332             return renderingResults;
333         }
334
335         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
336                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
337                 this.deviceRenderer));
338         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
339                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
340                 this.deviceRenderer));
341         return renderingResults;
342     }
343
344     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
345             ServicePowerSetupInput powerSetupInputZtoA) {
346         LOG.info("Olm power setup A-Z");
347         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
348                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
349         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
350                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
351
352         LOG.info("OLM power setup Z-A");
353         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
354                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
355         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
356                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
357         ListenableFuture<List<OLMRenderingResult>> olmFutures =
358                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
359
360         List<OLMRenderingResult> olmResults;
361         try {
362             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
363             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
364         } catch (InterruptedException | ExecutionException | TimeoutException e) {
365             LOG.warn("OLM power setup was not successful! Rendering and OLM will be rolled back.", e);
366             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
367                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
368                     "OLM power setup was not successful! Rendering and OLM will be rolled back.");
369             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
370                     this.olmService, powerSetupInputAtoZ));
371             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
372                     this.olmService, powerSetupInputZtoA));
373             return;
374         }
375
376         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
377                 this.olmService, powerSetupInputAtoZ));
378         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
379                 this.olmService, powerSetupInputZtoA));
380     }
381
382     private boolean isServiceActivated(String nodeId, String tpId) {
383         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
384         for (int i = 0; i < 3; i++) {
385             List<Measurements> measurements = getMeasurements(nodeId, tpId);
386             if ((measurements != null) && verifyPreFecBer(measurements)) {
387                 return true;
388             } else if (measurements == null) {
389                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
390                 return true;
391             } else {
392                 try {
393                     Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
394                 } catch (InterruptedException ex) {
395                     Thread.currentThread().interrupt();
396                 }
397             }
398         }
399         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
400         return false;
401     }
402
403     private List<Measurements> getMeasurements(String nodeId, String tp) {
404         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
405         getPmIpBldr.setNodeId(nodeId);
406         getPmIpBldr.setGranularity(PmGranularity._15min);
407         ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
408         rsrcBldr.setResourceName(tp + "-OTU");
409         getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
410         getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
411
412         try {
413             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
414             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
415             GetPmOutput getPmOutput = getPmRpcResult.getResult();
416             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
417                 LOG.info("successfully finished calling OLM's get PM");
418                 return getPmOutput.getMeasurements(); // may return null
419             } else {
420                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
421             }
422
423         } catch (ExecutionException | InterruptedException e) {
424             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
425         }
426         return null;
427     }
428
429
430     private boolean verifyPreFecBer(List<Measurements> measurements) {
431         double preFecCorrectedErrors = Double.MIN_VALUE;
432         double fecUncorrectableBlocks = Double.MIN_VALUE;
433
434         for (Measurements measurement : measurements) {
435             if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
436                 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
437             }
438             if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
439                 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
440             }
441         }
442
443         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
444                 fecUncorrectableBlocks);
445
446         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
447             LOG.error("Data has uncorrectable errors, BER test failed");
448             return false;
449         } else {
450             double numOfBitsPerSecond = 112000000000d;
451             double threshold = 0.00002d;
452             double result = preFecCorrectedErrors / numOfBitsPerSecond;
453             LOG.info("PreFEC value is {}", Double.toString(result));
454             return result <= threshold;
455         }
456     }
457
458 }