Refactor transportpce-routing-constraint model
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
index d1b3848986a10ea52ba1a48f320ef34d509ea095..8cbbc13e106d91da1c15a1bf426767f0cd395270 100644 (file)
@@ -13,6 +13,7 @@ import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 import java.util.Optional;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutionException;
@@ -20,6 +21,7 @@ import java.util.concurrent.Executors;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
+import java.util.stream.Collectors;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.NotificationPublishService;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
@@ -38,8 +40,8 @@ import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetu
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OlmPowerSetupTask;
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.OtnDeviceRenderingTask;
 import org.opendaylight.transportpce.renderer.provisiondevice.tasks.RollbackProcessor;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.Action;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.Action;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev211004.OtnServicePathInput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmInputBuilder;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.GetPmOutput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerSetupInput;
@@ -47,30 +49,31 @@ import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev21
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownOutput;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.TransportpceOlmService;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.get.pm.output.Measurements;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSp;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.RendererRpcResultSpBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceDeleteOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.ServiceImplementationRequestOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ATerminationBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.link._for.notif.ZTerminationBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.Link;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210618.renderer.rpc.result.sp.LinkBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSp;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.RendererRpcResultSpBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceDeleteOutput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestInput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.ServiceImplementationRequestOutput;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ATerminationBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.link._for.notif.ZTerminationBuilder;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.Link;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev210915.renderer.rpc.result.sp.LinkBuilder;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.NodeTypes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.pm.types.rev161014.PmGranularity;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceTypeEnum;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.format.rev190531.ServiceFormat;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.service.list.Services;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.pathdescription.rev210705.PathDescription;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.RpcStatusEx;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.ServicePathNotificationTypes;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.RpcStatusEx;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.ServicePathNotificationTypes;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.ServicePathList;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePaths;
 import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.servicepath.rev171017.service.path.list.ServicePathsKey;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.link.tp.LinkTp;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.olm.get.pm.input.ResourceIdentifierBuilder;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210618.optical.renderer.nodes.Nodes;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.link.tp.LinkTp;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.olm.get.pm.input.ResourceIdentifierBuilder;
+import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev210930.optical.renderer.nodes.Nodes;
+import org.opendaylight.yang.gen.v1.http.transportpce.topology.rev220123.OtnLinkType;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -125,11 +128,16 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
                 Uint32 serviceRate = getServiceRate(input);
