Network topology and inventory init 51/73551/5
authorShweta V <sv111y@att.com>
Wed, 20 Dec 2017 11:12:12 +0000 (12:12 +0100)
committerguillaume.lambert <guillaume.lambert@orange.com>
Wed, 18 Jul 2018 13:51:28 +0000 (15:51 +0200)
- Includes network topology creation when NE gets mounted including
CLLI, Openroadm-Network and Openroadm-Topology
- Abstracts network model for Roadm and Xponder nodes
- Derives Roadm-to-Roadm links from LLDP config and notifications
- Provides RPC to create Xponder-input and Xponder-output links
- Includes functionality to update available and used pool based
on service-create and service-delete request
- Remove log error for LLDP subtree
Differences with initial change from ATT-Sandbox branch
- Fix code design issues pointed by Juraj (Patch Set 5)
https://git.opendaylight.org/gerrit/#/c/68859/5
- fix inventory feature building

Co-Authored-By: Dhruv Bhardwaj <db929a@att.com>
Co-Authored-By: Shweta Vachhani <sv111y@att.com>
Co-Authored-By: Masha Dorfman <>
Co-Authored-By: Archana Soundararajan <as7463@att.com>
Co-Authored-By: Juraj Veverka <Juraj.Veverka@pantheon.tech>
Co-Authored-By: Samuel Kontri <samuel.kontris@pantheon.sk>
Co-Authored-By: Andrej Zan <andrej.zan@pantheon.sk>
Co-Authored-By: Milan Fratrik <>
Co-authored-by: Martial COULIBALY <martial.coulibaly@gfi.fr>
Change-Id: I440caf77157d2fa5a5b17ab048252c96833e7561
Signed-off-by: Shweta <sv111y@att.com>
Signed-off-by: Martial COULIBALY <martial.coulibaly@gfi.fr>
53 files changed:
features/features-transportpce/pom.xml
features/odl-transportpce-inventory/pom.xml [new file with mode: 0644]
features/odl-transportpce-inventory/src/main/feature/feature.xml [new file with mode: 0644]
features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg [new file with mode: 0644]
features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg [new file with mode: 0644]
features/odl-transportpce/pom.xml
features/pom.xml
inventory/pom.xml [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java [new file with mode: 0644]
inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java [new file with mode: 0644]
inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml [new file with mode: 0644]
networkmodel/pom.xml [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeOperationsListener.java [moved from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeOperationsListener.java with 94% similarity]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeviceListener.java [moved from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeviceListener.java with 89% similarity]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/TcaListener.java [moved from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/TcaListener.java with 84% similarity]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java [new file with mode: 0644]
networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java [new file with mode: 0644]
networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml [new file with mode: 0644]
networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java [new file with mode: 0644]
pom.xml
renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java [deleted file]
renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererProvider.java
renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java [deleted file]
renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java [deleted file]
renderer/src/main/java/org/opendaylight/transportpce/renderer/provisiondevice/tasks/RollbackProcessor.java
renderer/src/main/resources/org/opendaylight/blueprint/renderer-blueprint.xml

index 9ca8e011f75a258a3195ff12fec1a835066e04c3..25e70765bb877e6b3a0bfebc2bd9d69409b0bb74 100644 (file)
@@ -64,5 +64,12 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <classifier>features</classifier>
       <type>xml</type>
     </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>odl-transportpce-inventory</artifactId>
+      <version>${project.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+    </dependency>
   </dependencies>
 </project>
diff --git a/features/odl-transportpce-inventory/pom.xml b/features/odl-transportpce-inventory/pom.xml
new file mode 100644 (file)
index 0000000..d1f46e5
--- /dev/null
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright © 2016 Orange 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 INTERNAL -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.odlparent</groupId>
+        <artifactId>single-feature-parent</artifactId>
+        <version>3.1.0</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>odl-transportpce-inventory</artifactId>
+    <version>0.2.0-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <properties>
+        <transportpce.db.host>localhost:3306</transportpce.db.host>
+        <transportpce.db.database>tpce</transportpce.db.database>
+        <transportpce.db.username>root</transportpce.db.username>
+        <transportpce.db.password>root</transportpce.db.password>
+        <transporpce.device.backup.folder>data/transportpce/devicebackup</transporpce.device.backup.folder>
+        <transporpce.device.backup.prefix></transporpce.device.backup.prefix>
+        <transporpce.device.backup.period>600</transporpce.device.backup.period>
+        <!-- skipping single feature test because DataSource is not available in Pax4j (H2 possible workaround) -->
+        <skip.karaf.featureTest>true</skip.karaf.featureTest>
+    </properties>
+
+    <name>OpenDaylight :: transportpce :: Inventory</name>
+    <dependencies>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>transportpce-inventory</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.transportpce</groupId>
+            <artifactId>odl-transportpce-ui</artifactId>
+            <version>${project.version}</version>
+            <classifier>features</classifier>
+            <type>xml</type>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-resources-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${basedir}/target/resources</outputDirectory>
+                            <resources>
+                                <resource>
+                                    <directory>
+                                        src/main/resources
+                                    </directory>
+                                    <filtering>true</filtering>
+                                </resource>
+                            </resources>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>attach-db-artifact</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>target/resources/org.ops4j.datasource-transporpce.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>datasource</classifier>
+                                </artifact>
+                                <artifact>
+                                    <file>target/resources/org.opendaylight.transportpce.job.cfg</file>
+                                    <type>cfg</type>
+                                    <classifier>config</classifier>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/features/odl-transportpce-inventory/src/main/feature/feature.xml b/features/odl-transportpce-inventory/src/main/feature/feature.xml
new file mode 100644 (file)
index 0000000..f95a755
--- /dev/null
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<features xmlns="http://karaf.apache.org/xmlns/features/v1.4.0" name="odl-transportpce-inventory">
+    <feature name="odl-transportpce-inventory">
+        <feature>scheduler</feature>
+        <feature>pax-jdbc-mysql</feature>
+        <feature>pax-jdbc-pool-dbcp2</feature>
+        <configfile finalname="etc/org.ops4j.datasource-transportpce.cfg" override="false">
+            mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/datasource
+        </configfile>
+        <configfile finalname="etc/org.opendaylight.transportpce.job.cfg" override="false">
+            mvn:${project.groupId}/${project.artifactId}/${project.version}/cfg/config
+        </configfile>
+    </feature>
+</features>
\ No newline at end of file
diff --git a/features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg b/features/odl-transportpce-inventory/src/main/resources/org.opendaylight.transportpce.job.cfg
new file mode 100644 (file)
index 0000000..c350584
--- /dev/null
@@ -0,0 +1,6 @@
+#folder where backup files are stored
+deviceBackupFolder=${transporpce.device.backup.folder}
+#prefix for the generated files
+deviceBackupPrefix=${transporpce.device.backup.prefix}
+#period of storing the device info is seconds
+deviceBackupPeriod=${transporpce.device.backup.period}
diff --git a/features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg b/features/odl-transportpce-inventory/src/main/resources/org.ops4j.datasource-transporpce.cfg
new file mode 100644 (file)
index 0000000..c10ae34
--- /dev/null
@@ -0,0 +1,6 @@
+osgi.jdbc.driver.name=mysql
+url=jdbc:mysql://${transportpce.db.host}/${transportpce.db.database}?useUnicode=true&amp;characterEncoding=utf8
+pool=dbcp2
+user=${transportpce.db.username}
+password=${transportpce.db.password}
+dataSourceName=transportpce
index 4c4d1f13038153e0f9cbe0432edbc628fe0b216b..dd69778ee2e7061d0ad4d94f46bba35149562c1e 100644 (file)
@@ -94,6 +94,11 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
       <artifactId>transportpce-common</artifactId>
       <version>${project.version}</version>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.transportpce</groupId>
+      <artifactId>transportpce-networkmodel</artifactId>
+      <version>${project.version}</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.transportpce</groupId>
       <artifactId>transportpce-renderer</artifactId>
index 174fcc479f8a0ac64e8da3c2f921591f63b0ad49..d1b690d710602a6b8675361d86f946fcac7f1dfc 100644 (file)
@@ -29,6 +29,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <module>odl-transportpce-stubmodels</module>
     <module>odl-transportpce</module>
     <module>odl-transportpce-ui</module>
+    <module>odl-transportpce-inventory</module>
     <module>odl-transportpce-rest</module>
   </modules>
 
diff --git a/inventory/pom.xml b/inventory/pom.xml
new file mode 100644 (file)
index 0000000..ea11d15
--- /dev/null
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2016 Orange 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 -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>config-parent</artifactId>
+        <version>0.8.3-SNAPSHOT</version>
+        <relativePath />
+    </parent>
+
+    <groupId>org.opendaylight.transportpce</groupId>
+    <artifactId>transportpce-inventory</artifactId>
+    <version>0.2.0-SNAPSHOT</version>
+    <packaging>bundle</packaging>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.opendaylight.controller</groupId>
+                <artifactId>mdsal-artifacts</artifactId>
+                <version>1.7.3-SNAPSHOT</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+            <dependency>
+                <groupId>org.opendaylight.netconf</groupId>
+                <artifactId>netconf-artifacts</artifactId>
+                <version>1.4.3-SNAPSHOT</version>
+                <scope>import</scope>
+                <type>pom</type>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}.ordmodels</groupId>
+            <artifactId>transportpce-ordmodels-device</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>transportpce-renderer</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller.model</groupId>
+            <artifactId>model-topology</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>sal-netconf-connector</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.scheduler</groupId>
+            <artifactId>org.apache.karaf.scheduler.core</artifactId>
+            <version>4.0.9</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/DeviceInventory.java
new file mode 100644 (file)
index 0000000..63e0d41
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Pattern;
+
+import javax.sql.DataSource;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+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.Info;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class DeviceInventory {
+    private static final String INSERT_ALARM_STRING =
+        "insert into inv_alarm_info(nodeid, probablecause, direction,extension,location,"
+            + "notificationid,type,raisetime,severity,circuitid,circuitpack,connection,degree,iface,"
+            + "internallink,physicallink,service,shelf,sharedriskgroup,port,portcircuitpack, create_date, update_date) "
+            + "values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+    private static final Logger LOG = LoggerFactory.getLogger(DeviceInventory.class);
+
+    private final DataSource dataSource;
+    private final INode inode;
+    private final DeviceTransactionManager deviceTransactionManager;
+
+    public DeviceInventory(DataSource dataSource, INode inode,
+            DeviceTransactionManager deviceTransactionManager) {
+        this.dataSource = dataSource;
+        this.inode = inode;
+        this.deviceTransactionManager = deviceTransactionManager;
+    }
+
+    public void init() {
+        LOG.info("Initializing {}", DeviceInventory.class.getName());
+    }
+
+    public void initializeDevice(String deviceId) throws InterruptedException, ExecutionException {
+        InstanceIdentifier<Info> infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class);
+        Optional<Info> infoOpt =
+                this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, infoIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+
+        Info deviceInfo;
+        if (infoOpt.isPresent()) {
+            deviceInfo = infoOpt.get();
+        } else {
+            LOG.warn("Could not get device info from DataBrooker");
+            return;
+        }
+        LOG.info("Creating Device Inventory {}", deviceInfo);
+        if (!this.inode.nodeExists(deviceId)) {
+            LOG.info("Adding node {} to inventory", deviceId);
+            this.inode.addNode(deviceInfo);
+            this.inode.getRoadmShelves(deviceId);
+            this.inode.getCircuitPacks(deviceId);
+        }
+    }
+
+    /**
+     * Stores the alarm into DB using {@link PreparedStatement}.
+     *
+     * @param alarmString an alarm string
+     * @return number of rows inserted
+     */
+    public int storeAlarm(String alarmString) {
+        String delimiter = "|";
+        String[] splitAlarmString = alarmString.split(Pattern.quote(delimiter));
+        int count = 0;
+        try (Connection connection = this.dataSource.getConnection();
+                PreparedStatement statement = connection.prepareStatement(INSERT_ALARM_STRING)) {
+            LOG.debug("Inserting prepared stmt for {} query", INSERT_ALARM_STRING);
+            SimpleDateFormat simpleDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+            java.util.Date startTimetamp = new Date();
+            String startTimetampStr = simpleDate.format(startTimetamp);
+
+            for (int i = 0; i < 21; i++) {
+                String value = (splitAlarmString.length >= (i + 1)) ? splitAlarmString[i] : "";
+                LOG.debug("Setting parameter {}, to {} in the insert alarm query", i + 1, value);
+                statement.setString(i + 1, value);
+            }
+            statement.setString(22, startTimetampStr);
+            statement.setString(23, startTimetampStr);
+            LOG.debug("Setting current time and edited time to {}", startTimetampStr);
+            count = statement.executeUpdate();
+            LOG.debug("Statment {}, returned {}", INSERT_ALARM_STRING, count);
+            statement.clearParameters();
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+        return count;
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/INode.java
new file mode 100644 (file)
index 0000000..37c9ce7
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory;
+
+import static org.opendaylight.transportpce.inventory.utils.StringUtils.getCurrentTimestamp;
+import static org.opendaylight.transportpce.inventory.utils.StringUtils.prepareDashString;
+import static org.opendaylight.transportpce.inventory.utils.StringUtils.prepareEmptyString;
+
+import com.google.common.base.Preconditions;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.concurrent.ExecutionException;
+import javax.sql.DataSource;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.inventory.query.Queries;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
+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.Info;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.shelf.Slots;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.shelves.Shelves;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class INode {
+    private static final Logger LOG = LoggerFactory.getLogger(INode.class);
+
+    private final DataSource dataSource;
+    private final DeviceTransactionManager deviceTransactionManager;
+
+    public INode(DataSource dataSource, DeviceTransactionManager deviceTransactionManager) {
+        this.dataSource = dataSource;
+        this.deviceTransactionManager = deviceTransactionManager;
+    }
+
+    public boolean addNode(Info deviceInfo) {
+        boolean sqlResult = false;
+        String query = Queries.getQuery().deviceInfoInsert().get();
+        LOG.debug("Running {} query ", query);
+        try (Connection connection = dataSource.getConnection();
+                PreparedStatement preparedStatement = connection.prepareStatement(query)) {
+            String[] prepareParameters = prepareDeviceInfoParameters(deviceInfo);
+            for (int i = 0; i < prepareParameters.length; i++) {
+                LOG.debug("Parameter {} has value {}", i + 1, prepareParameters[i]);
+                preparedStatement.setString(i + 1, prepareParameters[i]);
+            }
+            int executeUpdate = preparedStatement.executeUpdate();
+            LOG.info("#{} entries were added", executeUpdate);
+            sqlResult = true;
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+        return sqlResult;
+    }
+
+    public boolean nodeExists(String nodeId) {
+        String selectTableSQL = "select count(*) node_exists from inv_dev_info where node_id = ?";
+        int nodeExists = 0;
+        LOG.info("Checking if {} exists in DB", nodeId);
+        try (Connection connection = dataSource.getConnection();
+                PreparedStatement preparedStmt = connection.prepareStatement(selectTableSQL)) {
+            preparedStmt.setString(1, nodeId);
+            try (ResultSet rs = preparedStmt.executeQuery()) {
+                while (rs.next()) {
+                    nodeExists = rs.getInt("node_exists");
+                    LOG.debug("Found {} devices matching {}", nodeExists, nodeId);
+                }
+            }
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+        return nodeExists == 0 ? false : true;
+    }
+
+    public void getRoadmShelves(String nodeId) throws InterruptedException, ExecutionException {
+        InstanceIdentifier<OrgOpenroadmDevice> deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class);
+        java.util.Optional<OrgOpenroadmDevice> deviceObject = deviceTransactionManager.getDataFromDevice(nodeId,
+                LogicalDatastoreType.OPERATIONAL, deviceIID, Timeouts.DEVICE_READ_TIMEOUT,
+                Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+
+        LOG.info("Shelves size {}", deviceObject.get().getShelves().size());
+        try (Connection connection = dataSource.getConnection()) {
+            Preconditions.checkNotNull(connection);
+            for (int i = 0; i < deviceObject.get().getShelves().size(); i++) {
+                Shelves shelve = deviceObject.get().getShelves().get(i);
+                String shelfName = shelve.getShelfName();
+
+                LOG.info("Getting Shelve Details of {}", shelfName);
+                LOG.info("Slot Size {} ", shelve.getSlots().size());
+
+                persistShelveSlots(nodeId, shelve, connection);
+
+                persistShelves(nodeId, connection, shelve);
+            }
+        } catch (SQLException e1) {
+            LOG.error(e1.getMessage(), e1);
+        }
+    }
+
+    public void getCircuitPacks(String nodeId) throws InterruptedException, ExecutionException {
+        InstanceIdentifier<OrgOpenroadmDevice> deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class);
+        java.util.Optional<OrgOpenroadmDevice> deviceObject =
+                deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (!deviceObject.isPresent()) {
+            LOG.warn("Device object {} was not found", nodeId);
+            return;
+        }
+        LOG.info("Circuit pack size {}", deviceObject.get().getCircuitPacks().size());
+
+        try (Connection connection = dataSource.getConnection()) {
+            Preconditions.checkNotNull(connection);
+            for (int i = 0; i < deviceObject.get().getCircuitPacks().size(); i++) {
+                CircuitPacks cp = deviceObject.get().getCircuitPacks().get(i);
+
+                if (cp.getCpSlots() != null) {
+                    persistCircuitPacksSlots(nodeId, cp, connection);
+                }
+                LOG.info("Everything {}", cp);
+                LOG.info("CP is {}", cp);
+
+                persistPorts(cp, connection);
+
+                persistCircuitPacks(nodeId, connection, cp);
+            }
+        } catch (SQLException e1) {
+            LOG.error(e1.getMessage(), e1);
+        }
+    }
+
+    private void persistCircuitPacks(String nodeId, Connection connection, CircuitPacks cp) {
+        String[] parameters = prepareCircuitPacksParameters(nodeId, cp);
+        String query = Queries.getQuery().deviceCircuitPackInsert().get();
+        try (PreparedStatement stmt = connection.prepareStatement(query)) {
+            for (int j = 0; j < parameters.length; j++) {
+                stmt.setString(j + 1, parameters[j]);
+            }
+            stmt.execute();
+            stmt.clearParameters();
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+    }
+
+    private void persistShelves(String nodeId, Connection connection, Shelves shelve) {
+        String[] shelvesParameter = prepareShelvesParameters(nodeId, shelve);
+        String query = Queries.getQuery().deviceShelfInsert().get();
+        try (PreparedStatement preparedStmt = connection.prepareStatement(query)) {
+            for (int j = 0; j < shelvesParameter.length; j++) {
+                preparedStmt.setString(j + 1, shelvesParameter[j]);
+            }
+            preparedStmt.execute();
+            preparedStmt.clearParameters();
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+    }
+
+    private void persistShelveSlots(String nodeId, Shelves shelves, Connection connection) {
+        String startTimetampStr = getCurrentTimestamp();
+        for (int i = 0; i < shelves.getSlots().size(); i++) {
+            Slots slot = shelves.getSlots().get(i);
+            LOG.info("Getting Slot Details of {}", slot.getSlotName());
+            String[] parameters = new String[] {nodeId, shelves.getShelfName(), slot.getSlotName(), slot.getLabel(),
+                    slot.getProvisionedCircuitPack(), startTimetampStr, startTimetampStr};
+            String query = Queries.getQuery().deviceShelfSlotInsert().get();
+            try (PreparedStatement stmt = connection.prepareStatement(query)) {
+                for (int j = 0; j < parameters.length; j++) {
+                    stmt.setString(j + 1, parameters[j]);
+                }
+                stmt.execute();
+                stmt.clearParameters();
+            } catch (SQLException e) {
+                LOG.error(e.getMessage(), e);
+            }
+        }
+    }
+
+    private void persistCircuitPacksSlots(String nodeId, CircuitPacks circuitPacks, Connection connection) {
+        LOG.warn("CP slots are not persisted yet");
+    }
+
+    private void persistPorts(CircuitPacks circuitPacks, Connection connection) {
+        LOG.warn("Ports are not persisted yet");
+    }
+
+
+    /**
+     * Prepares parameters for device insert query.
+     *
+     * @param deviceInfo the device Info
+     * @return String[] a string
+     */
+    private static String[] prepareDeviceInfoParameters(Info deviceInfo) {
+        String startTimetampStr = getCurrentTimestamp();
+
+        return new String[] {prepareDashString(deviceInfo.getNodeId()), prepareDashString(deviceInfo.getNodeNumber()),
+            prepareDashString(deviceInfo.getNodeType().getName()), prepareDashString(deviceInfo.getClli()),
+            prepareDashString(deviceInfo.getVendor()), prepareDashString(deviceInfo.getModel()),
+            prepareDashString(deviceInfo.getSerialId()), prepareDashString(deviceInfo.getPrefixLength()),
+            prepareDashString(deviceInfo.getDefaultGateway()), prepareDashString(deviceInfo.getSource().getName()),
+            prepareDashString(deviceInfo.getCurrentIpAddress()),
+            prepareDashString(deviceInfo.getCurrentPrefixLength()),
+            prepareDashString(deviceInfo.getDefaultGateway()),
+            prepareDashString(deviceInfo.getMacAddress().getValue()),
+            prepareDashString(deviceInfo.getSoftwareVersion()), prepareDashString(deviceInfo.getTemplate()),
+            prepareDashString(deviceInfo.getCurrentDatetime()),
+            deviceInfo.getGeoLocation() != null ? prepareDashString(deviceInfo.getGeoLocation().getLatitude()) : "",
+            deviceInfo.getGeoLocation() != null ? prepareDashString(deviceInfo.getGeoLocation().getLongitude()) : "",
+            prepareDashString(deviceInfo.getMaxDegrees()), prepareDashString(deviceInfo.getMaxSrgs()), startTimetampStr,
+            startTimetampStr};
+    }
+
+    /**
+     * Prepares parameters for shelves.
+     *
+     * @param nodeId the node ID
+     * @param shelve the shelves
+     * @return String[] a string
+     */
+    private static String[] prepareShelvesParameters(String nodeId, Shelves shelve) {
+        String startTimestamp = getCurrentTimestamp();
+
+        return new String[] {nodeId, shelve.getShelfName(), shelve.getShelfType(), shelve.getRack(),
+                shelve.getShelfPosition(), prepareEmptyString(shelve.getAdministrativeState()), shelve.getVendor(),
+                shelve.getModel(), shelve.getSerialId(), shelve.getType(), shelve.getProductCode(),
+                prepareEmptyString(shelve.getManufactureDate()), shelve.getClei(), shelve.getHardwareVersion(),
+                prepareEmptyString(shelve.getOperationalState()), prepareEmptyString(shelve.getEquipmentState()),
+                prepareEmptyString(shelve.getDueDate()), startTimestamp, startTimestamp};
+    }
+
+    private static String[] prepareCircuitPacksParameters(String nodeId, CircuitPacks cpack) {
+        return new String[] {nodeId, cpack.getCircuitPackName(), cpack.getCircuitPackType(),
+                cpack.getCircuitPackProductCode(), prepareEmptyString(cpack.getAdministrativeState()),
+                cpack.getVendor(), cpack.getModel(), cpack.getSerialId(), cpack.getType(), cpack.getProductCode(),
+                prepareEmptyString(cpack.getManufactureDate()), cpack.getClei(), cpack.getHardwareVersion(),
+                prepareEmptyString(cpack.getOperationalState()), prepareEmptyString(cpack.getEquipmentState()),
+                cpack.getCircuitPackMode(), cpack.getShelf(), cpack.getSlot(), cpack.getSubSlot(),
+                cpack.getCircuitPackCategory().getType().getName(), cpack.getCircuitPackCategory().getExtension(),
+                prepareEmptyString(cpack.getDueDate()), cpack.getParentCircuitPack().getCircuitPackName(),
+                cpack.getParentCircuitPack().getCpSlotName()};
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/ListenerProvider.java
new file mode 100644 (file)
index 0000000..0bfa503
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
+import org.opendaylight.transportpce.inventory.listener.ClliNetworkChangeListener;
+import org.opendaylight.transportpce.inventory.listener.DeviceListener;
+import org.opendaylight.transportpce.inventory.listener.OverlayNetworkChangeListener;
+import org.opendaylight.transportpce.inventory.listener.ServiceListener;
+import org.opendaylight.transportpce.inventory.listener.UnderlayNetworkChangeListener;
+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;
+
+/**
+ * {@link ListenerProvider} registers {@link DataTreeChangeListener} for each
+ * network layer.
+ *
+ */
+public class ListenerProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ListenerProvider.class);
+
+    private final DataBroker dataBroker;
+    private final OverlayNetworkChangeListener overlayNetworkListener;
+    private final UnderlayNetworkChangeListener underlayNetworkListener;
+    private final ClliNetworkChangeListener clliNetworkChangeListener;
+    private final ServiceListener serviceListener;
+    private final DeviceListener deviceListener;
+
+    /**
+     * Constructor invoked by blueprint injects all dependencies.
+     *
+     * @param dataBroker the databroker
+     * @param overlayNetworkListener the overlay network listener
+     * @param underlayNetworkListener the underlay network listener
+     * @param clliNetworkChangeListener the CLLI network changes listener
+     * @param serviceListener the service listener
+     * @param deviceListener the device listener
+     */
+    public ListenerProvider(DataBroker dataBroker, OverlayNetworkChangeListener overlayNetworkListener,
+            UnderlayNetworkChangeListener underlayNetworkListener, ClliNetworkChangeListener clliNetworkChangeListener,
+            ServiceListener serviceListener, DeviceListener deviceListener) {
+        this.dataBroker = dataBroker;
+        this.overlayNetworkListener = overlayNetworkListener;
+        this.underlayNetworkListener = underlayNetworkListener;
+        this.clliNetworkChangeListener = clliNetworkChangeListener;
+        this.serviceListener = serviceListener;
+        this.deviceListener = deviceListener;
+    }
+
+    /**
+     * Invoked by blueprint, registers the listeners.
+     */
+    public void initialize() {
+        LOG.debug("Registering listeners...");
+        dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.OVERLAY_NETWORK_II),
+                overlayNetworkListener);
+        LOG.info("Overlay network change listener was successfully registered");
+        dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.UNDERLAY_NETWORK_II),
+                underlayNetworkListener);
+        LOG.info("Underlay network change listener was successfully registered");
+        dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, InstanceIdentifiers.CLLI_NETWORK_II),
+                clliNetworkChangeListener);
+        LOG.info("CLLI network change listener was successfully registered");
+        dataBroker.registerDataTreeChangeListener(
+                new DataTreeIdentifier<>(LogicalDatastoreType.CONFIGURATION, ServiceListener.SERVICES_II),
+                serviceListener);
+        LOG.info("Service path listener was successfully registered");
+        dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), deviceListener);
+        LOG.info("Device change listener was successfully registered");
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/dto/InvDevInfo.java
new file mode 100644 (file)
index 0000000..c528f0e
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.dto;
+
+public class InvDevInfo {
+    private String nodeId;
+    private String nodeNumber;
+    private String nodeType;
+    private String clli;
+    private String vendor;
+    private String model;
+    private String serialId;
+    private String ipAddress;
+    private String prefixLength;
+    private String defaultGateway;
+    private String source;
+    private String currentIpAddress;
+    private String currentPrefixLength;
+    private String currentDefaultGateway;
+    private String macAddress;
+    private String softwareVersion;
+    private String template;
+    private String currentDatetime;
+    private String latitude;
+    private String longitude;
+    private String maxDegrees;
+    private String maxSrgs;
+    private String swVersion;
+    private String swValidationTimer;
+    private String activationDateTime;
+    private String createDate;
+    private String updateDate;
+
+
+    public String getNodeId() {
+        return this.nodeId;
+    }
+
+    public void setNode_id(String nodeId) {
+        this.nodeId = nodeId;
+    }
+
+    public String getNode_number() {
+        return this.nodeNumber;
+    }
+
+    public void setNode_number(String nodeNumber) {
+        this.nodeNumber = nodeNumber;
+    }
+
+    public String getNode_type() {
+        return this.nodeType;
+    }
+
+    public void setNode_type(String nodeType) {
+        this.nodeType = nodeType;
+    }
+
+    public String getClli() {
+        return this.clli;
+    }
+
+    public void setClli(String clli) {
+        this.clli = clli;
+    }
+
+    public String getVendor() {
+        return this.vendor;
+    }
+
+    public void setVendor(String vendor) {
+        this.vendor = vendor;
+    }
+
+    public String getModel() {
+        return this.model;
+    }
+
+    public void setModel(String model) {
+        this.model = model;
+    }
+
+    public String getSerial_id() {
+        return this.serialId;
+    }
+
+    public void setSerial_id(String serialId) {
+        this.serialId = serialId;
+    }
+
+    public String getIpAddress() {
+        return this.ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public String getPrefix_length() {
+        return this.prefixLength;
+    }
+
+    public void setPrefix_length(String prefixLength) {
+        this.prefixLength = prefixLength;
+    }
+
+    public String getDefault_gateway() {
+        return this.defaultGateway;
+    }
+
+    public void setDefault_gateway(String defaultGateway) {
+        this.defaultGateway = defaultGateway;
+    }
+
+    public String getSource() {
+        return this.source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public String getCurrent_ipAddress() {
+        return this.currentIpAddress;
+    }
+
+    public void setCurrent_ipAddress(String currentIpAddress) {
+        this.currentIpAddress = currentIpAddress;
+    }
+
+    public String getCurrent_prefix_length() {
+        return this.currentPrefixLength;
+    }
+
+    public void setCurrent_prefix_length(String currentPrefixLength) {
+        this.currentPrefixLength = currentPrefixLength;
+    }
+
+    public String getCurrent_default_gateway() {
+        return this.currentDefaultGateway;
+    }
+
+    public void setCurrent_default_gateway(String currentDefaultGateway) {
+        this.currentDefaultGateway = currentDefaultGateway;
+    }
+
+    public String getMacAddress() {
+        return this.macAddress;
+    }
+
+    public void setMacAddress(String macAddress) {
+        this.macAddress = macAddress;
+    }
+
+    public String getSoftware_version() {
+        return this.softwareVersion;
+    }
+
+    public void setSoftware_version(String softwareVersion) {
+        this.softwareVersion = softwareVersion;
+    }
+
+    public String getTemplate() {
+        return this.template;
+    }
+
+    public void setTemplate(String template) {
+        this.template = template;
+    }
+
+    public String getCurrent_datetime() {
+        return this.currentDatetime;
+    }
+
+    public void setCurrent_datetime(String currentDatetime) {
+        this.currentDatetime = currentDatetime;
+    }
+
+    public String getLatitude() {
+        return this.latitude;
+    }
+
+    public void setLatitude(String latitude) {
+        this.latitude = latitude;
+    }
+
+    public String getLongitude() {
+        return this.longitude;
+    }
+
+    public void setLongitude(String longitude) {
+        this.longitude = longitude;
+    }
+
+    public String getMax_degrees() {
+        return this.maxDegrees;
+    }
+
+    public void setMax_degrees(String maxDegrees) {
+        this.maxDegrees = maxDegrees;
+    }
+
+    public String getMax_srgs() {
+        return this.maxSrgs;
+    }
+
+    public void setMax_srgs(String maxSrgs) {
+        this.maxSrgs = maxSrgs;
+    }
+
+    public String getSw_version() {
+        return this.swVersion;
+    }
+
+    public void setSw_version(String swVersion) {
+        this.swVersion = swVersion;
+    }
+
+    public String getSw_validation_timer() {
+        return this.swValidationTimer;
+    }
+
+    public void setSw_validation_timer(String swValidationTimer) {
+        this.swValidationTimer = swValidationTimer;
+    }
+
+    public String getActivation_date_time() {
+        return this.activationDateTime;
+    }
+
+    public void setActivation_date_time(String activationDateTime) {
+        this.activationDateTime = activationDateTime;
+    }
+
+    public String getCreate_date() {
+        return this.createDate;
+    }
+
+    public void setCreate_date(String createDate) {
+        this.createDate = createDate;
+    }
+
+    public String getUpdate_date() {
+        return this.updateDate;
+    }
+
+    public void setUpdate_date(String updateDate) {
+        this.updateDate = updateDate;
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/job/PeriodicDeviceBackupJob.java
new file mode 100644 (file)
index 0000000..a431dd2
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.job;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.base.Strings;
+import com.google.common.io.Files;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+import org.apache.karaf.scheduler.Job;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.mdsal.dom.api.DOMSchemaService;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.OrgOpenroadmDevice;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNode;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
+import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Class which periodically backups the device into a file implements {@link Job}
+ * interface which is automatically registered via whitboard pattern into karaf
+ *  environment. This job will persist an {@link OrgOpenroadmDevice} capable with
+ *  the models provided in transportpce-models
+ */
+public class PeriodicDeviceBackupJob implements Runnable {
+
+    private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd_HH-mm-ss-SSS";
+    private static final String ORG_OPENROADM_DEVICE = "org-openroadm-device";
+    private static final Logger LOG = LoggerFactory.getLogger(PeriodicDeviceBackupJob.class);
+
+    private final DataBroker dataBroker;
+    private final DeviceTransactionManager deviceTransactionManager;
+
+    private final SchemaContext schemaContext;
+    private final SimpleDateFormat filenameFormatter;
+
+    /**
+     * Folder property, where the file is placed.
+     */
+    private String folder;
+    /**
+     * Prefix of device file.
+     */
+    private String filePrefix;
+
+    /**
+     * Constructor with injected fields.
+     *
+     * @param dataBroker the datatabroker
+     * @param domSchemaService the DOM schema service
+     * @param deviceTransactionManager the device transaction manager
+     */
+    public PeriodicDeviceBackupJob(DataBroker dataBroker, DOMSchemaService domSchemaService,
+            DeviceTransactionManager deviceTransactionManager) {
+        this.dataBroker = dataBroker;
+        this.schemaContext = domSchemaService.getGlobalContext();
+        this.deviceTransactionManager = deviceTransactionManager;
+        this.filenameFormatter = new SimpleDateFormat(TIMESTAMP_FORMAT);
+    }
+
+    @Override
+    public void run() {
+        LOG.info("Running periodical device backup into {}", folder);
+        try {
+            backupAllDevices();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Unable to read netconf topology from the operational datastore", e);
+        }
+    }
+
+    /**
+     * Gets the folder.
+     *
+     * @return the folder
+     */
+    public String getFolder() {
+        return folder;
+    }
+
+    /**
+     * Sets the folder.
+     *
+     * @param folder the folder to set
+     */
+    public void setFolder(String folder) {
+        this.folder = folder;
+    }
+
+    /**
+     * Gets the filePrefix.
+     *
+     * @return the filePrefix
+     */
+    public String getFilePrefix() {
+        return filePrefix;
+    }
+
+    /**
+     * Sets the filePrefix.
+     *
+     * @param filePrefix the filePrefix to set
+     */
+    public void setFilePrefix(String filePrefix) {
+        this.filePrefix = filePrefix;
+    }
+
+    /**
+     * Stores all devices into files.
+     *
+     * @throws InterruptedException interrupted exception
+     * @throws ExecutionException execution exception
+     */
+    private void backupAllDevices() throws InterruptedException, ExecutionException {
+        ReadOnlyTransaction newReadOnlyTransaction = dataBroker.newReadOnlyTransaction();
+        Optional<Topology> topology = newReadOnlyTransaction
+                .read(LogicalDatastoreType.OPERATIONAL, InstanceIdentifiers.NETCONF_TOPOLOGY_II).get().toJavaUtil();
+        if (!topology.isPresent()) {
+            LOG.warn("Netconf topology was not found in datastore");
+            return;
+        }
+
+        for (Node node : topology.get().getNode()) {
+            String nodeId = getNodeId(node);
+            if (Strings.isNullOrEmpty(nodeId)) {
+                LOG.debug("{} node is not a roadm device");
+                continue;
+            }
+            storeRoadmDevice(nodeId);
+        }
+    }
+
+    /**
+     * Stores a single ROADM device into a file.
+     *
+     * @param nodeId the node ID
+     */
+    private void storeRoadmDevice(String nodeId) {
+        InstanceIdentifier<OrgOpenroadmDevice> deviceIi = InstanceIdentifier.create(OrgOpenroadmDevice.class);
+        Optional<OrgOpenroadmDevice> deviceObject =
+                deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, deviceIi,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (!deviceObject.isPresent()) {
+            LOG.warn("Device object {} is not present.", nodeId);
+            return;
+        }
+
+        // TODO: Serialization should be done via XMLDataObjectConverter when devices use the same model as
+        // this project
+        /*
+         * XMLDataObjectConverter createWithSchemaContext =
+         * XMLDataObjectConverter.createWithSchemaContext(schemaContext, nodeSerializer); Writer
+         * writerFromDataObject = createWithSchemaContext.writerFromDataObject(deviceObject.get(),
+         * OrgOpenroadmDevice.class, createWithSchemaContext.dataContainer());
+         */
+        StringBuilder serializedDevice = new StringBuilder();
+        try {
+            serializedDevice.append(new ObjectMapper().writeValueAsString(deviceObject.get()));
+        } catch (JsonProcessingException e1) {
+            LOG.error(e1.getMessage(), e1);
+        }
+
+        String prepareFileName = prepareFileName(nodeId);
+        File parent = new File(folder);
+        if (!parent.exists() && !parent.isDirectory() && !parent.mkdirs()) {
+            LOG.error("Could not create empty directory {}", folder);
+            throw new IllegalStateException(String.format("Could not create empty directory %s", folder));
+        }
+
+        File file = new File(parent, filePrefix.concat(prepareFileName));
+        if (file.exists()) {
+            throw new IllegalStateException(String.format("The file %s already exists", file));
+        }
+        try {
+            Files.asCharSink(file, StandardCharsets.UTF_8).write(serializedDevice.toString());
+        } catch (IOException e) {
+            LOG.error("Could not write device backup into file {}", file);
+        }
+    }
+
+    private String prepareFileName(String nodeId) {
+        String format = filenameFormatter.format(new Date());
+        StringBuilder sb = new StringBuilder(format);
+        sb.append("__").append(nodeId).append("__").append(".xml");
+        return sb.toString();
+    }
+
+    /**
+     * If the {@link Node} in the {@link Topology} is a {@link NetconfNode}, has
+     * capabilities of {@link PeriodicDeviceBackupJob#ORG_OPENROADM_DEVICE} and the
+     * key is not null returns the identifier of {@link OrgOpenroadmDevice} node.
+     *
+     * @param node inside the {@link Topology}
+     * @return node key
+     */
+    private static String getNodeId(Node node) {
+        if (node == null) {
+            LOG.trace("The node is null");
+            return "";
+        }
+        NetconfNode netconfNode = node.getAugmentation(NetconfNode.class);
+        if (netconfNode == null) {
+            LOG.trace("The node {} has not properties of NetconfNode", node);
+            return "";
+        }
+        if (netconfNode.getAvailableCapabilities() == null
+                || netconfNode.getAvailableCapabilities().getAvailableCapability() == null) {
+            LOG.trace("No available capabilities");
+            return "";
+        }
+        long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream()
+                .filter(cp -> cp.getCapability() != null && cp.getCapability().contains(ORG_OPENROADM_DEVICE)).count();
+        if (count < 1) {
+            LOG.trace("The node {} has not capabilities of OpenROADMDevice", node);
+            return "";
+        }
+        if (node.getKey() == null || node.getKey().getNodeId() == null) {
+            LOG.trace("Node {} has invalid key", node);
+            return "";
+        }
+        if ("controller-config".equalsIgnoreCase(node.getKey().getNodeId().getValue())) {
+            LOG.info("Got controller-config instead of roadm-node");
+            return "";
+        }
+        return node.getKey().getNodeId().getValue();
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ClliNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..41a23ac
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.listener;
+
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClliNetworkChangeListener implements DataTreeChangeListener<Network> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClliNetworkChangeListener.class);
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Network>> changes) {
+        LOG.info("Clli network changed {}", changes);
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/DeviceListener.java
new file mode 100644 (file)
index 0000000..2f8f8c6
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.listener;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.transportpce.common.StringConstants;
+import org.opendaylight.transportpce.inventory.DeviceInventory;
+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;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus.ConnectionStatus;
+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;
+
+/**
+ * This class implements the {@link DataTreeChangeListener} on a {@link Node}. This listener should
+ * be registered on a netconf topology node.
+ *
+ */
+public class DeviceListener implements DataTreeChangeListener<Node> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(DeviceListener.class);
+    private final DeviceInventory deviceInventory;
+
+    /**
+     * Default constructor invoked by blueprint injects {@link DeviceInventory} as a persistence layer.
+     *
+     * @param deviceInventory reference to the {@link DeviceInventory}
+     */
+    public DeviceListener(DeviceInventory deviceInventory) {
+        this.deviceInventory = deviceInventory;
+    }
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
+        List<DataTreeModification<Node>> changesWithoutDefaultNetconfNode = getRealDevicesOnly(changes);
+        for (DataTreeModification<Node> device : changesWithoutDefaultNetconfNode) {
+            String nodeId = device.getRootNode().getDataAfter().getKey().getNodeId().getValue();
+            NetconfNode netconfNode = device.getRootNode().getDataAfter().getAugmentation(NetconfNode.class);
+            if (isCreate(device) || isUpdate(device)) {
+                LOG.info("Node {} was modified", nodeId);
+                try {
+                    processModifiedSubtree(nodeId, netconfNode);
+                } catch (InterruptedException | ExecutionException e) {
+                    LOG.error(e.getMessage(), e);
+                }
+            } else if (isDelete(device)) {
+                LOG.info("Node {} was deleted", nodeId);
+            }
+        }
+    }
+
+    /**
+     * Handles the {@link ModificationType#SUBTREE_MODIFIED} case. If the changed node has
+     * {@link StringConstants.OPENROADM_DEVICE_MODEL_NAME} capabilities it may be persisted.
+     *
+     * @param nodeId device id
+     * @param netconfNode netconf node
+     * @throws InterruptedException may be thrown if there is a problem getting the device from
+     *         datastore
+     * @throws ExecutionException may be thrown if there is a problem getting the device from datastore
+     */
+    private void processModifiedSubtree(String nodeId, NetconfNode netconfNode)
+            throws InterruptedException, ExecutionException {
+        NetconfNodeConnectionStatus.ConnectionStatus connectionStatus = netconfNode.getConnectionStatus();
+        long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream()
+                .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME)).count();
+        if (count < 1) {
+            LOG.info("No {} capable device was found", StringConstants.OPENROADM_DEVICE_MODEL_NAME);
+            return;
+        }
+        if (ConnectionStatus.Connected.equals(connectionStatus)) {
+            deviceInventory.initializeDevice(nodeId);
+        } else if (ConnectionStatus.Connecting.equals(connectionStatus)
+                || ConnectionStatus.UnableToConnect.equals(connectionStatus)) {
+            LOG.info("The device is in {} state", connectionStatus);
+        } else {
+            LOG.warn("Invalid connection status {}", connectionStatus);
+        }
+    }
+
+    /**
+     * Filters the {@link StringConstants#DEFAULT_NETCONF_NODEID} nodes from the provided
+     * {@link Collection}.
+     *
+     * @param changes a change
+     * @return {@code List<DataTreeModification<Node>>} a list of modifcations
+     */
+    private static List<DataTreeModification<Node>> getRealDevicesOnly(Collection<DataTreeModification<Node>> changes) {
+        return changes.stream()
+                .filter(change -> (change.getRootNode().getDataAfter() != null
+                        && !StringConstants.DEFAULT_NETCONF_NODEID
+                                .equalsIgnoreCase(change.getRootNode().getDataAfter().getKey().getNodeId().getValue())
+                        && change.getRootNode().getDataAfter().getAugmentation(NetconfNode.class) != null)
+                        || (change.getRootNode().getDataBefore() != null
+                                && !StringConstants.DEFAULT_NETCONF_NODEID.equalsIgnoreCase(
+                                        change.getRootNode().getDataBefore().getKey().getNodeId().getValue())
+                                && change.getRootNode().getDataBefore().getAugmentation(NetconfNode.class) != null
+
+                        )).collect(Collectors.toList());
+    }
+
+    /**
+     * In the filtered collection checks if the change is a new write.
+     *
+     * @param change the change
+     * @return boolean true if the change is a new write
+     */
+    private static boolean isCreate(DataTreeModification<Node> change) {
+        return change.getRootNode().getDataBefore() == null && change.getRootNode().getDataAfter() != null
+                && ModificationType.WRITE.equals(change.getRootNode().getModificationType());
+    }
+
+    /**
+     * In the filtered collection checks if the modification is update.
+     *
+     * @param change the change
+     * @return boolean true if the modification is update
+     */
+    private static boolean isUpdate(DataTreeModification<Node> change) {
+        return ModificationType.SUBTREE_MODIFIED.equals(change.getRootNode().getModificationType());
+    }
+
+    /**
+     * In the filtered collection checks if the node was deleted.
+     *
+     * @param change the change
+     * @return boolean true if the node was deleted
+     */
+    private static boolean isDelete(DataTreeModification<Node> change) {
+        return change.getRootNode().getDataBefore() != null && change.getRootNode().getDataAfter() == null
+                && ModificationType.DELETE.equals(change.getRootNode().getModificationType());
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/OverlayNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..f5acd15
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.listener;
+
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OverlayNetworkChangeListener implements DataTreeChangeListener<Network> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OverlayNetworkChangeListener.class);
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Network>> changes) {
+        LOG.info("Overlay network changed {}", changes);
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/ServiceListener.java
new file mode 100644 (file)
index 0000000..4c82b98
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.listener;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.sql.DataSource;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.transportpce.inventory.query.Queries;
+import org.opendaylight.transportpce.inventory.query.QueryUtils;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.ServiceList;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.service.list.Services;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * {@link ServiceListener} listens on {@link ServiceList} changes.
+ *
+ */
+public class ServiceListener implements DataTreeChangeListener<ServiceList> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ServiceListener.class);
+    public static final InstanceIdentifier<ServiceList> SERVICES_II =
+            InstanceIdentifier.create(ServiceList.class);
+    /**
+     * Implementation for the {@link ChangeHandler} stores a newly added {@link Services}.
+     */
+    private static final ChangeHandler CREATE_HANDLER = (services, connection) -> {
+        try (PreparedStatement stmt = connection.prepareStatement(Queries.getQuery().serviceCreate().get())) {
+            QueryUtils.setCreateServiceParameters(stmt, services);
+            stmt.executeUpdate();
+            stmt.clearParameters();
+        } catch (SQLException e) {
+            LOG.error("Could not insert service path {}", services);
+        }
+    };
+
+    /**
+     * Implementation for the {@link ChangeHandler} removes the deleted {@link Services}.
+     */
+    private static final ChangeHandler DELETE_HANDLER = (services, connection) -> {
+        try (PreparedStatement stmt = connection.prepareStatement(Queries.getQuery().serviceDelete().get())) {
+            stmt.setString(1, services.getServiceName());
+            stmt.executeUpdate();
+            stmt.clearParameters();
+        } catch (SQLException e) {
+            LOG.error("Could not delete service path {}", services);
+            LOG.error(e.getMessage(), e);
+        }
+    };
+
+    private final DataSource dataSource;
+
+    /**
+     * Default constructor invoked by bluprint injects all required dependencies.
+     *
+     * @param dataSource reference for {@link DataSource}
+     */
+    public ServiceListener(DataSource dataSource) {
+        this.dataSource = dataSource;
+    }
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<ServiceList>> changes) {
+        LOG.debug("Service path list changed ...");
+        List<DataTreeModification<ServiceList>> createItems =
+                changes.stream().filter(ServiceListener::writeFilter).collect(Collectors.toList());
+        List<DataTreeModification<ServiceList>> deleteItems =
+                changes.stream().filter(ServiceListener::deleteFilter).collect(Collectors.toList());
+        try (Connection connection = dataSource.getConnection()) {
+            handleModification(createItems, CREATE_HANDLER, connection);
+            handleModification(deleteItems, DELETE_HANDLER, connection);
+        } catch (SQLException e) {
+            LOG.error(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Handles the change with {@link ChangeHandler}.
+     *
+     * @param changeList list of modifications
+     * @param handleChange concrete implementation of {@link ChangeHandler}
+     * @param connection {@link DataSource} we don't want to create each time a new connection
+     */
+    private void handleModification(List<DataTreeModification<ServiceList>> changeList, ChangeHandler handleChange,
+            Connection connection) {
+        for (DataTreeModification<ServiceList> change : changeList) {
+            ServiceList serviceList = change.getRootNode().getDataAfter();
+            for (Services service : serviceList.getServices()) {
+                handleChange.handleChange(service, connection);
+            }
+        }
+    }
+
+    /**
+     * Returns the filter for {@link ModificationType#WRITE} type change.
+     *
+     * @see #buildFilter(DataTreeModification, ModificationType)
+     * @param modification write modification object
+     * @return if the object was created
+     */
+    private static boolean writeFilter(DataTreeModification<ServiceList> modification) {
+        return buildFilter(modification, ModificationType.WRITE);
+    }
+
+    /**
+     * Returns the filter for {@link ModificationType#DELETE} type change.
+     *
+     * @see #deleteFilter(DataTreeModification)
+     * @param modification delete modification
+     * @return if the object was deleted
+     */
+    private static boolean deleteFilter(DataTreeModification<ServiceList> modification) {
+        return buildFilter(modification, ModificationType.DELETE);
+    }
+
+    /**
+     * Generalizes the creation of filter used in
+     * {@link #onDataTreeChanged(Collection)} method.
+     *
+     * @param modification a modification
+     * @param modificationType a modification type
+     * @return boolean modification status
+     */
+    private static boolean buildFilter(DataTreeModification<ServiceList> modification,
+            ModificationType modificationType) {
+        return (modification.getRootNode().getDataAfter() != null
+                && modificationType.equals(modification.getRootNode().getModificationType()));
+    }
+
+    /**
+     * ChangeHandler interface is responsible for inserts or deletes in the DB based
+     * on the implementation.
+     *
+     */
+    private interface ChangeHandler {
+
+        /**
+         * Method will handle the changed {@link Services}.
+         *
+         * @param services changed object
+         * @param connection {@link Connection} should be created in the caller method and
+         *        not closed in the implementation
+         */
+        void handleChange(Services services, Connection connection);
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/listener/UnderlayNetworkChangeListener.java
new file mode 100644 (file)
index 0000000..c8937ee
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.listener;
+
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class UnderlayNetworkChangeListener implements DataTreeChangeListener<Network> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(UnderlayNetworkChangeListener.class);
+
+    @Override
+    public void onDataTreeChanged(Collection<DataTreeModification<Network>> changes) {
+        LOG.info("Underlay network changed {}", changes);
+    }
+
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/Queries.java
new file mode 100644 (file)
index 0000000..d0381ce
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.query;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+
+public class Queries {
+
+    private static final String DEVICE_INFO_INSERT =
+        "INSERT INTO %sinv_dev_info "
+        + "(node_id, node_number, node_type, clli, vendor, model, serial_id, ipAddress, prefix_length, "
+        + "default_gateway, source, current_ipAddress, current_prefix_length, current_default_gateway, macAddress, "
+        + "software_version, template, current_datetime, latitude, longitude, max_degrees, max_srgs, sw_version, "
+        + "sw_validation_timer, activation_date_time, create_date, update_date) "
+        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+    private static final String DEVICE_SHELF_INSERT =
+        "INSERT INTO %sinv_dev_shelf "
+        + "(node_id, shelf_name, shelf_type, rack, shelf_position, administrative_state, vendor, model, serial_id, "
+        + "type, product_code, manufacture_date, clei, hardware_version, operational_state, equipment_state, due_date, "
+        + "create_date, update_date) "
+        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+    private static final String DEVICE_SHELF_SLOT_INSERT =
+        "INSERT INTO %sinv_dev_shelf_slot "
+        + "(node_id, shelf_name, slot_name, label, provisioned_circuit_pack, create_date, update_date) "
+        + "VALUES (?, ?, ?, ?, ?, ?, ?)";
+
+    private static final String DEVICE_CP_INSERT =
+        "INSERT INTO %sinv_dev_circuit_pack "
+        + "(node_id, circuitPackName, circuitPackType, circuitPackProductCode, administrative_state, vendor, model, "
+        + "serial_id, type, product_code, manufacture_date, clei, hardware_version, operational_state, "
+        + "equipment_state, shelf, slot, subSlo, cpCatType, extension, due_date, parentCpName, parentCpSlotName) "
+        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+    private static final String SERVICE_INSERT =
+        "INSERT INTO %sinv_ser_main "
+        + "(service_name, common_id, sdnc_req_header_request_id, sdnc_req_header_rpc_action, "
+        + "sdnc_req_header_notification_url, sdnc_req_header_request_system_id, connection_type, lifecycle_state, "
+        + "administrative_state, operational_state, serv_condition, a_end_service_format, a_end_service_rate, "
+        + "a_end_clli, a_end_node_id, a_end_tx_port_device_name, a_end_tx_port_type, a_end_tx_port_name, "
+        + "a_end_tx_port_rack, a_end_tx_port_shelf, a_end_tx_port_slot, a_end_tx_port_sub_slot, "
+        + "a_end_tx_lgx_device_name, a_end_tx_lgx_port_name, a_end_tx_lgx_port_rack, a_end_tx_lgx_port_shelf, "
+        + "a_end_tx_tail_rnode_id, a_end_tx_xport_cp_name, a_end_tx_xport_port_name, a_end_tx_tail_roadm_port_aid, "
+        + "a_end_tx_tail_roadm_port_rack_loc, a_end_rx_port_device_name, a_end_rx_port_type, a_end_rx_port_name, "
+        + "a_end_rx_port_rack, a_end_rx_port_shelf, a_end_rx_port_slot, a_end_rx_port_sub_slot, "
+        + "a_end_rx_lgx_device_name, a_end_rx_lgx_port_name, a_end_rx_lgx_port_rack, a_end_rx_lgx_port_shelf, "
+        + "a_end_rx_tail_rnode_id, a_end_rx_xport_cp_name, a_end_rx_xport_port_name, a_end_rx_tail_roadm_port_aid, "
+        + "a_end_rx_tail_roadm_port_rack_loc, a_end_optic_type, a_end_router_node_id, a_end_router_ip_address, "
+        + "a_end_router_url, a_end_user_label, z_end_service_format, z_end_service_rate, z_end_clli, z_end_node_id, "
+        + "z_end_tx_port_device_name, z_end_tx_port_type, z_end_tx_port_name, z_end_tx_port_rack, z_end_tx_port_shelf, "
+        + "z_end_tx_port_slot, z_end_tx_port_sub_slot, z_end_tx_lgx_device_name, z_end_tx_lgx_port_name, "
+        + "z_end_tx_lgx_port_rack, z_end_tx_lgx_port_shelf, z_end_tx_tail_rnode_id, z_end_tx_xport_cp_name, "
+        + "z_end_tx_xport_port_name, z_end_tx_tail_roadm_port_aid, z_end_tx_tail_roadm_port_rack_loc, "
+        + "z_end_rx_port_device_name, z_end_rx_port_type, z_end_rx_port_name, z_end_rx_port_rack, z_end_rx_port_shelf, "
+        + "z_end_rx_port_slot, z_end_rx_port_sub_slot, z_end_rx_lgx_device_name, z_end_rx_lgx_port_name, "
+        + "z_end_rx_lgx_port_rack, z_end_rx_lgx_port_shelf, z_end_rx_tail_rnode_id, z_end_rx_xport_cp_name, "
+        + "z_end_rx_xport_port_name, z_end_rx_tail_roadm_port_aid, z_end_rx_tail_roadm_port_rack_loc, "
+        + "z_end_optic_type, z_end_router_node_id, z_end_router_ip_address, z_end_router_url, z_end_user_label, "
+        + "due_date, end_date, nc_code, nci_code, secondary_nci_code, customer, customer_contact, operator_contact, "
+        + "latency, fiber_span_srlgs, supp_serv_name, create_date, update_date) "
+        + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
+        + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, "
+        + "?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+
+    private static final String SERVICE_DELETE =
+        "DELETE FROM %sinv_ser_main WHERE service_name = ?";
+
+    private Queries() {
+        // util class
+    }
+
+    public static Query getQuery() {
+        return new Query();
+    }
+
+    public static class Query {
+        private String sql;
+        private String schema;
+
+        private Query() {
+            this.schema = "";
+        }
+
+        public Query withSchema(String schema) {
+            this.schema = schema;
+            return this;
+        }
+
+        public Query deviceInfoInsert() {
+            this.sql = DEVICE_INFO_INSERT;
+            return this;
+        }
+
+        public Query deviceShelfInsert() {
+            this.sql = DEVICE_SHELF_INSERT;
+            return this;
+        }
+
+        public Query deviceShelfSlotInsert() {
+            this.sql = DEVICE_SHELF_SLOT_INSERT;
+            return this;
+        }
+
+        public Query deviceCircuitPackInsert() {
+            this.sql = DEVICE_CP_INSERT;
+            return this;
+        }
+
+        public Query serviceCreate() {
+            this.sql = SERVICE_INSERT;
+            return this;
+        }
+
+        public Query serviceDelete() {
+            this.sql = SERVICE_DELETE;
+            return this;
+        }
+
+        public String get() {
+            Preconditions.checkArgument(!Strings.isNullOrEmpty(this.sql), "No query selected");
+            return String.format(this.sql, this.schema.concat("."));
+        }
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/QueryUtils.java
new file mode 100644 (file)
index 0000000..6e031f0
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.query;
+
+import static org.opendaylight.transportpce.inventory.utils.StringUtils.getCurrentTimestamp;
+
+import com.google.common.base.Strings;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.ServiceAEnd;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.ServiceZEnd;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.Router;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.RxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.endpoint.TxDirection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.service.types.rev161014.service.port.Port;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.service.rev161014.service.list.Services;
+
+/**
+ * Query manipulation class.
+ */
+public class QueryUtils {
+
+    private QueryUtils() {
+        // no instance, just static access
+    }
+
+    /**
+     * This method modifies the prepared statement for {@link Queries}.
+     *
+     * @param stmt the prepared statement
+     * @param servicePath the service path
+     * @throws SQLException a SQL exception
+     */
+    public static void setCreateServiceParameters(PreparedStatement stmt, Services servicePath) throws SQLException {
+        StatementBuilder builder = StatementBuilder.builder(stmt);
+        builder.setParameter(servicePath.getServiceName());
+        builder.setParameter(servicePath.getCommonId());
+
+        String requestId = "";
+        String rpcAction = "";
+        String notificationUrl = "";
+        String requestSystemId = "";
+
+        if (servicePath.getSdncRequestHeader() != null) {
+            requestId = getStringOf(servicePath.getSdncRequestHeader().getRequestId());
+            rpcAction = servicePath.getSdncRequestHeader().getRpcAction().getName();
+            notificationUrl = servicePath.getSdncRequestHeader().getNotificationUrl();
+            requestSystemId = servicePath.getSdncRequestHeader().getRequestSystemId();
+        }
+        builder.setParameter(requestId).setParameter(rpcAction).setParameter(notificationUrl)
+                .setParameter(requestSystemId);
+
+        String connectionType = "";
+        String lifecycleState = "";
+        String administrativeState = "";
+        String condition = "";
+        if (servicePath.getConnectionType() != null) {
+            connectionType = servicePath.getConnectionType().getName();
+        }
+        if (servicePath.getLifecycleState() != null) {
+            lifecycleState = servicePath.getLifecycleState().getName();
+        }
+        if (servicePath.getAdministrativeState() != null) {
+            administrativeState = servicePath.getAdministrativeState().getName();
+        }
+        if (servicePath.getCondition() != null) {
+            condition = servicePath.getCondition().getName();
+        }
+        // status stuff
+        builder.setParameter(connectionType);
+        builder.setParameter(lifecycleState);
+        builder.setParameter(administrativeState);
+        builder.setParameter(condition);
+
+        // status stuff
+        ServiceAEnd serviceAEnd = servicePath.getServiceAEnd();
+        builder.setParameter(serviceAEnd.getServiceFormat().getName()).setParameter(serviceAEnd.getServiceRate())
+                .setParameter(serviceAEnd.getClli()).setParameter(serviceAEnd.getNodeId());
+
+        // tx port stuff
+        Port aendTxDirection = servicePath.getServiceAEnd().getTxDirection().getPort();
+        builder.setParameter(aendTxDirection.getPortDeviceName()).setParameter(aendTxDirection.getPortName())
+                .setParameter(aendTxDirection.getPortRack()).setParameter(aendTxDirection.getPortShelf())
+                .setParameter(aendTxDirection.getPortSlot()).setParameter(aendTxDirection.getPortSubSlot());
+
+        // tx lgx stuff
+        TxDirection txDirectionA = servicePath.getServiceAEnd().getTxDirection();
+        builder.setParameter(txDirectionA.getLgx().getLgxDeviceName())
+                .setParameter(txDirectionA.getLgx().getLgxPortName())
+                .setParameter(txDirectionA.getLgx().getLgxPortRack())
+                .setParameter(txDirectionA.getLgx().getLgxPortShelf());
+        builder.setParameter(txDirectionA.getTail().getTailRoadm().getNodeId());
+        builder.setParameter(txDirectionA.getTail().getXponderPort().getCircuitPackName());
+        builder.setParameter(txDirectionA.getTail().getXponderPort().getPortName());
+        builder.setParameter(txDirectionA.getTail().getTailRoadmPortAid());
+        builder.setParameter(txDirectionA.getTail().getTailRoadmPortRackLocation());
+
+        // rx lgx stuff
+        RxDirection rxDirectionA = servicePath.getServiceAEnd().getRxDirection();
+        builder.setParameter(rxDirectionA.getLgx().getLgxDeviceName())
+                .setParameter(rxDirectionA.getLgx().getLgxPortName())
+                .setParameter(rxDirectionA.getLgx().getLgxPortRack())
+                .setParameter(rxDirectionA.getLgx().getLgxPortShelf());
+        builder.setParameter(rxDirectionA.getTail().getTailRoadm().getNodeId());
+        builder.setParameter(rxDirectionA.getTail().getXponderPort().getCircuitPackName());
+        builder.setParameter(rxDirectionA.getTail().getXponderPort().getPortName());
+        builder.setParameter(rxDirectionA.getTail().getTailRoadmPortAid());
+        builder.setParameter(rxDirectionA.getTail().getTailRoadmPortRackLocation());
+
+        builder.setParameter(servicePath.getServiceAEnd().getOpticType().getName());
+
+        Router routerA = servicePath.getServiceAEnd().getRouter();
+        builder.setParameter(routerA.getNodeId()).setParameter(routerA.getIpAddress().toString())
+                .setParameter(routerA.getUrl());
+        builder.setParameter(servicePath.getServiceAEnd().getUserLabel());
+
+        ServiceZEnd serviceZEnd = servicePath.getServiceZEnd();
+        builder.setParameter(serviceZEnd.getServiceFormat().getName()).setParameter(serviceZEnd.getServiceRate())
+                .setParameter(serviceZEnd.getClli()).setParameter(serviceZEnd.getNodeId());
+
+        // tx port stuff
+        Port zendTxDirection = serviceZEnd.getTxDirection().getPort();
+        builder.setParameter(zendTxDirection.getPortDeviceName()).setParameter(zendTxDirection.getPortName())
+                .setParameter(zendTxDirection.getPortRack()).setParameter(zendTxDirection.getPortShelf())
+                .setParameter(zendTxDirection.getPortSlot()).setParameter(zendTxDirection.getPortSubSlot());
+
+        // tx lgx stuff
+        TxDirection txDirectionZ = serviceZEnd.getTxDirection();
+        builder.setParameter(txDirectionZ.getLgx().getLgxDeviceName())
+                .setParameter(txDirectionZ.getLgx().getLgxPortName())
+                .setParameter(txDirectionZ.getLgx().getLgxPortRack())
+                .setParameter(txDirectionZ.getLgx().getLgxPortShelf());
+        builder.setParameter(txDirectionZ.getTail().getTailRoadm().getNodeId());
+        builder.setParameter(txDirectionZ.getTail().getXponderPort().getCircuitPackName());
+        builder.setParameter(txDirectionZ.getTail().getXponderPort().getPortName());
+        builder.setParameter(txDirectionZ.getTail().getTailRoadmPortAid());
+        builder.setParameter(txDirectionZ.getTail().getTailRoadmPortRackLocation());
+
+        // rx lgx stuff
+        RxDirection rxDirectionZ = servicePath.getServiceAEnd().getRxDirection();
+        builder.setParameter(rxDirectionZ.getLgx().getLgxDeviceName())
+                .setParameter(rxDirectionZ.getLgx().getLgxPortName())
+                .setParameter(rxDirectionZ.getLgx().getLgxPortRack())
+                .setParameter(rxDirectionZ.getLgx().getLgxPortShelf());
+        builder.setParameter(rxDirectionZ.getTail().getTailRoadm().getNodeId());
+        builder.setParameter(rxDirectionZ.getTail().getXponderPort().getCircuitPackName());
+        builder.setParameter(rxDirectionZ.getTail().getXponderPort().getPortName());
+        builder.setParameter(rxDirectionZ.getTail().getTailRoadmPortAid());
+        builder.setParameter(rxDirectionZ.getTail().getTailRoadmPortRackLocation());
+
+        builder.setParameter(servicePath.getServiceAEnd().getOpticType().getName());
+
+        Router routerZ = servicePath.getServiceZEnd().getRouter();
+        builder.setParameter(routerZ.getNodeId()).setParameter(routerZ.getIpAddress().toString())
+                .setParameter(routerZ.getUrl());
+        builder.setParameter(servicePath.getServiceZEnd().getUserLabel());
+
+        String customerCode = "";
+        if ((servicePath.getHardConstraints().getCustomerCode() == null)
+                || servicePath.getHardConstraints().getCustomerCode().isEmpty()) {
+            customerCode = servicePath.getHardConstraints().getCustomerCode().iterator().next();
+        }
+        builder.setParameter(customerCode);
+        builder.setParameter(servicePath.getDueDate().getValue());
+        builder.setParameter(servicePath.getEndDate().getValue());
+        builder.setParameter(servicePath.getNcCode());
+        builder.setParameter(servicePath.getNciCode());
+        builder.setParameter(servicePath.getSecondaryNciCode());
+        builder.setParameter(servicePath.getCustomer());
+        builder.setParameter(servicePath.getCustomerContact());
+        builder.setParameter(servicePath.getOperatorContact());
+        builder.setParameter(servicePath.getLatency());
+        String fiberSpanSrlgs = "";
+        if ((servicePath.getFiberSpanSrlgs() == null) || servicePath.getFiberSpanSrlgs().isEmpty()) {
+            fiberSpanSrlgs = servicePath.getFiberSpanSrlgs().iterator().next();
+        }
+        String supportingServiceName = "";
+        if ((servicePath.getSupportingServiceName() == null) || servicePath.getSupportingServiceName().isEmpty()) {
+            supportingServiceName = servicePath.getSupportingServiceName().iterator().next();
+        }
+        // TODO: hard constraints and soft constraints are missing
+        builder.setParameter(fiberSpanSrlgs);
+        builder.setParameter(supportingServiceName);
+        builder.setParameter(getCurrentTimestamp());
+        builder.setParameter(getCurrentTimestamp());
+    }
+
+    /**
+     * If the input value is null or empty string returns an empty string otherwise
+     * its value.
+     *
+     * @param value a value potentially NULL
+     * @return String the string value potentially empty if value is NULL
+     */
+    private static String getStringOf(String value) {
+        return Strings.isNullOrEmpty(value) ? "" : value;
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/query/StatementBuilder.java
new file mode 100644 (file)
index 0000000..1990bb9
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.query;
+
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+
+public class StatementBuilder {
+
+    private final PreparedStatement statement;
+    private int index;
+
+    private StatementBuilder(PreparedStatement statement) {
+        this.statement = statement;
+        this.index = 1;
+    }
+
+    public StatementBuilder setParameter(String value) throws SQLException {
+        this.statement.setString(this.index++, value);
+        return this;
+    }
+
+    public StatementBuilder setParameter(Long value) throws SQLException {
+        this.statement.setLong(this.index++, value);
+        return this;
+    }
+
+    public StatementBuilder setParameters(String... strings) throws SQLException {
+        for (int i = 0; i < strings.length; i++) {
+            statement.setString(i + 1, strings[i]);
+        }
+        return this;
+    }
+
+    public StatementBuilder reset() {
+        this.index = 1;
+        return this;
+    }
+
+    public static StatementBuilder builder(PreparedStatement statement) {
+        return new StatementBuilder(statement);
+    }
+}
diff --git a/inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java b/inventory/src/main/java/org/opendaylight/transportpce/inventory/utils/StringUtils.java
new file mode 100644 (file)
index 0000000..1ae6631
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2017 AT&T 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.inventory.utils;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+/**
+ * Utility class which handles strings in inventory project.
+ *
+ */
+public class StringUtils {
+    public static final String DEFAULT_SQL_DATE = "yyyy-MM-dd HH:mm:ss";
+
+    private StringUtils() {
+        // hiding the constructor
+    }
+
+    /**
+     * Returns the current timestamp formatted with
+     * {@link StringUtils#DEFAULT_SQL_DATE}.
+     *
+     * @see StringUtils#getTimestamp(Date)
+     * @return String the current timestamp formatted
+     */
+    public static String getCurrentTimestamp() {
+        return getTimestamp(new Date());
+    }
+
+    /**
+     * This method will format the provided {@link Date} with the
+     * {@link StringUtils#DEFAULT_SQL_DATE} format.
+     *
+     * @param date a date
+     * @return string represenation of the given date
+     */
+    public static String getTimestamp(Date date) {
+        SimpleDateFormat simpleDate = new SimpleDateFormat(DEFAULT_SQL_DATE);
+        return simpleDate.format(date);
+    }
+
+    /**
+     * Checks the input object for null and if it's null returns a dash instead.
+     *
+     * @param object an input object
+     * @return if object is null a dash is returned,
+     *         otherwise {@link Object#toString()}
+     */
+    public static String prepareDashString(Object object) {
+        return prepareString(object, "-");
+    }
+
+    /**
+     * Checks the input object for null and if's null returns an empty string instead.
+     *
+     * @param object an input object
+     * @return if object is null an empty string is returned,
+     *         otherwise {@link Object#toString()}
+     */
+    public static String prepareEmptyString(Object object) {
+        return prepareString(object, "");
+    }
+
+    /**
+     * Checks if the given object is null and returns its representation given by
+     * replacement.
+     *
+     * @param objectString a string object
+     * @param replacement a replacement
+     * @return String the representation of the object given by replacement
+     */
+    public static String prepareString(Object objectString, String replacement) {
+        return objectString == null ? replacement : objectString.toString();
+    }
+}
diff --git a/inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml b/inventory/src/main/resources/org/opendaylight/blueprint/inventory-blueprint.xml
new file mode 100644 (file)
index 0000000..072664d
--- /dev/null
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2016 Orange 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 -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+    odl:use-default-for-reference-types="true" xmlns:cm="http://aries.apache.org/blueprint/xmlns/blueprint-cm/v1.1.0">
+
+    <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"
+        odl:type="default" />
+    <reference id="schemaServiceImpl" interface="org.opendaylight.mdsal.dom.api.DOMSchemaService" />
+    <reference id="dataSource" interface="javax.sql.DataSource" />
+    <reference id="deviceTransactionManager" interface="org.opendaylight.transportpce.common.device.DeviceTransactionManager" />
+
+    <cm:property-placeholder persistent-id="org.opendaylight.transportpce.job" />
+
+    <bean id="deviceInventory" class="org.opendaylight.transportpce.inventory.DeviceInventory">
+        <argument ref="dataSource" />
+        <argument ref="iNodeImpl" />
+        <argument ref="deviceTransactionManager" />
+    </bean>
+    
+    <bean id="periodicDeviceBackupJob" class="org.opendaylight.transportpce.inventory.job.PeriodicDeviceBackupJob">
+        <argument ref="dataBroker"/>
+        <argument ref="schemaServiceImpl" />
+        <argument ref="deviceTransactionManager" />
+        <property name="folder" value="${deviceBackupFolder}" />
+        <property name="filePrefix" value="${deviceBackupPrefix}" />
+    </bean>
+
+    <bean id="iNodeImpl" class="org.opendaylight.transportpce.inventory.INode">
+        <argument ref="dataSource" />
+        <argument ref="deviceTransactionManager" />
+    </bean>
+    
+    <bean id="overlayNetworkChangeListener" class="org.opendaylight.transportpce.inventory.listener.OverlayNetworkChangeListener" />
+    <bean id="underlayNetworkChangeListener" class="org.opendaylight.transportpce.inventory.listener.UnderlayNetworkChangeListener" />
+    <bean id="clliNetworkChangeListener" class="org.opendaylight.transportpce.inventory.listener.ClliNetworkChangeListener" />
+    <bean id="serviceListener" class="org.opendaylight.transportpce.inventory.listener.ServiceListener">
+        <argument ref="dataSource" />
+    </bean>
+    <bean id="deviceListener" class="org.opendaylight.transportpce.inventory.listener.DeviceListener">
+        <argument ref="deviceInventory" />
+    </bean>
+
+    <bean id="listenerProvider" class="org.opendaylight.transportpce.inventory.ListenerProvider" init-method="initialize">
+        <argument ref="dataBroker" />
+        <argument ref="overlayNetworkChangeListener" />
+        <argument ref="underlayNetworkChangeListener" />
+        <argument ref="clliNetworkChangeListener" />
+        <argument ref="serviceListener" />
+        <argument ref="deviceListener" />
+    </bean>
+    
+    <service ref="periodicDeviceBackupJob" interface="java.lang.Runnable">
+        <service-properties>
+            <entry key="scheduler.period">
+                <value type="java.lang.Long">${deviceBackupPeriod}</value>
+            </entry>
+            <entry key="scheduler.name">
+                <value type="java.lang.String">org-openroadmdevice-backup-job</value>
+            </entry>
+        </service-properties>
+    </service>
+</blueprint>
diff --git a/networkmodel/pom.xml b/networkmodel/pom.xml
new file mode 100644 (file)
index 0000000..e7805e3
--- /dev/null
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+Copyright © 2016 Orange 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
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>config-parent</artifactId>
+    <version>0.8.3-SNAPSHOT</version>
+    <relativePath/>
+  </parent>
+
+  <groupId>org.opendaylight.transportpce</groupId>
+  <artifactId>transportpce-networkmodel</artifactId>
+  <version>0.2.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.opendaylight.netconf</groupId>
+        <artifactId>netconf-artifacts</artifactId>
+        <version>1.4.3-SNAPSHOT</version>
+        <scope>import</scope>
+        <type>pom</type>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
+
+  <dependencies>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>transportpce-api</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>transportpce-common</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}.ordmodels</groupId>
+      <artifactId>transportpce-ordmodels-network</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>${project.groupId}</groupId>
+      <artifactId>transportpce-renderer</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.netconf</groupId>
+      <artifactId>sal-netconf-connector</artifactId>
+    </dependency>
+
+    <!-- Testing Dependencies -->
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
+</project>
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetConfTopologyListener.java
new file mode 100644 (file)
index 0000000..0fc982e
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * Copyright © 2016 Orange 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.networkmodel;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+import javax.annotation.Nonnull;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
+import org.opendaylight.controller.md.sal.binding.api.MountPoint;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
+import org.opendaylight.transportpce.common.StringConstants;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.networkmodel.dto.NodeRegistration;
+import org.opendaylight.transportpce.networkmodel.listeners.AlarmNotificationListener;
+import org.opendaylight.transportpce.networkmodel.listeners.DeOperationsListener;
+import org.opendaylight.transportpce.networkmodel.listeners.DeviceListener;
+import org.opendaylight.transportpce.networkmodel.listeners.LldpListener;
+import org.opendaylight.transportpce.networkmodel.listeners.TcaListener;
+import org.opendaylight.transportpce.networkmodel.service.NetworkModelService;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.Netconf;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf.Streams;
+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;
+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.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetConfTopologyListener implements DataTreeChangeListener<Node> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetConfTopologyListener.class);
+
+    private final NetworkModelService networkModelService;
+    private final R2RLinkDiscovery linkDiscovery;
+    private final DataBroker dataBroker;
+    private final DeviceTransactionManager deviceTransactionManager;
+    private final Map<String, NodeRegistration> registrations;
+
+    public NetConfTopologyListener(final NetworkModelService networkModelService, final DataBroker dataBroker,
+            final R2RLinkDiscovery linkDiscovery, DeviceTransactionManager deviceTransactionManager) {
+        this.networkModelService = networkModelService;
+        this.linkDiscovery = linkDiscovery;
+        this.dataBroker = dataBroker;
+        this.deviceTransactionManager = deviceTransactionManager;
+        this.registrations = new ConcurrentHashMap<>();
+    }
+
+    private void onDeviceConnected(final String nodeId) {
+        LOG.info("onDeviceConnected: {}", nodeId);
+        Optional<MountPoint> mountPointOpt = this.deviceTransactionManager.getDeviceMountPoint(nodeId);
+        MountPoint mountPoint;
+        if (mountPointOpt.isPresent()) {
+            mountPoint = mountPointOpt.get();
+        } else {
+            LOG.error("Failed to get mount point for node {}", nodeId);
+            return;
+        }
+
+        final Optional<NotificationService> notificationService =
+                mountPoint.getService(NotificationService.class).toJavaUtil();
+        if (!notificationService.isPresent()) {
+            LOG.error("Failed to get RpcService for node {}", nodeId);
+            return;
+        }
+
+        final OrgOpenroadmAlarmListener alarmListener = new AlarmNotificationListener(this.dataBroker);
+        LOG.info("Registering notification listener on OrgOpenroadmAlarmListener for node: {}", nodeId);
+        final ListenerRegistration<OrgOpenroadmAlarmListener> accessAlarmNotificationListenerRegistration =
+                notificationService.get().registerNotificationListener(alarmListener);
+
+        final OrgOpenroadmDeOperationsListener deOperationsListener = new DeOperationsListener();
+        LOG.info("Registering notification listener on OrgOpenroadmDeOperationsListener for node: {}", nodeId);
+        final ListenerRegistration<OrgOpenroadmDeOperationsListener>
+            accessDeOperationasNotificationListenerRegistration =
+                notificationService.get().registerNotificationListener(deOperationsListener);
+
+        final OrgOpenroadmDeviceListener deviceListener = new DeviceListener();
+        LOG.info("Registering notification listener on OrgOpenroadmDeviceListener for node: {}", nodeId);
+        final ListenerRegistration<OrgOpenroadmDeviceListener> accessDeviceNotificationListenerRegistration =
+                notificationService.get().registerNotificationListener(deviceListener);
+
+        final OrgOpenroadmLldpListener lldpListener = new LldpListener(this.linkDiscovery, nodeId);
+        LOG.info("Registering notification listener on OrgOpenroadmLldpListener for node: {}", nodeId);
+        final ListenerRegistration<OrgOpenroadmLldpListener> accessLldpNotificationListenerRegistration =
+                notificationService.get().registerNotificationListener(lldpListener);
+
+        final OrgOpenroadmTcaListener tcaListener = new TcaListener();
+        LOG.info("Registering notification listener on OrgOpenroadmTcaListener for node: {}", nodeId);
+        final ListenerRegistration<OrgOpenroadmTcaListener> accessTcaNotificationListenerRegistration =
+                notificationService.get().registerNotificationListener(tcaListener);
+
+
+
+        String streamName = getSupportedStream(nodeId);
+        if (streamName == null) {
+            streamName = "OPENROADM";
+        }
+        final Optional<RpcConsumerRegistry> service = mountPoint.getService(RpcConsumerRegistry.class).toJavaUtil();
+        if (service.isPresent()) {
+            final NotificationsService rpcService = service.get().getRpcService(NotificationsService.class);
+            if (rpcService == null) {
+                LOG.error("Failed to get RpcService for node {}", nodeId);
+            } else {
+                final CreateSubscriptionInputBuilder createSubscriptionInputBuilder =
+                    new CreateSubscriptionInputBuilder();
+                createSubscriptionInputBuilder.setStream(new StreamNameType(streamName));
+                LOG.info("Triggering notification stream {} for node {}", streamName, nodeId);
+                rpcService.createSubscription(createSubscriptionInputBuilder.build());
+            }
+        } else {
+            LOG.error("Failed to get RpcService for node {}", nodeId);
+        }
+        NodeRegistration nodeRegistration = new NodeRegistration(nodeId, accessAlarmNotificationListenerRegistration,
+                accessDeOperationasNotificationListenerRegistration, accessDeviceNotificationListenerRegistration,
+                accessLldpNotificationListenerRegistration, accessTcaNotificationListenerRegistration);
+        this.registrations.put(nodeId, nodeRegistration);
+    }
+
+    private void onDeviceDisConnected(final String nodeId) {
+        LOG.info("onDeviceDisConnected: {}", nodeId);
+        NodeRegistration nodeRegistration = this.registrations.remove(nodeId);
+        if (nodeRegistration != null) {
+            nodeRegistration.getAccessAlarmNotificationListenerRegistration().close();
+            nodeRegistration.getAccessDeOperationasNotificationListenerRegistration().close();
+            nodeRegistration.getAccessDeviceNotificationListenerRegistration().close();
+            nodeRegistration.getAccessLldpNotificationListenerRegistration().close();
+            nodeRegistration.getAccessTcaNotificationListenerRegistration().close();
+        }
+    }
+
+    @Override
+    public void onDataTreeChanged(@Nonnull Collection<DataTreeModification<Node>> changes) {
+        LOG.info("onDataTreeChanged");
+        for (DataTreeModification<Node> change : changes) {
+            DataObjectModification<Node> rootNode = change.getRootNode();
+            if (rootNode.getDataAfter() == null) {
+                continue;
+            }
+            String nodeId = rootNode.getDataAfter().getKey().getNodeId().getValue();
+            NetconfNode netconfNode = rootNode.getDataAfter().getAugmentation(NetconfNode.class);
+            if ((netconfNode != null) && !StringConstants.DEFAULT_NETCONF_NODEID.equals(nodeId)) {
+                switch (rootNode.getModificationType()) {
+                    case WRITE:
+                        LOG.info("Node added: {}", nodeId);
+                        break;
+                    case SUBTREE_MODIFIED:
+                        NetconfNodeConnectionStatus.ConnectionStatus connectionStatus =
+                                netconfNode.getConnectionStatus();
+                        long count = netconfNode.getAvailableCapabilities().getAvailableCapability().stream()
+                                .filter(cp -> cp.getCapability().contains(StringConstants.OPENROADM_DEVICE_MODEL_NAME))
+                                .count();
+                        if (count > 0) {
+                            LOG.info("OpenROADM node detected: {} {}", nodeId, connectionStatus.name());
+                            switch (connectionStatus) {
+                                case Connected:
+                                    this.networkModelService.createOpenROADMnode(nodeId);
+                                    onDeviceConnected(nodeId);
+                                    break;
+                                case Connecting:
+                                case UnableToConnect:
+                                    this.networkModelService.setOpenROADMnodeStatus(nodeId, connectionStatus);
+                                    onDeviceDisConnected(nodeId);
+                                    break;
+                                default:
+                                    LOG.warn("Unsupported device state {}", connectionStatus.getName());
+                                    break;
+                            }
+                        }
+                        break;
+                    case DELETE:
+                        LOG.info("Node deleted: {}", nodeId);
+                        break;
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+
+    private String getSupportedStream(String nodeId) {
+        InstanceIdentifier<Streams> streamsIID = InstanceIdentifier.create(Netconf.class).child(Streams.class);
+        try {
+            Optional<Streams> ordmInfoObject =
+                    this.deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL,
+                            streamsIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+            if (!ordmInfoObject.isPresent()) {
+                LOG.error("Info subtree is not present");
+                return null;
+            }
+            for (org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netmod.notification.rev080714.netconf
+                        .streams.Stream strm : ordmInfoObject.get().getStream()) {
+
+                if ("OPENROADM".equalsIgnoreCase(strm.getName().getValue())) {
+                    return strm.getName().getValue().toUpperCase();
+                }
+            }
+            return "NETCONF";
+        } catch (NullPointerException ex) {
+            LOG.error("NullPointerException thrown while getting Info from a non Open ROADM device {}", nodeId);
+            return null;
+        }
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkModelProvider.java
new file mode 100644 (file)
index 0000000..e485367
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2016 Orange 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.networkmodel;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
+import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
+import org.opendaylight.transportpce.common.InstanceIdentifiers;
+import org.opendaylight.transportpce.networkmodel.util.ClliNetwork;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.NetworkutilsService;
+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.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetworkModelProvider {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetworkModelProvider.class);
+
+    private final DataBroker dataBroker;
+    private final RpcProviderRegistry rpcProviderRegistry;
+    private final NetworkutilsService networkutilsService;
+    private final NetConfTopologyListener topologyListener;
+    private final OpenRoadmTopology openRoadmTopology;
+    private ListenerRegistration<NetConfTopologyListener> dataTreeChangeListenerRegistration;
+    private BindingAwareBroker.RpcRegistration<NetworkutilsService> networkutilsServiceRpcRegistration;
+
+    public NetworkModelProvider(final DataBroker dataBroker, final RpcProviderRegistry rpcProviderRegistry,
+            final NetworkutilsService networkutilsService, final NetConfTopologyListener topologyListener,
+            OpenRoadmTopology openRoadmTopology) {
+        this.dataBroker = dataBroker;
+        this.rpcProviderRegistry = rpcProviderRegistry;
+        this.networkutilsService = networkutilsService;
+        this.topologyListener = topologyListener;
+        this.openRoadmTopology = openRoadmTopology;
+    }
+
+    /**
+     * Method called when the blueprint container is created.
+     */
+    public void init() {
+        LOG.info("NetworkModelProvider Session Initiated");
+        ClliNetwork.createClliLayer(dataBroker);
+        OpenRoadmNetwork.createOpenRoadmNetworkLayer(dataBroker);
+        openRoadmTopology.createTopoLayer(dataBroker);
+        dataTreeChangeListenerRegistration =
+                dataBroker.registerDataTreeChangeListener(new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL,
+                        InstanceIdentifiers.NETCONF_TOPOLOGY_II.child(Node.class)), topologyListener);
+        networkutilsServiceRpcRegistration =
+                rpcProviderRegistry.addRpcImplementation(NetworkutilsService.class, networkutilsService);
+    }
+
+    /**
+     * Method called when the blueprint container is destroyed.
+     */
+    public void close() {
+        LOG.info("NetworkModelProvider Closed");
+        if (dataTreeChangeListenerRegistration != null) {
+            dataTreeChangeListenerRegistration.close();
+        }
+        if (networkutilsServiceRpcRegistration != null) {
+            networkutilsServiceRpcRegistration.close();
+        }
+    }
+
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/NetworkUtilsImpl.java
new file mode 100644 (file)
index 0000000..e42520f
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2017 AT&T 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.networkmodel;
+
+import java.util.concurrent.Future;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRdmXpdrLinksOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksInput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksOutput;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitXpdrRdmLinksOutputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.NetworkutilsService;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetworkUtilsImpl implements NetworkutilsService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetworkUtilsImpl.class);
+    private final DataBroker dataBroker;
+    private final OpenRoadmTopology openRoadmTopology;
+
+    public NetworkUtilsImpl(DataBroker dataBroker, OpenRoadmTopology openRoadmTopology) {
+        this.dataBroker = dataBroker;
+        this.openRoadmTopology = openRoadmTopology;
+    }
+
+    public Future<RpcResult<InitRoadmNodesOutput>> initRoadmNodes(InitRoadmNodesInput input) {
+        boolean createRdmLinks = OrdLink.createRdm2RdmLinks(input,
+                openRoadmTopology,dataBroker);
+        if (createRdmLinks) {
+            return RpcResultBuilder
+                    .success(new InitRoadmNodesOutputBuilder().setResult(
+                            "Unidirectional Roadm-to-Roadm Link created successfully"))
+                    .buildFuture();
+        } else {
+            return RpcResultBuilder.<InitRoadmNodesOutput>failed().buildFuture();
+        }
+    }
+
+    @Override
+    public Future<RpcResult<InitXpdrRdmLinksOutput>> initXpdrRdmLinks(InitXpdrRdmLinksInput input) {
+        // Assigns user provided input in init-network-view RPC to nodeId
+        boolean createXpdrRdmLinks = Rdm2XpdrLink.createXpdrRdmLinks(input.getLinksInput(),
+                openRoadmTopology,dataBroker);
+        if (createXpdrRdmLinks) {
+            return RpcResultBuilder
+                    .success(new InitXpdrRdmLinksOutputBuilder().setResult("Xponder Roadm Link created successfully"))
+                    .buildFuture();
+        } else {
+            return RpcResultBuilder.<InitXpdrRdmLinksOutput>failed().buildFuture();
+        }
+    }
+
+    public Future<RpcResult<InitRdmXpdrLinksOutput>> initRdmXpdrLinks(InitRdmXpdrLinksInput input) {
+        boolean createRdmXpdrLinks = Rdm2XpdrLink.createRdmXpdrLinks(input.getLinksInput(),
+                openRoadmTopology,dataBroker);
+        if (createRdmXpdrLinks) {
+            return RpcResultBuilder
+                    .success(new InitRdmXpdrLinksOutputBuilder().setResult("Roadm Xponder links created successfully"))
+                    .buildFuture();
+        } else {
+            return RpcResultBuilder.<InitRdmXpdrLinksOutput>failed().buildFuture();
+        }
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/OrdLink.java
new file mode 100644 (file)
index 0000000..1915c5e
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.networkmodel.util.LinkIdUtil;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.link.OMSAttributesBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class OrdLink {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OrdLink.class);
+
+    /**Method to create OMS links if not discovered by LLDP. This is helpful
+    to create test topologies using simulators**/
+    public static boolean createRdm2RdmLinks(InitRoadmNodesInput input,
+        OpenRoadmTopology openRoadmTopology, DataBroker dataBroker) {
+
+        LinkId oppositeLinkId = LinkIdUtil.getRdm2RdmOppositeLinkId(input);
+
+        //For setting up attributes for openRoadm augment
+        Link1Builder link1Builder = new Link1Builder();
+        link1Builder.setLinkType(OpenroadmLinkType.ROADMTOROADM);
+        OMSAttributesBuilder omsAttributesBuilder = new OMSAttributesBuilder();
+        omsAttributesBuilder.setOppositeLink(oppositeLinkId);
+        link1Builder.setOMSAttributes(omsAttributesBuilder.build());
+
+        //For opposite link augment
+        org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder oppsiteLinkBuilder =
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder();
+        oppsiteLinkBuilder.setOppositeLink(oppositeLinkId);
+
+        String srcNode = new StringBuilder(input.getRdmANode()).append("-DEG").append(input.getDegANum()).toString();
+        String srcTp = input.getTerminationPointA();
+        String destNode = new StringBuilder(input.getRdmZNode()).append("-DEG").append(input.getDegZNum()).toString();
+        String destTp = input.getTerminationPointZ();
+
+        //IETF link builder
+        LinkBuilder linkBuilder = openRoadmTopology.createLink(srcNode, destNode, srcTp, destTp);
+
+        linkBuilder.addAugmentation(Link1.class,link1Builder.build());
+        linkBuilder.addAugmentation(org.opendaylight.yang.gen.v1.http
+                .org.openroadm.opposite.links.rev170929.Link1.class,oppsiteLinkBuilder.build());
+        LinkId linkId = LinkIdUtil.buildLinkId(srcNode, srcTp, destNode, destTp);
+
+        // Building link instance identifier
+        InstanceIdentifier.InstanceIdentifierBuilder<Link> linkIID =
+            InstanceIdentifier.builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+            .augmentation(Network1.class).child(Link.class, new LinkKey(linkId));
+
+        WriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
+        writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, linkIID.build(), linkBuilder.build());
+        try {
+            writeTransaction.submit().get();
+            LOG.info("A new link with linkId: {} added into {} layer.",
+                    linkId.getValue(), NetworkUtils.OVERLAY_NETWORK_ID);
+            return true;
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("Failed to create Roadm 2 Roadm Link for topo layer ");
+            return false;
+        }
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/R2RLinkDiscovery.java
new file mode 100644 (file)
index 0000000..5bc3865
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel;
+
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.MountPoint;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaceException;
+import org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev170929.Direction;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.interfaces.grp.Interface;
+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.Degree;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.DegreeKey;
+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.rev150608.NodeId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInputBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.Network;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.NodesKey;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegree;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.portmapping.rev170228.network.nodes.CpToDegreeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class R2RLinkDiscovery {
+
+    private static final Logger LOG = LoggerFactory.getLogger(R2RLinkDiscovery.class);
+
+    private final DataBroker dataBroker;
+    private final DeviceTransactionManager deviceTransactionManager;
+    private final OpenRoadmTopology openRoadmTopology;
+    private final OpenRoadmInterfaces openRoadmInterfaces;
+
+    public R2RLinkDiscovery(final DataBroker dataBroker,
+            DeviceTransactionManager deviceTransactionManager, OpenRoadmTopology openRoadmTopology,
+            OpenRoadmInterfaces openRoadmInterfaces) {
+        this.dataBroker = dataBroker;
+        this.deviceTransactionManager = deviceTransactionManager;
+        this.openRoadmTopology = openRoadmTopology;
+        this.openRoadmInterfaces = openRoadmInterfaces;
+    }
+
+    public boolean readLLDP(NodeId nodeId) {
+        InstanceIdentifier<Protocols> protocolsIID =
+                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().getAugmentation(Protocols1.class) == null)) {
+            LOG.warn("LLDP subtree is missing : isolated openroadm device");
+            return false;
+        }
+        NbrList nbrList = protocolObject.get().getAugmentation(Protocols1.class).getLldp().getNbrList();
+        LOG.info("LLDP subtree is present. Device has {} neighbours", nbrList.getIfName().size());
+        for (IfName ifName : nbrList.getIfName()) {
+            if (ifName.getRemoteSysName() == null) {
+                LOG.error("LLDP subtree is empty in the device for nodeId: {}",
+                        nodeId.getValue());
+                return false;
+            }
+            Optional<MountPoint> mps = this.deviceTransactionManager.getDeviceMountPoint(ifName.getRemoteSysName());
+            if (!mps.isPresent()) {
+                LOG.warn("Neighbouring nodeId: {} is not mounted yet", ifName.getRemoteSysName());
+                return false;
+            } else {
+                if (!createR2RLink(nodeId, ifName.getIfName(), ifName.getRemoteSysName(),
+                        ifName.getRemotePortId())) {
+                    LOG.warn("Link Creation failed between {} and {} nodes.", nodeId, ifName.getRemoteSysName());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    public Direction getDegreeDirection(Integer degreeCounter, NodeId nodeId) {
+        InstanceIdentifier<Degree> deviceIID =
+                InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Degree.class, new DegreeKey(degreeCounter));
+        Optional<Degree> degreeObject =
+                this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL,
+                    deviceIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (degreeObject.isPresent()) {
+            Integer connectionPortCount = degreeObject.get().getConnectionPorts().size();
+            if (connectionPortCount == 1) {
+                return Direction.Bidirectional;
+            } else if (connectionPortCount > 1) {
+                return Direction.Tx;
+            } else {
+                return Direction.NotApplicable;
+            }
+        }  else {
+            LOG.error("Couldnt retrieve Degree object for nodeId: {} and DegreeNumbner: {}",
+                    nodeId.getValue(),degreeCounter);
+            return Direction.NotApplicable;
+        }
+    }
+
+    public boolean createR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
+                                 String remoteInterfaceName) {
+        String srcTpTx = null;
+        String srcTpRx = null;
+        String destTpTx = null;
+        String destTpRx = null;
+        //Find which degree is associated with ethernet interface
+        //portmapping.getDegFromCP(nodeId,interfaceName);
+        Integer srcDegId = getDegFromCP(nodeId, interfaceName);
+        if (srcDegId == null) {
+            LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return false;
+        }
+        // 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("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
+            return false;
+        } 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";
+        }
+        // Find degree for which Ethernet interface is created on other end
+        NodeId destNodeId = new NodeId(remoteSystemName);
+        Integer destDegId = getDegFromCP(destNodeId, remoteInterfaceName);
+        //portmapping.getDegFromCP(nodeId,interfaceName);
+        if (destDegId == null) {
+            LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return false;
+        }
+        // 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("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
+            return false;
+        } 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";
+        }
+        //A->Z
+        LOG.debug(
+            "Found a neighbor SrcNodeId: {} , SrcDegId: {} , SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
+            nodeId.getValue(), srcDegId, srcTpTx, destNodeId, destDegId, destTpRx);
+        InitRoadmNodesInputBuilder r2rlinkBuilderAToZ = new InitRoadmNodesInputBuilder();
+        r2rlinkBuilderAToZ.setRdmANode(nodeId.getValue())
+                .setDegANum(srcDegId.shortValue()).setTerminationPointA(srcTpTx)
+                .setRdmZNode(destNodeId.getValue())
+                .setDegZNum(destDegId.shortValue()).setTerminationPointZ(destTpRx);
+        if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderAToZ.build(),openRoadmTopology,
+                dataBroker)) {
+            LOG.error("OMS Link creation failed between node: {} and nodeId: {} in A->Z direction",
+                    nodeId.getValue(),destNodeId.getValue());
+            return false;
+        }
+        //Z->A
+        LOG.debug(
+                "Found a neighbor SrcNodeId: {} , SrcDegId: {}"
+                        + ", SrcTPId: {}, DestNodeId:{} , DestDegId: {}, DestTPId: {}",
+                destNodeId, destDegId, destTpTx, nodeId.getValue(), srcDegId, srcTpRx);
+
+        InitRoadmNodesInputBuilder r2rlinkBuilderZToA = new InitRoadmNodesInputBuilder();
+        r2rlinkBuilderZToA.setRdmANode(destNodeId.getValue())
+                .setDegANum(destDegId.shortValue()).setTerminationPointA(destTpTx)
+                .setRdmZNode(nodeId.getValue())
+                .setDegZNum(srcDegId.shortValue()).setTerminationPointZ(srcTpRx);
+        if (!OrdLink.createRdm2RdmLinks(r2rlinkBuilderZToA.build(),openRoadmTopology,
+                dataBroker)) {
+            LOG.error("OMS Link creation failed between node: {} and nodeId: {} in Z->A direction",
+                    destNodeId.getValue(),nodeId.getValue());
+            return false;
+        }
+        return true;
+    }
+
+    public boolean deleteR2RLink(NodeId nodeId, String interfaceName, String remoteSystemName,
+            String remoteInterfaceName) {
+        String srcTpTx = null;
+        String srcTpRx = null;
+        String destTpTx = null;
+        String destTpRx = null;
+        //Find which degree is associated with ethernet interface
+        //portmapping.getDegFromCP(nodeId,interfaceName);
+        Integer srcDegId = getDegFromCP(nodeId, interfaceName);
+        if (srcDegId == null) {
+            LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return false;
+        }
+        // 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("Couldnt find degree direction for nodeId: {} and degree: {}", nodeId, srcDegId);
+            return false;
+        } 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";
+        }
+        // Find degree for which Ethernet interface is created on other end
+        NodeId destNodeId = new NodeId(remoteSystemName);
+        //portmapping.getDegFromCP(nodeId,interfaceName);
+        Integer destDegId = getDegFromCP(destNodeId, remoteInterfaceName);
+        if (destDegId == null) {
+            LOG.error("Couldnt find degree connected to Ethernet interface for nodeId: {}", nodeId);
+            return false;
+        }
+        // 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("Couldnt find degree direction for nodeId: {} and degree: {}", destNodeId, destDegId);
+            return false;
+        } 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";
+        }
+        return this.openRoadmTopology.deleteLink(nodeId.getValue(), destNodeId.getValue(), srcTpTx, destTpRx)
+                    && this.openRoadmTopology.deleteLink(destNodeId.getValue(), nodeId.getValue(), destTpTx, srcTpRx);
+    }
+
+    private CpToDegree getCPtoDegreeMapping(NodeId nodeId, String circuitPackName) {
+        InstanceIdentifier<CpToDegree> cptoDegMappingIID =
+                InstanceIdentifier.builder(Network.class).child(Nodes.class,
+                        new NodesKey(nodeId.getValue()))
+                        .child(CpToDegree.class, new CpToDegreeKey(circuitPackName)).build();
+        LOG.debug("Input parameters are {},{}", nodeId.getValue(), circuitPackName);
+        try (ReadOnlyTransaction readTx = this.dataBroker.newReadOnlyTransaction()) {
+            Optional<CpToDegree> cptpDegObject =
+                    readTx.read(LogicalDatastoreType.CONFIGURATION, cptoDegMappingIID).get().toJavaUtil();
+            if (cptpDegObject.isPresent()) {
+                CpToDegree cpToDeg = cptpDegObject.get();
+                LOG.debug("Found mapping for the Circuit Pack {}. Degree: {}", circuitPackName, cpToDeg);
+                return cpToDeg;
+            } else {
+                LOG.warn("Could not find mapping for Circuit Pack {} for nodeId {}", circuitPackName,
+                        nodeId.getValue());
+            }
+        } catch (InterruptedException | ExecutionException ex) {
+            LOG.error("Unable to read mapping for circuit pack : {} for nodeId {}", circuitPackName, nodeId, ex);
+        }
+        return null;
+    }
+
+    private Integer getDegFromParentCP(NodeId nodeId, String interfaceName, String supportingCircuitPack) {
+        InstanceIdentifier<CircuitPacks> circuitPackIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
+                .child(CircuitPacks.class, new CircuitPacksKey(supportingCircuitPack));
+        Optional<CircuitPacks> circuitPackObject =
+                this.deviceTransactionManager.getDataFromDevice(nodeId.getValue(), LogicalDatastoreType.OPERATIONAL,
+                        circuitPackIID, Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (!circuitPackObject.isPresent()
+                || (circuitPackObject.get().getParentCircuitPack().getCircuitPackName() == null)) {
+            LOG.warn("Parent circuitpack not found for NodeId: {} and Interface: {}", nodeId, interfaceName);
+            return null;
+        }
+        String parentCP = circuitPackObject.get().getParentCircuitPack().getCircuitPackName();
+        CpToDegree cpToDegree = getCPtoDegreeMapping(nodeId, parentCP);
+        if (cpToDegree == null) {
+            LOG.error("CP to Degree mapping not found even with parent circuitpack for NodeID: {}" + "and Interface {}",
+                    nodeId, interfaceName);
+            return null;
+        } else {
+            LOG.debug("CP to degree is {}", cpToDegree.getDegreeNumber());
+            return cpToDegree.getDegreeNumber().intValue();
+        }
+    }
+
+    private Integer getDegFromCP(NodeId nodeId, String interfaceName) {
+        try {
+            java.util.Optional<Interface> interfaceOpt = this.openRoadmInterfaces.getInterface(nodeId.getValue(),
+                    interfaceName);
+            if (!interfaceOpt.isPresent()) {
+                LOG.warn("Interface with {} on node {} was not found!", interfaceName, nodeId.getValue());
+                return null;
+            }
+            String supportingCircuitPack = interfaceOpt.get().getSupportingCircuitPackName();
+            LOG.debug("Supporting circuitpack name is :{}",
+                    interfaceOpt.get().getSupportingCircuitPackName());
+            CpToDegree cpToDegree = getCPtoDegreeMapping(nodeId, supportingCircuitPack);
+            // Currently devices have different ways to represent connection to Ethernet port and degree port
+            // If Circuit pack is not present under degree tree then read parent CP of given CP(Circuit pack)
+            if (cpToDegree != null) {
+                return cpToDegree.getDegreeNumber().intValue();
+            } else {
+                return getDegFromParentCP(nodeId, interfaceName, supportingCircuitPack);
+            }
+        } catch (OpenRoadmInterfaceException ex) {
+            LOG.error("Failed to get source interface {} from node {}!", interfaceName, nodeId, ex);
+            return null;
+        }
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/Rdm2XpdrLink.java
new file mode 100644 (file)
index 0000000..b757a7b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.util.concurrent.CheckedFuture;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.links.input.grouping.LinksInput;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class Rdm2XpdrLink {
+
+    private static final Logger LOG = LoggerFactory.getLogger(Rdm2XpdrLink.class);
+
+    public static boolean createXpdrRdmLinks(LinksInput linksInput, OpenRoadmTopology openRoadmTopology,
+        DataBroker dataBroker) {
+        String srcNode =
+                new StringBuilder(linksInput.getXpdrNode()).append("-XPDR").append(linksInput.getXpdrNum()).toString();
+        String srcTp = new StringBuilder("XPDR").append(linksInput.getXpdrNum()).append("-NETWORK")
+                .append(linksInput.getNetworkNum()).toString();
+        String destNode =
+                new StringBuilder(linksInput.getRdmNode()).append("-SRG").append(linksInput.getSrgNum()).toString();
+        String destTp = linksInput.getTerminationPointNum();
+
+        Network topoNetowkLayer = createNetworkBuilder(srcNode, srcTp, destNode, destTp, false,
+                openRoadmTopology).build();
+        InstanceIdentifier.InstanceIdentifierBuilder<Network> nwIID = InstanceIdentifier.builder(Network.class,
+                new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)));
+        WriteTransaction wrtx = dataBroker.newWriteOnlyTransaction();
+        wrtx.merge(LogicalDatastoreType.CONFIGURATION, nwIID.build(), topoNetowkLayer);
+
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrtx.submit();
+
+        try {
+            submit.checkedGet();
+            LOG.info("Post successful");
+            return true;
+
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to create Xponder to Roadm link in the Topo layer ");
+            return false;
+
+        }
+    }
+
+    public static boolean createRdmXpdrLinks(LinksInput linksInput,
+                                             OpenRoadmTopology openRoadmTopology, DataBroker dataBroker) {
+        String srcNode =
+                new StringBuilder(linksInput.getRdmNode()).append("-SRG").append(linksInput.getSrgNum()).toString();
+        String srcTp = linksInput.getTerminationPointNum();
+        String destNode =
+                new StringBuilder(linksInput.getXpdrNode()).append("-XPDR").append(linksInput.getXpdrNum()).toString();
+        String destTp = new StringBuilder("XPDR").append(linksInput.getXpdrNum()).append("-NETWORK")
+                .append(linksInput.getNetworkNum()).toString();
+
+        Network topoNetowkLayer = createNetworkBuilder(srcNode, srcTp, destNode, destTp, true,
+                openRoadmTopology).build();
+        InstanceIdentifier.InstanceIdentifierBuilder<Network> nwIID = InstanceIdentifier.builder(Network.class,
+                new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)));
+        WriteTransaction wrtx = dataBroker.newWriteOnlyTransaction();
+        wrtx.merge(LogicalDatastoreType.CONFIGURATION, nwIID.build(), topoNetowkLayer);
+        CheckedFuture<Void, TransactionCommitFailedException> submit = wrtx.submit();
+        try {
+            submit.checkedGet();
+            LOG.info("Post successful");
+            return true;
+
+        } catch (TransactionCommitFailedException e) {
+            LOG.warn("Failed to create Xponder to Roadm link in the Topo layer ");
+            return false;
+        }
+    }
+
+    private static NetworkBuilder createNetworkBuilder(String srcNode, String srcTp, String destNode, String destTp,
+            boolean isXponderInput, OpenRoadmTopology openRoadmTopology) {
+        NetworkId nwId = new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID);
+        NetworkBuilder nwBuilder = new NetworkBuilder();
+        nwBuilder.setNetworkId(nwId);
+        nwBuilder.setKey(new NetworkKey(nwId));
+        Link1Builder lnk1bldr = new Link1Builder();
+        LinkBuilder linkBuilder = openRoadmTopology.createLink(srcNode, destNode, srcTp, destTp);
+        lnk1bldr.setLinkType(isXponderInput ? OpenroadmLinkType.XPONDERINPUT : OpenroadmLinkType.XPONDEROUTPUT);
+        linkBuilder.addAugmentation(Link1.class, lnk1bldr.build());
+        LOG.info("Link id in the linkbldr {}", linkBuilder.getLinkId());
+        LOG.info("Link with oppo link {}", linkBuilder.getAugmentation(Link1.class));
+        Network1Builder nwBldr1 = new Network1Builder();
+        nwBldr1.setLink(ImmutableList.of(linkBuilder.build()));
+        nwBuilder.addAugmentation(Network1.class, nwBldr1.build());
+        return nwBuilder;
+    }
+}
+
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeData.java
new file mode 100644 (file)
index 0000000..c5eae82
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.dto;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder;
+
+public class NodeData {
+
+    private final NodeBuilder nodeBuilder;
+    private final int portDirectionEnum;
+
+    public NodeData(NodeBuilder nodeBuilder, int portDirectionEnum) {
+        this.nodeBuilder = nodeBuilder;
+        this.portDirectionEnum = portDirectionEnum;
+    }
+
+    public NodeBuilder getNodeBuilder() {
+        return nodeBuilder;
+    }
+
+    public int getPortDirectionEnum() {
+        return portDirectionEnum;
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/NodeRegistration.java
new file mode 100644 (file)
index 0000000..e802091
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.dto;
+
+import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+public class NodeRegistration {
+
+    private final String nodeId;
+    private final ListenerRegistration<OrgOpenroadmAlarmListener> accessAlarmNotificationListenerRegistration;
+    private final ListenerRegistration<OrgOpenroadmDeOperationsListener>
+        accessDeOperationasNotificationListenerRegistration;
+    private final ListenerRegistration<OrgOpenroadmDeviceListener> accessDeviceNotificationListenerRegistration;
+    private final ListenerRegistration<OrgOpenroadmLldpListener> accessLldpNotificationListenerRegistration;
+    private final ListenerRegistration<OrgOpenroadmTcaListener> accessTcaNotificationListenerRegistration;
+
+    public NodeRegistration(String nodeId,
+            ListenerRegistration<OrgOpenroadmAlarmListener> accessAlarmNotificationListenerRegistration,
+            ListenerRegistration<OrgOpenroadmDeOperationsListener> accessDeOperationasNotificationListenerRegistration,
+            ListenerRegistration<OrgOpenroadmDeviceListener> accessDeviceNotificationListenerRegistration,
+            ListenerRegistration<OrgOpenroadmLldpListener> accessLldpNotificationListenerRegistration,
+            ListenerRegistration<OrgOpenroadmTcaListener> accessTcaNotificationListenerRegistration) {
+        this.nodeId = nodeId;
+        this.accessAlarmNotificationListenerRegistration = accessAlarmNotificationListenerRegistration;
+        this.accessDeOperationasNotificationListenerRegistration = accessDeOperationasNotificationListenerRegistration;
+        this.accessDeviceNotificationListenerRegistration = accessDeviceNotificationListenerRegistration;
+        this.accessLldpNotificationListenerRegistration = accessLldpNotificationListenerRegistration;
+        this.accessTcaNotificationListenerRegistration = accessTcaNotificationListenerRegistration;
+    }
+
+    public String getNodeId() {
+        return nodeId;
+    }
+
+    public ListenerRegistration<OrgOpenroadmAlarmListener> getAccessAlarmNotificationListenerRegistration() {
+        return accessAlarmNotificationListenerRegistration;
+    }
+
+    public ListenerRegistration<OrgOpenroadmDeOperationsListener>
+        getAccessDeOperationasNotificationListenerRegistration() {
+        return accessDeOperationasNotificationListenerRegistration;
+    }
+
+    public ListenerRegistration<OrgOpenroadmDeviceListener> getAccessDeviceNotificationListenerRegistration() {
+        return accessDeviceNotificationListenerRegistration;
+    }
+
+    public ListenerRegistration<OrgOpenroadmLldpListener> getAccessLldpNotificationListenerRegistration() {
+        return accessLldpNotificationListenerRegistration;
+    }
+
+    public ListenerRegistration<OrgOpenroadmTcaListener> getAccessTcaNotificationListenerRegistration() {
+        return accessTcaNotificationListenerRegistration;
+    }
+
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/dto/TopologyShard.java
new file mode 100644 (file)
index 0000000..d750893
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.dto;
+
+import java.util.List;
+
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link;
+
+/**
+ * Data holder for topology fragment.
+ */
+public class TopologyShard {
+
+    private final List<Node> nodes;
+    private final List<Link> links;
+
+    public TopologyShard(List<Node> nodes, List<Link> links) {
+        this.nodes = nodes;
+        this.links = links;
+    }
+
+    public List<Node> getNodes() {
+        return nodes;
+    }
+
+    public List<Link> getLinks() {
+        return links;
+    }
+
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/AlarmNotificationListener.java
new file mode 100644 (file)
index 0000000..80e89c8
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ * Copyright © 2017 AT&T 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.networkmodel.listeners;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.alarm.ProbableCause;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.ResourceType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.Resource;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.CircuitPack;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Connection;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Degree;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Interface;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.InternalLink;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.PhysicalLink;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Port;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Service;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Shelf;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.rev161014.resource.resource.resource.Srg;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.ServiceNodelist;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.Nodelist;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.nodelist.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.alarmsuppression.rev171102.service.nodelist.nodelist.NodesBuilder;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AlarmNotificationListener implements OrgOpenroadmAlarmListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AlarmNotificationListener.class);
+    private static final String PIPE = "|";
+    private final DataBroker dataBroker;
+
+    public AlarmNotificationListener(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+
+    /**
+     * Callback for alarm-notification.
+     *
+     * @param notification AlarmNotification object
+     */
+    @Override
+    public void onAlarmNotification(AlarmNotification notification) {
+        List<Nodes> allNodeList = new ArrayList<>();
+        InstanceIdentifier<ServiceNodelist> serviceNodeListIID = InstanceIdentifier.create(ServiceNodelist.class);
+        try {
+            ReadOnlyTransaction rtx = dataBroker.newReadOnlyTransaction();
+            com.google.common.base.Optional<ServiceNodelist> serviceListObject =
+                    rtx.read(LogicalDatastoreType.OPERATIONAL, serviceNodeListIID).get();
+            if (serviceListObject.isPresent()) {
+                for (Nodelist nodelist : serviceListObject.get().getNodelist()) {
+                    allNodeList.addAll(nodelist.getNodes());
+                }
+            }
+        } catch (InterruptedException | ExecutionException ex) {
+            LOG.warn("Exception thrown while reading Logical Connection Point value from {} {}", ex);
+        }
+        StringBuilder sb = new StringBuilder(notification.getResource().getDevice().getNodeId()).append(PIPE);
+        sb.append(buildCause(notification.getProbableCause()));
+        sb.append(notification.getId() != null ? notification.getId() : "").append(PIPE)
+                .append(notification.getType() != null ? notification.getType().toString() : "").append(PIPE)
+                .append(notification.getRaiseTime() != null ? notification.getRaiseTime().toString() : "").append(PIPE)
+                .append(notification.getSeverity() != null ? notification.getSeverity().getName() : "").append(PIPE)
+                .append(notification.getCircuitId() != null ? notification.getCircuitId() : "").append(PIPE);
+
+        sb.append(buildType(notification));
+
+        String message = sb.toString();
+        Nodes build = new NodesBuilder().setNodeId(notification.getResource().getDevice().getNodeId()).build();
+        if (allNodeList.contains(build)) {
+            LOG.info(message);
+        } else {
+            LOG.warn(message);
+        }
+    }
+
+    private String buildCause(ProbableCause probableCause) {
+        StringBuilder sb = new StringBuilder();
+        if (probableCause == null) {
+            return "||||";
+        }
+        sb.append((probableCause.getCause() != null) ? probableCause.getCause().getName() : "").append(PIPE)
+                .append((probableCause.getDirection() != null) ? probableCause.getDirection().getName() : "")
+                .append(PIPE).append((probableCause.getExtension() != null) ? probableCause.getExtension() : "")
+                .append(PIPE).append((probableCause.getLocation() != null) ? probableCause.getLocation().getName() : "")
+                .append(PIPE);
+        return sb.toString();
+    }
+
+    @SuppressWarnings("unchecked")
+    private static <T extends Resource> Optional<T> tryCastToParticularResource(Class<T> resourceClass,
+            Resource resource) {
+        if (resource == null) {
+            LOG.error("Resource is null.");
+        } else if (!resourceClass.isInstance(resource)) {
+            LOG.error("Resource implement different type than expected. Expected {}, actual {}.",
+                    resourceClass.getSimpleName(), resource.getClass().getSimpleName());
+        } else {
+            return Optional.of((T) resource);
+        }
+        return Optional.empty();
+    }
+
+    private static String buildType(AlarmNotification notification) {
+        String circuitPack = "";
+        String connection = "";
+        String degree = "";
+        String iface = "";
+        String internalLink = "";
+        String physicalLink = "";
+        String service = "";
+        String shelf = "";
+        String sharedRiskGroup = "";
+        String port = "";
+        String portCircuitPack = "";
+
+        Resource resource = notification.getResource().getResource().getResource();
+        ResourceType wantedResourceType = notification.getResource().getResourceType();
+
+        switch (wantedResourceType.getType()) {
+            case CircuitPack:
+                Optional<CircuitPack> circuitPackOptional = tryCastToParticularResource(CircuitPack.class, resource);
+                if (circuitPackOptional.isPresent()) {
+                    circuitPack = circuitPackOptional.get().getCircuitPackName();
+                }
+                break;
+
+            case Connection:
+                Optional<Connection> connectionOptional = tryCastToParticularResource(Connection.class, resource);
+                if (connectionOptional.isPresent()) {
+                    connection = connectionOptional.get().getConnectionNumber();
+                }
+                break;
+
+            case Degree:
+                Optional<Degree> degreeOptional = tryCastToParticularResource(Degree.class, resource);
+                if (degreeOptional.isPresent()) {
+                    degree = degreeOptional.get().getDegreeNumber().toString();
+                }
+                break;
+
+            case Interface:
+                Optional<Interface> interfaceOptional = tryCastToParticularResource(Interface.class, resource);
+                if (interfaceOptional.isPresent()) {
+                    iface = interfaceOptional.get().getInterfaceName();
+                }
+                break;
+
+            case InternalLink:
+                Optional<InternalLink> internalLinkOptional = tryCastToParticularResource(InternalLink.class, resource);
+                if (internalLinkOptional.isPresent()) {
+                    internalLink = internalLinkOptional.get().getInternalLinkName();
+                }
+                break;
+
+            case PhysicalLink:
+                Optional<PhysicalLink> physicalLinkOptional = tryCastToParticularResource(PhysicalLink.class, resource);
+                if (physicalLinkOptional.isPresent()) {
+                    physicalLink = physicalLinkOptional.get().getPhysicalLinkName();
+                }
+                break;
+
+            case Service:
+                Optional<Service> serviceOptional = tryCastToParticularResource(Service.class, resource);
+                if (serviceOptional.isPresent()) {
+                    service = serviceOptional.get().getServiceName();
+                }
+                break;
+
+            case Shelf:
+                Optional<Shelf> shelfOptional = tryCastToParticularResource(Shelf.class, resource);
+                if (shelfOptional.isPresent()) {
+                    shelf = shelfOptional.get().getShelfName();
+                }
+                break;
+
+            case SharedRiskGroup:
+                Optional<Srg> sharedRiskGroupOptional = tryCastToParticularResource(Srg.class, resource);
+                if (sharedRiskGroupOptional.isPresent()) {
+                    sharedRiskGroup = sharedRiskGroupOptional.get().getSrgNumber().toString();
+                }
+                break;
+
+            case Port:
+                Optional<Port> portContainerOptional = tryCastToParticularResource(Port.class, resource);
+                if (portContainerOptional.isPresent()) {
+                    port = portContainerOptional.get().getPort().getPortName();
+                    portCircuitPack = portContainerOptional.get().getPort().getCircuitPackName();
+                }
+                break;
+
+            default:
+                LOG.warn("Unknown resource type {}", wantedResourceType);
+        }
+        StringBuilder sb = new StringBuilder(circuitPack);
+        sb.append(PIPE).append(connection).append(PIPE).append(degree).append(PIPE).append(iface);
+        sb.append(PIPE).append(internalLink).append(PIPE).append(physicalLink).append(PIPE).append(service);
+        sb.append(PIPE).append(shelf).append(PIPE).append(sharedRiskGroup).append(PIPE).append(port);
+        sb.append(PIPE).append(portCircuitPack);
+        return sb.toString();
+    }
+}
similarity index 94%
rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeOperationsListener.java
rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeOperationsListener.java
index 2292b2fd965f95cad86c040b4a04c24c945a3363..c861c2f8e5c80aa94d73cf4c8024c32310fcc96c 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.transportpce.renderer.listeners;
+package org.opendaylight.transportpce.networkmodel.listeners;
 
 import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.RestartNotification;
@@ -26,4 +26,5 @@ public class DeOperationsListener implements OrgOpenroadmDeOperationsListener {
     public void onRestartNotification(RestartNotification notification) {
         LOG.info("Notification {} received {}", RestartNotification.QNAME, notification);
     }
+
 }
\ No newline at end of file
similarity index 89%
rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/DeviceListener.java
rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/DeviceListener.java
index 2f57b31083485271d8f280383f2654d9f155205d..ab9d4e0367247d819b68bcce114f61a0b470b12d 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.transportpce.renderer.listeners;
+package org.opendaylight.transportpce.networkmodel.listeners;
 
 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.ChangeNotification;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener;
@@ -16,7 +16,7 @@ import org.slf4j.LoggerFactory;
 
 public class DeviceListener implements OrgOpenroadmDeviceListener {
 
-    private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmDeviceListener.class);
+    private static final Logger LOG = LoggerFactory.getLogger(DeviceListener.class);
 
     /**
      * Callback for change-notification.
@@ -39,4 +39,5 @@ public class DeviceListener implements OrgOpenroadmDeviceListener {
 
         LOG.info("Notification {} received {}", OtdrScanResult.QNAME, notification);
     }
+
 }
\ No newline at end of file
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/LldpListener.java
new file mode 100644 (file)
index 0000000..276ca0e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright © 2017 AT&T 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.networkmodel.listeners;
+
+import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.LldpNbrInfoChange;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.resource.types.rev161014.ResourceNotificationType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class LldpListener implements OrgOpenroadmLldpListener {
+
+    private static final Logger LOG = LoggerFactory.getLogger(LldpListener.class);
+    private final R2RLinkDiscovery linkDiscovery;
+    private final NodeId nodeId;
+
+    public LldpListener(final R2RLinkDiscovery linkDiscovery, final String nodeId) {
+        this.linkDiscovery = linkDiscovery;
+        this.nodeId = new NodeId(nodeId);
+    }
+
+    /**
+     * Callback for lldp-nbr-info-change.
+     * @param notification LldpNbrInfoChange object
+     */
+    @Override
+    public void onLldpNbrInfoChange(LldpNbrInfoChange notification) {
+        LOG.info("Notification {} received {}", LldpNbrInfoChange.QNAME, notification);
+        if (notification.getNotificationType().equals(ResourceNotificationType.ResourceCreation)) {
+            linkDiscovery.createR2RLink(nodeId,notification.getResource(),
+                                                notification.getNbrInfo().getRemoteSysName(),
+                                                notification.getNbrInfo().getRemotePortId());
+        } else if (notification.getNotificationType().equals(ResourceNotificationType.ResourceDeletion)) {
+            linkDiscovery.deleteR2RLink(nodeId,notification.getResource(),
+                                                notification.getNbrInfo().getRemoteSysName(),
+                                                notification.getNbrInfo().getRemotePortId());
+        }
+    }
+}
similarity index 84%
rename from renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/TcaListener.java
rename to networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/listeners/TcaListener.java
index b9b92c7570268fe420342777140e3d48660c1a99..ecfa36584faa228d07fa545506e706587f98bed5 100644 (file)
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.transportpce.renderer.listeners;
+package org.opendaylight.transportpce.networkmodel.listeners;
 
 import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener;
 import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.TcaNotification;
@@ -15,15 +15,15 @@ import org.slf4j.LoggerFactory;
 
 public class TcaListener implements OrgOpenroadmTcaListener {
 
-    private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmTcaListener.class);
+    private static final Logger LOG = LoggerFactory.getLogger(TcaListener.class);
 
     /**
      * Callback for tca-notification.
-     *
      * @param notification TcaNotification object
      */
     @Override
     public void onTcaNotification(TcaNotification notification) {
         LOG.info("Notification {} received {}", TcaNotification.QNAME, notification);
     }
+
 }
\ No newline at end of file
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelService.java
new file mode 100644 (file)
index 0000000..3a5e54d
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.service;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
+
+/**
+ * Service for data manipulation on OpenROADM topology models.
+ */
+public interface NetworkModelService {
+
+    /**
+     * Create new OpenROADM node in all OpenROADM topologies.
+     *
+     * @param nodeId
+     *   unique node ID of new OpenROADM node
+     */
+    void createOpenROADMnode(String nodeId);
+
+    /**
+     * Set/update connection status of OpenROADM node.
+     *
+     * @param nodeId
+     *   unique node ID of new OpenROADM node
+     * @param connectionStatus
+     *   connection status of the node
+     */
+    void setOpenROADMnodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus);
+
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/service/NetworkModelServiceImpl.java
new file mode 100644 (file)
index 0000000..daf0852
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.service;
+
+import java.util.concurrent.ExecutionException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.common.mapping.PortMapping;
+import org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery;
+import org.opendaylight.transportpce.networkmodel.dto.TopologyShard;
+import org.opendaylight.transportpce.networkmodel.util.ClliNetwork;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmNetwork;
+import org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.topology.rev150114.NetconfNodeConnectionStatus;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class NetworkModelServiceImpl implements NetworkModelService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(NetworkModelServiceImpl.class);
+    private static final boolean CREATE_MISSING_PARENTS = true;
+
+    private final DataBroker dataBroker;
+    private final R2RLinkDiscovery linkDiscovery;
+    private final DeviceTransactionManager deviceTransactionManager;
+    private final OpenRoadmTopology openRoadmTopology;
+    private final PortMapping portMapping;
+
+    public NetworkModelServiceImpl(final DataBroker dataBroker, final R2RLinkDiscovery linkDiscovery,
+            DeviceTransactionManager deviceTransactionManager,
+            OpenRoadmTopology openRoadmTopology, PortMapping portMapping) {
+        this.dataBroker = dataBroker;
+        this.linkDiscovery = linkDiscovery;
+        this.deviceTransactionManager = deviceTransactionManager;
+        this.openRoadmTopology = openRoadmTopology;
+        this.portMapping = portMapping;
+    }
+
+    public void init() {
+        LOG.info("init ...");
+    }
+
+    public void close() {
+    }
+
+    @Override
+    public void createOpenROADMnode(String nodeId) {
+        try {
+            LOG.info("createOpenROADMNode: {} ", nodeId);
+
+            this.portMapping.createMappingData(nodeId);
+            this.linkDiscovery.readLLDP(new NodeId(nodeId));
+
+            Node clliNode = ClliNetwork.createNode(this.deviceTransactionManager, nodeId);
+            if (clliNode == null) {
+                LOG.error("Unable to create clli node! Node id: {}", nodeId);
+                return;
+            }
+
+            Node openRoadmNode = OpenRoadmNetwork.createNode(nodeId, this.deviceTransactionManager);
+            if (openRoadmNode == null) {
+                LOG.error("Unable to create OpenRoadm node! Node id: {}", nodeId);
+                return;
+            }
+
+            TopologyShard topologyShard = this.openRoadmTopology.createTopologyShard(nodeId);
+            if (topologyShard == null) {
+                LOG.error("Unable to create topology shard for node {}!", nodeId);
+                return;
+            }
+
+            WriteTransaction writeTransaction = this.dataBroker.newWriteOnlyTransaction();
+            LOG.info("creating node in {}", NetworkUtils.CLLI_NETWORK_ID);
+            InstanceIdentifier<Node> iiClliNode = InstanceIdentifier
+                    .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)))
+                    .child(Node.class, clliNode.getKey())
+                    .build();
+            writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiClliNode, clliNode,
+                    CREATE_MISSING_PARENTS);
+            LOG.info("creating node in {}", NetworkUtils.UNDERLAY_NETWORK_ID);
+            InstanceIdentifier<Node> iiOpenRoadmNode = InstanceIdentifier
+                    .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)))
+                    .child(Node.class, openRoadmNode.getKey())
+                    .build();
+            writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmNode, openRoadmNode,
+                    CREATE_MISSING_PARENTS);
+            for (Node openRoadmTopologyNode: topologyShard.getNodes()) {
+                LOG.info("creating node {} in {}", openRoadmTopologyNode.getNodeId().getValue(),
+                        NetworkUtils.OVERLAY_NETWORK_ID);
+                InstanceIdentifier<Node> iiOpenRoadmTopologyNode = InstanceIdentifier
+                        .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                        .child(Node.class, openRoadmTopologyNode.getKey())
+                        .build();
+                writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyNode,
+                        openRoadmTopologyNode, CREATE_MISSING_PARENTS);
+            }
+            for (Link openRoadmTopologyLink: topologyShard.getLinks()) {
+                LOG.info("creating link {} in {}", openRoadmTopologyLink.getLinkId().getValue(),
+                        NetworkUtils.OVERLAY_NETWORK_ID);
+                InstanceIdentifier<Link> iiOpenRoadmTopologyLink = InstanceIdentifier
+                        .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                        .augmentation(Network1.class)
+                        .child(Link.class, openRoadmTopologyLink.getKey())
+                        .build();
+                writeTransaction.merge(LogicalDatastoreType.CONFIGURATION, iiOpenRoadmTopologyLink,
+                        openRoadmTopologyLink, CREATE_MISSING_PARENTS);
+            }
+            writeTransaction.submit().get();
+            LOG.info("all nodes and links created");
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.error("ERROR: ", e);
+        }
+    }
+
+    @Override
+    public void setOpenROADMnodeStatus(String nodeId, NetconfNodeConnectionStatus.ConnectionStatus connectionStatus) {
+        LOG.info("setOpenROADMNodeStatus: {} {}", nodeId, connectionStatus.name());
+        /*
+          TODO: set connection status of the device in model,
+          TODO: so we don't need to keep it in memory (Set<String> currentMountedDevice)
+          TODO: unfortunately there is no connection status OpenROADM in network models
+          TODO: waiting for new model version
+         */
+    }
+
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/ClliNetwork.java
new file mode 100644 (file)
index 0000000..9c25182
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.util;
+
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.NetworkTypes1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.NetworkTypes1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.Node1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.Node1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.clli.network.rev170626.network.network.types.ClliNetworkBuilder;
+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.Info;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ClliNetwork {
+
+    private static final Logger LOG = LoggerFactory.getLogger(ClliNetwork.class);
+
+    private ClliNetwork() {
+        // utility class
+    }
+
+    /**
+     * This public method creates the CLLI Layer and posts it to the controller.
+     */
+    public static void createClliLayer(DataBroker controllerdb) {
+        try {
+            Network clliNetwork = createNetwork();
+            InstanceIdentifierBuilder<Network> nwIID = InstanceIdentifier.builder(
+                       Network.class,new NetworkKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID)));
+            WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction();
+            wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), clliNetwork);
+            wrtx.submit().get(1, TimeUnit.SECONDS);
+            LOG.info("CLLI-Network created successfully.");
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            LOG.warn("Failed to create CLLI-Network", e);
+        }
+    }
+
+    /**
+     * Create single node entry for CLLI topology.
+     *
+     */
+    public static Node createNode(DeviceTransactionManager deviceTransactionManager, String deviceId) {
+        //Read clli from the device
+        InstanceIdentifier<Info> infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class);
+        Optional<Info> deviceInfo = deviceTransactionManager.getDataFromDevice(deviceId,
+                LogicalDatastoreType.OPERATIONAL, infoIID, Timeouts.DEVICE_READ_TIMEOUT,
+                Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        String clli;
+        if (deviceInfo.isPresent()) {
+            clli = deviceInfo.get().getClli();
+        } else {
+            return null;
+        }
+        /*
+         * Create node in the CLLI layer of the network model
+         * with nodeId equal to the clli attribute in the device
+         * model's info subtree
+         */
+        NodeBuilder nodeBldr = new NodeBuilder();
+        NodeId nwNodeId = new NodeId(clli);
+        nodeBldr.setNodeId(nwNodeId);
+        nodeBldr.setKey(new NodeKey(nwNodeId));
+        /*
+         * create clli node augmentation
+         * defined in openroadm-clli-network.yang
+         */
+        Node1Builder clliAugmentationBldr = new Node1Builder();
+        clliAugmentationBldr.setClli(clli);
+        nodeBldr.addAugmentation(Node1.class, clliAugmentationBldr.build());
+        return nodeBldr.build();
+    }
+
+    /**
+     * Create empty CLLI network.
+     */
+    private static Network createNetwork() {
+        NetworkBuilder nwBuilder = new NetworkBuilder();
+        NetworkId nwId = new NetworkId(NetworkUtils.CLLI_NETWORK_ID);
+        nwBuilder.setNetworkId(nwId);
+        nwBuilder.setKey(new NetworkKey(nwId));
+        //set network type to clli
+        NetworkTypes1Builder clliNetworkTypesBldr = new NetworkTypes1Builder();
+        clliNetworkTypesBldr.setClliNetwork(new ClliNetworkBuilder().build());
+        NetworkTypesBuilder nwTypeBuilder = new NetworkTypesBuilder();
+        nwTypeBuilder.addAugmentation(NetworkTypes1.class, clliNetworkTypesBldr.build());
+        nwBuilder.setNetworkTypes(nwTypeBuilder.build());
+        return nwBuilder.build();
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/LinkIdUtil.java
new file mode 100644 (file)
index 0000000..cf6eed3
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.util;
+
+import java.text.MessageFormat;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.networkutils.rev170818.InitRoadmNodesInput;
+
+public final class LinkIdUtil {
+
+    private static final String NETWORK = "-NETWORK";
+    private static final String TRANSMIT = "-TX";
+    private static final String RECEIVE = "-RX";
+    private static final String BIDIRECTIONAL = "-TXRX";
+    private static final MessageFormat LINK_ID_FORMAT = new MessageFormat("{0}-{1}to{2}-{3}");
+
+    private LinkIdUtil() {
+        // utility class
+    }
+
+    /**
+     * Builds the Link id in format {@link LinkIdUtil#LINK_ID_FORMAT}.
+     *
+     * @param srcNode source node id string
+     * @param srcTp source termination point
+     * @param destNode destination node id
+     * @param destTp destination termination point
+     * @return {@link LinkId}
+     */
+    public static LinkId buildLinkId(String srcNode, String srcTp, String destNode, String destTp) {
+        return new LinkId(LINK_ID_FORMAT
+                .format(new Object[] {srcNode, srcTp, destNode, destTp}, new StringBuffer(), null).toString());
+    }
+
+    /**
+     * Builds the opposite {@link LinkId} from the {@link InitRoadmNodesInput}.
+     *
+     * @param input an init link for ROADM nodes
+     * @return opposite {@link LinkId}
+     */
+    public static LinkId getRdm2RdmOppositeLinkId(InitRoadmNodesInput input) {
+        String srcNode = new StringBuilder(input.getRdmANode()).append("-DEG").append(input.getDegANum()).toString();
+        String srcTp = input.getTerminationPointA();
+        String destNode = new StringBuilder(input.getRdmZNode()).append("-DEG").append(input.getDegZNum()).toString();
+        String destTp = input.getTerminationPointZ();
+
+        Object[] params = buildParams(srcNode, srcTp, destNode, destTp, false);
+
+        return new LinkId(LINK_ID_FORMAT.format(params, new StringBuffer(), null).toString());
+    }
+
+    /**
+     * Builds the opposite {@link LinkId} from string descriptors.
+     *
+     * @param srcNode a source node
+     * @param srcTp a source termination point
+     * @param destNode a destination node
+     * @param destTp a destination termination point
+     * @return LinkId a link identifier
+     */
+    public static LinkId getOppositeLinkId(String srcNode, String srcTp, String destNode, String destTp) {
+        return getOppositeLinkId(srcNode, srcTp, destNode, destTp, true);
+    }
+
+    /**
+     * Builds the opposite {@link LinkId} from string descriptors.
+     *
+     * @param srcNode a source node
+     * @param srcTp a source termination point
+     * @param destNode a destination node
+     * @param destTp a destination termination point
+     * @return LinkId a link identifier
+     */
+    public static LinkId getOppositeLinkId(String srcNode, String srcTp, String destNode, String destTp,
+        boolean checkNode) {
+        Object[] params = buildParams(srcNode, srcTp, destNode, destTp, checkNode);
+        return new LinkId(LINK_ID_FORMAT.format(params, new StringBuffer(), null).toString());
+    }
+
+    private static Object[] buildParams(String srcNode, String srcTp, String destNode, String destTp,
+            boolean checkForNetwork) {
+        Object[] params = null;
+        if (checkBidirectional(checkForNetwork, srcTp)) {
+            if (checkBidirectional(checkForNetwork, destTp)) {
+                params = new Object[] {destNode, destTp, srcNode, srcTp};
+            } else if (destTp.contains(RECEIVE)) {
+                params = new Object[] {destNode, destTp.replace("RX", "TX"), srcNode, srcTp};
+            } else {
+                throw new IllegalArgumentException("Dest Termination Point is either RX/TX_RX ! Check TP");
+            }
+        } else if (srcTp.contains(TRANSMIT)) {
+            String replacedSrcTp = srcTp.replace("TX", "RX");
+            if (checkBidirectional(checkForNetwork, destTp)) {
+                params = new Object[] {destNode, destTp, srcNode, replacedSrcTp};
+            } else if (destTp.contains(RECEIVE)) {
+                params = new Object[] {destNode, destTp.replace("RX", "TX"), srcNode, replacedSrcTp};
+            } else {
+                throw new IllegalArgumentException("Dest Termination Point is either RX/TX_RX ! Check TP");
+            }
+        } else {
+            throw new IllegalArgumentException("SRC Termination Point is either TX/TXRX ! Check TP");
+        }
+        return params;
+    }
+
+    private static boolean checkBidirectional(boolean check, String tp) {
+        return tp.contains(BIDIRECTIONAL) || (check && tp.contains(NETWORK));
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmNetwork.java
new file mode 100644 (file)
index 0000000..2292cf1
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.util;
+
+import com.google.common.collect.ImmutableList;
+
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.NodeTypes;
+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.Info;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.NetworkTypes1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.NetworkTypes1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.Node1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.Node1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.rev170929.network.network.types.OpenroadmNetworkBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmNodeType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.inet.types.rev130715.IpAddress;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class OpenRoadmNetwork {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmNetwork.class);
+
+    private OpenRoadmNetwork() {
+        // utility class
+    }
+
+    /**
+     * This public method creates the OpenRoadmNetwork Layer and posts it to the controller.
+     */
+    public static void createOpenRoadmNetworkLayer(DataBroker controllerdb) {
+        try {
+            Network openRoadmNetwork = createOpenRoadmNetwork();
+            InstanceIdentifierBuilder<Network> nwIID = InstanceIdentifier.builder(Network.class,
+                    new NetworkKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID)));
+            WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction();
+            wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), openRoadmNetwork);
+            wrtx.submit().get(1, TimeUnit.SECONDS);
+            LOG.info("OpenRoadm-Network created successfully.");
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            LOG.warn("Failed to create OpenRoadm-Network", e);
+        }
+    }
+
+    /**
+     * Create single node entry for OpenRoadmNetwork.
+     *
+     */
+    public static Node createNode(String nodeId, DeviceTransactionManager deviceTransactionManager) {
+        // Fetches the info from the deviceInfo
+        InstanceIdentifier<Info> infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class);
+        Optional<Info> deviceInfoOpt =
+                deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, infoIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        Info deviceInfo;
+        if (deviceInfoOpt.isPresent()) {
+            deviceInfo = deviceInfoOpt.get();
+        } else {
+            LOG.error("Unable to get device info from device {}!", nodeId);
+            return null;
+        }
+        NodeTypes nodeType = deviceInfo.getNodeType();
+
+        // Uses the Node Builder to set the nodeId and Key
+        NodeBuilder nodeBldr = new NodeBuilder();
+        NodeId nwNodeId = new NodeId(nodeId);
+        nodeBldr.setNodeId(nwNodeId);
+        nodeBldr.setKey(new NodeKey(nwNodeId));
+        Node1Builder node1bldr = new Node1Builder();
+
+        /*
+         * If the type of the Node is ROADM, Node type is set to ROADM Else, XPONDER
+         */
+        if (nodeType.getIntValue() == 1) {
+            node1bldr.setNodeType(OpenroadmNodeType.ROADM);
+        } else if (nodeType.getIntValue() == 3) {
+            node1bldr.setNodeType(OpenroadmNodeType.XPONDER);
+        }
+
+        String vendor = deviceInfo.getVendor();
+        String model = deviceInfo.getModel();
+        IpAddress ipAddress = deviceInfo.getIpAddress();
+        // Sets IP, Model and Vendor information fetched from the deviceInfo
+        node1bldr.setIp(ipAddress);
+        node1bldr.setModel(model);
+        node1bldr.setVendor(vendor);
+
+        // Sets the value of Network-ref and Node-ref as a part of the supporting node attribute
+        String clli = deviceInfo.getClli();
+        SupportingNodeBuilder supportbldr = new SupportingNodeBuilder();
+        supportbldr.setKey(new SupportingNodeKey(new NetworkId(NetworkUtils.CLLI_NETWORK_ID), new NodeId(clli)));
+        supportbldr.setNetworkRef(new NetworkId(NetworkUtils.CLLI_NETWORK_ID));
+        supportbldr.setNodeRef(new NodeId(clli));
+        nodeBldr.setSupportingNode(ImmutableList.of(supportbldr.build()));
+
+        // Augment to the main node builder
+        nodeBldr.addAugmentation(Node1.class, node1bldr.build());
+        return nodeBldr.build();
+    }
+
+    /**
+     * Create empty OpenROADM network.
+     */
+    private static Network createOpenRoadmNetwork() {
+        NetworkBuilder openrdmnwBuilder = new NetworkBuilder();
+        NetworkId nwId = new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID);
+        openrdmnwBuilder.setNetworkId(nwId);
+        openrdmnwBuilder.setKey(new NetworkKey(nwId));
+        //sets network type to OpenRoadmNetwork
+        NetworkTypes1Builder openRoadmNetworkTypesBldr = new NetworkTypes1Builder();
+        openRoadmNetworkTypesBldr.setOpenroadmNetwork(new OpenroadmNetworkBuilder().build());
+        NetworkTypesBuilder openrdmnwTypeBuilder = new NetworkTypesBuilder();
+        openrdmnwTypeBuilder.addAugmentation(NetworkTypes1.class, openRoadmNetworkTypesBldr.build());
+        openrdmnwBuilder.setNetworkTypes(openrdmnwTypeBuilder.build());
+        return openrdmnwBuilder.build();
+    }
+}
diff --git a/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java b/networkmodel/src/main/java/org/opendaylight/transportpce/networkmodel/util/OpenRoadmTopology.java
new file mode 100644 (file)
index 0000000..3a23f7c
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ * Copyright © 2016 AT&T 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.networkmodel.util;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.transportpce.common.NetworkUtils;
+import org.opendaylight.transportpce.common.Timeouts;
+import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
+import org.opendaylight.transportpce.networkmodel.dto.NodeData;
+import org.opendaylight.transportpce.networkmodel.dto.TopologyShard;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.common.types.rev161014.NodeTypes;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengths;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengthsBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.degree.rev170929.degree.node.attributes.AvailableWavelengthsKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.Ports;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.pack.PortsKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacks;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.circuit.packs.CircuitPacksKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.degree.ConnectionPorts;
+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.Degree;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.DegreeKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.Info;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.SharedRiskGroup;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.org.openroadm.device.container.org.openroadm.device.SharedRiskGroupKey;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Link1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.NetworkTypes1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.NetworkTypes1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Node1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.Node1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.TerminationPoint1;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.TerminationPoint1Builder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.network.types.OpenroadmTopologyBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.DegreeAttributesBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.SrgAttributesBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.termination.point.XpdrClientAttributesBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.topology.rev170929.network.node.termination.point.XpdrNetworkAttributesBuilder;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmLinkType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmNodeType;
+import org.opendaylight.yang.gen.v1.http.org.openroadm.network.types.rev170929.OpenroadmTpType;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.Network;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NetworkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.NodeId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NetworkTypesBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.Node;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.NodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNode;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.rev150608.network.node.SupportingNodeKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.LinkId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Network1Builder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.TpId;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.Link;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.LinkKey;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.link.DestinationBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.link.SourceBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPoint;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPointBuilder;
+import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.network.node.TerminationPointKey;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OpenRoadmTopology {
+
+    private static final Logger LOG = LoggerFactory.getLogger(OpenRoadmTopology.class);
+    private static final int DEFAULT_PORT_DIRECTION = -1;
+    private static final int MAX_DEGREE = 20;
+    private static final int MAX_SRG = 20;
+
+    private final DataBroker dataBroker;
+    private final DeviceTransactionManager deviceTransactionManager;
+
+    public OpenRoadmTopology(DataBroker dataBroker, DeviceTransactionManager deviceTransactionManager) {
+        this.dataBroker = dataBroker;
+        this.deviceTransactionManager = deviceTransactionManager;
+    }
+
+    /**
+     * This public method creates the OpenROADM Topology Layer and posts it to the controller.
+     */
+    public void createTopoLayer(DataBroker controllerdb) {
+        try {
+            Network openRoadmTopology = createOpenRoadmTopology();
+            InstanceIdentifierBuilder<Network> nwIID = InstanceIdentifier.builder(Network.class,
+                    new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)));
+            WriteTransaction wrtx = controllerdb.newWriteOnlyTransaction();
+            wrtx.put(LogicalDatastoreType.CONFIGURATION, nwIID.build(), openRoadmTopology);
+            wrtx.submit().get(1, TimeUnit.SECONDS);
+            LOG.info("OpenRoadm-Topology created successfully.");
+        } catch (ExecutionException | TimeoutException | InterruptedException e) {
+            LOG.warn("Failed to create OpenRoadm-Topology", e);
+        }
+    }
+
+    /**
+     * Create empty OpenROADM topology.
+     */
+    private Network createOpenRoadmTopology() {
+        NetworkBuilder nwBuilder = new NetworkBuilder();
+        NetworkId nwId = new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID);
+        nwBuilder.setNetworkId(nwId);
+        nwBuilder.setKey(new NetworkKey(nwId));
+        // set network type to Transport Underlay
+        NetworkTypes1Builder topoNetworkTypesBldr = new NetworkTypes1Builder();
+        topoNetworkTypesBldr.setOpenroadmTopology(new OpenroadmTopologyBuilder().build());
+        NetworkTypesBuilder nwTypeBuilder = new NetworkTypesBuilder();
+        nwTypeBuilder.addAugmentation(NetworkTypes1.class, topoNetworkTypesBldr.build());
+        nwBuilder.setNetworkTypes(nwTypeBuilder.build());
+        // Array to store nodes in the topolayer of a roadm/Xponder
+        Network1Builder nwBldr1 = new Network1Builder();
+        // adding expressLinks
+        nwBldr1.setLink(Collections.emptyList());
+        nwBuilder.addAugmentation(Network1.class, nwBldr1.build());
+        nwBuilder.setNode(Collections.emptyList());
+        return nwBuilder.build();
+    }
+
+    public TopologyShard createTopologyShard(String nodeId) {
+        int numOfDegrees;
+        int numOfSrgs;
+        int portDirectionEnum = DEFAULT_PORT_DIRECTION;
+
+        InstanceIdentifier<Info> infoIID = InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Info.class);
+        java.util.Optional<Info> deviceInfoOpt =
+                this.deviceTransactionManager.getDataFromDevice(nodeId, LogicalDatastoreType.OPERATIONAL, infoIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        Info deviceInfo;
+        if (deviceInfoOpt.isPresent()) {
+            deviceInfo = deviceInfoOpt.get();
+        } else {
+            LOG.error("Unable to get device info for device {}!", nodeId);
+            return null;
+        }
+        List<Node> nodes = new ArrayList<>();
+
+        // Check if node is ROADM
+        if (NodeTypes.Rdm.equals(deviceInfo.getNodeType())) {
+
+            /*
+             * Adding Degree Node Get Degree Number -> x then get connection ports then find the port directions
+             * to decide whether TX/RX/TXRX Get value for max degree from info subtree, required for iteration
+             * if not present assume to be 20 (temporary)
+             */
+
+            Integer maxDegree;
+            if (deviceInfo.getMaxDegrees() != null) {
+                maxDegree = deviceInfo.getMaxDegrees();
+            } else {
+                maxDegree = MAX_DEGREE;
+            }
+
+            // Starting with degree Number = 1
+            Integer degreeCounter = 1;
+
+            while (degreeCounter <= maxDegree) {
+                LOG.info("creating degree node {}/{}", degreeCounter, maxDegree);
+                NodeData nodeData = createDegreeNode(nodeId, degreeCounter);
+                if (nodeData != null) {
+                    NodeBuilder tempNode = nodeData.getNodeBuilder();
+                    portDirectionEnum = nodeData.getPortDirectionEnum();
+                    nodes.add(tempNode.build());
+                    degreeCounter++;
+                } else {
+                // null returned if Degree number= degreeCounter not present in the device
+                    break;
+                }
+            }
+            numOfDegrees = degreeCounter - 1;
+
+            Integer maxSrg;
+            if (deviceInfo.getMaxSrgs() != null) {
+                maxSrg = deviceInfo.getMaxSrgs();
+            } else {
+                maxSrg = MAX_SRG;
+            }
+
+            // Starting with degree Number = 1
+            Integer srgCounter = 1;
+
+            while (srgCounter <= maxSrg) {
+                LOG.info("creating SRG node {}/{}", srgCounter, maxSrg);
+                NodeBuilder tempNode = createSrgNode(nodeId, srgCounter, portDirectionEnum);
+
+                if (tempNode != null) {
+                    nodes.add(tempNode.build());
+                    srgCounter++;
+                } else {
+                    // null returned if Degree number= degreeCounter not present in the device
+                    break;
+                }
+            }
+            numOfSrgs = srgCounter - 1;
+
+
+            LOG.info("adding links numOfDegrees={} numOfSrgs={}", numOfDegrees, numOfSrgs);
+            List<Link> links = new ArrayList<>();
+            links.addAll(createExpressLinks(nodeId, numOfDegrees, portDirectionEnum));
+            links.addAll(createAddDropLinks(nodeId, numOfDegrees, numOfSrgs, portDirectionEnum));
+            LOG.info("created nodes/links: {}/{}", nodes.size(), links.size());
+            return new TopologyShard(nodes, links);
+        } else if (NodeTypes.Xpdr.equals(deviceInfo.getNodeType())) {
+            // Check if node is XPONDER
+            Integer clientport = getNoOfClientPorts(nodeId);
+            List<Link> links = new ArrayList<>();
+            Integer clientCounter = 1;
+            Integer lineCounter = 1;
+            while (clientCounter <= clientport) {
+                NodeBuilder tempNode = createXpdr(clientCounter, lineCounter, nodeId);
+                if (tempNode == null) {
+                    break;
+                }
+                nodes.add(tempNode.build());
+                clientCounter++;
+                lineCounter++;
+                LOG.info("Entered this loop");
+            }
+            return new TopologyShard(nodes, links);
+        }
+
+        return null;
+    }
+
+    /**
+     * This private method gets the list of circuit packs on a xponder. For each circuit pack on a
+     * Xponder, it does a get on circuit-pack subtree with circuit-pack-name as key in order to get the
+     * list of ports. It then iterates over the list of ports to get ports with port-qual as
+     * xpdr-network/xpdr-client. The line and client ports are saved as:
+     *
+     * <p>
+     * 1. LINEn
+     *
+     * <p>
+     * 2. CLNTn
+     */
+    private int getNoOfClientPorts(String deviceId) {
+        // Creating for Xponder Line and Client Ports
+        InstanceIdentifier<OrgOpenroadmDevice> deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class);
+        Optional<OrgOpenroadmDevice> deviceObject =
+                this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, deviceIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+
+        // Variable to keep track of number of client ports
+        int client = 1;
+        if (deviceObject.isPresent()) {
+            for (CircuitPacks cp : deviceObject.get().getCircuitPacks()) {
+                if (cp.getPorts() != null) {
+                    for (Ports port : cp.getPorts()) {
+                        if (port.getPortQual() != null) {
+                            if (port.getPortQual().getIntValue() == 4) {
+                                client++;
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            return 0;
+        }
+        return client;
+    }
+
+    private NodeBuilder createXpdr(Integer clientCounter, Integer lineCounter, String nodeId) {
+        // Create a generic Topo Layer node
+        NodeBuilder nodebldr = createTopoLayerNode(nodeId);
+        // Create augmentation node to inorder to add degree
+        Node1Builder node1bldr = new Node1Builder();
+        TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder();
+        TerminationPointBuilder tempTpBldr;
+
+        // set node type to Xponder
+        node1bldr.setNodeType(OpenroadmNodeType.XPONDER);
+        List<TerminationPoint> tpList = new ArrayList<>();
+        String nodeIdtopo = new StringBuilder().append(nodeId).append("-XPDR1").toString();
+        // Ad degree node specific augmentation
+        nodebldr.setNodeId(new NodeId(nodeIdtopo));
+        nodebldr.setKey(new NodeKey(new NodeId(nodeIdtopo)));
+        nodebldr.addAugmentation(Node1.class, node1bldr.build());
+        while (clientCounter != 0) {
+            // Create CLNT-TX termination
+            tempTpBldr = createTpBldr("XPDR1-CLIENT" + clientCounter);
+            tp1Bldr.setTpType(OpenroadmTpType.XPONDERCLIENT);
+            XpdrClientAttributesBuilder xpdrClntBldr = new XpdrClientAttributesBuilder();
+            xpdrClntBldr.setTailEquipmentId("XPDR1-NETWORK" + clientCounter);
+            tp1Bldr.setXpdrClientAttributes(xpdrClntBldr.build());
+            tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+            clientCounter--;
+        }
+        while (lineCounter != 0) {
+            // Create LINE-TX termination
+            tempTpBldr = (createTpBldr("XPDR1-NETWORK" + lineCounter));
+            tp1Bldr.setTpType(OpenroadmTpType.XPONDERNETWORK);
+            XpdrNetworkAttributesBuilder xpdrNwAttrBldr = new XpdrNetworkAttributesBuilder();
+            xpdrNwAttrBldr.setTailEquipmentId("XPDR1-CLIENT" + lineCounter);
+            tp1Bldr.setXpdrNetworkAttributes(xpdrNwAttrBldr.build());
+            tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+            lineCounter--;
+        }
+        LOG.info("printing tpList {}",tpList);
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 =
+            new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder();
+        tpNode1.setTerminationPoint(tpList);
+        nodebldr.addAugmentation(
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class,
+                tpNode1.build());
+        LOG.info("The nodebldr {}",nodebldr);
+        return nodebldr;
+    }
+
+
+    private NodeData createDegreeNode(String nodeId, int degreeCounter) {
+        // Create augmentation node to inorder to add degree
+        Node1Builder node1bldr = new Node1Builder();
+        // set node type to degree
+        node1bldr.setNodeType(OpenroadmNodeType.DEGREE);
+
+        // Get connection ports on degree number = degreeCounter in order to get port
+        // direction
+        List<ConnectionPorts> degreeConPorts = getDegreePorts(nodeId, degreeCounter);
+        if ((degreeConPorts == null) || degreeConPorts.isEmpty()) {
+            return null;
+        }
+
+        DegreeAttributesBuilder degAttBldr = new DegreeAttributesBuilder();
+        degAttBldr.setDegreeNumber(degreeCounter);
+        degAttBldr.setAvailableWavelengths(create96AvalWaveDegree());
+        node1bldr.setDegreeAttributes(degAttBldr.build());
+
+        String nodeIdtopo = new StringBuilder(nodeId).append("-DEG").append(degreeCounter).toString();
+        // Create a generic Topo Layer node
+        NodeBuilder nodebldr = createTopoLayerNode(nodeId);
+        nodebldr.setNodeId(new NodeId(nodeIdtopo));
+        // Ad degree node specific augmentation
+        nodebldr.addAugmentation(Node1.class, node1bldr.build());
+        // Get Port direction
+        int portDirectionEnum = getPortDirection(nodeId, degreeConPorts.get(0).getCircuitPackName(),
+                                             degreeConPorts.get(0).getPortName().toString());
+
+        /*
+         * if bi-directional then create 2 tp's :
+         *
+         * --> TTP-TXRX --> CTP-TXRX
+         *
+         * if uni-directional :
+         *
+         *     --> TTP-TX
+         *     --> TTP-RX
+         *     --> CTP-TX
+         *     --> CTP-RX
+         */
+        TerminationPoint1Builder tp1Bldr = new TerminationPoint1Builder();
+        TerminationPointBuilder tempTpBldr;
+
+        List<TerminationPoint> tpList = new ArrayList<>();
+        if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) {
+            // ports are uni Directional on a degree, therefore 4 termination points
+            // Create TTP-TX termination
+
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-TX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREETXTTP);
+            tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+            // Create TTP-RX termination
+            tp1Bldr = new TerminationPoint1Builder();
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-RX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREERXTTP);
+
+            tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+            // Create CTP-TX termination
+            tp1Bldr = new TerminationPoint1Builder();
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-TX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREETXCTP);
+            tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+            // Create CTP-RX termination
+            tp1Bldr = new TerminationPoint1Builder();
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-RX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREERXCTP);
+            tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+        } else if (portDirectionEnum == 3) {
+            // Ports are bi directional therefore 2 termination points
+            // Create TTP-TXRX termination
+            tp1Bldr = new TerminationPoint1Builder();
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-TTP-TXRX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREETXRXTTP);
+            tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+            // Create CTP-TXRX termination
+            tp1Bldr = new TerminationPoint1Builder();
+            tempTpBldr = createTpBldr("DEG" + degreeCounter + "-CTP-TXRX");
+            tp1Bldr.setTpType(OpenroadmTpType.DEGREETXRXCTP);
+            tempTpBldr.addAugmentation(TerminationPoint1.class,tp1Bldr.build());
+            tpList.add(tempTpBldr.build());
+
+        }
+
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 =
+            new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder();
+
+        tpNode1.setTerminationPoint(tpList);
+
+        nodebldr.addAugmentation(
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class,
+                tpNode1.build());
+        return new NodeData(nodebldr, portDirectionEnum);
+    }
+
+
+    private NodeBuilder createSrgNode(String nodeId, int srgCounter, int portDirectionEnum) {
+        // Create augmentation node to inorder to add degree
+        Node1Builder node1bldr = new Node1Builder();
+        // set node type to degree
+        node1bldr.setNodeType(OpenroadmNodeType.SRG);
+
+        node1bldr.setNodeType(OpenroadmNodeType.SRG);
+
+        SrgAttributesBuilder srgAttrBldr = new SrgAttributesBuilder();
+        srgAttrBldr.setAvailableWavelengths(create96AvalWaveSrg());
+        node1bldr.setSrgAttributes(srgAttrBldr.build());
+
+        // Create a generic Topo Layer node
+        NodeBuilder nodebldr = createTopoLayerNode(nodeId);
+        nodebldr.addAugmentation(Node1.class, node1bldr.build());
+
+        // Get connection ports on degree number = degreeCounter in order to get port
+        // direction
+        int maxPpPorts = getMaxPp(nodeId, srgCounter);
+        if (maxPpPorts == -1) {
+            return null;
+        }
+
+
+        String nodeIdtopo = new StringBuilder().append(nodeId).append("-SRG").append(srgCounter).toString();
+        nodebldr.setNodeId(new NodeId(nodeIdtopo));
+        List<TerminationPoint> tpList = new ArrayList<>();
+
+        TerminationPoint1Builder tp1Bldr;
+        TerminationPointBuilder tempTpBldr;
+
+        for (int i = 1; i <= maxPpPorts; i++) {
+            if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) {
+                if (i >= (maxPpPorts / 2)) {
+                    break;
+                }
+                // ports are uni Directional on a degree, therefore 4 termination points
+                // Create TTP-TX termination
+                tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-TX");
+                tp1Bldr = new TerminationPoint1Builder();
+                tp1Bldr.setTpType(OpenroadmTpType.SRGTXPP);
+                tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+                tpList.add(tempTpBldr.build());
+
+                // Create TTP-RX termination
+                tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-RX");
+                tp1Bldr = new TerminationPoint1Builder();
+                tp1Bldr.setTpType(OpenroadmTpType.SRGRXPP);
+                tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+                tpList.add(tempTpBldr.build());
+
+            } else if (portDirectionEnum == 3) {
+                // Ports are bi directional therefore 2 termination points
+                // Create TTP-TXRX termination
+                tempTpBldr = createTpBldr("SRG" + srgCounter + "-PP" + i + "-TXRX");
+                tp1Bldr = new TerminationPoint1Builder();
+                tp1Bldr.setTpType(OpenroadmTpType.SRGTXRXPP);
+                tempTpBldr.addAugmentation(TerminationPoint1.class, tp1Bldr.build());
+                tpList.add(tempTpBldr.build());
+            }
+        }
+
+        org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder tpNode1 =
+            new org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1Builder();
+
+        tpNode1.setTerminationPoint(tpList);
+
+        nodebldr.addAugmentation(
+                org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.yang.ietf.network.topology.rev150608.Node1.class,
+                tpNode1.build());
+
+        return nodebldr;
+    }
+
+    /*
+     * This method will return the TTP ports in the device for a given degree number to be used by the
+     * node to create TTP and CTP termination point on the device
+     */
+    private List<ConnectionPorts> getDegreePorts(String deviceId, Integer degreeCounter) {
+        List<ConnectionPorts> degreeConPorts = new ArrayList<>();
+        LOG.info("Getting Connection ports for Degree Number {}", degreeCounter);
+        InstanceIdentifier<Degree> deviceIID =
+                InstanceIdentifier.create(OrgOpenroadmDevice.class).child(Degree.class, new DegreeKey(degreeCounter));
+
+        Optional<Degree> ordmDegreeObject =
+                this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.CONFIGURATION, deviceIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+
+        if (ordmDegreeObject.isPresent()) {
+            degreeConPorts.addAll(new ArrayList<>(ordmDegreeObject.get().getConnectionPorts()));
+        } else {
+            LOG.info("Device has {} degree", (degreeCounter - 1));
+            return Collections.emptyList();
+        }
+        return degreeConPorts;
+    }
+
+    private int getMaxPp(String deviceId, Integer srgCounter) {
+        int maxPpPorts;
+        LOG.info("Getting max pp ports for Srg Number {}", srgCounter);
+        InstanceIdentifier<SharedRiskGroup> deviceIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
+                .child(SharedRiskGroup.class, new SharedRiskGroupKey(srgCounter));
+        Optional<SharedRiskGroup> ordmSrgObject =
+                this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, deviceIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (ordmSrgObject.isPresent()) {
+            if (ordmSrgObject.get().getMaxAddDropPorts() != null) {
+                maxPpPorts = ordmSrgObject.get().getMaxAddDropPorts();
+            } else {
+                LOG.info("Max add drop ports absent");
+                return -1;
+            }
+        } else {
+            LOG.info("SRG  absent");
+            return -1;
+        }
+        return maxPpPorts;
+    }
+
+    private NodeBuilder createTopoLayerNode(String nodeId) {
+        // Sets the value of Network-ref and Node-ref as a part of the supporting node
+        // attribute
+        SupportingNodeBuilder supportbldr = new SupportingNodeBuilder();
+        supportbldr.setKey(new SupportingNodeKey(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID), new NodeId(nodeId)));
+        supportbldr.setNetworkRef(new NetworkId(NetworkUtils.UNDERLAY_NETWORK_ID));
+        supportbldr.setNodeRef(new NodeId(nodeId));
+        ArrayList<SupportingNode> supportlist = new ArrayList<>();
+        supportlist.add(supportbldr.build());
+        NodeBuilder nodebldr = new NodeBuilder();
+        nodebldr.setSupportingNode(supportlist);
+        return nodebldr;
+    }
+
+    // Return 0 for null/error values
+    // Return 1 for tx
+    // Return 2 for rx
+    // Return 3 for bi-directional
+
+    private int getPortDirection(String deviceId, String circuitPackName, String portName) {
+        InstanceIdentifier<Ports> portIID = InstanceIdentifier.create(OrgOpenroadmDevice.class)
+                .child(CircuitPacks.class, new CircuitPacksKey(circuitPackName))
+                .child(Ports.class, new PortsKey(portName));
+        LOG.info("Fetching Port Direction for port {} at circuit pack {}", portName, circuitPackName);
+        Optional<Ports> portObject =
+                this.deviceTransactionManager.getDataFromDevice(deviceId, LogicalDatastoreType.OPERATIONAL, portIID,
+                        Timeouts.DEVICE_READ_TIMEOUT, Timeouts.DEVICE_READ_TIMEOUT_UNIT);
+        if (portObject.isPresent()) {
+            Ports port = portObject.get();
+            if (port.getPortDirection() != null) {
+                return port.getPortDirection().getIntValue();
+            } else {
+                LOG.warn("Port direction value missing for {} {}", circuitPackName, port.getPortName());
+                return 0;
+            }
+        }
+        return 0;
+    }
+
+    // This method returns a generic termination point builder for a given tpid
+    private TerminationPointBuilder createTpBldr(String tpId) {
+        TerminationPointBuilder tpBldr = new TerminationPointBuilder();
+        TpId tp = new TpId(tpId);
+        TerminationPointKey tpKey = new TerminationPointKey(tp);
+        tpBldr.setKey(tpKey);
+        tpBldr.setTpId(tp);
+        return tpBldr;
+    }
+
+    // This method returns the linkBuilder object for given source and destination
+    public LinkBuilder createLink(String srcNode, String dstNode, String srcTp, String destTp) {
+        LOG.info("creating link for {}-{}", srcNode, dstNode);
+        // Create Destination for link
+        DestinationBuilder dstNodeBldr = new DestinationBuilder();
+        dstNodeBldr.setDestTp(destTp);
+        dstNodeBldr.setDestNode(new NodeId(dstNode));
+        // Create Source for the link
+        SourceBuilder srcNodeBldr = new SourceBuilder();
+        srcNodeBldr.setSourceNode(new NodeId(srcNode));
+        srcNodeBldr.setSourceTp(srcTp);
+        LinkBuilder lnkBldr = new LinkBuilder();
+        // set link builder attribute
+        lnkBldr.setDestination(dstNodeBldr.build());
+        lnkBldr.setSource(srcNodeBldr.build());
+        lnkBldr.setLinkId(LinkIdUtil.buildLinkId(srcNode, srcTp, dstNode, destTp));
+        lnkBldr.setKey(new LinkKey(lnkBldr.getLinkId()));
+        org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder lnk1Bldr =
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1Builder();
+        LinkId oppositeLinkId = LinkIdUtil.getOppositeLinkId(srcNode, srcTp, dstNode, destTp);
+        lnk1Bldr.setOppositeLink(oppositeLinkId);
+        lnkBldr.addAugmentation(org.opendaylight.yang.gen.v1.http.org.openroadm.opposite.links.rev170929.Link1.class,
+                lnk1Bldr.build());
+        return lnkBldr;
+    }
+
+    private List<Link> createExpressLinks(String nodeId, int numOfDegrees, int portDirectionEnum) {
+        LOG.info("creating express links {} {} {}", nodeId, numOfDegrees, portDirectionEnum);
+        List<Link> links = new ArrayList<>();
+
+        String srcNode;
+        String destNode;
+
+        String srcTp;
+        String destTp;
+
+        // ports are uni-directional
+        if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) {
+            LOG.info("creating uni-directional express links");
+            for (int i = 1; i <= numOfDegrees; i++) {
+                for (int j = i + 1; j <= numOfDegrees; j++) {
+
+                    srcNode = nodeId + "-DEG" + i;
+                    destNode = nodeId + "-DEG" + j;
+
+                    // AtoZ direction
+                    srcTp = "DEG" + i + "-CTP-TX";
+                    destTp = "DEG" + j + "-CTP-RX";
+
+                    LinkBuilder expLinkBldr = createLink(srcNode, destNode, srcTp, destTp);
+
+                    Link1Builder lnk1Bldr = new Link1Builder();
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.EXPRESSLINK);
+                    expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+
+                    links.add(expLinkBldr.build());
+
+                    // ZtoA direction
+                    srcTp = "DEG" + i + "-CTP-RX";
+                    destTp = "DEG" + j + "-CTP-TX";
+
+                    expLinkBldr = createLink(destNode, srcNode, destTp, srcTp);
+                    expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+
+                    links.add(expLinkBldr.build());
+
+                }
+            }
+        }
+
+        // ports are bi-directional
+        if (portDirectionEnum == 3) {
+            LOG.info("creating bi-directional express links");
+            for (int i = 1; i <= numOfDegrees; i++) {
+                for (int j = i + 1; j <= numOfDegrees; j++) {
+
+                    srcNode = nodeId + "-DEG" + i;
+                    destNode = nodeId + "-DEG" + j;
+
+                    // AtoZ direction
+                    srcTp = "DEG" + i + "-CTP-TXRX";
+                    destTp = "DEG" + j + "-CTP-TXRX";
+
+                    Link1Builder lnk1Bldr = new Link1Builder();
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.EXPRESSLINK);
+
+
+                    LinkBuilder expLinkBldr = createLink(srcNode, destNode, srcTp, destTp);
+                    expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(expLinkBldr.build());
+
+                    // ZtoA direction
+                    expLinkBldr = createLink(destNode, srcNode, destTp, srcTp);
+                    expLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(expLinkBldr.build());
+                }
+            }
+        }
+        return links;
+    }
+
+    private List<Link> createAddDropLinks(String nodeId, int numOfDegrees, int numOfSrgs,
+            int portDirectionEnum) {
+        LOG.info("creating add-drop links {} {} {} {}", nodeId, numOfDegrees, numOfSrgs, portDirectionEnum);
+        List<Link> links = new ArrayList<>();
+
+        String srcNode;
+        String destNode;
+
+        String srcTp;
+        String destTp;
+
+        // ports are uni-directional
+        if ((portDirectionEnum == 1) || (portDirectionEnum == 2)) {
+            LOG.info("creating uni-directional add-drop links");
+            for (int i = 1; i <= numOfDegrees; i++) {
+                for (int j = 1; j <= numOfSrgs; j++) {
+
+                    srcNode = nodeId + "-DEG" + i;
+                    destNode = nodeId + "-SRG" + j;
+
+                    // drop links
+                    srcTp = "DEG" + i + "-CTP-TX";
+                    destTp = "SRG" + j + "-CP-RX";
+
+                    LinkBuilder addDropLinkBldr = createLink(srcNode, destNode, srcTp, destTp);
+                    Link1Builder lnk1Bldr = new Link1Builder();
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.DROPLINK);
+                    addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(addDropLinkBldr.build());
+
+                    // add links direction
+                    srcTp = "DEG" + i + "-CTP-RX";
+                    destTp = "SRG" + j + "-CP-TX";
+
+                    addDropLinkBldr = createLink(destNode, srcNode, destTp, srcTp);
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.ADDLINK);
+                    addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(addDropLinkBldr.build());
+
+                }
+            }
+        }
+        // ports are bi-directional
+        if (portDirectionEnum == 3) {
+            LOG.info("creating bi-directional add-drop links");
+            for (int i = 1; i <= numOfDegrees; i++) {
+                for (int j = 1; j <= numOfSrgs; j++) {
+
+                    srcNode = nodeId + "-DEG" + i;
+                    destNode = nodeId + "-SRG" + j;
+
+                    // drop links
+                    srcTp = "DEG" + i + "-CTP-TXRX";
+                    destTp = "SRG" + j + "-CP-TXRX";
+
+                    LinkBuilder addDropLinkBldr = createLink(srcNode, destNode, srcTp, destTp);
+                    Link1Builder lnk1Bldr = new Link1Builder();
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.DROPLINK);
+                    addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(addDropLinkBldr.build());
+
+                    // add link
+                    addDropLinkBldr = createLink(destNode, srcNode, destTp, srcTp);
+                    lnk1Bldr.setLinkType(OpenroadmLinkType.ADDLINK);
+                    addDropLinkBldr.addAugmentation(Link1.class, lnk1Bldr.build());
+                    links.add(addDropLinkBldr.build());
+                }
+            }
+        }
+        return links;
+    }
+
+    // This method returns the linkBuilder object for given source and destination
+    public boolean deleteLink(String srcNode, String dstNode, String srcTp, String destTp) {
+        LOG.info("deleting link for {}-{}", srcNode, dstNode);
+        try {
+            InstanceIdentifierBuilder<Link> linkIID = InstanceIdentifier
+                    .builder(Network.class, new NetworkKey(new NetworkId(NetworkUtils.OVERLAY_NETWORK_ID)))
+                    .augmentation(Network1.class)
+                    .child(Link.class, new LinkKey(LinkIdUtil.buildLinkId(srcNode, srcTp, dstNode, destTp)));
+            WriteTransaction wrtx = this.dataBroker.newWriteOnlyTransaction();
+            wrtx.delete(LogicalDatastoreType.CONFIGURATION, linkIID.build());
+            wrtx.submit().get(1, TimeUnit.SECONDS);
+        } catch (InterruptedException | ExecutionException | TimeoutException e) {
+            LOG.error(e.getMessage(), e);
+            return false;
+        }
+        return true;
+    }
+
+    private List<AvailableWavelengths> create96AvalWaveDegree() {
+        List<AvailableWavelengths> waveList = new ArrayList<>();
+
+        for (int i = 1; i < 97; i++) {
+            AvailableWavelengthsBuilder avalBldr = new AvailableWavelengthsBuilder();
+            avalBldr.setIndex((long) i);
+            avalBldr.setKey(new AvailableWavelengthsKey((long) i));
+            waveList.add(avalBldr.build());
+        }
+
+        return waveList;
+    }
+
+    private List<org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes.AvailableWavelengths>
+        create96AvalWaveSrg() {
+
+        List<org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes.AvailableWavelengths>
+            waveList = new ArrayList<>();
+
+        for (int i = 1; i < 97; i++) {
+            org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes
+                .AvailableWavelengthsBuilder avalBldr =
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes
+                    .AvailableWavelengthsBuilder();
+            avalBldr.setIndex((long) i);
+            avalBldr.setKey(
+                new org.opendaylight.yang.gen.v1.http.org.openroadm.srg.rev170929.srg.node.attributes
+                    .AvailableWavelengthsKey((long) i));
+            waveList.add(avalBldr.build());
+        }
+
+        return waveList;
+    }
+}
diff --git a/networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml b/networkmodel/src/main/resources/org/opendaylight/blueprint/networkmodel-blueprint.xml
new file mode 100644 (file)
index 0000000..0264ab2
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!-- Copyright © 2016 Orange 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 -->
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+    odl:use-default-for-reference-types="true">
+
+    <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"
+        odl:type="default" />
+    <reference id="rpcProviderRegistry" interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry" />
+    <reference id="deviceTransactionManager" interface="org.opendaylight.transportpce.common.device.DeviceTransactionManager" />
+    <reference id="openRoadmInterfaces" interface="org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces" />
+    <reference id="portMapping" interface="org.opendaylight.transportpce.common.mapping.PortMapping" />
+
+    <bean id="openRoadmTopology" class="org.opendaylight.transportpce.networkmodel.util.OpenRoadmTopology">
+        <argument ref="dataBroker" />
+        <argument ref="deviceTransactionManager" />
+    </bean>
+
+    <bean id="networkModelService" class="org.opendaylight.transportpce.networkmodel.service.NetworkModelServiceImpl">
+        <argument ref="dataBroker" />
+        <argument ref="linkDiscoveryImpl" />
+        <argument ref="deviceTransactionManager" />
+        <argument ref="openRoadmTopology" />
+        <argument ref="portMapping" />
+    </bean>
+
+    <bean id="provider" class="org.opendaylight.transportpce.networkmodel.NetworkModelProvider"
+        init-method="init" destroy-method="close">
+        <argument ref="dataBroker" />
+        <argument ref="rpcProviderRegistry" />
+        <argument ref="networkutilsServiceImpl" />
+        <argument ref="netconfTopologyListener" />
+        <argument ref="openRoadmTopology" />
+    </bean>
+
+    <bean id="netconfTopologyListener" class="org.opendaylight.transportpce.networkmodel.NetConfTopologyListener">
+        <argument ref="networkModelService" />
+        <argument ref="dataBroker" />
+        <argument ref="linkDiscoveryImpl" />
+        <argument ref="deviceTransactionManager" />
+    </bean>
+
+    <bean id="networkutilsServiceImpl" class="org.opendaylight.transportpce.networkmodel.NetworkUtilsImpl">
+        <argument ref="dataBroker" />
+        <argument ref="openRoadmTopology" />
+    </bean>
+
+    <bean id="linkDiscoveryImpl" class="org.opendaylight.transportpce.networkmodel.R2RLinkDiscovery">
+        <argument ref="dataBroker" />
+        <argument ref="deviceTransactionManager" />
+        <argument ref="openRoadmTopology" />
+        <argument ref="openRoadmInterfaces" />
+   </bean>
+
+    <service ref="networkModelService" interface="org.opendaylight.transportpce.networkmodel.service.NetworkModelService" />
+
+</blueprint>
diff --git a/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java b/networkmodel/src/test/java/org/opendaylight/transportpce/networkmodel/NetworkModelTest.java
new file mode 100644 (file)
index 0000000..5002d57
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Copyright © 2017 AT&T 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.networkmodel;
+
+import org.junit.Test;
+
+public class NetworkModelTest {
+    @Test
+    public void init() throws Exception {
+        //TODO implement test
+    }
+
+}
diff --git a/pom.xml b/pom.xml
index 67eb9b846cfbd387458f61eba3be6b8663d2f53c..747bdde8993a0982b756a396ec44d6b8874d35df 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,8 @@ and is available at http://www.eclipse.org/legal/epl-v10.html INTERNAL
     <module>api</module>
     <module>common</module>
     <module>renderer</module>
