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