Manage ODU4 services over multiple OTU4
[transportpce.git] / renderer / src / main / java / org / opendaylight / transportpce / renderer / provisiondevice / RendererServiceOperationsImpl.java
index 8784618d7f6f5c0a491775a0a2391b47ca5b9eec..a9fd162b0d9c244417ea59362abfaab771403894 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,23 +40,26 @@ 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.OtnServicePathInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.device.renderer.rev210618.OtnServicePathOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmInputBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.GetPmOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerSetupInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownInputBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.ServicePowerTurndownOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.get.pm.output.Measurements;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210426.mapping.Mapping;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSp;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.RendererRpcResultSpBuilder;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceDeleteOutput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestInput;
-import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.renderer.rev201125.ServiceImplementationRequestOutput;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev190531.ConnectionType;
+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;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev210618.ServicePowerTurndownInputBuilder;
+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.portmapping.rev210927.mapping.Mapping;
+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;
@@ -66,8 +71,10 @@ import org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service
 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.rev201211.olm.get.pm.input.ResourceIdentifierBuilder;
-import org.opendaylight.yang.gen.v1.http.org.transportpce.common.types.rev201211.olm.renderer.input.Nodes;
+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.transportpce.topology.rev210511.OtnLinkType;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.opendaylight.yangtools.yang.common.RpcResult;
@@ -122,66 +129,44 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest, input.getServiceName(),
                         RpcStatusEx.Pending, "Service compliant, submitting service implementation Request ...");
                 Uint32 serviceRate = getServiceRate(input);
-                String serviceType;
-                if (NodeTypes.Xpdr.equals(portMapping.getNode(input.getServiceAEnd().getNodeId())
+                String serviceType = ServiceTypes.getServiceType(
+                    input.getServiceAEnd().getServiceFormat().getName(),
+                    serviceRate,
+                    (NodeTypes.Xpdr.equals(portMapping.getNode(input.getServiceAEnd().getNodeId())
                         .getNodeInfo().getNodeType())
-                    && input.getServiceAEnd().getTxDirection() != null
-                    && input.getServiceAEnd().getTxDirection().getPort() != null
-                    && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null) {
-                    Mapping mapping = portMapping.getMapping(input.getServiceAEnd().getNodeId(),
-                        input.getServiceAEnd().getTxDirection().getPort().getPortName());
-                    serviceType = ServiceTypes.getServiceType(input.getServiceAEnd().getServiceFormat().getName(),
-                        serviceRate, mapping);
-                } else {
-                    serviceType = ServiceTypes.getServiceType(input.getServiceAEnd().getServiceFormat().getName(),
-                        serviceRate, null);
-                }
+                            && input.getServiceAEnd().getTxDirection() != null
+                            && input.getServiceAEnd().getTxDirection().getPort() != null
+                            && input.getServiceAEnd().getTxDirection().getPort().getPortName() != null)
+                        ? portMapping.getMapping(input.getServiceAEnd().getNodeId(),
+                                input.getServiceAEnd().getTxDirection().getPort().getPortName())
+                        : null);
 
                 switch (serviceType) {
                     case StringConstants.SERVICE_TYPE_100GE_T:
                     case StringConstants.SERVICE_TYPE_400GE:
                     case StringConstants.SERVICE_TYPE_OTU4:
                     case StringConstants.SERVICE_TYPE_OTUC4:
-                        if (!createServicepathInput(input)) {
+                        if (!manageServicePathCreation(input, serviceType)) {
                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
                                 OPERATION_FAILED);
                         }
                         break;
                     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_ODUC4:
-                        // This is A-Z side
-                        OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
-                            .rendererCreateOtnServiceInput(input.getServiceName(),
-                                input.getServiceAEnd().getServiceFormat().getName(),
-                                serviceRate,
-                                input.getPathDescription(), true);
-                        // This is Z-A side
-                        OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
-                            .rendererCreateOtnServiceInput(input.getServiceName(),
-                                input.getServiceZEnd().getServiceFormat().getName(),
-                                serviceRate,
-                                input.getPathDescription(), false);
-                        // Rollback should be same for all conditions, so creating a new one
-                        RollbackProcessor rollbackProcessor = new RollbackProcessor();
-                        otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA);
-                        if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
-                            sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
-                                input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
+                        if (!manageOtnServicePathCreation(input, serviceType, serviceRate)) {
                             return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
                                 OPERATION_FAILED);
                         }
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
-
-                sendNotificationsWithPathDescription(
-                        ServicePathNotificationTypes.ServiceImplementationRequest,
-                        input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL,
-                        input.getPathDescription());
                 return ModelMappingUtils.createServiceImplResponse(ResponseCodes.RESPONSE_OK,
                     OPERATION_SUCCESSFUL);
             }
