3d4d72d9ef5b2f9811e6bb20321556234eb51434
[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.ResponseCodes;
28 import org.opendaylight.transportpce.common.StringConstants;
29 import org.opendaylight.transportpce.common.Timeouts;
30 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
31 import org.opendaylight.transportpce.renderer.ServicePathInputData;
32 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
33 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
34 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
35 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
39 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev200128.OtnServicePathInput;
40 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev200128.OtnServicePathOutput;
41 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSp;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSpBuilder;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteInput;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteOutput;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestInput;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestOutput;
54 import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
55 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.ODU4;
56 import org.opendaylight.yang.gen.v1.http.org.openroadm.otn.common.types.rev200327.OTU4;
57 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
58 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
59 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
60 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
61 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev201210.PathDescription;
62 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
63 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
64 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
65 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev201211.olm.get.pm.input.ResourceIdentifierBuilder;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev201211.olm.renderer.input.Nodes;
69 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
70 import org.opendaylight.yangtools.yang.binding.Notification;
71 import org.opendaylight.yangtools.yang.common.RpcResult;
72 import org.opendaylight.yangtools.yang.common.Uint32;
73 import org.slf4j.Logger;
74 import org.slf4j.LoggerFactory;
75
76
77 public class RendererServiceOperationsImpl implements RendererServiceOperations {
78
79     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
80             "Device rendering was not successful! Rendering will be rolled back.";
81     private static final String OLM_ROLL_BACK_MSG =
82             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
83     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
84     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
85     private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
86     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
87     private static final String FAILED = "Failed";
88     private static final String OPERATION_FAILED = "Operation Failed";
89     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
90     private static final int NUMBER_OF_THREADS = 4;
91
92     private final DeviceRendererService deviceRenderer;
93     private final OtnDeviceRendererService otnDeviceRenderer;
94     private final TransportpceOlmService olmService;
95     private final DataBroker dataBroker;
96     private final NotificationPublishService notificationPublishService;
97     private ListeningExecutorService executor;
98
99     public RendererServiceOperationsImpl(DeviceRendererService deviceRenderer,
100             OtnDeviceRendererService otnDeviceRenderer, TransportpceOlmService olmService,
101             DataBroker dataBroker, NotificationPublishService notificationPublishService) {
102         this.deviceRenderer = deviceRenderer;
103         this.otnDeviceRenderer = otnDeviceRenderer;
104         this.olmService = olmService;
105         this.dataBroker = dataBroker;
106         this.notificationPublishService = notificationPublishService;
107         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
108     }
109
110     @Override
111     public ListenableFuture<ServiceImplementationRequestOutput>
112             serviceImplementation(ServiceImplementationRequestInput input) {
113         LOG.info("Calling service impl request {}", input.getServiceName());
114         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
115
116             @Override
117             public ServiceImplementationRequestOutput call() throws Exception {
118                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
119                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
120                 // Here is the switch statement that distinguishes on the connection-type
121                 LOG.info("Connection-type is {} for {}", input.getConnectionType(), input.getServiceName());
122                 switch (input.getConnectionType()) {
123                     case Service: case RoadmLine: // This takes into account of Ethernet 100G, 1G, 10G and ODU4
124                         LOG.info("RPC implementation for {}", input.getConnectionType());
125                         if (((input.getServiceAEnd().getServiceRate() != null)
126                             && ((input.getServiceAEnd().getServiceRate().intValue() == 100))
127                             || (input.getServiceAEnd().getServiceRate().intValue() == 400))
128                             && ((input.getServiceAEnd().getServiceFormat().getName().equals("Ethernet"))
129                                 || (input.getServiceAEnd().getServiceFormat().getName().equals("OC")))) {
130                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
131                                 input.getServiceAEnd().getServiceFormat(), input.getServiceAEnd().getServiceRate());
132                             if (!createServicepathInput(input)) {
133                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
134                                     OPERATION_FAILED);
135                             }
136                         } else { // This implies, service-rate is 1 or 10G
137                             // This includes the lower-order odu (1G, 10G) and this is A-Z side
138                             LOG.info("RPC implementation for LO-ODU");
139                             String serviceRate = ""; // Assuming service at A-side and Z-side has same service rate
140                             if (input.getServiceAEnd().getServiceRate() != null) {
141                                 serviceRate = input.getServiceAEnd().getServiceRate().toString() + "G";
142                             }
143                             LOG.info("Start rendering for {} service with {} rate and {} format",
144                                 input.getServiceName(), serviceRate,
145                                 input.getServiceAEnd().getServiceFormat());
146                             // This is A-Z side
147                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
148                                 .rendererCreateOtnServiceInput(input.getServiceName(),
149                                     input.getServiceAEnd().getServiceFormat().getName(),
150                                     serviceRate, (PathDescription) input.getPathDescription(), true);
151                             // Rollback should be same for all conditions, so creating a new one
152                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
153                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
154                                 otnServicePathInputAtoZ, null);
155                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
156                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
157                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
158                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
159                                     OPERATION_FAILED);
160                             }
161                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
162                         }
163                         break;
164                     case Infrastructure:
165                         LOG.info("RPC implementation for {}", input.getConnectionType());
166                         if ((input.getServiceAEnd().getOtuServiceRate() != null)
167                             && (input.getServiceAEnd().getOtuServiceRate().equals(OTU4.class))) {
168                             // For the service of OTU4 infrastructure
169                             // First create the OCH and OTU interfaces
170                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
171                             if (!createServicepathInput(input)) {
172                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
173                                     OPERATION_FAILED);
174                             }
175                         }
176                         if ((input.getServiceAEnd().getOduServiceRate() != null)
177                             && (input.getServiceAEnd().getOduServiceRate().equals(ODU4.class))) {
178                             // For the service of OTU4 infrastructure
179                             String serviceRate = "100G"; // For OtnDeviceRendererServiceImpl
180                             LOG.info("Service format for {} is {} and rate is {}", input.getServiceName(),
181                                 input.getServiceAEnd().getOduServiceRate(), serviceRate);
182                             // Now start rendering ODU4 interface
183                             // This is A-Z side
184                             OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
185                                 .rendererCreateOtnServiceInput(input.getServiceName(),
186                                     input.getServiceAEnd().getServiceFormat().getName(),
187                                     serviceRate,
188                                     input.getPathDescription(), true);
189                             // This is Z-A side
190                             OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
191                                 .rendererCreateOtnServiceInput(input.getServiceName(),
192                                     input.getServiceZEnd().getServiceFormat().getName(),
193                                     serviceRate,
194                                     input.getPathDescription(), false);
195                             // Rollback should be same for all conditions, so creating a new one
196                             RollbackProcessor rollbackProcessor = new RollbackProcessor();
197                             List<OtnDeviceRenderingResult> otnRenderingResults = otnDeviceRendering(rollbackProcessor,
198                                 otnServicePathInputAtoZ, otnServicePathInputZtoA);
199                             if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
200                                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
201                                     input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
202                                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
203                                     OPERATION_FAILED);
204                             }
205                             LOG.info("OTN rendering result size {}", otnRenderingResults.size());
206                         }
207                         break;
208                     default:
209                         LOG.warn("Unsupported connection type {}", input.getConnectionType());
210                 }
211                 sendNotificationsWithPathDescription(
212                         ServicePathNotificationTypes.ServiceImplementationRequest,
213                         input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
214                         input.getPathDescription());
215                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
216                     OPERATION_SUCCESSFUL);
217             }
218         });
219     }
220
221     @Override
222     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
223         String serviceName = input.getServiceName();
224         LOG.info("Calling service delete request {}", serviceName);
225         return executor.submit(new Callable<ServiceDeleteOutput>() {
226
227             @Override
228             public ServiceDeleteOutput call() throws Exception {
229                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
230                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
231                 // Obtain path description
232                 Optional<
233                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
234                     .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
235                 PathDescription pathDescription;
236                 if (pathDescriptionOpt.isPresent()) {
237                     pathDescription = pathDescriptionOpt.get();
238                 } else {
239                     LOG.error("Unable to get path description for service {}!", serviceName);
240                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
241                             RpcStatusEx.Failed, "Unable to get path description for service");
242                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
243                             OPERATION_FAILED);
244                 }
245                 switch (service.getConnectionType()) {
246                     case RoadmLine:
247                     case Service:
248                         if ((ServiceFormat.Ethernet.equals(service.getServiceAEnd().getServiceFormat())
249                                 || ServiceFormat.OC.equals(service.getServiceAEnd().getServiceFormat()))
250                             && Uint32.valueOf("100").equals(service.getServiceAEnd().getServiceRate())) {
251                             if (!manageServicePathDeletion(serviceName, pathDescription)) {
252                                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
253                                     OPERATION_FAILED);
254                             }
255                         }
256                         if (ServiceFormat.Ethernet.equals(service.getServiceAEnd().getServiceFormat())
257                             && (Uint32.valueOf("10").equals(service.getServiceAEnd().getServiceRate())
258                                 || Uint32.valueOf("1").equals(service.getServiceAEnd().getServiceRate()))) {
259                             if (!manageOtnServicePathDeletion(serviceName, pathDescription, service)) {
260                                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
261                                     OPERATION_FAILED);
262                             }
263                         }
264                         break;
265                     case Infrastructure:
266                         if (ServiceFormat.OTU.equals(service.getServiceAEnd().getServiceFormat())) {
267                             if (!manageServicePathDeletion(serviceName, pathDescription)) {
268                                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
269                                     OPERATION_FAILED);
270                             }
271                         } else if (ServiceFormat.ODU.equals(service.getServiceAEnd().getServiceFormat())) {
272                             if (!manageOtnServicePathDeletion(serviceName, pathDescription, service)) {
273                                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
274                                     OPERATION_FAILED);
275                             }
276                         }
277                         break;
278                     default:
279                         LOG.error("Unmanaged connection-type for deletion of service {}", serviceName);
280                         break;
281                     }
282                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
283             }
284         });
285     }
286
287     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
288             value = "UPM_UNCALLED_PRIVATE_METHOD",
289             justification = "call in call() method")
290     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
291             throws InterruptedException, ExecutionException, TimeoutException {
292         LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
293         Future<RpcResult<ServicePowerTurndownOutput>> powerTurndownFuture = this.olmService.servicePowerTurndown(
294                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build());
295         return powerTurndownFuture.get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS).getResult();
296     }
297
298     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
299             value = "UPM_UNCALLED_PRIVATE_METHOD",
300             justification = "call in call() method")
301     private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
302         .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
303         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
304             .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
305                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
306                 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
307                     .service.path.PathDescription.class);
308         ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
309         try {
310             LOG.debug("Getting path description for service {}", serviceName);
311             return pathDescReadTx.read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
312                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
313         } catch (InterruptedException | ExecutionException | TimeoutException e) {
314             LOG.warn("Exception while getting path description from datastore {} for service {}!", pathDescriptionIID,
315                     serviceName, e);
316             return Optional.empty();
317         }
318     }
319
320     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
321             value = "UPM_UNCALLED_PRIVATE_METHOD",
322             justification = "call in call() method")
323     private List<DeviceRenderingResult> deviceRendering(RollbackProcessor rollbackProcessor,
324             ServicePathInputData servicePathDataAtoZ, ServicePathInputData servicePathDataZtoA) {
325         LOG.info(RENDERING_DEVICES_A_Z_MSG);
326         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
327                 servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
328                 RENDERING_DEVICES_A_Z_MSG);
329         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
330                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ,
331                         ServicePathDirection.A_TO_Z));
332
333         LOG.info("Rendering devices Z-A");
334         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
335                 servicePathDataZtoA.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
336                 RENDERING_DEVICES_Z_A_MSG);
337         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
338                 this.executor.submit(new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA,
339                         ServicePathDirection.Z_TO_A));
340         ListenableFuture<List<DeviceRenderingResult>> renderingCombinedFuture =
341                 Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
342
343         List<DeviceRenderingResult> renderingResults = new ArrayList<>(2);
344         try {
345             LOG.info("Waiting for A-Z and Z-A device renderers ...");
346             renderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
347         } catch (InterruptedException | ExecutionException | TimeoutException e) {
348             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
349             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
350                     servicePathDataAtoZ.getServicePathInput().getServiceName(), RpcStatusEx.Pending,
351                     DEVICE_RENDERING_ROLL_BACK_MSG);
352             //FIXME we can't do rollback here, because we don't have rendering results.
353             return renderingResults;
354         }
355
356         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("AtoZDeviceTask",
357                 ! renderingResults.get(0).isSuccess(), renderingResults.get(0).getRenderedNodeInterfaces(),
358                 this.deviceRenderer));
359         rollbackProcessor.addTask(new DeviceRenderingRollbackTask("ZtoADeviceTask",
360                 ! renderingResults.get(1).isSuccess(), renderingResults.get(1).getRenderedNodeInterfaces(),
361                 this.deviceRenderer));
362         return renderingResults;
363     }
364
365     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
366         value = "UPM_UNCALLED_PRIVATE_METHOD",
367         justification = "call in call() method")
368     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
369         OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
370         LOG.info(RENDERING_DEVICES_A_Z_MSG);
371         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
372             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
373             RENDERING_DEVICES_A_Z_MSG);
374         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
375             this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
376         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture;
377         if (otnServicePathZtoA != null) {
378             LOG.info("Rendering devices Z-A");
379             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
380                 otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
381                 RENDERING_DEVICES_Z_A_MSG);
382             ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
383                 this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
384             renderingCombinedFuture = Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
385         } else {
386             renderingCombinedFuture = Futures.allAsList(atozrenderingFuture);
387         }
388         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
389         try {
390             LOG.info("Waiting for A-Z and Z-A device renderers ...");
391             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
392         } catch (InterruptedException | ExecutionException | TimeoutException e) {
393             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
394             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
395                 otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
396                 DEVICE_RENDERING_ROLL_BACK_MSG);
397             //FIXME we can't do rollback here, because we don't have rendering results.
398             return otnRenderingResults;
399         }
400         for (int i = 0; i < otnRenderingResults.size(); i++) {
401             rollbackProcessor.addTask(new DeviceRenderingRollbackTask("DeviceTask n° " + i + 1,
402                 ! otnRenderingResults.get(i).isSuccess(), otnRenderingResults.get(i).getRenderedNodeInterfaces(),
403                 this.deviceRenderer));
404         }
405         return otnRenderingResults;
406     }
407
408     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
409             value = "UPM_UNCALLED_PRIVATE_METHOD",
410             justification = "call in call() method")
411     private void olmPowerSetup(RollbackProcessor rollbackProcessor, ServicePowerSetupInput powerSetupInputAtoZ,
412             ServicePowerSetupInput powerSetupInputZtoA) {
413         LOG.info("Olm power setup A-Z");
414         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
415                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup A-Z");
416         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ
417                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
418
419         LOG.info("OLM power setup Z-A");
420         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
421                 powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending, "Olm power setup Z-A");
422         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA
423                 = this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
424         ListenableFuture<List<OLMRenderingResult>> olmFutures =
425                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
426
427         List<OLMRenderingResult> olmResults;
428         try {
429             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
430             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
431         } catch (InterruptedException | ExecutionException | TimeoutException e) {
432             LOG.warn(OLM_ROLL_BACK_MSG, e);
433             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
434                     powerSetupInputAtoZ.getServiceName(), RpcStatusEx.Pending,
435                     OLM_ROLL_BACK_MSG);
436             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", true,
437                     this.olmService, powerSetupInputAtoZ));
438             rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", true,
439                     this.olmService, powerSetupInputZtoA));
440             return;
441         }
442
443         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("AtoZOLMTask", ! olmResults.get(0).isSuccess(),
444                 this.olmService, powerSetupInputAtoZ));
445         rollbackProcessor.addTask(new OlmPowerSetupRollbackTask("ZtoAOLMTask", ! olmResults.get(1).isSuccess(),
446                 this.olmService, powerSetupInputZtoA));
447     }
448
449     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
450             value = "UPM_UNCALLED_PRIVATE_METHOD",
451             justification = "call in call() method")
452     private boolean isServiceActivated(String nodeId, String tpId) {
453         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
454         for (int i = 0; i < 3; i++) {
455             List<Measurements> measurements = getMeasurements(nodeId, tpId);
456             if ((measurements != null) && verifyPreFecBer(measurements)) {
457                 return true;
458             } else if (measurements == null) {
459                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
460                 return true;
461             } else {
462                 try {
463                     Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
464                 } catch (InterruptedException ex) {
465                     Thread.currentThread().interrupt();
466                 }
467             }
468         }
469         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
470         return false;
471     }
472
473     private List<Measurements> getMeasurements(String nodeId, String tp) {
474         GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
475         getPmIpBldr.setNodeId(nodeId);
476         getPmIpBldr.setGranularity(PmGranularity._15min);
477         ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
478         rsrcBldr.setResourceName(tp + "-OTU");
479         getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
480         getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
481
482         try {
483             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
484             RpcResult<GetPmOutput> getPmRpcResult = getPmFuture.get();
485             GetPmOutput getPmOutput = getPmRpcResult.getResult();
486             if ((getPmOutput != null) && (getPmOutput.getNodeId() != null)) {
487                 LOG.info("successfully finished calling OLM's get PM");
488                 return getPmOutput.getMeasurements();
489                 // may return null
490             } else {
491                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
492             }
493
494         } catch (ExecutionException | InterruptedException e) {
495             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
496         }
497         return null;
498     }
499
500     private boolean verifyPreFecBer(List<Measurements> measurements) {
501         double preFecCorrectedErrors = Double.MIN_VALUE;
502         double fecUncorrectableBlocks = Double.MIN_VALUE;
503
504         for (Measurements measurement : measurements) {
505             if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
506                 preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
507             }
508             if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
509                 fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
510             }
511         }
512
513         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}", preFecCorrectedErrors,
514                 fecUncorrectableBlocks);
515
516         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
517             LOG.error("Data has uncorrectable errors, BER test failed");
518             return false;
519         } else {
520             double numOfBitsPerSecond = 112000000000d;
521             double threshold = 0.00002d;
522             double result = preFecCorrectedErrors / numOfBitsPerSecond;
523             LOG.info("PreFEC value is {}", Double.toString(result));
524             return result <= threshold;
525         }
526     }
527
528     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
529         value = "UPM_UNCALLED_PRIVATE_METHOD",
530         justification = "call in call() method")
531     private boolean createServicepathInput(ServiceImplementationRequestInput input) {
532         ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
533             .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
534         ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
535             .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
536         // Rollback should be same for all conditions, so creating a new one
537         RollbackProcessor rollbackProcessor = new RollbackProcessor();
538         List<DeviceRenderingResult> renderingResults =
539             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
540         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
541             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
542                 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
543             return false;
544         }
545         ServicePowerSetupInput olmPowerSetupInputAtoZ =
546             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input);
547         ServicePowerSetupInput olmPowerSetupInputZtoA =
548             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input);
549         olmPowerSetup(rollbackProcessor, olmPowerSetupInputAtoZ, olmPowerSetupInputZtoA);
550         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
551             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
552                 input.getServiceName(), RpcStatusEx.Failed, OLM_ROLL_BACK_MSG);
553             return false;
554         }
555         // run service activation test twice - once on source node and once on
556         // destination node
557         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
558         if ((nodes == null) || (nodes.isEmpty())) {
559             return false;
560         }
561
562         Nodes sourceNode = nodes.get(0);
563         Nodes destNode = nodes.get(nodes.size() - 1);
564         String srcNetworkTp;
565         String dstNetowrkTp;
566         if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
567             srcNetworkTp = sourceNode.getDestTp();
568         } else {
569             srcNetworkTp = sourceNode.getSrcTp();
570         }
571         if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
572             dstNetowrkTp = destNode.getDestTp();
573         } else {
574             dstNetowrkTp = destNode.getSrcTp();
575         }
576         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
577             || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
578             rollbackProcessor.rollbackAll();
579             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
580                 input.getServiceName(), RpcStatusEx.Failed,
581                 "Service activation test failed.");
582             return false;
583         }
584         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
585             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription());
586         return true;
587     }
588
589     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
590         value = "UPM_UNCALLED_PRIVATE_METHOD",
591         justification = "call in call() method")
592     private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription) {
593         ServicePathInputData servicePathInputDataAtoZ =
594             ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
595         ServicePathInputData servicePathInputDataZtoA =
596             ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
597         // OLM turn down power
598         try {
599             LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
600             sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
601                 RpcStatusEx.Pending, TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
602             ServicePowerTurndownOutput atozPowerTurndownOutput = olmPowerTurndown(servicePathInputDataAtoZ);
603             // TODO add some flag rather than string
604             if (FAILED.equals(atozPowerTurndownOutput.getResult())) {
605                 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
606                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
607                         "Service power turndown failed on A-to-Z path for service");
608                 return false;
609             }
610             LOG.debug("Turning down power on Z-to-A path");
611             sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
612                     "Turning down power on Z-to-A path");
613             ServicePowerTurndownOutput ztoaPowerTurndownOutput = olmPowerTurndown(servicePathInputDataZtoA);
614             // TODO add some flag rather than string
615             if (FAILED.equals(ztoaPowerTurndownOutput.getResult())) {
616                 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
617                 sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Failed,
618                         "Service power turndown failed on Z-to-A path for service");
619                 return false;
620             }
621         } catch (InterruptedException | ExecutionException | TimeoutException e) {
622             LOG.error("Error while turning down power!", e);
623             return false;
624         }
625         // delete service path with renderer
626         LOG.info("Deleting service path via renderer");
627         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
628                 "Deleting service path via renderer");
629         deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
630         deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
631         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
632                 serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL,pathDescription);
633         return true;
634     }
635
636     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
637         value = "UPM_UNCALLED_PRIVATE_METHOD",
638         justification = "call in call() method")
639     private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
640         Services service) {
641         OtnServicePathInput ospi = null;
642         if (ConnectionType.Infrastructure.equals(service.getConnectionType())) {
643             ospi = ModelMappingUtils.rendererCreateOtnServiceInput(
644                 serviceName, service.getServiceAEnd().getServiceFormat().getName(), "100G", pathDescription, true);
645         } else if (ConnectionType.Service.equals(service.getConnectionType())) {
646             ospi = ModelMappingUtils.rendererCreateOtnServiceInput(serviceName,
647                 service.getServiceAEnd().getServiceFormat().getName(),
648                 service.getServiceAEnd().getServiceRate().toString() + "G", pathDescription, true);
649         }
650         LOG.info("Deleting otn-service path {} via renderer", serviceName);
651         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
652                 "Deleting otn-service path via renderer");
653         OtnServicePathOutput result = otnDeviceRenderer.deleteOtnServicePath(ospi);
654         if (result.getSuccess()) {
655             sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
656                     serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription);
657             return true;
658         } else {
659             return false;
660         }
661     }
662
663     /**
664      * Send renderer notification.
665      * @param servicePathNotificationTypes ServicePathNotificationTypes
666      * @param serviceName String
667      * @param rpcStatusEx RpcStatusEx
668      * @param message String
669      */
670     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
671             RpcStatusEx rpcStatusEx, String message) {
672         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
673                 null);
674         send(notification);
675     }
676
677     /**
678      * Send renderer notification with path description information.
679      * @param servicePathNotificationTypes ServicePathNotificationTypes
680      * @param serviceName String
681      * @param rpcStatusEx RpcStatusEx
682      * @param message String
683      * @param pathDescription PathDescription
684      */
685     private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
686             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
687         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
688                 pathDescription);
689         send(notification);
690     }
691
692     /**
693      * Build notification containing path description information.
694      * @param servicePathNotificationTypes ServicePathNotificationTypes
695      * @param serviceName String
696      * @param rpcStatusEx RpcStatusEx
697      * @param message String
698      * @param pathDescription PathDescription
699      * @return notification with RendererRpcResultSp type.
700      */
701     private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
702             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
703         RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
704                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
705                 .setStatusMessage(message);
706         if (pathDescription != null) {
707             builder.setAToZDirection(pathDescription.getAToZDirection())
708                     .setZToADirection(pathDescription.getZToADirection());
709         }
710         return builder.build();
711     }
712
713     /**
714      * Send renderer notification.
715      * @param notification Notification
716      */
717     private void send(Notification notification) {
718         try {
719             LOG.info("Sending notification {}", notification);
720             notificationPublishService.putNotification(notification);
721         } catch (InterruptedException e) {
722             LOG.info("notification offer rejected: ", e);
723             Thread.currentThread().interrupt();
724         }
725     }
726
727 }