Merge "Add exists method on DOMStoreReadTransaction and DOMDataReadTransaction"
authorTom Pantelis <tpanteli@brocade.com>
Wed, 13 Aug 2014 12:12:10 +0000 (12:12 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Wed, 13 Aug 2014 12:12:10 +0000 (12:12 +0000)
67 files changed:
features/config-netty/pom.xml
features/config-netty/src/main/resources/features.xml
features/config-persister/pom.xml
features/config-persister/src/main/resources/features.xml
features/config/pom.xml
features/config/src/main/resources/features.xml
features/flow/pom.xml [new file with mode: 0644]
features/flow/src/main/resources/features.xml [new file with mode: 0644]
features/mdsal/pom.xml
features/mdsal/src/main/resources/features.xml
features/netconf/pom.xml
features/netconf/src/main/resources/features.xml
features/pom.xml
features/protocol-framework/pom.xml
features/protocol-framework/src/main/resources/features.xml
opendaylight/commons/liblldp/pom.xml [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java [new file with mode: 0644]
opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java [new file with mode: 0644]
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigPusher.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/pom.xml [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/ConfigPusherFeatureActivator.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigSnapshotHolder.java [new file with mode: 0644]
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureServiceCustomizer.java [new file with mode: 0644]
opendaylight/config/pom.xml
opendaylight/distribution/opendaylight-karaf/pom.xml
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml [deleted file]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml [deleted file]
opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml [deleted file]
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/custom.properties
opendaylight/distribution/opendaylight-karaf/src/main/resources/etc/jre.properties
opendaylight/distribution/opendaylight/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTable.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Messages.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java
opendaylight/md-sal/sal-rest-connector-config/pom.xml
opendaylight/md-sal/sal-rest-connector-config/src/main/resources/initial/10-rest-connector.xml
opendaylight/md-sal/topology-lldp-discovery/pom.xml
opendaylight/md-sal/topology-lldp-discovery/src/main/java/org/opendaylight/md/controller/topology/lldp/utils/LLDPDiscoveryUtils.java
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusherImpl.java [moved from opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/ConfigPusher.java with 85% similarity]
opendaylight/netconf/config-persister-impl/src/main/java/org/opendaylight/controller/netconf/persist/impl/osgi/ConfigPersisterActivator.java
opendaylight/netconf/config-persister-impl/src/test/java/org/opendaylight/controller/netconf/persist/impl/osgi/MockedBundleContext.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronPort.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
pom.xml

index 16fd975130592a1975332b6b390dbce2f9f1d614..2f4b4b1e2198bb4e85cd1c66f19fb6e009cf4626 100644 (file)
@@ -7,7 +7,7 @@
     <version>0.2.5-SNAPSHOT</version>
     <relativePath>../../opendaylight/config/</relativePath>
   </parent>
-  <artifactId>config-netty-features</artifactId>
+  <artifactId>features-config-netty</artifactId>
 
   <packaging>pom</packaging>
 
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-persister-features</artifactId>
+      <artifactId>features-config-persister</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netty-event-executor-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netty-threadgroup-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netty-timer-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>threadpool-config-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>threadpool-config-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-netty-config</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index f1b2d1f753f66cf83dd03ddca24cb6155fe7ab33..7f57d8cb84cbb3b5d103799646c8ea787f8e0d88 100644 (file)
@@ -3,7 +3,7 @@
 <features name="odl-config-persister-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-  <repository>mvn:org.opendaylight.controller/config-persister-features/${config.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
   <feature name='odl-config-netty' version='${project.version}'>
     <feature version='${project.version}'>odl-config-netty-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/netty-event-executor-config/${project.version}</bundle>
@@ -12,6 +12,6 @@
     <bundle>mvn:org.opendaylight.controller/threadpool-config-api/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/threadpool-config-impl/${project.version}</bundle>
     <feature version='${project.version}'>odl-config-startup</feature>
-    <configfile finalname="configuration/initial/00-netty.xml">mvn:org.opendaylight.controller/config-netty-config/${config.version}/xml/config</configfile>
+    <configfile finalname="${config.configfile.directory}/${config.netty.configfile}">mvn:org.opendaylight.controller/config-netty-config/${config.version}/xml/config</configfile>
   </feature>
 </features>
\ No newline at end of file
index ec1520ed9818eb573942cde1ac6561110d2cb44f..6dc894134546fabde2a2d7ef2bf71d0673fab5b0 100644 (file)
@@ -7,7 +7,7 @@
     <version>0.2.5-SNAPSHOT</version>
     <relativePath>../../opendaylight/config/</relativePath>
   </parent>
-  <artifactId>config-persister-features</artifactId>
+  <artifactId>features-config-persister</artifactId>
 
   <packaging>pom</packaging>
 
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>netconf-features</artifactId>
+      <artifactId>features-netconf</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-features</artifactId>
+      <artifactId>features-config</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-persister-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-persister-file-xml-adapter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-persister-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-persister-feature-adapter</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-mapping-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>commons-io</groupId>
+      <artifactId>commons-io</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.moxy</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index 2273a4a3091db030bfd967e434234066c6ffcc62..a3c005b3bd8937425420c1eff652e89262657225 100644 (file)
@@ -4,22 +4,20 @@
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
-  <repository>mvn:org.opendaylight.controller/netconf-features/${netconf.version}/xml/features</repository>
-  <repository>mvn:org.opendaylight.controller/config-features/${config.version}/xml/features</repository>
-  <feature name='odl-config-startup' version='${project.version}'>
-    <feature version='${project.version}'>odl-config-netconf-connector</feature>
+  <repository>mvn:org.opendaylight.controller/features-netconf/${netconf.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
+  <feature name='odl-config-all' version='${project.version}'>
     <feature version='${project.version}'>odl-config-persister</feature>
-    <feature version='${project.version}'>odl-netconf-impl</feature>
+    <feature version='${project.version}'>odl-config-startup</feature>
   </feature>
   <feature name='odl-config-persister' version='${project.version}'>
     <feature version='${netconf.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-config-api</feature>
-    <feature version='${yangtools.version}'>yangtools-binding-generator</feature>
+    <feature version='${yangtools.version}'>odl-yangtools-binding-generator</feature>
     <bundle>mvn:org.opendaylight.controller/config-persister-api/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/config-persister-file-xml-adapter/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller/config-persister-directory-xml-adapter/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/config-persister-impl/${project.version}</bundle>
-
+    <bundle>mvn:org.opendaylight.controller/config-persister-feature-adapter/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/netconf-util/${netconf.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/netconf-mapping-api/${netconf.version}</bundle>
 
@@ -29,4 +27,9 @@
     <bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.core/${eclipse.persistence.version}</bundle>
     <bundle>mvn:org.eclipse.persistence/org.eclipse.persistence.moxy/${eclipse.persistence.version}</bundle>
   </feature>
-</features>
\ No newline at end of file
+  <feature name='odl-config-startup' version='${project.version}'>
+    <feature version='${project.version}'>odl-config-netconf-connector</feature>
+    <feature version='${project.version}'>odl-config-persister</feature>
+    <feature version='${project.version}'>odl-netconf-impl</feature>
+  </feature>
+</features>
index 7e5dd6472bc7320a6b7c20953c811fb41982cb26..c69e11bed2c91e2a08d936dbffad02c601b12d7f 100644 (file)
@@ -7,7 +7,7 @@
     <version>0.2.5-SNAPSHOT</version>
     <relativePath>../../opendaylight/config/</relativePath>
   </parent>
-  <artifactId>config-features</artifactId>
+  <artifactId>features-config</artifactId>
 
   <packaging>pom</packaging>
 
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-common-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netty-config-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>yang-jmx-generator</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>shutdown-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>shutdown-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.osgi</groupId>
+      <artifactId>org.osgi.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-manager</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index de5b198173f6c88da2c5983c2b2daae9c989ea6d..6c0d32427da9508ccd39463e89e716e603bd2101 100644 (file)
@@ -5,45 +5,52 @@
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
   <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
 
-  <feature name='odl-config-core' version='${project.version}'>
-    <feature version='${yangtools.version}'>yangtools-concepts</feature>
-    <feature version='${yangtools.version}'>yangtools-binding</feature>
-    <feature version='${yangtools.version}'>yangtools-binding-generator</feature>
-    <feature version='${mdsal.version}'>odl-mdsal-commons</feature>
-    <feature version='${project.version}'>odl-config-api</feature>
-    <bundle>mvn:org.opendaylight.controller/config-util/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller/yang-jmx-generator/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller/shutdown-api/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller/shutdown-impl/${project.version}</bundle>
-    <bundle>mvn:org.osgi/org.osgi.core/${osgi.core.version}</bundle>
-    <bundle>mvn:com.google.guava/guava/${guava.version}</bundle>
-    <bundle>mvn:org.javassist/javassist/${javassist.version}</bundle>
+  <feature name='odl-config-all' version='${project.version}'>
+    <feature version='${project.version}'>odl-mdsal-common</feature>
+      <feature version='${project.version}'>odl-config-api</feature>
+      <feature version='${project.version}'>odl-config-netty-config-api</feature>
+      <feature version='${project.version}'>odl-config-core</feature>
+      <feature version='${project.version}'>odl-config-manager</feature>
   </feature>
-  <feature name='odl-config-manager' version='${project.version}'>
-    <feature version='${project.version}'>odl-config-core</feature>
-    <bundle>mvn:org.opendaylight.controller/config-manager/${project.version}</bundle>
+
+  <feature name='odl-mdsal-common' version='${mdsal.version}'>
+      <feature version='${yangtools.version}'>odl-yangtools-data-binding</feature>
+      <bundle>mvn:org.opendaylight.controller/sal-common/${mdsal.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal-common-api/${mdsal.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal-common-impl/${mdsal.version}</bundle>
+      <bundle>mvn:org.opendaylight.controller/sal-common-util/${mdsal.version}</bundle>
   </feature>
 
   <feature name='odl-config-api' version='${project.version}'>
     <bundle>mvn:org.opendaylight.controller/config-api/${project.version}</bundle>
-
-    <!-- yangtools features -->
-    <feature version='${yangtools.version}'>yangtools-concepts</feature>
-    <feature version='${yangtools.version}'>yangtools-binding</feature>
+    <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+    <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
   </feature>
 
   <feature name='odl-config-netty-config-api' version='${project.version}'>
+    <feature version='${project.version}'>odl-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/netty-config-api/${project.version}</bundle>
-
-    <!-- netty bundles -->
     <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
     <bundle>mvn:io.netty/netty-common/${netty.version}</bundle>
     <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
+  </feature>
 
+  <feature name='odl-config-core' version='${project.version}'>
+    <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+    <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
+    <feature version='${yangtools.version}'>odl-yangtools-binding-generator</feature>
+    <feature version='${mdsal.version}'>odl-mdsal-common</feature>
     <feature version='${project.version}'>odl-config-api</feature>
+    <bundle>mvn:org.opendaylight.controller/config-util/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.controller/yang-jmx-generator/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.controller/shutdown-api/${project.version}</bundle>
+    <bundle>mvn:org.opendaylight.controller/shutdown-impl/${project.version}</bundle>
+    <bundle>mvn:org.osgi/org.osgi.core/${osgi.core.version}</bundle>
+    <bundle>mvn:com.google.guava/guava/${guava.version}</bundle>
+    <bundle>mvn:org.javassist/javassist/${javassist.version}</bundle>
   </feature>
-  <feature name='odl-config-dispatcher' version='${project.version}'>
-      <bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${project.version}</bundle>
+  <feature name='odl-config-manager' version='${project.version}'>
+    <feature version='${project.version}'>odl-config-core</feature>
+    <bundle>mvn:org.opendaylight.controller/config-manager/${project.version}</bundle>
   </feature>
-
 </features>
\ No newline at end of file
diff --git a/features/flow/pom.xml b/features/flow/pom.xml
new file mode 100644 (file)
index 0000000..09bb6c9
--- /dev/null
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>sal-parent</artifactId>
+    <version>1.1-SNAPSHOT</version>
+    <relativePath>../../opendaylight/md-sal</relativePath>
+  </parent>
+  <artifactId>features-flow</artifactId>
+
+  <packaging>pom</packaging>
+
+  <properties>
+    <features.file>features.xml</features.file>
+  </properties>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-mdsal</artifactId>
+      <version>${mdsal.version}</version>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-base</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-service</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-flow-statistics</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-inventory</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-topology</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.md</groupId>
+      <artifactId>topology-manager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.md</groupId>
+      <artifactId>topology-lldp-discovery</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.md</groupId>
+      <artifactId>statistics-manager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.md</groupId>
+      <artifactId>inventory-manager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.md</groupId>
+      <artifactId>forwardingrules-manager</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <resources>
+      <resource>
+        <filtering>true</filtering>
+        <directory>src/main/resources</directory>
+      </resource>
+    </resources>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-resources-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>filter</id>
+            <goals>
+              <goal>resources</goal>
+            </goals>
+            <phase>generate-resources</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/${features.file}</file>
+                  <type>xml</type>
+                  <classifier>features</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
+  </scm>
+</project>
diff --git a/features/flow/src/main/resources/features.xml b/features/flow/src/main/resources/features.xml
new file mode 100644 (file)
index 0000000..3f914be
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<features name="odl-flow-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+   xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.controller/features-mdsal/${mdsal.version}/xml/features</repository>
+    <feature name='odl-flow-model' version='${project.version}'>
+        <feature version='${yangtools.version}'>odl-yangtools-models</feature>
+        <bundle>mvn:org.opendaylight.controller.model/model-flow-base/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.model/model-flow-service/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.model/model-flow-statistics/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.model/model-inventory/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.model/model-topology/${project.version}</bundle>
+    </feature>
+    <feature name='odl-flow-services' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <feature version='${project.version}'>odl-flow-model</feature>
+        <bundle>mvn:org.opendaylight.controller.md/topology-manager/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.md/topology-lldp-discovery/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.md/statistics-manager/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.md/inventory-manager/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.md/forwardingrules-manager/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller/liblldp/${sal.version}</bundle>
+    </feature>
+
+</features>
index 2983c5efab8fb21031991fe6af248032eb842365..4f1ba98e5c5d4f60cc4d0a5a2fcbe7c06706d429 100644 (file)
@@ -7,7 +7,7 @@
     <version>1.1-SNAPSHOT</version>
     <relativePath>../../opendaylight/md-sal</relativePath>
   </parent>
-  <artifactId>mdsal-features</artifactId>
+  <artifactId>features-mdsal</artifactId>
 
   <packaging>pom</packaging>
 
     <features.file>features.xml</features.file>
   </properties>
 
-  <dependencies></dependencies>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>features-yangtools</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-config</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-config-persister</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-config-netty</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-core-spi</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-broker-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-broker-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-binding-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-connector-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-inmemory-datastore</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>md-sal-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-netconf-connector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.model</groupId>
+      <artifactId>model-inventory</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-config-dispatcher</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-connector-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-rest-connector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.google.code.gson</groupId>
+      <artifactId>gson</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-server</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>com.sun.jersey.jersey-servlet</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec-http</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-remote</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-rest-connector-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.samples</groupId>
+      <artifactId>sample-toaster</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.samples</groupId>
+      <artifactId>sample-toaster-provider</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.samples</groupId>
+      <artifactId>sample-toaster-consumer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.samples</groupId>
+      <artifactId>toaster-config</artifactId>
+    </dependency>
+  </dependencies>
 
   <build>
     <resources>
index 7d393bc64cdc7aab9056043d8b1f852260dcfe27..a3d7ed0f83df6455006a4c94dbb52283d1438461 100644 (file)
@@ -1,28 +1,24 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
-<features name="mdsal-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
+<features name="odl-mdsal-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
+    <repository>mvn:org.opendaylight.yangtools/features-yangtools/${yangtools.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-config-persister/${config.version}/xml/features</repository>
+    <repository>mvn:org.opendaylight.controller/features-config-netty/${config.version}/xml/features</repository>
     <feature name='odl-mdsal-all' version='${project.version}'>
-        <feature version='${project.version}'>odl-mdsal-commons</feature>
         <feature version='${project.version}'>odl-mdsal-broker</feature>
-        <feature version='${project.version}'>odl-mdsal-restconf</feature>
-    </feature>
-    <feature name='odl-mdsal-commons' version='${project.version}'>
-        <feature version='${yangtools.version}'>yangtools-data-binding</feature>
-        <bundle>mvn:org.opendaylight.controller/sal-common/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller/sal-common-api/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller/sal-common-impl/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller/sal-common-util/${project.version}</bundle>
+        <feature version='${project.version}'>odl-mdsal-netconf-connector</feature>
+        <feature version='${project.version}'>odl-restconf</feature>
+        <feature version='${project.version}'>odl-toaster</feature>
     </feature>
     <feature name='odl-mdsal-broker' version='${project.version}'>
-        <feature version='${yangtools.version}'>yangtools-concepts</feature>
-        <feature version='${yangtools.version}'>yangtools-binding</feature>
-        <feature version='${mdsal.version}'>odl-mdsal-commons</feature>
-        <feature version='${config.version}'>odl-config-core</feature>
-        <feature version='${config.version}'>odl-config-manager</feature>
-        <feature version='${config.version}'>odl-config-api</feature>
-        <feature version='${config.version}'>odl-config-persister</feature>
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
+        <feature version='${mdsal.version}'>odl-mdsal-common</feature>
+        <feature version='${config.version}'>odl-config-startup</feature>
+        <feature version='${config.version}'>odl-config-netty</feature>
         <bundle>mvn:org.opendaylight.controller/sal-core-api/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-core-spi/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-broker-impl/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-binding-util/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-connector-api/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller/sal-inmemory-datastore/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.mdsal.configfile}">mvn:org.opendaylight.controller/md-sal-config/${mdsal.version}/xml/config</configfile>
+    </feature>
+    <feature name='odl-mdsal-netconf-connector' version='${project.version}'>
+        <feature version='${project.version}'>odl-mdsal-broker</feature>
+        <feature version='${netconf.version}'>odl-netconf-client</feature>
+        <feature version='${yangtools.version}'>odl-yangtools-models</feature>
+        <bundle>mvn:org.opendaylight.controller/sal-netconf-connector/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller.model/model-inventory/${project.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller/netconf-config-dispatcher/${config.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.netconf.connector.configfile}">mvn:org.opendaylight.controller/netconf-connector-config/${netconf.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-mdsal-restconf' version='${project.version}'>
+    <feature name='odl-restconf' version='${project.version}'>
         <feature version='${mdsal.version}'>odl-mdsal-broker</feature>
+        <feature>war</feature>
         <bundle>mvn:org.opendaylight.controller/sal-rest-connector/${project.version}</bundle>
-        <bundle>wrap:mvn:com.google.code.gson/gson/${gson.version}</bundle>
-        <bundle>wrap:mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
-        <bundle>wrap:mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
+        <bundle>mvn:com.google.code.gson/gson/${gson.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-core/${jersey.version}</bundle>
+        <bundle>mvn:com.sun.jersey/jersey-server/${jersey.version}</bundle>
         <bundle>mvn:org.opendaylight.controller.thirdparty/com.sun.jersey.jersey-servlet/${jersey.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-buffer/${netty.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-codec/${netty.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-codec-http/${netty.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-common/${netty.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-handler/${netty.version}</bundle>
-        <bundle>wrap:mvn:io.netty/netty-transport/${netty.version}</bundle>
-    </feature>
-    <feature name='odl-mdsal-model' version='${project.version}'>
-        <bundle>mvn:org.opendaylight.controller.model/model-flow-base/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.model/model-flow-management/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.model/model-flow-service/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.model/model-flow-statistics/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.model/model-inventory/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.model/model-topology/${project.version}</bundle>
+        <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
+        <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
+        <bundle>mvn:io.netty/netty-codec-http/${netty.version}</bundle>
+        <bundle>mvn:io.netty/netty-common/${netty.version}</bundle>
+        <bundle>mvn:io.netty/netty-handler/${netty.version}</bundle>
+        <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
+        <bundle>mvn:org.opendaylight.controller/sal-remote/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.restconf.configfile}">mvn:org.opendaylight.controller/sal-rest-connector-config/${mdsal.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-mdsal-toaster' version='${project.version}'>
-        <feature version='${yangtools.version}'>yangtools-concepts</feature>
-        <feature version='${yangtools.version}'>yangtools-binding</feature>
+    <feature name='odl-toaster' version='${project.version}'>
+        <feature version='${yangtools.version}'>odl-yangtools-common</feature>
+        <feature version='${yangtools.version}'>odl-yangtools-binding</feature>
         <feature version='${project.version}'>odl-mdsal-broker</feature>
-        <feature version='${project.version}'>odl-mdsal-all</feature>
         <bundle>mvn:org.opendaylight.controller.samples/sample-toaster/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller.samples/sample-toaster-consumer/${project.version}</bundle>
         <bundle>mvn:org.opendaylight.controller.samples/sample-toaster-provider/${project.version}</bundle>
+        <configfile finalname="${config.configfile.directory}/${config.toaster.configfile}">mvn:org.opendaylight.controller.samples/toaster-config/${project.version}/xml/config</configfile>
     </feature>
-    <feature name='odl-mdsal-misc' version='${project.version}'>
-        <bundle>mvn:org.opendaylight.controller/sal-netconf-connector/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller/sal-restconf-broker/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller/sal-remote/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.md/topology-manager/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.md/topology-lldp-discovery/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.md/statistics-manager/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.md/inventory-manager/${project.version}</bundle>
-        <bundle>mvn:org.opendaylight.controller.md/forwardingrules-manager/${project.version}</bundle>
-    </feature>
-
 </features>
index 856557c1e8245ef24ada6cdb63e9ad4c775b696e..956a67e28b3652d05ebb0547d5e3e456bc135dbd 100644 (file)
@@ -7,7 +7,7 @@
     <version>0.2.5-SNAPSHOT</version>
     <relativePath>../../opendaylight/netconf</relativePath>
   </parent>
-  <artifactId>netconf-features</artifactId>
+  <artifactId>features-netconf</artifactId>
 
   <packaging>pom</packaging>
 
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-features</artifactId>
+      <artifactId>features-config</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>features-odl-protocol-framework</artifactId>
+      <artifactId>features-protocol-framework</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>ietf-netconf-monitoring</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>ietf-netconf-monitoring-extension</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-inet-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools.model</groupId>
+      <artifactId>ietf-yang-types</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-mapping-api</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-impl</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>config-netconf-connector</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-netty-util</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller.thirdparty</groupId>
+      <artifactId>ganymed</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.openexi</groupId>
+      <artifactId>nagasena</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-codec</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-common</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-buffer</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-transport</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-client</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-config</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>netconf-monitoring</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index 50a537b50ae2eee799e706e60dd8acfc6985a61d..0033b0d83c7e4bf02aea300b62cf0ee69be350ba 100644 (file)
@@ -3,14 +3,24 @@
 <features name="odl-netconf-${project.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-  <repository>mvn:org.opendaylight.controller/features-odl-protocol-framework/${protocol-framework.version}/xml/features</repository>
-  <repository>mvn:org.opendaylight.controller/config-features/${config.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-protocol-framework/${protocol-framework.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
+  <feature name='odl-netconf-all' version='${project.version}'>
+    <feature version='${project.version}'>odl-netconf-api</feature>
+    <feature version='${project.version}'>odl-netconf-mapping-api</feature>
+    <feature version='${project.version}'>odl-netconf-util</feature>
+    <feature version='${project.version}'>odl-netconf-impl</feature>
+    <feature version='${project.version}'>odl-config-netconf-connector</feature>
+    <feature version='${project.version}'>odl-netconf-netty-util</feature>
+    <feature version='${project.version}'>odl-netconf-client</feature>
+    <feature version='${project.version}'>odl-netconf-monitoring</feature>
+  </feature>
 
   <feature name='odl-netconf-api' version='${project.version}'>
+    <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-api/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller/ietf-netconf-monitoring-extension/${project.version}</bundle>
-    <feature version='${protocol-framework.version}'>odl-protocol-framework</feature>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-inet-types/${ietf-inet-types.version}</bundle>
     <bundle>mvn:org.opendaylight.yangtools.model/ietf-yang-types/${ietf-yang-types.version}</bundle>
   </feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-util/${project.version}</bundle>
   </feature>
-  <feature name='odl-config-netconf-connector' version='${project.version}'>
-    <feature version='${config.version}'>odl-config-manager</feature>
-    <bundle>mvn:org.opendaylight.controller/config-netconf-connector/${project.version}</bundle>
+    <feature name='odl-netconf-impl' version='${project.version}'>
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
-  </feature>
-
-  <feature name='odl-netconf-impl' version='${project.version}'>
+    <feature version='${project.version}'>odl-netconf-netty-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-impl/${project.version}</bundle>
+  </feature>
+  <feature name='odl-config-netconf-connector' version='${project.version}'>
+    <feature version='${config.version}'>odl-config-manager</feature>
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
-    <feature version='${project.version}'>odl-netconf-netty-util</feature>
+    <bundle>mvn:org.opendaylight.controller/config-netconf-connector/${project.version}</bundle>
   </feature>
   <feature name='odl-netconf-netty-util' version='${project.version}'>
-    <bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
     <feature version='${project.version}'>odl-netconf-api</feature>
     <feature version='${project.version}'>odl-netconf-mapping-api</feature>
     <feature version='${project.version}'>odl-netconf-util</feature>
+    <bundle>mvn:org.opendaylight.controller/netconf-netty-util/${project.version}</bundle>
     <bundle>mvn:org.opendaylight.controller.thirdparty/ganymed/${ganymed.version}</bundle>
     <bundle>mvn:org.openexi/nagasena/${exi.nagasena.version}</bundle>
     <bundle>mvn:io.netty/netty-codec/${netty.version}</bundle>
     <bundle>mvn:io.netty/netty-buffer/${netty.version}</bundle>
     <bundle>mvn:io.netty/netty-transport/${netty.version}</bundle>
   </feature>
-  <feature name='odl-netconf-misc' version='${project.version}'>
+  <feature name='odl-netconf-client' version="${project.version}">
+    <feature version='${project.version}'>odl-netconf-netty-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-client/${project.version}</bundle>
+    <configfile finalname="${config.configfile.directory}/${config.netconf.client.configfile}">mvn:org.opendaylight.controller/netconf-config/${netconf.version}/xml/config</configfile>
+  </feature>
+  <feature name='odl-netconf-monitoring' version='${project.version}'>
+    <feature version='${project.version}'>odl-netconf-util</feature>
     <bundle>mvn:org.opendaylight.controller/netconf-monitoring/${project.version}</bundle>
-    <bundle>mvn:org.opendaylight.controller/netconf-tcp/${project.version}</bundle>
   </feature>
 
 </features>
\ No newline at end of file
index f69190cebd4e5bd45fc0d11fc674305f65a0589c..88ed7491a75d922646dcdfcf6f43cad77392be00 100644 (file)
@@ -22,6 +22,7 @@
     <module>config-persister</module>
     <module>config-netty</module>
     <module>mdsal</module>
+    <module>flow</module>
     <module>netconf</module>
     <module>protocol-framework</module>
   </modules>
index ba5dd18fc21615f3e52ddcbbe6f91c2323cc33d5..97836be4552f88e4ad960981ebea186e664a090f 100644 (file)
@@ -7,7 +7,7 @@
     <version>1.4.2-SNAPSHOT</version>
     <relativePath>../../opendaylight/commons/opendaylight</relativePath>
   </parent>
-  <artifactId>features-odl-protocol-framework</artifactId>
+  <artifactId>features-protocol-framework</artifactId>
   <version>${protocol-framework.version}</version>
   <packaging>pom</packaging>
 
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-features</artifactId>
+      <artifactId>features-config</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>protocol-framework</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index d2560f5cb046f3d70a905c37a6ed520ca3854552..6daa3432c14285d8746bcd7385b08e520213f330 100644 (file)
@@ -3,10 +3,10 @@
 <features name="odl-protocol-framework-${protocol-framework.version}" xmlns="http://karaf.apache.org/xmlns/features/v1.2.0"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://karaf.apache.org/xmlns/features/v1.2.0 http://karaf.apache.org/xmlns/features/v1.2.0">
-  <repository>mvn:org.opendaylight.controller/config-features/${config.version}/xml/features</repository>
+  <repository>mvn:org.opendaylight.controller/features-config/${config.version}/xml/features</repository>
   <feature name='odl-protocol-framework' version='${project.version}'>
+    <feature version='${config.version}'>odl-config-api</feature>
+    <feature version='${config.version}'>odl-config-netty-config-api</feature>
     <bundle>mvn:org.opendaylight.controller/protocol-framework/${protocol-framework.version}</bundle>
-    <feature version='${config.version}'>odl-config-api</feature> <!-- needed by netty-config-api -->
-    <feature version='${config.version}'>odl-config-netty-config-api</feature> <!-- needed by netty-config-api -->
   </feature>
 </features>
\ No newline at end of file
diff --git a/opendaylight/commons/liblldp/pom.xml b/opendaylight/commons/liblldp/pom.xml
new file mode 100644 (file)
index 0000000..1551041
--- /dev/null
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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>commons.opendaylight</artifactId>
+    <version>1.4.2-SNAPSHOT</version>
+    <relativePath>../opendaylight</relativePath>
+  </parent>
+
+  <artifactId>liblldp</artifactId>
+  <version>0.8.1-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.slf4j</groupId>
+      <artifactId>slf4j-api</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>org.slf4j,
+              org.apache.commons.lang3.builder,
+              org.apache.commons.lang3.tuple
+            </Import-Package>
+            <Export-Package>
+              org.opendaylight.controller.liblldp</Export-Package>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+  </scm>
+</project>
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BitBufferHelper.java
new file mode 100644 (file)
index 0000000..3eae432
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ *
+ */
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * BitBufferHelper class that provides utility methods to
+ * - fetch specific bits from a serialized stream of bits
+ * - convert bits to primitive data type - like short, int, long
+ * - store bits in specified location in stream of bits
+ * - convert primitive data types to stream of bits
+ */
+public abstract class BitBufferHelper {
+    protected static final Logger logger = LoggerFactory
+    .getLogger(BitBufferHelper.class);
+
+    public static final long ByteMask = 0xFF;
+
+    // Getters
+    // data: array where data are stored
+    // startOffset: bit from where to start reading
+    // numBits: number of bits to read
+    // All this function return an exception if overflow or underflow
+
+    /**
+     * Returns the first byte from the byte array
+     * @param byte[] data
+     * @return byte value
+     */
+    public static byte getByte(byte[] data) {
+        if ((data.length * NetUtils.NumBitsInAByte) > Byte.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        return (data[0]);
+    }
+
+    /**
+     * Returns the short value for the byte array passed.
+     * Size of byte array is restricted to Short.SIZE
+     * @param byte[] data
+     * @return short value
+     */
+    public static short getShort(byte[] data) {
+        if (data.length > Short.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        return (short) toNumber(data);
+    }
+
+    /**
+     * Returns the int value for the byte array passed.
+     * Size of byte array is restricted to Integer.SIZE
+     * @param byte[] data
+     * @return int - the integer value of byte array
+     */
+    public static int getInt(byte[] data) {
+        if (data.length > Integer.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        return (int) toNumber(data);
+    }
+
+    /**
+     * Returns the long value for the byte array passed.
+     * Size of byte array is restricted to Long.SIZE
+     * @param byte[] data
+     * @return long - the integer value of byte array
+     */
+    public static long getLong(byte[] data) {
+        if (data.length > Long.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (Exception e) {
+                logger.error("", e);
+            }
+        }
+        return (long) toNumber(data);
+    }
+
+    /**
+     * Returns the short value for the last numBits of the byte array passed.
+     * Size of numBits is restricted to Short.SIZE
+     * @param byte[] data
+     * @param int - numBits
+     * @return short - the short value of byte array
+     */
+    public static short getShort(byte[] data, int numBits) {
+        if (numBits > Short.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+        byte[] bits = null;
+        try {
+            bits = BitBufferHelper.getBits(data, startOffset, numBits);
+        } catch (BufferException e) {
+            logger.error("", e);
+        }
+        return (short) toNumber(bits, numBits);
+    }
+
+    /**
+     * Returns the int value for the last numBits of the byte array passed.
+     * Size of numBits is restricted to Integer.SIZE
+     * @param byte[] data
+     * @param int - numBits
+     * @return int - the integer value of byte array
+     */
+    public static int getInt(byte[] data, int numBits) {
+        if (numBits > Integer.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+        byte[] bits = null;
+        try {
+            bits = BitBufferHelper.getBits(data, startOffset, numBits);
+        } catch (BufferException e) {
+            logger.error("", e);
+        }
+        return (int) toNumber(bits, numBits);
+    }
+
+    /**
+     * Returns the long value for the last numBits of the byte array passed.
+     * Size of numBits is restricted to Long.SIZE
+     * @param byte[] data
+     * @param int - numBits
+     * @return long - the integer value of byte array
+     */
+    public static long getLong(byte[] data, int numBits) {
+        if (numBits > Long.SIZE) {
+            try {
+                throw new BufferException(
+                        "Container is too small for the number of requested bits");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        if (numBits > data.length * NetUtils.NumBitsInAByte) {
+            try {
+                throw new BufferException(
+                        "Trying to read more bits than contained in the data buffer");
+            } catch (BufferException e) {
+                logger.error("", e);
+            }
+        }
+        int startOffset = data.length * NetUtils.NumBitsInAByte - numBits;
+        byte[] bits = null;
+        try {
+            bits = BitBufferHelper.getBits(data, startOffset, numBits);
+        } catch (BufferException e) {
+            logger.error("", e);
+        }
+        return (long) toNumber(bits, numBits);
+    }
+
+    /**
+     * Reads the specified number of bits from the passed byte array
+     * starting to read from the specified offset
+     * The bits read are stored in a byte array which size is dictated
+     * by the number of bits to be stored.
+     * The bits are stored in the byte array LSB aligned.
+     *
+     * Ex.
+     * Read 7 bits at offset 10
+     * 0         9 10     16 17
+     * 0101000010 | 0000101 | 1111001010010101011
+     * will be returned as {0,0,0,0,0,1,0,1}
+     *
+     * @param byte[] data
+     * @param int startOffset - offset to start fetching bits from data from
+     * @param int numBits - number of bits to be fetched from data
+     * @return byte [] - LSB aligned bits
+     *
+     * @throws BufferException
+     *             when the startOffset and numBits parameters are not congruent
+     *             with the data buffer size
+     */
+    public static byte[] getBits(byte[] data, int startOffset, int numBits)
+            throws BufferException {
+
+        int startByteOffset = 0;
+        int valfromcurr, valfromnext;
+        int extranumBits = numBits % NetUtils.NumBitsInAByte;
+        int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
+        int numBytes = (numBits % NetUtils.NumBitsInAByte != 0) ? 1 + numBits
+                / NetUtils.NumBitsInAByte : numBits / NetUtils.NumBitsInAByte;
+        byte[] shiftedBytes = new byte[numBytes];
+        startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+        byte[] bytes = new byte[numBytes];
+        if (numBits == 0) {
+            return bytes;
+        }
+
+        checkExceptions(data, startOffset, numBits);
+
+        if (extraOffsetBits == 0) {
+            if (extranumBits == 0) {
+                System.arraycopy(data, startByteOffset, bytes, 0, numBytes);
+                return bytes;
+            } else {
+                System.arraycopy(data, startByteOffset, bytes, 0, numBytes - 1);
+                bytes[numBytes - 1] = (byte) ((int) data[startByteOffset
+                        + numBytes - 1] & getMSBMask(extranumBits));
+            }
+        } else {
+            int i;
+            for (i = 0; i < numBits / NetUtils.NumBitsInAByte; i++) {
+                // Reading numBytes starting from offset
+                valfromcurr = (data[startByteOffset + i])
+                        & getLSBMask(NetUtils.NumBitsInAByte - extraOffsetBits);
+                valfromnext = (data[startByteOffset + i + 1])
+                        & getMSBMask(extraOffsetBits);
+                bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
+            }
+            // Now adding the rest of the bits if any
+            if (extranumBits != 0) {
+                if (extranumBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+                    valfromnext = (byte) (data[startByteOffset + i] & ((getMSBMask(extranumBits)) >> extraOffsetBits));
+                    bytes[i] = (byte) (valfromnext << extraOffsetBits);
+                } else if (extranumBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+                    valfromcurr = (data[startByteOffset + i])
+                            & getLSBMask(NetUtils.NumBitsInAByte
+                                    - extraOffsetBits);
+                    bytes[i] = (byte) (valfromcurr << extraOffsetBits);
+                } else {
+                    valfromcurr = (data[startByteOffset + i])
+                            & getLSBMask(NetUtils.NumBitsInAByte
+                                    - extraOffsetBits);
+                    valfromnext = (data[startByteOffset + i + 1])
+                            & (getMSBMask(extranumBits
+                                    - (NetUtils.NumBitsInAByte - extraOffsetBits)));
+                    bytes[i] = (byte) (valfromcurr << (extraOffsetBits) | (valfromnext >> (NetUtils.NumBitsInAByte - extraOffsetBits)));
+                }
+
+            }
+        }
+        // Aligns the bits to LSB
+        shiftedBytes = shiftBitsToLSB(bytes, numBits);
+        return shiftedBytes;
+    }
+
+    // Setters
+    // data: array where data will be stored
+    // input: the data that need to be stored in the data array
+    // startOffset: bit from where to start writing
+    // numBits: number of bits to read
+
+    /**
+     * Bits are expected to be stored in the input byte array from LSB
+     * @param byte[] - data to set the input byte
+     * @param byte - input byte to be inserted
+     * @param startOffset - offset of data[] to start inserting byte from
+     * @param numBits - number of bits of input to be inserted into data[]
+     *
+     * @throws BufferException
+     *             when the input, startOffset and numBits are not congruent
+     *             with the data buffer size
+     */
+    public static void setByte(byte[] data, byte input, int startOffset,
+            int numBits) throws BufferException {
+        byte[] inputByteArray = new byte[1];
+        Arrays.fill(inputByteArray, 0, 1, input);
+        setBytes(data, inputByteArray, startOffset, numBits);
+    }
+
+    /**
+     * Bits are expected to be stored in the input byte array from LSB
+     * @param byte[] - data to set the input byte
+     * @param byte[] - input bytes to be inserted
+     * @param startOffset - offset of data[] to start inserting byte from
+     * @param numBits - number of bits of input to be inserted into data[]
+     * @return void
+     * @throws BufferException
+     *             when the startOffset and numBits parameters are not congruent
+     *             with data and input buffers' size
+     */
+    public static void setBytes(byte[] data, byte[] input, int startOffset,
+            int numBits) throws BufferException {
+        checkExceptions(data, startOffset, numBits);
+        insertBits(data, input, startOffset, numBits);
+    }
+
+    /**
+     * Returns numBits 1's in the MSB position
+     *
+     * @param numBits
+     * @return
+     */
+    public static int getMSBMask(int numBits) {
+        int mask = 0;
+        for (int i = 0; i < numBits; i++) {
+            mask = mask | (1 << (7 - i));
+        }
+        return mask;
+    }
+
+    /**
+     * Returns numBits 1's in the LSB position
+     *
+     * @param numBits
+     * @return
+     */
+    public static int getLSBMask(int numBits) {
+        int mask = 0;
+        for (int i = 0; i < numBits; i++) {
+            mask = mask | (1 << i);
+        }
+        return mask;
+    }
+
+    /**
+     * Returns the numerical value of the byte array passed
+     *
+     * @param byte[] - array
+     * @return long - numerical value of byte array passed
+     */
+    static public long toNumber(byte[] array) {
+        long ret = 0;
+        long length = array.length;
+        int value = 0;
+        for (int i = 0; i < length; i++) {
+            value = array[i];
+            if (value < 0)
+                value += 256;
+            ret = ret
+                    | (long) ((long) value << ((length - i - 1) * NetUtils.NumBitsInAByte));
+        }
+        return ret;
+    }
+
+    /**
+     * Returns the numerical value of the last numBits (LSB bits) of the byte
+     * array passed
+     *
+     * @param byte[] - array
+     * @param int - numBits
+     * @return long - numerical value of byte array passed
+     */
+    static public long toNumber(byte[] array, int numBits) {
+        int length = numBits / NetUtils.NumBitsInAByte;
+        int bitsRest = numBits % NetUtils.NumBitsInAByte;
+        int startOffset = array.length - length;
+        long ret = 0;
+        int value = 0;
+
+        value = array[startOffset - 1] & getLSBMask(bitsRest);
+        value = (array[startOffset - 1] < 0) ? (array[startOffset - 1] + 256)
+                : array[startOffset - 1];
+        ret = ret
+                | (value << ((array.length - startOffset) * NetUtils.NumBitsInAByte));
+
+        for (int i = startOffset; i < array.length; i++) {
+            value = array[i];
+            if (value < 0)
+                value += 256;
+            ret = ret
+                    | (long) ((long) value << ((array.length - i - 1) * NetUtils.NumBitsInAByte));
+        }
+
+        return ret;
+    }
+
+    /**
+     * Accepts a number as input and returns its value in byte form in LSB
+     * aligned form example: input = 5000 [1001110001000] bytes = 19, -120
+     * [00010011] [10001000]
+     *
+     * @param Number
+     * @return byte[]
+     *
+     */
+
+    public static byte[] toByteArray(Number input) {
+        Class<? extends Number> dataType = input.getClass();
+        short size = 0;
+        long longValue = input.longValue();
+
+        if (dataType == Byte.class || dataType == byte.class) {
+            size = Byte.SIZE;
+        } else if (dataType == Short.class || dataType == short.class) {
+            size = Short.SIZE;
+        } else if (dataType == Integer.class || dataType == int.class) {
+            size = Integer.SIZE;
+        } else if (dataType == Long.class || dataType == long.class) {
+            size = Long.SIZE;
+        } else {
+            throw new IllegalArgumentException(
+                    "Parameter must one of the following: Short/Int/Long\n");
+        }
+
+        int length = size / NetUtils.NumBitsInAByte;
+        byte bytes[] = new byte[length];
+
+        // Getting the bytes from input value
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
+                    - i - 1))) & ByteMask);
+        }
+        return bytes;
+    }
+
+    /**
+     * Accepts a number as input and returns its value in byte form in MSB
+     * aligned form example: input = 5000 [1001110001000] bytes = -114, 64
+     * [10011100] [01000000]
+     *
+     * @param Number
+     *            input
+     * @param int numBits - the number of bits to be returned
+     * @return byte[]
+     *
+     */
+    public static byte[] toByteArray(Number input, int numBits) {
+        Class<? extends Number> dataType = input.getClass();
+        short size = 0;
+        long longValue = input.longValue();
+
+        if (dataType == Short.class) {
+            size = Short.SIZE;
+        } else if (dataType == Integer.class) {
+            size = Integer.SIZE;
+        } else if (dataType == Long.class) {
+            size = Long.SIZE;
+        } else {
+            throw new IllegalArgumentException(
+                    "Parameter must one of the following: Short/Int/Long\n");
+        }
+
+        int length = size / NetUtils.NumBitsInAByte;
+        byte bytes[] = new byte[length];
+        byte[] inputbytes = new byte[length];
+        byte shiftedBytes[];
+
+        // Getting the bytes from input value
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) ((longValue >> (NetUtils.NumBitsInAByte * (length
+                    - i - 1))) & ByteMask);
+        }
+
+        if ((bytes[0] == 0 && dataType == Long.class)
+                || (bytes[0] == 0 && dataType == Integer.class)) {
+            int index = 0;
+            for (index = 0; index < length; ++index) {
+                if (bytes[index] != 0) {
+                    bytes[0] = bytes[index];
+                    break;
+                }
+            }
+            System.arraycopy(bytes, index, inputbytes, 0, length - index);
+            Arrays.fill(bytes, length - index + 1, length - 1, (byte) 0);
+        } else {
+            System.arraycopy(bytes, 0, inputbytes, 0, length);
+        }
+
+        shiftedBytes = shiftBitsToMSB(inputbytes, numBits);
+
+        return shiftedBytes;
+    }
+
+    /**
+     * Takes an LSB aligned byte array and returned the LSB numBits in a MSB
+     * aligned byte array
+     *
+     * @param inputbytes
+     * @param numBits
+     * @return
+     */
+    /**
+     * It aligns the last numBits bits to the head of the byte array following
+     * them with numBits % 8 zero bits.
+     *
+     * Example: For inputbytes = [00000111][01110001] and numBits = 12 it
+     * returns: shiftedBytes = [01110111][00010000]
+     *
+     * @param byte[] inputBytes
+     * @param int numBits - number of bits to be left aligned
+     * @return byte[]
+     */
+    public static byte[] shiftBitsToMSB(byte[] inputBytes, int numBits) {
+        int numBitstoShiftBy = 0, leadZeroesMSB = 8, numEndRestBits = 0;
+        int size = inputBytes.length;
+        byte[] shiftedBytes = new byte[size];
+        int i;
+
+        for (i = 0; i < Byte.SIZE; i++) {
+            if (((byte) (inputBytes[0] & getMSBMask(i + 1))) != 0) {
+                leadZeroesMSB = i;
+                break;
+            }
+        }
+
+        if (numBits % NetUtils.NumBitsInAByte == 0) {
+            numBitstoShiftBy = 0;
+        } else {
+            numBitstoShiftBy = ((NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte)) < leadZeroesMSB) ? (NetUtils.NumBitsInAByte - (numBits % NetUtils.NumBitsInAByte))
+                    : leadZeroesMSB;
+        }
+        if (numBitstoShiftBy == 0) {
+            return inputBytes;
+        }
+
+        if (numBits < NetUtils.NumBitsInAByte) {
+            // inputbytes.length = 1 OR read less than a byte
+            shiftedBytes[0] = (byte) ((inputBytes[0] & getLSBMask(numBits)) << numBitstoShiftBy);
+        } else {
+            // # of bits to read from last byte
+            numEndRestBits = NetUtils.NumBitsInAByte
+                    - (inputBytes.length * NetUtils.NumBitsInAByte - numBits - numBitstoShiftBy);
+
+            for (i = 0; i < (size - 1); i++) {
+                if ((i + 1) == (size - 1)) {
+                    if (numEndRestBits > numBitstoShiftBy) {
+                        shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (numEndRestBits - numBitstoShiftBy)));
+                        shiftedBytes[i + 1] = (byte) ((inputBytes[i + 1] & getLSBMask(numEndRestBits
+                                - numBitstoShiftBy)) << numBitstoShiftBy);
+                    } else
+                        shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | ((inputBytes[i + 1] & getMSBMask(numEndRestBits)) >> (NetUtils.NumBitsInAByte - numEndRestBits)));
+                }
+                shiftedBytes[i] = (byte) ((inputBytes[i] << numBitstoShiftBy) | (inputBytes[i + 1] & getMSBMask(numBitstoShiftBy)) >> (NetUtils.NumBitsInAByte - numBitstoShiftBy));
+            }
+
+        }
+        return shiftedBytes;
+    }
+
+    /**
+     * It aligns the first numBits bits to the right end of the byte array
+     * preceding them with numBits % 8 zero bits.
+     *
+     * Example: For inputbytes = [01110111][00010000] and numBits = 12 it
+     * returns: shiftedBytes = [00000111][01110001]
+     *
+     * @param byte[] inputBytes
+     * @param int numBits - number of bits to be right aligned
+     * @return byte[]
+     */
+    public static byte[] shiftBitsToLSB(byte[] inputBytes, int numBits) {
+        int numBytes = inputBytes.length;
+        int numBitstoShift = numBits % NetUtils.NumBitsInAByte;
+        byte[] shiftedBytes = new byte[numBytes];
+        int inputLsb = 0, inputMsb = 0;
+
+        if (numBitstoShift == 0) {
+            return inputBytes;
+        }
+
+        for (int i = 1; i < numBytes; i++) {
+            inputLsb = inputBytes[i - 1]
+                    & getLSBMask(NetUtils.NumBitsInAByte - numBitstoShift);
+            inputLsb = (inputLsb < 0) ? (inputLsb + 256) : inputLsb;
+            inputMsb = inputBytes[i] & getMSBMask(numBitstoShift);
+            inputMsb = (inputBytes[i] < 0) ? (inputBytes[i] + 256)
+                    : inputBytes[i];
+            shiftedBytes[i] = (byte) ((inputLsb << numBitstoShift) | (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift)));
+        }
+        inputMsb = inputBytes[0] & (getMSBMask(numBitstoShift));
+        inputMsb = (inputMsb < 0) ? (inputMsb + 256) : inputMsb;
+        shiftedBytes[0] = (byte) (inputMsb >> (NetUtils.NumBitsInAByte - numBitstoShift));
+        return shiftedBytes;
+    }
+
+    /**
+     * Insert in the data buffer at position dictated by the offset the number
+     * of bits specified from the input data byte array. The input byte array
+     * has the bits stored starting from the LSB
+     *
+     * @param byte[] data
+     * @param byte[] inputdata
+     * @param int startOffset
+     * @param int numBits
+     */
+    public static void insertBits(byte[] data, byte[] inputdataLSB,
+            int startOffset, int numBits) {
+        byte[] inputdata = shiftBitsToMSB(inputdataLSB, numBits); // Align to
+                                                                  // MSB the
+                                                                  // passed byte
+                                                                  // array
+        int numBytes = numBits / NetUtils.NumBitsInAByte;
+        int startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+        int extraOffsetBits = startOffset % NetUtils.NumBitsInAByte;
+        int extranumBits = numBits % NetUtils.NumBitsInAByte;
+        int RestBits = numBits % NetUtils.NumBitsInAByte;
+        int InputMSBbits = 0, InputLSBbits = 0;
+        int i;
+
+        if (numBits == 0) {
+            return;
+        }
+
+        if (extraOffsetBits == 0) {
+            if (extranumBits == 0) {
+                numBytes = numBits / NetUtils.NumBitsInAByte;
+                System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
+            } else {
+                System.arraycopy(inputdata, 0, data, startByteOffset, numBytes);
+                data[startByteOffset + numBytes] = (byte) (data[startByteOffset
+                        + numBytes] | (inputdata[numBytes] & getMSBMask(extranumBits)));
+            }
+        } else {
+            for (i = 0; i < numBytes; i++) {
+                if (i != 0)
+                    InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+                InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+                        - extraOffsetBits)));
+                InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+                        : InputMSBbits + 256;
+                data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+                        | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+                InputMSBbits = InputLSBbits = 0;
+            }
+            if (RestBits < (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+                if (numBytes != 0)
+                    InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+                InputMSBbits = (byte) (inputdata[i] & (getMSBMask(RestBits)));
+                InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+                        : InputMSBbits + 256;
+                data[startByteOffset + i] = (byte) ((data[startByteOffset + i])
+                        | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+            } else if (RestBits == (NetUtils.NumBitsInAByte - extraOffsetBits)) {
+                if (numBytes != 0)
+                    InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+                InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+                        - extraOffsetBits)));
+                InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+                        : InputMSBbits + 256;
+                data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+                        | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+            } else {
+                if (numBytes != 0)
+                    InputLSBbits = (inputdata[i - 1] & getLSBMask(extraOffsetBits));
+                InputMSBbits = (byte) (inputdata[i] & (getMSBMask(NetUtils.NumBitsInAByte
+                        - extraOffsetBits)));
+                InputMSBbits = (InputMSBbits >= 0) ? InputMSBbits
+                        : InputMSBbits + 256;
+                data[startByteOffset + i] = (byte) (data[startByteOffset + i]
+                        | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)) | (InputMSBbits >> extraOffsetBits));
+
+                InputLSBbits = (inputdata[i] & (getLSBMask(RestBits
+                        - (NetUtils.NumBitsInAByte - extraOffsetBits)) << (NetUtils.NumBitsInAByte - RestBits)));
+                data[startByteOffset + i + 1] = (byte) (data[startByteOffset
+                        + i + 1] | (InputLSBbits << (NetUtils.NumBitsInAByte - extraOffsetBits)));
+            }
+        }
+    }
+
+    /**
+     * Checks for overflow and underflow exceptions
+     * @param data
+     * @param startOffset
+     * @param numBits
+     * @throws PacketException when the startOffset and numBits parameters
+     *                    are not congruent with the data buffer's size
+     */
+    public static void checkExceptions(byte[] data, int startOffset, int numBits)
+            throws BufferException {
+        int endOffsetByte;
+        int startByteOffset;
+        endOffsetByte = startOffset
+                / NetUtils.NumBitsInAByte
+                + numBits
+                / NetUtils.NumBitsInAByte
+                + ((numBits % NetUtils.NumBitsInAByte != 0) ? 1 : ((startOffset
+                        % NetUtils.NumBitsInAByte != 0) ? 1 : 0));
+        startByteOffset = startOffset / NetUtils.NumBitsInAByte;
+
+        if (data == null) {
+            throw new BufferException("data[] is null\n");
+        }
+
+        if ((startOffset < 0) || (startByteOffset >= data.length)
+                || (endOffsetByte > data.length) || (numBits < 0)
+                || (numBits > NetUtils.NumBitsInAByte * data.length)) {
+            throw new BufferException(
+                    "Illegal arguement/out of bound exception - data.length = "
+                            + data.length + " startOffset = " + startOffset
+                            + " numBits " + numBits);
+        }
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/BufferException.java
new file mode 100644 (file)
index 0000000..fa0848d
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.liblldp;
+
+/**
+ * Describes an exception that is raised during BitBufferHelper operations.
+ */
+public class BufferException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public BufferException(String message) {
+        super(message);
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/ConstructionException.java
new file mode 100644 (file)
index 0000000..8b1d9d2
--- /dev/null
@@ -0,0 +1,28 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * @file   ConstructionException.java
+ *
+ *
+ * @brief  Describe an exception that is raised when a construction
+ * for a Node/NodeConnector/Edge or any of the SAL basic object fails
+ * because input passed are not valid or compatible
+ *
+ *
+ */
+package org.opendaylight.controller.liblldp;
+
+public class ConstructionException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public ConstructionException(String message) {
+        super(message);
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/DataLinkAddress.java
new file mode 100644 (file)
index 0000000..d617c05
--- /dev/null
@@ -0,0 +1,96 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.io.Serializable;
+
+import javax.xml.bind.annotation.XmlRootElement;
+
+/**
+ * @file   DataLinkAddress.java
+ *
+ * @brief  Abstract base class for a Datalink Address
+ *
+ */
+
+/**
+ * Abstract base class for a Datalink Address
+ *
+ */
+@XmlRootElement
+abstract public class DataLinkAddress implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private String name;
+
+    public DataLinkAddress() {
+
+    }
+
+    /**
+     * Constructor of super class
+     *
+     * @param name Create a new DataLink, not for general use but
+     * available only for sub classes
+     *
+     * @return constructed object
+     */
+    protected DataLinkAddress(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Used to copy the DataLinkAddress in a polymorphic way
+     *
+     *
+     * @return A clone of this DataLinkAddress
+     */
+    @Override
+    abstract public DataLinkAddress clone();
+
+    /**
+     * Allow to distinguish among different data link addresses
+     *
+     *
+     * @return Name of the DataLinkAdress we are working on
+     */
+    public String getName() {
+        return this.name;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((name == null) ? 0 : name.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        DataLinkAddress other = (DataLinkAddress) obj;
+        if (name == null) {
+            if (other.name != null)
+                return false;
+        } else if (!name.equals(other.name))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "DataLinkAddress [name=" + name + "]";
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EtherTypes.java
new file mode 100644 (file)
index 0000000..876d495
--- /dev/null
@@ -0,0 +1,117 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The enum contains the most common 802.3 ethernet types and 802.2 + SNAP protocol ids
+ *
+ *
+ *
+ */
+public enum EtherTypes {
+    PVSTP("PVSTP", 0x010B), // 802.2 + SNAP (Spanning Tree)
+    CDP("CDP", 0x2000), // 802.2 + SNAP
+    VTP("VTP", 0x2003), // 802.2 + SNAP
+    IPv4("IPv4", 0x800), ARP("ARP", 0x806), RARP("Reverse ARP", 0x8035), VLANTAGGED(
+            "VLAN Tagged", 0x8100), // 802.1Q
+    IPv6("IPv6", 0x86DD), MPLSUCAST("MPLS Unicast", 0x8847), MPLSMCAST(
+            "MPLS Multicast", 0x8848), QINQ("QINQ", 0x88A8), // Standard 802.1ad QinQ
+    LLDP("LLDP", 0x88CC), OLDQINQ("Old QINQ", 0x9100), // Old non-standard QinQ
+    CISCOQINQ("Cisco QINQ", 0x9200); // Cisco non-standard QinQ
+
+    private static final String regexNumberString = "^[0-9]+$";
+    private String description;
+    private int number;
+
+    private EtherTypes(String description, int number) {
+        this.description = description;
+        this.number = number;
+    }
+
+    public String toString() {
+        return description;
+    }
+
+    public int intValue() {
+        return number;
+    }
+
+    public short shortValue() {
+        return ((Integer) number).shortValue();
+    }
+
+    public static String getEtherTypeName(int number) {
+        return getEtherTypeInternal(number);
+    }
+
+    public static String getEtherTypeName(short number) {
+        return getEtherTypeInternal((int) number & 0xffff);
+    }
+
+    public static String getEtherTypeName(byte number) {
+        return getEtherTypeInternal((int) number & 0xff);
+    }
+
+    private static String getEtherTypeInternal(int number) {
+        for (EtherTypes type : EtherTypes.values()) {
+            if (type.number == number) {
+                return type.toString();
+            }
+        }
+        return "0x" + Integer.toHexString(number);
+    }
+
+    public static short getEtherTypeNumberShort(String name) {
+        if (name.matches(regexNumberString)) {
+            return Short.valueOf(name);
+        }
+        for (EtherTypes type : EtherTypes.values()) {
+            if (type.description.equalsIgnoreCase(name)) {
+                return type.shortValue();
+            }
+        }
+        return 0;
+    }
+
+    public static int getEtherTypeNumberInt(String name) {
+        if (name.matches(regexNumberString)) {
+            return Integer.valueOf(name);
+        }
+        for (EtherTypes type : EtherTypes.values()) {
+            if (type.description.equalsIgnoreCase(name)) {
+                return type.intValue();
+            }
+        }
+        return 0;
+    }
+
+    public static List<String> getEtherTypesNameList() {
+        List<String> ethertypesList = new ArrayList<String>();
+        for (EtherTypes type : EtherTypes.values()) {
+            ethertypesList.add(type.toString());
+        }
+        return ethertypesList;
+    }
+
+    public static EtherTypes loadFromString(String string) {
+        int intType = Integer.parseInt(string);
+
+        for (EtherTypes type : EtherTypes.values()) {
+            if (type.number == intType) {
+                return type;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Ethernet.java
new file mode 100644 (file)
index 0000000..54452bb
--- /dev/null
@@ -0,0 +1,134 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Class that represents the Ethernet frame objects
+ */
+public class Ethernet extends Packet {
+    private static final String DMAC = "DestinationMACAddress";
+    private static final String SMAC = "SourceMACAddress";
+    private static final String ETHT = "EtherType";
+
+    // TODO: This has to be outside and it should be possible for osgi
+    // to add new coming packet classes
+    public static final Map<Short, Class<? extends Packet>> etherTypeClassMap;
+    static {
+        etherTypeClassMap = new HashMap<Short, Class<? extends Packet>>();
+        etherTypeClassMap.put(EtherTypes.LLDP.shortValue(), LLDP.class);
+    }
+    private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+        {
+            put(DMAC, new ImmutablePair<Integer, Integer>(0, 48));
+            put(SMAC, new ImmutablePair<Integer, Integer>(48, 48));
+            put(ETHT, new ImmutablePair<Integer, Integer>(96, 16));
+        }
+    };
+    private final Map<String, byte[]> fieldValues;
+
+    /**
+     * Default constructor that creates and sets the HashMap
+     */
+    public Ethernet() {
+        super();
+        fieldValues = new HashMap<String, byte[]>();
+        hdrFieldCoordMap = fieldCoordinates;
+        hdrFieldsMap = fieldValues;
+    }
+
+    /**
+     * Constructor that sets the access level for the packet and
+     * creates and sets the HashMap
+     */
+    public Ethernet(boolean writeAccess) {
+        super(writeAccess);
+        fieldValues = new HashMap<String, byte[]>();
+        hdrFieldCoordMap = fieldCoordinates;
+        hdrFieldsMap = fieldValues;
+    }
+
+    @Override
+    public void setHeaderField(String headerField, byte[] readValue) {
+        if (headerField.equals(ETHT)) {
+            payloadClass = etherTypeClassMap.get(BitBufferHelper
+                    .getShort(readValue));
+        }
+        hdrFieldsMap.put(headerField, readValue);
+    }
+
+    /**
+     * Gets the destination MAC address stored
+     * @return byte[] - the destinationMACAddress
+     */
+    public byte[] getDestinationMACAddress() {
+        return fieldValues.get(DMAC);
+    }
+
+    /**
+     * Gets the source MAC address stored
+     * @return byte[] - the sourceMACAddress
+     */
+    public byte[] getSourceMACAddress() {
+        return fieldValues.get(SMAC);
+    }
+
+    /**
+     * Gets the etherType stored
+     * @return short - the etherType
+     */
+    public short getEtherType() {
+        return BitBufferHelper.getShort(fieldValues.get(ETHT));
+    }
+
+    public boolean isBroadcast(){
+        return NetUtils.isBroadcastMACAddr(getDestinationMACAddress());
+    }
+
+    public boolean isMulticast(){
+        return NetUtils.isMulticastMACAddr(getDestinationMACAddress());
+    }
+
+    /**
+     * Sets the destination MAC address for the current Ethernet object instance
+     * @param byte[] - the destinationMACAddress to set
+     */
+    public Ethernet setDestinationMACAddress(byte[] destinationMACAddress) {
+        fieldValues.put(DMAC, destinationMACAddress);
+        return this;
+    }
+
+    /**
+     * Sets the source MAC address for the current Ethernet object instance
+     * @param byte[] - the sourceMACAddress to set
+     */
+    public Ethernet setSourceMACAddress(byte[] sourceMACAddress) {
+        fieldValues.put(SMAC, sourceMACAddress);
+        return this;
+    }
+
+    /**
+     * Sets the etherType for the current Ethernet object instance
+     * @param short - the etherType to set
+     */
+    public Ethernet setEtherType(short etherType) {
+        byte[] ethType = BitBufferHelper.toByteArray(etherType);
+        fieldValues.put(ETHT, ethType);
+        return this;
+    }
+
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/EthernetAddress.java
new file mode 100644 (file)
index 0000000..b7b72cb
--- /dev/null
@@ -0,0 +1,124 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlTransient;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class EthernetAddress extends DataLinkAddress {
+    private static final long serialVersionUID = 1L;
+    @XmlTransient
+    private byte[] macAddress;
+
+    public static final EthernetAddress BROADCASTMAC = createWellKnownAddress(new byte[] {
+            (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff,
+            (byte) 0xff });
+
+    public static final EthernetAddress INVALIDHOST = BROADCASTMAC;
+
+    public static final String addressName = "Ethernet MAC Address";
+    public static final int SIZE = 6;
+
+    private static final EthernetAddress createWellKnownAddress(byte[] mac) {
+        try {
+            return new EthernetAddress(mac);
+        } catch (ConstructionException ce) {
+            return null;
+        }
+    }
+
+    /* Private constructor to satisfy JAXB */
+    @SuppressWarnings("unused")
+    private EthernetAddress() {
+    }
+
+    /**
+     * Public constructor for an Ethernet MAC address starting from
+     * the byte constituing the address, the constructor validate the
+     * size of the arrive to make sure it met the expected size
+     *
+     * @param macAddress A byte array in big endian format
+     * representing the Ethernet MAC Address
+     *
+     * @return The constructed object if valid
+     */
+    public EthernetAddress(byte[] macAddress) throws ConstructionException {
+        super(addressName);
+
+        if (macAddress == null) {
+            throw new ConstructionException("Null input parameter passed");
+        }
+
+        if (macAddress.length != SIZE) {
+            throw new ConstructionException(
+                    "Wrong size of passed byte array, expected:" + SIZE
+                            + " got:" + macAddress.length);
+        }
+        this.macAddress = new byte[SIZE];
+        System.arraycopy(macAddress, 0, this.macAddress, 0, SIZE);
+    }
+
+    public EthernetAddress clone() {
+        try {
+            return new EthernetAddress(this.macAddress.clone());
+        } catch (ConstructionException ce) {
+            return null;
+        }
+    }
+
+    /**
+     * Return the Ethernet Mac address in byte array format
+     *
+     * @return The Ethernet Mac address in byte array format
+     */
+    public byte[] getValue() {
+        return this.macAddress;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result + Arrays.hashCode(macAddress);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (!super.equals(obj))
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        EthernetAddress other = (EthernetAddress) obj;
+        if (!Arrays.equals(macAddress, other.macAddress))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return "EthernetAddress [macAddress=" + HexEncode.bytesToHexStringFormat(macAddress)
+                + "]";
+    }
+
+    @XmlElement(name = "macAddress")
+    public String getMacAddress() {
+        return HexEncode.bytesToHexStringFormat(macAddress);
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/HexEncode.java
new file mode 100644 (file)
index 0000000..8236d4c
--- /dev/null
@@ -0,0 +1,114 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.math.BigInteger;
+
+/**
+ * The class provides methods to convert hex encode strings
+ *
+ *
+ */
+public class HexEncode {
+    /**
+     * This method converts byte array into String format without ":" inserted.
+     *
+     * @param bytes
+     *            The byte array to convert to string
+     * @return The hexadecimal representation of the byte array. If bytes is
+     *         null, "null" string is returned
+     */
+    public static String bytesToHexString(byte[] bytes) {
+
+        if (bytes == null) {
+            return "null";
+        }
+
+        String ret = "";
+        StringBuffer buf = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            if (i > 0) {
+                ret += ":";
+            }
+            short u8byte = (short) (bytes[i] & 0xff);
+            String tmp = Integer.toHexString(u8byte);
+            if (tmp.length() == 1) {
+                buf.append("0");
+            }
+            buf.append(tmp);
+        }
+        ret = buf.toString();
+        return ret;
+    }
+
+    public static String longToHexString(long val) {
+        char arr[] = Long.toHexString(val).toCharArray();
+        StringBuffer buf = new StringBuffer();
+        // prepend the right number of leading zeros
+        int i = 0;
+        for (; i < (16 - arr.length); i++) {
+            buf.append("0");
+            if ((i & 0x01) == 1) {
+                buf.append(":");
+            }
+        }
+        for (int j = 0; j < arr.length; j++) {
+            buf.append(arr[j]);
+            if ((((i + j) & 0x01) == 1) && (j < (arr.length - 1))) {
+                buf.append(":");
+            }
+        }
+        return buf.toString();
+    }
+
+
+    public static byte[] bytesFromHexString(String values) {
+        String target = "";
+        if (values != null) {
+            target = values;
+        }
+        String[] octets = target.split(":");
+
+        byte[] ret = new byte[octets.length];
+        for (int i = 0; i < octets.length; i++) {
+            ret[i] = Integer.valueOf(octets[i], 16).byteValue();
+        }
+        return ret;
+    }
+
+    public static long stringToLong(String values) {
+        long value = new BigInteger(values.replaceAll(":", ""), 16).longValue();
+        return value;
+    }
+
+    /**
+     * This method converts byte array into HexString format with ":" inserted.
+     */
+    public static String bytesToHexStringFormat(byte[] bytes) {
+        if (bytes == null) {
+            return "null";
+        }
+        String ret = "";
+        StringBuffer buf = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            if (i > 0) {
+                buf.append(":");
+            }
+            short u8byte = (short) (bytes[i] & 0xff);
+            String tmp = Integer.toHexString(u8byte);
+            if (tmp.length() == 1) {
+                buf.append("0");
+            }
+            buf.append(tmp);
+        }
+        ret = buf.toString();
+        return ret;
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDP.java
new file mode 100644 (file)
index 0000000..9b7efbb
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class that represents the LLDP frame objects
+ */
+
+public class LLDP extends Packet {
+    private static final String CHASSISID = "ChassisId";
+    private static final String SYSTEMNAMEID = "SystemNameID";
+    private static final String PORTID = "PortId";
+    private static final String TTL = "TTL";
+    private static final int LLDPDefaultTlvs = 4;
+    private static LLDPTLV emptyTLV = new LLDPTLV().setLength((short) 0)
+            .setType((byte) 0);
+    public static final byte[] LLDPMulticastMac = { 1, (byte) 0x80,
+            (byte) 0xc2, 0, 0, (byte) 0xe };
+    private Map<Byte, LLDPTLV> tlvList;
+
+    /**
+     * Default constructor that creates the tlvList LinkedHashMap
+     */
+    public LLDP() {
+        super();
+        tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs);
+    }
+
+    /**
+     * Constructor that creates the tlvList LinkedHashMap and sets the write
+     * access for the same
+     */
+    public LLDP(boolean writeAccess) {
+        super(writeAccess);
+        tlvList = new LinkedHashMap<Byte, LLDPTLV>(LLDPDefaultTlvs); // Mandatory
+                                                                     // TLVs
+    }
+
+    /**
+     * @param String
+     *            - description of the type of TLV
+     * @return byte - type of TLV
+     */
+    private byte getType(String typeDesc) {
+        if (typeDesc.equals(CHASSISID)) {
+            return LLDPTLV.TLVType.ChassisID.getValue();
+        } else if (typeDesc.equals(PORTID)) {
+            return LLDPTLV.TLVType.PortID.getValue();
+        } else if (typeDesc.equals(TTL)) {
+            return LLDPTLV.TLVType.TTL.getValue();
+        } else {
+            return LLDPTLV.TLVType.Unknown.getValue();
+        }
+    }
+
+    /**
+     * @param String
+     *            - description of the type of TLV
+     * @return LLDPTLV - full TLV
+     */
+    public LLDPTLV getTLV(String type) {
+        return tlvList.get(getType(type));
+    }
+
+    /**
+     * @param String
+     *            - description of the type of TLV
+     * @param LLDPTLV
+     *            - tlv to set
+     * @return void
+     */
+    public void setTLV(String type, LLDPTLV tlv) {
+        tlvList.put(getType(type), tlv);
+    }
+
+    /**
+     * @return the chassisId TLV
+     */
+    public LLDPTLV getChassisId() {
+        return getTLV(CHASSISID);
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the chassisId to set
+     */
+    public LLDP setChassisId(LLDPTLV chassisId) {
+        tlvList.put(getType(CHASSISID), chassisId);
+        return this;
+    }
+
+    /**
+     * @return the SystemName TLV
+     */
+    public LLDPTLV getSystemNameId() {
+        return getTLV(SYSTEMNAMEID);
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the chassisId to set
+     */
+    public LLDP setSystemNameId(LLDPTLV systemNameId) {
+        tlvList.put(getType(SYSTEMNAMEID), systemNameId);
+        return this;
+    }
+
+    /**
+     * @return LLDPTLV - the portId TLV
+     */
+    public LLDPTLV getPortId() {
+        return tlvList.get(getType(PORTID));
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the portId to set
+     * @return LLDP
+     */
+    public LLDP setPortId(LLDPTLV portId) {
+        tlvList.put(getType(PORTID), portId);
+        return this;
+    }
+
+    /**
+     * @return LLDPTLV - the ttl TLV
+     */
+    public LLDPTLV getTtl() {
+        return tlvList.get(getType(TTL));
+    }
+
+    /**
+     * @param LLDPTLV
+     *            - the ttl to set
+     * @return LLDP
+     */
+    public LLDP setTtl(LLDPTLV ttl) {
+        tlvList.put(getType(TTL), ttl);
+        return this;
+    }
+
+    /**
+     * @return the optionalTLVList
+     */
+    public List<LLDPTLV> getOptionalTLVList() {
+        List<LLDPTLV> list = new ArrayList<LLDPTLV>();
+        for (Map.Entry<Byte, LLDPTLV> entry : tlvList.entrySet()) {
+            byte type = entry.getKey();
+            if ((type == LLDPTLV.TLVType.ChassisID.getValue())
+                    || (type == LLDPTLV.TLVType.PortID.getValue())
+                    || (type == LLDPTLV.TLVType.TTL.getValue())) {
+                continue;
+            } else {
+                list.add(entry.getValue());
+            }
+        }
+        return list;
+    }
+
+    /**
+     * @param optionalTLVList
+     *            the optionalTLVList to set
+     * @return LLDP
+     */
+    public LLDP setOptionalTLVList(List<LLDPTLV> optionalTLVList) {
+        for (LLDPTLV tlv : optionalTLVList) {
+            tlvList.put(tlv.getType(), tlv);
+        }
+        return this;
+    }
+
+    @Override
+    public Packet deserialize(byte[] data, int bitOffset, int size)
+            throws PacketException {
+        int lldpOffset = bitOffset; // LLDP start
+        int lldpSize = size; // LLDP size
+
+        if (logger.isTraceEnabled()) {
+          logger.trace("LLDP: {} (offset {} bitsize {})", new Object[] {
+                  HexEncode.bytesToHexString(data), lldpOffset, lldpSize });
+        }
+        /*
+         * Deserialize the TLVs until we reach the end of the packet
+         */
+        while (lldpSize > 0) {
+            LLDPTLV tlv = new LLDPTLV();
+            tlv.deserialize(data, lldpOffset, lldpSize);
+            if (tlv.getType() == 0 && tlv.getLength() == 0) {
+               break;
+            }
+            int tlvSize = tlv.getTLVSize(); // Size of current TLV in bits
+            lldpOffset += tlvSize;
+            lldpSize -= tlvSize;
+            this.tlvList.put(tlv.getType(), tlv);
+        }
+        return this;
+    }
+
+    @Override
+    public byte[] serialize() throws PacketException {
+        int startOffset = 0;
+        byte[] serializedBytes = new byte[getLLDPPacketLength()];
+
+        for (Map.Entry<Byte, LLDPTLV> entry : tlvList.entrySet()) {
+            LLDPTLV tlv = entry.getValue();
+            int numBits = tlv.getTLVSize();
+            try {
+                BitBufferHelper.setBytes(serializedBytes, tlv.serialize(),
+                        startOffset, numBits);
+            } catch (BufferException e) {
+                throw new PacketException(e.getMessage());
+            }
+            startOffset += numBits;
+        }
+        // Now add the empty LLDPTLV at the end
+        try {
+            BitBufferHelper.setBytes(serializedBytes,
+                    LLDP.emptyTLV.serialize(), startOffset,
+                    LLDP.emptyTLV.getTLVSize());
+        } catch (BufferException e) {
+            throw new PacketException(e.getMessage());
+        }
+
+        if (logger.isTraceEnabled()) {
+          logger.trace("LLDP: serialized: {}",
+                  HexEncode.bytesToHexString(serializedBytes));
+        }
+        return serializedBytes;
+    }
+
+    /**
+     * Returns the size of LLDP packet in bytes
+     *
+     * @return int - LLDP Packet size in bytes
+     */
+    private int getLLDPPacketLength() {
+        int len = 0;
+        LLDPTLV tlv;
+
+        for (Map.Entry<Byte, LLDPTLV> entry : this.tlvList.entrySet()) {
+            tlv = entry.getValue();
+            len += tlv.getTLVSize();
+        }
+        len += LLDP.emptyTLV.getTLVSize();
+
+        return len / NetUtils.NumBitsInAByte;
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/LLDPTLV.java
new file mode 100644 (file)
index 0000000..22bd462
--- /dev/null
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Class that represents the LLDPTLV objects
+ */
+
+public class LLDPTLV extends Packet {
+    private static final String TYPE = "Type";
+    private static final String LENGTH = "Length";
+    private static final String VALUE = "Value";
+    private static final int LLDPTLVFields = 3;
+    public static final byte[] OFOUI = new byte[] { (byte) 0x00, (byte) 0x26,
+        (byte) 0xe1 }; // OpenFlow OUI
+    public static final byte[] customTlvSubType = new byte[] { 0 };
+    public static final int customTlvOffset = OFOUI.length
+            + customTlvSubType.length;
+    public static final byte chassisIDSubType[] = new byte[] { 4 }; // MAC address for the system
+    public static final byte portIDSubType[] = new byte[] { 7 }; // locally assigned
+
+    public enum TLVType {
+        Unknown((byte) 0), ChassisID((byte) 1), PortID((byte) 2), TTL((byte) 3), PortDesc(
+                (byte) 4), SystemName((byte) 5), SystemDesc((byte) 6), Custom(
+                        (byte) 127);
+
+        private byte value;
+
+        private TLVType(byte value) {
+            this.value = value;
+        }
+
+        public byte getValue() {
+            return value;
+        }
+    }
+
+    private static Map<String, Pair<Integer, Integer>> fieldCoordinates = new LinkedHashMap<String, Pair<Integer, Integer>>() {
+        private static final long serialVersionUID = 1L;
+
+        {
+            put(TYPE, new MutablePair<Integer, Integer>(0, 7));
+            put(LENGTH, new MutablePair<Integer, Integer>(7, 9));
+            put(VALUE, new MutablePair<Integer, Integer>(16, 0));
+        }
+    };
+
+    protected Map<String, byte[]> fieldValues;
+
+    /**
+     * Default constructor that creates and sets the hash map values and sets
+     * the payload to null
+     */
+    public LLDPTLV() {
+        payload = null;
+        fieldValues = new HashMap<String, byte[]>(LLDPTLVFields);
+        hdrFieldCoordMap = fieldCoordinates;
+        hdrFieldsMap = fieldValues;
+    }
+
+    /**
+     * Constructor that writes the passed LLDPTLV values to the hdrFieldsMap
+     */
+    public LLDPTLV(LLDPTLV other) {
+        for (Map.Entry<String, byte[]> entry : other.hdrFieldsMap.entrySet()) {
+            this.hdrFieldsMap.put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * @return int - the length of TLV
+     */
+    public int getLength() {
+        return (int) BitBufferHelper.toNumber(fieldValues.get(LENGTH),
+                fieldCoordinates.get(LENGTH).getRight().intValue());
+    }
+
+    /**
+     * @return byte - the type of TLV
+     */
+    public byte getType() {
+        return BitBufferHelper.getByte(fieldValues.get(TYPE));
+    }
+
+    /**
+     * @return byte[] - the value field of TLV
+     */
+    public byte[] getValue() {
+        return fieldValues.get(VALUE);
+    }
+
+    /**
+     * @param byte - the type to set
+     * @return LLDPTLV
+     */
+    public LLDPTLV setType(byte type) {
+        byte[] lldpTLVtype = { type };
+        fieldValues.put(TYPE, lldpTLVtype);
+        return this;
+    }
+
+    /**
+     * @param short - the length to set
+     * @return LLDPTLV
+     */
+    public LLDPTLV setLength(short length) {
+        fieldValues.put(LENGTH, BitBufferHelper.toByteArray(length));
+        return this;
+    }
+
+    /**
+     * @param byte[] - the value to set
+     * @return LLDPTLV
+     */
+    public LLDPTLV setValue(byte[] value) {
+        fieldValues.put(VALUE, value);
+        return this;
+    }
+
+    @Override
+    public void setHeaderField(String headerField, byte[] readValue) {
+        hdrFieldsMap.put(headerField, readValue);
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result
+                + ((fieldValues == null) ? 0 : fieldValues.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!super.equals(obj)) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        LLDPTLV other = (LLDPTLV) obj;
+        if (fieldValues == null) {
+            if (other.fieldValues != null) {
+                return false;
+            }
+        } else if (!fieldValues.equals(other.fieldValues)) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public int getfieldnumBits(String fieldName) {
+        if (fieldName.equals(VALUE)) {
+            return (NetUtils.NumBitsInAByte * BitBufferHelper.getShort(
+                    fieldValues.get(LENGTH), fieldCoordinates.get(LENGTH)
+                    .getRight().intValue()));
+        }
+        return fieldCoordinates.get(fieldName).getRight();
+    }
+
+    /**
+     * Returns the size in bits of the whole TLV
+     *
+     * @return int - size in bits of full TLV
+     */
+    public int getTLVSize() {
+        return (LLDPTLV.fieldCoordinates.get(TYPE).getRight() + // static
+                LLDPTLV.fieldCoordinates.get(LENGTH).getRight() + // static
+                getfieldnumBits(VALUE)); // variable
+    }
+
+    /**
+     * Creates the SystemName TLV value
+     *
+     * @param nodeId
+     *            node identifier string
+     * @return the SystemName TLV value in byte array
+     */
+    static public byte[] createSystemNameTLVValue(String nodeId) {
+        byte[] nid = nodeId.getBytes();
+        return nid;
+    }
+
+    /**
+     * Creates the ChassisID TLV value including the subtype and ChassisID
+     * string
+     *
+     * @param nodeId
+     *            node identifier string
+     * @return the ChassisID TLV value in byte array
+     */
+    static public byte[] createChassisIDTLVValue(String nodeId) {
+        byte[] nid = HexEncode.bytesFromHexString(nodeId);
+        byte[] cid = new byte[6];
+        int srcPos = 0, dstPos = 0;
+
+        if (nid.length > cid.length) {
+            srcPos = nid.length - cid.length;
+        } else {
+            dstPos = cid.length - nid.length;
+        }
+        System.arraycopy(nid, srcPos, cid, dstPos, cid.length);
+
+        byte[] cidValue = new byte[cid.length + chassisIDSubType.length];
+
+        System.arraycopy(chassisIDSubType, 0, cidValue, 0,
+                chassisIDSubType.length);
+        System.arraycopy(cid, 0, cidValue, chassisIDSubType.length, cid.length);
+
+        return cidValue;
+    }
+
+    /**
+     * Creates the PortID TLV value including the subtype and PortID string
+     *
+     * @param portId
+     *            port identifier string
+     * @return the PortID TLV value in byte array
+     */
+    static public byte[] createPortIDTLVValue(String portId) {
+        byte[] pid = portId.getBytes(Charset.defaultCharset());
+        byte[] pidValue = new byte[pid.length + portIDSubType.length];
+
+        System.arraycopy(portIDSubType, 0, pidValue, 0, portIDSubType.length);
+        System.arraycopy(pid, 0, pidValue, portIDSubType.length, pid.length);
+
+        return pidValue;
+    }
+
+    /**
+     * Creates the custom TLV value including OUI, subtype and custom string
+     *
+     * @param portId
+     *            port identifier string
+     * @return the custom TLV value in byte array
+     */
+    static public byte[] createCustomTLVValue(String customString) {
+        byte[] customArray = customString.getBytes(Charset.defaultCharset());
+        byte[] customValue = new byte[customTlvOffset + customArray.length];
+
+        System.arraycopy(OFOUI, 0, customValue, 0, OFOUI.length);
+        System.arraycopy(customTlvSubType, 0, customValue, OFOUI.length,
+                customTlvSubType.length);
+        System.arraycopy(customArray, 0, customValue, customTlvOffset,
+                customArray.length);
+
+        return customValue;
+    }
+
+    /**
+     * Retrieves the string from TLV value and returns it in HexString format
+     *
+     * @param tlvValue
+     *            the TLV value
+     * @param tlvLen
+     *            the TLV length
+     * @return the HexString
+     */
+    static public String getHexStringValue(byte[] tlvValue, int tlvLen) {
+        byte[] cidBytes = new byte[tlvLen - chassisIDSubType.length];
+        System.arraycopy(tlvValue, chassisIDSubType.length, cidBytes, 0,
+                cidBytes.length);
+        return HexEncode.bytesToHexStringFormat(cidBytes);
+    }
+
+    /**
+     * Retrieves the string from TLV value
+     *
+     * @param tlvValue
+     *            the TLV value
+     * @param tlvLen
+     *            the TLV length
+     * @return the string
+     */
+    static public String getStringValue(byte[] tlvValue, int tlvLen) {
+        byte[] pidSubType = new byte[portIDSubType.length];
+        byte[] pidBytes = new byte[tlvLen - portIDSubType.length];
+        System.arraycopy(tlvValue, 0, pidSubType, 0,
+                pidSubType.length);
+        System.arraycopy(tlvValue, portIDSubType.length, pidBytes, 0,
+                pidBytes.length);
+        if (pidSubType[0] == (byte) 0x3) {
+            return HexEncode.bytesToHexStringFormat(pidBytes);
+        } else {
+            return (new String(pidBytes, Charset.defaultCharset()));
+        }
+    }
+
+    /**
+     * Retrieves the custom string from the Custom TLV value which includes OUI,
+     * subtype and custom string
+     *
+     * @param customTlvValue
+     *            the custom TLV value
+     * @param customTlvLen
+     *            the custom TLV length
+     * @return the custom string
+     */
+    static public String getCustomString(byte[] customTlvValue, int customTlvLen) {
+        String customString = "";
+        byte[] vendor = new byte[3];
+        System.arraycopy(customTlvValue, 0, vendor, 0, vendor.length);
+        if (Arrays.equals(vendor, LLDPTLV.OFOUI)) {
+            int customArrayLength = customTlvLen - customTlvOffset;
+            byte[] customArray = new byte[customArrayLength];
+            System.arraycopy(customTlvValue, customTlvOffset, customArray, 0,
+                    customArrayLength);
+            try {
+                customString = new String(customArray, "UTF-8");
+            } catch (UnsupportedEncodingException e) {
+            }
+        }
+
+        return customString;
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/NetUtils.java
new file mode 100644 (file)
index 0000000..0320cf6
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.net.Inet4Address;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class containing the common utility functions needed for operating on
+ * networking data structures
+ */
+public abstract class NetUtils {
+    protected static final Logger logger = LoggerFactory.getLogger(NetUtils.class);
+    /**
+     * Constant holding the number of bits in a byte
+     */
+    public static final int NumBitsInAByte = 8;
+
+    /**
+     * Constant holding the number of bytes in MAC Address
+     */
+    public static final int MACAddrLengthInBytes = 6;
+
+    /**
+     * Constant holding the number of words in MAC Address
+     */
+    public static final int MACAddrLengthInWords = 3;
+
+    /**
+     * Constant holding the broadcast MAC address
+     */
+    private static final byte[] BroadcastMACAddr = {-1, -1, -1, -1, -1, -1};
+
+    /**
+     * Converts a 4 bytes array into an integer number
+     *
+     * @param ba
+     *            the 4 bytes long byte array
+     * @return the integer number
+     */
+    public static int byteArray4ToInt(byte[] ba) {
+        if (ba == null || ba.length != 4) {
+            return 0;
+        }
+        return (0xff & ba[0]) << 24 | (0xff & ba[1]) << 16 | (0xff & ba[2]) << 8 | (0xff & ba[3]);
+    }
+
+    /**
+     * Converts a 6 bytes array into a long number MAC addresses.
+     *
+     * @param ba
+     *            The 6 bytes long byte array.
+     * @return The long number.
+     *         Zero is returned if {@code ba} is {@code null} or
+     *         the length of it is not six.
+     */
+    public static long byteArray6ToLong(byte[] ba) {
+        if (ba == null || ba.length != MACAddrLengthInBytes) {
+            return 0L;
+        }
+        long num = 0L;
+        int i = 0;
+        do {
+            num <<= NumBitsInAByte;
+            num |= 0xff & ba[i];
+            i++;
+        } while (i < MACAddrLengthInBytes);
+        return num;
+    }
+
+    /**
+     * Converts a long number to a 6 bytes array for MAC addresses.
+     *
+     * @param addr
+     *            The long number.
+     * @return The byte array.
+     */
+    public static byte[] longToByteArray6(long addr){
+        byte[] mac = new byte[MACAddrLengthInBytes];
+        int i = MACAddrLengthInBytes - 1;
+        do {
+            mac[i] = (byte) addr;
+            addr >>>= NumBitsInAByte;
+            i--;
+        } while (i >= 0);
+        return mac;
+    }
+
+    /**
+     * Converts an integer number into a 4 bytes array
+     *
+     * @param i
+     *            the integer number
+     * @return the byte array
+     */
+    public static byte[] intToByteArray4(int i) {
+        return new byte[] { (byte) ((i >> 24) & 0xff), (byte) ((i >> 16) & 0xff), (byte) ((i >> 8) & 0xff),
+                (byte) (i & 0xff) };
+    }
+
+    /**
+     * Converts an IP address passed as integer value into the respective
+     * InetAddress object
+     *
+     * @param address
+     *            the IP address in integer form
+     * @return the IP address in InetAddress form
+     */
+    public static InetAddress getInetAddress(int address) {
+        InetAddress ip = null;
+        try {
+            ip = InetAddress.getByAddress(NetUtils.intToByteArray4(address));
+        } catch (UnknownHostException e) {
+            logger.error("", e);
+        }
+        return ip;
+    }
+
+    /**
+     * Return the InetAddress Network Mask given the length of the prefix bit
+     * mask. The prefix bit mask indicates the contiguous leading bits that are
+     * NOT masked out. Example: A prefix bit mask length of 8 will give an
+     * InetAddress Network Mask of 255.0.0.0
+     *
+     * @param prefixMaskLength
+     *            integer representing the length of the prefix network mask
+     * @param isV6
+     *            boolean representing the IP version of the returned address
+     * @return
+     */
+    public static InetAddress getInetNetworkMask(int prefixMaskLength, boolean isV6) {
+        if (prefixMaskLength < 0 || (!isV6 && prefixMaskLength > 32) || (isV6 && prefixMaskLength > 128)) {
+            return null;
+        }
+        byte v4Address[] = { 0, 0, 0, 0 };
+        byte v6Address[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+        byte address[] = (isV6) ? v6Address : v4Address;
+        int numBytes = prefixMaskLength / 8;
+        int numBits = prefixMaskLength % 8;
+        int i = 0;
+        for (; i < numBytes; i++) {
+            address[i] = (byte) 0xff;
+        }
+        if (numBits > 0) {
+            int rem = 0;
+            for (int j = 0; j < numBits; j++) {
+                rem |= 1 << (7 - j);
+            }
+            address[i] = (byte) rem;
+        }
+
+        try {
+            return InetAddress.getByAddress(address);
+        } catch (UnknownHostException e) {
+            logger.error("", e);
+        }
+        return null;
+    }
+
+    /**
+     * Returns the prefix size in bits of the specified subnet mask. Example:
+     * For the subnet mask ff.ff.ff.e0 it returns 25 while for ff.00.00.00 it
+     * returns 8. If the passed subnetMask array is null, 0 is returned.
+     *
+     * @param subnetMask
+     *            the subnet mask as byte array
+     * @return the prefix length as number of bits
+     */
+    public static int getSubnetMaskLength(byte[] subnetMask) {
+        int maskLength = 0;
+        if (subnetMask != null && (subnetMask.length == 4 || subnetMask.length == 16)) {
+            int index = 0;
+            while (index < subnetMask.length && subnetMask[index] == (byte) 0xFF) {
+                maskLength += NetUtils.NumBitsInAByte;
+                index++;
+            }
+            if (index != subnetMask.length) {
+                int bits = NetUtils.NumBitsInAByte - 1;
+                while (bits >= 0 && (subnetMask[index] & 1 << bits)  != 0) {
+                    bits--;
+                    maskLength++;
+                }
+            }
+        }
+        return maskLength;
+    }
+
+    /**
+     * Returns the prefix size in bits of the specified subnet mask. Example:
+     * For the subnet mask 255.255.255.128 it returns 25 while for 255.0.0.0 it
+     * returns 8. If the passed subnetMask object is null, 0 is returned
+     *
+     * @param subnetMask
+     *            the subnet mask as InetAddress
+     * @return the prefix length as number of bits
+     */
+    public static int getSubnetMaskLength(InetAddress subnetMask) {
+        return subnetMask == null ? 0 : NetUtils.getSubnetMaskLength(subnetMask.getAddress());
+    }
+
+    /**
+     * Given an IP address and a prefix network mask length, it returns the
+     * equivalent subnet prefix IP address Example: for ip = "172.28.30.254" and
+     * maskLen = 25 it will return "172.28.30.128"
+     *
+     * @param ip
+     *            the IP address in InetAddress form
+     * @param maskLen
+     *            the length of the prefix network mask
+     * @return the subnet prefix IP address in InetAddress form
+     */
+    public static InetAddress getSubnetPrefix(InetAddress ip, int maskLen) {
+        int bytes = maskLen / 8;
+        int bits = maskLen % 8;
+        byte modifiedByte;
+        byte[] sn = ip.getAddress();
+        if (bits > 0) {
+            modifiedByte = (byte) (sn[bytes] >> (8 - bits));
+            sn[bytes] = (byte) (modifiedByte << (8 - bits));
+            bytes++;
+        }
+        for (; bytes < sn.length; bytes++) {
+            sn[bytes] = (byte) (0);
+        }
+        try {
+            return InetAddress.getByAddress(sn);
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Checks if the test address and mask conflicts with the filter address and
+     * mask
+     *
+     * For example:
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.255.0
+     * do conflict
+     *
+     * testAddress: 172.28.2.23
+     * testMask: 255.255.255.0
+     * filterAddress: 172.28.1.10
+     * testMask: 255.255.0.0
+     * do not conflict
+     *
+     * Null parameters are permitted
+     *
+     * @param testAddress
+     * @param filterAddress
+     * @param testMask
+     * @param filterMask
+     * @return
+     */
+    public static boolean inetAddressConflict(InetAddress testAddress, InetAddress filterAddress, InetAddress testMask,
+            InetAddress filterMask) {
+        // Sanity check
+        if ((testAddress == null) || (filterAddress == null)) {
+            return false;
+        }
+
+        // Presence check
+        if (isAny(testAddress) || isAny(filterAddress)) {
+            return false;
+        }
+
+        int testMaskLen = (testMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                .getSubnetMaskLength(testMask);
+        int filterMaskLen = (filterMask == null) ? ((testAddress instanceof Inet4Address) ? 32 : 128) : NetUtils
+                .getSubnetMaskLength(filterMask);
+
+        // Mask length check. Test mask has to be more specific than filter one
+        if (testMaskLen < filterMaskLen) {
+            return true;
+        }
+
+        // Subnet Prefix on filter mask length must be the same
+        InetAddress prefix1 = getSubnetPrefix(testAddress, filterMaskLen);
+        InetAddress prefix2 = getSubnetPrefix(filterAddress, filterMaskLen);
+        return (!prefix1.equals(prefix2));
+    }
+
+    /**
+     * Returns true if the passed MAC address is all zero
+     *
+     * @param mac
+     *            the byte array representing the MAC address
+     * @return true if all MAC bytes are zero
+     */
+    public static boolean isZeroMAC(byte[] mac) {
+        for (short i = 0; i < 6; i++) {
+            if (mac[i] != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Returns true if the MAC address is the broadcast MAC address and false
+     * otherwise.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isBroadcastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes) {
+            for (int i = 0; i < 6; i++) {
+                if (MACAddress[i] != BroadcastMACAddr[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        return false;
+    }
+    /**
+     * Returns true if the MAC address is a unicast MAC address and false
+     * otherwise.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isUnicastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes) {
+            return (MACAddress[0] & 1) == 0;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the MAC address is a multicast MAC address and false
+     * otherwise. Note that this explicitly returns false for the broadcast MAC
+     * address.
+     *
+     * @param MACAddress
+     * @return
+     */
+    public static boolean isMulticastMACAddr(byte[] MACAddress) {
+        if (MACAddress.length == MACAddrLengthInBytes && !isBroadcastMACAddr(MACAddress)) {
+            return (MACAddress[0] & 1) != 0;
+        }
+        return false;
+    }
+
+    /**
+     * Returns true if the passed InetAddress contains all zero
+     *
+     * @param ip
+     *            the IP address to test
+     * @return true if the address is all zero
+     */
+    public static boolean isAny(InetAddress ip) {
+        for (byte b : ip.getAddress()) {
+            if (b != 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static boolean fieldsConflict(int field1, int field2) {
+        if ((field1 == 0) || (field2 == 0) || (field1 == field2)) {
+            return false;
+        }
+        return true;
+    }
+
+    public static InetAddress parseInetAddress(String addressString) {
+        InetAddress address = null;
+        try {
+            address = InetAddress.getByName(addressString);
+        } catch (UnknownHostException e) {
+            logger.error("", e);
+        }
+        return address;
+    }
+
+    /**
+     * Checks if the passed IP v4 address in string form is valid The address
+     * may specify a mask at the end as "/MM"
+     *
+     * @param cidr
+     *            the v4 address as A.B.C.D/MM
+     * @return
+     */
+    public static boolean isIPv4AddressValid(String cidr) {
+        if (cidr == null) {
+            return false;
+        }
+
+        String values[] = cidr.split("/");
+        Pattern ipv4Pattern = Pattern
+                .compile("(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])");
+        Matcher mm = ipv4Pattern.matcher(values[0]);
+        if (!mm.matches()) {
+            return false;
+        }
+        if (values.length >= 2) {
+            int prefix = Integer.valueOf(values[1]);
+            if ((prefix < 0) || (prefix > 32)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the passed IP v6 address in string form is valid The address
+     * may specify a mask at the end as "/MMM"
+     *
+     * @param cidr
+     *            the v6 address as A::1/MMM
+     * @return
+     */
+    public static boolean isIPv6AddressValid(String cidr) {
+        if (cidr == null) {
+            return false;
+        }
+
+        String values[] = cidr.split("/");
+        try {
+            // when given an IP address, InetAddress.getByName validates the ip
+            // address
+            InetAddress addr = InetAddress.getByName(values[0]);
+            if (!(addr instanceof Inet6Address)) {
+                return false;
+            }
+        } catch (UnknownHostException ex) {
+            return false;
+        }
+
+        if (values.length >= 2) {
+            int prefix = Integer.valueOf(values[1]);
+            if ((prefix < 0) || (prefix > 128)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Checks if the passed IP address in string form is a valid v4 or v6
+     * address. The address may specify a mask at the end as "/MMM"
+     *
+     * @param cidr
+     *            the v4 or v6 address as IP/MMM
+     * @return
+     */
+    public static boolean isIPAddressValid(String cidr) {
+        return NetUtils.isIPv4AddressValid(cidr) || NetUtils.isIPv6AddressValid(cidr);
+    }
+
+    /*
+     * Following utilities are useful when you need to compare or bit shift java
+     * primitive type variable which are inherently signed
+     */
+    /**
+     * Returns the unsigned value of the passed byte variable
+     *
+     * @param b
+     *            the byte value
+     * @return the int variable containing the unsigned byte value
+     */
+    public static int getUnsignedByte(byte b) {
+        return b & 0xFF;
+    }
+
+    /**
+     * Return the unsigned value of the passed short variable
+     *
+     * @param s
+     *            the short value
+     * @return the int variable containing the unsigned short value
+     */
+    public static int getUnsignedShort(short s) {
+        return s & 0xFFFF;
+    }
+
+    /**
+     * Returns the highest v4 or v6 InetAddress
+     *
+     * @param v6
+     *            true for IPv6, false for Ipv4
+     * @return The highest IPv4 or IPv6 address
+     */
+    public static InetAddress gethighestIP(boolean v6) {
+        try {
+            return (v6) ? InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") : InetAddress
+                    .getByName("255.255.255.255");
+        } catch (UnknownHostException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Returns Broadcast MAC Address
+     *
+     * @return the byte array containing  broadcast mac address
+     */
+    public static byte[] getBroadcastMACAddr() {
+        return Arrays.copyOf(BroadcastMACAddr, BroadcastMACAddr.length);
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/Packet.java
new file mode 100644 (file)
index 0000000..2af1852
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * Copyright (c) 2013-2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.liblldp;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.commons.lang3.tuple.Pair;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract class which represents the generic network packet object It provides
+ * the basic methods which are common for all the packets, like serialize and
+ * deserialize
+ */
+
+public abstract class Packet {
+    protected static final Logger logger = LoggerFactory
+            .getLogger(Packet.class);
+    // Access level granted to this packet
+    protected boolean writeAccess;
+    // When deserialized from wire, packet could result corrupted
+    protected boolean corrupted;
+    // The packet that encapsulate this packet
+    protected Packet parent;
+    // The packet encapsulated by this packet
+    protected Packet payload;
+    // The unparsed raw payload carried by this packet
+    protected byte[] rawPayload;
+    // Bit coordinates of packet header fields
+    protected Map<String, Pair<Integer, Integer>> hdrFieldCoordMap;
+    // Header fields values: Map<FieldName,Value>
+    protected Map<String, byte[]> hdrFieldsMap;
+    // The class of the encapsulated packet object
+    protected Class<? extends Packet> payloadClass;
+
+    public Packet() {
+        writeAccess = false;
+        corrupted = false;
+    }
+
+    public Packet(boolean writeAccess) {
+        this.writeAccess = writeAccess;
+        corrupted = false;
+    }
+
+    public Packet getParent() {
+        return parent;
+    }
+
+    public Packet getPayload() {
+        return payload;
+    }
+
+    public void setParent(Packet parent) {
+        this.parent = parent;
+    }
+
+    public void setPayload(Packet payload) {
+        this.payload = payload;
+    }
+
+    public void setHeaderField(String headerField, byte[] readValue) {
+        hdrFieldsMap.put(headerField, readValue);
+    }
+
+    /**
+     * This method deserializes the data bits obtained from the wire into the
+     * respective header and payload which are of type Packet
+     *
+     * @param byte[] data - data from wire to deserialize
+     * @param int bitOffset bit position where packet header starts in data
+     *        array
+     * @param int size of packet in bits
+     * @return Packet
+     * @throws PacketException
+     */
+    public Packet deserialize(byte[] data, int bitOffset, int size)
+            throws PacketException {
+
+        // Deserialize the header fields one by one
+        int startOffset = 0, numBits = 0;
+        for (Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
+                .entrySet()) {
+            String hdrField = pairs.getKey();
+            startOffset = bitOffset + this.getfieldOffset(hdrField);
+            numBits = this.getfieldnumBits(hdrField);
+
+            byte[] hdrFieldBytes = null;
+            try {
+                hdrFieldBytes = BitBufferHelper.getBits(data, startOffset,
+                        numBits);
+            } catch (BufferException e) {
+                throw new PacketException(e.getMessage());
+            }
+
+            /*
+             * Store the raw read value, checks the payload type and set the
+             * payloadClass accordingly
+             */
+            this.setHeaderField(hdrField, hdrFieldBytes);
+
+            if (logger.isTraceEnabled()) {
+                logger.trace("{}: {}: {} (offset {} bitsize {})",
+                        new Object[] { this.getClass().getSimpleName(), hdrField,
+                        HexEncode.bytesToHexString(hdrFieldBytes),
+                        startOffset, numBits });
+            }
+        }
+
+        // Deserialize the payload now
+        int payloadStart = startOffset + numBits;
+        int payloadSize = data.length * NetUtils.NumBitsInAByte - payloadStart;
+
+        if (payloadClass != null) {
+            try {
+                payload = payloadClass.newInstance();
+            } catch (Exception e) {
+                throw new RuntimeException(
+                        "Error parsing payload for Ethernet packet", e);
+            }
+            payload.deserialize(data, payloadStart, payloadSize);
+            payload.setParent(this);
+        } else {
+            /*
+             *  The payload class was not set, it means no class for parsing
+             *  this payload is present. Let's store the raw payload if any.
+             */
+            int start = payloadStart / NetUtils.NumBitsInAByte;
+            int stop = start + payloadSize / NetUtils.NumBitsInAByte;
+            rawPayload = Arrays.copyOfRange(data, start, stop);
+        }
+
+
+        // Take care of computation that can be done only after deserialization
+        postDeserializeCustomOperation(data, payloadStart - getHeaderSize());
+
+        return this;
+    }
+
+    /**
+     * This method serializes the header and payload from the respective
+     * packet class, into a single stream of bytes to be sent on the wire
+     *
+     * @return The byte array representing the serialized Packet
+     * @throws PacketException
+     */
+    public byte[] serialize() throws PacketException {
+
+        // Acquire or compute the serialized payload
+        byte[] payloadBytes = null;
+        if (payload != null) {
+            payloadBytes = payload.serialize();
+        } else if (rawPayload != null) {
+            payloadBytes = rawPayload;
+        }
+        int payloadSize = (payloadBytes == null) ? 0 : payloadBytes.length;
+
+        // Allocate the buffer to contain the full (header + payload) packet
+        int headerSize = this.getHeaderSize() / NetUtils.NumBitsInAByte;
+        byte packetBytes[] = new byte[headerSize + payloadSize];
+        if (payloadBytes != null) {
+            System.arraycopy(payloadBytes, 0, packetBytes, headerSize, payloadSize);
+        }
+
+        // Serialize this packet header, field by field
+        for (Map.Entry<String, Pair<Integer, Integer>> pairs : hdrFieldCoordMap
+                .entrySet()) {
+            String field = pairs.getKey();
+            byte[] fieldBytes = hdrFieldsMap.get(field);
+            // Let's skip optional fields when not set
+            if (fieldBytes != null) {
+                try {
+                    BitBufferHelper.setBytes(packetBytes, fieldBytes,
+                            getfieldOffset(field), getfieldnumBits(field));
+                } catch (BufferException e) {
+                    throw new PacketException(e.getMessage());
+                }
+            }
+        }
+
+        // Perform post serialize operations (like checksum computation)
+        postSerializeCustomOperation(packetBytes);
+
+        if (logger.isTraceEnabled()) {
+            logger.trace("{}: {}", this.getClass().getSimpleName(),
+                    HexEncode.bytesToHexString(packetBytes));
+        }
+
+        return packetBytes;
+    }
+
+    /**
+     * This method gets called at the end of the serialization process It is
+     * intended for the child packets to insert some custom data into the output
+     * byte stream which cannot be done or cannot be done efficiently during the
+     * normal Packet.serialize() path. An example is the checksum computation
+     * for IPv4
+     *
+     * @param byte[] - serialized bytes
+     * @throws PacketException
+     */
+    protected void postSerializeCustomOperation(byte[] myBytes)
+            throws PacketException {
+        // no op
+    }
+
+    /**
+     * This method re-computes the checksum of the bits received on the wire and
+     * validates it with the checksum in the bits received Since the computation
+     * of checksum varies based on the protocol, this method is overridden.
+     * Currently only IPv4 and ICMP do checksum computation and validation. TCP
+     * and UDP need to implement these if required.
+     *
+     * @param byte[] data The byte stream representing the Ethernet frame
+     * @param int startBitOffset The bit offset from where the byte array corresponding to this Packet starts in the frame
+     * @throws PacketException
+     */
+    protected void postDeserializeCustomOperation(byte[] data, int startBitOffset)
+            throws PacketException {
+        // no op
+    }
+
+    /**
+     * Gets the header length in bits
+     *
+     * @return int the header length in bits
+     */
+    public int getHeaderSize() {
+        int size = 0;
+        /*
+         * We need to iterate over the fields that were read in the frame
+         * (hdrFieldsMap) not all the possible ones described in
+         * hdrFieldCoordMap. For ex, 802.1Q may or may not be there
+         */
+        for (Map.Entry<String, byte[]> fieldEntry : hdrFieldsMap.entrySet()) {
+            if (fieldEntry.getValue() != null) {
+                String field = fieldEntry.getKey();
+                size += getfieldnumBits(field);
+            }
+        }
+        return size;
+    }
+
+    /**
+     * This method fetches the start bit offset for header field specified by
+     * 'fieldname'. The offset is present in the hdrFieldCoordMap of the
+     * respective packet class
+     *
+     * @param String
+     *            fieldName
+     * @return Integer - startOffset of the requested field
+     */
+    public int getfieldOffset(String fieldName) {
+        return hdrFieldCoordMap.get(fieldName).getLeft();
+    }
+
+    /**
+     * This method fetches the number of bits for header field specified by
+     * 'fieldname'. The numBits are present in the hdrFieldCoordMap of the
+     * respective packet class
+     *
+     * @param String
+     *            fieldName
+     * @return Integer - number of bits of the requested field
+     */
+    public int getfieldnumBits(String fieldName) {
+        return hdrFieldCoordMap.get(fieldName).getRight();
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder ret = new StringBuilder();
+        ret.append(this.getClass().getSimpleName());
+        ret.append(": [");
+        for (String field : hdrFieldCoordMap.keySet()) {
+            byte[] value = hdrFieldsMap.get(field);
+            ret.append(field);
+            ret.append(": ");
+            ret.append(HexEncode.bytesToHexString(value));
+            ret.append(", ");
+        }
+        ret.replace(ret.length()-2, ret.length()-1, "]");
+        return ret.toString();
+    }
+
+    /**
+     * Returns the raw payload carried by this packet in case payload was not
+     * parsed. Caller can call this function in case the getPaylod() returns null.
+     *
+     * @return The raw payload if not parsable as an array of bytes, null otherwise
+     */
+    public byte[] getRawPayload() {
+        return rawPayload;
+    }
+
+    /**
+     * Set a raw payload in the packet class
+     *
+     * @param payload The raw payload as byte array
+     */
+    public void setRawPayload(byte[] payload) {
+        this.rawPayload = Arrays.copyOf(payload, payload.length);
+    }
+
+    /**
+     * Return whether the deserialized packet is to be considered corrupted.
+     * This is the case when the checksum computed after reconstructing the
+     * packet received from wire is not equal to the checksum read from the
+     * stream. For the Packet class which do not have a checksum field, this
+     * function will always return false.
+     *
+     *
+     * @return true if the deserialized packet's recomputed checksum is not
+     *         equal to the packet carried checksum
+     */
+    public boolean isCorrupted() {
+        return corrupted;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = super.hashCode();
+        result = prime * result
+                + ((this.hdrFieldsMap == null) ? 0 : hdrFieldsMap.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        Packet other = (Packet) obj;
+        if (hdrFieldsMap == other.hdrFieldsMap) {
+            return true;
+        }
+        if (hdrFieldsMap == null || other.hdrFieldsMap == null) {
+            return false;
+        }
+        if (hdrFieldsMap != null && other.hdrFieldsMap != null) {
+            for (String field : hdrFieldsMap.keySet()) {
+                if (!Arrays.equals(hdrFieldsMap.get(field), other.hdrFieldsMap.get(field))) {
+                    return false;
+                }
+            }
+        } else {
+            return false;
+        }
+        return true;
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java b/opendaylight/commons/liblldp/src/main/java/org/opendaylight/controller/liblldp/PacketException.java
new file mode 100644 (file)
index 0000000..c69fc03
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.liblldp;
+
+/**
+ * Describes an exception that is raised when the process of serializing or
+ * deserializing a network packet/stream fails. This generally happens when the
+ * packet/stream is malformed.
+ *
+ */
+public class PacketException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    public PacketException(String message) {
+        super(message);
+    }
+}
diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/BitBufferHelperTest.java
new file mode 100644 (file)
index 0000000..07fbf05
--- /dev/null
@@ -0,0 +1,693 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.packet;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+import org.opendaylight.controller.liblldp.BitBufferHelper;
+
+public class BitBufferHelperTest {
+
+    @Test
+    public void testGetByte() {
+        byte[] data = { 100 };
+        Assert.assertTrue(BitBufferHelper.getByte(data) == 100);
+    }
+
+    @Test
+    public void testGetBits() throws Exception {
+        byte[] data = { 10, 12, 14, 20, 55, 69, 82, 97, 109, 117, 127, -50 };
+        byte[] bits;
+
+        bits = BitBufferHelper.getBits(data, 88, 8); //BYTE extraOffsetBits = extranumBits = 0
+        Assert.assertTrue(bits[0] == -50);
+
+        bits = BitBufferHelper.getBits(data, 8, 16); //Short
+        Assert.assertTrue(bits[0] == 12);
+        Assert.assertTrue(bits[1] == 14);
+
+        bits = BitBufferHelper.getBits(data, 32, 32); //Int
+        Assert.assertTrue(bits[0] == 55);
+        Assert.assertTrue(bits[1] == 69);
+        Assert.assertTrue(bits[2] == 82);
+        Assert.assertTrue(bits[3] == 97);
+
+        bits = BitBufferHelper.getBits(data, 16, 48); //Long
+        Assert.assertTrue(bits[0] == 14);
+        Assert.assertTrue(bits[1] == 20);
+        Assert.assertTrue(bits[2] == 55);
+        Assert.assertTrue(bits[3] == 69);
+        Assert.assertTrue(bits[4] == 82);
+        Assert.assertTrue(bits[5] == 97);
+
+        bits = BitBufferHelper.getBits(data, 40, 7); //BYTE extraOffsetBits = extranumBits != 0
+        Assert.assertTrue(bits[0] == 34);
+
+        bits = BitBufferHelper.getBits(data, 8, 13); //Short
+        Assert.assertTrue(bits[0] == 1);
+        Assert.assertTrue(bits[1] == -127);
+
+        bits = BitBufferHelper.getBits(data, 32, 28); //Int
+        Assert.assertTrue(bits[0] == 3);
+        Assert.assertTrue(bits[1] == 116);
+        Assert.assertTrue(bits[2] == 85);
+        Assert.assertTrue(bits[3] == 38);
+
+        bits = BitBufferHelper.getBits(data, 16, 41); //Long
+        Assert.assertTrue(bits[0] == 0);
+        Assert.assertTrue(bits[1] == 28);
+        Assert.assertTrue(bits[2] == 40);
+        Assert.assertTrue(bits[3] == 110);
+        Assert.assertTrue(bits[4] == -118);
+        Assert.assertTrue(bits[5] == -92);
+
+        bits = BitBufferHelper.getBits(data, 3, 7); //BYTE extraOffsetBits != 0; extranumBits == 0
+        Assert.assertTrue(bits[0] == 40);
+
+        bits = BitBufferHelper.getBits(data, 13, 16); //Short
+        Assert.assertTrue(bits[0] == -127);
+        Assert.assertTrue(bits[1] == -62);
+
+        bits = BitBufferHelper.getBits(data, 5, 32); //Int
+        Assert.assertTrue(bits[0] == 65);
+        Assert.assertTrue(bits[1] == -127);
+        Assert.assertTrue(bits[2] == -62);
+        Assert.assertTrue(bits[3] == -122);
+
+        bits = BitBufferHelper.getBits(data, 23, 48); //Long
+        Assert.assertTrue(bits[0] == 10);
+        Assert.assertTrue(bits[1] == 27);
+        Assert.assertTrue(bits[2] == -94);
+        Assert.assertTrue(bits[3] == -87);
+        Assert.assertTrue(bits[4] == 48);
+        Assert.assertTrue(bits[5] == -74);
+
+        bits = BitBufferHelper.getBits(data, 66, 9); //BYTE extraOffsetBits != 0; extranumBits != 0
+        Assert.assertTrue(bits[0] == 1);
+        Assert.assertTrue(bits[1] == 107);
+
+        bits = BitBufferHelper.getBits(data, 13, 15); //Short
+        Assert.assertTrue(bits[0] == 64);
+        Assert.assertTrue(bits[1] == -31);
+
+        bits = BitBufferHelper.getBits(data, 5, 29); //Int
+        Assert.assertTrue(bits[0] == 8);
+        Assert.assertTrue(bits[1] == 48);
+        Assert.assertTrue(bits[2] == 56);
+        Assert.assertTrue(bits[3] == 80);
+
+        bits = BitBufferHelper.getBits(data, 31, 43); //Long
+        Assert.assertTrue(bits[0] == 0);
+        Assert.assertTrue(bits[1] == -35);
+        Assert.assertTrue(bits[2] == 21);
+        Assert.assertTrue(bits[3] == 73);
+        Assert.assertTrue(bits[4] == -123);
+        Assert.assertTrue(bits[5] == -75);
+
+        bits = BitBufferHelper.getBits(data, 4, 12); //Short
+        Assert.assertTrue(bits[0] == 10);
+        Assert.assertTrue(bits[1] == 12);
+
+        byte[] data1 = { 0, 8 };
+        bits = BitBufferHelper.getBits(data1, 7, 9); //Short
+        Assert.assertTrue(bits[0] == 0);
+        Assert.assertTrue(bits[1] == 8);
+
+        byte[] data2 = { 2, 8 };
+        bits = BitBufferHelper.getBits(data2, 0, 7); //Short
+        Assert.assertTrue(bits[0] == 1);
+
+        bits = BitBufferHelper.getBits(data2, 7, 9); //Short
+        Assert.assertTrue(bits[0] == 0);
+        Assert.assertTrue(bits[1] == 8);
+    }
+
+    // [01101100][01100000]
+    //     [01100011]
+    @Test
+    public void testGetBytes() throws Exception {
+        byte data[] = { 108, 96, 125, -112, 5, 6, 108, 8, 9, 10, 11, 12, 13,
+                14, 15, 16, 17, 18, 19, 20, 21, 22 };
+        byte[] x;
+
+        Assert.assertTrue(BitBufferHelper.getBits(data, 0, 8)[0] == 108);
+        Assert.assertTrue(BitBufferHelper.getBits(data, 8, 8)[0] == 96);
+
+        x = BitBufferHelper.getBits(data, 0, 10);
+        Assert.assertTrue(x[0] == 1);
+        Assert.assertTrue(x[1] == -79);
+
+        x = BitBufferHelper.getBits(data, 3, 8);
+        Assert.assertTrue(x[0] == 99);
+        //Assert.assertTrue(x[1] == 97);
+
+    }
+
+    @Test
+    public void testMSBMask() {
+        int numBits = 1; //MSB
+        int mask = BitBufferHelper.getMSBMask(numBits);
+        Assert.assertTrue(mask == 128);
+
+        numBits = 8;
+        mask = BitBufferHelper.getMSBMask(numBits);
+        Assert.assertTrue(mask == 255);
+
+        numBits = 2;
+        mask = BitBufferHelper.getMSBMask(numBits);
+        Assert.assertTrue(mask == 192);
+    }
+
+    @Test
+    public void testLSBMask() {
+        int numBits = 1; //LSB
+        int mask = BitBufferHelper.getLSBMask(numBits);
+        Assert.assertTrue(mask == 1);
+
+        numBits = 3;
+        mask = BitBufferHelper.getLSBMask(numBits);
+        Assert.assertTrue(mask == 7);
+
+        numBits = 8;
+        mask = BitBufferHelper.getLSBMask(numBits);
+        Assert.assertTrue(mask == 255);
+    }
+
+    @Test
+    public void testToByteArray() {
+        short sh = Short.MAX_VALUE;
+        byte[] data_sh = new byte[Byte.SIZE / 8];
+        data_sh = BitBufferHelper.toByteArray(sh);
+        Assert.assertTrue(data_sh[0] == 127);
+        Assert.assertTrue(data_sh[1] == -1);
+
+        short sh2 = Short.MIN_VALUE;
+        byte[] data_sh2 = new byte[Byte.SIZE / 8];
+        data_sh2 = BitBufferHelper.toByteArray(sh2);
+        Assert.assertTrue(data_sh2[0] == -128);
+        Assert.assertTrue(data_sh2[1] == 0);
+
+        short sh3 = 16384;
+        byte[] data_sh3 = new byte[Byte.SIZE / 8];
+        data_sh3 = BitBufferHelper.toByteArray(sh3);
+        Assert.assertTrue(data_sh3[0] == 64);
+        Assert.assertTrue(data_sh3[1] == 0);
+
+        short sh4 = 146; //TCP headerlenflags - startoffset = 103
+        byte[] data_sh4 = new byte[Byte.SIZE / 8];
+        data_sh4 = BitBufferHelper.toByteArray(sh4);
+        Assert.assertTrue(data_sh4[0] == 0);
+        Assert.assertTrue(data_sh4[1] == -110);
+
+        short sh4_2 = 5000; //IPv4 Offset - startOffset = 51 (to 63)
+        byte[] data_sh4_2 = new byte[Byte.SIZE / 8];
+        data_sh4_2 = BitBufferHelper.toByteArray(sh4_2);
+        Assert.assertTrue(data_sh4_2[0] == 19);
+        Assert.assertTrue(data_sh4_2[1] == -120);
+
+        short sh4_3 = 5312; //numEndRestBits < numBitstoShiftBy
+        byte[] data_sh4_3 = new byte[Byte.SIZE / 8];
+        data_sh4_3 = BitBufferHelper.toByteArray(sh4_3);
+        Assert.assertTrue(data_sh4_3[0] == 20);
+        Assert.assertTrue(data_sh4_3[1] == -64);
+
+        int Int = Integer.MAX_VALUE;
+        byte[] data_Int = new byte[Integer.SIZE / 8];
+        data_Int = BitBufferHelper.toByteArray(Int);
+        Assert.assertTrue(data_Int[0] == 127);
+        Assert.assertTrue(data_Int[1] == -1);
+        Assert.assertTrue(data_Int[2] == -1);
+        Assert.assertTrue(data_Int[3] == -1);
+
+        int Int2 = Integer.MIN_VALUE;
+        byte[] data_Int2 = new byte[Integer.SIZE / 8];
+        data_Int2 = BitBufferHelper.toByteArray(Int2);
+        Assert.assertTrue(data_Int2[0] == -128);
+        Assert.assertTrue(data_Int2[1] == 0);
+        Assert.assertTrue(data_Int2[2] == 0);
+        Assert.assertTrue(data_Int2[3] == 0);
+
+        int Int3 = 1077952576;
+        byte[] data_Int3 = new byte[Integer.SIZE / 8];
+        data_Int3 = BitBufferHelper.toByteArray(Int3);
+        Assert.assertTrue(data_Int3[0] == 64);
+        Assert.assertTrue(data_Int3[1] == 64);
+        Assert.assertTrue(data_Int3[2] == 64);
+        Assert.assertTrue(data_Int3[3] == 64);
+
+        long Lng = Long.MAX_VALUE;
+        byte[] data_lng = new byte[Long.SIZE / 8];
+        data_lng = BitBufferHelper.toByteArray(Lng);
+        Assert.assertTrue(data_lng[0] == 127);
+        Assert.assertTrue(data_lng[1] == -1);
+        Assert.assertTrue(data_lng[2] == -1);
+        Assert.assertTrue(data_lng[3] == -1);
+        Assert.assertTrue(data_lng[4] == -1);
+        Assert.assertTrue(data_lng[5] == -1);
+        Assert.assertTrue(data_lng[6] == -1);
+        Assert.assertTrue(data_lng[7] == -1);
+
+        long Lng2 = Long.MIN_VALUE;
+        byte[] data_lng2 = new byte[Long.SIZE / 8];
+        data_lng2 = BitBufferHelper.toByteArray(Lng2);
+        Assert.assertTrue(data_lng2[0] == -128);
+        Assert.assertTrue(data_lng2[1] == 0);
+        Assert.assertTrue(data_lng2[2] == 0);
+        Assert.assertTrue(data_lng2[3] == 0);
+        Assert.assertTrue(data_lng2[4] == 0);
+        Assert.assertTrue(data_lng2[5] == 0);
+        Assert.assertTrue(data_lng2[6] == 0);
+        Assert.assertTrue(data_lng2[7] == 0);
+
+        byte B = Byte.MAX_VALUE;
+        byte[] data_B = new byte[Byte.SIZE / 8];
+        data_B = BitBufferHelper.toByteArray(B);
+        Assert.assertTrue(data_B[0] == 127);
+
+        byte B1 = Byte.MIN_VALUE;
+        byte[] data_B1 = new byte[Byte.SIZE / 8];
+        data_B1 = BitBufferHelper.toByteArray(B1);
+        Assert.assertTrue(data_B1[0] == -128);
+
+        byte B2 = 64;
+        byte[] data_B2 = new byte[Byte.SIZE / 8];
+        data_B2 = BitBufferHelper.toByteArray(B2);
+        Assert.assertTrue(data_B2[0] == 64);
+
+        byte B3 = 32;
+        byte[] data_B3 = new byte[Byte.SIZE / 8];
+        data_B3 = BitBufferHelper.toByteArray(B3);
+        Assert.assertTrue(data_B3[0] == 32);
+
+    }
+
+    @Test
+    public void testToByteArrayVariable() {
+        int len = 9;
+        byte[] data_sh;
+        data_sh = BitBufferHelper.toByteArray(511, len);
+        Assert.assertTrue(data_sh[0] == (byte) 255);
+        Assert.assertTrue(data_sh[1] == (byte) 128);
+
+        data_sh = BitBufferHelper.toByteArray((int) 511, len);
+        Assert.assertTrue(data_sh[0] == (byte) 255);
+        Assert.assertTrue(data_sh[1] == (byte) 128);
+
+        data_sh = BitBufferHelper.toByteArray((long) 511, len);
+        Assert.assertTrue(data_sh[0] == (byte) 255);
+        Assert.assertTrue(data_sh[1] == (byte) 128);
+    }
+
+    @Test
+    public void testToInt() {
+        byte data[] = { 1 };
+        Assert.assertTrue(BitBufferHelper.toNumber(data) == 1);
+
+        byte data2[] = { 1, 1 };
+        Assert.assertTrue(BitBufferHelper.toNumber(data2) == 257);
+
+        byte data3[] = { 1, 1, 1 };
+        Assert.assertTrue(BitBufferHelper.toNumber(data3) == 65793);
+    }
+
+    @Test
+    public void testToLongGetter() {
+        byte data[] = { 1, 1 };
+        Assert.assertTrue(BitBufferHelper.getLong(data) == 257L);
+    }
+
+    @Test
+    public void testSetByte() throws Exception {
+        byte input;
+        byte[] data = new byte[20];
+
+        input = 125;
+        BitBufferHelper.setByte(data, input, 0, Byte.SIZE);
+        Assert.assertTrue(data[0] == 125);
+
+        input = 109;
+        BitBufferHelper.setByte(data, input, 152, Byte.SIZE);
+        Assert.assertTrue(data[19] == 109);
+    }
+
+    @Test
+    public void testSetBytes() throws Exception {
+        byte[] input = { 0, 1 };
+        byte[] data = { 6, 0 };
+
+        BitBufferHelper.setBytes(data, input, 7, 9);
+        Assert.assertTrue(data[0] == 6);
+        Assert.assertTrue(data[1] == 1);
+    }
+
+    //@Test
+    //INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+    // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]*/
+    public void testInsertBits() throws Exception {
+        //CASE 1: startOffset%8 == 0 && numBits%8 == 0
+        byte inputdata[] = { 75, 110, 107, 80, 10, 12, 35, 100, 125, 65 };
+        int startOffset = 0;
+        int numBits = 8;
+
+        byte data1[] = new byte[2];
+        startOffset = 0;
+        numBits = 16;
+        BitBufferHelper.insertBits(data1, inputdata, startOffset, numBits);
+        Assert.assertTrue(data1[0] == 75);
+        Assert.assertTrue(data1[1] == 110);
+
+        byte data2[] = new byte[4];
+        startOffset = 0;
+        numBits = 32;
+        BitBufferHelper.insertBits(data2, inputdata, startOffset, numBits);
+        Assert.assertTrue(data2[0] == 75);
+        Assert.assertTrue(data2[1] == 110);
+        Assert.assertTrue(data2[2] == 107);
+        Assert.assertTrue(data2[3] == 80);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        // OUTPUT: [01001011] [01101000] = {75, 104}
+        byte data10[] = new byte[2];
+        startOffset = 0;
+        numBits = 13;
+        BitBufferHelper.insertBits(data10, inputdata, startOffset, numBits);
+        Assert.assertTrue(data10[0] == 75);
+        Assert.assertTrue(data10[1] == 104);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        // OUTPUT: [01001000] = {72}
+        byte data11[] = new byte[4];
+        startOffset = 8;
+        numBits = 6;
+        BitBufferHelper.insertBits(data11, inputdata, startOffset, numBits);
+        Assert.assertTrue(data11[1] == 72);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [01001011] [01101110] [01101000] = {75, 110, 105}
+        byte data12[] = new byte[4];
+        startOffset = 0;
+        numBits = 23;
+        BitBufferHelper.insertBits(data12, inputdata, startOffset, numBits);
+        Assert.assertTrue(data12[0] == 75);
+        Assert.assertTrue(data12[1] == 110);
+        Assert.assertTrue(data12[2] == 106);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [01001011] [01101110] [01100000] = {75, 110, 96}
+        byte data13[] = new byte[4];
+        startOffset = 8;
+        numBits = 20;
+        BitBufferHelper.insertBits(data13, inputdata, startOffset, numBits);
+        Assert.assertTrue(data13[1] == 75);
+        Assert.assertTrue(data13[2] == 110);
+        Assert.assertTrue(data13[3] == 96);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [01001011] [01101110] [01101011] [10100000]= {75, 110, 107, 80}
+        byte data14[] = new byte[4];
+        startOffset = 0;
+        numBits = 30;
+        BitBufferHelper.insertBits(data14, inputdata, startOffset, numBits);
+        Assert.assertTrue(data14[0] == 75);
+        Assert.assertTrue(data14[1] == 110);
+        Assert.assertTrue(data14[2] == 107);
+        Assert.assertTrue(data14[3] == 80);
+
+        //CASE 3: startOffset%8 != 0, numBits%8 = 0
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [10100000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00001001] [11000000] = {72, 96}
+        byte data16[] = new byte[5];
+        startOffset = 3;
+        numBits = 8;
+        BitBufferHelper.insertBits(data16, inputdata, startOffset, numBits);
+        Assert.assertTrue(data16[0] == 9);
+        Assert.assertTrue(data16[1] == 96);
+        Assert.assertTrue(data16[2] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [00000100] [1011 0110] [1110 0000] = {4, -54, -96}
+
+        startOffset = 3;
+        numBits = 16;
+        byte data17[] = new byte[5];
+        BitBufferHelper.insertBits(data17, inputdata, startOffset, numBits);
+        Assert.assertTrue(data17[0] == 9);
+        Assert.assertTrue(data17[1] == 109);
+        Assert.assertTrue(data17[2] == -64);
+        Assert.assertTrue(data17[3] == 0);
+
+        // INPUT: {79, 110, 111}
+        // = [01001111] [01101110] [01101111]
+        //OUTPUT: [0000 1001] [1110 1101] [110 00000] = {9, -19, -64}
+        byte data18[] = new byte[5];
+        byte inputdata3[] = { 79, 110, 111 };
+        startOffset = 3;
+        numBits = 16;
+        BitBufferHelper.insertBits(data18, inputdata3, startOffset, numBits);
+        Assert.assertTrue(data18[0] == 9);
+        Assert.assertTrue(data18[1] == -19);
+        Assert.assertTrue(data18[2] == -64);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 1001] [0110 1101] [1100 1101] [0110 1010] [0000 0001] = {9, 109, -51, 106, 0}
+
+        startOffset = 3;
+        numBits = 32;
+        byte data19[] = new byte[5];
+        BitBufferHelper.insertBits(data19, inputdata, startOffset, numBits);
+        Assert.assertTrue(data19[0] == 9);
+        Assert.assertTrue(data19[1] == 109);
+        Assert.assertTrue(data19[2] == -51);
+        Assert.assertTrue(data19[3] == 106);
+        Assert.assertTrue(data19[4] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: data[4, 5, 6] = [0 010 0101] [1 011 0111] [0 000 0000] = {37, -73, 0}
+        startOffset = 33;
+        numBits = 16;
+        byte data20[] = new byte[7];
+        BitBufferHelper.insertBits(data20, inputdata, startOffset, numBits);
+        Assert.assertTrue(data20[4] == 37);
+        Assert.assertTrue(data20[5] == -73);
+        Assert.assertTrue(data20[6] == 0);
+
+        //CASE 4: extranumBits != 0 AND extraOffsetBits != 0
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 1001] [0100 0000]  = {9, 96}
+        startOffset = 3;
+        numBits = 7;
+        byte data21[] = new byte[7];
+        BitBufferHelper.insertBits(data21, inputdata, startOffset, numBits);
+        Assert.assertTrue(data21[0] == 9);
+        Assert.assertTrue(data21[1] == 64);
+        Assert.assertTrue(data21[2] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: data = [00000 010] [01011 011] [01110 000] = {37, -73, 0}
+        startOffset = 5;
+        numBits = 17;
+        byte data22[] = new byte[7];
+        BitBufferHelper.insertBits(data22, inputdata, startOffset, numBits);
+        Assert.assertTrue(data22[0] == 2);
+        Assert.assertTrue(data22[1] == 91);
+        Assert.assertTrue(data22[2] == 112);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 1001] [0110 1101] [110 01101] [01 00000] = {9, 109, -51, 64}
+        startOffset = 3;
+        numBits = 23;
+        byte data23[] = new byte[7];
+        BitBufferHelper.insertBits(data23, inputdata, startOffset, numBits);
+        Assert.assertTrue(data23[0] == 9);
+        Assert.assertTrue(data23[1] == 109);
+        Assert.assertTrue(data23[2] == -51);
+        Assert.assertTrue(data23[3] == 64);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 1001] [0110 1101]  = {9, 109}
+        startOffset = 3;
+        numBits = 13;
+        byte data24[] = new byte[7];
+        BitBufferHelper.insertBits(data24, inputdata, startOffset, numBits);
+        Assert.assertTrue(data24[0] == 9);
+        Assert.assertTrue(data24[1] == 109);
+        Assert.assertTrue(data24[2] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 0100] [1011 0110] [1110 0110]  = {4, -74, -26}
+        startOffset = 4;
+        numBits = 20;
+        byte data25[] = new byte[7];
+        BitBufferHelper.insertBits(data25, inputdata, startOffset, numBits);
+        Assert.assertTrue(data25[0] == 4);
+        Assert.assertTrue(data25[1] == -74);
+        Assert.assertTrue(data25[2] == -26);
+        Assert.assertTrue(data25[3] == -0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [0000 0010] [0101 1011]   = {0, 2, 91, 0}
+        startOffset = 13;
+        numBits = 11;
+        byte data26[] = new byte[7];
+        BitBufferHelper.insertBits(data26, inputdata, startOffset, numBits);
+        Assert.assertTrue(data26[0] == 0);
+        Assert.assertTrue(data26[1] == 2);
+        Assert.assertTrue(data26[2] == 91);
+        Assert.assertTrue(data26[3] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [000 01001] [011 01101] [110 0 0000]   = {9, 109, -64, 0}
+        startOffset = 3;
+        numBits = 17;
+        byte data27[] = new byte[7];
+        BitBufferHelper.insertBits(data27, inputdata, startOffset, numBits);
+        Assert.assertTrue(data27[0] == 9);
+        Assert.assertTrue(data27[1] == 109);
+        Assert.assertTrue(data27[2] == -64);
+        Assert.assertTrue(data27[3] == 0);
+
+        // INPUT: {75, 110, 107, 80, 10, 12, 35, 100, 125, 65} =
+        // [01001011] [01101110] [01101011] [01010000] [00001010] [00001100] [00100011] [01100100] [11111101] [01000001]        //OUTPUT: [00000000] [00000100] [10110110] [11100000]= {0, 4, -54, -96}
+        // OUTPUT: [00 000000] [00 000000] [00 010010] [11 011011] [10 011010] [11 010100] [0000 0000] = {0, 0, 18, -37,-102,-44,0}
+        startOffset = 18;
+        numBits = 34;
+        byte data28[] = new byte[7];
+        BitBufferHelper.insertBits(data28, inputdata, startOffset, numBits);
+        Assert.assertTrue(data28[0] == 0);
+        Assert.assertTrue(data28[1] == 0);
+        Assert.assertTrue(data28[2] == 18);
+        Assert.assertTrue(data28[3] == -37);
+        Assert.assertTrue(data28[4] == -102);
+        Assert.assertTrue(data28[5] == -44);
+        Assert.assertTrue(data28[6] == 0);
+
+    }
+
+    @Test
+    public void testGetShort() throws Exception {
+        byte data[] = new byte[2];
+        data[0] = 7;
+        data[1] = 8;
+        int length = 9; // num bits
+        Assert.assertTrue(BitBufferHelper.getShort(data, length) == 264);
+
+        data[0] = 6;
+        data[1] = 8;
+        short result = BitBufferHelper.getShort(data, length);
+        Assert.assertTrue(result == 8);
+
+        data[0] = 8;
+        data[1] = 47;
+        result = BitBufferHelper.getShort(data, length);
+        Assert.assertTrue(result == 47);
+
+        //[0000 0001] [0001 0100] [0110 0100]
+        byte[] data1 = new byte[2];
+        data1[0] = 1;
+        data1[1] = 20; //data1[2] = 100;
+        length = 15;
+        result = BitBufferHelper.getShort(data1, length);
+        Assert.assertTrue(result == 276);
+
+        byte[] data2 = new byte[2];
+        data2[0] = 64;
+        data2[1] = 99; //data2[2] = 100;
+        length = 13;
+        result = BitBufferHelper.getShort(data2, length);
+        Assert.assertTrue(result == 99);
+
+        byte[] data3 = { 100, 50 };
+        result = BitBufferHelper.getShort(data3);
+        Assert.assertTrue(result == 25650);
+    }
+
+    @Test
+    public void testToIntVarLength() throws Exception {
+        byte data[] = { (byte) 255, (byte) 128 };
+        int length = 9; // num bits
+        Assert.assertTrue(BitBufferHelper.getInt(data, length) == 384);
+
+        byte data2[] = { 0, 8 };
+        Assert.assertTrue(BitBufferHelper.getInt(data2, 9) == 8);
+
+        byte data3[] = { 1, 1, 1 };
+        Assert.assertTrue(BitBufferHelper.getInt(data3) == 65793);
+
+        byte data4[] = { 1, 1, 1 };
+        Assert.assertTrue(BitBufferHelper.getInt(data4) == 65793);
+
+        byte data5[] = { 1, 1 };
+        Assert.assertTrue(BitBufferHelper.getInt(data5) == 257);
+
+    }
+
+    @Test
+    public void testShiftBitstoLSB() {
+        byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
+
+        byte[] data2 = { 8, 9, 10 };
+        byte[] shiftedBytes2 = BitBufferHelper.shiftBitsToLSB(data2, 11);
+
+        Assert.assertTrue(shiftedBytes2[0] == 0);
+        Assert.assertTrue(shiftedBytes2[1] == 64);
+        Assert.assertTrue(shiftedBytes2[2] == 72);
+
+        byte[] shiftedBytes = BitBufferHelper.shiftBitsToLSB(data, 49);
+
+        Assert.assertTrue(shiftedBytes[0] == 0);
+        Assert.assertTrue(shiftedBytes[1] == 2);
+        Assert.assertTrue(shiftedBytes[2] == 4);
+        Assert.assertTrue(shiftedBytes[3] == 6);
+        Assert.assertTrue(shiftedBytes[4] == 8);
+        Assert.assertTrue(shiftedBytes[5] == 10);
+        Assert.assertTrue(shiftedBytes[6] == 12);
+        Assert.assertTrue(shiftedBytes[7] == 14);
+        Assert.assertTrue(shiftedBytes[8] == 16);
+        Assert.assertTrue(shiftedBytes[9] == 18);
+
+        byte[] data1 = { 1, 2, 3 };
+        byte[] shiftedBytes1 = BitBufferHelper.shiftBitsToLSB(data1, 18);
+        Assert.assertTrue(shiftedBytes1[0] == 0);
+        Assert.assertTrue(shiftedBytes1[1] == 4);
+        Assert.assertTrue(shiftedBytes1[2] == 8);
+
+    }
+
+    @Test
+    public void testShiftBitstoLSBMSB() {
+        byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
+
+        byte[] clone = BitBufferHelper.shiftBitsToMSB(BitBufferHelper
+                .shiftBitsToLSB(data, 72), 72);
+
+        Assert.assertTrue(clone[0] == 1);
+        Assert.assertTrue(clone[1] == 2);
+        Assert.assertTrue(clone[2] == 3);
+        Assert.assertTrue(clone[3] == 4);
+        Assert.assertTrue(clone[4] == 5);
+        Assert.assertTrue(clone[5] == 6);
+        Assert.assertTrue(clone[6] == 7);
+        Assert.assertTrue(clone[7] == 8);
+        Assert.assertTrue(clone[8] == 9);
+        Assert.assertTrue(clone[9] == 0);
+    }
+
+}
diff --git a/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java b/opendaylight/commons/liblldp/src/test/java/org/opendaylight/controller/sal/packet/address/EthernetAddressTest.java
new file mode 100644 (file)
index 0000000..cfdc785
--- /dev/null
@@ -0,0 +1,114 @@
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+/**
+ * @file   EthernetAddressTest.java
+ *
+ * @brief  Unit Tests for EthernetAddress class
+ *
+ * Unit Tests for EthernetAddress class
+ */
+package org.opendaylight.controller.sal.packet.address;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.liblldp.ConstructionException;
+import org.opendaylight.controller.liblldp.EthernetAddress;
+
+public class EthernetAddressTest {
+    @Test
+    public void testNonValidConstructor() {
+        @SuppressWarnings("unused")
+        EthernetAddress ea1;
+        // Null input array
+        try {
+            ea1 = new EthernetAddress((byte[]) null);
+
+            // Exception is expected if NOT raised test will fail
+            Assert.assertTrue(false);
+        } catch (ConstructionException e) {
+        }
+
+        // Array too short
+        try {
+            ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0 });
+
+            // Exception is expected if NOT raised test will fail
+            Assert.assertTrue(false);
+        } catch (ConstructionException e) {
+        }
+
+        // Array too long
+        try {
+            ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0 });
+
+            // Exception is expected if NOT raised test will fail
+            Assert.assertTrue(false);
+        } catch (ConstructionException e) {
+        }
+    }
+
+    @Test
+    public void testEquality() {
+        EthernetAddress ea1;
+        EthernetAddress ea2;
+        try {
+            ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+
+            ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+            Assert.assertTrue(ea1.equals(ea2));
+        } catch (ConstructionException e) {
+            // Exception is NOT expected if raised test will fail
+            Assert.assertTrue(false);
+        }
+
+        try {
+            ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+
+            ea2 = ea1.clone();
+            Assert.assertTrue(ea1.equals(ea2));
+        } catch (ConstructionException e) {
+            // Exception is NOT expected if raised test will fail
+            Assert.assertTrue(false);
+        }
+
+        // Check for well knowns
+        try {
+            ea1 = EthernetAddress.BROADCASTMAC;
+            ea2 = new EthernetAddress(new byte[] { (byte) 0xff, (byte) 0xff,
+                    (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff });
+            Assert.assertTrue(ea1.equals(ea2));
+        } catch (ConstructionException e) {
+            // Exception is NOT expected if raised test will fail
+            Assert.assertTrue(false);
+        }
+    }
+
+    @Test
+    public void testUnEquality() {
+        EthernetAddress ea1;
+        EthernetAddress ea2;
+        try {
+            ea1 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x2 });
+
+            ea2 = new EthernetAddress(new byte[] { (byte) 0x0, (byte) 0x0,
+                    (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x1 });
+            Assert.assertTrue(!ea1.equals(ea2));
+        } catch (ConstructionException e) {
+            // Exception is NOT expected if raised test will fail
+            Assert.assertTrue(false);
+        }
+    }
+}
index 8797c7e85c7c0abbb06fc82df8f06783fc74b2d2..66a403560e132addee3c6ab35181c1daafd457f7 100644 (file)
     <concepts.version>0.5.2-SNAPSHOT</concepts.version>
     <concurrentlinkedhashmap.version>1.4</concurrentlinkedhashmap.version>
     <config.version>0.2.5-SNAPSHOT</config.version>
+    <config.configfile.directory>etc/opendaylight/karaf</config.configfile.directory>
+    <config.netty.configfile>00-netty.xml</config.netty.configfile>
+    <config.mdsal.configfile>01-mdsal.xml</config.mdsal.configfile>
+    <config.netconf.client.configfile>01-netconf.xml</config.netconf.client.configfile>
+    <config.toaster.configfile>03-toaster-sample.xml</config.toaster.configfile>
+    <config.restconf.configfile>10-rest-connector.xml</config.restconf.configfile>
+    <config.netconf.connector.configfile>99-netconf-connector.xml</config.netconf.connector.configfile>
     <configuration.implementation.version>0.4.3-SNAPSHOT</configuration.implementation.version>
     <configuration.version>0.4.3-SNAPSHOT</configuration.version>
     <connectionmanager.version>0.1.2-SNAPSHOT</connectionmanager.version>
@@ -83,6 +90,7 @@
     <!-- OpenEXI third party lib for netconf-->
 
     <exi.nagasena.version>0000.0002.0038.0</exi.nagasena.version>
+    <felix.util.version>1.6.0</felix.util.version>
     <filtervalve.version>1.4.2-SNAPSHOT</filtervalve.version>
     <findbugs.maven.plugin.version>2.4.0</findbugs.maven.plugin.version>
     <flowprogrammer.northbound.version>0.4.2-SNAPSHOT</flowprogrammer.northbound.version>
         <artifactId>config-persister-file-xml-adapter</artifactId>
         <version>${config.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>config-persister-feature-adapter</artifactId>
+        <version>${config.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>config-persister-impl</artifactId>
         <artifactId>karaf.branding</artifactId>
         <version>${karaf.branding.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>liblldp</artifactId>
+        <version>${sal.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>logback-config</artifactId>
         <artifactId>sal-common-util</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>sal-inmemory-datastore</artifactId>
+        <version>${mdsal.version}</version>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
         <artifactId>sal-compatibility</artifactId>
         <artifactId>toaster-config</artifactId>
         <version>${mdsal.version}</version>
       </dependency>
+      <dependency>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>features-yangtools</artifactId>
+        <version>${yangtools.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller.samples</groupId>
+        <artifactId>features-toaster</artifactId>
+        <version>${mdsal.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>features-config-netty</artifactId>
+        <version>${config.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
+      <dependency>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>features-flow</artifactId>
+        <version>${mdsal.version}</version>
+        <classifier>features</classifier>
+        <type>xml</type>
+        <scope>runtime</scope>
+      </dependency>
       <dependency>
         <groupId>org.opendaylight.controller.thirdparty</groupId>
         <artifactId>com.sun.jersey.jersey-servlet</artifactId>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>config-features</artifactId>
+        <artifactId>features-config</artifactId>
         <version>${config.version}</version>
         <classifier>features</classifier>
         <type>xml</type>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>features-odl-protocol-framework</artifactId>
+        <artifactId>features-protocol-framework</artifactId>
         <version>${protocol-framework.version}</version>
         <classifier>features</classifier>
         <type>xml</type>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>netconf-features</artifactId>
+        <artifactId>features-netconf</artifactId>
         <version>${netconf.version}</version>
         <classifier>features</classifier>
         <type>xml</type>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>config-persister-features</artifactId>
+        <artifactId>features-config-persister</artifactId>
         <version>${config.version}</version>
         <classifier>features</classifier>
         <type>xml</type>
       </dependency>
       <dependency>
         <groupId>org.opendaylight.controller</groupId>
-        <artifactId>mdsal-features</artifactId>
+        <artifactId>features-mdsal</artifactId>
         <version>${mdsal.version}</version>
         <classifier>features</classifier>
         <type>xml</type>
diff --git a/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigPusher.java b/opendaylight/config/config-persister-api/src/main/java/org/opendaylight/controller/config/persist/api/ConfigPusher.java
new file mode 100644 (file)
index 0000000..2dade8a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.config.persist.api;
+
+import java.util.List;
+/*
+ * The config pusher service pushes configs into the config subsystem
+ */
+public interface ConfigPusher {
+
+    /*
+     * Pushes configs into the config subsystem
+     */
+
+    public void pushConfigs(List<? extends ConfigSnapshotHolder> configs) throws InterruptedException;
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/pom.xml b/opendaylight/config/config-persister-feature-adapter/pom.xml
new file mode 100644 (file)
index 0000000..7412a51
--- /dev/null
@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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-subsystem</artifactId>
+        <version>0.2.5-SNAPSHOT</version>
+        <relativePath>..</relativePath>
+    </parent>
+
+    <artifactId>config-persister-feature-adapter</artifactId>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+            <version>${karaf.version}</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-impl</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.controller</groupId>
+            <artifactId>config-persister-directory-xml-adapter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.utils</artifactId>
+            <version>1.6.0</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+           <groupId>com.google.guava</groupId>
+           <artifactId>guava</artifactId>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                        <Bundle-Activator>org.opendaylight.controller.configpusherfeature.ConfigPusherFeatureActivator</Bundle-Activator>
+                        <Private-Package>
+                            org.apache.karaf.features.internal.model,
+                            org.apache.felix.utils.version,
+                            org.opendaylight.controller.configpusherfeature.internal
+                        </Private-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/ConfigPusherFeatureActivator.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/ConfigPusherFeatureActivator.java
new file mode 100644 (file)
index 0000000..ea99579
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature;
+
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.opendaylight.controller.configpusherfeature.internal.ConfigPusherCustomizer;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.util.tracker.ServiceTracker;
+
+public class ConfigPusherFeatureActivator implements BundleActivator {
+
+    BundleContext bc = null;
+    ConfigPusherCustomizer cpc = null;
+    ServiceTracker<ConfigPusher,ConfigPusher> cpst = null;
+
+    public void start(BundleContext context) throws Exception {
+        bc = context;
+        cpc = new ConfigPusherCustomizer();
+        cpst = new ServiceTracker<ConfigPusher, ConfigPusher>(bc, ConfigPusher.class.getName(), cpc);
+        cpst.open();
+    }
+
+    public void stop(BundleContext context) throws Exception {
+        if(cpst != null) {
+            cpst.close();
+            cpst = null;
+        }
+        if(cpc != null) {
+            cpc.close();
+            cpc = null;
+        }
+        bc = null;
+    }
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/AbstractFeatureWrapper.java
new file mode 100644 (file)
index 0000000..1bf2025
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.karaf.features.BundleInfo;
+import org.apache.karaf.features.Conditional;
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/*
+ * Wrap a Feature for the purposes of extracting the FeatureConfigSnapshotHolders from
+ * its underlying ConfigFileInfo's
+ *
+ * Delegates the the contained feature and provides additional methods.
+ */
+public class AbstractFeatureWrapper implements Feature {
+    private static final Logger logger = LoggerFactory.getLogger(AbstractFeatureWrapper.class);
+    protected Feature feature = null;
+
+    protected AbstractFeatureWrapper() {
+        // prevent instantiation without Feature
+    }
+
+    /*
+     * @param f Feature to wrap
+     */
+    public AbstractFeatureWrapper(Feature f) {
+        Preconditions.checkNotNull(f,"FeatureWrapper requires non-null Feature in constructor");
+        this.feature = f;
+    }
+
+    /*
+     * Get FeatureConfigSnapshotHolders appropriate to feed to the config subsystem
+     * from the underlying Feature Config files
+     */
+    public LinkedHashSet<FeatureConfigSnapshotHolder> getFeatureConfigSnapshotHolders() throws Exception {
+        LinkedHashSet <FeatureConfigSnapshotHolder> snapShotHolders = new LinkedHashSet<FeatureConfigSnapshotHolder>();
+        for(ConfigFileInfo c: getConfigurationFiles()) {
+            try {
+                snapShotHolders.add(new FeatureConfigSnapshotHolder(c,this));
+            } catch (JAXBException e) {
+                logger.debug("{} is not a config subsystem config file",c.getFinalname());
+            }
+        }
+        return snapShotHolders;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((feature == null) ? 0 : feature.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        AbstractFeatureWrapper other = (AbstractFeatureWrapper) obj;
+        if (feature == null) {
+            if (other.feature != null)
+                return false;
+        } else if (!feature.equals(other.feature))
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return feature.getName();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getId()
+     */
+    public String getId() {
+        return feature.getId();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getName()
+     */
+    public String getName() {
+        return feature.getName();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getDescription()
+     */
+    public String getDescription() {
+        return feature.getDescription();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getDetails()
+     */
+    public String getDetails() {
+        return feature.getDetails();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getVersion()
+     */
+    public String getVersion() {
+        return feature.getVersion();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#hasVersion()
+     */
+    public boolean hasVersion() {
+        return feature.hasVersion();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getResolver()
+     */
+    public String getResolver() {
+        return feature.getResolver();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getInstall()
+     */
+    public String getInstall() {
+        return feature.getInstall();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getDependencies()
+     */
+    public List<Dependency> getDependencies() {
+        return feature.getDependencies();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getBundles()
+     */
+    public List<BundleInfo> getBundles() {
+        return feature.getBundles();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getConfigurations()
+     */
+    public Map<String, Map<String, String>> getConfigurations() {
+        return feature.getConfigurations();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getConfigurationFiles()
+     */
+    public List<ConfigFileInfo> getConfigurationFiles() {
+        return feature.getConfigurationFiles();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getConditional()
+     */
+    public List<? extends Conditional> getConditional() {
+        return feature.getConditional();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getStartLevel()
+     */
+    public int getStartLevel() {
+        return feature.getStartLevel();
+    }
+
+    /**
+     * @return
+     * @see org.apache.karaf.features.Feature#getRegion()
+     */
+    public String getRegion() {
+        return feature.getRegion();
+    }
+
+}
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ChildAwareFeatureWrapper.java
new file mode 100644 (file)
index 0000000..8d2ae68
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import org.apache.felix.utils.version.VersionRange;
+import org.apache.felix.utils.version.VersionTable;
+import org.apache.karaf.features.Dependency;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.osgi.framework.Version;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Preconditions;
+
+/*
+ * Wrap a Feature for the purposes of extracting the FeatureConfigSnapshotHolders from
+ * its underlying ConfigFileInfo's and those of its children recursively
+ *
+ * Delegates the the contained feature and provides additional methods.
+ */
+public class ChildAwareFeatureWrapper extends AbstractFeatureWrapper implements Feature {
+    private static final Logger logger = LoggerFactory.getLogger(ChildAwareFeatureWrapper.class);
+    private FeaturesService featuresService= null;
+
+    protected ChildAwareFeatureWrapper(Feature f) {
+        // Don't use without a feature service
+    }
+
+    /*
+     * @param f Feature to wrap
+     * @param s FeaturesService to look up dependencies
+     */
+    ChildAwareFeatureWrapper(Feature f, FeaturesService s) throws Exception {
+        super(s.getFeature(f.getName(), f.getVersion()));
+        Preconditions.checkNotNull(s, "FeatureWrapper requires non-null FeatureService in constructor");
+        this.featuresService = s;
+    }
+
+    protected FeaturesService getFeaturesService() {
+        return featuresService;
+    }
+
+    /*
+     * Get FeatureConfigSnapshotHolders appropriate to feed to the config subsystem
+     * from the underlying Feature Config files and those of its children recursively
+     */
+    public LinkedHashSet <? extends ChildAwareFeatureWrapper> getChildFeatures() throws Exception {
+        List<Dependency> dependencies = feature.getDependencies();
+        LinkedHashSet <ChildAwareFeatureWrapper> childFeatures = new LinkedHashSet<ChildAwareFeatureWrapper>();
+        if(dependencies != null) {
+            for(Dependency dependency: dependencies) {
+                Feature fi = extractFeatureFromDependency(dependency);
+                if(fi != null){
+                    ChildAwareFeatureWrapper wrappedFeature = new ChildAwareFeatureWrapper(fi,featuresService);
+                    childFeatures.add(wrappedFeature);
+                }
+            }
+        }
+        return childFeatures;
+    }
+
+    public LinkedHashSet<FeatureConfigSnapshotHolder> getFeatureConfigSnapshotHolders() throws Exception {
+        LinkedHashSet <FeatureConfigSnapshotHolder> snapShotHolders = new LinkedHashSet<FeatureConfigSnapshotHolder>();
+        for(ChildAwareFeatureWrapper c: getChildFeatures()) {
+            for(FeatureConfigSnapshotHolder h: c.getFeatureConfigSnapshotHolders()) {
+                FeatureConfigSnapshotHolder f;
+                try {
+                    f = new FeatureConfigSnapshotHolder(h,this);
+                    snapShotHolders.add(f);
+                } catch (JAXBException e) {
+                    logger.debug("{} is not a config subsystem config file",h.getFileInfo().getFinalname());
+                }
+            }
+        }
+        snapShotHolders.addAll(super.getFeatureConfigSnapshotHolders());
+        return snapShotHolders;
+    }
+
+    protected Feature extractFeatureFromDependency(Dependency dependency) throws Exception {
+        Feature[] features = featuresService.listFeatures();
+        VersionRange range = org.apache.karaf.features.internal.model.Feature.DEFAULT_VERSION.equals(dependency.getVersion())
+                ? VersionRange.ANY_VERSION : new VersionRange(dependency.getVersion(), true, true);
+        Feature fi = null;
+        for(Feature f: features) {
+            if (f.getName().equals(dependency.getName())) {
+                Version v = VersionTable.getVersion(f.getVersion());
+                if (range.contains(v)) {
+                    if (fi == null || VersionTable.getVersion(fi.getVersion()).compareTo(v) < 0) {
+                        fi = f;
+                        break;
+                    }
+                }
+            }
+        }
+        return fi;
+    }
+
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigFeaturesListener.java
new file mode 100644 (file)
index 0000000..f5f1b85
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.RepositoryEvent;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigFeaturesListener implements  FeaturesListener,  AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigFeaturesListener.class);
+    private static final int QUEUE_SIZE = 100;
+    private BlockingQueue<FeatureEvent> queue = new LinkedBlockingQueue<FeatureEvent>(QUEUE_SIZE);
+    Thread pushingThread = null;
+
+    public ConfigFeaturesListener(ConfigPusher p, FeaturesService f) {
+        pushingThread = new Thread(new ConfigPushingRunnable(p, f, queue), "ConfigFeatureListener - ConfigPusher");
+        pushingThread.start();
+    }
+
+    @Override
+    public void featureEvent(FeatureEvent event) {
+        queue.offer(event);
+    }
+
+    @Override
+    public void repositoryEvent(RepositoryEvent event) {
+        logger.debug("Repository: " + event.getType() + " " + event.getRepository());
+    }
+
+    @Override
+    public void close() {
+        if(pushingThread != null) {
+            pushingThread.interrupt();
+            pushingThread = null;
+        }
+    }
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPusherCustomizer.java
new file mode 100644 (file)
index 0000000..d33a8cb
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import org.apache.karaf.features.FeaturesService;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConfigPusherCustomizer implements ServiceTrackerCustomizer<ConfigPusher, ConfigPusher>, AutoCloseable {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPusherCustomizer.class);
+    private ConfigFeaturesListener configFeaturesListener = null;
+    private FeatureServiceCustomizer featureServiceCustomizer = null;
+    private ServiceTracker<FeaturesService,FeaturesService> fsst = null;
+
+    @Override
+    public ConfigPusher addingService(ServiceReference<ConfigPusher> configPusherServiceReference) {
+        logger.trace("Got ConfigPusherCustomizer.addingService {}", configPusherServiceReference);
+        BundleContext bc = configPusherServiceReference.getBundle().getBundleContext();
+        ConfigPusher cpService = bc.getService(configPusherServiceReference);
+        featureServiceCustomizer = new FeatureServiceCustomizer(cpService);
+        fsst = new ServiceTracker<FeaturesService, FeaturesService>(bc, FeaturesService.class.getName(), featureServiceCustomizer);
+        fsst.open();
+        return cpService;
+    }
+
+    @Override
+    public void modifiedService(ServiceReference<ConfigPusher> configPusherServiceReference, ConfigPusher configPusher) {
+        // we don't care if the properties change
+    }
+
+    @Override
+    public void removedService(ServiceReference<ConfigPusher> configPusherServiceReference, ConfigPusher configPusher) {
+        this.close();
+    }
+
+    @Override
+    public void close() {
+        if(fsst != null) {
+            fsst.close();
+            fsst = null;
+        }
+        if(configFeaturesListener != null) {
+            configFeaturesListener.close();
+            configFeaturesListener = null;
+        }
+        if(featureServiceCustomizer != null) {
+            featureServiceCustomizer.close();
+            featureServiceCustomizer = null;
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/ConfigPushingRunnable.java
new file mode 100644 (file)
index 0000000..06c5c92
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.FeatureEvent.EventType;
+import org.apache.karaf.features.FeaturesService;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.LinkedHashMultimap;
+
+public class ConfigPushingRunnable implements Runnable {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPushingRunnable.class);
+    private static final int POLL_TIME = 1;
+    private BlockingQueue<FeatureEvent> queue;
+    private FeatureConfigPusher configPusher;
+    public ConfigPushingRunnable(ConfigPusher p, FeaturesService f,BlockingQueue<FeatureEvent> q) {
+        queue = q;
+        configPusher = new FeatureConfigPusher(p, f);
+    }
+
+    @Override
+    public void run() {
+        List<Feature> toInstall = new ArrayList<Feature>();
+        FeatureEvent event;
+        boolean interuppted = false;
+        while(true) {
+            try {
+                if(!interuppted) {
+                        if(toInstall.isEmpty()) {
+                            event = queue.take();
+                        } else {
+                            event = queue.poll(POLL_TIME, TimeUnit.MILLISECONDS);
+                        }
+                        if(event != null && event.getFeature() !=null) {
+                            processFeatureEvent(event,toInstall);
+                        }
+                } else if(toInstall.isEmpty()) {
+                    logger.error("ConfigPushingRunnable - exiting");
+                    return;
+                }
+            } catch (InterruptedException e) {
+                logger.error("ConfigPushingRunnable - interupted");
+                interuppted = true;
+            } catch (Exception e) {
+                logger.error("Exception while processing features {}", e);
+            }
+        }
+    }
+
+    protected void processFeatureEvent(FeatureEvent event, List<Feature> toInstall) throws InterruptedException, Exception {
+        if(event.getType() == EventType.FeatureInstalled) {
+            toInstall.add(event.getFeature());
+            LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> result = configPusher.pushConfigs(toInstall);
+            toInstall.removeAll(result.keySet());
+        } else if(event.getType() == EventType.FeatureUninstalled) {
+            toInstall.remove(event.getFeature());
+        }
+    }
+
+    protected void logPushResult(LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> results) {
+        for(Feature f:results.keySet()) {
+            logger.info("Pushed configs for feature {} {}",f,results.get(f));
+        }
+    }
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigPusher.java
new file mode 100644 (file)
index 0000000..1c094ad
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.LinkedHashMultimap;
+
+/*
+ * Simple class to push configs to the config subsystem from Feature's configfiles
+ */
+public class FeatureConfigPusher {
+    private static final Logger logger = LoggerFactory.getLogger(FeatureConfigPusher.class);
+    private FeaturesService featuresService = null;
+    private ConfigPusher pusher = null;
+    /*
+     * A LinkedHashSet (to preserve order and insure uniqueness) of the pushedConfigs
+     * This is used to prevent pushing duplicate configs if a Feature is in multiple dependency
+     * chains.  Also, preserves the *original* Feature chain for which we pushed the config.
+     * (which is handy for logging).
+     */
+    LinkedHashSet<FeatureConfigSnapshotHolder> pushedConfigs = new LinkedHashSet<FeatureConfigSnapshotHolder>();
+    /*
+     * LinkedHashMultimap to track which configs we pushed for each Feature installation
+     * For future use
+     */
+    LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> feature2configs = LinkedHashMultimap.create();
+
+    /*
+     * @param p - ConfigPusher to push ConfigSnapshotHolders
+     */
+    public FeatureConfigPusher(ConfigPusher p, FeaturesService f) {
+        pusher = p;
+        featuresService = f;
+    }
+    /*
+     * Push config files from Features to config subsystem
+     * @param features - list of Features to extract config files from recursively and push
+     * to the config subsystem
+     *
+     * @return A LinkedHashMultimap of Features to the FeatureConfigSnapshotHolder actually pushed
+     * If a Feature is not in the returned LinkedHashMultimap then we couldn't push its configs
+     * (Ususally because it was not yet installed)
+     */
+    public LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> pushConfigs(List<Feature> features) throws Exception, InterruptedException {
+        LinkedHashMultimap<Feature,FeatureConfigSnapshotHolder> pushedFeatures = LinkedHashMultimap.create();
+        for(Feature feature: features) {
+            LinkedHashSet<FeatureConfigSnapshotHolder> configSnapShots = pushConfig(feature);
+            if(!configSnapShots.isEmpty()) {
+                pushedFeatures.putAll(feature,configSnapShots);
+            }
+        }
+        return pushedFeatures;
+    }
+
+    private LinkedHashSet<FeatureConfigSnapshotHolder> pushConfig(Feature feature) throws Exception, InterruptedException {
+        LinkedHashSet<FeatureConfigSnapshotHolder> configs = new LinkedHashSet<FeatureConfigSnapshotHolder>();
+        if(isInstalled(feature)) {
+            ChildAwareFeatureWrapper wrappedFeature = new ChildAwareFeatureWrapper(feature,featuresService);
+            configs = wrappedFeature.getFeatureConfigSnapshotHolders();
+            if(!configs.isEmpty()) {
+                configs = pushConfig(configs);
+                feature2configs.putAll(feature, configs);
+            }
+        }
+        return configs;
+    }
+
+    private boolean isInstalled(Feature feature) {
+        List<Feature> installedFeatures = Arrays.asList(featuresService.listInstalledFeatures());
+        return installedFeatures.contains(feature);
+    }
+
+    private LinkedHashSet<FeatureConfigSnapshotHolder> pushConfig(LinkedHashSet<FeatureConfigSnapshotHolder> configs) throws InterruptedException {
+        LinkedHashSet<FeatureConfigSnapshotHolder> configsToPush = new LinkedHashSet<FeatureConfigSnapshotHolder>(configs);
+        configsToPush.removeAll(pushedConfigs);
+        if(!configsToPush.isEmpty()) {
+            pusher.pushConfigs(new ArrayList<ConfigSnapshotHolder>(configsToPush));
+            pushedConfigs.addAll(configsToPush);
+        }
+        LinkedHashSet<FeatureConfigSnapshotHolder> configsPushed = new LinkedHashSet<FeatureConfigSnapshotHolder>(pushedConfigs);
+        configsPushed.retainAll(configs);
+        return configsPushed;
+    }
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigSnapshotHolder.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigSnapshotHolder.java
new file mode 100644 (file)
index 0000000..d1a92eb
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedSet;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+
+import org.apache.karaf.features.ConfigFileInfo;
+import org.apache.karaf.features.Feature;
+import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
+
+/*
+ * A ConfigSnapshotHolder that can track all the additional information
+ * relavent to the fact we are getting these from a Feature.
+ *
+ * Includes tracking the 'featureChain' - an reverse ordered list of the dependency
+ * graph of features that caused us to push this FeatureConfigSnapshotHolder.
+ * So if A -> B -> C, then the feature chain would be C -> B -> A
+ */
+public class FeatureConfigSnapshotHolder implements ConfigSnapshotHolder {
+    private ConfigSnapshot unmarshalled = null;
+    private ConfigFileInfo fileInfo = null;
+    private List<Feature> featureChain = new ArrayList<Feature>();
+
+    /*
+     * @param holder - FeatureConfigSnapshotHolder that we
+     * @param feature - new
+     */
+    public FeatureConfigSnapshotHolder(final FeatureConfigSnapshotHolder holder, final Feature feature) throws JAXBException {
+        this(holder.fileInfo,holder.getFeature());
+        this.featureChain.add(feature);
+    }
+
+    /*
+     * Create a FeatureConfigSnapshotHolder for a given ConfigFileInfo and record the associated
+     * feature we are creating it from.
+     * @param fileInfo - ConfigFileInfo to read into the ConfigSnapshot
+     * @param feature - Feature the ConfigFileInfo was attached to
+     */
+    public FeatureConfigSnapshotHolder(final ConfigFileInfo fileInfo, final Feature feature) throws JAXBException {
+        Preconditions.checkNotNull(fileInfo);
+        Preconditions.checkNotNull(fileInfo.getFinalname());
+        Preconditions.checkNotNull(feature);
+        this.fileInfo = fileInfo;
+        this.featureChain.add(feature);
+        JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
+        Unmarshaller um = jaxbContext.createUnmarshaller();
+        File file = new File(fileInfo.getFinalname());
+        unmarshalled = ((ConfigSnapshot) um.unmarshal(file));
+    }
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#hashCode()
+     *
+     * We really care most about the underlying ConfigShapshot, so compute hashcode on that
+     */
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((unmarshalled != null && unmarshalled.getConfigSnapshot() == null) ? 0 : unmarshalled.getConfigSnapshot().hashCode());
+        return result;
+    }
+    /*
+     * (non-Javadoc)
+     * @see java.lang.Object#equals(java.lang.Object)
+     * *
+     * We really care most about the underlying ConfigShapshot, so compute equality on that
+     */
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        FeatureConfigSnapshotHolder fcsh = (FeatureConfigSnapshotHolder)obj;
+        if(this.unmarshalled.getConfigSnapshot().equals(fcsh.unmarshalled.getConfigSnapshot())) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+       StringBuilder b = new StringBuilder();
+       Path p = Paths.get(fileInfo.getFinalname());
+       b.append(p.getFileName())
+           .append("(")
+           .append(getCauseFeature())
+           .append(",")
+           .append(getFeature())
+           .append(")");
+       return b.toString();
+
+    }
+
+    @Override
+    public String getConfigSnapshot() {
+        return unmarshalled.getConfigSnapshot();
+    }
+
+    @Override
+    public SortedSet<String> getCapabilities() {
+        return unmarshalled.getCapabilities();
+    }
+
+    public ConfigFileInfo getFileInfo() {
+        return fileInfo;
+    }
+
+    /*
+     * @returns The original feature to which the ConfigFileInfo was attached
+     * Example:
+     * A -> B -> C, ConfigFileInfo Foo is attached to C.
+     * feature:install A
+     * thus C is the 'Feature' Foo was attached.
+     */
+    public Feature getFeature() {
+        return featureChain.get(0);
+    }
+
+    /*
+     * @return The dependency chain of the features that caused the ConfigFileInfo to be pushed in reverse order.
+     * Example:
+     * A -> B -> C, ConfigFileInfo Foo is attached to C.
+     * The returned list is
+     * [C,B,A]
+     */
+    public ImmutableList<Feature> getFeatureChain() {
+        return ImmutableList.copyOf(Lists.reverse(featureChain));
+    }
+
+    /*
+     * @return The feature the installation of which was the root cause
+     * of this pushing of the ConfigFileInfo.
+     * Example:
+     * A -> B -> C, ConfigFileInfo Foo is attached to C.
+     * feature:install A
+     * this A is the 'Cause' of the installation of Foo.
+     */
+    public Feature getCauseFeature() {
+        return Iterables.getLast(featureChain);
+    }
+}
diff --git a/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureServiceCustomizer.java b/opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureServiceCustomizer.java
new file mode 100644 (file)
index 0000000..e72c827
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.configpusherfeature.internal;
+
+import org.apache.karaf.features.FeaturesListener;
+import org.apache.karaf.features.FeaturesService;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+public class FeatureServiceCustomizer implements ServiceTrackerCustomizer<FeaturesService, FeaturesService>, AutoCloseable {
+    private ConfigPusher configPusher = null;
+    private ConfigFeaturesListener configFeaturesListener = null;
+    private ServiceRegistration<?> registration;
+
+    FeatureServiceCustomizer(ConfigPusher c) {
+        configPusher = c;
+    }
+
+
+    @Override
+    public FeaturesService addingService(ServiceReference<FeaturesService> reference) {
+        BundleContext bc = reference.getBundle().getBundleContext();
+        FeaturesService featureService = bc.getService(reference);
+        configFeaturesListener = new ConfigFeaturesListener(configPusher,featureService);
+        registration = bc.registerService(FeaturesListener.class.getCanonicalName(), configFeaturesListener, null);
+        return featureService;
+    }
+
+    @Override
+    public void modifiedService(ServiceReference<FeaturesService> reference,
+            FeaturesService service) {
+        // we don't care if the properties change
+
+    }
+
+    @Override
+    public void removedService(ServiceReference<FeaturesService> reference,
+            FeaturesService service) {
+        close();
+    }
+
+    @Override
+    public void close() {
+        if(registration != null) {
+            registration.unregister();
+            registration = null;
+        }
+    }
+
+}
index 343d13e9c19194ad67680801639fdf52df9563b3..b8ad26116a2915634be51f430d8d5769ce2e949b 100644 (file)
@@ -23,6 +23,7 @@
     <module>config-util</module>
     <module>config-persister-api</module>
     <module>config-persister-file-xml-adapter</module>
+    <module>config-persister-feature-adapter</module>
     <module>yang-jmx-generator</module>
     <module>yang-jmx-generator-plugin</module>
     <module>yang-test</module>
index 5effbb09fc81536ed2cf176427c37f25d16e9ddf..b3c3f20ba80bb5cc829c5a208669a239ec8a1981 100644 (file)
       <type>kar</type>
       <scope>runtime</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>config-netty-features</artifactId>
-      <classifier>features</classifier>
-      <type>xml</type>
-      <scope>runtime</scope>
-    </dependency>
-
     <!-- AD-SAL Related Features -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
     <!-- MD-SAL Related Features -->
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>mdsal-features</artifactId>
+      <artifactId>features-mdsal</artifactId>
+      <classifier>features</classifier>
+      <type>xml</type>
+      <scope>runtime</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>features-flow</artifactId>
       <classifier>features</classifier>
       <type>xml</type>
       <scope>runtime</scope>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/00-netty.xml
deleted file mode 100644 (file)
index 2365c70..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-<snapshot>
-    <required-capabilities>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty?module=netty&amp;revision=2013-11-19</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&amp;revision=2013-11-12</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup?module=threadgroup&amp;revision=2013-11-07</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:timer?module=netty-timer&amp;revision=2013-11-19</capability>
-    </required-capabilities>
-    <configuration>
-    
-        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <module>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
-                    <name>global-boss-group</name>
-                </module>
-                <module>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:threadgroup">netty:netty-threadgroup-fixed</type>
-                    <name>global-worker-group</name>
-                </module>
-                <module>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:timer">netty:netty-hashed-wheel-timer</type>
-                    <name>global-timer</name>
-                </module>
-                <module>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor">netty:netty-global-event-executor</type>
-                    <name>singleton</name>
-                </module>
-            </modules>
-            
-            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-threadgroup</type>
-                    <instance>
-                        <name>global-boss-group</name>
-                        <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-boss-group']</provider>
-                    </instance>
-                    <instance>
-                        <name>global-worker-group</name>
-                        <provider>/modules/module[type='netty-threadgroup-fixed'][name='global-worker-group']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-event-executor</type>
-                    <instance>
-                        <name>global-event-executor</name>
-                        <provider>/modules/module[type='netty-global-event-executor'][name='singleton']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:netty="urn:opendaylight:params:xml:ns:yang:controller:netty">netty:netty-timer</type>
-                    <instance>
-                        <name>global-timer</name>
-                        <provider>/modules/module[type='netty-hashed-wheel-timer'][name='global-timer']</provider>
-                    </instance>
-                </service>
-            </services>
-        </data>
-
-    </configuration>
-</snapshot>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/01-md-sal.xml
deleted file mode 100644 (file)
index 619ab06..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- vi: set et smarttab sw=4 tabstop=4: -->
-<!--
- Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
-
- This program and the accompanying materials are made available under the
- terms of the Eclipse Public License v1.0 which accompanies this distribution,
- and is available at http://www.eclipse.org/legal/epl-v10.html
--->
-<snapshot>
-    <configuration>
-        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
-                    <name>yang-schema-service</name>
-                </module>
-                <!-- To enable use of new in-memory datastore and new implementations
-                     of data brokers, comment out all parts of this
-                     xml which are marked with DATA-BROKER and uncomment all parts
-                     of this xml which are marked with NEW-DATA-BROKER
-                -->
-                <!-- DATA-BROKER start-->
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:hash-map-data-store</type>
-                    <name>hash-map-data-store</name>
-                </module>
-                <!-- DATA BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
-                    <name>async-data-broker</name>
-                    <schema-service>
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
-                        <name>yang-schema-service</name>
-                    </schema-service>
-                </module>
-                -->
-                <!-- NEW-DATA-BROKER end -->
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
-                    <name>dom-broker</name>
-                    <!-- DATA-BROKER start -->
-                    <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-                        <!-- to switch to the clustered data store, comment out the hash-map-data-store <name> and uncomment the cluster-data-store one -->
-                        <name>hash-map-data-store</name>
-                        <!-- <name>cluster-data-store</name> -->
-                    </data-store>
-                    <!-- DATA-BROKER end -->
-                    <!-- NEW-DATA-BROKER start -->
-                    <!--
-                    <async-data-broker>
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-                        <name>async-data-broker</name>
-                    </async-data-broker>
-                    -->
-                    <!-- NEW-DATA-BROKER end -->
-                </module>
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
-                    <name>binding-broker-impl</name>
-                    <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
-                        <name>binding-notification-broker</name>
-                    </notification-service>
-                    <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
-                        <name>binding-data-broker</name>
-                    </data-broker>
-                </module>
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
-                    <name>runtime-mapping-singleton</name>
-                </module>
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
-                    <name>binding-notification-broker</name>
-                </module>
-                <!-- DATA-BROKER start -->
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-broker</type>
-                    <name>binding-data-broker</name>
-                    <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                        <name>dom-broker</name>
-                    </dom-broker>
-                    <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
-                        <name>runtime-mapping-singleton</name>
-                    </mapping-service>
-                </module>
-                <!-- DATA-BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
-                    <name>binding-data-broker</name>
-                    <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                        <name>dom-broker</name>
-                    </dom-async-broker>
-                    <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
-                        <name>runtime-mapping-singleton</name>
-                    </binding-mapping-service>
-                </module>
-                -->
-                <!-- NEW-DATA-BROKER end -->
-            </modules>
-            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
-                    <instance>
-                        <name>yang-schema-service</name>
-                        <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
-                    <instance>
-                        <name>binding-notification-broker</name>
-                        <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
-                    </instance>
-                </service>
-                <!-- DATA-BROKER start -->
-                <service>
-                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-data-store</type>
-                    <instance>
-                        <name>hash-map-data-store</name>
-                        <provider>/modules/module[type='hash-map-data-store'][name='hash-map-data-store']</provider>
-                    </instance>
-                </service>
-                <!-- DATA-BROKER end -->
-                <!-- NEW-DATA-BROKER start -->
-                <!--
-                <service>
-                    <type  xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
-                    <instance>
-                        <name>async-data-broker</name>
-                        <provider>/modules/module[type='dom-inmemory-data-broker'][name='async-data-broker']</provider>
-                    </instance>
-                </service>
-                -->
-                <!-- NEW-DATA-BROKER end -->
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
-                    <instance>
-                        <name>binding-osgi-broker</name>
-                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
-                    <instance>
-                        <name>binding-rpc-broker</name>
-                        <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
-                    <instance>
-                        <name>runtime-mapping-singleton</name>
-                        <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
-                    </instance>
-                </service>
-                <service>
-                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
-                    <instance>
-                        <name>dom-broker</name>
-                        <provider>/modules/module[type='dom-broker-impl'][name='dom-broker']</provider>
-                    </instance>
-                </service>
-
-                <service>
-                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
-                    <instance>
-                        <name>binding-data-broker</name>
-                        <!--  DATA-BROKER start -->
-                        <provider>/modules/module[type='binding-data-broker'][name='binding-data-broker']</provider>
-                        <!--  DATA-BROKER end -->
-                        <!-- NEW-DATA-BROKER start -->
-                        <!--
-                        <provider>/modules/module[type='binding-data-compatible-broker'][name='binding-data-broker']</provider>
-                        -->
-                        <!--  NEW-DATA-BROKER end -->
-                    </instance>
-                </service>
-
-            </services>
-        </data>
-    </configuration>
-    <required-capabilities>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:netty:eventexecutor?module=netty-event-executor&amp;revision=2013-11-12</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:threadpool?module=threadpool&amp;revision=2013-04-09</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&amp;revision=2013-10-28</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&amp;revision=2013-10-28</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&amp;revision=2013-10-28</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&amp;revision=2013-10-28</capability>
-    </required-capabilities>
-</snapshot>
diff --git a/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml b/opendaylight/distribution/opendaylight-karaf/src/main/resources/configuration/initial/03-toaster-sample.xml
deleted file mode 100644 (file)
index c481485..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<snapshot>
-    <configuration>
-        <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
-            <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
-                        prefix:toaster-provider-impl
-                    </type>
-                    <name>toaster-provider-impl</name>
-
-                    <rpc-registry>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
-                        <name>binding-rpc-broker</name>
-                    </rpc-registry>
-
-                    <notification-service>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                            binding:binding-notification-service
-                        </type>
-                        <name>binding-notification-broker</name>
-                    </notification-service>
-                </module>
-
-                <module>
-                    <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl">
-                        prefix:toaster-consumer-impl
-                    </type>
-                    <name>toaster-consumer-impl</name>
-
-                    <rpc-registry>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-rpc-registry</type>
-                        <name>binding-rpc-broker</name>
-                    </rpc-registry>
-
-                    <notification-service>
-                        <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                            binding:binding-notification-service
-                        </type>
-                        <name>binding-notification-broker</name>
-                    </notification-service>
-                </module>
-            </modules>
-
-            <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
-                <service>
-                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider">toaster:toaster-provider</type>
-                    <instance>
-                        <name>toaster-provider</name>
-                        <provider>/modules/module[type='toaster-provider-impl'][name='toaster-provider-impl']</provider>
-                    </instance>
-                </service>
-                <service>
-                    <type xmlns:toaster="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer">toaster:toaster-consumer</type>
-                    <instance>
-                        <name>toaster-consumer</name>
-                        <provider>/modules/module[type='toaster-consumer-impl'][name='toaster-consumer-impl']</provider>
-                    </instance>
-                </service>
-            </services>
-        </data>
-
-    </configuration>
-
-    <required-capabilities>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&amp;revision=2013-10-28</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer?module=toaster-consumer&amp;revision=2014-01-31</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-consumer:impl?module=toaster-consumer-impl&amp;revision=2014-01-31</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider?module=toaster-provider&amp;revision=2014-01-31</capability>
-        <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&amp;revision=2014-01-31</capability>
-    </required-capabilities>
-
-</snapshot>
-
index 6c1ca421c257ab81807c20f4a939d556cb5338c6..e9a6992521250d612c1924e4f0fa46548f63d741 100644 (file)
@@ -25,18 +25,11 @@ netconf.ssh.port=1830
 netconf.ssh.pk.path = ./configuration/RSA.pk
 
 
-netconf.config.persister.active=1,2
-# read startup configuration
-netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.directory.xml.XmlDirectoryStorageAdapter
-netconf.config.persister.1.properties.directoryStorage=configuration/initial/
-
-# include only xml files, files with other extensions will be skipped, multiple extensions are permitted e.g. netconf.config.persister.1.properties.includeExtensions=xml,cfg,config
-netconf.config.persister.1.properties.includeExtensions=xml
-netconf.config.persister.1.readonly=true
-
-netconf.config.persister.2.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
-netconf.config.persister.2.properties.fileStorage=configuration/current/controller.currentconfig.xml
-netconf.config.persister.2.properties.numberOfBackups=1
+netconf.config.persister.active=1
+
+netconf.config.persister.1.storageAdapterClass=org.opendaylight.controller.config.persist.storage.file.xml.XmlFileStorageAdapter
+netconf.config.persister.1.properties.fileStorage=etc/opendaylight/current/controller.currentconfig.xml
+netconf.config.persister.1.properties.numberOfBackups=1
 
 # logback configuration
 logback.configurationFile=configuration/logback.xml
index e91da89970b381a5127dc99bf9027ea4969765db..a98956e98d41043a4e373e40e65799d38faa5f77 100644 (file)
@@ -180,7 +180,8 @@ jre-1.6= \
  org.w3c.dom.xpath, \
  org.xml.sax, \
  org.xml.sax.ext, \
- org.xml.sax.helpers
+ org.xml.sax.helpers, \
+ javax.annotation.processing
 
 # Standard package set.  Note that:
 #   - javax.transaction* is exported with a mandatory attribute
@@ -341,7 +342,8 @@ jre-1.7= \
  org.w3c.dom.xpath, \
  org.xml.sax, \
  org.xml.sax.ext, \
- org.xml.sax.helpers
+ org.xml.sax.helpers, \
+ javax.annotation.processing
 
 jre-1.8= \
  javax.accessibility, \
@@ -500,4 +502,5 @@ jre-1.8= \
  org.w3c.dom.xpath, \
  org.xml.sax, \
  org.xml.sax.ext, \
- org.xml.sax.helpers
+ org.xml.sax.helpers, \
+ javax.annotation.processing
index 7ab56e6d03d63071216189c716f3022b6e834967..969ecc2cbed41054fde61fb8aecfe8ae940ed95d 100644 (file)
           <groupId>org.opendaylight.controller.md</groupId>
           <artifactId>topology-lldp-discovery</artifactId>
         </dependency>
+        <dependency>
+          <groupId>org.opendaylight.controller</groupId>
+          <artifactId>liblldp</artifactId>
+        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller.md</groupId>
           <artifactId>topology-manager</artifactId>
index c25aa523e2e0823769a28e9dc01b32da711b0ae5..d21d05d7fe9b02ae9a604a2f6c0567706ec2f68a 100644 (file)
@@ -14,7 +14,6 @@ import org.opendaylight.controller.remote.rpc.registry.gossip.Copier;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 
 import java.io.Serializable;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -26,7 +25,7 @@ public class RoutingTable implements Copier<RoutingTable>, Serializable {
     @Override
     public RoutingTable copy() {
         RoutingTable copy = new RoutingTable();
-        copy.setTable(Collections.unmodifiableMap(table));
+        copy.setTable(new HashMap<>(table));
         copy.setRouter(this.getRouter());
 
         return copy;
@@ -53,6 +52,9 @@ public class RoutingTable implements Copier<RoutingTable>, Serializable {
         return table.containsKey(routeId);
     }
 
+    public Boolean isEmpty(){
+        return table.isEmpty();
+    }
     ///
     /// Getter, Setters
     ///
index 51609870cc4aad1c8789dfdcd0b68f04563b5cdf..e2ebcb2b25a62c3f60232db52e90749736561948 100644 (file)
@@ -28,9 +28,10 @@ import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoute;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoute;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoutes;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoutes;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
 import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBuckets;
 import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBucketsReply;
 import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetLocalBucket;
@@ -39,10 +40,9 @@ import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.Bu
 
 /**
  * Registry to look up cluster nodes that have registered for a given rpc.
- * <p>
+ * <p/>
  * It uses {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} to maintain this
  * cluster wide information.
- *
  */
 public class RpcRegistry extends UntypedActor {
 
@@ -76,14 +76,14 @@ public class RpcRegistry extends UntypedActor {
         if (message instanceof SetLocalRouter)
             receiveSetLocalRouter((SetLocalRouter) message);
 
-        if (message instanceof AddOrUpdateRoute)
-            receiveAddRoute((AddOrUpdateRoute) message);
+        if (message instanceof AddOrUpdateRoutes)
+            receiveAddRoutes((AddOrUpdateRoutes) message);
 
-        else if (message instanceof RemoveRoute)
-            receiveRemoveRoute((RemoveRoute) message);
+        else if (message instanceof RemoveRoutes)
+            receiveRemoveRoutes((RemoveRoutes) message);
 
         else if (message instanceof Messages.FindRouters)
-            receiveGetRouter((Messages.FindRouters) message);
+            receiveGetRouter((FindRouters) message);
 
         else
             unhandled(message);
@@ -95,55 +95,40 @@ public class RpcRegistry extends UntypedActor {
      * @param message contains {@link akka.actor.ActorRef} for rpc broker
      */
     private void receiveSetLocalRouter(SetLocalRouter message) {
-        if (message == null || message.getRouter() == null)
-            return;//ignore
-
         localRouter = message.getRouter();
     }
 
     /**
-     * //TODO: update this to accept multiple route registration
      * @param msg
      */
-    private void receiveAddRoute(AddOrUpdateRoute msg) {
-        if (msg.getRouteIdentifier() == null)
-            return;//ignore
+    private void receiveAddRoutes(AddOrUpdateRoutes msg) {
 
         Preconditions.checkState(localRouter != null, "Router must be set first");
 
         Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
-        futureReply.map(getMapperToAddRoute(msg.getRouteIdentifier()), getContext().dispatcher());
+        futureReply.map(getMapperToAddRoutes(msg.getRouteIdentifiers()), getContext().dispatcher());
     }
 
     /**
-     * //TODO: update this to accept multiple routes
-     * @param msg
+     * @param msg contains list of route ids to remove
      */
-    private void receiveRemoveRoute(RemoveRoute msg) {
-        if (msg.getRouteIdentifier() == null)
-            return;//ignore
+    private void receiveRemoveRoutes(RemoveRoutes msg) {
 
         Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
-        futureReply.map(getMapperToRemoveRoute(msg.getRouteIdentifier()), getContext().dispatcher());
+        futureReply.map(getMapperToRemoveRoutes(msg.getRouteIdentifiers()), getContext().dispatcher());
 
     }
 
     /**
      * Finds routers for the given rpc.
+     *
      * @param msg
      */
-    private void receiveGetRouter(Messages.FindRouters msg) {
+    private void receiveGetRouter(FindRouters msg) {
         final ActorRef sender = getSender();
 
-        //if empty message, return empty list
-        if (msg.getRouteIdentifier() == null) {
-            sender.tell(createEmptyReply(), getSelf());
-            return;
-        }
-
         Future<Object> futureReply = Patterns.ask(bucketStore, new GetAllBuckets(), 1000);
         futureReply.map(getMapperToGetRouter(msg.getRouteIdentifier(), sender), getContext().dispatcher());
-
     }
 
     /**
@@ -158,6 +143,7 @@ public class RpcRegistry extends UntypedActor {
 
     /**
      * Helper to create a reply when routers are found for the given rpc
+     *
      * @param buckets
      * @param routeId
      * @return
@@ -165,18 +151,15 @@ public class RpcRegistry extends UntypedActor {
     private Messages.FindRoutersReply createReplyWithRouters(Map<Address, Bucket> buckets, RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
 
         List<Pair<ActorRef, Long>> routers = new ArrayList<>();
-
         Option<Pair<ActorRef, Long>> routerWithUpdateTime = null;
 
         for (Bucket bucket : buckets.values()) {
 
             RoutingTable table = (RoutingTable) bucket.getData();
-
             if (table == null)
                 continue;
 
             routerWithUpdateTime = table.getRouterFor(routeId);
-
             if (routerWithUpdateTime.isEmpty())
                 continue;
 
@@ -192,7 +175,7 @@ public class RpcRegistry extends UntypedActor {
     ///
 
     /**
-     *  Receives all buckets returned from bucket store and finds routers for the buckets where given rpc(routeId) is found
+     * Receives all buckets returned from bucket store and finds routers for the buckets where given rpc(routeId) is found
      *
      * @param routeId the rpc
      * @param sender  client who asked to find the routers.
@@ -224,10 +207,10 @@ public class RpcRegistry extends UntypedActor {
      * Receives local bucket from bucket store and updates routing table in it by removing the route. Subsequently,
      * it updates the local bucket in bucket store.
      *
-     * @param routeId rpc to remote
+     * @param routeIds rpc to remote
      * @return
      */
-    private Mapper<Object, Void> getMapperToRemoveRoute(final RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
+    private Mapper<Object, Void> getMapperToRemoveRoutes(final List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds) {
         return new Mapper<Object, Void>() {
             @Override
             public Void apply(Object replyMessage) {
@@ -246,8 +229,12 @@ public class RpcRegistry extends UntypedActor {
                         table = new RoutingTable();
 
                     table.setRouter(localRouter);
-                    table.removeRoute(routeId);
 
+                    if (!table.isEmpty()) {
+                        for (RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
+                            table.removeRoute(routeId);
+                        }
+                    }
                     bucket.setData(table);
 
                     UpdateBucket updateBucketMessage = new UpdateBucket(bucket);
@@ -262,10 +249,10 @@ public class RpcRegistry extends UntypedActor {
      * Receives local bucket from bucket store and updates routing table in it by adding the route. Subsequently,
      * it updates the local bucket in bucket store.
      *
-     * @param routeId rpc to add
+     * @param routeIds rpc to add
      * @return
      */
-    private Mapper<Object, Void> getMapperToAddRoute(final RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
+    private Mapper<Object, Void> getMapperToAddRoutes(final List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds) {
 
         return new Mapper<Object, Void>() {
             @Override
@@ -285,7 +272,9 @@ public class RpcRegistry extends UntypedActor {
                         table = new RoutingTable();
 
                     table.setRouter(localRouter);
-                    table.addRoute(routeId);
+                    for (RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
+                        table.addRoute(routeId);
+                    }
 
                     bucket.setData(table);
 
@@ -305,47 +294,50 @@ public class RpcRegistry extends UntypedActor {
 
 
         public static class ContainsRoute {
-            final RpcRouter.RouteIdentifier<?,?,?> routeIdentifier;
+            final List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIdentifiers;
 
-            public ContainsRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
-                Preconditions.checkArgument(routeIdentifier != null);
-                this.routeIdentifier = routeIdentifier;
+            public ContainsRoute(List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIdentifiers) {
+                Preconditions.checkArgument(routeIdentifiers != null &&
+                                            !routeIdentifiers.isEmpty(),
+                                            "Route Identifiers must be supplied");
+                this.routeIdentifiers = routeIdentifiers;
             }
 
-            public RpcRouter.RouteIdentifier<?,?,?> getRouteIdentifier(){
-                return this.routeIdentifier;
+            public List<RpcRouter.RouteIdentifier<?, ?, ?>> getRouteIdentifiers() {
+                return this.routeIdentifiers;
             }
 
             @Override
             public String toString() {
-                return this.getClass().getSimpleName() + "{" +
-                        "routeIdentifier=" + routeIdentifier +
+                return "ContainsRoute{" +
+                        "routeIdentifiers=" + routeIdentifiers +
                         '}';
             }
         }
 
-        public static class AddOrUpdateRoute extends ContainsRoute{
+        public static class AddOrUpdateRoutes extends ContainsRoute {
 
-            public AddOrUpdateRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
-                super(routeIdentifier);
+            public AddOrUpdateRoutes(List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIdentifiers) {
+                super(routeIdentifiers);
             }
         }
 
-        public static class RemoveRoute extends ContainsRoute {
+        public static class RemoveRoutes extends ContainsRoute {
 
-            public RemoveRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
-                super(routeIdentifier);
+            public RemoveRoutes(List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIdentifiers) {
+                super(routeIdentifiers);
             }
         }
 
-        public static class SetLocalRouter{
+        public static class SetLocalRouter {
             private final ActorRef router;
 
             public SetLocalRouter(ActorRef router) {
+                Preconditions.checkArgument(router != null, "Router must not be null");
                 this.router = router;
             }
 
-            public ActorRef getRouter(){
+            public ActorRef getRouter() {
                 return this.router;
             }
 
@@ -357,9 +349,23 @@ public class RpcRegistry extends UntypedActor {
             }
         }
 
-        public static class FindRouters extends ContainsRoute {
+        public static class FindRouters {
+            private final RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier;
+
             public FindRouters(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
-                super(routeIdentifier);
+                Preconditions.checkArgument(routeIdentifier != null, "Route must not be null");
+                this.routeIdentifier = routeIdentifier;
+            }
+
+            public RpcRouter.RouteIdentifier<?, ?, ?> getRouteIdentifier() {
+                return routeIdentifier;
+            }
+
+            @Override
+            public String toString() {
+                return "FindRouters{" +
+                        "routeIdentifier=" + routeIdentifier +
+                        '}';
             }
         }
 
@@ -367,10 +373,11 @@ public class RpcRegistry extends UntypedActor {
             final List<Pair<ActorRef, Long>> routerWithUpdateTime;
 
             public FindRoutersReply(List<Pair<ActorRef, Long>> routerWithUpdateTime) {
+                Preconditions.checkArgument(routerWithUpdateTime != null, "List of routers found must not be null");
                 this.routerWithUpdateTime = routerWithUpdateTime;
             }
 
-            public List<Pair<ActorRef, Long>> getRouterWithUpdateTime(){
+            public List<Pair<ActorRef, Long>> getRouterWithUpdateTime() {
                 return routerWithUpdateTime;
             }
 
index 0b64136c49f9bda7bb331c9f5111d2146b91da9d..2320789d594aa56c8f7d4ff1ca4f99525b84ca95 100644 (file)
@@ -41,15 +41,18 @@ import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.Go
 
 /**
  * Gossiper that syncs bucket store across nodes in the cluster.
- * <p>
- * It keeps a local scheduler that periodically sends Gossip ticks to itself to send bucket store's bucket versions
- * to a randomly selected remote gossiper.
- * <p>
- * When bucket versions are received from a remote gossiper, it is compared with bucket store's bucket versions.
- * Which ever buckets are newer locally, are sent to remote gossiper. If any bucket is older in bucket store, a
- * gossip status is sent to remote gossiper so that it can send the newer buckets.
- * <p>
- * When a bucket is received from a remote gossiper, its sent to the bucket store for update.
+ * <p/>
+ * It keeps a local scheduler that periodically sends Gossip ticks to
+ * itself to send bucket store's bucket versions to a randomly selected remote
+ * gossiper.
+ * <p/>
+ * When bucket versions are received from a remote gossiper, it is compared
+ * with bucket store's bucket versions. Which ever buckets are newer
+ * locally, are sent to remote gossiper. If any bucket is older in bucket store,
+ * a gossip status is sent to remote gossiper so that it can send the newer buckets.
+ * <p/>
+ * When a bucket is received from a remote gossiper, its sent to the bucket store
+ * for update.
  *
  */
 
@@ -77,7 +80,8 @@ public class Gossiper extends UntypedActor {
 
     /**
      * Helpful for testing
-     * @param autoStartGossipTicks used for turning off gossip ticks during testing. Gossip tick can be manually sent.
+     * @param autoStartGossipTicks used for turning off gossip ticks during testing.
+     *                             Gossip tick can be manually sent.
      */
     public Gossiper(Boolean autoStartGossipTicks){
         this.autoStartGossipTicks = autoStartGossipTicks;
@@ -94,7 +98,7 @@ public class Gossiper extends UntypedActor {
         if (autoStartGossipTicks) {
             gossipTask = getContext().system().scheduler().schedule(
                     new FiniteDuration(1, TimeUnit.SECONDS),        //initial delay
-                    new FiniteDuration(500, TimeUnit.MILLISECONDS),         //interval
+                    new FiniteDuration(500, TimeUnit.MILLISECONDS), //interval
                     getSelf(),                                       //target
                     new Messages.GossiperMessages.GossipTick(),      //message
                     getContext().dispatcher(),                       //execution context
@@ -211,14 +215,12 @@ public class Gossiper extends UntypedActor {
      * @param status bucket versions from a remote member
      */
     void receiveGossipStatus(GossipStatus status){
-        //Dont want to accept messages from non-members
+        //Don't accept messages from non-members
         if (!clusterMembers.contains(status.from()))
             return;
 
         final ActorRef sender = getSender();
-
         Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
-
         futureReply.map(getMapperToProcessRemoteStatus(sender, status), getContext().dispatcher());
 
     }
@@ -231,11 +233,9 @@ public class Gossiper extends UntypedActor {
     void receiveGossip(GossipEnvelope envelope){
         //TODO: Add more validations
         if (!selfAddress.equals(envelope.to())) {
-            log.info("Ignoring message intended for someone else. From [{}] to [{}]", envelope.from(), envelope.to());
+            log.debug("Ignoring message intended for someone else. From [{}] to [{}]", envelope.from(), envelope.to());
             return;
         }
-        if (envelope.getBuckets() == null)
-            return; //nothing to do
 
         updateRemoteBuckets(envelope.getBuckets());
 
@@ -248,11 +248,7 @@ public class Gossiper extends UntypedActor {
      */
     void updateRemoteBuckets(Map<Address, Bucket> buckets) {
 
-        if (buckets == null || buckets.isEmpty())
-            return; //nothing to merge
-
         UpdateRemoteBuckets updateRemoteBuckets = new UpdateRemoteBuckets(buckets);
-
         getContext().parent().tell(updateRemoteBuckets, getSelf());
     }
 
@@ -265,9 +261,7 @@ public class Gossiper extends UntypedActor {
     void sendGossipTo(final ActorRef remote, final Set<Address> addresses){
 
         Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketsByMembers(addresses), 1000);
-
         futureReply.map(getMapperToSendGossip(remote), getContext().dispatcher());
-
     }
 
     /**
@@ -279,7 +273,6 @@ public class Gossiper extends UntypedActor {
 
         //Get local status from bucket store and send to remote
         Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
-
         ActorSelection remoteRef = getContext().system().actorSelection(
                 remoteActorSystemAddress.toString() + getSelf().path().toStringWithoutAddress());
 
@@ -328,14 +321,16 @@ public class Gossiper extends UntypedActor {
     }
 
     /**
-     * Process bucket versions received from {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore}.
+     * Process bucket versions received from
+     * {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore}.
      * Then this method compares remote bucket versions with local bucket versions.
      * <ul>
      *     <li>The buckets that are newer locally, send
-     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope} to remote
+     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope}
+     *     to remote
      *     <li>The buckets that are older locally, send
-     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus} to remote so that
-     *     remote sends GossipEnvelop.
+     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus}
+     *     to remote so that remote sends GossipEnvelop.
      * </ul>
      *
      * @param sender the remote member
@@ -390,9 +385,10 @@ public class Gossiper extends UntypedActor {
     }
 
     /**
-     * Processes the message from {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} that contains
-     * {@link org.opendaylight.controller.remote.rpc.registry.gossip.Bucket}. These buckets are sent to a remote member encapsulated
-     * in {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope}
+     * Processes the message from {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore}
+     * that contains {@link org.opendaylight.controller.remote.rpc.registry.gossip.Bucket}.
+     * These buckets are sent to a remote member encapsulated in
+     * {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope}
      *
      * @param sender the remote member that sent
      *               {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus}
@@ -407,7 +403,7 @@ public class Gossiper extends UntypedActor {
             public Void apply(Object msg) {
                 if (msg instanceof GetBucketsByMembersReply) {
                     Map<Address, Bucket> buckets = ((GetBucketsByMembersReply) msg).getBuckets();
-                    log.info("Buckets to send from {}: {}", selfAddress, buckets);
+                    log.debug("Buckets to send from {}: {}", selfAddress, buckets);
                     GossipEnvelope envelope = new GossipEnvelope(selfAddress, sender.path().address(), buckets);
                     sender.tell(envelope, getSelf());
                 }
index 9a247d97c77d308ec1eba9329facc12dc0ba6a69..bf8b20213b48e10a147dc96ddec473f6e891f882 100644 (file)
@@ -17,6 +17,10 @@ import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.ContainsBucketVersions;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.ContainsBuckets;
+
+
 /**
  * These messages are used by {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} and
  * {@link org.opendaylight.controller.remote.rpc.registry.gossip.Gossiper} actors.
@@ -107,7 +111,8 @@ public class Messages {
             Map<Address, Long> versions;
 
             public ContainsBucketVersions(Map<Address, Long> versions) {
-                Preconditions.checkArgument(versions != null, "versions can not be null");
+                Preconditions.checkArgument(versions != null, "versions can not be null or empty");
+
                 this.versions = versions;
             }
 
@@ -135,7 +140,7 @@ public class Messages {
 
         public static final class GossipTick extends Tick {}
 
-        public static final class GossipStatus extends BucketStoreMessages.ContainsBucketVersions implements Serializable{
+        public static final class GossipStatus extends ContainsBucketVersions implements Serializable{
             private Address from;
 
             public GossipStatus(Address from, Map<Address, Long> versions) {
@@ -148,12 +153,13 @@ public class Messages {
             }
         }
 
-        public static final class GossipEnvelope extends BucketStoreMessages.ContainsBuckets implements Serializable {
+        public static final class GossipEnvelope extends ContainsBuckets implements Serializable {
             private final Address from;
             private final Address to;
 
             public GossipEnvelope(Address from, Address to, Map<Address, Bucket> buckets) {
                 super(buckets);
+                Preconditions.checkArgument(to != null, "Recipient of message must not be null");
                 this.to = to;
                 this.from = from;
             }
index ab609413dd82731466495365d0c46f28731fcdc0..da3942a828182ff3e253e7c6ffcca2f99fdeb8b6 100644 (file)
@@ -24,10 +24,12 @@ import scala.concurrent.duration.FiniteDuration;
 
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoute;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoutes;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoutes;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRoutersReply;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
@@ -83,13 +85,14 @@ public class RpcRegistryTest {
 
     /**
      * One node cluster.
-     * Register rpc. Ensure router can be found
+     * 1. Register rpc, ensure router can be found
+     * 2. Then remove rpc, ensure its deleted
      *
      * @throws URISyntaxException
      * @throws InterruptedException
      */
     @Test
-    public void testWhenRpcAddedOneNodeShouldAppearOnSameNode() throws URISyntaxException, InterruptedException {
+    public void testAddRemoveRpcOnSameNode() throws URISyntaxException, InterruptedException {
 
         final JavaTestKit mockBroker = new JavaTestKit(node1);
 
@@ -105,17 +108,28 @@ public class RpcRegistryTest {
         List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
 
         validateRouterReceived(pairs, mockBroker.getRef());
+
+        //Now remove rpc
+        registry1.tell(getRemoveRouteMessage(), mockBroker.getRef());
+        Thread.sleep(1000);
+        //find the route on node 1's registry
+        registry1.tell(new FindRouters(createRouteId()), mockBroker.getRef());
+        message = mockBroker.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        pairs = message.getRouterWithUpdateTime();
+
+        Assert.assertTrue(pairs.isEmpty());
     }
 
     /**
      * Three node cluster.
-     * Register rpc on 1 node. Ensure its router can be found on other 2.
+     * 1. Register rpc on 1 node, ensure its router can be found on other 2.
+     * 2. Remove rpc on 1 node, ensure its removed on other 2.
      *
      * @throws URISyntaxException
      * @throws InterruptedException
      */
     @Test
-    public void testWhenRpcAddedOneNodeShouldAppearOnAnother() throws URISyntaxException, InterruptedException {
+    public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
 
         validateSystemStartup();
 
@@ -127,22 +141,25 @@ public class RpcRegistryTest {
         registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
         registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
 
-        Thread.sleep(5000);// give some time for bucket store data sync
+        Thread.sleep(1000);// give some time for bucket store data sync
 
         //find the route in node 2's registry
-        registry2.tell(new FindRouters(createRouteId()), mockBroker2.getRef());
-        FindRoutersReply message = mockBroker2.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
-        List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
-
+        List<Pair<ActorRef, Long>> pairs = findRouters(registry2, mockBroker2);
         validateRouterReceived(pairs, mockBroker1.getRef());
 
         //find the route in node 3's registry
-        registry3.tell(new FindRouters(createRouteId()), mockBroker3.getRef());
-        message = mockBroker3.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
-        pairs = message.getRouterWithUpdateTime();
-
+        pairs = findRouters(registry3, mockBroker3);
         validateRouterReceived(pairs, mockBroker1.getRef());
 
+        //Now remove
+        registry1.tell(getRemoveRouteMessage(), mockBroker1.getRef());
+        Thread.sleep(1000);// give some time for bucket store data sync
+
+        pairs = findRouters(registry2, mockBroker2);
+        Assert.assertTrue(pairs.isEmpty());
+
+        pairs = findRouters(registry3, mockBroker3);
+        Assert.assertTrue(pairs.isEmpty());
     }
 
     /**
@@ -171,7 +188,7 @@ public class RpcRegistryTest {
         registry2.tell(getAddRouteMessage(), mockBroker2.getRef());
 
         registry3.tell(new SetLocalRouter(mockBroker3.getRef()), mockBroker3.getRef());
-        Thread.sleep(5000);// give some time for bucket store data sync
+        Thread.sleep(1000);// give some time for bucket store data sync
 
         //find the route in node 3's registry
         registry3.tell(new FindRouters(createRouteId()), mockBroker3.getRef());
@@ -182,6 +199,12 @@ public class RpcRegistryTest {
 
     }
 
+    private List<Pair<ActorRef, Long>> findRouters(ActorRef registry, JavaTestKit receivingActor) throws URISyntaxException {
+        registry.tell(new FindRouters(createRouteId()), receivingActor.getRef());
+        FindRoutersReply message = receivingActor.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        return message.getRouterWithUpdateTime();
+    }
+
     private void validateMultiRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef... expected) {
         Assert.assertTrue(actual != null);
         Assert.assertTrue(actual.size() == expected.length);
@@ -237,8 +260,19 @@ public class RpcRegistryTest {
         return resolved;
     }
 
-    private AddOrUpdateRoute getAddRouteMessage() throws URISyntaxException {
-        return new AddOrUpdateRoute(createRouteId());
+    private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
+        return new AddOrUpdateRoutes(createRouteIds());
+    }
+
+    private RemoveRoutes getRemoveRouteMessage() throws URISyntaxException {
+        return new RemoveRoutes(createRouteIds());
+    }
+
+    private List<RpcRouter.RouteIdentifier<?,?,?>> createRouteIds() throws URISyntaxException {
+        QName type = new QName(new URI("/mockrpc"), "mockrpc");
+        List<RpcRouter.RouteIdentifier<?,?,?>> routeIds = new ArrayList<>();
+        routeIds.add(new RouteIdentifierImpl(null, type, null));
+        return routeIds;
     }
 
     private RpcRouter.RouteIdentifier<?,?,?> createRouteId() throws URISyntaxException {
index d862dcb8cd5f96b5e81aea87a3da297b5164340e..f076c136feb80d0752777988efb711766086721a 100644 (file)
@@ -115,17 +115,6 @@ public class GossiperTest {
         verify(mockGossiper, times(0)).updateRemoteBuckets(anyMap());
     }
 
-    @Test
-    public void testUpdateRemoteBuckets_WhenNoBucketShouldIgnore(){
-
-        mockGossiper.updateRemoteBuckets(null);
-        verify(mockGossiper, times(0)).getContext();
-
-        Map<Address, Bucket> empty = Collections.emptyMap();
-        mockGossiper.updateRemoteBuckets(empty);
-        verify(mockGossiper, times(0)).getContext();
-    }
-
     /**
      * Create Gossiper actor and return the underlying instance of Gossiper class.
      *
index 6d050cf4252b141a60fb04b550cda7d923c092b3..fa91f0398d75cac155269ab83dd6f804e940acec 100644 (file)
   <artifactId>sal-rest-connector-config</artifactId>
   <description>Configuration files for sal-rest-connector</description>
   <packaging>jar</packaging>
+    <build>
+    <plugins>
+        <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <executions>
+          <execution>
+            <id>attach-artifacts</id>
+            <goals>
+              <goal>attach-artifact</goal>
+            </goals>
+            <phase>package</phase>
+            <configuration>
+              <artifacts>
+                <artifact>
+                  <file>${project.build.directory}/classes/initial/10-rest-connector.xml</file>
+                  <type>xml</type>
+                  <classifier>config</classifier>
+                </artifact>
+              </artifacts>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+  </build>
 </project>
index 2fdc8c7d1ef2e0873db819c2cb1b68cf88fb41d9..3be423c35628d06378ead78b344059a15dcc3ed6 100644 (file)
@@ -14,7 +14,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
         <module>
           <type xmlns:rest="urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector">rest:rest-connector-impl</type>
           <name>rest-connector-default-impl</name>
-          <websocket-port>8181</websocket-port>
+          <websocket-port>8185</websocket-port>
           <dom-broker>
             <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
             <name>dom-broker</name>
@@ -35,4 +35,7 @@ and is available at http://www.eclipse.org/legal/epl-v10.html
       </services>
     </data>
   </configuration>
+  <required-capabilities>
+      <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:rest:connector?module=opendaylight-rest-connector&amp;revision=2014-07-24</capability>
+  </required-capabilities>
 </snapshot>
index e01a0d5dcba4956f790d2274462455911970742c..97ed15df191d8159300e5754aa111d2c0ee8ea51 100644 (file)
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal</artifactId>
+      <artifactId>sal-binding-api</artifactId>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-binding-api</artifactId>
+      <artifactId>liblldp</artifactId>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller.model</groupId>
index 82ab4432462af79fbbc6fe611f06175fa5cb93e9..0d1ba11ee12a991d4806a90c56b2150832af2378 100644 (file)
@@ -9,10 +9,10 @@ package org.opendaylight.md.controller.topology.lldp.utils;
 
 import java.nio.charset.Charset;
 
-import org.opendaylight.controller.sal.packet.Ethernet;
-import org.opendaylight.controller.sal.packet.LLDP;
-import org.opendaylight.controller.sal.packet.LLDPTLV;
-import org.opendaylight.controller.sal.utils.NetUtils;
+import org.opendaylight.controller.liblldp.Ethernet;
+import org.opendaylight.controller.liblldp.LLDP;
+import org.opendaylight.controller.liblldp.LLDPTLV;
+import org.opendaylight.controller.liblldp.NetUtils;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
@@ -10,9 +10,6 @@ package org.opendaylight.controller.netconf.persist.impl;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
-import com.google.common.base.Function;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.Collections2;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Collection;
@@ -23,10 +20,17 @@ import java.util.Map.Entry;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeMap;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+
 import javax.annotation.concurrent.Immutable;
+import javax.management.MBeanServerConnection;
+
 import org.opendaylight.controller.config.api.ConflictingVersionException;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
+import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
@@ -45,22 +49,60 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.xml.sax.SAXException;
 
+import com.google.common.base.Function;
+import com.google.common.base.Stopwatch;
+import com.google.common.collect.Collections2;
+
 @Immutable
-public class ConfigPusher {
-    private static final Logger logger = LoggerFactory.getLogger(ConfigPusher.class);
+public class ConfigPusherImpl implements ConfigPusher {
+    private static final Logger logger = LoggerFactory.getLogger(ConfigPusherImpl.class);
 
     private final long maxWaitForCapabilitiesMillis;
     private final long conflictingVersionTimeoutMillis;
     private final NetconfOperationServiceFactory configNetconfConnector;
+    private static final int QUEUE_SIZE = 100;
+    private BlockingQueue<List<? extends ConfigSnapshotHolder>> queue = new LinkedBlockingQueue<List<? extends ConfigSnapshotHolder>>(QUEUE_SIZE);
 
-    public ConfigPusher(NetconfOperationServiceFactory configNetconfConnector, long maxWaitForCapabilitiesMillis,
+    public ConfigPusherImpl(NetconfOperationServiceFactory configNetconfConnector, long maxWaitForCapabilitiesMillis,
                         long conflictingVersionTimeoutMillis) {
         this.configNetconfConnector = configNetconfConnector;
         this.maxWaitForCapabilitiesMillis = maxWaitForCapabilitiesMillis;
         this.conflictingVersionTimeoutMillis = conflictingVersionTimeoutMillis;
     }
 
-    public synchronized LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponse> pushConfigs(List<ConfigSnapshotHolder> configs) throws NetconfDocumentedException {
+    public void process(List<AutoCloseable> autoCloseables, MBeanServerConnection platformMBeanServer, Persister persisterAggregator) throws InterruptedException {
+        List<? extends ConfigSnapshotHolder> configs;
+        while(true) {
+            configs = queue.take();
+            try {
+                internalPushConfigs(configs);
+                ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
+                synchronized (autoCloseables) {
+                    autoCloseables.add(jmxNotificationHandler);
+                }
+                /*
+                 * We have completed initial configuration. At this point
+                 * it is good idea to perform garbage collection to prune
+                 * any garbage we have accumulated during startup.
+                 */
+                logger.debug("Running post-initialization garbage collection...");
+                System.gc();
+                logger.debug("Post-initialization garbage collection completed.");
+                logger.debug("ConfigPusher has pushed configs {}, gc completed", configs);
+            }
+            catch (NetconfDocumentedException e) {
+                logger.error("Error pushing configs {}",configs);
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    public void pushConfigs(List<? extends ConfigSnapshotHolder> configs) throws InterruptedException {
+        logger.debug("Requested to push configs {}", configs);
+        this.queue.put(configs);
+    }
+
+    private LinkedHashMap<? extends ConfigSnapshotHolder, EditAndCommitResponse> internalPushConfigs(List<? extends ConfigSnapshotHolder> configs) throws NetconfDocumentedException {
         logger.debug("Last config snapshots to be pushed to netconf: {}", configs);
         LinkedHashMap<ConfigSnapshotHolder, EditAndCommitResponse> result = new LinkedHashMap<>();
         // start pushing snapshots:
@@ -278,7 +320,7 @@ public class ConfigPusher {
 
     private static NetconfMessage getCommitMessage() {
         String resource = "/netconfOp/commit.xml";
-        try (InputStream stream = ConfigPusher.class.getResourceAsStream(resource)) {
+        try (InputStream stream = ConfigPusherImpl.class.getResourceAsStream(resource)) {
             checkNotNull(stream, "Unable to load resource " + resource);
             return new NetconfMessage(XmlUtil.readXmlToDocument(stream));
         } catch (SAXException | IOException e) {
index 48ae0cb91a132d1cd7bff773df604e2d5ae1c47a..0a48e6c67dc8cc290c2b81a1b0eb67c05ac7c618 100644 (file)
@@ -8,13 +8,18 @@
 
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
-import com.google.common.annotations.VisibleForTesting;
+import java.lang.management.ManagementFactory;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.management.MBeanServer;
+
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
-import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationProvider;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPersisterNotificationHandler;
-import org.opendaylight.controller.netconf.persist.impl.ConfigPusher;
+import org.opendaylight.controller.netconf.persist.impl.ConfigPusherImpl;
 import org.opendaylight.controller.netconf.persist.impl.PersisterAggregator;
 import org.opendaylight.controller.netconf.util.CloseableUtil;
 import org.osgi.framework.BundleActivator;
@@ -23,16 +28,13 @@ import org.osgi.framework.Constants;
 import org.osgi.framework.Filter;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.util.tracker.ServiceTracker;
 import org.osgi.util.tracker.ServiceTrackerCustomizer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.management.MBeanServer;
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
+import com.google.common.annotations.VisibleForTesting;
 
 public class ConfigPersisterActivator implements BundleActivator {
 
@@ -49,11 +51,15 @@ public class ConfigPersisterActivator implements BundleActivator {
     public static final String STORAGE_ADAPTER_CLASS_PROP_SUFFIX = "storageAdapterClass";
 
     private List<AutoCloseable> autoCloseables;
+    private volatile BundleContext context;
 
+    ServiceRegistration<?> registration;
 
     @Override
     public void start(final BundleContext context) throws Exception {
         logger.debug("ConfigPersister starting");
+        this.context = context;
+
         autoCloseables = new ArrayList<>();
         PropertiesProviderBaseImpl propertiesProvider = new PropertiesProviderBaseImpl(context);
 
@@ -81,8 +87,14 @@ public class ConfigPersisterActivator implements BundleActivator {
     }
 
     @Override
-    public synchronized void stop(BundleContext context) throws Exception {
-        CloseableUtil.closeAll(autoCloseables);
+    public void stop(BundleContext context) throws Exception {
+        synchronized(autoCloseables) {
+            CloseableUtil.closeAll(autoCloseables);
+            if (registration != null) {
+                registration.unregister();
+            }
+            this.context = null;
+        }
     }
 
 
@@ -147,35 +159,29 @@ public class ConfigPersisterActivator implements BundleActivator {
             logger.trace("Got InnerCustomizer.addingService {}", reference);
             NetconfOperationServiceFactory service = reference.getBundle().getBundleContext().getService(reference);
 
-            final ConfigPusher configPusher = new ConfigPusher(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
+            logger.debug("Creating new job queue");
+
+            final ConfigPusherImpl configPusher = new ConfigPusherImpl(service, maxWaitForCapabilitiesMillis, conflictingVersionTimeoutMillis);
             logger.debug("Configuration Persister got {}", service);
+            logger.debug("Context was {}", context);
+            logger.debug("Registration was {}", registration);
+
             final Thread pushingThread = new Thread(new Runnable() {
                 @Override
                 public void run() {
                     try {
-                        configPusher.pushConfigs(configs);
-                    } catch (NetconfDocumentedException e) {
-                        logger.error("Error pushing configs {}",configs);
-                        throw new IllegalStateException(e);
+                        if(configs != null && !configs.isEmpty()) {
+                            configPusher.pushConfigs(configs);
+                        }
+                        registration = context.registerService(ConfigPusher.class.getName(), configPusher, null);
+                        configPusher.process(autoCloseables, platformMBeanServer, persisterAggregator);
+                    } catch (InterruptedException e) {
+                        logger.info("ConfigPusher thread stopped",e);
                     }
                     logger.info("Configuration Persister initialization completed.");
-
-                    /*
-                     * We have completed initial configuration. At this point
-                     * it is good idea to perform garbage collection to prune
-                     * any garbage we have accumulated during startup.
-                     */
-                    logger.debug("Running post-initialization garbage collection...");
-                    System.gc();
-                    logger.debug("Post-initialization garbage collection completed.");
-
-                    ConfigPersisterNotificationHandler jmxNotificationHandler = new ConfigPersisterNotificationHandler(platformMBeanServer, persisterAggregator);
-                    synchronized (ConfigPersisterActivator.this) {
-                        autoCloseables.add(jmxNotificationHandler);
-                    }
                 }
             }, "config-pusher");
-            synchronized (ConfigPersisterActivator.this) {
+            synchronized (autoCloseables) {
                 autoCloseables.add(new AutoCloseable() {
                     @Override
                     public void close() {
index 95fd5f65498e507c54e6d88023dc24b25475031a..3e5249468da703051ed8fe436843d37c316ab7c5 100644 (file)
@@ -7,10 +7,23 @@
  */
 package org.opendaylight.controller.netconf.persist.impl.osgi;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.Collections;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.config.persist.api.ConfigPusher;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.api.PropertiesProvider;
@@ -23,18 +36,10 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.Filter;
 import org.osgi.framework.ServiceListener;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 
-import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyString;
-import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
 
 final class MockedBundleContext {
     @Mock
@@ -49,6 +54,8 @@ final class MockedBundleContext {
     NetconfOperationServiceFactory serviceFactory;
     @Mock
     private NetconfOperationService service;
+    @Mock
+    private ServiceRegistration<?> registration;
 
     MockedBundleContext(long maxWaitForCapabilitiesMillis, long conflictingVersionTimeoutMillis) throws Exception {
         MockitoAnnotations.initMocks(this);
@@ -77,6 +84,11 @@ final class MockedBundleContext {
         doReturn(Collections.emptySet()).when(service).getCapabilities();
         doNothing().when(service).close();
         doReturn("serviceFactoryMock").when(serviceFactory).toString();
+
+        doNothing().when(registration).unregister();
+        doReturn(registration).when(context).registerService(
+                eq(ConfigPusher.class.getName()), any(Closeable.class),
+                any(Dictionary.class));
     }
 
     public BundleContext getBundleContext() {
index b32b01cb3f3015930510d22fd1a39836a25a0cbb..803e5e8d41ff8af5d1e51ffc09abaa364ad214cc 100644 (file)
@@ -235,6 +235,11 @@ public class NeutronPort extends ConfigurationObject implements Serializable, IN
             if (s.equals("tenant_id")) {
                 ans.setTenantID(this.getTenantID());
             }
+            if (s.equals("security_groups")) {
+                List<NeutronSecurityGroup> securityGroups = new ArrayList<NeutronSecurityGroup>();
+                securityGroups.addAll(this.getSecurityGroups());
+                ans.setSecurityGroups(securityGroups);
+            }
         }
         return ans;
     }
index 806e853b3604ec7848e08176aaf7f8d8e8f3996f..0c02adad8a0d4d4ddf499efca66d39b05aff513c 100644 (file)
@@ -527,6 +527,9 @@ public class NeutronRoutersNorthbound {
         if (input.getPortUUID() != null &&
                 input.getSubnetUUID() == null) {
             NeutronRouter_Interface targetInterface = target.getInterfaces().get(input.getPortUUID());
+            if (targetInterface == null) {
+                throw new ResourceNotFoundException("Router interface not found for given Port UUID");
+            }
             input.setSubnetUUID(targetInterface.getSubnetUUID());
             input.setID(target.getID());
             input.setTenantID(target.getTenantID());
@@ -554,7 +557,7 @@ public class NeutronRoutersNorthbound {
                 throw new ResourceNotFoundException("Port UUID not found");
             }
             if (port.getFixedIPs() == null) {
-                throw new ResourceNotFoundException("Port UUID jas no fixed IPs");
+                throw new ResourceNotFoundException("Port UUID has no fixed IPs");
             }
             NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
             if (subnet == null) {
diff --git a/pom.xml b/pom.xml
index 8bebd2aa61050f0d8058d82f312ac572ec44bf86..e4c51b7839cff2f9af808d3fc78866bd0f599d45 100644 (file)
--- a/pom.xml
+++ b/pom.xml
     <module>opendaylight/commons/parent</module>
     <module>opendaylight/commons/logback_settings</module>
     <module>opendaylight/commons/filter-valve</module>
+    <module>opendaylight/commons/liblldp</module>
 
     <!-- Karaf Distribution -->
     <module>opendaylight/dummy-console</module>