@@ -202,40 +187,43 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 Optional<
                     org.opendaylight.yang.gen.v1.http.org.transportpce.b.c._interface.service.types.rev200128.service
                     .path.PathDescription> pathDescriptionOpt = getPathDescriptionFromDatastore(serviceName);
-                PathDescription pathDescription;
-                if (pathDescriptionOpt.isPresent()) {
-                    pathDescription = pathDescriptionOpt.get();
-                } else {
+                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");
                     return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
                             OPERATION_FAILED);
                 }
+                PathDescription pathDescription = pathDescriptionOpt.get();
+                Mapping mapping = portMapping.getMapping(service.getServiceAEnd().getNodeId().getValue(),
+                    service.getServiceAEnd().getTxDirection().getPort().getPortName());
                 String serviceType = ServiceTypes.getServiceType(service.getServiceAEnd().getServiceFormat().getName(),
-                    service.getServiceAEnd().getServiceRate(), null);
+                    service.getServiceAEnd().getServiceRate(), mapping);
                 switch (serviceType) {
                     case StringConstants.SERVICE_TYPE_100GE_T:
                     case StringConstants.SERVICE_TYPE_400GE:
                     case StringConstants.SERVICE_TYPE_OTU4:
                     case StringConstants.SERVICE_TYPE_OTUC4:
-                        if (!manageServicePathDeletion(serviceName, pathDescription)) {
+                        if (!manageServicePathDeletion(serviceName, pathDescription, serviceType)) {
                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
                                 OPERATION_FAILED);
                         }
                         break;
                     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_ODUC4:
-                        if (!manageOtnServicePathDeletion(serviceName, pathDescription, service)) {
+                        if (!manageOtnServicePathDeletion(serviceName, pathDescription, service, serviceType)) {
                             return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
                                 OPERATION_FAILED);
                         }
                         break;
                     default:
                         LOG.error("unsupported service-type");
-                        break;
+                        return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_FAILED,
+                            OPERATION_FAILED);
                 }
                 return ModelMappingUtils.createServiceDeleteResponse(ResponseCodes.RESPONSE_OK, OPERATION_SUCCESSFUL);
             }
@@ -253,43 +241,33 @@ 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());
+        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(
@@ -374,25 +352,21 @@ 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));
-        ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture;
-        if (otnServicePathZtoA != null) {
-            LOG.info("Rendering devices Z-A");
-            sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
-                otnServicePathZtoA.getServiceName(), RpcStatusEx.Pending,
-                RENDERING_DEVICES_Z_A_MSG);
-            ListenableFuture<OtnDeviceRenderingResult> ztoarenderingFuture =
-                this.executor.submit(new OtnDeviceRenderingTask(this.otnDeviceRenderer, otnServicePathZtoA));
-            renderingCombinedFuture = Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
-        } else {
-            renderingCombinedFuture = Futures.allAsList(atozrenderingFuture);
-        }
+            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, serviceType));
+        ListenableFuture<List<OtnDeviceRenderingResult>> renderingCombinedFuture =
+            Futures.allAsList(atozrenderingFuture, ztoarenderingFuture);
         List<OtnDeviceRenderingResult> otnRenderingResults = new ArrayList<>(2);
         try {
             LOG.info("Waiting for A-Z and Z-A device renderers ...");
@@ -461,17 +435,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);
@@ -479,13 +453,11 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
     }
 
     private List<Measurements> getMeasurements(String nodeId, String tp) {
-        GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder();
-        getPmIpBldr.setNodeId(nodeId);
-        getPmIpBldr.setGranularity(PmGranularity._15min);
-        ResourceIdentifierBuilder rsrcBldr = new ResourceIdentifierBuilder();
-        rsrcBldr.setResourceName(tp + "-OTU");
-        getPmIpBldr.setResourceIdentifier(rsrcBldr.build());
-        getPmIpBldr.setResourceType(ResourceTypeEnum.Interface);
+        GetPmInputBuilder getPmIpBldr = new GetPmInputBuilder()
+            .setNodeId(nodeId)
+            .setGranularity(PmGranularity._15min)
+            .setResourceIdentifier(new ResourceIdentifierBuilder().setResourceName(tp + "-OTU").build())
+            .setResourceType(ResourceTypeEnum.Interface);
 
         try {
             Future<RpcResult<GetPmOutput>> getPmFuture = this.olmService.getPm(getPmIpBldr.build());
@@ -510,11 +482,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;
             }
         }
 