+    <module>inventory</module>
+    <module>networkmodel</module>
     <module>olm</module>
     <module>tests</module>
     <module>servicehandler</module>
diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/RendererNotificationsImpl.java
deleted file mode 100644 (file)
index c0dd38e..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright © 2017 AT&T 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.renderer;
-
-import com.google.common.base.Preconditions;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.Optional;
-import java.util.Set;
-import java.util.stream.Collectors;
-
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.DataObjectModification;
-import org.opendaylight.controller.md.sal.binding.api.DataObjectModification.ModificationType;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeChangeListener;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeIdentifier;
-import org.opendaylight.controller.md.sal.binding.api.DataTreeModification;
-import org.opendaylight.controller.md.sal.binding.api.MountPoint;
-import org.opendaylight.controller.md.sal.binding.api.MountPointService;
-import org.opendaylight.controller.md.sal.binding.api.NotificationService;
-import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
-import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
-import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
-import org.opendaylight.transportpce.common.mapping.PortMapping;
-import org.opendaylight.transportpce.renderer.listeners.AlarmNotificationListener;
-import org.opendaylight.transportpce.renderer.listeners.DeOperationsListener;
-import org.opendaylight.transportpce.renderer.listeners.DeviceListener;
-import org.opendaylight.transportpce.renderer.listeners.LldpListener;
-import org.opendaylight.transportpce.renderer.listeners.TcaListener;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.de.operations.rev161014.OrgOpenroadmDeOperationsListener;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.device.rev170206.OrgOpenroadmDeviceListener;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.tca.rev161014.OrgOpenroadmTcaListener;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.CreateSubscriptionInputBuilder;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.NotificationsService;
-import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.notification._1._0.rev080714.StreamNameType;
-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.network.topology.topology.topology.types.TopologyNetconf;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NetworkTopology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.NodeId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.TopologyId;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.Topology;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.TopologyKey;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.Node;
-import org.opendaylight.yang.gen.v1.urn.tbd.params.xml.ns.yang.network.topology.rev131021.network.topology.topology.NodeKey;
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.KeyedInstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class RendererNotificationsImpl implements DataTreeChangeListener<Node> {
-    private final DataBroker dataBroker;
-    private final MountPointService mountService;
-    private static final Logger LOG = LoggerFactory.getLogger(RendererNotificationsImpl.class);
-    private ListenerRegistration<RendererNotificationsImpl> dataTreeChangeListenerRegistration;
-    private final PortMapping portMapping;
-    private final DeviceTransactionManager deviceTransactionManager;
-    private final Set<String> currentMountedDevice;
-    public static final InstanceIdentifier<Topology> NETCONF_TOPO_IID = InstanceIdentifier.create(NetworkTopology.class)
-        .child(Topology.class, new TopologyKey(new TopologyId(TopologyNetconf.QNAME.getLocalName())));
-
-    LoadingCache<String, KeyedInstanceIdentifier<Node, NodeKey>> mountIds = CacheBuilder.newBuilder().maximumSize(20)
-        .build(new CacheLoader<String, KeyedInstanceIdentifier<Node, NodeKey>>() {
-            @Override
-            public KeyedInstanceIdentifier<Node, NodeKey> load(final String key) {
-                return NETCONF_TOPO_IID.child(Node.class, new NodeKey(new NodeId(key)));
-            }
-        });
-
-    public RendererNotificationsImpl(final DataBroker dataBroker, final MountPointService mountService,
-        Set<String> currentMountedDevice, PortMapping portMapping,DeviceTransactionManager deviceTransactionManager) {
-        this.dataBroker = dataBroker;
-        this.mountService = mountService;
-        this.currentMountedDevice = currentMountedDevice;
-        this.portMapping = portMapping;
-        this.deviceTransactionManager = deviceTransactionManager;
-        if (portMapping == null) {
-            LOG.error("Portmapping is null !");
-        }
-        if (deviceTransactionManager == null) {
-            LOG.error("deviceTransactionManager is null");
-        }
-        if (mountService == null) {
-            LOG.error("Mount service is null");
-        }
-        if (dataBroker != null) {
-            this.dataTreeChangeListenerRegistration = dataBroker.registerDataTreeChangeListener(
-                new DataTreeIdentifier<>(LogicalDatastoreType.OPERATIONAL, NETCONF_TOPO_IID.child(Node.class)), this);
-        }
-    }
-
-    private void registerNotificationListener(final String nodeId) {
-
-        LOG.info("onDeviceConnected: {}", nodeId);
-        Optional<MountPoint> mountPointOpt = this.deviceTransactionManager.getDeviceMountPoint(nodeId);
-        MountPoint mountPoint;
-        if (mountPointOpt.isPresent()) {
-            mountPoint = mountPointOpt.get();
-        } else {
-            LOG.error("Failed to get mount point for node {}", nodeId);
-            return;
-        }
-
-        final Optional<NotificationService> notificationService =
-                mountPoint.getService(NotificationService.class).toJavaUtil();
-        if (!notificationService.isPresent()) {
-            LOG.error("Failed to get RpcService for node {}", nodeId);
-            return;
-        }
-
-        final OrgOpenroadmAlarmListener alarmListener;
-        alarmListener = new AlarmNotificationListener();
-        LOG.info("Registering notification listener on {} for node: {}", AlarmNotification.QNAME, nodeId);
-        // Register notification listener
-
-        final OrgOpenroadmDeOperationsListener deOperationsListener;
-        deOperationsListener = new DeOperationsListener();
-        LOG.info("Registering notification listener on OrgOpenroadmDeOperationsListener for node: {}", nodeId);
-        // Register notification listener
-
-        final OrgOpenroadmDeviceListener deviceListener;
-        deviceListener = new DeviceListener();
-        LOG.info("Registering notification listener on OrgOpenroadmDeviceListener for node: {}", nodeId);
-        // Register notification listener
-
-        final OrgOpenroadmLldpListener lldpListener;
-        lldpListener = new LldpListener();
-        LOG.info("Registering notification listener on OrgOpenroadmLldpListener for node: {}", nodeId);
-        // Register notification listener
-
-        final OrgOpenroadmTcaListener tcaListener;
-        tcaListener = new TcaListener();
-        LOG.info("Registering notification listener on OrgOpenroadmTcaListener for node: {}", nodeId);
-        // Register notification listener
-
-        // Listening to NETCONF datastream
-        final String streamName = "NETCONF";
-        final Optional<RpcConsumerRegistry> service = mountPoint.getService(RpcConsumerRegistry.class).toJavaUtil();
-        if (!service.isPresent()) {
-            LOG.error("Failed to get RpcService for node {}", nodeId);
-        }
-
-        final NotificationsService rpcService = service.get().getRpcService(NotificationsService.class);
-        final CreateSubscriptionInputBuilder createSubscriptionInputBuilder = new CreateSubscriptionInputBuilder();
-        createSubscriptionInputBuilder.setStream(new StreamNameType(streamName));
-        LOG.info("Triggering notification stream {} for node {}", streamName, nodeId);
-
-    }
-
-    public void close() {
-        LOG.info("RenderernotificationsImpl Closed");
-        // Clean up the Data Change Listener registration
-        if (this.dataTreeChangeListenerRegistration != null) {
-            this.dataTreeChangeListenerRegistration.close();
-        }
-    }
-
-    @Override
-    public void onDataTreeChanged(Collection<DataTreeModification<Node>> changes) {
-
-        for (DataTreeModification<Node> change : changes) {
-
-            DataObjectModification<Node> rootNode = change.getRootNode();
-            NetconfNode nnode = null;
-            String nodeId = new String();
-            if (rootNode.getDataAfter() != null) {
-                nnode = Preconditions.checkNotNull(rootNode.getDataAfter().getAugmentation(NetconfNode.class),
-                    "Node not connected via Netconf protocol");
-                nodeId = rootNode.getDataAfter().getKey().getNodeId().getValue();
-            }
-
-            if (rootNode.getModificationType() == ModificationType.DELETE) {
-                String nodeid = rootNode.getDataBefore().getKey().getNodeId().getValue();
-                LOG.info("Node {} removed...", nodeid);
-                this.portMapping.deleteMappingData(nodeid);
-            }
-
-            if (nnode != null) {
-                if (nodeId.equals("controller-config")) {
-                    // We shouldn't process controller-config as an OpenROAM device
-                    LOG.info("{} ignored: org-openroadm-device advertised but not a real ROADM device", nodeId);
-                    return;
-                }
-                if ((rootNode.getModificationType() == ModificationType.WRITE) ||
-                        (rootNode.getModificationType() == ModificationType.SUBTREE_MODIFIED)) {
-                    LOG.info("Node added or modified {}", nodeId);
-                    ConnectionStatus csts = nnode.getConnectionStatus();
-
-                    switch (csts) {
-                        case Connected: {
-                            LOG.info("NETCONF Node: {} is fully connected", nodeId);
-                            List<String> capabilities = nnode.getAvailableCapabilities().getAvailableCapability()
-                                .stream().map(cp -> cp.getCapability()).collect(Collectors.toList());
-                            LOG.info("Capabilities: {}", capabilities);
-                            /*
-                             * TODO: check for required capabilities to listen
-                             * for notifications
-                             */
-                            registerNotificationListener(nodeId);
-                            this.currentMountedDevice.add(nodeId);
-                            this.portMapping.createMappingData(nodeId);
-                            break;
-                        }
-                        case Connecting: {
-                            LOG.info("NETCONF Node: {} is (dis)connecting", nodeId);
-                            break;
-                        }
-                        case UnableToConnect: {
-                            LOG.info("NETCONF Node: {} connection failed", nodeId);
-                            break;
-                        }
-                        default:
-                            LOG.warn("Unexpected connection status {}", csts.getName());
-                    }
-                }
-            }
-        }
-        LOG.info("Netconf devices currently mounted are : {}", this.currentMountedDevice.toString());
-    }
-}
index 4729514532aa0e65c0b0f848ac741bb72c9ef32a..69dad3864565ebef98c839252226ebacf4138ba0 100644 (file)
@@ -7,15 +7,8 @@
  */
 package org.opendaylight.transportpce.renderer;
 
