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