+                LOG.info("Using {}G rate", serviceRate);
+                org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev220114.network.Nodes
+                    mappingNode = portMapping.isNodeExist(input.getServiceAEnd().getNodeId())
+                        ? portMapping.getNode(input.getServiceAEnd().getNodeId())
+                        : null;
                 String serviceType = ServiceTypes.getServiceType(
                     input.getServiceAEnd().getServiceFormat().getName(),
                     serviceRate,
-                    (NodeTypes.Xpdr.equals(portMapping.getNode(input.getServiceAEnd().getNodeId())
-                        .getNodeInfo().getNodeType())
+                    (mappingNode != null
+                        && NodeTypes.Xpdr.equals(mappingNode.getNodeInfo().getNodeType())
                             && input.getServiceAEnd().getTxDirection() != null
                             && input.getServiceAEnd().getTxDirection().getPort() != null
                             && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
@@ -141,6 +149,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     case StringConstants.SERVICE_TYPE_100GE_T:
                     case StringConstants.SERVICE_TYPE_400GE:
                     case StringConstants.SERVICE_TYPE_OTU4:
+                    case StringConstants.SERVICE_TYPE_OTUC2:
+                    case StringConstants.SERVICE_TYPE_OTUC3:
                     case StringConstants.SERVICE_TYPE_OTUC4:
                         if (!manageServicePathCreation(input, serviceType)) {
                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
@@ -150,7 +160,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     case StringConstants.SERVICE_TYPE_1GE:
                     case StringConstants.SERVICE_TYPE_10GE:
                     case StringConstants.SERVICE_TYPE_100GE_M:
+                    case StringConstants.SERVICE_TYPE_100GE_S:
                     case StringConstants.SERVICE_TYPE_ODU4:
+                    case StringConstants.SERVICE_TYPE_ODUC2:
+                    case StringConstants.SERVICE_TYPE_ODUC3:
                     case StringConstants.SERVICE_TYPE_ODUC4:
                         if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
@@ -159,7 +172,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
                     OPERATION_SUCCESSFUL);
@@ -179,9 +193,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                         RpcStatusEx.Pending, "Service compliant, submitting service delete Request ...");
                 // Obtain path description
                 Optional<
-                    org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
+                    org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118.service
                     .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
-                if (!pathDescriptionOpt.isPresent()) {
+                if (pathDescriptionOpt.isEmpty()) {
                     LOG.error("Unable to get path description for service {}!", serviceName);
                     sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName,
                             RpcStatusEx.Failed, "Unable to get path description for service");
@@ -189,12 +203,23 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                             OPERATION_FAILED);
                 }
                 PathDescription pathDescription = pathDescriptionOpt.get();
-                String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
-                    service.getServiceAEnd().getServiceRate(), null);
+                String serviceType =
+                    ServiceTypes.getServiceType(
+                        service.getServiceAEnd().getServiceFormat().getName(),
+                        service.getServiceAEnd().getServiceRate(),
+                        service.getServiceAEnd().getTxDirection() == null
+                                || service.getServiceAEnd().getTxDirection().getPort() == null
+                                || service.getServiceAEnd().getTxDirection().getPort().getPortName() == null
+                            ? null
+                            : portMapping.getMapping(
+                                    service.getServiceAEnd().getNodeId().getValue(),
+                                    service.getServiceAEnd().getTxDirection().getPort().getPortName()));
                 switch (serviceType) {
                     case StringConstants.SERVICE_TYPE_100GE_T:
                     case StringConstants.SERVICE_TYPE_400GE:
                     case StringConstants.SERVICE_TYPE_OTU4:
+                    case StringConstants.SERVICE_TYPE_OTUC2:
+                    case StringConstants.SERVICE_TYPE_OTUC3:
                     case StringConstants.SERVICE_TYPE_OTUC4:
                         if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
@@ -204,7 +229,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     case StringConstants.SERVICE_TYPE_1GE:
                     case StringConstants.SERVICE_TYPE_10GE:
                     case StringConstants.SERVICE_TYPE_100GE_M:
+                    case StringConstants.SERVICE_TYPE_100GE_S:
                     case StringConstants.SERVICE_TYPE_ODU4:
+                    case StringConstants.SERVICE_TYPE_ODUC2:
+                    case StringConstants.SERVICE_TYPE_ODUC3:
                     case StringConstants.SERVICE_TYPE_ODUC4:
                         if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
@@ -213,7 +241,8 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
             }
@@ -231,43 +260,35 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (input.getServiceAEnd().getServiceRate() != null) {
             return input.getServiceAEnd().getServiceRate();
         }
-        if (ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
-                && input.getServiceAEnd().getOtuServiceRate() != null) {
-            switch (input.getServiceAEnd().getOtuServiceRate().getSimpleName()) {
-                case "OTUCn":
-                    return Uint32.valueOf(400);
-                case "OTU4":
-                    return Uint32.valueOf(100);
-                case "OTU2":
-                case "OTU2e":
-                    return Uint32.valueOf(10);
-                default:
-                    LOG.warn("otu-service-rate {} not managed yet", input.getServiceAEnd().getOtuServiceRate()
-                        .getSimpleName());
-                    return Uint32.ZERO;
-            }
-        } else if (ServiceFormat.ODU.equals(input.getServiceAEnd().getServiceFormat())
-                && input.getServiceAEnd().getOduServiceRate() != null) {
-            switch (input.getServiceAEnd().getOduServiceRate().getSimpleName()) {
-                case "ODUCn":
-                    return Uint32.valueOf(400);
-                case "ODU4":
-                    return Uint32.valueOf(100);
-                case "ODU2":
-                case "ODU2e":
-                    return Uint32.valueOf(10);
-                case "ODU0":
-                    return Uint32.valueOf(1);
-                default:
-                    LOG.warn("odu-service-rate {} not managed yet", input.getServiceAEnd().getOduServiceRate()
-                        .getSimpleName());
-                    return Uint32.ZERO;
-            }
-        } else {
-            LOG.warn("Unable to get service-rate for service {} - otu-service-rate should not be null",
-                input.getServiceName());
+        LOG.warn("Input should have rate if you are using 200 or 300G");
+        // TODO: missing 200, and 300G rates here, OTUCn cannot always be 400G
+        Map<ServiceFormat, Map<String, Uint32>> formatRateMap  = Map.of(
+                ServiceFormat.OTU, Map.of(
+                    "OTUCn", Uint32.valueOf(400),
+                    "OTU4", Uint32.valueOf(100),
+                    "OTU2", Uint32.valueOf(10),
+                    "OTU2e", Uint32.valueOf(10)),
+                ServiceFormat.ODU, Map.of(
+                    "ODUCn",Uint32.valueOf(400),
+                    "ODU4", Uint32.valueOf(100),
+                    "ODU2", Uint32.valueOf(10),
+                    "ODU2e", Uint32.valueOf(10),
+                    "ODU0", Uint32.valueOf(1)));
+        if (!formatRateMap.containsKey(input.getServiceAEnd().getServiceFormat())) {
+            LOG.warn("Unable to get service-rate for service {} - unsupported service format {}",
+                input.getServiceName(), input.getServiceAEnd().getServiceFormat());
+            return Uint32.ZERO;
+        }
+        String serviceName =
+            ServiceFormat.OTU.equals(input.getServiceAEnd().getServiceFormat())
+                ? input.getServiceAEnd().getOtuServiceRate().getSimpleName()
+                : input.getServiceAEnd().getOduServiceRate().getSimpleName();
+        if (!formatRateMap.get(input.getServiceAEnd().getServiceFormat()).containsKey(serviceName)) {
+            LOG.warn("Unable to get service-rate for service {} - unsupported service name {}",
+                input.getServiceName(), serviceName);
             return Uint32.ZERO;
         }
+        return formatRateMap.get(input.getServiceAEnd().getServiceFormat()).get(serviceName);
     }
 
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
@@ -284,12 +305,12 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
             value = "UPM_UNCALLED_PRIVATE_METHOD",
             justification = "call in call() method")