-import java.util.HashSet;
-import java.util.Set;
-
-import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.binding.api.MountPointService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.RpcRegistration;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
-import org.opendaylight.transportpce.common.device.DeviceTransactionManager;
-import org.opendaylight.transportpce.common.mapping.PortMapping;
 import org.opendaylight.transportpce.renderer.provisiondevice.RendererServiceOperations;
 import org.opendaylight.transportpce.renderer.rpcs.DeviceRendererRPCImpl;
 import org.opendaylight.transportpce.renderer.rpcs.TransportPCEServicePathRPCImpl;
@@ -27,30 +20,17 @@ import org.slf4j.LoggerFactory;
 public class RendererProvider {
 
     private static final Logger LOG = LoggerFactory.getLogger(RendererProvider.class);
-    private final DataBroker dataBroker;
-    private final MountPointService mountPointService;
     private final RpcProviderRegistry rpcProviderRegistry;
-    private final PortMapping portMapping;
-    private final DeviceTransactionManager deviceTransactionManager;
     private RpcRegistration<RendererService> deviceRendererRegistration;
     private DeviceRendererRPCImpl deviceRendererRPCImpl;
     private RpcRegistration<TransportpceServicepathService> tpceServiceRegistry;
     private RendererServiceOperations rendererServiceOperations;
-    private RendererNotificationsImpl rendererNotificationsImpl;
-    private final Set<String> currentMountedDevice;
 
     public RendererProvider(RpcProviderRegistry rpcProviderRegistry, DeviceRendererRPCImpl deviceRendererRPCImpl,
-                            RendererServiceOperations rendererServiceOperations,DataBroker dataBroker,
-                            MountPointService mountPointService, PortMapping portMapping,
-                            DeviceTransactionManager deviceTransactionManager) {
+                            RendererServiceOperations rendererServiceOperations) {
         this.rpcProviderRegistry = rpcProviderRegistry;
         this.deviceRendererRPCImpl = deviceRendererRPCImpl;
         this.rendererServiceOperations = rendererServiceOperations;
-        this.dataBroker = dataBroker;
-        this.mountPointService = mountPointService;
-        this.currentMountedDevice = new HashSet<>();
-        this.portMapping = portMapping;
-        this.deviceTransactionManager = deviceTransactionManager;
     }
 
     /**
@@ -64,8 +44,6 @@ public class RendererProvider {
                 .addRpcImplementation(RendererService.class, this.deviceRendererRPCImpl);
         this.tpceServiceRegistry = this.rpcProviderRegistry
                 .addRpcImplementation(TransportpceServicepathService.class, transportPCEServicePathRPCImpl);
-        this.rendererNotificationsImpl = new RendererNotificationsImpl(this.dataBroker, this.mountPointService,
-                this.currentMountedDevice,this.portMapping,this.deviceTransactionManager);
     }
 
     /**
@@ -79,10 +57,6 @@ public class RendererProvider {
         if (this.tpceServiceRegistry != null) {
             this.tpceServiceRegistry.close();
         }
-        // Clean up the RendererNotificationsImpl
-        if (this.rendererNotificationsImpl != null) {
-            this.rendererNotificationsImpl.close();
-        }
     }
 
 }
diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/AlarmNotificationListener.java
deleted file mode 100644 (file)
index 8102abe..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright © 2017 AT&T 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.renderer.listeners;
-
-import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.AlarmNotification;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.alarm.rev161014.OrgOpenroadmAlarmListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class AlarmNotificationListener implements OrgOpenroadmAlarmListener {
-
-    private static final Logger LOG = LoggerFactory.getLogger(AlarmNotificationListener.class);
-
-    /**
-     * Callback for alarm-notification.
-     *
-     * @param notification AlarmNotification object
-     */
-    @Override
-    public void onAlarmNotification(AlarmNotification notification) {
-        LOG.info("Notification {} received {}", AlarmNotification.QNAME, notification);
-    }
-}
\ No newline at end of file
diff --git a/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java b/renderer/src/main/java/org/opendaylight/transportpce/renderer/listeners/LldpListener.java
deleted file mode 100644 (file)
index 7b18f09..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright © 2017 AT&T 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.renderer.listeners;
-
-import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.LldpNbrInfoChange;
-import org.opendaylight.yang.gen.v1.http.org.openroadm.lldp.rev161014.OrgOpenroadmLldpListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class LldpListener implements OrgOpenroadmLldpListener {
-    private static final Logger LOG = LoggerFactory.getLogger(OrgOpenroadmLldpListener.class);
-
-    /**
-     * Callback for lldp-nbr-info-change.
-     *
-     * @param notification LldpNbrInfoChange object
-     */
-    @Override
-    public void onLldpNbrInfoChange(LldpNbrInfoChange notification) {
-
-        LOG.info("Notification {} received {}", LldpNbrInfoChange.QNAME, notification);
-
-    }
-}
\ No newline at end of file
index 2531a426058f400d26ca0f924f5aa9374b091c9c..0405432a3958731efa3b54b42673be63c340bc7c 100644 (file)
@@ -69,7 +69,7 @@ public class RollbackProcessor {
             try {
                 LOG.info("rolling back: {}", task.getId());
                 task.call();
-            //this methode prototype only use the generic Exception and no specific and useable subclasse
+            //this method prototype only uses the generic Exception but no specific and useable subclass
             } catch (Exception e) {
                 LOG.error("ERROR: Rollback task {} has failed", task.getId(), e);
             }
index f5d667642870919b7d78a93a8c0395e2bd8c6d70..fe04922d84e019f2ee2560235369e9eda25023d3 100644 (file)
@@ -13,7 +13,6 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <reference id="dataBroker" interface="org.opendaylight.controller.md.sal.binding.api.DataBroker"
         odl:type="default" />
-  <reference id="mountPointService" interface="org.opendaylight.controller.md.sal.binding.api.MountPointService" />
   <reference id="rpcProviderRegistry" interface="org.opendaylight.controller.sal.binding.api.RpcProviderRegistry" />
   <reference id="deviceTransactionManager" interface="org.opendaylight.transportpce.common.device.DeviceTransactionManager" />
   <reference id="openRoadmInterfaces" interface="org.opendaylight.transportpce.common.openroadminterfaces.OpenRoadmInterfaces" />
@@ -54,13 +53,9 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
 
   <bean id="rendererProvider" class="org.opendaylight.transportpce.renderer.RendererProvider"
         init-method="init" destroy-method="close">
-    <argument ref="dataBroker"/>
-    <argument ref="mountPointService"/>
     <argument ref="rpcProviderRegistry" />
     <argument ref="deviceRendererRPCImpl" />
     <argument ref="rendererServiceOperations" />
-    <argument ref="portMapping" />
-    <argument ref="deviceTransactionManager" />
   </bean>
 
   <service ref="deviceRenderer"