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