Disable optical control mode for temp service
[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.Map;
17 import java.util.Optional;
18 import java.util.Set;
19 import java.util.concurrent.Callable;
20 import java.util.concurrent.ExecutionException;
21 import java.util.concurrent.Executors;
22 import java.util.concurrent.TimeUnit;
23 import java.util.concurrent.TimeoutException;
24 import java.util.stream.Collectors;
25 import org.opendaylight.mdsal.binding.api.DataBroker;
26 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
27 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
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.common.mapping.PortMapping;
32 import org.opendaylight.transportpce.common.service.ServiceTypes;
33 import org.opendaylight.transportpce.renderer.ModelMappingUtils;
34 import org.opendaylight.transportpce.renderer.ServicePathInputData;
35 import org.opendaylight.transportpce.renderer.provisiondevice.servicepath.ServicePathDirection;
36 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingRollbackTask;
37 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.DeviceRenderingTask;
38 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupRollbackTask;
39 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
40 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
41 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
42 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
43 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
44 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev220630.OtnLinkType;
45 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
46 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
47 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
48 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
49 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
50 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
51 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
52 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
53 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
54 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
55 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
56 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
57 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
58 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
59 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
60 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
61 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
62 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
63 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
64 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev191129.ServiceFormat;
65 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev211210.service.list.Services;
66 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev230501.PathDescription;
67 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
68 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
69 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
70 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
71 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
72 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.PmGranularity;
73 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.link.tp.LinkTp;
74 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.olm.get.pm.input.ResourceIdentifierBuilder;
75 import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev220926.optical.renderer.nodes.Nodes;
76 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
77 import org.opendaylight.yangtools.yang.binding.Notification;
78 import org.opendaylight.yangtools.yang.common.Uint32;
79 import org.osgi.service.component.annotations.Activate;
80 import org.osgi.service.component.annotations.Component;
81 import org.osgi.service.component.annotations.Reference;
82 import org.slf4j.Logger;
83 import org.slf4j.LoggerFactory;
84
85
86 @Component(immediate = true)
87 public class RendererServiceOperationsImpl implements RendererServiceOperations {
88
89     private static final Logger LOG = LoggerFactory.getLogger(RendererServiceOperationsImpl.class);
90     private static final String DEVICE_RENDERING_ROLL_BACK_MSG =
91             "Device rendering was not successful! Rendering will be rolled back.";
92     private static final String OLM_ROLL_BACK_MSG =
93             "OLM power setup was not successful! Rendering and OLM will be rolled back.";
94     private static final String RENDERING_DEVICES_A_Z_MSG = "Rendering devices A-Z";
95     private static final String RENDERING_DEVICES_Z_A_MSG = "Rendering device Z-A";
96     private static final String TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG = "Turning down power on A-to-Z path";
97     private static final String FAILED = "Failed";
98     private static final String OPERATION_FAILED = "Operation Failed";
99     private static final String OPERATION_SUCCESSFUL = "Operation Successful";
100     private static final int NUMBER_OF_THREADS = 4;
101
102     private final DeviceRendererService deviceRenderer;
103     private final OtnDeviceRendererService otnDeviceRenderer;
104     private final TransportpceOlmService olmService;
105     private final DataBroker dataBroker;
106     private final NotificationPublishService notificationPublishService;
107     private final PortMapping portMapping;
108     private ListeningExecutorService executor;
109
110     @Activate
111     public RendererServiceOperationsImpl(@Reference DeviceRendererService deviceRenderer,
112             @Reference OtnDeviceRendererService otnDeviceRenderer,
113             @Reference TransportpceOlmService olmService,
114             @Reference DataBroker dataBroker,
115             @Reference NotificationPublishService notificationPublishService,
116             @Reference PortMapping portMapping) {
117         this.deviceRenderer = deviceRenderer;
118         this.otnDeviceRenderer = otnDeviceRenderer;
119         this.olmService = olmService;
120         this.dataBroker = dataBroker;
121         this.notificationPublishService = notificationPublishService;
122         this.portMapping = portMapping;
123         this.executor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(NUMBER_OF_THREADS));
124         LOG.debug("RendererServiceOperationsImpl instantiated");
125     }
126
127     @Override
128     public ListenableFuture<ServiceImplementationRequestOutput>
129             serviceImplementation(ServiceImplementationRequestInput input, boolean isTempService) {
130         LOG.info("Calling service impl request {}", input.getServiceName());
131         LOG.debug("Check if it is temp-service {}", isTempService);
132         return executor.submit(new Callable<ServiceImplementationRequestOutput>() {
133
134             @Override
135             public ServiceImplementationRequestOutput call() throws Exception {
136                 sendNotifications(
137                     ServicePathNotificationTypes.ServiceImplementationRequest,
138                     input.getServiceName(),
139                     RpcStatusEx.Pending,
140                     "Service compliant, submitting service implementation Request ...");
141                 Uint32 serviceRate = getServiceRate(input);
142                 LOG.info("Using {}G rate", serviceRate);
143                 org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220922
144                         .network.Nodes mappingNode =
145                     portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
146                         ? portMapping.getNode(input.getServiceAEnd().getNodeId())
147                         : null;
148                 String serviceType = ServiceTypes.getServiceType(
149                     input.getServiceAEnd().getServiceFormat().getName(),
150                     serviceRate,
151                     mappingNode != null
152                         && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
153                             && input.getServiceAEnd().getTxDirection() != null
154                             && input.getServiceAEnd().getTxDirection().getPort() != null
155                             && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null
156                         ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
157                                 input.getServiceAEnd().getTxDirection().getPort().getPortName())
158                         : null);
159                 //TODO a Map might be more indicated here
160                 switch (serviceType) {
161                     case StringConstants.SERVICE_TYPE_100GE_T:
162                     case StringConstants.SERVICE_TYPE_400GE:
163                     case StringConstants.SERVICE_TYPE_OTU4:
164                     case StringConstants.SERVICE_TYPE_OTUC2:
165                     case StringConstants.SERVICE_TYPE_OTUC3:
166                     case StringConstants.SERVICE_TYPE_OTUC4:
167                         LOG.debug("Check temp service {}", isTempService);
168                         if (!manageServicePathCreation(input, serviceType, isTempService)) {
169                             return ModelMappingUtils
170                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
171                         }
172                         break;
173                     case StringConstants.SERVICE_TYPE_1GE:
174                     case StringConstants.SERVICE_TYPE_10GE:
175                     case StringConstants.SERVICE_TYPE_100GE_M:
176                     case StringConstants.SERVICE_TYPE_100GE_S:
177                     case StringConstants.SERVICE_TYPE_ODU4:
178                     case StringConstants.SERVICE_TYPE_ODUC2:
179                     case StringConstants.SERVICE_TYPE_ODUC3:
180                     case StringConstants.SERVICE_TYPE_ODUC4:
181                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
182                             return ModelMappingUtils
183                                 .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
184                         }
185                         break;
186                     default:
187                         LOG.error("unsupported service-type");
188                         return ModelMappingUtils
189                             .createServiceImplResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
190                 }
191                 return ModelMappingUtils
192                     .createServiceImplResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
193             }
194         });
195     }
196
197     @Override
198     public ListenableFuture<ServiceDeleteOutput> serviceDelete(ServiceDeleteInput input, Services service) {
199         String serviceName = input.getServiceName();
200         LOG.info("Calling service delete request {}", serviceName);
201         return executor.submit(new Callable<ServiceDeleteOutput>() {
202
203             @Override
204             public ServiceDeleteOutput call() throws Exception {
205                 sendNotifications(
206                     ServicePathNotificationTypes.ServiceDelete,
207                     serviceName,
208                     RpcStatusEx.Pending,
209                     "Service compliant, submitting service delete Request ...");
210                 // Obtain path description
211                 Optional<
212                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
213                         .service.path.PathDescription> pathDescriptionOpt =
214                     getPathDescriptionFromDatastore(serviceName);
215                 if (pathDescriptionOpt.isEmpty()) {
216                     LOG.error("Unable to get path description for service {}!", serviceName);
217                     sendNotifications(
218                         ServicePathNotificationTypes.ServiceDelete,
219                         serviceName,
220                         RpcStatusEx.Failed,
221                         "Unable to get path description for service");
222                     return ModelMappingUtils
223                         .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
224                 }
225                 PathDescription pathDescription = pathDescriptionOpt.orElseThrow();
226                 String serviceType =
227                     ServiceTypes.getServiceType(
228                         service.getServiceAEnd().getServiceFormat().getName(),
229                         service.getServiceAEnd().getServiceRate(),
230                         service.getServiceAEnd().getTxDirection() == null
231                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
232                                     .getPort() == null
233                                 || service.getServiceAEnd().getTxDirection().values().stream().findFirst().orElseThrow()
234                                     .getPort().getPortName() == null
235                             ? null
236                             : portMapping.getMapping(
237                                     service.getServiceAEnd().getNodeId().getValue(),
238                                     service.getServiceAEnd().getTxDirection().values().stream().findFirst()
239                                         .orElseThrow().getPort().getPortName()));
240                 switch (serviceType) {
241                     case StringConstants.SERVICE_TYPE_100GE_T:
242                     case StringConstants.SERVICE_TYPE_400GE:
243                     case StringConstants.SERVICE_TYPE_OTU4:
244                     case StringConstants.SERVICE_TYPE_OTUC2:
245                     case StringConstants.SERVICE_TYPE_OTUC3:
246                     case StringConstants.SERVICE_TYPE_OTUC4:
247                         if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
248                             return ModelMappingUtils
249                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
250                         }
251                         break;
252                     case StringConstants.SERVICE_TYPE_1GE:
253                     case StringConstants.SERVICE_TYPE_10GE:
254                     case StringConstants.SERVICE_TYPE_100GE_M:
255                     case StringConstants.SERVICE_TYPE_100GE_S:
256                     case StringConstants.SERVICE_TYPE_ODU4:
257                     case StringConstants.SERVICE_TYPE_ODUC2:
258                     case StringConstants.SERVICE_TYPE_ODUC3:
259                     case StringConstants.SERVICE_TYPE_ODUC4:
260                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
261                             return ModelMappingUtils
262                                 .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
263                         }
264                         break;
265                     default:
266                         LOG.error("unsupported service-type");
267                         return ModelMappingUtils
268                             .createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED, OPERATION_FAILED);
269                 }
270                 return ModelMappingUtils
271                     .createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
272             }
273         });
274     }
275
276     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
277         value = "UPM_UNCALLED_PRIVATE_METHOD",
278         justification = "call in call() method")
279     private Uint32 getServiceRate(ServiceImplementationRequestInput input) {
280         if (input.getServiceAEnd() == null) {
281             LOG.warn("Unable to get service-rate for service {}", input.getServiceName());
282             return Uint32.ZERO;
283         }
284         if (input.getServiceAEnd().getServiceRate() != null) {
285             return input.getServiceAEnd().getServiceRate();
286         }
287         LOG.warn("Input should have rate if you are using 200 or 300G");
288         // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
289         Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
290                 ServiceFormat.OTU, Map.of(
291                     "OTUCn", Uint32.valueOf(400),
292                     "OTU4", Uint32.valueOf(100),
293                     "OTU2", Uint32.valueOf(10),
294                     "OTU2e", Uint32.valueOf(10)),
295                 ServiceFormat.ODU, Map.of(
296                     "ODUCn",Uint32.valueOf(400),
297                     "ODU4", Uint32.valueOf(100),
298                     "ODU2", Uint32.valueOf(10),
299                     "ODU2e", Uint32.valueOf(10),
300                     "ODU0", Uint32.valueOf(1)));
301         if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
302             LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
303                 input.getServiceName(), input.getServiceAEnd().getServiceFormat());
304             return Uint32.ZERO;
305         }
306         String serviceName =
307             ServiceFormat.OTU.getName().equals(input.getServiceAEnd().getServiceFormat().getName())
308                 ? input.getServiceAEnd().getOtuServiceRate().toString().split("\\{")[0]
309                 : input.getServiceAEnd().getOduServiceRate().toString().split("\\{")[0];
310         if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
311             LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
312                 input.getServiceName(), serviceName);
313             return Uint32.ZERO;
314         }
315         return formatRateMap
316             .get(input.getServiceAEnd().getServiceFormat())
317             .get(serviceName);
318     }
319
320     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
321             value = "UPM_UNCALLED_PRIVATE_METHOD",
322             justification = "call in call() method")
323     private ServicePowerTurndownOutput olmPowerTurndown(ServicePathInputData servicePathInputData)
324             throws InterruptedException, ExecutionException, TimeoutException {
325         LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
326         return this.olmService
327             .servicePowerTurndown(
328                 new ServicePowerTurndownInputBuilder(servicePathInputData.getServicePathInput()).build())
329             .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS)
330             .getResult();
331     }
332
333     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
334             value = "UPM_UNCALLED_PRIVATE_METHOD",
335             justification = "call in call() method")
336     private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
337             .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
338         InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
339                 .service.path.PathDescription> pathDescriptionIID =
340             InstanceIdentifier.create(ServicePathList.class)
341                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
342                 .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
343                     .service.path.PathDescription.class);
344         try {
345             LOG.debug("Getting path description for service {}", serviceName);
346             return this.dataBroker.newReadOnlyTransaction()
347                     .read(LogicalDatastoreType.OPERATIONAL, pathDescriptionIID)
348                     .get(Timeouts.DATASTORE_READ, TimeUnit.MILLISECONDS);
349         } catch (InterruptedException | ExecutionException | TimeoutException e) {
350             LOG.warn("Exception while getting path description from datastore {} for service {}!",
351                     pathDescriptionIID, serviceName, e);
352             return Optional.empty();
353         }
354     }
355
356     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
357             value = "UPM_UNCALLED_PRIVATE_METHOD",
358             justification = "call in call() method")
359     private List<DeviceRenderingResult> deviceRendering(
360             RollbackProcessor rollbackProcessor,
361             ServicePathInputData servicePathDataAtoZ,
362             ServicePathInputData servicePathDataZtoA) {
363
364         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
365         //     Do notifications & LOG.info deserve this ?
366         LOG.info(RENDERING_DEVICES_A_Z_MSG);
367         sendNotifications(
368             ServicePathNotificationTypes.ServiceImplementationRequest,
369             servicePathDataAtoZ.getServicePathInput().getServiceName(),
370             RpcStatusEx.Pending,
371             RENDERING_DEVICES_A_Z_MSG);
372         ListenableFuture<DeviceRenderingResult> atozrenderingFuture =
373             this.executor.submit(
374                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataAtoZ, ServicePathDirection.A_TO_Z));
375
376         LOG.info(RENDERING_DEVICES_Z_A_MSG);
377         sendNotifications(
378             ServicePathNotificationTypes.ServiceImplementationRequest,
379             servicePathDataZtoA.getServicePathInput().getServiceName(),
380             RpcStatusEx.Pending,
381             RENDERING_DEVICES_Z_A_MSG);
382         ListenableFuture<DeviceRenderingResult> ztoarenderingFuture =
383             this.executor.submit(
384                 new DeviceRenderingTask(this.deviceRenderer, servicePathDataZtoA, ServicePathDirection.Z_TO_A));
385
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(
396                 ServicePathNotificationTypes.ServiceImplementationRequest,
397                 servicePathDataAtoZ.getServicePathInput().getServiceName(),
398                 RpcStatusEx.Pending,
399                 DEVICE_RENDERING_ROLL_BACK_MSG);
400             //FIXME we can't do rollback here, because we don't have rendering results.
401             return renderingResults;
402         }
403
404         rollbackProcessor.addTask(
405             new DeviceRenderingRollbackTask(
406                 "AtoZDeviceTask",
407                 ! renderingResults.get(0).isSuccess(),
408                 renderingResults.get(0).getRenderedNodeInterfaces(),
409                 this.deviceRenderer));
410         rollbackProcessor.addTask(
411                 new DeviceRenderingRollbackTask("ZtoADeviceTask",
412                 ! renderingResults.get(1).isSuccess(),
413                 renderingResults.get(1).getRenderedNodeInterfaces(),
414                 this.deviceRenderer));
415         return renderingResults;
416     }
417
418     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
419         value = "UPM_UNCALLED_PRIVATE_METHOD",
420         justification = "call in call() method")
421     private List<OtnDeviceRenderingResult> otnDeviceRendering(
422             RollbackProcessor rollbackProcessor,
423             OtnServicePathInput otnServicePathAtoZ,
424             OtnServicePathInput otnServicePathZtoA,
425             String serviceType) {
426
427         //TODO atozrenderingFuture & ztoarenderingFuture & renderingCombinedFuture used only once
428         //     Do notifications & LOG.info deserve this ?
429         LOG.info(RENDERING_DEVICES_A_Z_MSG);
430         sendNotifications(
431             ServicePathNotificationTypes.ServiceImplementationRequest,
432             otnServicePathAtoZ.getServiceName(),
433             RpcStatusEx.Pending,
434             RENDERING_DEVICES_A_Z_MSG);
435         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
436             this.executor.submit(
437                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
438
439         LOG.info(RENDERING_DEVICES_Z_A_MSG);
440         sendNotifications(
441             ServicePathNotificationTypes.ServiceImplementationRequest,
442             otnServicePathZtoA.getServiceName(),
443             RpcStatusEx.Pending,
444             RENDERING_DEVICES_Z_A_MSG);
445         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
446             this.executor.submit(
447                 new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
448
449         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
450             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
451         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
452         try {
453             LOG.info("Waiting for A-Z and Z-A device renderers ...");
454             otnRenderingResults = renderingCombinedFuture.get(Timeouts.RENDERING_TIMEOUT, TimeUnit.MILLISECONDS);
455         } catch (InterruptedException | ExecutionException | TimeoutException e) {
456             LOG.warn(DEVICE_RENDERING_ROLL_BACK_MSG, e);
457             sendNotifications(
458                 ServicePathNotificationTypes.ServiceImplementationRequest,
459                 otnServicePathAtoZ.getServiceName(),
460                 RpcStatusEx.Pending,
461                 DEVICE_RENDERING_ROLL_BACK_MSG);
462             //FIXME we can't do rollback here, because we don't have rendering results.
463             return otnRenderingResults;
464         }
465         for (int i = 0; i < otnRenderingResults.size(); i++) {
466             rollbackProcessor.addTask(
467                 new DeviceRenderingRollbackTask(
468                     "DeviceTask n° " + i + 1,
469                     ! otnRenderingResults.get(i).isSuccess(),
470                     otnRenderingResults.get(i).getRenderedNodeInterfaces(),
471                     this.deviceRenderer));
472         }
473         return otnRenderingResults;
474     }
475
476     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
477             value = "UPM_UNCALLED_PRIVATE_METHOD",
478             justification = "call in call() method")
479     private void olmPowerSetup(
480             RollbackProcessor rollbackProcessor,
481             ServicePowerSetupInput powerSetupInputAtoZ,
482             ServicePowerSetupInput powerSetupInputZtoA, boolean isTempService) {
483
484         //TODO olmPowerSetupFutureAtoZ & olmPowerSetupFutureZtoA & olmFutures used only once
485         //     Do notifications & LOG.info deserve this ?
486         //TODO use constants for LOG.info & notifications common messages
487         // if the service create is a temp-service, OLM will be skipped
488         if (isTempService) {
489             LOG.info("For temp-service create OLM is not computed and skipped");
490             return;
491         }
492         LOG.info("Olm power setup A-Z");
493         sendNotifications(
494                 ServicePathNotificationTypes.ServiceImplementationRequest,
495                 powerSetupInputAtoZ.getServiceName(),
496                 RpcStatusEx.Pending,
497                 "Olm power setup A-Z");
498         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureAtoZ =
499                 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputAtoZ));
500
501         LOG.info("OLM power setup Z-A");
502         sendNotifications(
503                 ServicePathNotificationTypes.ServiceImplementationRequest,
504                 powerSetupInputAtoZ.getServiceName(),
505                 RpcStatusEx.Pending,
506                 "Olm power setup Z-A");
507         ListenableFuture<OLMRenderingResult> olmPowerSetupFutureZtoA =
508                 this.executor.submit(new OlmPowerSetupTask(this.olmService, powerSetupInputZtoA));
509         ListenableFuture<List<OLMRenderingResult>> olmFutures =
510                 Futures.allAsList(olmPowerSetupFutureAtoZ, olmPowerSetupFutureZtoA);
511
512         List<OLMRenderingResult> olmResults;
513         try {
514             LOG.info("Waiting for A-Z and Z-A OLM power setup ...");
515             olmResults = olmFutures.get(Timeouts.OLM_TIMEOUT, TimeUnit.MILLISECONDS);
516         } catch (InterruptedException | ExecutionException | TimeoutException e) {
517             LOG.warn(OLM_ROLL_BACK_MSG, e);
518             sendNotifications(
519                     ServicePathNotificationTypes.ServiceImplementationRequest,
520                     powerSetupInputAtoZ.getServiceName(),
521                     RpcStatusEx.Pending,
522                     OLM_ROLL_BACK_MSG);
523             rollbackProcessor.addTask(
524                     new OlmPowerSetupRollbackTask("AtoZOLMTask", true, this.olmService, powerSetupInputAtoZ));
525             rollbackProcessor.addTask(
526                     new OlmPowerSetupRollbackTask("ZtoAOLMTask", true, this.olmService, powerSetupInputZtoA));
527             return;
528         }
529         rollbackProcessor.addTask(
530                 new OlmPowerSetupRollbackTask(
531                         "AtoZOLMTask",
532                         !olmResults.get(0).isSuccess(),
533                         this.olmService,
534                         powerSetupInputAtoZ));
535         rollbackProcessor.addTask(
536                 new OlmPowerSetupRollbackTask(
537                         "ZtoAOLMTask",
538                         !olmResults.get(1).isSuccess(),
539                         this.olmService,
540                         powerSetupInputZtoA));
541     }
542
543     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
544             value = "UPM_UNCALLED_PRIVATE_METHOD",
545             justification = "call in call() method")
546     private boolean isServiceActivated(String nodeId, String tpId) {
547         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
548         for (int i = 0; i < 3; i++) {
549             List<Measurements> measurements = getMeasurements(nodeId, tpId);
550             if (measurements == null) {
551                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
552                 return true;
553             }
554             if (verifyPreFecBer(measurements)) {
555                 return true;
556             }
557             try {
558                 Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
559             } catch (InterruptedException ex) {
560                 Thread.currentThread().interrupt();
561             }
562         }
563         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
564         return false;
565     }
566
567     private List<Measurements> getMeasurements(String nodeId, String tp) {
568         try {
569             GetPmOutput getPmOutput =
570                 this.olmService
571                     .getPm(
572                         new GetPmInputBuilder()
573                             .setNodeId(nodeId)
574                             .setGranularity(PmGranularity._15min)
575                             .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
576                             .setResourceType(ResourceTypeEnum.Interface)
577                             .build())
578                     .get()
579                     .getResult();
580             if ((getPmOutput == null) || (getPmOutput.getNodeId() == null)) {
581                 LOG.warn("OLM's get PM failed for node {} and tp {}", nodeId, tp);
582             } else {
583                 LOG.info("successfully finished calling OLM's get PM");
584                 return getPmOutput.getMeasurements();
585                 // may return null
586             }
587
588         } catch (ExecutionException | InterruptedException e) {
589             LOG.warn("Error occurred while getting PM for node {} and tp {}", nodeId, tp, e);
590         }
591         return null;
592     }
593
594     private boolean verifyPreFecBer(List<Measurements> measurements) {
595         double preFecCorrectedErrors = Double.MIN_VALUE;
596         double fecUncorrectableBlocks = Double.MIN_VALUE;
597
598         for (Measurements measurement : measurements) {
599             switch (measurement.getPmparameterName()) {
600                 case "preFECCorrectedErrors":
601                     preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
602                     break;
603                 case "FECUncorrectableBlocks":
604                     fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
605                     break;
606                 default:
607                     break;
608             }
609         }
610
611         LOG.info("Measurements: preFECCorrectedErrors = {}; FECUncorrectableBlocks = {}",
612                 preFecCorrectedErrors, fecUncorrectableBlocks);
613
614         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
615             LOG.error("Data has uncorrectable errors, BER test failed");
616             return false;
617         }
618
619         double numOfBitsPerSecond = 112000000000d;
620         double threshold = 0.00002d;
621         double result = preFecCorrectedErrors / numOfBitsPerSecond;
622         LOG.info("PreFEC value is {}", Double.toString(result));
623         return result <= threshold;
624     }
625
626     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
627         value = "UPM_UNCALLED_PRIVATE_METHOD",
628         justification = "call in call() method")
629     private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
630                                               boolean isTempService) {
631         ServicePathInputData servicePathInputDataAtoZ =
632             ModelMappingUtils
633                 .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
634         ServicePathInputData servicePathInputDataZtoA =
635             ModelMappingUtils
636                 .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
637         // Rollback should be same for all conditions, so creating a new one
638         RollbackProcessor rollbackProcessor = new RollbackProcessor();
639         List<DeviceRenderingResult> renderingResults =
640             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
641         if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
642             sendNotifications(
643                 ServicePathNotificationTypes.ServiceImplementationRequest,
644                 input.getServiceName(),
645                 RpcStatusEx.Failed,
646                 DEVICE_RENDERING_ROLL_BACK_MSG);
647             return false;
648         }
649         olmPowerSetup(
650             rollbackProcessor,
651             //olmPowerSetupInputAtoZ,
652             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(0).getOlmList(), input),
653             //olmPowerSetupInputZtoA
654             ModelMappingUtils.createServicePowerSetupInput(renderingResults.get(1).getOlmList(), input), isTempService);
655         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
656             sendNotifications(
657                 ServicePathNotificationTypes.ServiceImplementationRequest,
658                 input.getServiceName(),
659                 RpcStatusEx.Failed,
660                 OLM_ROLL_BACK_MSG);
661             return false;
662         }
663         // run service activation test twice - once on source node and once on
664         // destination node
665         List<Nodes> nodes = servicePathInputDataAtoZ.getServicePathInput().getNodes();
666         if ((nodes == null) || (nodes.isEmpty())) {
667             return false;
668         }
669
670         Nodes sourceNode = nodes.get(0);
671         Nodes destNode = nodes.get(nodes.size() - 1);
672         String srcNetworkTp =
673             sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
674                 ? sourceNode.getDestTp()
675                 : sourceNode.getSrcTp();
676         String dstNetowrkTp =
677             destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
678                 ? destNode.getDestTp()
679                 : destNode.getSrcTp();
680
681         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
682                 || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
683             rollbackProcessor.rollbackAll();
684             sendNotifications(
685                 ServicePathNotificationTypes.ServiceImplementationRequest,
686                 input.getServiceName(),
687                 RpcStatusEx.Failed,
688                 "Service activation test failed.");
689             return false;
690         }
691         sendNotificationsWithPathDescription(
692             ServicePathNotificationTypes.ServiceImplementationRequest,
693             input.getServiceName(),
694             RpcStatusEx.Successful,
695             OPERATION_SUCCESSFUL,
696             input.getPathDescription(),
697             createLinkForNotif(
698                 renderingResults.stream()
699                     .flatMap(rr -> rr.getOtnLinkTps().stream())
700                     .collect(Collectors.toList())),
701             null,
702             serviceType);
703         return true;
704     }
705
706     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
707         value = "UPM_UNCALLED_PRIVATE_METHOD",
708         justification = "call in call() method")
709     private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
710             throws InterruptedException {
711         ServicePathInputData servicePathInputDataAtoZ =
712             ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
713         ServicePathInputData servicePathInputDataZtoA =
714             ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
715         // OLM turn down power
716         try {
717             LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
718             sendNotifications(
719                 ServicePathNotificationTypes.ServiceDelete,
720                 serviceName,
721                 RpcStatusEx.Pending,
722                 TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
723             // TODO add some flag rather than string
724             if (FAILED.equals(
725                     olmPowerTurndown(servicePathInputDataAtoZ)
726                         .getResult())) {
727                 LOG.error("Service power turndown failed on A-to-Z path for service {}!", serviceName);
728                 sendNotifications(
729                     ServicePathNotificationTypes.ServiceDelete,
730                     serviceName,
731                     RpcStatusEx.Failed,
732                     "Service power turndown failed on A-to-Z path for service");
733                 return false;
734             }
735             LOG.debug("Turning down power on Z-to-A path");
736             sendNotifications(
737                 ServicePathNotificationTypes.ServiceDelete,
738                 serviceName,
739                 RpcStatusEx.Pending,
740                 "Turning down power on Z-to-A path");
741             // TODO add some flag rather than string
742             if (FAILED.equals(
743                     olmPowerTurndown(servicePathInputDataZtoA)
744                         .getResult())) {
745                 LOG.error("Service power turndown failed on Z-to-A path for service {}!", serviceName);
746                 sendNotifications(
747                     ServicePathNotificationTypes.ServiceDelete,
748                     serviceName,
749                     RpcStatusEx.Failed,
750                     "Service power turndown failed on Z-to-A path for service");
751                 return false;
752             }
753         } catch (InterruptedException | ExecutionException | TimeoutException e) {
754             LOG.error("Error while turning down power!", e);
755             return false;
756         }
757         // delete service path with renderer
758         LOG.info("Deleting service path via renderer");
759         sendNotifications(
760             ServicePathNotificationTypes.ServiceDelete,
761             serviceName,
762             RpcStatusEx.Pending,
763             "Deleting service path via renderer");
764         sendNotificationsWithPathDescription(
765             ServicePathNotificationTypes.ServiceDelete,
766             serviceName,
767             RpcStatusEx.Successful,
768             OPERATION_SUCCESSFUL,
769             pathDescription,
770             createLinkForNotif(
771                 deviceRendering(
772                         new RollbackProcessor(),
773                         servicePathInputDataAtoZ,
774                         servicePathInputDataZtoA)
775                     .stream()
776                     .flatMap(rr -> rr.getOtnLinkTps().stream())
777                     .collect(Collectors.toList())),
778             null,
779             serviceType);
780         return true;
781     }
782
783     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
784         value = "UPM_UNCALLED_PRIVATE_METHOD",
785         justification = "call in call() method")
786     private boolean manageOtnServicePathCreation(
787             ServiceImplementationRequestInput input,
788             String serviceType,
789             Uint32 serviceRate) {
790         // Rollback should be same for all conditions, so creating a new one
791         RollbackProcessor rollbackProcessor = new RollbackProcessor();
792         List<OtnDeviceRenderingResult> renderingResults =
793             otnDeviceRendering(
794                 rollbackProcessor,
795                 // This is A-Z side
796                 ModelMappingUtils
797                     .rendererCreateOtnServiceInput(
798                         input.getServiceName(),
799                         Action.Create,
800                         input.getServiceAEnd().getServiceFormat().getName(),
801                         serviceRate,
802                         input.getPathDescription(),
803                         true),
804                 // This is Z-A side
805                 ModelMappingUtils
806                     .rendererCreateOtnServiceInput(
807                         input.getServiceName(),
808                         Action.Create,
809                         input.getServiceZEnd().getServiceFormat().getName(),
810                         serviceRate,
811                         input.getPathDescription(),
812                         false),
813                 serviceType);
814         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
815             rollbackProcessor.rollbackAll();
816             sendNotifications(
817                 ServicePathNotificationTypes.ServiceImplementationRequest,
818                 input.getServiceName(),
819                 RpcStatusEx.Failed,
820                 DEVICE_RENDERING_ROLL_BACK_MSG);
821             return false;
822         }
823         sendNotificationsWithPathDescription(
824             ServicePathNotificationTypes.ServiceImplementationRequest,
825             input.getServiceName(),
826             RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
827             input.getPathDescription(),
828             createLinkForNotif(
829                 renderingResults.stream()
830                     .flatMap(rr -> rr.getOtnLinkTps().stream())
831                     .collect(Collectors.toList())),
832             getSupportedLinks(
833                 ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription()),
834                 serviceType),
835             serviceType);
836         return true;
837     }
838
839     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
840         value = "UPM_UNCALLED_PRIVATE_METHOD",
841         justification = "call in call() method")
842     private boolean manageOtnServicePathDeletion(
843             String serviceName,
844             PathDescription pathDescription,
845             Services service,
846             String serviceType) {
847         LOG.info("Deleting otn-service path {} via renderer", serviceName);
848         sendNotifications(
849                 ServicePathNotificationTypes.ServiceDelete,
850                 serviceName,
851                 RpcStatusEx.Pending,
852                 "Deleting otn-service path via renderer");
853         List<OtnDeviceRenderingResult> renderingResults =
854             otnDeviceRendering(
855                 new RollbackProcessor(),
856                 // This is A-Z side
857                 ModelMappingUtils
858                     .rendererCreateOtnServiceInput(
859                         serviceName,
860                         Action.Delete,
861                         service.getServiceAEnd().getServiceFormat().getName(),
862                         service.getServiceAEnd().getServiceRate(),
863                         pathDescription,
864                         true),
865                 // This is Z-A side
866                 ModelMappingUtils
867                     .rendererCreateOtnServiceInput(
868                         serviceName,
869                         Action.Delete,
870                         service.getServiceZEnd().getServiceFormat().getName(),
871                         service.getServiceAEnd().getServiceRate(),
872                         pathDescription,
873                         false),
874                 serviceType);
875         sendNotificationsWithPathDescription(
876             ServicePathNotificationTypes.ServiceDelete,
877             serviceName,
878             RpcStatusEx.Successful,
879             OPERATION_SUCCESSFUL,
880             pathDescription,
881             createLinkForNotif(
882                 renderingResults.stream()
883                     .flatMap(rr -> rr.getOtnLinkTps().stream())
884                     .collect(Collectors.toList())),
885             getSupportedLinks(
886                 ModelMappingUtils.getLinksFromServicePathDescription(pathDescription),
887                 serviceType),
888             serviceType);
889         return true;
890     }
891
892     /**
893      * Send renderer notification.
894      * @param servicePathNotificationTypes ServicePathNotificationTypes
895      * @param serviceName String
896      * @param rpcStatusEx RpcStatusEx
897      * @param message String
898      */
899     private void sendNotifications(
900             ServicePathNotificationTypes servicePathNotificationTypes,
901             String serviceName,
902             RpcStatusEx rpcStatusEx,
903             String message) {
904         send(
905             buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
906                 null, null, null, null));
907     }
908
909     /**
910      * Send renderer notification with path description information.
911      * @param servicePathNotificationTypes ServicePathNotificationTypes
912      * @param serviceName String
913      * @param rpcStatusEx RpcStatusEx
914      * @param message String
915      * @param pathDescription PathDescription
916      */
917     private void sendNotificationsWithPathDescription(
918             ServicePathNotificationTypes servicePathNotificationTypes,
919             String serviceName,
920             RpcStatusEx rpcStatusEx,
921             String message,
922             PathDescription pathDescription,
923             Link notifLink,
924             Set<String> supportedLinks,
925             String serviceType) {
926         send(
927             buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
928                 pathDescription, notifLink, supportedLinks, serviceType));
929     }
930
931     /**
932      * Build notification containing path description information.
933      * @param servicePathNotificationTypes ServicePathNotificationTypes
934      * @param serviceName String
935      * @param rpcStatusEx RpcStatusEx
936      * @param message String
937      * @param pathDescription PathDescription
938      * @return notification with RendererRpcResultSp type.
939      */
940     private RendererRpcResultSp buildNotification(
941             ServicePathNotificationTypes servicePathNotificationTypes,
942             String serviceName,
943             RpcStatusEx rpcStatusEx,
944             String message,
945             PathDescription pathDescription,
946             Link notifLink,
947             Set<String> supportedLinks,
948             String serviceType) {
949         RendererRpcResultSpBuilder builder =
950             new RendererRpcResultSpBuilder()
951                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
952                 .setStatusMessage(message)
953                 .setServiceType(serviceType);
954         if (pathDescription != null) {
955             builder
956                 .setAToZDirection(pathDescription.getAToZDirection())
957                 .setZToADirection(pathDescription.getZToADirection());
958         }
959         if (notifLink != null) {
960             builder.setLink(notifLink);
961         }
962         if (supportedLinks != null) {
963             builder.setLinkId(supportedLinks);
964         }
965         return builder.build();
966     }
967
968     /**
969      * Send renderer notification.
970      * @param notification Notification
971      */
972     private void send(Notification<?> notification) {
973         try {
974             LOG.info("Sending notification {}", notification);
975             notificationPublishService.putNotification(notification);
976         } catch (InterruptedException e) {
977             LOG.info("notification offer rejected: ", e);
978             Thread.currentThread().interrupt();
979         }
980     }
981
982     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
983         return
984             otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2
985                 ? null
986                 : new LinkBuilder()
987                     .setATermination(
988                         new ATerminationBuilder()
989                             .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
990                             .setTpId(otnLinkTerminationPoints.get(0).getTpId())
991                             .build())
992                     .setZTermination(
993                         new ZTerminationBuilder()
994                             .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
995                             .setTpId(otnLinkTerminationPoints.get(1).getTpId())
996                             .build())
997                     .build();
998     }
999
1000     private Set<String> getSupportedLinks(Set<String> allSupportLinks, String serviceType) {
1001         //TODO a Map might be more indicated here
1002         switch (serviceType) {
1003             case StringConstants.SERVICE_TYPE_10GE:
1004             case StringConstants.SERVICE_TYPE_1GE:
1005                 return allSupportLinks.stream()
1006                     .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toSet());
1007             case StringConstants.SERVICE_TYPE_100GE_M:
1008                 return allSupportLinks.stream()
1009                     .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toSet());
1010             case StringConstants.SERVICE_TYPE_ODU4:
1011             case StringConstants.SERVICE_TYPE_100GE_S:
1012                 return allSupportLinks.stream()
1013                     .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toSet());
1014             case StringConstants.SERVICE_TYPE_ODUC4:
1015                 return allSupportLinks.stream()
1016                     .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toSet());
1017             default:
1018                 return null;
1019         }
1020     }
1021 }