-    private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
+    private Optional<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
         .service.path.PathDescription> getPathDescriptionFromDatastore(String serviceName) {
-        InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
+        InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
             .service.path.PathDescription> pathDescriptionIID = InstanceIdentifier.create(ServicePathList.class)
                 .child(ServicePaths.class, new ServicePathsKey(serviceName))
-                .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128
+                .child(org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev220118
                     .service.path.PathDescription.class);
         ReadTransaction pathDescReadTx = this.dataBroker.newReadOnlyTransaction();
         try {
@@ -352,19 +373,19 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         value = "UPM_UNCALLED_PRIVATE_METHOD",
         justification = "call in call() method")
     private List<OtnDeviceRenderingResult> otnDeviceRendering(RollbackProcessor rollbackProcessor,
-        OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA) {
+        OtnServicePathInput otnServicePathAtoZ, OtnServicePathInput otnServicePathZtoA, String serviceType) {
         LOG.info(RENDERING_DEVICES_A_Z_MSG);
         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
             otnServicePathAtoZ.getServiceName(), RpcStatusEx.Pending,
             RENDERING_DEVICES_A_Z_MSG);
         ListenableFuture<OtnDeviceRenderingResult> atozrenderingFuture =
-            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ));
-        LOG.info("Rendering devices Z-A");
+            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathAtoZ, serviceType));
+        LOG.info(RENDERING_DEVICES_Z_A_MSG);
         sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
             otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
             RENDERING_DEVICES_Z_A_MSG);
         ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
-            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
+            this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA, serviceType));
         ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
             Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
