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