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