@@ -524,23 +500,23 @@ 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(
         value = "UPM_UNCALLED_PRIVATE_METHOD",
         justification = "call in call() method")
-    private boolean createServicepathInput(ServiceImplementationRequestInput input) {
+    private boolean manageServicePathCreation(ServiceImplementationRequestInput input, String serviceType) {
         ServicePathInputData servicePathInputDataAtoZ = ModelMappingUtils
-            .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription());
+            .rendererCreateServiceInputAToZ(input.getServiceName(), input.getPathDescription(), Action.Create);
         ServicePathInputData servicePathInputDataZtoA = ModelMappingUtils
-            .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription());
+            .rendererCreateServiceInputZToA(input.getServiceName(), input.getPathDescription(), Action.Create);
         // Rollback should be same for all conditions, so creating a new one
         RollbackProcessor rollbackProcessor = new RollbackProcessor();
         List<DeviceRenderingResult> renderingResults =
@@ -569,18 +545,15 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
 
         Nodes sourceNode = nodes.get(0);
         Nodes destNode = nodes.get(nodes.size() - 1);
-        String srcNetworkTp;
-        String dstNetowrkTp;
-        if (sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
-            srcNetworkTp = sourceNode.getDestTp();
-        } else {
-            srcNetworkTp = sourceNode.getSrcTp();
-        }
-        if (destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)) {
-            dstNetowrkTp = destNode.getDestTp();
-        } else {
-            dstNetowrkTp = destNode.getSrcTp();
-        }
+        String srcNetworkTp =
+            sourceNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
+                ? sourceNode.getDestTp()
+                : sourceNode.getSrcTp();
+        String dstNetowrkTp =
+            destNode.getDestTp().contains(StringConstants.NETWORK_TOKEN)
+                ? destNode.getDestTp()
+                : destNode.getSrcTp();
+
         if (!isServiceActivated(sourceNode.getNodeId(), srcNetworkTp)
             || !isServiceActivated(destNode.getNodeId(), dstNetowrkTp)) {
             rollbackProcessor.rollbackAll();
@@ -589,19 +562,25 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
                 "Service activation test failed.");
             return false;
         }
+        List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
+        renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
+        Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
-            input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription());
+            input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
+            notifLink, null, serviceType);
         return true;
     }
 
     @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
         value = "UPM_UNCALLED_PRIVATE_METHOD",
         justification = "call in call() method")
-    private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription) {
+    private boolean manageServicePathDeletion(String serviceName, PathDescription pathDescription, String serviceType)
+            throws InterruptedException {
         ServicePathInputData servicePathInputDataAtoZ =
-            ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription);
+            ModelMappingUtils.rendererCreateServiceInputAToZ(serviceName, pathDescription, Action.Delete);
         ServicePathInputData servicePathInputDataZtoA =
-            ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription);
+            ModelMappingUtils.rendererCreateServiceInputZToA(serviceName, pathDescription, Action.Delete);
         // OLM turn down power
         try {
             LOG.debug(TURNING_DOWN_POWER_ON_A_TO_Z_PATH_MSG);
@@ -634,10 +613,67 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         LOG.info("Deleting service path via renderer");
         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
                 "Deleting service path via renderer");
