TAPI Netconf Topology Listener 16/95016/32
authorJavier Errea <errea@eurecom.fr>
Wed, 3 Feb 2021 15:39:30 +0000 (16:39 +0100)
committererrea <errea@eurecom.fr>
Fri, 30 Apr 2021 12:38:24 +0000 (14:38 +0200)
- TAPI network model service equiv. to Network Model module
- TAPI blueprint modification.
- Lighty module initializes TAPI accordingly
- TAPI PortMappingListener implementation
- TAPI topology context population: nodes and links
- TAPI sip context population
- TAPI rdm2rdm link creating with LLDP

JIRA: TRNSPRTPCE-385
Change-Id: I70a68c0cd6156da53cb09ec84d25f600e4d31c87
Signed-off-by: errea <errea@eurecom.fr>
lighty/src/main/java/io/lighty/controllers/tpce/module/TransportPCEImpl.java
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java
tapi/pom.xml
tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java [new file with mode: 0644]
tapi/src/main/java/org/opendaylight/transportpce/tapi/impl/TapiProvider.java
tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java [new file with mode: 0644]
tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java [new file with mode: 0644]
tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java [new file with mode: 0644]
tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java [new file with mode: 0644]
tapi/src/main/resources/OSGI-INF/blueprint/tapi-blueprint.xml

index 05992243da2a8fc7c6c80feda3c113412c19d481..179196f19e1bb6262f0dcc40fd792e2ea0555048 100644 (file)
@@ -74,7 +74,12 @@ import org.opendaylight.transportpce.servicehandler.listeners.PceListenerImpl;
 import org.opendaylight.transportpce.servicehandler.listeners.RendererListenerImpl;
 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperationsImpl;
+import org.opendaylight.transportpce.tapi.R2RTapiLinkDiscovery;
 import org.opendaylight.transportpce.tapi.impl.TapiProvider;
+import org.opendaylight.transportpce.tapi.topology.TapiNetconfTopologyListener;
+import org.opendaylight.transportpce.tapi.topology.TapiNetworkModelService;
+import org.opendaylight.transportpce.tapi.topology.TapiNetworkModelServiceImpl;
+import org.opendaylight.transportpce.tapi.topology.TapiPortMappingListener;
 import org.opendaylight.transportpce.tapi.utils.TapiListener;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.networkutils.rev170818.TransportpceNetworkutilsService;
 import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.olm.rev170418.TransportpceOlmService;
@@ -189,7 +194,17 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
                 serviceDataStoreOperations, pceListenerImpl, rendererListenerImpl, networkModelListenerImpl,
                 servicehandler);
 