@@ -435,17 +456,17 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         LOG.info("Starting service activation test on node {} and tp {}", nodeId, tpId);
         for (int i = 0; i < 3; i++) {
             List<Measurements> measurements = getMeasurements(nodeId, tpId);
-            if ((measurements != null) && verifyPreFecBer(measurements)) {
-                return true;
-            } else if (measurements == null) {
+            if (measurements == null) {
                 LOG.warn("Device {} is not reporting PreFEC on TP: {}", nodeId, tpId);
                 return true;
-            } else {
-                try {
-                    Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
-                } catch (InterruptedException ex) {
-                    Thread.currentThread().interrupt();
-                }
+            }
+            if (verifyPreFecBer(measurements)) {
+                return true;
+            }
+            try {
+                Thread.sleep(Timeouts.SERVICE_ACTIVATION_TEST_RETRY_TIME);
+            } catch (InterruptedException ex) {
+                Thread.currentThread().interrupt();
             }
         }
         LOG.error("Service activation test failed on node {} and termination point {}!", nodeId, tpId);
@@ -482,11 +503,15 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         double fecUncorrectableBlocks = Double.MIN_VALUE;
 
         for (Measurements measurement : measurements) {
-            if (measurement.getPmparameterName().equals("preFECCorrectedErrors")) {
-                preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
-            }
-            if (measurement.getPmparameterName().equals("FECUncorrectableBlocks")) {
-                fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
+            switch (measurement.getPmparameterName()) {
+                case "preFECCorrectedErrors":
+                    preFecCorrectedErrors = Double.parseDouble(measurement.getPmparameterValue());
+                    break;
+                case "FECUncorrectableBlocks":
+                    fecUncorrectableBlocks = Double.parseDouble(measurement.getPmparameterValue());
+                    break;
+                default:
+                    break;
             }
         }
 
@@ -496,13 +521,13 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (fecUncorrectableBlocks > Double.MIN_VALUE) {
             LOG.error("Data has uncorrectable errors, BER test failed");
             return false;
-        } else {
-            double numOfBitsPerSecond = 112000000000d;
-            double threshold = 0.00002d;
-            double result = preFecCorrectedErrors / numOfBitsPerSecond;
-            LOG.info("PreFEC value is {}", Double.toString(result));
-            return result <= threshold;
         }
+
+        double numOfBitsPerSecond = 112000000000d;
+        double threshold = 0.00002d;
+        double result = preFecCorrectedErrors / numOfBitsPerSecond;
+        LOG.info("PreFEC value is {}", Double.toString(result));
+        return result <= threshold;
     }
 
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
@@ -517,7 +542,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<DeviceRenderingResult> renderingResults =
             deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
-        if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
+        if (rollbackProcessor.rollbackAllIfNecessary() > 0 || renderingResults.isEmpty()) {
             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
                 input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
             return false;
@@ -564,7 +589,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
-            notifLink, serviceType);
+            notifLink, null, serviceType);
         return true;
     }
 
@@ -617,7 +642,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
+            serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
         return true;
     }
 
@@ -641,7 +666,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         // Rollback should be same for all conditions, so creating a new one
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<OtnDeviceRenderingResult> renderingResults =
-            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
+            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
         if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
             rollbackProcessor.rollbackAll();
             sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
@@ -651,10 +676,12 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+        List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(input.getPathDescription());
+        List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
             input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
-            notifLink, serviceType);
+            notifLink, supportedLinks, serviceType);
         return true;
     }
 
@@ -681,14 +708,17 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
 
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<OtnDeviceRenderingResult> renderingResults =
-            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
+            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
 
         List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
         renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
         Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+        List<String> allSupportLinks = ModelMappingUtils.getLinksFromServicePathDescription(pathDescription);
+        List<String> supportedLinks = getSupportedLinks(allSupportLinks, serviceType);
 
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, serviceType);
+                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
+                serviceType);
         return true;
     }
 
@@ -702,7 +732,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     private void sendNotifications(ServicePathNotificationTypes servicePathNotificationTypes, String serviceName,
             RpcStatusEx rpcStatusEx, String message) {
         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
-                null, null, null);
+                null, null, null, null);
         send(notification);
     }
 
@@ -716,9 +746,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      */
     private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
-            Link notifLink, String serviceType) {
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
-                pathDescription, notifLink, serviceType);
+                pathDescription, notifLink, supportedLinks, serviceType);
         send(notification);
     }
 
@@ -733,7 +763,7 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      */
     private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
             String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
-            Link notifLink, String serviceType) {
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
                 .setStatusMessage(message)
@@ -745,6 +775,9 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         if (notifLink != null) {
             builder.setLink(notifLink);
         }
+        if (supportedLinks != null) {
+            builder.setLinkId(supportedLinks);
+        }
         return builder.build();
     }
 
@@ -763,10 +796,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     }
 
     private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
-        if (otnLinkTerminationPoints.size() != 2 || otnLinkTerminationPoints.isEmpty()) {
+        if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
             return null;
-        } else {
-            return new LinkBuilder()
+        }
+        return new LinkBuilder()
                 .setATermination(new ATerminationBuilder()
                     .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
                     .setTpId(otnLinkTerminationPoints.get(0).getTpId())
@@ -776,6 +809,26 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                     .setTpId(otnLinkTerminationPoints.get(1).getTpId())
                     .build())
                 .build();
+    }
+
+    private List<String> getSupportedLinks(List<String> allSupportLinks, String serviceType) {
+        switch (serviceType) {
+            case StringConstants.SERVICE_TYPE_10GE:
+            case StringConstants.SERVICE_TYPE_1GE:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.ODTU4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_100GE_M:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.ODUC4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_ODU4:
+            case StringConstants.SERVICE_TYPE_100GE_S:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
+            case StringConstants.SERVICE_TYPE_ODUC4:
+                return allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());
+            default:
+                return null;
         }
     }
 }