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