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