-        deviceRenderer.deleteServicePath(servicePathInputDataAtoZ.getServicePathInput());
-        deviceRenderer.deleteServicePath(servicePathInputDataZtoA.getServicePathInput());
+        RollbackProcessor rollbackProcessor = new RollbackProcessor();
+        List<DeviceRenderingResult> renderingResults =
+            deviceRendering(rollbackProcessor, servicePathInputDataAtoZ, servicePathInputDataZtoA);
+        List<LinkTp> otnLinkTerminationPoints = new ArrayList<>();
+        renderingResults.forEach(rr -> otnLinkTerminationPoints.addAll(rr.getOtnLinkTps()));
+        Link notifLink = createLinkForNotif(otnLinkTerminationPoints);
+
         sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL,pathDescription);
+            serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, null, serviceType);
+        return true;
+    }
+
+    @edu.umd.cs.findbugs.annotations.SuppressFBWarnings(
+        value = "UPM_UNCALLED_PRIVATE_METHOD",
+        justification = "call in call() method")
+    private boolean manageOtnServicePathCreation(ServiceImplementationRequestInput input, String serviceType,
+            Uint32 serviceRate) {
+        // This is A-Z side
+        OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
+            .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
+                input.getServiceAEnd().getServiceFormat().getName(),
+                serviceRate,
+                input.getPathDescription(), true);
+        // This is Z-A side
+        OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
+            .rendererCreateOtnServiceInput(input.getServiceName(), Action.Create,
+                input.getServiceZEnd().getServiceFormat().getName(),
+                serviceRate,
+                input.getPathDescription(), false);
+        // Rollback should be same for all conditions, so creating a new one
+        RollbackProcessor rollbackProcessor = new RollbackProcessor();
+        List<OtnDeviceRenderingResult> renderingResults =
+            otnDeviceRendering(rollbackProcessor, otnServicePathInputAtoZ, otnServicePathInputZtoA, serviceType);
+        if (rollbackProcessor.rollbackAllIfNecessary() > 0) {
+            rollbackProcessor.rollbackAll();
+            sendNotifications(ServicePathNotificationTypes.ServiceImplementationRequest,
+                input.getServiceName(), RpcStatusEx.Failed, DEVICE_RENDERING_ROLL_BACK_MSG);
+            return false;
+        }
+        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 = null;
+        switch (serviceType) {
+            case StringConstants.SERVICE_TYPE_ODU4:
+            case StringConstants.SERVICE_TYPE_100GE_S:
+                supportedLinks = allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
+                break;
+            case StringConstants.SERVICE_TYPE_ODUC4:
+                supportedLinks = allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());
+                break;
+            default:
+                break;
+        }
+
+        sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceImplementationRequest,
+            input.getServiceName(), RpcStatusEx.Successful, OPERATION_SUCCESSFUL, input.getPathDescription(),
+            notifLink, supportedLinks, serviceType);
         return true;
     }
 
@@ -645,28 +681,50 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         value = "UPM_UNCALLED_PRIVATE_METHOD",
         justification = "call in call() method")
     private boolean manageOtnServicePathDeletion(String serviceName, PathDescription pathDescription,
-        Services service) {
-        OtnServicePathInput ospi = null;
-        if (ConnectionType.Infrastructure.equals(service.getConnectionType())) {
-            ospi = ModelMappingUtils.rendererCreateOtnServiceInput(
-                serviceName, service.getServiceAEnd().getServiceFormat().getName(), Uint32.valueOf(100),
-                pathDescription, true);
-        } else if (ConnectionType.Service.equals(service.getConnectionType())) {
-            ospi = ModelMappingUtils.rendererCreateOtnServiceInput(serviceName,
+            Services service, String serviceType) {
+        // This is A-Z side
+        OtnServicePathInput otnServicePathInputAtoZ = ModelMappingUtils
+            .rendererCreateOtnServiceInput(serviceName, Action.Delete,
                 service.getServiceAEnd().getServiceFormat().getName(),
-                service.getServiceAEnd().getServiceRate(), pathDescription, true);
-        }
+                service.getServiceAEnd().getServiceRate(),
+                pathDescription, true);
+        // This is Z-A side
+        OtnServicePathInput otnServicePathInputZtoA = ModelMappingUtils
+            .rendererCreateOtnServiceInput(serviceName, Action.Delete,
+                service.getServiceZEnd().getServiceFormat().getName(),
+                service.getServiceAEnd().getServiceRate(),
+                pathDescription, false);
         LOG.info("Deleting otn-service path {} via renderer", serviceName);
         sendNotifications(ServicePathNotificationTypes.ServiceDelete, serviceName, RpcStatusEx.Pending,
                 "Deleting otn-service path via renderer");
-        OtnServicePathOutput result = otnDeviceRenderer.deleteOtnServicePath(ospi);
-        if (result.getSuccess()) {
-            sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
-                    serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription);
-            return true;
-        } else {
-            return false;
+
+        RollbackProcessor rollbackProcessor = new RollbackProcessor();
+        List<OtnDeviceRenderingResult> renderingResults =
+            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 = null;
+        switch (serviceType) {
+            case StringConstants.SERVICE_TYPE_ODU4:
+            case StringConstants.SERVICE_TYPE_100GE_S:
+                supportedLinks = allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTU4.getName())).collect(Collectors.toList());
+                break;
+            case StringConstants.SERVICE_TYPE_ODUC4:
+                supportedLinks = allSupportLinks.stream()
+                    .filter(lk -> lk.startsWith(OtnLinkType.OTUC4.getName())).collect(Collectors.toList());
+                break;
+            default:
+                break;
         }
