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