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