+
+        sendNotificationsWithPathDescription(ServicePathNotificationTypes.ServiceDelete,
+                serviceName, RpcStatusEx.Successful, OPERATION_SUCCESSFUL, pathDescription, notifLink, supportedLinks,
+                serviceType);
+        return true;
     }
 
     /**
@@ -679,7 +737,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);
         send(notification);
     }
 
@@ -692,9 +750,10 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      * @param pathDescription PathDescription
      */
     private void sendNotificationsWithPathDescription(ServicePathNotificationTypes servicePathNotificationTypes,
-            String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
+            String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         Notification notification = buildNotification(servicePathNotificationTypes, serviceName, rpcStatusEx, message,
-                pathDescription);
+                pathDescription, notifLink, supportedLinks, serviceType);
         send(notification);
     }
 
@@ -708,13 +767,21 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
      * @return notification with RendererRpcResultSp type.
      */
     private RendererRpcResultSp buildNotification(ServicePathNotificationTypes servicePathNotificationTypes,
-            String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription) {
+            String serviceName, RpcStatusEx rpcStatusEx, String message, PathDescription pathDescription,
+            Link notifLink, List<String> supportedLinks, String serviceType) {
         RendererRpcResultSpBuilder builder = new RendererRpcResultSpBuilder()
                 .setNotificationType(servicePathNotificationTypes).setServiceName(serviceName).setStatus(rpcStatusEx)
-                .setStatusMessage(message);
+                .setStatusMessage(message)
+                .setServiceType(serviceType);
         if (pathDescription != null) {
             builder.setAToZDirection(pathDescription.getAToZDirection())
-                    .setZToADirection(pathDescription.getZToADirection());
+                .setZToADirection(pathDescription.getZToADirection());
+        }
+        if (notifLink != null) {
+            builder.setLink(notifLink);
+        }
+        if (supportedLinks != null) {
+            builder.setLinkId(supportedLinks);
         }
         return builder.build();
     }
@@ -733,4 +800,19 @@ public class RendererServiceOperationsImpl implements RendererServiceOperations
         }
     }
 
+    private Link createLinkForNotif(List<LinkTp> otnLinkTerminationPoints) {
+        if (otnLinkTerminationPoints == null || otnLinkTerminationPoints.size() != 2) {
+            return null;
+        }
+        return new LinkBuilder()
+                .setATermination(new ATerminationBuilder()
+                    .setNodeId(otnLinkTerminationPoints.get(0).getNodeId())
+                    .setTpId(otnLinkTerminationPoints.get(0).getTpId())
+                    .build())
+                .setZTermination(new ZTerminationBuilder()
+                    .setNodeId(otnLinkTerminationPoints.get(1).getNodeId())
+                    .setTpId(otnLinkTerminationPoints.get(1).getTpId())
+                    .build())
+                .build();
+    }
 }