-        tapiProvider = initTapi(lightyServices, servicehandler, networkTransaction, serviceDataStoreOperations);
+        LOG.info("Creating tapi beans ...");
+        R2RTapiLinkDiscovery tapilinkDiscoveryImpl = new R2RTapiLinkDiscovery(lightyServices.getBindingDataBroker(),
+            deviceTransactionManager);
+        TapiNetworkModelService tapiNetworkModelService = new TapiNetworkModelServiceImpl(
+            tapilinkDiscoveryImpl, networkTransaction);
+        TapiNetconfTopologyListener tapiNetConfTopologyListener =
+                new TapiNetconfTopologyListener(tapiNetworkModelService);
+        TapiPortMappingListener tapiPortMappingListener =
+            new TapiPortMappingListener(tapiNetworkModelService);
+        tapiProvider = initTapi(lightyServices, servicehandler, networkTransaction, serviceDataStoreOperations,
+                tapiNetConfTopologyListener, tapiPortMappingListener);
         if(activateNbiNotification) {
             LOG.info("Creating nbi-notifications beans ...");
             nbiNotificationsProvider = new NbiNotificationsProvider(
@@ -251,9 +266,12 @@ public class TransportPCEImpl extends AbstractLightyModule implements TransportP
      */
     private TapiProvider initTapi(LightyServices lightyServices, OrgOpenroadmServiceService servicehandler,
                                   NetworkTransactionService networkTransaction,
-                                  ServiceDataStoreOperations serviceDataStoreOperations) {
+                                  ServiceDataStoreOperations serviceDataStoreOperations,
+                                  TapiNetconfTopologyListener tapiNetConfTopologyListener,
+                                  TapiPortMappingListener tapiPortMappingListener) {
         return new TapiProvider(lightyServices.getBindingDataBroker(), lightyServices.getRpcProviderService(),
-                servicehandler, serviceDataStoreOperations, new TapiListener(), networkTransaction);
+            servicehandler, serviceDataStoreOperations, new TapiListener(), networkTransaction,
+            tapiNetConfTopologyListener, tapiPortMappingListener);
     }
 
     /**
index c120a38b214ea12120a9a705be03d82f3b823e3a..427e22b95836113ef1fbb96ff5ba8ae7e5f31872 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.transportpce.networkmodel;
 
 import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_1_2_1;
 import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_2_2_1;
+import static org.opendaylight.transportpce.common.StringConstants.OPENROADM_DEVICE_VERSION_7_1_0;
 
 import java.util.Collection;
 import java.util.Optional;
@@ -58,93 +59,107 @@ public class R2RLinkDiscovery {
     }
 
     public boolean readLLDP(NodeId nodeId, String nodeVersion) {
-
-        if (nodeVersion.equals(OPENROADM_DEVICE_VERSION_1_2_1)) {
-            InstanceIdentifier<Protocols> protocolsIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
+        switch (nodeVersion) {
+            case OPENROADM_DEVICE_VERSION_1_2_1:
+                InstanceIdentifier<Protocols> protocols121IID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
                     .child(Protocols.class);
-            Optional<Protocols> protocolObject = this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(),
-                LogicalDatastoreType.OPERATIONAL, protocolsIID, Timeouts.DEVICE_READ_TIMEOUT,
-                Timeouts.DEVICE_READ_TIMEOUT_UNIT);
-            if (!protocolObject.isPresent() || (protocolObject.get().augmentation(Protocols1.class) == null)) {
-                LOG.warn("LLDP subtree is missing : isolated openroadm device");
+                Optional<Protocols> protocol121Object = this.deviceTransactionManager.getDataFromDevice(
+                    nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT,
+                    Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+                if (!protocol121Object.isPresent()
+                        || (protocol121Object.get().augmentation(Protocols1.class) == null)) {
+                    LOG.warn("LLDP subtree is missing : isolated openroadm device");
+                    return false;
+                }
+                // get neighbor list
+                NbrList nbr121List = protocol121Object.get().augmentation(Protocols1.class).getLldp().getNbrList();
+                LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size());
+                // try to create rdm2rdm link
+                return rdm2rdmLinkCreatedv121(nodeId, nbr121List);
+            case OPENROADM_DEVICE_VERSION_2_2_1:
+                InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
+                    .container.org.openroadm.device.Protocols> protocols221IID =
+                        InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http
+                            .org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice.class)
+                            .child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
+                                .org.openroadm.device.container.org.openroadm.device.Protocols.class);
+                Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
+                    .container.org.openroadm.device.Protocols> protocol221Object = this.deviceTransactionManager
+                    .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+                if (!protocol221Object.isPresent() || (protocol221Object.get().augmentation(
+                        org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null)) {
+                    LOG.warn("LLDP subtree is missing : isolated openroadm device");
+                    return false;
+                }
+                org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList
+                    nbr221List = protocol221Object.get().augmentation(org.opendaylight.yang.gen.v1.http
+                        .org.openroadm.lldp.rev181019.Protocols1.class).getLldp().getNbrList();
+                LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size());
+                return rdm2rdmLinkCreatedv221(nodeId, nbr221List);
+            case OPENROADM_DEVICE_VERSION_7_1_0:
+                LOG.info("Not yet implemented?");
                 return false;
-            }
-            NbrList nbrList = protocolObject.get().augmentation(Protocols1.class).getLldp().getNbrList();
-            LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size());
-            boolean success = true;
-            for (IfName ifName : nbrList.nonnullIfName().values()) {
-                if (ifName.getRemoteSysName() == null) {
-                    LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
-                        nodeId.getValue(),ifName.getIfName());
+            default:
+                LOG.error("Unable to read LLDP data for unmanaged openroadm device version");
+                return false;
+        }
+    }
+
+    private boolean rdm2rdmLinkCreatedv221(NodeId nodeId,
+            org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) {
+        boolean success = true;
+        for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName
+            ifName : nbrList.nonnullIfName().values()) {
+            if (ifName.getRemoteSysName() == null) {
+                LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
+                    nodeId.getValue(),ifName.getIfName());
+            } else {
+                Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
+                    .getRemoteSysName());
+                if (!mps.isPresent()) {
+                    LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
+                    // The controller raises a warning rather than an error because the first node to
+                    // mount cannot see its neighbors yet. The link will be detected when processing
+                    // the neighbor node.
                 } else {
-                    Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
-                        .getRemoteSysName());
-                    if (!mps.isPresent()) {
-                        LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
-                        // The controller raises a warning rather than an error because the first node to
-                        // mount cannot see its neighbors yet. The link will be detected when processing
-                        // the neighbor node.
-                    } else {
-                        if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
-                            ifName.getRemotePortId())) {
-                            LOG.error("Link Creation failed between {} and {} nodes.", nodeId.getValue(),
-                                ifName.getRemoteSysName());
-                            success = false;
-                        }
+                    if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
+                        ifName.getRemotePortId())) {
+                        LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName
+                            .getRemoteSysName());
+                        success = false;
                     }
                 }
             }
-            return success;
         }
-        else if (nodeVersion.equals(OPENROADM_DEVICE_VERSION_2_2_1)) {
-            InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
-                .container.org.openroadm.device.Protocols> protocolsIID = InstanceIdentifier.create(org.opendaylight
-                .yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device.container
-                .OrgOpenroadmDevice.class).child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
-                .org.openroadm.device.container.org.openroadm.device.Protocols.class);
-            Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
-                .container.org.openroadm.device.Protocols> protocolObject = this.deviceTransactionManager
-                .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocolsIID,
-                Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
-            if (!protocolObject.isPresent() || (protocolObject.get().augmentation(org.opendaylight.yang.gen.v1.http.org
-                .openroadm.lldp.rev181019.Protocols1.class) == null)) {
-                LOG.warn("LLDP subtree is missing : isolated openroadm device");
-                return false;
-            }
-            org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList nbrList
-                = protocolObject.get().augmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019
-                .Protocols1.class).getLldp().getNbrList();
-            LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size());
-            boolean success = true;
-            for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName
-                ifName : nbrList.nonnullIfName().values()) {
-                if (ifName.getRemoteSysName() == null) {
-                    LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
-                        nodeId.getValue(),ifName.getIfName());
+        return success;
+    }
+
+    private boolean rdm2rdmLinkCreatedv121(NodeId nodeId, NbrList nbrList) {
+        boolean success = true;
+        for (IfName ifName : nbrList.nonnullIfName().values()) {
+            if (ifName.getRemoteSysName() == null) {
+                LOG.warn("LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
+                    nodeId.getValue(),ifName.getIfName());
+            } else {
+                Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
+                    .getRemoteSysName());
+                if (!mps.isPresent()) {
+                    LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
+                    // The controller raises a warning rather than an error because the first node to
+                    // mount cannot see its neighbors yet. The link will be detected when processing
+                    // the neighbor node.
                 } else {
-                    Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
-                        .getRemoteSysName());
-                    if (!mps.isPresent()) {
-                        LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
-                        // The controller raises a warning rather than an error because the first node to
-                        // mount cannot see its neighbors yet. The link will be detected when processing
-                        // the neighbor node.
-                    } else {
-                        if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
-                            ifName.getRemotePortId())) {
-                            LOG.error("Link Creation failed between {} and {} nodes.", nodeId, ifName
-                                .getRemoteSysName());
-                            success = false;
-                        }
+                    if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
+                        ifName.getRemotePortId())) {
+                        LOG.error("Link Creation failed between {} and {} nodes.", nodeId.getValue(),
+                            ifName.getRemoteSysName());
+                        success = false;
                     }
                 }
             }
-            return success;
-        }
-        else {
-            LOG.error("Unable to read LLDP data for unmanaged openroadm device version");
-            return false;
         }
+        return success;
     }
 
     public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
index 478be2601495956735845ccf3ad61fa5ed071bc2..b427c9813e9160d285673d6f3dacf52ea2c3ae79 100644 (file)
@@ -78,6 +78,14 @@ Author: Martial Coulibaly <martial.coulibaly@gfi.com> on behalf of Orange
       <version>${project.version}</version>
     </dependency>
 
+    <!-- Sodium bump: javax.annotation.Nullable and friends -->
+    <dependency>
+      <groupId>com.google.code.findbugs</groupId>
+      <artifactId>jsr305</artifactId>
+      <version>3.0.2</version>
+      <optional>true</optional>
+    </dependency>
+
     <!-- Testing Dependencies -->
     <dependency>
       <groupId>junit</groupId>
diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/R2RTapiLinkDiscovery.java
new file mode 100644 (file)
index 0000000..8982918
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright © 2021 Nokia.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.tapi;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import org.eclipse.jdt.annotation.Nullable;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.MountPoint;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.Network;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.cp.to.degree.CpToDegree;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.NodesKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Protocols;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.Protocols1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.NbrList;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.lldp.container.lldp.nbr.list.IfName;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.AdministrativeState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.CapacityUnit;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ForwardingDirection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LifecycleState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.OperationalState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.TotalSizeBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.AvailableCapacityBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.TotalPotentialCapacityBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ProtectionType;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RestorationPolicy;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.ResilienceTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Link;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanism;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanismBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class R2RTapiLinkDiscovery {
+
+    private static final Logger LOG = LoggerFactory.getLogger(R2RTapiLinkDiscovery.class);
+
+    private final DataBroker dataBroker;
+    private final DeviceTransactionManager deviceTransactionManager;
+    private static final String PHTNC_MEDIA = "PHOTONIC_MEDIA";
+
+    public R2RTapiLinkDiscovery(final DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager) {
+        this.dataBroker = dataBroker;
+        this.deviceTransactionManager = deviceTransactionManager;
+    }
+
+    public Map<LinkKey, Link> readLLDP(NodeId nodeId, int nodeVersion, Uuid tapiTopoUuid) {
+        LOG.info("Tapi R2R Link Node version = {}", nodeVersion);
+        // TODO -> waiting for device 7.1 in network model to change this to a switch statement and include
+        //  support for 7.1 devices
+        switch (nodeVersion) {
+            case 1:
+                // 1.2.1
+                InstanceIdentifier<Protocols> protocols121IID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
+                    .child(Protocols.class);
+                Optional<Protocols> protocol121Object = this.deviceTransactionManager.getDataFromDevice(
+                    nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols121IID, Timeouts.DEVICE_READ_TIMEOUT,
+                    Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+                if (!protocol121Object.isPresent()
+                        || (protocol121Object.get().augmentation(Protocols1.class) == null)) {
+                    LOG.warn("LLDP subtree is missing : isolated openroadm device");
+                    return new HashMap<>();
+                }
+                // get neighbor list
+                NbrList nbr121List = protocol121Object.get().augmentation(Protocols1.class).getLldp().getNbrList();
+                LOG.info("LLDP subtree is present. Device has {} neighbours", nbr121List.getIfName().size());
+                // try to create rdm2rdm link
+                return rdm2rdmLinkCreatev121(nodeId, tapiTopoUuid, nbr121List);
+            case 2:
+                // 2.2.1
+                InstanceIdentifier<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
+                    .container.org.openroadm.device.Protocols> protocols221IID =
+                        InstanceIdentifier.create(org.opendaylight.yang.gen.v1.http
+                            .org.openroadm.device.rev181019.org.openroadm.device.container.OrgOpenroadmDevice.class)
+                            .child(org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019
+                                .org.openroadm.device.container.org.openroadm.device.Protocols.class);
+                Optional<org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev181019.org.openroadm.device
+                    .container.org.openroadm.device.Protocols> protocol221Object = this.deviceTransactionManager
+                    .getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL, protocols221IID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+                if (!protocol221Object.isPresent() || (protocol221Object.get().augmentation(
+                        org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.Protocols1.class) == null)) {
+                    LOG.warn("LLDP subtree is missing : isolated openroadm device");
+                    return new HashMap<>();
+                }
+                org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.@Nullable NbrList
+                    nbr221List = protocol221Object.get().augmentation(org.opendaylight.yang.gen.v1.http
+                        .org.openroadm.lldp.rev181019.Protocols1.class).getLldp().getNbrList();
+                LOG.info("LLDP subtree is present. Device has {} neighbours", nbr221List.getIfName().size());
+                return rdm2rdmLinkCreatev221(nodeId, tapiTopoUuid, nbr221List);
+            case 3:
+                // 7.1.0
+                LOG.info("Not yet supported?");
+                return new HashMap<>();
+            default:
+                LOG.error("Unable to read LLDP data for unmanaged openroadm device version");
+                return new HashMap<>();
+        }
+    }
+
+    private Map<LinkKey, Link> rdm2rdmLinkCreatev221(NodeId nodeId, Uuid tapiTopoUuid,
+            org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.NbrList nbrList) {
+        Map<LinkKey, Link> linkMap = new HashMap<>();
+        for (org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev181019.lldp.container.lldp.nbr.list.IfName
+                ifName : nbrList.nonnullIfName().values()) {
+            if (ifName.getRemoteSysName() == null) {
+                LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
+                    nodeId.getValue(),ifName.getIfName());
+                continue;
+            }
+            Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName());
+            if (!mps.isPresent()) {
+                LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
+                // The controller raises a warning rather than an error because the first node to
+                // mount cannot see its neighbors yet. The link will be detected when processing
+                // the neighbor node.
+                continue;
+            }
+            Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
+                ifName.getRemotePortId(), tapiTopoUuid);
+            if (omsLink != null) {
+                linkMap.put(omsLink.key(), omsLink);
+            }
+        }
+        return linkMap;
+    }
+
+    private Map<LinkKey, Link> rdm2rdmLinkCreatev121(NodeId nodeId, Uuid tapiTopoUuid, NbrList nbrList) {
+        Map<LinkKey, Link> linkMap = new HashMap<>();
+        for (IfName ifName : nbrList.nonnullIfName().values()) {
+            if (ifName.getRemoteSysName() == null) {
+                LOG.warn("Tapi R2R Link LLDP subtree neighbour is empty for nodeId: {}, ifName: {}",
+                    nodeId.getValue(),ifName.getIfName());
+                continue;
+            }
+            Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName
+                .getRemoteSysName());
+            if (!mps.isPresent()) {
+                LOG.warn("Tapi R2R Link Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
+                // The controller raises a warning rather than an error because the first node to
+                // mount cannot see its neighbors yet. The link will be detected when processing
+                // the neighbor node.
+                continue;
+            }
+            Link omsLink = createR2RTapiLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
+                ifName.getRemotePortId(), tapiTopoUuid);
+            if (omsLink != null) {
+                linkMap.put(omsLink.key(), omsLink);
+            }
+        }
+        return linkMap;
+    }
+
+    public Link createR2RTapiLink(NodeId nodeId, String interfaceName, String remoteSystemName,
+                                 String remoteInterfaceName, Uuid tapiTopoUuid) {
+        String srcTpTx = null;
+        String srcTpRx = null;
+        String destTpTx = null;
+        String destTpRx = null;
+        // Find which degree is associated with ethernet interface
+        Integer srcDegId = getDegFromInterface(nodeId, interfaceName);
+        if (srcDegId == null) {
+            LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return null;
+        }
+        // Check whether degree is Unidirectional or Bidirectional by counting
+        // number of
+        // circuit-packs under degree subtree
+        Direction sourceDirection = getDegreeDirection(srcDegId, nodeId);
+        if (Direction.NotApplicable == sourceDirection) {
+            LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
+            return null;
+        } else if (Direction.Bidirectional == sourceDirection) {
+            srcTpTx = "DEG" + srcDegId + "-TTP-TXRX";
+            srcTpRx = "DEG" + srcDegId + "-TTP-TXRX";
+        } else {
+            srcTpTx = "DEG" + srcDegId + "-TTP-TX";
+            srcTpRx = "DEG" + srcDegId + "-TTP-RX";
+        }
+        LOG.debug("Tapi R2R Link SrcTPTx {}, SrcTPRx {}", srcTpTx, srcTpRx);
+        // Find degree for which Ethernet interface is created on other end
+        NodeId destNodeId = new NodeId(remoteSystemName);
+        Integer destDegId = getDegFromInterface(destNodeId, remoteInterfaceName);
+        if (destDegId == null) {
+            LOG.error("Tapi R2R Link Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return null;
+        }
+        // Check whether degree is Unidirectional or Bidirectional by counting
+        // number of
+        // circuit-packs under degree subtree
+        Direction destinationDirection = getDegreeDirection(destDegId, destNodeId);
+        if (Direction.NotApplicable == destinationDirection) {
+            LOG.error("Tapi R2R Link Couldnt find degree direction for nodeId: {} and degree: {}",
+                destNodeId, destDegId);
+            return null;
+        } else if (Direction.Bidirectional == destinationDirection) {
+            destTpTx = "DEG" + destDegId + "-TTP-TXRX";
+            destTpRx = "DEG" + destDegId + "-TTP-TXRX";
+        } else {
+            destTpTx = "DEG" + destDegId + "-TTP-TX";
+            destTpRx = "DEG" + destDegId + "-TTP-RX";
+        }
+        // Todo -> only handling for the bidirectional case. I assume all tps are of the type bidirectional
+        LOG.debug("Tapi R2R Link DstTPTx {}, DstTPRx {}", destTpTx, srcTpRx);
+        // Create OMS Tapi Link
+        LOG.info("Tapi R2R Link Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , "
+            + "DestDegId: {}, DestTPId: {}", nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx);
+        Link omsLink = createTapiLink(nodeId.getValue(), srcTpTx, destNodeId.getValue(), destTpRx, tapiTopoUuid);
+        LOG.info("Tapi R2R Link OMS link created = {}", omsLink);
+        return omsLink;
+    }
+
+    private Link createTapiLink(String sourceNode, String sourceTp, String destNode, String destTp, Uuid tapiTopoUuid) {
+        Map<NodeEdgePointKey, NodeEdgePoint> nepList = new HashMap<>();
+        Uuid sourceUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode,
+            PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString());
+        Uuid sourceUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", sourceNode, PHTNC_MEDIA, sourceTp))
+            .getBytes(Charset.forName("UTF-8"))).toString());
+        Uuid destUuidNode = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode,
+            PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString());
+        Uuid destUuidTp = new Uuid(UUID.nameUUIDFromBytes((String.join("+", destNode, PHTNC_MEDIA, destTp))
+            .getBytes(Charset.forName("UTF-8"))).toString());
+        NodeEdgePoint sourceNep = new NodeEdgePointBuilder()
+            .setTopologyUuid(tapiTopoUuid)
+            .setNodeUuid(sourceUuidNode)
+            .setNodeEdgePointUuid(sourceUuidTp)
+            .build();
+        nepList.put(sourceNep.key(), sourceNep);
+        NodeEdgePoint destNep = new NodeEdgePointBuilder()
+            .setTopologyUuid(tapiTopoUuid)
+            .setNodeUuid(destUuidNode)
+            .setNodeEdgePointUuid(destUuidTp)
+            .build();
+        nepList.put(destNep.key(), destNep);
+        String linkNameValue = String.join("-", sourceNode, sourceTp.split("-")[0], sourceTp)
+            + "to" + String.join("-", destNode, destTp.split("-")[0], destTp);
+        Name linkName = new NameBuilder().setValueName("OMS link name")
+            .setValue(linkNameValue)
+            .build();
+        CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+            .setCostAlgorithm("Restricted Shortest Path - RSP")
+            .setCostName("HOP_COUNT")
+            .setCostValue("12345678")
+            .build();
+        LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+            .setFixedLatencyCharacteristic("12345678")
+            .setQueingLatencyCharacteristic("12345678")
+            .setJitterCharacteristic("12345678")
+            .setWanderCharacteristic("12345678")
+            .setTrafficPropertyName("FIXED_LATENCY")
+            .build();
+        RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder()
+            .setRiskCharacteristicName("risk characteristic")
+            .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2"))
+            .build();
+        ValidationMechanism validationMechanism = new ValidationMechanismBuilder()
+            .setValidationMechanism("validation mechanism")
+            .setValidationRobustness("validation robustness")
+            .setLayerProtocolAdjacencyValidated("layer protocol adjacency")
+            .build();
+        return new LinkBuilder()
+            .setUuid(new Uuid(
+                UUID.nameUUIDFromBytes(linkNameValue.getBytes(Charset.forName("UTF-8")))
+                    .toString()))
+            .setName(Map.of(linkName.key(), linkName))
+            .setLayerProtocolName(List.of(LayerProtocolName.PHOTONICMEDIA))
+            .setTransitionedLayerProtocolName(new ArrayList<>())
+            .setNodeEdgePoint(nepList)
+            .setDirection(ForwardingDirection.BIDIRECTIONAL)
+            .setResilienceType(new ResilienceTypeBuilder().setProtectionType(ProtectionType.NOPROTECTON)
+                .setRestorationPolicy(RestorationPolicy.NA)
+                .build())
+            .setAdministrativeState(AdministrativeState.UNLOCKED)
+            .setOperationalState(OperationalState.ENABLED)
+            .setLifecycleState(LifecycleState.INSTALLED)
+            .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().setTotalSize(
+                new TotalSizeBuilder().setUnit(CapacityUnit.GBPS)
+                    .setValue(Uint64.valueOf(100)).build()).build())
+            .setAvailableCapacity(new AvailableCapacityBuilder().setTotalSize(
+                new TotalSizeBuilder().setUnit(CapacityUnit.MBPS)
+                    .setValue(Uint64.valueOf(100)).build())
+                .build())
+            .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+            .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+            .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic))
+            .setErrorCharacteristic("error")
+            .setLossCharacteristic("loss")
+            .setRepeatDeliveryCharacteristic("repeat delivery")
+            .setDeliveryOrderCharacteristic("delivery order")
+            .setUnavailableTimeCharacteristic("unavailable time")
+            .setServerIntegrityProcessCharacteristic("server integrity process")
+            .setValidationMechanism(Map.of(validationMechanism.key(), validationMechanism))
+            .build();
+    }
+
+    private Integer getDegFromInterface(NodeId nodeId, String interfaceName) {
+        InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
+            .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
+        try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
+            Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
+            if (nodesObject.isEmpty() || (nodesObject.get().getCpToDegree() == null)) {
+                LOG.warn("Could not find mapping for Interface {} for nodeId {}", interfaceName,
+                    nodeId.getValue());
+                return null;
+            }
+            Collection<CpToDegree> cpToDeg = nodesObject.get().nonnullCpToDegree().values();
+            Stream<CpToDegree> cpToDegStream = cpToDeg.stream().filter(cp -> cp.getInterfaceName() != null)
+                .filter(cp -> cp.getInterfaceName().equals(interfaceName));
+            if (cpToDegStream != null) {
+                @SuppressWarnings("unchecked") Optional<CpToDegree> firstCpToDegree = cpToDegStream.findFirst();
+                if (firstCpToDegree.isEmpty() || (firstCpToDegree == null)) {
+                    LOG.debug("Not found so returning nothing");
+                    return null;
+                }
+                LOG.debug("Found and returning {}",firstCpToDegree.get().getDegreeNumber().intValue());
+                return firstCpToDegree.get().getDegreeNumber().intValue();
+            } else {
+                LOG.warn("CircuitPack stream couldnt find anything for nodeId: {} and interfaceName: {}",
+                    nodeId.getValue(),interfaceName);
+            }
+        } catch (InterruptedException | ExecutionException ex) {
+            LOG.error("Unable to read mapping for Interface : {} for nodeId {}", interfaceName, nodeId, ex);
+        }
+        return null;
+    }
+
+    public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
+        InstanceIdentifier<Nodes> nodesIID = InstanceIdentifier.builder(Network.class)
+            .child(Nodes.class, new NodesKey(nodeId.getValue())).build();
+        try (ReadTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
+            Optional<Nodes> nodesObject = readTx.read(LogicalDatastoreType.CONFIGURATION, nodesIID).get();
+            if (nodesObject.isPresent() && (nodesObject.get().getMapping() != null)) {
+                Collection<Mapping> mappingList = nodesObject.get().nonnullMapping().values();
+                mappingList = mappingList.stream().filter(mp -> mp.getLogicalConnectionPoint().contains("DEG"
+                    + degreeCounter)).collect(Collectors.toList());
+                if (mappingList.size() == 1) {
+                    return Direction.Bidirectional;
+                } else if (mappingList.size() > 1) {
+                    return Direction.Tx;
+                }
+            }
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed getting Mapping data from portMapping",e);
+        }
+        return Direction.NotApplicable;
+    }
+}
index 68c9f023699fce3c319a24dc0f03d475d3af1dec..7beb695cb3e7a2d69b6acf6e06ffd7adb0ca8b27 100644 (file)
@@ -13,19 +13,26 @@ import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
 import org.opendaylight.mdsal.binding.api.RpcProviderService;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
 import org.opendaylight.transportpce.common.network.NetworkTransactionService;
 import org.opendaylight.transportpce.servicehandler.service.ServiceDataStoreOperations;
 import org.opendaylight.transportpce.tapi.connectivity.ConnectivityUtils;
 import org.opendaylight.transportpce.tapi.connectivity.TapiConnectivityImpl;
+import org.opendaylight.transportpce.tapi.topology.TapiNetconfTopologyListener;
+import org.opendaylight.transportpce.tapi.topology.TapiPortMappingListener;
 import org.opendaylight.transportpce.tapi.topology.TapiTopologyImpl;
 import org.opendaylight.transportpce.tapi.topology.TopologyUtils;
 import org.opendaylight.transportpce.tapi.utils.TapiContext;
 import org.opendaylight.transportpce.tapi.utils.TapiInitialORMapping;
 import org.opendaylight.transportpce.tapi.utils.TapiListener;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.Network;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev190531.OrgOpenroadmServiceService;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.TapiConnectivityService;
 import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.TapiTopologyService;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.tapi.rev180928.ServiceInterfacePoints;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
@@ -41,23 +48,33 @@ public class TapiProvider {
 
     private static final Logger LOG = LoggerFactory.getLogger(TapiProvider.class);
 
+    private static final InstanceIdentifier<Nodes> MAPPING_II = InstanceIdentifier.create(Network.class)
+        .child(org.opendaylight.yang.gen.v1.http
+            .org.opendaylight.transportpce.portmapping.rev210315.network.Nodes.class);
     private final DataBroker dataBroker;
     private final RpcProviderService rpcProviderService;
     private ObjectRegistration<TapiConnectivityService> rpcRegistration;
+    private ListenerRegistration<TapiNetconfTopologyListener> dataTreeChangeListenerRegistration;
+    private ListenerRegistration<TapiPortMappingListener> mappingListenerListenerRegistration;
     private final OrgOpenroadmServiceService serviceHandler;
     private final ServiceDataStoreOperations serviceDataStoreOperations;
     private final TapiListener tapiListener;
+    private final TapiNetconfTopologyListener topologyListener;
+    private TapiPortMappingListener tapiPortMappingListener;
     private final NetworkTransactionService networkTransactionService;
 
     public TapiProvider(DataBroker dataBroker, RpcProviderService rpcProviderService,
             OrgOpenroadmServiceService serviceHandler, ServiceDataStoreOperations serviceDataStoreOperations,
-            TapiListener tapiListener, NetworkTransactionService networkTransactionService) {
+            TapiListener tapiListener, NetworkTransactionService networkTransactionService,
+            TapiNetconfTopologyListener topologyListener, TapiPortMappingListener tapiPortMappingListener) {
         this.dataBroker = dataBroker;
         this.rpcProviderService = rpcProviderService;
         this.serviceHandler = serviceHandler;
         this.serviceDataStoreOperations = serviceDataStoreOperations;
         this.tapiListener = tapiListener;
         this.networkTransactionService = networkTransactionService;
+        this.topologyListener = topologyListener;
+        this.tapiPortMappingListener = tapiPortMappingListener;
     }
 
     /**
@@ -80,6 +97,12 @@ public class TapiProvider {
         TapiTopologyImpl topo = new TapiTopologyImpl(this.dataBroker, tapiContext, topologyUtils);
         rpcRegistration = rpcProviderService.registerRpcImplementation(TapiConnectivityService.class, tapi);
         rpcProviderService.registerRpcImplementation(TapiTopologyService.class, topo);
+        dataTreeChangeListenerRegistration =
+            dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), topologyListener);
+        mappingListenerListenerRegistration =
+            dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(LogicalDatastoreType.CONFIGURATION,
+                MAPPING_II), tapiPortMappingListener);
         @NonNull
         InstanceIdentifier<ServiceInterfacePoints> sipIID = InstanceIdentifier.create(ServiceInterfacePoints.class);
         dataBroker.registerDataTreeChangeListener(DataTreeIdentifier.create(
@@ -91,6 +114,12 @@ public class TapiProvider {
      */
     public void close() {
         LOG.info("TapiProvider Session Closed");
+        if (dataTreeChangeListenerRegistration != null) {
+            dataTreeChangeListenerRegistration.close();
+        }
+        if (mappingListenerListenerRegistration != null) {
+            mappingListenerListenerRegistration.close();
+        }
         rpcRegistration.close();
     }
 }
diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetconfTopologyListener.java
new file mode 100644 (file)
index 0000000..85c3e0a
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2021 Nokia, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.tapi.topology;
+
+import java.util.Collection;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.api.DataObjectModification;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.transportpce.common.StringConstants;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.netconf.node.connection.status.available.capabilities.AvailableCapability;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TapiNetconfTopologyListener implements DataTreeChangeListener<Node> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TapiNetconfTopologyListener.class);
+    private final TapiNetworkModelService tapiNetworkModelService;
+
+    public TapiNetconfTopologyListener(final TapiNetworkModelService tapiNetworkModelService) {
+        this.tapiNetworkModelService = tapiNetworkModelService;
+    }
+
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        LOG.info("onDataTreeChanged - {}", this.getClass().getSimpleName());
+        for (DataTreeModification<Node> change : changes) {
+            DataObjectModification<Node> rootNode = change.getRootNode();
+            if (rootNode.getDataBefore() == null) {
+                continue;
+            }
+            String nodeId = rootNode.getDataBefore().key().getNodeId().getValue();
+            NetconfNode netconfNodeBefore = rootNode.getDataBefore().augmentation(NetconfNode.class);
+            switch (rootNode.getModificationType()) {
+                case DELETE:
+                    this.tapiNetworkModelService.deleteTapinode(nodeId);
+                    // TODO -> unregistration to NETCONF stream not yet supported
+                    // onDeviceDisConnected(nodeId);
+                    LOG.info("Device {} correctly disconnected from controller", nodeId);
+                    break;
+                case WRITE:
+                    NetconfNode netconfNodeAfter = rootNode.getDataAfter().augmentation(NetconfNode.class);
+                    if (ConnectionStatus.Connecting.equals(netconfNodeBefore.getConnectionStatus())
+                            && ConnectionStatus.Connected.equals(netconfNodeAfter.getConnectionStatus())) {
+                        LOG.info("Connecting Node: {}", nodeId);
+                        Optional<AvailableCapability> deviceCapabilityOpt = netconfNodeAfter
+                            .getAvailableCapabilities().getAvailableCapability().stream()
+                            .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME))
+                            .sorted((c1, c2) -> c2.getCapability().compareTo(c1.getCapability()))
+                            .findFirst();
+                        if (deviceCapabilityOpt.isEmpty()) {
+                            LOG.error("Unable to get openroadm-device-capability");
+                            return;
+                        }
+                        // TODO -> subscription to NETCONF stream not yet supported... no listeners implementation
+                        // onDeviceConnected(nodeId,deviceCapabilityOpt.get().getCapability());
+                        LOG.info("Device {} waiting for portmapping to be populated", nodeId);
+                    }
+                    if (ConnectionStatus.Connected.equals(netconfNodeBefore.getConnectionStatus())
+                            && ConnectionStatus.Connecting.equals(netconfNodeAfter.getConnectionStatus())) {
+                        LOG.warn("Node: {} is being disconnected", nodeId);
+                    }
+                    break;
+                default:
+                    LOG.debug("Unknown modification type {}", rootNode.getModificationType().name());
+                    break;
+            }
+        }
+    }
+}
diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelService.java
new file mode 100644 (file)
index 0000000..85df605
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2021 Nokia, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.tapi.topology;
+
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes;
+
+public interface TapiNetworkModelService {
+
+    /**
+     * Create new TAPI node in tapi topologies.
+     *
+     * @param orNodeId
+     *     unique node ID of new OpenROADM node
+     * @param orNodeVersion
+     *     OpenROADM node version
+     * @param node
+     *     OpenRoadm node
+     */
+    void createTapiNode(String orNodeId, int orNodeVersion, Nodes node);
+
+    /**
+     * Delete TAPI node in topologies and update corresponding TAPI context objects.
+     *
+     * @param nodeId
+     *     unique node ID of OpenROADM node.
+     *
+     */
+    void deleteTapinode(String nodeId);
+}
diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiNetworkModelServiceImpl.java
new file mode 100644 (file)
index 0000000..863103c
--- /dev/null
@@ -0,0 +1,1394 @@
+/*
+ * Copyright © 2021 Nokia, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.tapi.topology;
+
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.network.NetworkTransactionService;
+import org.opendaylight.transportpce.tapi.R2RTapiLinkDiscovery;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev181019.NodeTypes;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.types.rev191129.XpdrNodeTypes;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.OduSwitchingPools;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.OduSwitchingPoolsBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingList;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingListBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.types.rev200327.xpdr.odu.switching.pools.odu.switching.pools.NonBlockingListKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.OpenroadmNodeType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapability;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev200529.xpdr.tp.supported.interfaces.SupportedInterfaceCapabilityKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If100GE;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If100GEODU4;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GE;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GEODU2;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If10GEODU2e;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If1GE;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.If1GEODU0;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.IfOCH;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.IfOCHOTU4ODU4;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.port.types.rev200327.SupportedIfCapability;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.switching.pool.types.rev191129.SwitchingPoolTypes;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev180226.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev180226.TpId;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.AdministrativeState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.CapacityUnit;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Context;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ContextBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.ForwardingDirection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LAYERPROTOCOLQUALIFIER;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LayerProtocolName;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.LifecycleState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.OperationalState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.PortDirection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.PortRole;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.TerminationDirection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.TerminationState;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.Uuid;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.TotalSizeBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.AvailableCapacityBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.capacity.pac.TotalPotentialCapacityBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.Name;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.global._class.NameKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.Connection;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectionKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityService;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityServiceBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.context.ConnectivityServiceKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.EndPoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.connectivity.service.EndPointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.context.ConnectivityContext;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.dsr.rev181210.DIGITALSIGNALTYPE100GigE;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.dsr.rev181210.DIGITALSIGNALTYPE10GigELAN;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU2;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU2E;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.odu.rev181210.ODUTYPEODU4;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.photonic.media.rev181210.PHOTONICLAYERQUALIFIEROMS;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.photonic.media.rev181210.PHOTONICLAYERQUALIFIEROTSi;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ForwardingRule;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.ProtectionType;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RestorationPolicy;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.RuleType;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.NodeEdgePointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.link.ResilienceTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroup;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroupBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.NodeRuleGroupKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.OwnedNodeEdgePointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePoint;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePointBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.edge.point.MappedServiceInterfacePointKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.Rule;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.RuleBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.RuleKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.risk.parameter.pac.RiskCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Link;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.LinkKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.Topology;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.TopologyBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.context.TopologyKey;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.cost.pac.CostCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristic;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.transfer.timing.pac.LatencyCharacteristicBuilder;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanism;
+import org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.validation.pac.ValidationMechanismBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TapiNetworkModelServiceImpl implements TapiNetworkModelService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TapiNetworkModelServiceImpl.class);
+    private static final String DSR = "DSR";
+    private static final String I_ODU = "iODU";
+    private static final String E_ODU = "eODU";
+    private static final String OTSI = "OTSi";
+    private static final String E_OTSI = "eOTSi";
+    private static final String I_OTSI = "iOTSi";
+    private static final String PHTNC_MEDIA = "PHOTONIC_MEDIA";
+    private static final String MC = "MEDIA_CHANNEL";
+    private static final String OTSI_MC = "OTSi_MEDIA_CHANNEL";
+    private static final String CLIENT = "-CLIENT";
+    private static final String NETWORK = "-NETWORK";
+    private static final String XPDR = "-XPDR";
+    private final Uuid tapiTopoUuid = new Uuid(UUID.nameUUIDFromBytes(TopologyUtils.T0_FULL_MULTILAYER
+            .getBytes(Charset.forName("UTF-8"))).toString());
+    private final NetworkTransactionService networkTransactionService;
+    private Map<ServiceInterfacePointKey, ServiceInterfacePoint> sipMap;
+    private final R2RTapiLinkDiscovery linkDiscovery;
+
+    public TapiNetworkModelServiceImpl(final R2RTapiLinkDiscovery linkDiscovery,
+                                       NetworkTransactionService networkTransactionService) {
+        this.networkTransactionService = networkTransactionService;
+        this.sipMap = new HashMap<>();
+        this.linkDiscovery = linkDiscovery;
+    }
+
+    @Override
+    public void createTapiNode(String orNodeId, int orNodeVersion, Nodes node) {
+        // TODO -> Implementation with PortMappingListener
+        // check if port mapping exists or not...
+        if (node.getMapping() == null) {
+            LOG.warn("Could not generate port mapping for {} skipping network model creation", orNodeId);
+            return;
+        }
+        this.sipMap.clear();
+        LOG.info("Mapping of node {}: {}", orNodeId, node.getMapping().values());
+
+        // check type of device, check version and create node mapping
+        if (NodeTypes.Rdm.getIntValue() == node.getNodeInfo().getNodeType().getIntValue()) {
+            // ROADM device
+            // transform flat mapping list to per degree and per srg mapping lists
+            Map<String, List<Mapping>> mapDeg = new HashMap<>();
+            Map<String, List<Mapping>> mapSrg = new HashMap<>();
+            List<Mapping> mappingList = new ArrayList<>(node.nonnullMapping().values());
+            mappingList.sort(Comparator.comparing(Mapping::getLogicalConnectionPoint));
+
+            List<String> nodeShardList = getRoadmNodelist(mappingList);
+
+            // populate degree and srg LCP map
+            for (String str : nodeShardList) {
+                List<Mapping> interList = mappingList.stream().filter(x -> x.getLogicalConnectionPoint().contains(str))
+                        .collect(Collectors.toList());
+                if (str.contains("DEG")) {
+                    mapDeg.put(str, interList);
+                } else if (str.contains("SRG")) {
+                    mapSrg.put(str, interList);
+                } else {
+                    LOG.error("unknown element");
+                }
+            }
+            // Transform LCPs into ONEP
+            Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap =
+                new HashMap<>(transformDegToOnep(orNodeId, mapDeg));
+            onepMap.putAll(transformSrgToOnep(orNodeId, mapSrg));
+
+            // create tapi Node
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node roadmNode =
+                    createRoadmTapiNode(orNodeId, onepMap);
+            // TODO add states corresponding to device config -> based on mapping.
+            //  This should be possible after Gilles work is merged
+
+            // rdm to rdm link creation if neighbour roadm is mounted
+            LOG.info("checking if neighbor roadm exists");
+            Map<LinkKey, Link> rdm2rdmLinks = this.linkDiscovery.readLLDP(new NodeId(orNodeId), orNodeVersion,
+                this.tapiTopoUuid);
+            mergeNodeinTopology(Map.of(roadmNode.key(), roadmNode));
+            mergeSipsinContext(this.sipMap);
+            if (!rdm2rdmLinks.isEmpty()) {
+                mergeLinkinTopology(rdm2rdmLinks);
+            }
+
+        } else if (NodeTypes.Xpdr.getIntValue() ==  node.getNodeInfo().getNodeType().getIntValue()) {
+            List<Mapping> networkMappings = node.nonnullMapping().values()
+                    .stream().filter(k -> k.getLogicalConnectionPoint()
+                            .contains("NETWORK")).collect(Collectors.toList());
+            Map<Integer, String> xpdrMap = new HashMap<>();
+            for (Mapping mapping : networkMappings) {
+                Integer xpdrNb = Integer.parseInt(mapping.getLogicalConnectionPoint().split("XPDR")[1].split("-")[0]);
+                String nodeId = node.getNodeId() + XPDR + xpdrNb;
+                if (!xpdrMap.containsKey(xpdrNb)) {
+                    List<Mapping> xpdrNetMaps = node.nonnullMapping().values()
+                            .stream().filter(k -> k.getLogicalConnectionPoint()
+                                    .contains("XPDR" + xpdrNb + NETWORK)).collect(Collectors.toList());
+                    List<Mapping> xpdrClMaps = node.nonnullMapping().values()
+                            .stream().filter(k -> k.getLogicalConnectionPoint()
+                                    .contains("XPDR" + xpdrNb + CLIENT)).collect(Collectors.toList());
+                    xpdrMap.put(xpdrNb, node.getNodeId());
+
+                    // create switching pool
+                    OduSwitchingPools oorOduSwitchingPool = createSwitchPoolForXpdr(
+                        mapping.getXponderType().getIntValue(), xpdrClMaps, xpdrNetMaps, xpdrNb);
+
+                    // node transformation
+                    Map<NodeKey, Node> nodeMap = new HashMap<>(transformXpdrToTapiNode(
+                        nodeId, xpdrClMaps, xpdrNetMaps, mapping.getXponderType(), oorOduSwitchingPool,
+                        mapping.getSupportedInterfaceCapability()));
+
+                    // add nodes and sips to tapi context
+                    mergeNodeinTopology(nodeMap);
+                    mergeSipsinContext(this.sipMap);
+                }
+            }
+        }
+        // Device not managed yet
+    }
+
+    private Map<NodeKey, Node> transformXpdrToTapiNode(String nodeId, List<Mapping> xpdrClMaps,
+                                                       List<Mapping> xpdrNetMaps, XpdrNodeTypes xponderType,
+                                                       OduSwitchingPools oorOduSwitchingPool,
+                                                       List<Class<? extends SupportedIfCapability>>
+                                                           supportedInterfaceCapability) {
+        Map<NodeKey, Node> nodeMap = new HashMap<>();
+        LOG.info("creation of a DSR/ODU node for {}", nodeId);
+        Uuid nodeUuidDsr = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, DSR))
+            .getBytes(Charset.forName("UTF-8"))).toString());
+        Name nameDsr = new NameBuilder().setValueName("dsr/odu node name").setValue(
+            String.join("+", nodeId, DSR)).build();
+        List<LayerProtocolName> dsrLayerProtocols = Arrays.asList(LayerProtocolName.DSR,
+            LayerProtocolName.ODU);
+        org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology
+            .Node dsrNode = createTapiXpdrNode(Map.of(nameDsr.key(), nameDsr), dsrLayerProtocols,
+            nodeId, nodeUuidDsr, xpdrClMaps, xpdrNetMaps, xponderType, oorOduSwitchingPool,
+            supportedInterfaceCapability);
+
+        nodeMap.put(dsrNode.key(), dsrNode);
+
+        // node creation [otsi]
+        LOG.info("creation of an OTSi node for {}", nodeId);
+        Uuid nodeUuidOtsi = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, OTSI))
+            .getBytes(Charset.forName("UTF-8"))).toString());
+        Name nameOtsi =  new NameBuilder().setValueName("otsi node name").setValue(
+            String.join("+", nodeId, OTSI)).build();
+        List<LayerProtocolName> otsiLayerProtocols = Arrays.asList(LayerProtocolName.PHOTONICMEDIA);
+        org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology
+            .Node otsiNode = createTapiXpdrNode(Map.of(nameOtsi.key(), nameOtsi), otsiLayerProtocols,
+            nodeId, nodeUuidOtsi, xpdrClMaps, xpdrNetMaps, xponderType, null,
+            supportedInterfaceCapability);
+
+        nodeMap.put(otsiNode.key(), otsiNode);
+
+        // transitional link cration between network nep of DSR/ODU node and iNep of otsi node
+        LOG.info("creation of transitional links between DSR/ODU and OTSi nodes");
+        Map<LinkKey, Link> linkMap = createTapiTransitionalLinks(nodeId, xpdrNetMaps, nodeUuidDsr,
+            nodeUuidOtsi);
+        mergeLinkinTopology(linkMap);
+
+        return nodeMap;
+    }
+
+    private OduSwitchingPools createSwitchPoolForXpdr(int xpdrType, List<Mapping> xpdrClMaps, List<Mapping> xpdrNetMaps,
+                                                      Integer xpdrNb) {
+        // todo: are switching pool correct here??
+        switch (xpdrType) {
+            case 1:
+                // Tpdr
+                return createTpdrSwitchPool();
+            case 2:
+                // Mux
+                return createMuxSwitchPool(xpdrClMaps, xpdrNetMaps, xpdrNb);
+            case 3:
+                // Switch
+                return createSwtchSwitchPool(xpdrClMaps, xpdrNetMaps, xpdrNb);
+            default:
+                LOG.warn("Xpdr type {} not supported", xpdrType);
+        }
+        return null;
+    }
+
+    private Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> transformSrgToOnep(String orNodeId,
+                                                                              Map<String, List<Mapping>> mapSrg) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap = new HashMap<>();
+        for (Map.Entry<String, List<Mapping>> entry : mapSrg.entrySet()) {
+            // For each srg node. Loop through the LCPs and create neps and sips for PP
+            for (Mapping m:entry.getValue()) {
+                if (!m.getLogicalConnectionPoint().contains("PP")) {
+                    LOG.info("LCP {} is not an external TP of SRG node", m.getLogicalConnectionPoint());
+                    continue;
+                }
+                Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> srgNeps =
+                    createRoadmNeps(orNodeId, m.getLogicalConnectionPoint(), true);
+                onepMap.putAll(srgNeps);
+            }
+        }
+        return onepMap;
+    }
+
+    private Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> transformDegToOnep(String orNodeId,
+                                                                              Map<String, List<Mapping>> mapDeg) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap = new HashMap<>();
+        for (Map.Entry<String, List<Mapping>> entry : mapDeg.entrySet()) {
+            // For each degree node. Loop through the LCPs and create neps and sips for TTP
+            for (Mapping m:entry.getValue()) {
+                if (!m.getLogicalConnectionPoint().contains("TTP")) {
+                    LOG.info("LCP {} is not an external TP of DEGREE node", m.getLogicalConnectionPoint());
+                    continue;
+                }
+                Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> degNeps =
+                    createRoadmNeps(orNodeId, m.getLogicalConnectionPoint(), false);
+                onepMap.putAll(degNeps);
+            }
+        }
+        return onepMap;
+    }
+
+    private List<String> getRoadmNodelist(List<Mapping> mappingList) {
+        List<String> nodeShardList = new ArrayList<>();
+        for (Mapping mapping : mappingList) {
+            // TODO -> maybe we need to check the id based on the version
+            String str = mapping.getLogicalConnectionPoint().split("-")[0];
+            LOG.info("LCP = {}", str);
+            if (!nodeShardList.contains(str)) {
+                nodeShardList.add(str);
+            }
+        }
+        return nodeShardList;
+    }
+
+    @Override
+    public void deleteTapinode(String nodeId) {
+        // TODO: check for null objects
+        // Check if it is ROADM or XPDR --> create the uuids of the node and delete from topology the node.
+        // This will delete NEPs. Then check for links that have this node and delete them.
+        // Then check SIPs and delete them. Then services and connections with SIPs and put them to another state.
+        LOG.info("Deleting node {} from TAPI topology", nodeId);
+        InstanceIdentifier<Topology> topologyIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class,
+                        new TopologyKey(tapiTopoUuid)).build();
+        Topology topology = null;
+        try {
+            Optional<Topology> optTopology =
+                    this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, topologyIID).get();
+            if (!optTopology.isPresent()) {
+                LOG.error("No topology object present. Error deleting node {}", nodeId);
+                return;
+            }
+            topology = optTopology.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Couldnt read tapi topology from datastore", e);
+        }
+        if (topology == null) {
+            LOG.error("Topology is null, nothing to delete");
+            return;
+        }
+        if (topology.getNode() == null) {
+            LOG.error("No nodes in topology");
+            return;
+        }
+        if (nodeId.contains("ROADM")) {
+            // Node is in photonic media layer and UUID can be built from nodeId + PHTN_MEDIA
+            Uuid nodeUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", nodeId, PHTNC_MEDIA))
+                    .getBytes(Charset.forName("UTF-8"))).toString());
+            deleteNodeFromTopo(nodeUuid);
+        }
+        if (nodeId.contains("XPDR") || nodeId.contains("SPDR") || nodeId.contains("MXPDR")) {
+            // Node is either XPDR, MXPDR or SPDR. Retrieve nodes from topology and check names
+            for (Node tapiNode:topology.getNode().values()) {
+                if (tapiNode.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) {
+                    // Found node we need to delete
+                    deleteNodeFromTopo(tapiNode.getUuid());
+                }
+            }
+        }
+        // Delete links of topology
+        Map<LinkKey, Link> linkMap = topology.getLink();
+        if (linkMap != null) {
+            for (Link link:linkMap.values()) {
+                if (link.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) {
+                    deleteLinkFromTopo(link.getUuid());
+                }
+            }
+        }
+        // Delete sips of sip map
+        InstanceIdentifier<Context> contextIID = InstanceIdentifier.builder(Context.class).build();
+        Context context = null;
+        try {
+            Optional<Context> optContext = this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL,
+                    contextIID).get();
+            if (!optContext.isPresent()) {
+                LOG.error("No context object present in datastore.");
+                return;
+            }
+            context = optContext.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Couldnt read tapi context from datastore", e);
+        }
+        if (context == null) {
+            LOG.error("Context is null, nothing to delete");
+            return;
+        }
+        Map<ServiceInterfacePointKey, ServiceInterfacePoint> sips = context.getServiceInterfacePoint();
+        if (sips != null) {
+            for (ServiceInterfacePoint sip:sips.values()) {
+                if (sip.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) {
+                    // Update state of services that have this sip as an endpoint and also connections
+                    updateConnectivityServicesState(sip.getUuid(), nodeId);
+                    deleteSipFromTopo(sip.getUuid());
+                }
+            }
+        }
+    }
+
+    private Node createTapiXpdrNode(Map<NameKey, Name> nameMap, List<LayerProtocolName> layerProtocols,
+                                    String nodeId, Uuid nodeUuid, List<Mapping> xpdrClMaps, List<Mapping> xpdrNetMaps,
+                                    XpdrNodeTypes xponderType, OduSwitchingPools oorOduSwitchingPool,
+                                    List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepl = new HashMap<>();
+        Map<NodeRuleGroupKey, NodeRuleGroup> nodeRuleGroupList = new HashMap<>();
+        Map<RuleKey, Rule> ruleList = new HashMap<>();
+        Rule rule = new RuleBuilder()
+                .setLocalId("forward")
+                .setForwardingRule(ForwardingRule.MAYFORWARDACROSSGROUP)
+                .setRuleType(RuleType.FORWARDING)
+                .build();
+        ruleList.put(rule.key(), rule);
+        if (layerProtocols.contains(LayerProtocolName.DSR)) {
+            // neps for dsr/odu layer
+            Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> dsroduNeps =
+                    createXpdrDsrOduNeps(nodeId, xpdrClMaps, xpdrNetMaps, xponderType, supportedInterfaceCapability);
+            onepl.putAll(dsroduNeps);
+            nodeRuleGroupList = createNodeRuleGroupForDsrNode(nodeId, oorOduSwitchingPool, ruleList, onepl);
+        } else if (layerProtocols.contains(LayerProtocolName.PHOTONICMEDIA)) {
+            // neps for photonic layer
+            Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> phtmdNeps =
+                    createXpdrPhtnMdNeps(nodeId, xpdrNetMaps, supportedInterfaceCapability);
+            onepl.putAll(phtmdNeps);
+            nodeRuleGroupList = createNodeRuleGroupForOtsiNode(nodeId, xpdrNetMaps, ruleList);
+        } else {
+            LOG.error("Undefined LayerProtocolName for {} node {}", nameMap.get(nameMap.keySet().iterator().next())
+                    .getValueName(), nameMap.get(nameMap.keySet().iterator().next()).getValue());
+        }
+        // Empty random creation of mandatory fields for avoiding errors....
+        CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+            .setCostAlgorithm("Restricted Shortest Path - RSP")
+            .setCostName("HOP_COUNT")
+            .setCostValue("12345678")
+            .build();
+        LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+            .setFixedLatencyCharacteristic("12345678")
+            .setQueingLatencyCharacteristic("12345678")
+            .setJitterCharacteristic("12345678")
+            .setWanderCharacteristic("12345678")
+            .setTrafficPropertyName("FIXED_LATENCY")
+            .build();
+        return new NodeBuilder()
+            .setUuid(nodeUuid)
+            .setName(nameMap)
+            .setLayerProtocolName(layerProtocols)
+            .setAdministrativeState(AdministrativeState.UNLOCKED)
+            .setOperationalState(OperationalState.ENABLED)
+            .setLifecycleState(LifecycleState.INSTALLED)
+            .setOwnedNodeEdgePoint(onepl)
+            .setNodeRuleGroup(nodeRuleGroupList)
+            .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+            .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+            .setErrorCharacteristic("error")
+            .setLossCharacteristic("loss")
+            .setRepeatDeliveryCharacteristic("repeat delivery")
+            .setDeliveryOrderCharacteristic("delivery order")
+            .setUnavailableTimeCharacteristic("unavailable time")
+            .setServerIntegrityProcessCharacteristic("server integrity process")
+            .build();
+    }
+
+    private Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> createXpdrPhtnMdNeps(String nodeId,
+            List<Mapping> xpdrNetMaps, List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepl = new HashMap<>();
+
+        // iNep creation on otsi node
+        for (int i = 0; i < xpdrNetMaps.size(); i++) {
+            Uuid nepUuid1 = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, I_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8")))
+                    .toString());
+            Name onedName = new NameBuilder()
+                    .setValueName("iNodeEdgePoint")
+                    .setValue(String.join("+", nodeId, I_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                    .build();
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid1, xpdrNetMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA,
+                    true, String.join("+", nodeId, I_OTSI), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        // eNep creation on otsi node
+        for (int i = 0; i < xpdrNetMaps.size(); i++) {
+            Uuid nepUuid2 = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, E_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            Name onedName = new NameBuilder()
+                    .setValueName("eNodeEdgePoint")
+                    .setValue(String.join("+", nodeId, E_OTSI, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                    .build();
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid2, xpdrNetMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA,
+                    false, String.join("+", nodeId, E_OTSI), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        // Photonic Media Nep creation on otsi node
+        for (int i = 0; i < xpdrNetMaps.size(); i++) {
+            Uuid nepUuid3 = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, PHTNC_MEDIA, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            Name onedName = new NameBuilder()
+                    .setValueName("PhotMedNodeEdgePoint")
+                    .setValue(String.join("+", nodeId, PHTNC_MEDIA, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                    .build();
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid3, xpdrNetMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(onedName.key(), onedName), LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.PHOTONICMEDIA,
+                    false, String.join("+", nodeId, PHTNC_MEDIA), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        return onepl;
+    }
+
+    private Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> createXpdrDsrOduNeps(String nodeId, List<Mapping> xpdrClMaps,
+            List<Mapping> xpdrNetMaps, XpdrNodeTypes xponderType,
+            List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepl = new HashMap<>();
+        // client nep creation on DSR node
+        for (int i = 0; i < xpdrClMaps.size(); i++) {
+            LOG.info("Client NEP = {}", String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint()));
+            Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            NameBuilder nameBldr = new NameBuilder().setValue(
+                String.join("+", nodeId, DSR, xpdrClMaps.get(i).getLogicalConnectionPoint()));
+            Name name;
+            if (OpenroadmNodeType.TPDR.getName().equalsIgnoreCase(xponderType.getName())) {
+                name = nameBldr.setValueName("100G-tpdr").build();
+            } else {
+                name = nameBldr.setValueName("NodeEdgePoint_C").build();
+            }
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrClMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(name.key(), name), LayerProtocolName.DSR, LayerProtocolName.DSR, true,
+                    String.join("+", nodeId, DSR), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        // network nep creation on I_ODU node
+        for (int i = 0; i < xpdrNetMaps.size(); i++) {
+            LOG.info("iODU NEP = {}", String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()));
+            Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            Name onedName = new NameBuilder()
+                    .setValueName("iNodeEdgePoint_N")
+                    .setValue(String.join("+", nodeId, I_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                    .build();
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrNetMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(onedName.key(), onedName),
+                    LayerProtocolName.ODU, LayerProtocolName.DSR, false,
+                    String.join("+", nodeId, I_ODU), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        // network nep creation on E_ODU node
+        for (int i = 0; i < xpdrNetMaps.size(); i++) {
+            LOG.info("eODU NEP = {}", String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()));
+            Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            Name onedName = new NameBuilder()
+                    .setValueName("eNodeEdgePoint_N")
+                    .setValue(String.join("+", nodeId, E_ODU, xpdrNetMaps.get(i).getLogicalConnectionPoint()))
+                    .build();
+
+            OwnedNodeEdgePoint onep = createNep(nepUuid, xpdrNetMaps.get(i).getLogicalConnectionPoint(),
+                    Map.of(onedName.key(), onedName),
+                    LayerProtocolName.ODU, LayerProtocolName.DSR, true,
+                    String.join("+", nodeId, E_ODU), supportedInterfaceCapability);
+            onepl.put(onep.key(), onep);
+        }
+        return onepl;
+    }
+
+    private OwnedNodeEdgePoint createNep(Uuid nepUuid, String tpid, Map<NameKey, Name> nepNames,
+                                         LayerProtocolName nepProtocol, LayerProtocolName nodeProtocol, boolean withSip,
+                                         String keyword,
+                                         List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        OwnedNodeEdgePointBuilder onepBldr = new OwnedNodeEdgePointBuilder()
+                .setUuid(nepUuid)
+                .setLayerProtocolName(nepProtocol)
+                .setName(nepNames);
+        if (withSip) {
+            onepBldr.setMappedServiceInterfacePoint(createMSIP(1, nepProtocol, tpid, keyword,
+                    supportedInterfaceCapability));
+        }
+        LOG.debug("Node layer {}", nodeProtocol.getName());
+        onepBldr.setSupportedCepLayerProtocolQualifier(createSupportedLayerProtocolQualifier(
+                supportedInterfaceCapability, nodeProtocol));
+        onepBldr.setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC)
+                .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL)
+                .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL);
+        return onepBldr.build();
+    }
+
+    private Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> createRoadmNeps(String orNodeId, String tpId,
+                                                                           boolean withSip) {
+        Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> onepMap = new HashMap<>();
+        // PHOTONIC MEDIA nep
+        Uuid nepUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, PHTNC_MEDIA, tpId))
+                .getBytes(Charset.forName("UTF-8")))
+                .toString());
+        Name nepName = new NameBuilder()
+                .setValueName("NodeEdgePoint name")
+                .setValue(String.join("+", orNodeId, PHTNC_MEDIA, tpId))
+                .build();
+        OwnedNodeEdgePointBuilder onepBldr = new OwnedNodeEdgePointBuilder()
+                .setUuid(nepUuid)
+                .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA)
+                .setName(Map.of(nepName.key(), nepName))
+                .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class))
+                .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC)
+                .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL)
+                .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL);
+        OwnedNodeEdgePoint onep = onepBldr.build();
+        onepMap.put(onep.key(), onep);
+
+        // MC nep
+        Uuid nepUuid1 = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, MC, tpId))
+                .getBytes(Charset.forName("UTF-8")))
+                .toString());
+        Name nepName1 = new NameBuilder()
+                .setValueName("NodeEdgePoint name")
+                .setValue(String.join("+", orNodeId, MC, tpId))
+                .build();
+        OwnedNodeEdgePointBuilder onepBldr1 = new OwnedNodeEdgePointBuilder()
+                .setUuid(nepUuid1)
+                .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA)
+                .setName(Map.of(nepName1.key(), nepName1))
+                .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class))
+                .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC)
+                .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL)
+                .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL);
+        if (withSip) {
+            onepBldr1.setMappedServiceInterfacePoint(createMSIP(1, LayerProtocolName.PHOTONICMEDIA,
+                    tpId, String.join("+", orNodeId, MC), null));
+        }
+        OwnedNodeEdgePoint onep1 = onepBldr1.build();
+        onepMap.put(onep1.key(), onep1);
+
+        // OTSiMC nep
+        Uuid nepUuid2 = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId, OTSI_MC, tpId))
+                .getBytes(Charset.forName("UTF-8")))
+                .toString());
+        Name nepName2 = new NameBuilder()
+                .setValueName("NodeEdgePoint name")
+                .setValue(String.join("+", orNodeId, OTSI_MC, tpId))
+                .build();
+        OwnedNodeEdgePointBuilder onepBldr2 = new OwnedNodeEdgePointBuilder()
+                .setUuid(nepUuid2)
+                .setLayerProtocolName(LayerProtocolName.PHOTONICMEDIA)
+                .setName(Map.of(nepName2.key(), nepName2))
+                .setSupportedCepLayerProtocolQualifier(List.of(PHOTONICLAYERQUALIFIEROMS.class))
+                .setLinkPortDirection(PortDirection.BIDIRECTIONAL).setLinkPortRole(PortRole.SYMMETRIC)
+                .setAdministrativeState(AdministrativeState.UNLOCKED).setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED).setTerminationDirection(TerminationDirection.BIDIRECTIONAL)
+                .setTerminationState(TerminationState.TERMINATEDBIDIRECTIONAL);
+        OwnedNodeEdgePoint onep2 = onepBldr2.build();
+        onepMap.put(onep2.key(), onep2);
+        return onepMap;
+    }
+
+    private Map<MappedServiceInterfacePointKey, MappedServiceInterfacePoint> createMSIP(int nb,
+                                            LayerProtocolName layerProtocol, String tpid, String nodeid,
+                                            List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        Map<MappedServiceInterfacePointKey, MappedServiceInterfacePoint> msipl = new HashMap<>();
+        for (int i = 0; i < nb; i++) {
+            Uuid sipUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", "SIP", nodeid,
+                    tpid)).getBytes(Charset.forName("UTF-8"))).toString());
+            MappedServiceInterfacePoint msip = new MappedServiceInterfacePointBuilder()
+                    .setServiceInterfacePointUuid(sipUuid).build();
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.common.rev181210.tapi.context.ServiceInterfacePoint sip
+                    = createSIP(sipUuid, layerProtocol, tpid, nodeid, supportedInterfaceCapability);
+            this.sipMap.put(sip.key(), sip);
+            LOG.info("SIP created {}", sip.getUuid());
+            // this.tapiSips.put(sip.key(), sip);
+            msipl.put(msip.key(), msip);
+        }
+        return msipl;
+    }
+
+    private ServiceInterfacePoint createSIP(Uuid sipUuid, LayerProtocolName layerProtocol, String tpid, String nodeid,
+                                            List<Class<? extends SupportedIfCapability>> supportedInterfaceCapability) {
+        // TODO: what value should be set in total capacity and available capacity
+        LOG.info("SIP name = {}", String.join("+", nodeid, tpid));
+        Name sipName = new NameBuilder()
+                .setValueName("SIP name")
+                .setValue(String.join("+", nodeid, tpid))
+                .build();
+        return new ServiceInterfacePointBuilder()
+                .setUuid(sipUuid)
+                .setName(Map.of(sipName.key(), sipName))
+                .setLayerProtocolName(layerProtocol)
+                .setAdministrativeState(AdministrativeState.UNLOCKED)
+                .setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED)
+                .setAvailableCapacity(new AvailableCapacityBuilder().build())
+                .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().build())
+                .setSupportedLayerProtocolQualifier(createSupportedLayerProtocolQualifier(supportedInterfaceCapability,
+                        layerProtocol))
+                .build();
+    }
+
+    private org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.topology.Node
+            createRoadmTapiNode(String orNodeId, Map<OwnedNodeEdgePointKey, OwnedNodeEdgePoint> oneplist) {
+        // UUID
+        Uuid nodeUuid = new Uuid(UUID.nameUUIDFromBytes((String.join("+", orNodeId,
+            PHTNC_MEDIA)).getBytes(Charset.forName("UTF-8"))).toString());
+        // Names
+        Name nodeNames =  new NameBuilder().setValueName("roadm node name")
+            .setValue(String.join("+", orNodeId, PHTNC_MEDIA)).build();
+        // Protocol Layer
+        List<LayerProtocolName> layerProtocols = Arrays.asList(LayerProtocolName.PHOTONICMEDIA);
+        // Empty random creation of mandatory fields for avoiding errors....
+        CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+            .setCostAlgorithm("Restricted Shortest Path - RSP")
+            .setCostName("HOP_COUNT")
+            .setCostValue("12345678")
+            .build();
+        LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+            .setFixedLatencyCharacteristic("12345678")
+            .setQueingLatencyCharacteristic("12345678")
+            .setJitterCharacteristic("12345678")
+            .setWanderCharacteristic("12345678")
+            .setTrafficPropertyName("FIXED_LATENCY")
+            .build();
+        return new NodeBuilder()
+            .setUuid(nodeUuid)
+            .setName(Map.of(nodeNames.key(), nodeNames))
+            .setLayerProtocolName(layerProtocols)
+            .setAdministrativeState(AdministrativeState.UNLOCKED)
+            .setOperationalState(OperationalState.ENABLED)
+            .setLifecycleState(LifecycleState.INSTALLED)
+            .setOwnedNodeEdgePoint(oneplist)
+            .setNodeRuleGroup(createNodeRuleGroupForRdmNode(nodeUuid, oneplist.values()))
+            .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+            .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+            .setErrorCharacteristic("error")
+            .setLossCharacteristic("loss")
+            .setRepeatDeliveryCharacteristic("repeat delivery")
+            .setDeliveryOrderCharacteristic("delivery order")
+            .setUnavailableTimeCharacteristic("unavailable time")
+            .setServerIntegrityProcessCharacteristic("server integrity process")
+            .build();
+    }
+
+    private Map<NodeRuleGroupKey, NodeRuleGroup> createNodeRuleGroupForRdmNode(Uuid nodeUuid,
+                                                                               Collection<OwnedNodeEdgePoint> onepl) {
+        Map<org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePointKey,
+                org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint>
+                nepMap = new HashMap<>();
+        for (OwnedNodeEdgePoint onep : onepl) {
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint
+                    nep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group
+                    .NodeEdgePointBuilder()
+                    .setTopologyUuid(tapiTopoUuid)
+                    .setNodeUuid(nodeUuid)
+                    .setNodeEdgePointUuid(onep.key().getUuid())
+                    .build();
+            nepMap.put(nep.key(), nep);
+        }
+        Map<NodeRuleGroupKey, NodeRuleGroup> nodeRuleGroupMap = new HashMap<>();
+        Map<RuleKey, Rule> ruleList = new HashMap<>();
+        Rule rule = new RuleBuilder()
+                .setLocalId("forward")
+                .setForwardingRule(ForwardingRule.MAYFORWARDACROSSGROUP)
+                .setRuleType(RuleType.FORWARDING)
+                .build();
+        ruleList.put(rule.key(), rule);
+        NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder()
+                .setUuid(new Uuid(UUID.nameUUIDFromBytes(("rdm infra node rule group")
+                        .getBytes(Charset.forName("UTF-8"))).toString()))
+                .setRule(ruleList)
+                .setNodeEdgePoint(nepMap)
+                .build();
+        nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup);
+        return nodeRuleGroupMap;
+    }
+
+    private Map<LinkKey, Link> createTapiTransitionalLinks(String nodeId, List<Mapping> xpdrNetMaps, Uuid nodeUuidDsr,
+                                                           Uuid nodeUuidOtsi) {
+        Map<LinkKey, Link> linkMap = new HashMap<>();
+        for (Mapping mapping : xpdrNetMaps) {
+            Map<NodeEdgePointKey, NodeEdgePoint> nepList = new HashMap<>();
+            String sourceKey = String.join("+", nodeId, I_ODU, mapping.getLogicalConnectionPoint());
+            Uuid sourceUuidTp = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, I_ODU, mapping.getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            String destKey = String.join("+", nodeId, I_OTSI, mapping.getLogicalConnectionPoint());
+            Uuid destUuidTp = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, I_OTSI, mapping.getLogicalConnectionPoint()))
+                            .getBytes(Charset.forName("UTF-8"))).toString());
+            NodeEdgePoint sourceNep = new NodeEdgePointBuilder()
+                    .setTopologyUuid(this.tapiTopoUuid)
+                    .setNodeUuid(nodeUuidDsr)
+                    .setNodeEdgePointUuid(sourceUuidTp)
+                    .build();
+            nepList.put(sourceNep.key(), sourceNep);
+            NodeEdgePoint destNep = new NodeEdgePointBuilder()
+                    .setTopologyUuid(this.tapiTopoUuid)
+                    .setNodeUuid(nodeUuidOtsi)
+                    .setNodeEdgePointUuid(destUuidTp)
+                    .build();
+            nepList.put(destNep.key(), destNep);
+            Name linkName = new NameBuilder().setValueName("transitional link name")
+                    .setValue(String.join("--",nodeId, sourceKey, destKey))
+                    .build();
+            CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+                .setCostAlgorithm("Restricted Shortest Path - RSP")
+                .setCostName("HOP_COUNT")
+                .setCostValue("12345678")
+                .build();
+            LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+                .setFixedLatencyCharacteristic("12345678")
+                .setQueingLatencyCharacteristic("12345678")
+                .setJitterCharacteristic("12345678")
+                .setWanderCharacteristic("12345678")
+                .setTrafficPropertyName("FIXED_LATENCY")
+                .build();
+            RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder()
+                .setRiskCharacteristicName("risk characteristic")
+                .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2"))
+                .build();
+            ValidationMechanism validationMechanism = new ValidationMechanismBuilder()
+                .setValidationMechanism("validation mechanism")
+                .setValidationRobustness("validation robustness")
+                .setLayerProtocolAdjacencyValidated("layer protocol adjacency")
+                .build();
+            Link transiLink = new LinkBuilder()
+                .setUuid(new Uuid(
+                    UUID.nameUUIDFromBytes((String.join("--", nodeId, sourceKey, destKey))
+                        .getBytes(Charset.forName("UTF-8")))
+                        .toString()))
+                .setName(Map.of(linkName.key(), linkName))
+                .setTransitionedLayerProtocolName(Arrays.asList(LayerProtocolName.ODU.getName(),
+                    LayerProtocolName.PHOTONICMEDIA.getName()))
+                .setNodeEdgePoint(nepList)
+                .setLayerProtocolName(Arrays.asList(LayerProtocolName.PHOTONICMEDIA, LayerProtocolName.ODU))
+                .setDirection(ForwardingDirection.BIDIRECTIONAL)
+                .setAvailableCapacity(new AvailableCapacityBuilder().setTotalSize(
+                    new TotalSizeBuilder().setUnit(CapacityUnit.GBPS).setValue(Uint64.valueOf(100)).build())
+                    .build())
+                .setResilienceType(new ResilienceTypeBuilder().setProtectionType(ProtectionType.NOPROTECTON)
+                    .setRestorationPolicy(RestorationPolicy.NA)
+                    .build())
+                .setAdministrativeState(AdministrativeState.UNLOCKED)
+                .setOperationalState(OperationalState.ENABLED)
+                .setLifecycleState(LifecycleState.INSTALLED)
+                .setTotalPotentialCapacity(new TotalPotentialCapacityBuilder().setTotalSize(
+                    new TotalSizeBuilder().setUnit(CapacityUnit.GBPS).setValue(Uint64.valueOf(100)).build())
+                    .build())
+                .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+                .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+                .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic))
+                .setErrorCharacteristic("error")
+                .setLossCharacteristic("loss")
+                .setRepeatDeliveryCharacteristic("repeat delivery")
+                .setDeliveryOrderCharacteristic("delivery order")
+                .setUnavailableTimeCharacteristic("unavailable time")
+                .setServerIntegrityProcessCharacteristic("server integrity process")
+                .setValidationMechanism(Map.of(validationMechanism.key(), validationMechanism))
+                .build();
+            linkMap.put(transiLink.key(), transiLink);
+        }
+        // return a map of links and then we can do merge the corresponding link map into the topology context
+        return linkMap;
+    }
+
+    private OduSwitchingPools createTpdrSwitchPool() {
+        return new OduSwitchingPoolsBuilder().build();
+    }
+
+    private OduSwitchingPools createSwtchSwitchPool(List<Mapping> xpdrClMaps, List<Mapping> xpdrNetMaps,
+                                                    Integer xpdrNb) {
+        List<TpId> tpl = new ArrayList<>();
+        TpId tpId = null;
+        for (int i = 1; i <= xpdrClMaps.size(); i++) {
+            tpId = new TpId("XPDR" + xpdrNb + CLIENT + i);
+            tpl.add(tpId);
+        }
+        for (int i = 1; i <= xpdrNetMaps.size(); i++) {
+            tpId = new TpId("XPDR" + xpdrNb + NETWORK + i);
+            tpl.add(tpId);
+        }
+        Map<NonBlockingListKey, NonBlockingList> nbMap = new HashMap<>();
+        NonBlockingList nbl = new NonBlockingListBuilder()
+                .setNblNumber(Uint16.valueOf(1))
+                .setTpList(tpl)
+                .build();
+        nbMap.put(nbl.key(),nbl);
+
+        return new OduSwitchingPoolsBuilder()
+                .setSwitchingPoolNumber(Uint16.valueOf(1))
+                .setSwitchingPoolType(SwitchingPoolTypes.NonBlocking)
+                .setNonBlockingList(nbMap)
+                .build();
+    }
+
+    private OduSwitchingPools createMuxSwitchPool(List<Mapping> xpdrClMaps, List<Mapping> xpdrNetMaps, Integer xpdrNb) {
+        Map<NonBlockingListKey, NonBlockingList> nbMap = new HashMap<>();
+        for (int i = 1; i <= xpdrClMaps.size(); i++) {
+            List<TpId> tpList = new ArrayList<>();
+            TpId tpId = new TpId("XPDR" + xpdrNb + CLIENT + i);
+            tpList.add(tpId);
+            tpId = new TpId("XPDR" + xpdrNb + "-NETWORK1");
+            tpList.add(tpId);
+            NonBlockingList nbl = new NonBlockingListBuilder()
+                    .setNblNumber(Uint16.valueOf(i))
+                    .setTpList(tpList)
+                    .setAvailableInterconnectBandwidth(Uint32.valueOf(xpdrNetMaps.size() * 10L))
+                    .setInterconnectBandwidthUnit(Uint32.valueOf(1000000000))
+                    .build();
+            nbMap.put(nbl.key(),nbl);
+        }
+        return new OduSwitchingPoolsBuilder()
+                .setSwitchingPoolNumber(Uint16.valueOf(1))
+                .setSwitchingPoolType(SwitchingPoolTypes.NonBlocking)
+                .setNonBlockingList(nbMap)
+                .build();
+    }
+
+    private Map<NodeRuleGroupKey, NodeRuleGroup> createNodeRuleGroupForOtsiNode(String nodeId,
+                                                                                List<Mapping> xpdrNetMaps,
+                                                                                Map<RuleKey, Rule> ruleList) {
+        Map<NodeRuleGroupKey, NodeRuleGroup> nodeRuleGroupMap = new HashMap<>();
+        // create NodeRuleGroup
+        int count = 1;
+        for (Mapping tpMapping : xpdrNetMaps) {
+            Map<org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePointKey,
+                org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint>
+                    nepList = new HashMap<>();
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group
+                    .NodeEdgePoint inep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210
+                    .node.rule.group.NodeEdgePointBuilder()
+                    .setTopologyUuid(tapiTopoUuid)
+                    .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes(
+                            (String.join("+", nodeId, OTSI)).getBytes(Charset.forName("UTF-8")))
+                            .toString()))
+                    .setNodeEdgePointUuid(new Uuid(UUID.nameUUIDFromBytes(
+                            (String.join("+", nodeId, I_OTSI, tpMapping.getLogicalConnectionPoint()))
+                                    .getBytes(Charset.forName("UTF-8"))).toString()))
+                    .build();
+            org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group
+                    .NodeEdgePoint enep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210
+                    .node.rule.group.NodeEdgePointBuilder()
+                    .setTopologyUuid(tapiTopoUuid)
+                    .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes(
+                            (String.join("+", nodeId, OTSI)).getBytes(Charset.forName("UTF-8")))
+                            .toString()))
+                    .setNodeEdgePointUuid(new Uuid(UUID.nameUUIDFromBytes(
+                            (String.join("+", nodeId, E_OTSI, tpMapping.getLogicalConnectionPoint()))
+                                    .getBytes(Charset.forName("UTF-8"))).toString()))
+                    .build();
+            nepList.put(inep.key(), inep);
+            nepList.put(enep.key(), enep);
+            // Empty random creation of mandatory fields for avoiding errors....
+            CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+                .setCostAlgorithm("Restricted Shortest Path - RSP")
+                .setCostName("HOP_COUNT")
+                .setCostValue("12345678")
+                .build();
+            LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+                .setFixedLatencyCharacteristic("12345678")
+                .setQueingLatencyCharacteristic("12345678")
+                .setJitterCharacteristic("12345678")
+                .setWanderCharacteristic("12345678")
+                .setTrafficPropertyName("FIXED_LATENCY")
+                .build();
+            RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder()
+                .setRiskCharacteristicName("risk characteristic")
+                .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2"))
+                .build();
+            NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder()
+                .setUuid(new Uuid(
+                    UUID.nameUUIDFromBytes(("otsi node rule group " + count).getBytes(Charset.forName("UTF-8")))
+                        .toString()))
+                .setRule(ruleList)
+                .setNodeEdgePoint(nepList)
+                .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic))
+                .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+                .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+                .build();
+            nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup);
+            count++;
+        }
+        return nodeRuleGroupMap;
+    }
+
+    private Map<NodeRuleGroupKey, NodeRuleGroup> createNodeRuleGroupForDsrNode(String nodeId,
+                                                                               OduSwitchingPools oorOduSwitchingPool,
+                                                                               Map<RuleKey, Rule> ruleList,
+                                                                               Map<OwnedNodeEdgePointKey,
+                                                                                       OwnedNodeEdgePoint> onepl) {
+        // create NodeRuleGroup
+        if (oorOduSwitchingPool == null) {
+            LOG.info("TPDR node --> no switching pool");
+            return new HashMap<>();
+        }
+        LOG.info("ONEPL = {}", onepl.values());
+        Map<NodeRuleGroupKey, NodeRuleGroup> nodeRuleGroupMap = new HashMap<>();
+        int count = 1;
+        for (NonBlockingList nbl : oorOduSwitchingPool.nonnullNonBlockingList().values()) {
+            LOG.info("Non blocking list = {}", nbl);
+            Map<org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePointKey,
+                org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint>
+                    nepList = new HashMap<>();
+            for (TpId tp : nbl.getTpList()) {
+                LOG.info("EDOU TP = {}", String.join("+", nodeId, E_ODU, tp.getValue()));
+                LOG.info("DSR TP = {}", String.join("+", nodeId, DSR, tp.getValue()));
+                Uuid tpUuid = new Uuid(UUID.nameUUIDFromBytes(
+                        (String.join("+", nodeId, E_ODU, tp.getValue())).getBytes(Charset.forName("UTF-8")))
+                        .toString());
+                Uuid tp1Uuid = new Uuid(UUID.nameUUIDFromBytes(
+                    (String.join("+", nodeId, DSR, tp.getValue())).getBytes(Charset.forName("UTF-8")))
+                    .toString());
+                if (onepl.containsKey(new OwnedNodeEdgePointKey(tpUuid))
+                        || onepl.containsKey(new OwnedNodeEdgePointKey(tp1Uuid))) {
+                    org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group.NodeEdgePoint
+                        nep = new org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.node.rule.group
+                            .NodeEdgePointBuilder()
+                            .setTopologyUuid(tapiTopoUuid)
+                            .setNodeUuid(new Uuid(UUID.nameUUIDFromBytes(
+                                    (String.join("+", nodeId, DSR)).getBytes(Charset.forName("UTF-8")))
+                                    .toString()))
+                            .setNodeEdgePointUuid((tp.getValue().contains("CLIENT")) ? tp1Uuid : tpUuid)
+                            .build();
+                    nepList.put(nep.key(), nep);
+                }
+            }
+            // Empty random creation of mandatory fields for avoiding errors....
+            CostCharacteristic costCharacteristic = new CostCharacteristicBuilder()
+                .setCostAlgorithm("Restricted Shortest Path - RSP")
+                .setCostName("HOP_COUNT")
+                .setCostValue("12345678")
+                .build();
+            LatencyCharacteristic latencyCharacteristic = new LatencyCharacteristicBuilder()
+                .setFixedLatencyCharacteristic("12345678")
+                .setQueingLatencyCharacteristic("12345678")
+                .setJitterCharacteristic("12345678")
+                .setWanderCharacteristic("12345678")
+                .setTrafficPropertyName("FIXED_LATENCY")
+                .build();
+            RiskCharacteristic riskCharacteristic = new RiskCharacteristicBuilder()
+                .setRiskCharacteristicName("risk characteristic")
+                .setRiskIdentifierList(List.of("risk identifier1", "risk identifier2"))
+                .build();
+            NodeRuleGroup nodeRuleGroup = new NodeRuleGroupBuilder()
+                .setUuid(new Uuid(
+                    UUID.nameUUIDFromBytes(("dsr node rule group " + count).getBytes(Charset.forName("UTF-8")))
+                        .toString()))
+                .setRule(ruleList)
+                .setNodeEdgePoint(nepList)
+                .setRiskCharacteristic(Map.of(riskCharacteristic.key(), riskCharacteristic))
+                .setCostCharacteristic(Map.of(costCharacteristic.key(), costCharacteristic))
+                .setLatencyCharacteristic(Map.of(latencyCharacteristic.key(), latencyCharacteristic))
+                .build();
+            nodeRuleGroupMap.put(nodeRuleGroup.key(), nodeRuleGroup);
+            count++;
+        }
+        return nodeRuleGroupMap;
+    }
+
+    private List<Class<? extends LAYERPROTOCOLQUALIFIER>> createSupportedLayerProtocolQualifier(
+            List<Class<? extends SupportedIfCapability>> sicList, LayerProtocolName lpn) {
+        if (sicList == null) {
+            return List.of(PHOTONICLAYERQUALIFIEROMS.class);
+        }
+        Map<SupportedInterfaceCapabilityKey, SupportedInterfaceCapability> supIfMap = new HashMap<>();
+        LOG.info("SIC list = {}", sicList);
+        for (Class<? extends SupportedIfCapability> supInterCapa : sicList) {
+            SupportedInterfaceCapability supIfCapa = new SupportedInterfaceCapabilityBuilder()
+                    .withKey(new SupportedInterfaceCapabilityKey(convertSupIfCapa(supInterCapa)))
+                    .setIfCapType(convertSupIfCapa(supInterCapa))
+                    .build();
+            supIfMap.put(supIfCapa.key(), supIfCapa);
+        }
+        List<Class<? extends LAYERPROTOCOLQUALIFIER>> sclpqList = new ArrayList<>();
+        for (SupportedInterfaceCapability sic : supIfMap.values()) {
+            switch (lpn.getName()) {
+                case "DSR":
+                case "ODU":
+                    switch (sic.getIfCapType().getSimpleName()) {
+                        case "If10GEODU2e":
+                            sclpqList.add(ODUTYPEODU2E.class);
+                            sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class);
+                            break;
+                        case "If10GEODU2":
+                            sclpqList.add(ODUTYPEODU2.class);
+                            sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class);
+                            break;
+                        case "If10GE":
+                            sclpqList.add(DIGITALSIGNALTYPE10GigELAN.class);
+                            break;
+                        case "If100GEODU4":
+                            sclpqList.add(DIGITALSIGNALTYPE100GigE.class);
+                            sclpqList.add(ODUTYPEODU4.class);
+                            break;
+                        case "If100GE":
+                            sclpqList.add(DIGITALSIGNALTYPE100GigE.class);
+                            break;
+                        case "IfOCHOTU4ODU4":
+                        case "IfOCH":
+                            sclpqList.add(ODUTYPEODU4.class);
+                            break;
+                        default:
+                            LOG.error("IfCapability type not managed");
+                            break;
+                    }
+                    break;
+                case "PHOTONIC_MEDIA":
+                    if (sic.getIfCapType().getSimpleName().equals("IfOCHOTU4ODU4")
+                        || sic.getIfCapType().getSimpleName().equals("IfOCH")) {
+                        sclpqList.add(PHOTONICLAYERQUALIFIEROTSi.class);
+                        sclpqList.add(PHOTONICLAYERQUALIFIEROMS.class);
+                    }
+                    break;
+                default:
+                    LOG.error("Layer Protocol Name is unknown {}", lpn.getName());
+                    break;
+            }
+        }
+        return sclpqList;
+    }
+
+    private static Class<? extends SupportedIfCapability> convertSupIfCapa(Class<? extends
+            SupportedIfCapability> ifCapType) {
+        LOG.info("Interface Capability type = {}", ifCapType.getSimpleName());
+        switch (ifCapType.getSimpleName()) {
+            case "If100GEODU4":
+                return If100GEODU4.class;
+            case "IfOCHOTU4ODU4":
+                return IfOCHOTU4ODU4.class;
+            case "If1GEODU0":
+                return If1GEODU0.class;
+            case "If10GEODU2e":
+                return If10GEODU2e.class;
+            case "If10GEODU2":
+                return If10GEODU2.class;
+            case "If100GE":
+                return If100GE.class;
+            case "If10GE":
+                return If10GE.class;
+            case "If1GE":
+                return If1GE.class;
+            case "IfOCH":
+                return IfOCH.class;
+            default:
+                return null;
+        }
+    }
+
+    private void mergeNodeinTopology(Map<NodeKey, Node> nodeMap) {
+        // TODO is this merge correct? Should we just merge topology by changing the nodes map??
+        // TODO: verify this is correct. Should we identify the context IID with the context UUID??
+        LOG.info("Creating tapi node in TAPI topology context");
+        InstanceIdentifier<Topology> topoIID = InstanceIdentifier.builder(Context.class)
+            .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1.class)
+            .child(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext.class)
+            .child(Topology.class, new TopologyKey(tapiTopoUuid))
+            .build();
+
+        Topology topology = new TopologyBuilder().setUuid(tapiTopoUuid).setNode(nodeMap).build();
+
+        // merge in datastore
+        this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, topoIID,
+                topology);
+        try {
+            this.networkTransactionService.commit().get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error populating TAPI topology: ", e);
+        }
+        LOG.info("Roadm Node added succesfully.");
+    }
+
+    private void mergeLinkinTopology(Map<LinkKey, Link> linkMap) {
+        // TODO is this merge correct? Should we just merge topology by changing the nodes map??
+        // TODO: verify this is correct. Should we identify the context IID with the context UUID??
+        LOG.info("Creating tapi node in TAPI topology context");
+        InstanceIdentifier<Topology> topoIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.topology.rev181210.Context1.class)
+                .child(org.opendaylight.yang.gen.v1.urn
+                        .onf.otcc.yang.tapi.topology.rev181210.context.TopologyContext.class)
+                .child(Topology.class, new TopologyKey(tapiTopoUuid))
+                .build();
+
+        Topology topology = new TopologyBuilder().setUuid(tapiTopoUuid).setLink(linkMap).build();
+
+        // merge in datastore
+        this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, topoIID,
+                topology);
+        try {
+            this.networkTransactionService.commit().get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error populating TAPI topology: ", e);
+        }
+        LOG.info("Roadm Link added succesfully.");
+    }
+
+    private void mergeSipsinContext(Map<ServiceInterfacePointKey, ServiceInterfacePoint> sips) {
+        // TODO is this merge correct? Should we just merge topology by changing the nodes map??
+        // TODO: verify this is correct. Should we identify the context IID with the context UUID??
+        try {
+            ContextBuilder contextBuilder = new ContextBuilder();
+            contextBuilder.setServiceInterfacePoint(sips);
+            InstanceIdentifier<Context> contextIID = InstanceIdentifier.builder(Context.class).build();
+            // merge in datastore
+            this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, contextIID,
+                    contextBuilder.build());
+            this.networkTransactionService.commit().get();
+            LOG.info("TAPI SIPs merged successfully.");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to merge TAPI Sips", e);
+        }
+    }
+
+    private void deleteLinkFromTopo(Uuid linkUuid) {
+        // TODO: check if this IID is correct
+        try {
+            InstanceIdentifier<Link> linkIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class,
+                    new TopologyKey(tapiTopoUuid)).child(Link.class, new LinkKey(linkUuid)).build();
+            this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, linkIID);
+            this.networkTransactionService.commit().get();
+            LOG.info("TAPI link deleted successfully.");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete TAPI link", e);
+        }
+    }
+
+    private void deleteNodeFromTopo(Uuid nodeUuid) {
+        // TODO: check if this IID is correct
+        try {
+            InstanceIdentifier<Node> nodeIDD = InstanceIdentifier.builder(Context.class)
+                .augmentation(Context1.class).child(TopologyContext.class).child(Topology.class,
+                    new TopologyKey(tapiTopoUuid)).child(Node.class, new NodeKey(nodeUuid)).build();
+            this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, nodeIDD);
+            this.networkTransactionService.commit().get();
+            LOG.info("TAPI Node deleted successfully.");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete TAPI Node", e);
+        }
+    }
+
+    private void deleteSipFromTopo(Uuid sipUuid) {
+        // TODO: check if this IID is correct
+        try {
+            InstanceIdentifier<ServiceInterfacePoint> sipIID = InstanceIdentifier.builder(Context.class)
+                    .child(ServiceInterfacePoint.class, new ServiceInterfacePointKey(sipUuid)).build();
+            this.networkTransactionService.delete(LogicalDatastoreType.OPERATIONAL, sipIID);
+            this.networkTransactionService.commit().get();
+            LOG.info("TAPI SIP deleted successfully.");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Failed to delete TAPI SIP", e);
+        }
+    }
+
+    private void updateConnectivityServicesState(Uuid sipUuid, String nodeId) {
+        // TODO: check if this IID is correct
+        InstanceIdentifier<ConnectivityContext> connectivitycontextIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class)
+                .child(ConnectivityContext.class)
+                .build();
+        ConnectivityContext connContext = null;
+        try {
+            Optional<ConnectivityContext> optConnContext =
+                    this.networkTransactionService.read(LogicalDatastoreType.OPERATIONAL, connectivitycontextIID)
+                            .get();
+            if (!optConnContext.isPresent()) {
+                LOG.error("Couldnt retrieve connectivity context from datastore");
+                return;
+            }
+            connContext = optConnContext.get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Couldnt read connectivity context from datastore", e);
+        }
+        if (connContext == null) {
+            LOG.error("Connectivity context is empty");
+            return;
+        }
+        // Loop through services, check if the endpoint uuid is equal to the sip.
+        // If so update state.
+        Map<ConnectivityServiceKey, ConnectivityService> connServMap = connContext.getConnectivityService();
+        Map<ConnectionKey, Connection> connMap = connContext.getConnection();
+        if (connServMap != null) {
+            for (ConnectivityService service:connServMap.values()) {
+                Map<EndPointKey, EndPoint> serviceEndPoints = service.getEndPoint();
+                if (serviceEndPoints.values().stream().anyMatch(endPoint -> endPoint.getServiceInterfacePoint()
+                    .getServiceInterfacePointUuid().equals(sipUuid))) {
+                    LOG.info("Service using SIP of node {} identified. Update state of service", nodeId);
+                    ConnectivityService updService = new ConnectivityServiceBuilder(service)
+                        .setAdministrativeState(AdministrativeState.LOCKED)
+                        .setOperationalState(OperationalState.DISABLED)
+                        .setLifecycleState(LifecycleState.PENDINGREMOVAL)
+                        .build();
+                    updateConnectivityService(updService);
+                }
+            }
+        }
+        // Update state of connections
+        if (connMap != null) {
+            for (Connection connection:connMap.values()) {
+                if (connection.getName().values().stream().anyMatch(name -> name.getValue().contains(nodeId))) {
+                    Connection updConn = new ConnectionBuilder(connection)
+                        .setLifecycleState(LifecycleState.PENDINGREMOVAL)
+                        .setOperationalState(OperationalState.DISABLED)
+                        .build();
+                    updateConnection(updConn);
+                }
+            }
+        }
+    }
+
+    private void updateConnection(Connection updConn) {
+        // TODO: check if this IID is correct
+        InstanceIdentifier<Connection> connectionIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class)
+                .child(ConnectivityContext.class).child(Connection.class,
+                        new ConnectionKey(updConn.getUuid())).build();
+        this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connectionIID, updConn);
+        try {
+            this.networkTransactionService.commit().get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error committing into datastore", e);
+        }
+    }
+
+    private void updateConnectivityService(ConnectivityService updService) {
+        // TODO: check if this IID is correct
+        InstanceIdentifier<ConnectivityService> connectivityserviceIID = InstanceIdentifier.builder(Context.class)
+                .augmentation(org.opendaylight.yang.gen.v1.urn.onf.otcc.yang.tapi.connectivity.rev181210.Context1.class)
+                .child(ConnectivityContext.class).child(ConnectivityService.class,
+                        new ConnectivityServiceKey(updService.getUuid())).build();
+        this.networkTransactionService.merge(LogicalDatastoreType.OPERATIONAL, connectivityserviceIID, updService);
+        try {
+            this.networkTransactionService.commit().get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("Error committing into datastore", e);
+        }
+    }
+
+}
diff --git a/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java b/tapi/src/main/java/org/opendaylight/transportpce/tapi/topology/TapiPortMappingListener.java
new file mode 100644 (file)
index 0000000..de9e8bb
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2021 Nokia.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.transportpce.tapi.topology;
+
+import java.util.Collection;
+import java.util.Map;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.api.DataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.Mapping;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.mapping.MappingKey;
+import org.opendaylight.yang.gen.v1.http.org.opendaylight.transportpce.portmapping.rev210315.network.Nodes;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TapiPortMappingListener implements DataTreeChangeListener<Nodes> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(TapiPortMappingListener.class);
+
+    private final TapiNetworkModelService tapiNetworkModelService;
+
+    public TapiPortMappingListener(TapiNetworkModelService tapiNetworkModelService) {
+        this.tapiNetworkModelService = tapiNetworkModelService;
+    }
+
+    @Override
+    public void onDataTreeChanged(@NonNull Collection<DataTreeModification<Nodes>> changes) {
+        for (DataTreeModification<Nodes> change : changes) {
+            LOG.debug("TAPI module: Change in Node = {}", change.getRootNode());
+            // Data before needs to be not null
+            if (change.getRootNode().getDataAfter() != null && change.getRootNode().getDataBefore() != null) {
+                Nodes nodesAft = change.getRootNode().getDataAfter();
+                Nodes nodesBef = change.getRootNode().getDataBefore();
+                // TODO -> need to filter out the ones that are not after creation.
+                //  (Mapping before = null & Mapping after != null) is the rule for a first time connected device
+                String nodeId = nodesAft.getNodeId();
+                Map<MappingKey, Mapping> mappingAft = nodesAft.getMapping();
+                Map<MappingKey, Mapping> mappingBef = nodesBef.getMapping();
+                LOG.info("Change in node {} with OR version = {}", nodeId,
+                    nodesAft.getNodeInfo().getOpenroadmVersion().getName());
+                if (mappingAft != null && mappingBef == null) {
+                    LOG.info("New mapping for node {} = {}", nodeId, mappingAft);
+                    LOG.info("As the mapping is now created for the first time, "
+                        + "we can proceed with the creation of the node {} in the TAPI topology", nodeId);
+                    this.tapiNetworkModelService.createTapiNode(nodeId,
+                        nodesAft.getNodeInfo().getOpenroadmVersion().getIntValue(), nodesAft);
+                } else {
+                    LOG.warn("Mapping already existed in the datastore, which means that node {} already existed "
+                        + "in TAPI topology. The action to take will be different", nodeId);
+                }
+            }
+        }
+    }
+}
index 293ad605bc6bb3186c03fa75546e17acf6a2b89b..314df38f66cf7968bd19e29ea0c25234bcdbfbe7 100644 (file)
@@ -16,6 +16,9 @@ Author: Gilles Thouenon <gilles.thouenon@orange.com>
     <reference id="dataBroker"
           interface="org.opendaylight.mdsal.binding.api.DataBroker"/>
 
+    <reference id="deviceTransactionManager"
+               interface="org.opendaylight.transportpce.common.device.DeviceTransactionManager" />
+
     <reference id="rpcProviderService"
           interface="org.opendaylight.mdsal.binding.api.RpcProviderService"/>
 
@@ -32,6 +35,15 @@ Author: Gilles Thouenon <gilles.thouenon@orange.com>
           class="org.opendaylight.transportpce.tapi.utils.TapiListener">
     </bean>
 
+    <bean id="tapiNetworkModelService" class="org.opendaylight.transportpce.tapi.topology.TapiNetworkModelServiceImpl">
+        <argument ref="tapilinkDiscoveryImpl" />
+        <argument ref="networkTransactionImpl" />
+    </bean>
+
+    <bean id="tapiNetconfTopologyListener" class="org.opendaylight.transportpce.tapi.topology.TapiNetconfTopologyListener">
+        <argument ref="tapiNetworkModelService" />
+    </bean>
+
     <bean id="tapiProvider"
           class="org.opendaylight.transportpce.tapi.impl.TapiProvider"
           init-method="init" destroy-method="close">
@@ -41,6 +53,19 @@ Author: Gilles Thouenon <gilles.thouenon@orange.com>
         <argument ref="serviceDatastoreOperation" />
         <argument ref="tapiListener" />
         <argument ref="networkTransactionImpl" />
+        <argument ref="tapiNetconfTopologyListener" />
+        <argument ref="tapiPortMappingListener" />
     </bean>
 
+    <bean id="tapiPortMappingListener" class="org.opendaylight.transportpce.tapi.topology.TapiPortMappingListener">
+        <argument ref="tapiNetworkModelService" />
+    </bean>
+
+    <bean id="tapilinkDiscoveryImpl" class="org.opendaylight.transportpce.tapi.R2RTapiLinkDiscovery">
+        <argument ref="dataBroker" />
+        <argument ref="deviceTransactionManager" />
+    </bean>
+
+    <service ref="tapiNetworkModelService" interface="org.opendaylight.transportpce.tapi.topology.TapiNetworkModelService" />
+
 </blueprint>