Merge "Bug 2517: Catch RuntimeExceptions thrown from the DCL in DataChangeListener"
authorMoiz Raja <moraja@cisco.com>
Tue, 23 Dec 2014 18:12:30 +0000 (18:12 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 23 Dec 2014 18:12:31 +0000 (18:12 +0000)
53 files changed:
features/neutron/pom.xml
opendaylight/adsal/features/adsal/pom.xml
opendaylight/adsal/features/base/pom.xml
opendaylight/adsal/features/controller/pom.xml
opendaylight/adsal/features/extras/pom.xml
opendaylight/adsal/features/nsf/pom.xml
opendaylight/archetypes/odl-model-project/src/main/resources/archetype-resources/pom.xml
opendaylight/commons/opendaylight/pom.xml
opendaylight/config/config-persister-directory-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/directory/xml/XmlDirectoryPersister.java
opendaylight/config/config-persister-feature-adapter/src/main/java/org/opendaylight/controller/configpusherfeature/internal/FeatureConfigSnapshotHolder.java
opendaylight/config/config-persister-file-xml-adapter/src/main/java/org/opendaylight/controller/config/persist/storage/file/xml/model/Config.java
opendaylight/md-sal/sal-akka-raft/src/main/java/org/opendaylight/controller/cluster/raft/behaviors/Follower.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/FollowerTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/impl/connect/dom/RpcInvocationStrategyTest.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/client/messages/CompositeModificationByteStringPayload.java [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/RandomPrefix.java
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/xml/codec/XmlStreamUtils.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/Shard.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationByteStringPayloadTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ShardTest.java
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMService.java
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/IdentityValuesDTO.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestCodec.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/cnsn/to/xml/test/CnSnToXmlTest.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/TestUtils.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/test/java/org/opendaylight/controller/netconf/client/NetconfClientSessionTest.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerSession.java
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/osgi/NetconfOperationServiceSnapshotImpl.java
opendaylight/netconf/netconf-it/pom.xml
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTest.java
opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTestTool.java [new file with mode: 0644]
opendaylight/netconf/netconf-it/src/test/resources/logback-test.xml
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/AbstractNetconfSession.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXICodec.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXIToMessageDecoder.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfMessageToEXIEncoder.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/AsyncSshHandlerWriter.java
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/AbstractNetconfSessionTest.java
opendaylight/netconf/netconf-netty-util/src/test/java/org/opendaylight/controller/netconf/nettyutil/handler/NetconfEXIHandlersTest.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java
opendaylight/netconf/netconf-util/src/test/resources/netconfMessages/editConfig.xml
pom.xml

index 59a0af2..642ce98 100644 (file)
   </properties>
 
   <dependencies>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>networkconfig.neutron</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.osgi</groupId>
       <artifactId>org.osgi.core</artifactId>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>features-test</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.yangtools</groupId>
-      <artifactId>features-test</artifactId>
-      <version>0.7.0-SNAPSHOT</version>
-    </dependency>
   </dependencies>
 
   <build>
index 57fa1e2..a13c2cb 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project>
+<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>
index 795a323..c5ea280 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project>
+<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>
index 34be32f..9e41561 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project>
+<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>
index 103fbef..b86b0e2 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project>
+<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>
index 0c8e838..19b3fe0 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project>
+<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>
index 6b41485..0786b36 100644 (file)
-<?xml version="1.0" encoding="UTF-8"?>\r
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
-  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
-  <modelVersion>4.0.0</modelVersion>\r
-  <artifactId>${artifactId}</artifactId>\r
-  <groupId>${groupId}</groupId>\r
-  <version>${version}</version>\r
-  <packaging>bundle</packaging>\r
-  <properties>\r
-    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\r
-    <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>\r
+<?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>
+  <artifactId>${artifactId}</artifactId>
+  <groupId>${groupId}</groupId>
+  <version>${version}</version>
+  <packaging>bundle</packaging>
+  <properties>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <nexusproxy>http://nexus.opendaylight.org/content</nexusproxy>
     <nexus.repository.release>opendaylight.release</nexus.repository.release>
-    <nexus.repository.snapshot>opendaylight.release</nexus.repository.snaphot>
-    <yang.version>0.7.0-SNAPSHOT</yang.version>\r
-    <yang.codegen.version>0.7.0-SNAPSHOT</yang.codegen.version>\r
-    <bundle.plugin.version>2.3.7</bundle.plugin.version>\r
-  </properties>\r
-  <scm>\r
-    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>\r
-    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>\r
-    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>\r
-  </scm>\r
-\r
-  <build>\r
-    <plugins>\r
-      <plugin>\r
-        <groupId>org.apache.felix</groupId>\r
-        <artifactId>maven-bundle-plugin</artifactId>\r
-        <version>${bundle.plugin.version}</version>\r
-        <extensions>true</extensions>\r
-        <configuration>\r
-          <instructions>\r
-            <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>\r
-          </instructions>\r
-          <manifestLocation>${project.basedir}/META-INF</manifestLocation>\r
-        </configuration>\r
-      </plugin>\r
-      <plugin>\r
-        <groupId>org.apache.maven.plugins</groupId>\r
-        <artifactId>maven-compiler-plugin</artifactId>\r
-        <version>2.5.1</version>\r
-        <inherited>true</inherited>\r
-        <configuration>\r
-          <source>1.7</source>\r
-          <target>1.7</target>\r
-        </configuration>\r
-      </plugin>\r
-      <plugin>\r
-        <groupId>org.apache.maven.plugins</groupId>\r
-        <artifactId>maven-javadoc-plugin</artifactId>\r
-        <version>2.8.1</version>\r
-        <configuration>\r
-          <stylesheet>maven</stylesheet>\r
-        </configuration>\r
-        <executions>\r
-          <execution>\r
-            <goals>\r
-              <goal>aggregate</goal>\r
-            </goals>\r
-            <phase>site</phase>\r
-          </execution>\r
-        </executions>\r
-      </plugin>\r
-      <plugin>\r
-        <groupId>org.opendaylight.yangtools</groupId>\r
-        <artifactId>yang-maven-plugin</artifactId>\r
-        <version>${yang.version}</version>\r
-        <executions>\r
-          <execution>\r
-            <goals>\r
-              <goal>generate-sources</goal>\r
-            </goals>\r
-            <configuration>\r
-              <yangFilesRootDir>src/main/yang</yangFilesRootDir>\r
-              <codeGenerators>\r
-                <generator>\r
-                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>\r
-                  <outputBaseDir>target/generated-sources/sal</outputBaseDir>\r
-                </generator>\r
-              </codeGenerators>\r
-              <inspectDependencies>false</inspectDependencies>\r
-            </configuration>\r
-          </execution>\r
-        </executions>\r
-\r
-        <dependencies>\r
-          <dependency>\r
-            <groupId>org.opendaylight.yangtools</groupId>\r
-            <artifactId>maven-sal-api-gen-plugin</artifactId>\r
-            <version>${yang.codegen.version}</version>\r
-            <type>jar</type>\r
-          </dependency>\r
-        </dependencies>\r
-      </plugin>\r
-      <plugin>\r
-        <groupId>org.codehaus.mojo</groupId>\r
-        <artifactId>build-helper-maven-plugin</artifactId>\r
-        <version>1.7</version>\r
-        <executions>\r
-          <execution>\r
-            <phase>generate-sources</phase>\r
-            <goals>\r
-              <goal>add-source</goal>\r
-            </goals>\r
-            <configuration>\r
-              <sources>\r
-                <source>target/generated-sources/sal</source>\r
-              </sources>\r
-            </configuration>\r
-          </execution>\r
-        </executions>\r
-      </plugin>\r
-    </plugins>\r
-    <pluginManagement>\r
-      <plugins>\r
-        <!--This plugin's configuration is used to store Eclipse m2e settings\r
-          only. It has no influence on the Maven build itself. -->\r
-        <plugin>\r
-          <groupId>org.eclipse.m2e</groupId>\r
-          <artifactId>lifecycle-mapping</artifactId>\r
-          <version>1.0.0</version>\r
-          <configuration>\r
-            <lifecycleMappingMetadata>\r
-              <pluginExecutions>\r
-                <pluginExecution>\r
-                  <pluginExecutionFilter>\r
-                    <groupId>org.opendaylight.yangtools</groupId>\r
-                    <artifactId>yang-maven-plugin</artifactId>\r
-                    <versionRange>[0.5,)</versionRange>\r
-                    <goals>\r
-                      <goal>generate-sources</goal>\r
-                    </goals>\r
-                  </pluginExecutionFilter>\r
-                  <action>\r
-                    <ignore></ignore>\r
-                  </action>\r
-                </pluginExecution>\r
-              </pluginExecutions>\r
-            </lifecycleMappingMetadata>\r
-          </configuration>\r
-        </plugin>\r
-      </plugins>\r
-    </pluginManagement>\r
-  </build>\r
-  <pluginRepositories>\r
-    <!-- OpenDayLight Repo Mirror -->\r
-    <pluginRepository>\r
-      <id>opendaylight-mirror</id>\r
-      <name>opendaylight-mirror</name>\r
-      <url>${nexusproxy}/groups/public/</url>\r
-      <snapshots>\r
-          <enabled>false</enabled>\r
-      </snapshots>\r
-      <releases>\r
-          <enabled>true</enabled>\r
-          <updatePolicy>never</updatePolicy>\r
-      </releases>\r
-    </pluginRepository>\r
-    <!-- OpenDayLight Snapshot artifact -->\r
-    <pluginRepository>\r
-      <id>opendaylight-snapshot</id>\r
-      <name>opendaylight-snapshot</name>\r
+    <nexus.repository.snapshot>opendaylight.release</nexus.repository.snapshot>
+    <yang.version>0.7.0-SNAPSHOT</yang.version>
+    <yang.codegen.version>0.7.0-SNAPSHOT</yang.codegen.version>
+    <bundle.plugin.version>2.3.7</bundle.plugin.version>
+  </properties>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+  </scm>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <version>${bundle.plugin.version}</version>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
+          </instructions>
+          <manifestLocation>${project.basedir}/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <version>2.5.1</version>
+        <inherited>true</inherited>
+        <configuration>
+          <source>1.7</source>
+          <target>1.7</target>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-javadoc-plugin</artifactId>
+        <version>2.8.1</version>
+        <configuration>
+          <stylesheet>maven</stylesheet>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>aggregate</goal>
+            </goals>
+            <phase>site</phase>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.opendaylight.yangtools</groupId>
+        <artifactId>yang-maven-plugin</artifactId>
+        <version>${yang.version}</version>
+        <executions>
+          <execution>
+            <goals>
+              <goal>generate-sources</goal>
+            </goals>
+            <configuration>
+              <yangFilesRootDir>src/main/yang</yangFilesRootDir>
+              <codeGenerators>
+                <generator>
+                  <codeGeneratorClass>org.opendaylight.yangtools.maven.sal.api.gen.plugin.CodeGeneratorImpl</codeGeneratorClass>
+                  <outputBaseDir>target/generated-sources/sal</outputBaseDir>
+                </generator>
+              </codeGenerators>
+              <inspectDependencies>false</inspectDependencies>
+            </configuration>
+          </execution>
+        </executions>
+
+        <dependencies>
+          <dependency>
+            <groupId>org.opendaylight.yangtools</groupId>
+            <artifactId>maven-sal-api-gen-plugin</artifactId>
+            <version>${yang.codegen.version}</version>
+            <type>jar</type>
+          </dependency>
+        </dependencies>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.mojo</groupId>
+        <artifactId>build-helper-maven-plugin</artifactId>
+        <version>1.7</version>
+        <executions>
+          <execution>
+            <phase>generate-sources</phase>
+            <goals>
+              <goal>add-source</goal>
+            </goals>
+            <configuration>
+              <sources>
+                <source>target/generated-sources/sal</source>
+              </sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+    </plugins>
+    <pluginManagement>
+      <plugins>
+        <!--This plugin's configuration is used to store Eclipse m2e settings
+          only. It has no influence on the Maven build itself. -->
+        <plugin>
+          <groupId>org.eclipse.m2e</groupId>
+          <artifactId>lifecycle-mapping</artifactId>
+          <version>1.0.0</version>
+          <configuration>
+            <lifecycleMappingMetadata>
+              <pluginExecutions>
+                <pluginExecution>
+                  <pluginExecutionFilter>
+                    <groupId>org.opendaylight.yangtools</groupId>
+                    <artifactId>yang-maven-plugin</artifactId>
+                    <versionRange>[0.5,)</versionRange>
+                    <goals>
+                      <goal>generate-sources</goal>
+                    </goals>
+                  </pluginExecutionFilter>
+                  <action>
+                    <ignore></ignore>
+                  </action>
+                </pluginExecution>
+              </pluginExecutions>
+            </lifecycleMappingMetadata>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+  <pluginRepositories>
+    <!-- OpenDayLight Repo Mirror -->
+    <pluginRepository>
+      <id>opendaylight-mirror</id>
+      <name>opendaylight-mirror</name>
+      <url>${nexusproxy}/groups/public/</url>
+      <snapshots>
+          <enabled>false</enabled>
+      </snapshots>
+      <releases>
+          <enabled>true</enabled>
+          <updatePolicy>never</updatePolicy>
+      </releases>
+    </pluginRepository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <pluginRepository>
+      <id>opendaylight-snapshot</id>
+      <name>opendaylight-snapshot</name>
       <url>${nexusproxy}/repositories/${nexus.repository.snapshot}/</url>
-      <snapshots>\r
-          <enabled>true</enabled>\r
-      </snapshots>\r
-      <releases>\r
-          <enabled>false</enabled>\r
-      </releases>\r
-    </pluginRepository>\r
-  </pluginRepositories>\r
-\r
-  <repositories>\r
-    <!-- OpenDayLight Repo Mirror -->\r
-    <repository>\r
-      <id>opendaylight-mirror</id>\r
-      <name>opendaylight-mirror</name>\r
-      <url>${nexusproxy}/groups/public/</url>\r
-      <snapshots>\r
-          <enabled>false</enabled>\r
-      </snapshots>\r
-      <releases>\r
-          <enabled>true</enabled>\r
-          <updatePolicy>never</updatePolicy>\r
-      </releases>\r
-    </repository>\r
-    <!-- OpenDayLight Snapshot artifact -->\r
-    <repository>\r
-      <id>opendaylight-snapshot</id>\r
-      <name>opendaylight-snapshot</name>\r
+      <snapshots>
+          <enabled>true</enabled>
+      </snapshots>
+      <releases>
+          <enabled>false</enabled>
+      </releases>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <repositories>
+    <!-- OpenDayLight Repo Mirror -->
+    <repository>
+      <id>opendaylight-mirror</id>
+      <name>opendaylight-mirror</name>
+      <url>${nexusproxy}/groups/public/</url>
+      <snapshots>
+          <enabled>false</enabled>
+      </snapshots>
+      <releases>
+          <enabled>true</enabled>
+          <updatePolicy>never</updatePolicy>
+      </releases>
+    </repository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <repository>
+      <id>opendaylight-snapshot</id>
+      <name>opendaylight-snapshot</name>
       <url>${nexusproxy}/repositories/${nexus.repository.snapshot}/</url>
-      <snapshots>\r
-          <enabled>true</enabled>\r
-      </snapshots>\r
-      <releases>\r
-          <enabled>false</enabled>\r
-      </releases>\r
-    </repository>\r
-  </repositories>\r
-\r
-  <distributionManagement>\r
-    <!-- OpenDayLight Released artifact -->\r
-    <repository>\r
-      <id>opendaylight-release</id>\r
+      <snapshots>
+          <enabled>true</enabled>
+      </snapshots>
+      <releases>
+          <enabled>false</enabled>
+      </releases>
+    </repository>
+  </repositories>
+
+  <distributionManagement>
+    <!-- OpenDayLight Released artifact -->
+    <repository>
+      <id>opendaylight-release</id>
       <url>${nexusproxy}/repositories/${nexus.repository.release}/</url>
-    </repository>\r
-    <!-- OpenDayLight Snapshot artifact -->\r
-    <snapshotRepository>\r
-      <id>opendaylight-snapshot</id>\r
+    </repository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <snapshotRepository>
+      <id>opendaylight-snapshot</id>
       <url>${nexusproxy}/repositories/${nexus.repository.snapshot}/</url>
-    </snapshotRepository>\r
-    <!-- Site deployment -->\r
-    <site>\r
-      <id>website</id>\r
-      <url>${sitedeploy}</url>\r
-    </site>\r
-  </distributionManagement>\r
-  <dependencies>\r
-    <dependency>\r
-      <groupId>org.opendaylight.yangtools</groupId>\r
-      <artifactId>yang-binding</artifactId>\r
-      <version>${yang.codegen.version}</version>\r
-    </dependency>\r
-  </dependencies>\r
-</project>\r
+    </snapshotRepository>
+    <!-- Site deployment -->
+    <site>
+      <id>website</id>
+      <url>${sitedeploy}</url>
+    </site>
+  </distributionManagement>
+  <dependencies>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-binding</artifactId>
+      <version>${yang.codegen.version}</version>
+    </dependency>
+  </dependencies>
+</project>
index 8596412..84c04e0 100644 (file)
     <sonar.jacoco.reportPath>target/code-coverage/jacoco.exec</sonar.jacoco.reportPath>
     <sonar.jacoco.itReportPath>target/code-coverage/jacoco-it.exec</sonar.jacoco.itReportPath>
     <sonar.skippedModules>org.openflow.openflowj,net.sf.jung2,org.opendaylight.controller.protobuff.messages</sonar.skippedModules>
-    <sonar.profile>Sonar way with Findbugs</sonar.profile>
     <spifly.version>1.0.0</spifly.version>
     <spring-osgi.version>1.2.1</spring-osgi.version>
     <spring-security-karaf.version>3.1.4.RELEASE</spring-security-karaf.version>
index 85f70b9..3ea432e 100644 (file)
@@ -23,6 +23,10 @@ import java.util.SortedSet;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
 import org.opendaylight.controller.config.persist.api.Persister;
 import org.opendaylight.controller.config.persist.storage.file.xml.model.ConfigSnapshot;
@@ -105,8 +109,15 @@ public class XmlDirectoryPersister implements Persister {
     public static ConfigSnapshotHolder loadLastConfig(final File file) throws JAXBException {
         JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
         Unmarshaller um = jaxbContext.createUnmarshaller();
-
-        return asHolder((ConfigSnapshot) um.unmarshal(file));
+        XMLInputFactory xif = XMLInputFactory.newFactory();
+        xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+        xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+        try {
+            XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(file));
+            return asHolder((ConfigSnapshot) um.unmarshal(xsr));
+        } catch (final XMLStreamException e) {
+            throw new JAXBException(e);
+        }
     }
 
     private static ConfigSnapshotHolder asHolder(final ConfigSnapshot unmarshalled) {
index 1bce5f2..518716c 100644 (file)
@@ -20,6 +20,10 @@ import java.util.SortedSet;
 import javax.xml.bind.JAXBContext;
 import javax.xml.bind.JAXBException;
 import javax.xml.bind.Unmarshaller;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
 import org.apache.karaf.features.ConfigFileInfo;
 import org.apache.karaf.features.Feature;
 import org.opendaylight.controller.config.persist.api.ConfigSnapshotHolder;
@@ -59,10 +63,18 @@ public class FeatureConfigSnapshotHolder implements ConfigSnapshotHolder {
         Preconditions.checkNotNull(feature);
         this.fileInfo = fileInfo;
         this.featureChain.add(feature);
+        // TODO extract utility method for umarshalling config snapshots
         JAXBContext jaxbContext = JAXBContext.newInstance(ConfigSnapshot.class);
         Unmarshaller um = jaxbContext.createUnmarshaller();
-        File file = new File(fileInfo.getFinalname());
-        unmarshalled = ((ConfigSnapshot) um.unmarshal(file));
+        XMLInputFactory xif = XMLInputFactory.newFactory();
+        xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+        xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+        try {
+            XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(new File(fileInfo.getFinalname())));
+            unmarshalled = ((ConfigSnapshot) um.unmarshal(xsr));
+        } catch (final XMLStreamException e) {
+            throw new JAXBException(e);
+        }
     }
     /*
      * (non-Javadoc)
index e629d20..6a6d360 100644 (file)
@@ -22,6 +22,10 @@ import javax.xml.bind.Unmarshaller;
 import javax.xml.bind.annotation.XmlElement;
 import javax.xml.bind.annotation.XmlElementWrapper;
 import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import javax.xml.transform.stream.StreamSource;
 import org.apache.commons.lang3.StringUtils;
 
 @XmlRootElement(name = "persisted-snapshots")
@@ -72,9 +76,12 @@ public final class Config {
         try {
             JAXBContext jaxbContext = JAXBContext.newInstance(Config.class);
             Unmarshaller um = jaxbContext.createUnmarshaller();
-
-            return (Config) um.unmarshal(from);
-        } catch (JAXBException e) {
+            XMLInputFactory xif = XMLInputFactory.newFactory();
+            xif.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false);
+            xif.setProperty(XMLInputFactory.SUPPORT_DTD, false);
+            XMLStreamReader xsr = xif.createXMLStreamReader(new StreamSource(from));
+            return ((Config) um.unmarshal(xsr));
+        } catch (JAXBException | XMLStreamException e) {
             throw new PersistException("Unable to restore configuration", e);
         }
     }
index b1c73f6..cc2e55d 100644 (file)
@@ -45,8 +45,35 @@ public class Follower extends AbstractRaftActorBehavior {
         scheduleElection(electionDuration());
     }
 
+    private boolean isLogEntryPresent(long index){
+        if(index == context.getReplicatedLog().getSnapshotIndex()){
+            return true;
+        }
+
+        ReplicatedLogEntry previousEntry = context.getReplicatedLog()
+                .get(index);
+
+        return previousEntry != null;
+
+    }
+
+    private long getLogEntryTerm(long index){
+        if(index == context.getReplicatedLog().getSnapshotIndex()){
+            return context.getReplicatedLog().getSnapshotTerm();
+        }
+
+        ReplicatedLogEntry previousEntry = context.getReplicatedLog()
+                .get(index);
+
+        if(previousEntry != null){
+            return previousEntry.getTerm();
+        }
+
+        return -1;
+    }
+
     @Override protected RaftActorBehavior handleAppendEntries(ActorRef sender,
-        AppendEntries appendEntries) {
+                                                              AppendEntries appendEntries) {
 
         if(appendEntries.getEntries() != null && appendEntries.getEntries().size() > 0) {
             if(LOG.isDebugEnabled()) {
@@ -67,15 +94,15 @@ public class Follower extends AbstractRaftActorBehavior {
         // 2. Reply false if log doesn’t contain an entry at prevLogIndex
         // whose term matches prevLogTerm (§5.3)
 
-        ReplicatedLogEntry previousEntry = context.getReplicatedLog()
-            .get(appendEntries.getPrevLogIndex());
+        long prevLogTerm = getLogEntryTerm(appendEntries.getPrevLogIndex());
+        boolean prevEntryPresent = isLogEntryPresent(appendEntries.getPrevLogIndex());
 
 
         boolean outOfSync = true;
 
         // First check if the logs are in sync or not
         if (lastIndex() == -1
-            && appendEntries.getPrevLogIndex() != -1) {
+                && appendEntries.getPrevLogIndex() != -1) {
 
             // The follower's log is out of sync because the leader does have
             // an entry at prevLogIndex and this follower has no entries in
@@ -83,34 +110,34 @@ public class Follower extends AbstractRaftActorBehavior {
 
             if(LOG.isDebugEnabled()) {
                 LOG.debug("The followers log is empty and the senders prevLogIndex is {}",
-                    appendEntries.getPrevLogIndex());
+                        appendEntries.getPrevLogIndex());
             }
 
         } else if (lastIndex() > -1
-            && appendEntries.getPrevLogIndex() != -1
-            && previousEntry == null) {
+                && appendEntries.getPrevLogIndex() != -1
+                && !prevEntryPresent) {
 
             // The follower's log is out of sync because the Leader's
             // prevLogIndex entry was not found in it's log
 
             if(LOG.isDebugEnabled()) {
                 LOG.debug("The log is not empty but the prevLogIndex {} was not found in it",
-                    appendEntries.getPrevLogIndex());
+                        appendEntries.getPrevLogIndex());
             }
 
         } else if (lastIndex() > -1
-            && previousEntry != null
-            && previousEntry.getTerm()!= appendEntries.getPrevLogTerm()) {
+                && prevEntryPresent
+                && prevLogTerm != appendEntries.getPrevLogTerm()) {
 
             // The follower's log is out of sync because the Leader's
             // prevLogIndex entry does exist in the follower's log but it has
             // a different term in it
 
-            if(LOG.isDebugEnabled()) {
+            if (LOG.isDebugEnabled()) {
                 LOG.debug(
-                    "Cannot append entries because previous entry term {}  is not equal to append entries prevLogTerm {}"
-                    , previousEntry.getTerm()
-                    , appendEntries.getPrevLogTerm());
+                        "Cannot append entries because previous entry term {}  is not equal to append entries prevLogTerm {}"
+                        , prevLogTerm
+                        , appendEntries.getPrevLogTerm());
             }
         } else {
             outOfSync = false;
@@ -120,9 +147,9 @@ public class Follower extends AbstractRaftActorBehavior {
             // We found that the log was out of sync so just send a negative
             // reply and return
             if(LOG.isDebugEnabled()) {
-                LOG.debug("Follower is out-of-sync, " +
+                LOG.debug("Follower ({}) is out-of-sync, " +
                         "so sending negative reply, lastIndex():{}, lastTerm():{}",
-                    lastIndex(), lastTerm()
+                        context.getId(), lastIndex(), lastTerm()
                 );
             }
             sender.tell(
index 0ee9693..a04d6ae 100644 (file)
@@ -421,6 +421,119 @@ public class FollowerTest extends AbstractRaftActorBehaviorTest {
         }};
     }
 
+    @Test
+    public void testHandleAppendEntriesPreviousLogEntryMissing(){
+        new JavaTestKit(getSystem()) {{
+
+            MockRaftActorContext context = (MockRaftActorContext)
+                    createActorContext();
+
+            // Prepare the receivers log
+            MockRaftActorContext.SimpleReplicatedLog log =
+                    new MockRaftActorContext.SimpleReplicatedLog();
+            log.append(
+                    new MockRaftActorContext.MockReplicatedLogEntry(1, 0, new MockRaftActorContext.MockPayload("zero")));
+            log.append(
+                    new MockRaftActorContext.MockReplicatedLogEntry(1, 1, new MockRaftActorContext.MockPayload("one")));
+            log.append(
+                    new MockRaftActorContext.MockReplicatedLogEntry(1, 2, new MockRaftActorContext.MockPayload("two")));
+
+            context.setReplicatedLog(log);
+
+            // Prepare the entries to be sent with AppendEntries
+            List<ReplicatedLogEntry> entries = new ArrayList<>();
+            entries.add(
+                    new MockRaftActorContext.MockReplicatedLogEntry(1, 4, new MockRaftActorContext.MockPayload("two-1")));
+
+            AppendEntries appendEntries =
+                    new AppendEntries(1, "leader-1", 3, 1, entries, 4);
+
+            RaftActorBehavior behavior = createBehavior(context);
+
+            // Send an unknown message so that the state of the RaftActor remains unchanged
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+
+            RaftActorBehavior raftBehavior =
+                    behavior.handleMessage(getRef(), appendEntries);
+
+            assertEquals(expected, raftBehavior);
+
+            // Also expect an AppendEntriesReply to be sent where success is false
+            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
+                    "AppendEntriesReply") {
+                // do not put code outside this method, will run afterwards
+                protected Boolean match(Object in) {
+                    if (in instanceof AppendEntriesReply) {
+                        AppendEntriesReply reply = (AppendEntriesReply) in;
+                        return reply.isSuccess();
+                    } else {
+                        throw noMatch();
+                    }
+                }
+            }.get();
+
+            assertEquals(false, out);
+
+        }};
+
+    }
+
+    @Test
+    public void testHandleAppendAfterInstallingSnapshot(){
+        new JavaTestKit(getSystem()) {{
+
+            MockRaftActorContext context = (MockRaftActorContext)
+                    createActorContext();
+
+
+            // Prepare the receivers log
+            MockRaftActorContext.SimpleReplicatedLog log =
+                    new MockRaftActorContext.SimpleReplicatedLog();
+
+            // Set up a log as if it has been snapshotted
+            log.setSnapshotIndex(3);
+            log.setSnapshotTerm(1);
+
+            context.setReplicatedLog(log);
+
+            // Prepare the entries to be sent with AppendEntries
+            List<ReplicatedLogEntry> entries = new ArrayList<>();
+            entries.add(
+                    new MockRaftActorContext.MockReplicatedLogEntry(1, 4, new MockRaftActorContext.MockPayload("two-1")));
+
+            AppendEntries appendEntries =
+                    new AppendEntries(1, "leader-1", 3, 1, entries, 4);
+
+            RaftActorBehavior behavior = createBehavior(context);
+
+            // Send an unknown message so that the state of the RaftActor remains unchanged
+            RaftActorBehavior expected = behavior.handleMessage(getRef(), "unknown");
+
+            RaftActorBehavior raftBehavior =
+                    behavior.handleMessage(getRef(), appendEntries);
+
+            assertEquals(expected, raftBehavior);
+
+            // Also expect an AppendEntriesReply to be sent where success is false
+            final Boolean out = new ExpectMsg<Boolean>(duration("1 seconds"),
+                    "AppendEntriesReply") {
+                // do not put code outside this method, will run afterwards
+                protected Boolean match(Object in) {
+                    if (in instanceof AppendEntriesReply) {
+                        AppendEntriesReply reply = (AppendEntriesReply) in;
+                        return reply.isSuccess();
+                    } else {
+                        throw noMatch();
+                    }
+                }
+            }.get();
+
+            assertEquals(true, out);
+
+        }};
+
+    }
+
 
     /**
      * This test verifies that when InstallSnapshot is received by
index 6977588..116491b 100644 (file)
@@ -13,14 +13,14 @@ import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
-
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Future;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
@@ -35,9 +35,6 @@ import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
 public class RpcInvocationStrategyTest {
 
     @Mock
@@ -68,11 +65,11 @@ public class RpcInvocationStrategyTest {
 
     public class MockRpcService implements RpcService {
 
-        public Future<?> rpcnameWithInputNoOutput(DataObject input) {
+        public Future<?> rpcnameWithInputNoOutput(final DataObject input) {
             return futureDataObj;
         }
 
-        public Future<RpcResult<DataObject>> rpcnameWithInputWithOutput(DataObject input) {
+        public Future<RpcResult<DataObject>> rpcnameWithInputWithOutput(final DataObject input) {
             return futureDataObj;
         }
 
@@ -94,7 +91,7 @@ public class RpcInvocationStrategyTest {
         urn = new URI(new String("urn:a:valid:urn"));
     }
 
-    private void setupForForwardToDom(boolean hasOutput, boolean hasInput, int expectedErrorSize) {
+    private void setupForForwardToDom(final boolean hasOutput, final boolean hasInput, final int expectedErrorSize) {
 
         if (expectedErrorSize > 0) {
             errors.add(rpcError);
@@ -117,8 +114,8 @@ public class RpcInvocationStrategyTest {
 
     }
 
-    private void validateForwardToDomBroker(ListenableFuture<RpcResult<?>> forwardToDomBroker,
-            boolean expectedSuccess, DataObject expectedResult, int expectedErrorSize)
+    private void validateForwardToDomBroker(final ListenableFuture<RpcResult<?>> forwardToDomBroker,
+            final boolean expectedSuccess, final DataObject expectedResult, final int expectedErrorSize)
             throws InterruptedException, ExecutionException {
         assertNotNull(forwardToDomBroker);
         assertEquals(expectedSuccess, forwardToDomBroker.get().isSuccessful());
@@ -126,9 +123,9 @@ public class RpcInvocationStrategyTest {
         assertEquals(expectedErrorSize, forwardToDomBroker.get().getErrors().size());
     }
 
-    private void setupTestMethod(String rpcName, String testMethodName, boolean hasInput)
+    private void setupTestMethod(final String rpcName, final String testMethodName, final boolean hasInput)
             throws NoSuchMethodException {
-        mockQName = new QName(urn, new Date(0L), new String("prefix"), new String(rpcName));
+        mockQName = QName.create(urn, new Date(0L), new String(rpcName));
         java.lang.reflect.Method rpcMethod = hasInput ? MockRpcService.class.getMethod(rpcName,
                 DataObject.class) : MockRpcService.class.getMethod(rpcName);
         rpcInvocationStrategy = new RpcInvocationStrategy(mockQName, rpcMethod, mockMappingService,
@@ -192,7 +189,7 @@ public class RpcInvocationStrategyTest {
     /*
      * invokeOn Tests
      */
-    private void setupRpcResultsWithOutput(int expectedErrorSize) {
+    private void setupRpcResultsWithOutput(final int expectedErrorSize) {
         if (expectedErrorSize > 0) {
             errors.add(rpcError);
         }
@@ -206,7 +203,7 @@ public class RpcInvocationStrategyTest {
         when(mockMappingService.toDataDom(toDataDomInput)).thenReturn(outputInvokeOn);
     }
 
-    private void setupRpcResultsNoOutput(int expectedErrorSize) {
+    private void setupRpcResultsNoOutput(final int expectedErrorSize) {
         if (expectedErrorSize > 0) {
             errors.add(rpcError);
         }
@@ -219,8 +216,8 @@ public class RpcInvocationStrategyTest {
     }
 
     private void validateReturnedImmediateFuture(
-            ListenableFuture<RpcResult<CompositeNode>> immediateFuture, boolean expectedSuccess,
-            CompositeNode expectedReturn, int expectedErrorSize) throws InterruptedException,
+            final ListenableFuture<RpcResult<CompositeNode>> immediateFuture, final boolean expectedSuccess,
+            final CompositeNode expectedReturn, final int expectedErrorSize) throws InterruptedException,
             ExecutionException {
         assertNotNull(immediateFuture);
         assertEquals(expectedSuccess, immediateFuture.get().isSuccessful());
diff --git a/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/client/messages/CompositeModificationByteStringPayload.java b/opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/raft/protobuff/client/messages/CompositeModificationByteStringPayload.java
new file mode 100644 (file)
index 0000000..99de5dd
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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.cluster.raft.protobuff.client.messages;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Preconditions;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.GeneratedMessage;
+import com.google.protobuf.InvalidProtocolBufferException;
+import com.google.protobuf.UnknownFieldSet;
+import java.io.IOException;
+import java.io.Serializable;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+import org.opendaylight.controller.protobuff.messages.cluster.raft.AppendEntriesMessages;
+import org.opendaylight.controller.protobuff.messages.persistent.PersistentMessages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class CompositeModificationByteStringPayload extends Payload implements
+        Serializable {
+    private static final long serialVersionUID = 1L;
+
+    private ByteString byteString;
+    private SoftReference<PersistentMessages.CompositeModification> modificationReference;
+    private static final Logger LOG = LoggerFactory.getLogger(CompositeModificationByteStringPayload.class);
+
+    public CompositeModificationByteStringPayload(){
+        byteString = null;
+    }
+    public CompositeModificationByteStringPayload(Object modification){
+        this(((PersistentMessages.CompositeModification) modification).toByteString());
+        this.modificationReference = new SoftReference<>((PersistentMessages.CompositeModification) modification);
+    }
+
+    private CompositeModificationByteStringPayload(ByteString byteString){
+        this.byteString = Preconditions.checkNotNull(byteString, "byteString should not be null");
+    }
+
+
+    @Override
+    public Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> encode() {
+        Preconditions.checkState(byteString!=null);
+        Map<GeneratedMessage.GeneratedExtension, PersistentMessages.CompositeModification> map = new HashMap<>();
+        map.put(org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification,
+                getModificationInternal());
+        return map;
+    }
+
+    @Override
+    public Payload decode(
+            AppendEntriesMessages.AppendEntries.ReplicatedLogEntry.Payload payload) {
+        PersistentMessages.CompositeModification modification = payload
+                .getExtension(
+                        org.opendaylight.controller.protobuff.messages.shard.CompositeModificationPayload.modification);
+
+        // The extension was put in the unknown field.
+        // This is because extensions need to be registered
+        // see org.opendaylight.controller.mdsal.CompositeModificationPayload.registerAllExtensions
+        // also see https://developers.google.com/protocol-buffers/docs/reference/java/com/google/protobuf/ExtensionRegistry
+        // If that is not done then on the other end the extension shows up as an unknown field
+        // Need to figure out a better way to do this
+        if(payload.getUnknownFields().hasField(2)){
+            UnknownFieldSet.Field field =
+                    payload.getUnknownFields().getField(2);
+
+            return new CompositeModificationByteStringPayload(field.getLengthDelimitedList().get(0));
+        }
+
+        return new CompositeModificationByteStringPayload(modification);
+    }
+
+    public Object getModification(){
+        return getModificationInternal();
+    }
+
+    private PersistentMessages.CompositeModification getModificationInternal(){
+        if(this.modificationReference != null && this.modificationReference.get() != null){
+            return this.modificationReference.get();
+        }
+        try {
+            PersistentMessages.CompositeModification compositeModification = PersistentMessages.CompositeModification.parseFrom(this.byteString);
+            this.modificationReference = new SoftReference<>(compositeModification);
+            return compositeModification;
+        } catch (InvalidProtocolBufferException e) {
+            LOG.error("Unexpected exception occurred when parsing byteString to CompositeModification", e);
+        }
+
+        return null;
+    }
+
+    public int size(){
+        return byteString.size();
+    }
+
+    private void writeObject(java.io.ObjectOutputStream stream)
+            throws IOException {
+        byteString.writeTo(stream);
+    }
+
+    private void readObject(java.io.ObjectInputStream stream)
+            throws IOException, ClassNotFoundException {
+        byteString = ByteString.readFrom(stream);
+    }
+
+    @VisibleForTesting
+    public void clearModificationReference(){
+        if(this.modificationReference != null) {
+            this.modificationReference.clear();
+        }
+    }
+}
\ No newline at end of file
index 1349e1e..0ad701b 100644 (file)
@@ -29,19 +29,15 @@ final class RandomPrefix {
     String encodeQName(final QName qname) {
         String prefix = prefixes.get(qname.getNamespace());
         if (prefix == null) {
-            prefix = qname.getPrefix();
-            if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
-                final ThreadLocalRandom random = ThreadLocalRandom.current();
-                do {
-                    final StringBuilder sb = new StringBuilder();
-                    for (int i = 0; i < 4; i++) {
-                        sb.append((char)('a' + random.nextInt(25)));
-                    }
-
-                    prefix = sb.toString();
-                } while (prefixes.containsValue(prefix));
-            }
-
+            final ThreadLocalRandom random = ThreadLocalRandom.current();
+            do {
+                final StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < 4; i++) {
+                    sb.append((char)('a' + random.nextInt(25)));
+                }
+
+                prefix = sb.toString();
+            } while (prefixes.containsValue(prefix));
             prefixes.put(qname.getNamespace(), prefix);
         }
 
index 0f93f43..c90d3e5 100644 (file)
@@ -9,6 +9,12 @@ package org.opendaylight.controller.xml.codec;
 
 import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
+import java.net.URI;
+import java.util.Map.Entry;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamWriter;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.AttributesContainer;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
@@ -29,13 +35,6 @@ import org.opendaylight.yangtools.yang.model.api.type.InstanceIdentifierTypeDefi
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.XMLStreamWriter;
-import java.net.URI;
-import java.util.Map.Entry;
-
 /**
  * Utility class for bridging JAXP Stream and YANG Data APIs. Note that the definition of this class
  * by no means final and subject to change as more functionality is centralized here.
@@ -136,15 +135,14 @@ public class XmlStreamUtils {
    */
   public void writeElement(final XMLStreamWriter writer, final @Nonnull Node<?> data, final SchemaNode schema) throws XMLStreamException {
     final QName qname = data.getNodeType();
-    final String pfx = qname.getPrefix() != null ? qname.getPrefix() : "";
     final String ns = qname.getNamespace() != null ? qname.getNamespace().toString() : "";
 
     if (isEmptyElement(data)) {
-      writer.writeEmptyElement(pfx, qname.getLocalName(), ns);
+      writer.writeEmptyElement("", qname.getLocalName(), ns);
       return;
     }
 
-    writer.writeStartElement(pfx, qname.getLocalName(), ns);
+    writer.writeStartElement("", qname.getLocalName(), ns);
     if (data instanceof AttributesContainer && ((AttributesContainer) data).getAttributes() != null) {
       for (Entry<QName, String> attribute : ((AttributesContainer) data).getAttributes().entrySet()) {
         writer.writeAttribute(attribute.getKey().getNamespace().toString(), attribute.getKey().getLocalName(), attribute.getValue());
@@ -226,15 +224,9 @@ public class XmlStreamUtils {
   private static void write(final @Nonnull XMLStreamWriter writer, final @Nonnull IdentityrefTypeDefinition type, final @Nonnull Object value) throws XMLStreamException {
     if (value instanceof QName) {
       final QName qname = (QName) value;
-      final String prefix;
-      if (qname.getPrefix() != null && !qname.getPrefix().isEmpty()) {
-        prefix = qname.getPrefix();
-      } else {
-        prefix = "x";
-      }
 
-      writer.writeNamespace(prefix, qname.getNamespace().toString());
-      writer.writeCharacters(prefix + ':' + qname.getLocalName());
+      writer.writeNamespace("x", qname.getNamespace().toString());
+      writer.writeCharacters("x:" + qname.getLocalName());
     } else {
       if(LOG.isDebugEnabled()) {
         LOG.debug("Value of {}:{} is not a QName but {}", type.getQName().getNamespace(), type.getQName().getLocalName(), value.getClass());
index a22e535..7d6dde9 100644 (file)
@@ -69,6 +69,7 @@ import org.opendaylight.controller.cluster.notifications.RoleChangeNotifier;
 import org.opendaylight.controller.cluster.raft.RaftActor;
 import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
 import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshotReply;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
@@ -321,7 +322,7 @@ public class Shard extends RaftActor {
             cohortEntry.getCohort().preCommit().get();
 
             Shard.this.persistData(getSender(), transactionID,
-                    new CompositeModificationPayload(cohortEntry.getModification().toSerializable()));
+                    new CompositeModificationByteStringPayload(cohortEntry.getModification().toSerializable()));
         } catch (InterruptedException | ExecutionException e) {
             LOG.error(e, "An exception occurred while preCommitting transaction {}",
                     cohortEntry.getTransactionID());
@@ -679,6 +680,8 @@ public class Shard extends RaftActor {
     protected void appendRecoveredLogEntry(final Payload data) {
         if (data instanceof CompositeModificationPayload) {
             currentLogRecoveryBatch.add(((CompositeModificationPayload) data).getModification());
+        } else if (data instanceof CompositeModificationByteStringPayload) {
+            currentLogRecoveryBatch.add(((CompositeModificationByteStringPayload) data).getModification());
         } else {
             LOG.error("Unknown state received {} during recovery", data);
         }
@@ -755,19 +758,12 @@ public class Shard extends RaftActor {
         if (data instanceof CompositeModificationPayload) {
             Object modification = ((CompositeModificationPayload) data).getModification();
 
-            if(modification == null) {
-                LOG.error(
-                     "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
-                     identifier, clientActor != null ? clientActor.path().toString() : null);
-            } else if(clientActor == null) {
-                // There's no clientActor to which to send a commit reply so we must be applying
-                // replicated state from the leader.
-                commitWithNewTransaction(MutableCompositeModification.fromSerializable(
-                        modification, schemaContext));
-            } else {
-                // This must be the OK to commit after replication consensus.
-                finishCommit(clientActor, identifier);
-            }
+            applyModificationToState(clientActor, identifier, modification);
+        } else if(data instanceof CompositeModificationByteStringPayload ){
+            Object modification = ((CompositeModificationByteStringPayload) data).getModification();
+
+            applyModificationToState(clientActor, identifier, modification);
+
         } else {
             LOG.error("Unknown state received {} Class loader = {} CompositeNodeMod.ClassLoader = {}",
                     data, data.getClass().getClassLoader(),
@@ -778,6 +774,22 @@ public class Shard extends RaftActor {
 
     }
 
+    private void applyModificationToState(ActorRef clientActor, String identifier, Object modification) {
+        if(modification == null) {
+            LOG.error(
+                    "modification is null - this is very unexpected, clientActor = {}, identifier = {}",
+                    identifier, clientActor != null ? clientActor.path().toString() : null);
+        } else if(clientActor == null) {
+            // There's no clientActor to which to send a commit reply so we must be applying
+            // replicated state from the leader.
+            commitWithNewTransaction(MutableCompositeModification.fromSerializable(
+                    modification, schemaContext));
+        } else {
+            // This must be the OK to commit after replication consensus.
+            finishCommit(clientActor, identifier);
+        }
+    }
+
     private void updateJournalStats() {
         ReplicatedLogEntry lastLogEntry = getLastLogEntry();
 
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationByteStringPayloadTest.java b/opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/CompositeModificationByteStringPayloadTest.java
new file mode 100644 (file)
index 0000000..db9f3d1
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * 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.cluster.datastore;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang.SerializationUtils;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.modification.Modification;
+import org.opendaylight.controller.cluster.datastore.modification.MutableCompositeModification;
+import org.opendaylight.controller.cluster.datastore.modification.WriteModification;
+import org.opendaylight.controller.cluster.raft.ReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.ReplicatedLogImplEntry;
+import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class CompositeModificationByteStringPayloadTest {
+
+    private static final SchemaContext SCHEMA_CONTEXT = TestModel.createTestContext();
+
+    @Test
+    public void testSerialization(){
+        WriteModification writeModification =
+                new WriteModification(TestModel.TEST_PATH, ImmutableNodes
+                        .containerNode(TestModel.TEST_QNAME),
+                        TestModel.createTestContext());
+
+        MutableCompositeModification compositeModification =
+                new MutableCompositeModification();
+
+        compositeModification.addModification(writeModification);
+
+        CompositeModificationByteStringPayload compositeModificationByteStringPayload
+                = new CompositeModificationByteStringPayload(compositeModification.toSerializable());
+
+        byte[] bytes = SerializationUtils.serialize(compositeModificationByteStringPayload);
+
+        Object deserialize = SerializationUtils.deserialize(bytes);
+
+        assertTrue(deserialize instanceof CompositeModificationByteStringPayload);
+
+    }
+
+    @Test
+    public void testAppendEntries(){
+        List<ReplicatedLogEntry> entries = new ArrayList<>();
+
+        CompositeModificationByteStringPayload payload = newByteStringPayload(
+                new WriteModification(TestModel.OUTER_LIST_PATH,
+                        ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
+                        SCHEMA_CONTEXT));
+
+        payload.clearModificationReference();
+
+        entries.add(new ReplicatedLogImplEntry(0, 1, payload));
+
+
+        assertNotNull(new AppendEntries(10, "foobar", 10, 10, entries, 10).toSerializable());
+    }
+
+
+
+    private CompositeModificationByteStringPayload newByteStringPayload(final Modification... mods) {
+        MutableCompositeModification compMod = new MutableCompositeModification();
+        for(Modification mod: mods) {
+            compMod.addModification(mod);
+        }
+
+        return new CompositeModificationByteStringPayload(compMod.toSerializable());
+    }
+
+}
index 926cef6..2792342 100644 (file)
@@ -75,6 +75,7 @@ import org.opendaylight.controller.cluster.raft.base.messages.CaptureSnapshot;
 import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeader;
 import org.opendaylight.controller.cluster.raft.client.messages.FindLeaderReply;
+import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationByteStringPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.CompositeModificationPayload;
 import org.opendaylight.controller.cluster.raft.protobuff.client.messages.Payload;
 import org.opendaylight.controller.md.cluster.datastore.model.SchemaContextHelper;
@@ -432,9 +433,9 @@ public class ShardTest extends AbstractActorTest {
                           ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME).build(),
                           SCHEMA_CONTEXT))));
 
-        int nListEntries = 11;
+        int nListEntries = 16;
         Set<Integer> listEntryKeys = new HashSet<>();
-        for(int i = 1; i <= nListEntries; i++) {
+        for(int i = 1; i <= nListEntries-5; i++) {
             listEntryKeys.add(Integer.valueOf(i));
             YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
                     .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build();
@@ -445,6 +446,19 @@ public class ShardTest extends AbstractActorTest {
                     newPayload(mod)));
         }
 
+        // Add some of the new CompositeModificationByteStringPayload
+        for(int i = 11; i <= nListEntries; i++) {
+            listEntryKeys.add(Integer.valueOf(i));
+            YangInstanceIdentifier path = YangInstanceIdentifier.builder(TestModel.OUTER_LIST_PATH)
+                    .nodeWithKey(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i).build();
+            Modification mod = new MergeModification(path,
+                    ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, i),
+                    SCHEMA_CONTEXT);
+            InMemoryJournal.addEntry(shardID.toString(), i, new ReplicatedLogImplEntry(i, 1,
+                    newByteStringPayload(mod)));
+        }
+
+
         InMemoryJournal.addEntry(shardID.toString(), nListEntries + 1,
                 new ApplyLogEntries(nListEntries));
 
@@ -516,6 +530,16 @@ public class ShardTest extends AbstractActorTest {
         return new CompositeModificationPayload(compMod.toSerializable());
     }
 
+    private CompositeModificationByteStringPayload newByteStringPayload(final Modification... mods) {
+        MutableCompositeModification compMod = new MutableCompositeModification();
+        for(Modification mod: mods) {
+            compMod.addModification(mod);
+        }
+
+        return new CompositeModificationByteStringPayload(compMod.toSerializable());
+    }
+
+
     private DOMStoreThreePhaseCommitCohort setupMockWriteTransaction(final String cohortName,
             final InMemoryDOMDataStore dataStore, final YangInstanceIdentifier path, final NormalizedNode<?, ?> data,
             final MutableCompositeModification modification) {
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotification.java
new file mode 100644 (file)
index 0000000..d99001e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * 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.md.sal.dom.api;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * A single YANG notification.
+ */
+public interface DOMNotification {
+    /**
+     * Return the type of this notification.
+     *
+     * @return Notification type.
+     */
+    @Nonnull SchemaPath getType();
+
+    /**
+     * Return the body of this notification.
+     *
+     * @return Notification body.
+     */
+    @Nonnull ContainerNode getBody();
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListener.java
new file mode 100644 (file)
index 0000000..7085588
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * 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.md.sal.dom.api;
+
+import java.util.EventListener;
+import javax.annotation.Nonnull;
+
+/**
+ * Interface implemented by listeners interested in {@link DOMNotification}s.
+ */
+public interface DOMNotificationListener extends EventListener {
+    /**
+     * Invoked whenever a {@link DOMNotification} matching the subscription
+     * criteria is received.
+     *
+     * @param notification Received notification
+     */
+    void onNotification(@Nonnull DOMNotification notification);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationListenerRegistration.java
new file mode 100644 (file)
index 0000000..4dccad2
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * 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.md.sal.dom.api;
+
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A registration of a {@link DOMNotificationListener}. Invoking {@link #close()} will prevent further
+ * delivery of events to the listener.
+ */
+public interface DOMNotificationListenerRegistration extends ListenerRegistration<DOMNotificationListener> {
+
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationPublishService.java
new file mode 100644 (file)
index 0000000..8a845e8
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * 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.md.sal.dom.api;
+
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnegative;
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link DOMService} which allows its user to send {@link DOMNotification}s. It
+ * provides two styles of initiating the notification delivery, similar to
+ * {@link java.util.concurrent.BlockingQueue}:
+ * - a put-style method which waits until the implementation can accept the notification
+ *   for delivery, and
+ * - an offer-style method, which attempts to enqueue the notification, but allows
+ *   the caller to specify that it should never wait, or put an upper bound on how
+ *   long it is going to wait.
+ */
+public interface DOMNotificationPublishService extends DOMService {
+    /**
+     * Well-known value indicating that the implementation is currently not
+     * able to accept a notification.
+     */
+    ListenableFuture<Object> REJECTED = Futures.immediateFailedFuture(new Throwable("Unacceptable blocking conditions encountered"));
+
+    /**
+     * Publish a notification. The result of this method is a {@link ListenableFuture}
+     * which will complete once the notification has been delivered to all immediate
+     * registrants. The type of the object resulting from the future is not defined
+     * and implementations may use it to convey additional information related to the
+     * publishing process.
+     *
+     * Abstract subclasses can refine the return type as returning a promise of a
+     * more specific type, e.g.:
+     *
+     *     public interface DeliveryStatus { int getListenerCount(); }
+     *     ListenableFuture<? extends DeliveryStatus> putNotification(DOMNotification notification);
+     *
+     * Once the Future succeeds, the resulting object can be queried for traits using
+     * instanceof, e.g:
+     *
+     *     // Can block when (for example) the implemention's ThreadPool queue is full
+     *     Object o = service.putNotification(notif).get();
+     *     if (o instanceof DeliveryStatus) {
+     *         DeliveryStatus ds = (DeliveryStatus)o;
+     *         LOG.debug("Notification was received by {} listeners", ds.getListenerCount(););
+     *     }
+     * }
+     *
+     * In case an implementation is running out of resources, it can block the calling
+     * thread until enough resources become available to accept the notification for
+     * processing, or it is interrupted.
+     *
+     * Caution: completion here means that the implementation has completed processing
+     *          of the notification. This does not mean that all existing registrants
+     *          have seen the notification. Most importantly, the delivery process at
+     *          other cluster nodes may have not begun yet.
+     *
+     * @param notification Notification to be published.
+     * @return A listenable future which will report completion when the service
+     *         has finished propagating the notification to its immediate registrants.
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if notification is null.
+     */
+    @Nonnull ListenableFuture<? extends Object> putNotification(@Nonnull DOMNotification notification) throws InterruptedException;
+
+    /**
+     * Attempt to publish a notification. The result of this method is a {@link ListenableFuture}
+     * which will complete once the notification has been delivered to all immediate
+     * registrants. The type of the object resulting from the future is not defined
+     * and implementations may use it to convey additional information related to the
+     * publishing process. Unlike {@link #putNotification(DOMNotification)}, this method
+     * is guaranteed not to block if the underlying implementation encounters contention.
+     *
+     * @param notification Notification to be published.
+     * @return A listenable future which will report completion when the service
+     *         has finished propagating the notification to its immediate registrants,
+     *         or {@value #REJECTED} if resource constraints prevent
+     *         the implementation from accepting the notification for delivery.
+     * @throws NullPointerException if notification is null.
+     */
+    @Nonnull ListenableFuture<? extends Object> offerNotification(@Nonnull DOMNotification notification);
+
+    /**
+     * Attempt to publish a notification. The result of this method is a {@link ListenableFuture}
+     * which will complete once the notification has been delivered to all immediate
+     * registrants. The type of the object resulting from the future is not defined
+     * and implementations may use it to convey additional information related to the
+     * publishing process. Unlike {@link #putNotification(DOMNotification)}, this method
+     * is guaranteed to block more than the specified timeout.
+     *
+     * @param notification Notification to be published.
+     * @param timeout how long to wait before giving up, in units of unit
+     * @param unit a TimeUnit determining how to interpret the timeout parameter
+     * @return A listenable future which will report completion when the service
+     *         has finished propagating the notification to its immediate registrants,
+     *         or {@value #REJECTED} if resource constraints prevent
+     *         the implementation from accepting the notification for delivery.
+     * @throws InterruptedException if interrupted while waiting
+     * @throws NullPointerException if notification or unit is null.
+     * @throws IllegalArgumentException if timeout is negative.
+     */
+    @Nonnull ListenableFuture<? extends Object> offerNotification(@Nonnull DOMNotification notification,
+        @Nonnegative long timeout, @Nonnull TimeUnit unit) throws InterruptedException;
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMNotificationService.java
new file mode 100644 (file)
index 0000000..6bce9c4
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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.md.sal.dom.api;
+
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * A {@link DOMService} which allows its users to subscribe to receive
+ * {@link DOMNotification}s.
+ */
+public interface DOMNotificationService {
+    /**
+     * Register a {@link DOMNotificationListener} to receive a set of notifications. As with
+     * other ListenerRegistration-based interfaces, registering an instance multiple times
+     * results in notifications being delivered for each registration.
+     *
+     * @param listener Notification instance to register
+     * @param types Notification types which should be delivered to the listener. Duplicate
+     *              entries are processed only once, null entries are ignored.
+     * @return Registration handle. Invoking {@link DOMNotificationListenerRegistration#close()}
+     *         will stop the delivery of notifications to the listener
+     * @throws IllegalArgumentException if types is empty or contains an invalid element, such as
+     *         null or a SchemaPath which does not represent a valid {@link DOMNotification} type.
+     * @throws NullPointerException if either of the arguments is null
+     */
+    DOMNotificationListenerRegistration registerNotificationListener(@Nonnull DOMNotificationListener listener, @Nonnull Collection<SchemaPath> types);
+
+    /**
+     * Register a {@link DOMNotificationListener} to receive a set of notifications. As with
+     * other ListenerRegistration-based interfaces, registering an instance multiple times
+     * results in notifications being delivered for each registration.
+     *
+     * @param listener Notification instance to register
+     * @param types Notification types which should be delivered to the listener. Duplicate
+     *              entries are processed only once, null entries are ignored.
+     * @return Registration handle. Invoking {@link DOMNotificationListenerRegistration#close()}
+     *         will stop the delivery of notifications to the listener
+     * @throws IllegalArgumentException if types is empty or contains an invalid element, such as
+     *         null or a SchemaPath which does not represent a valid {@link DOMNotification} type.
+     * @throws NullPointerException if listener is null
+     */
+    // FIXME: Java 8: provide a default implementation of this method.
+    DOMNotificationListenerRegistration registerNotificationListener(@Nonnull DOMNotificationListener listener, SchemaPath... types);
+}
index 357cb8b..dc18394 100644 (file)
@@ -5,9 +5,12 @@
  * 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.md.sal.dom.api;
 
+/**
+ * Marker interface for services which can be obtained from a {@link DOMMountPoint}
+ * instance. No further semantics are implied.
+ */
 public interface DOMService {
 
 }
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMNotificationListenerRegistration.java
new file mode 100644 (file)
index 0000000..2934b0d
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.md.sal.dom.spi;
+
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListenerRegistration;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+
+/**
+ * Utility base class for {@link DOMNotificationListenerRegistration}
+ * implementations.
+ */
+public abstract class AbstractDOMNotificationListenerRegistration extends AbstractListenerRegistration<DOMNotificationListener> implements DOMNotificationListenerRegistration {
+    /**
+     * Default constructor. Subclasses need to invoke it from their
+     * constructor(s).
+     *
+     * @param listener {@link DOMNotificationListener} instance which is
+     *                 being held by this registration. May not be null.
+     */
+    protected AbstractDOMNotificationListenerRegistration(final @Nonnull DOMNotificationListener listener) {
+        super(listener);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationPublishService.java
new file mode 100644 (file)
index 0000000..6bc1107
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.md.sal.dom.spi;
+
+import com.google.common.collect.ForwardingObject;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.concurrent.TimeUnit;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotification;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService;
+
+/**
+ * Utility implementations of {@link DOMNotificationPublishService} which forwards
+ * all requests to a delegate instance.
+ */
+public abstract class ForwardingDOMNotificationPublishService extends ForwardingObject implements DOMNotificationPublishService {
+    @Override
+    protected abstract DOMNotificationPublishService delegate();
+
+    @Override
+    public ListenableFuture<? extends Object> putNotification(final DOMNotification notification) throws InterruptedException {
+        return delegate().putNotification(notification);
+    }
+
+    @Override
+    public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification) {
+        return delegate().offerNotification(notification);
+    }
+
+    @Override
+    public ListenableFuture<? extends Object> offerNotification(final DOMNotification notification, final long timeout,
+            final TimeUnit unit) throws InterruptedException {
+        return delegate().offerNotification(notification, timeout, unit);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMNotificationService.java
new file mode 100644 (file)
index 0000000..5199a38
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.md.sal.dom.spi;
+
+import com.google.common.collect.ForwardingObject;
+import java.util.Collection;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationListenerRegistration;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Utility implementation of a {@link DOMNotificationService} which forwards all requests
+ * to a delegate instance.
+ */
+public abstract class ForwardingDOMNotificationService extends ForwardingObject implements DOMNotificationService {
+    @Override
+    protected abstract DOMNotificationService delegate();
+
+    @Override
+    public DOMNotificationListenerRegistration registerNotificationListener(final DOMNotificationListener listener,
+            final Collection<SchemaPath> types) {
+        return delegate().registerNotificationListener(listener, types);
+    }
+
+    @Override
+    public DOMNotificationListenerRegistration registerNotificationListener(final DOMNotificationListener listener,
+            final SchemaPath... types) {
+        return delegate().registerNotificationListener(listener, types);
+    }
+}
index 7890931..b5a2b42 100644 (file)
@@ -34,25 +34,25 @@ public final class RestUtil {
     }
 
     public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
-        String valueTrimmed = value.trim();
+        final String valueTrimmed = value.trim();
         if (!valueTrimmed.startsWith("/")) {
             return null;
         }
-        String[] xPathParts = valueTrimmed.split("/");
+        final String[] xPathParts = valueTrimmed.split("/");
         if (xPathParts.length < 2) { // must be at least "/pr:node"
             return null;
         }
-        IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
+        final IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO(value);
         for (int i = 1; i < xPathParts.length; i++) {
-            String xPathPartTrimmed = xPathParts[i].trim();
+            final String xPathPartTrimmed = xPathParts[i].trim();
 
-            String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
-            IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
+            final String xPathPartStr = getIdAndPrefixAsStr(xPathPartTrimmed);
+            final IdentityValue identityValue = toIdentity(xPathPartStr, prefixMap);
             if (identityValue == null) {
                 return null;
             }
 
-            List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
+            final List<Predicate> predicates = toPredicates(xPathPartTrimmed, prefixMap);
             if (predicates == null) {
                 return null;
             }
@@ -64,47 +64,47 @@ public final class RestUtil {
     }
 
     private static String getIdAndPrefixAsStr(final String pathPart) {
-        int predicateStartIndex = pathPart.indexOf("[");
+        final int predicateStartIndex = pathPart.indexOf("[");
         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
     }
 
     private static IdentityValue toIdentity(final String xPathPart, final PrefixesMaping prefixMap) {
-        String xPathPartTrimmed = xPathPart.trim();
+        final String xPathPartTrimmed = xPathPart.trim();
         if (xPathPartTrimmed.isEmpty()) {
             return null;
         }
-        String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
+        final String[] prefixAndIdentifier = xPathPartTrimmed.split(":");
         // it is not "prefix:value"
         if (prefixAndIdentifier.length != 2) {
             return null;
         }
-        String prefix = prefixAndIdentifier[0].trim();
-        String identifier = prefixAndIdentifier[1].trim();
+        final String prefix = prefixAndIdentifier[0].trim();
+        final String identifier = prefixAndIdentifier[1].trim();
         if (prefix.isEmpty() || identifier.isEmpty()) {
             return null;
         }
-        String namespace = prefixMap.getNamespace(prefix);
-        return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix);
+        final String namespace = prefixMap.getNamespace(prefix);
+        return new IdentityValue(namespace, identifier);
     }
 
     private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
-        List<Predicate> result = new ArrayList<>();
-        List<String> predicates = new ArrayList<>();
-        Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
+        final List<Predicate> result = new ArrayList<>();
+        final List<String> predicates = new ArrayList<>();
+        final Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
         while (matcher.find()) {
             predicates.add(matcher.group(1).trim());
         }
-        for (String predicate : predicates) {
-            int indexOfEqualityMark = predicate.indexOf("=");
+        for (final String predicate : predicates) {
+            final int indexOfEqualityMark = predicate.indexOf("=");
             if (indexOfEqualityMark != -1) {
-                String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
+                final String predicateValue = toPredicateValue(predicate.substring(indexOfEqualityMark + 1));
                 if (predicate.startsWith(".")) { // it is leaf-list
                     if (predicateValue == null) {
                         return null;
                     }
                     result.add(new Predicate(null, predicateValue));
                 } else {
-                    IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
+                    final IdentityValue identityValue = toIdentity(predicate.substring(0, indexOfEqualityMark), prefixMap);
                     if (identityValue == null || predicateValue == null) {
                         return null;
                     }
@@ -116,7 +116,7 @@ public final class RestUtil {
     }
 
     private static String toPredicateValue(final String predicatedValue) {
-        String predicatedValueTrimmed = predicatedValue.trim();
+        final String predicatedValueTrimmed = predicatedValue.trim();
         if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
                 && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
             return predicatedValueTrimmed.substring(1, predicatedValueTrimmed.length() - 1);
index 4e797d9..2488308 100644 (file)
@@ -16,12 +16,12 @@ public final class IdentityValuesDTO {
     private final List<IdentityValue> elementData = new ArrayList<>();
     private final String originValue;
 
-    public IdentityValuesDTO(String namespace, String value, String prefix, String originValue) {
-        elementData.add(new IdentityValue(namespace, value, prefix));
+    public IdentityValuesDTO(final String namespace, final String value, final String prefix, final String originValue) {
+        elementData.add(new IdentityValue(namespace, value));
         this.originValue = originValue;
     }
 
-    public IdentityValuesDTO(String originValue) {
+    public IdentityValuesDTO(final String originValue) {
         this.originValue = originValue;
     }
 
@@ -29,11 +29,11 @@ public final class IdentityValuesDTO {
         originValue = null;
     }
 
-    public void add(String namespace, String value, String prefix) {
-        elementData.add(new IdentityValue(namespace, value, prefix));
+    public void add(final String namespace, final String value, final String prefix) {
+        elementData.add(new IdentityValue(namespace, value));
     }
 
-    public void add(IdentityValue identityValue) {
+    public void add(final IdentityValue identityValue) {
         elementData.add(identityValue);
     }
 
@@ -54,13 +54,11 @@ public final class IdentityValuesDTO {
 
         private final String namespace;
         private final String value;
-        private final String prefix;
         private List<Predicate> predicates;
 
-        public IdentityValue(String namespace, String value, String prefix) {
+        public IdentityValue(final String namespace, final String value) {
             this.namespace = namespace;
             this.value = value;
-            this.prefix = prefix;
         }
 
         public String getNamespace() {
@@ -71,9 +69,6 @@ public final class IdentityValuesDTO {
             return value;
         }
 
-        public String getPrefix() {
-            return prefix;
-        }
 
         public List<Predicate> getPredicates() {
             if (predicates == null) {
@@ -82,24 +77,21 @@ public final class IdentityValuesDTO {
             return Collections.unmodifiableList(predicates);
         }
 
-        public void setPredicates(List<Predicate> predicates) {
+        public void setPredicates(final List<Predicate> predicates) {
             this.predicates = predicates;
         }
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder();
+            final StringBuilder sb = new StringBuilder();
             if (namespace != null) {
                 sb.append(namespace);
             }
-            if (prefix != null) {
-                sb.append("(").append(prefix).append(")");
-            }
             if (value != null) {
                 sb.append(" - ").append(value);
             }
             if (predicates != null && !predicates.isEmpty()) {
-                for (Predicate predicate : predicates) {
+                for (final Predicate predicate : predicates) {
                     sb.append("[");
                     predicate.toString();
                     sb.append("]");
@@ -115,7 +107,7 @@ public final class IdentityValuesDTO {
         private final IdentityValue name;
         private final String value;
 
-        public Predicate(IdentityValue name, String value) {
+        public Predicate(final IdentityValue name, final String value) {
             super();
             this.name = name;
             this.value = value;
@@ -131,7 +123,7 @@ public final class IdentityValuesDTO {
 
         @Override
         public String toString() {
-            StringBuilder sb = new StringBuilder();
+            final StringBuilder sb = new StringBuilder();
             if (name != null) {
                 sb.append(name.toString());
             }
index ceac03e..763d1c6 100644 (file)
@@ -97,7 +97,7 @@ public class RestCodec {
                             input == null ? "null" : input.getClass(), String.valueOf(input));
                     return null;
                 } else {
-                    TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
+                    final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
                             .from(type);
                     if (typeAwarecodec != null) {
                         if (input instanceof IdentityValuesDTO) {
@@ -110,7 +110,7 @@ public class RestCodec {
                         return null;
                     }
                 }
-            } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
+            } catch (final ClassCastException e) { // TODO remove this catch when everyone use codecs
                 logger.error(
                         "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
                         e);
@@ -129,7 +129,7 @@ public class RestCodec {
                 } else if (type instanceof InstanceIdentifierTypeDefinition) {
                     return instanceIdentifier.serialize(input);
                 } else {
-                    TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
+                    final TypeDefinitionAwareCodec<Object, ? extends TypeDefinition<?>> typeAwarecodec = TypeDefinitionAwareCodec
                             .from(type);
                     if (typeAwarecodec != null) {
                         return typeAwarecodec.serialize(input);
@@ -139,7 +139,7 @@ public class RestCodec {
                         return null;
                     }
                 }
-            } catch (ClassCastException e) { // TODO remove this catch when everyone use codecs
+            } catch (final ClassCastException e) { // TODO remove this catch when everyone use codecs
                 logger.error(
                         "ClassCastException was thrown when codec is invoked with parameter " + String.valueOf(input),
                         e);
@@ -161,13 +161,13 @@ public class RestCodec {
 
         @Override
         public IdentityValuesDTO serialize(final QName data) {
-            return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), data.getPrefix(), null);
+            return new IdentityValuesDTO(data.getNamespace().toString(), data.getLocalName(), null, null);
         }
 
         @Override
         public QName deserialize(final IdentityValuesDTO data) {
-            IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
-            Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
+            final IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+            final Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
             if (module == null) {
                 logger.info("Module was not found for namespace {}", valueWithNamespace.getNamespace());
                 logger.info("Idenetityref will be translated as NULL for data - {}", String.valueOf(valueWithNamespace));
@@ -203,16 +203,16 @@ public class RestCodec {
 
         @Override
         public IdentityValuesDTO serialize(final YangInstanceIdentifier data) {
-            IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
-            for (PathArgument pathArgument : data.getPathArguments()) {
-                IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
+            final IdentityValuesDTO identityValuesDTO = new IdentityValuesDTO();
+            for (final PathArgument pathArgument : data.getPathArguments()) {
+                final IdentityValue identityValue = qNameToIdentityValue(pathArgument.getNodeType());
                 if (pathArgument instanceof NodeIdentifierWithPredicates && identityValue != null) {
-                    List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
+                    final List<Predicate> predicates = keyValuesToPredicateList(((NodeIdentifierWithPredicates) pathArgument)
                             .getKeyValues());
                     identityValue.setPredicates(predicates);
                 } else if (pathArgument instanceof NodeWithValue && identityValue != null) {
-                    List<Predicate> predicates = new ArrayList<>();
-                    String value = String.valueOf(((NodeWithValue) pathArgument).getValue());
+                    final List<Predicate> predicates = new ArrayList<>();
+                    final String value = String.valueOf(((NodeWithValue) pathArgument).getValue());
                     predicates.add(new Predicate(null, value));
                     identityValue.setPredicates(predicates);
                 }
@@ -223,9 +223,9 @@ public class RestCodec {
 
         @Override
         public YangInstanceIdentifier deserialize(final IdentityValuesDTO data) {
-            List<PathArgument> result = new ArrayList<PathArgument>();
-            IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
-            Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
+            final List<PathArgument> result = new ArrayList<PathArgument>();
+            final IdentityValue valueWithNamespace = data.getValuesWithNamespaces().get(0);
+            final Module module = getModuleByNamespace(valueWithNamespace.getNamespace(), mountPoint);
             if (module == null) {
                 logger.info("Module by namespace '{}' of first node in instance-identifier was not found.",
                         valueWithNamespace.getNamespace());
@@ -235,11 +235,11 @@ public class RestCodec {
             }
 
             DataNodeContainer parentContainer = module;
-            List<IdentityValue> identities = data.getValuesWithNamespaces();
+            final List<IdentityValue> identities = data.getValuesWithNamespaces();
             for (int i = 0; i < identities.size(); i++) {
-                IdentityValue identityValue = identities.get(i);
+                final IdentityValue identityValue = identities.get(i);
                 URI validNamespace = resolveValidNamespace(identityValue.getNamespace(), mountPoint);
-                DataSchemaNode node = ControllerContext.findInstanceDataChildByNameAndNamespace(
+                final DataSchemaNode node = ControllerContext.findInstanceDataChildByNameAndNamespace(
                         parentContainer, identityValue.getValue(), validNamespace);
                 if (node == null) {
                     logger.info("'{}' node was not found in {}", identityValue, parentContainer.getChildNodes());
@@ -247,13 +247,13 @@ public class RestCodec {
                             String.valueOf(identityValue.getValue()));
                     return null;
                 }
-                QName qName = node.getQName();
+                final QName qName = node.getQName();
                 PathArgument pathArgument = null;
                 if (identityValue.getPredicates().isEmpty()) {
                     pathArgument = new NodeIdentifier(qName);
                 } else {
                     if (node instanceof LeafListSchemaNode) { // predicate is value of leaf-list entry
-                        Predicate leafListPredicate = identityValue.getPredicates().get(0);
+                        final Predicate leafListPredicate = identityValue.getPredicates().get(0);
                         if (!leafListPredicate.isLeafList()) {
                             logger.info("Predicate's data is not type of leaf-list. It should be in format \".='value'\"");
                             logger.info("Instance-identifier will be translated as NULL for data - {}",
@@ -262,11 +262,11 @@ public class RestCodec {
                         }
                         pathArgument = new NodeWithValue(qName, leafListPredicate.getValue());
                     } else if (node instanceof ListSchemaNode) { // predicates are keys of list
-                        DataNodeContainer listNode = (DataNodeContainer) node;
-                        Map<QName, Object> predicatesMap = new HashMap<>();
-                        for (Predicate predicate : identityValue.getPredicates()) {
+                        final DataNodeContainer listNode = (DataNodeContainer) node;
+                        final Map<QName, Object> predicatesMap = new HashMap<>();
+                        for (final Predicate predicate : identityValue.getPredicates()) {
                             validNamespace = resolveValidNamespace(predicate.getName().getNamespace(), mountPoint);
-                            DataSchemaNode listKey = ControllerContext
+                            final DataSchemaNode listKey = ControllerContext
                                     .findInstanceDataChildByNameAndNamespace(listNode, predicate.getName().getValue(),
                                             validNamespace);
                             predicatesMap.put(listKey.getQName(), predicate.getValue());
@@ -297,9 +297,9 @@ public class RestCodec {
         }
 
         private List<Predicate> keyValuesToPredicateList(final Map<QName, Object> keyValues) {
-            List<Predicate> result = new ArrayList<>();
-            for (QName qName : keyValues.keySet()) {
-                Object value = keyValues.get(qName);
+            final List<Predicate> result = new ArrayList<>();
+            for (final QName qName : keyValues.keySet()) {
+                final Object value = keyValues.get(qName);
                 result.add(new Predicate(qNameToIdentityValue(qName), String.valueOf(value)));
             }
             return result;
@@ -307,14 +307,14 @@ public class RestCodec {
 
         private IdentityValue qNameToIdentityValue(final QName qName) {
             if (qName != null) {
-                return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName(), qName.getPrefix());
+                return new IdentityValue(qName.getNamespace().toString(), qName.getLocalName());
             }
             return null;
         }
     }
 
     private static Module getModuleByNamespace(final String namespace, final DOMMountPoint mountPoint) {
-        URI validNamespace = resolveValidNamespace(namespace, mountPoint);
+        final URI validNamespace = resolveValidNamespace(namespace, mountPoint);
 
         Module module = null;
         if (mountPoint != null) {
index a6e0263..8481a9f 100644 (file)
@@ -96,13 +96,13 @@ public class ListenerAdapter implements DOMDataChangeListener {
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+    public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
         // TODO Auto-generated method stub
 
         if (!change.getCreatedData().isEmpty() || !change.getUpdatedData().isEmpty()
                 || !change.getRemovedPaths().isEmpty()) {
-            String xml = prepareXmlFrom(change);
-            Event event = new Event(EventType.NOTIFY);
+            final String xml = prepareXmlFrom(change);
+            final Event event = new Event(EventType.NOTIFY);
             event.setData(xml);
             eventBus.post(event);
         }
@@ -115,7 +115,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
         @Subscribe
         public void recordCustomerChange(final Event event) {
             if (event.getType() == EventType.REGISTER) {
-                Channel subscriber = event.getSubscriber();
+                final Channel subscriber = event.getSubscriber();
                 if (!subscribers.contains(subscriber)) {
                     subscribers.add(subscriber);
                 }
@@ -123,7 +123,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
                 subscribers.remove(event.getSubscriber());
                 Notificator.removeListenerIfNoSubscriberExists(ListenerAdapter.this);
             } else if (event.getType() == EventType.NOTIFY) {
-                for (Channel subscriber : subscribers) {
+                for (final Channel subscriber : subscribers) {
                     if (subscriber.isActive()) {
                         LOG.debug("Data are sent to subscriber {}:", subscriber.remoteAddress());
                         subscriber.writeAndFlush(new TextWebSocketFrame(event.getData()));
@@ -218,34 +218,34 @@ public class ListenerAdapter implements DOMDataChangeListener {
      *            DataChangeEvent
      * @return Data in printable form.
      */
-    private String prepareXmlFrom(AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
-        Document doc = createDocument();
-        Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0",
+    private String prepareXmlFrom(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+        final Document doc = createDocument();
+        final Element notificationElement = doc.createElementNS("urn:ietf:params:xml:ns:netconf:notification:1.0",
                 "notification");
         doc.appendChild(notificationElement);
 
-        Element eventTimeElement = doc.createElement("eventTime");
+        final Element eventTimeElement = doc.createElement("eventTime");
         eventTimeElement.setTextContent(toRFC3339(new Date()));
         notificationElement.appendChild(eventTimeElement);
 
-        Element dataChangedNotificationEventElement = doc.createElementNS(
+        final Element dataChangedNotificationEventElement = doc.createElementNS(
                 "urn:opendaylight:params:xml:ns:yang:controller:md:sal:remote", "data-changed-notification");
         addValuesToDataChangedNotificationEventElement(doc, dataChangedNotificationEventElement, change);
         notificationElement.appendChild(dataChangedNotificationEventElement);
 
         try {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            Transformer transformer = FACTORY.newTransformer();
+            final ByteArrayOutputStream out = new ByteArrayOutputStream();
+            final Transformer transformer = FACTORY.newTransformer();
             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
             transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, Charsets.UTF_8)));
-            byte[] charData = out.toByteArray();
+            final byte[] charData = out.toByteArray();
             return new String(charData, "UTF-8");
         } catch (TransformerException | UnsupportedEncodingException e) {
-            String msg = "Error during transformation of Document into String";
+            final String msg = "Error during transformation of Document into String";
             LOG.error(msg, e);
             return msg;
         }
@@ -270,7 +270,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
         final DocumentBuilder bob;
         try {
             bob = DBF.newDocumentBuilder();
-        } catch (ParserConfigurationException e) {
+        } catch (final ParserConfigurationException e) {
             return null;
         }
         return bob.newDocument();
@@ -288,7 +288,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
      */
     private void addValuesToDataChangedNotificationEventElement(final Document doc,
             final Element dataChangedNotificationEventElement,
-            AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+            final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
         addValuesFromDataToElement(doc, change.getCreatedData().keySet(), dataChangedNotificationEventElement,
                 Operation.CREATED);
         if (change.getCreatedData().isEmpty()) {
@@ -313,13 +313,13 @@ public class ListenerAdapter implements DOMDataChangeListener {
      * @param operation
      *            {@link Operation}
      */
-    private void addValuesFromDataToElement(Document doc, Set<YangInstanceIdentifier> data, Element element,
-            Operation operation) {
+    private void addValuesFromDataToElement(final Document doc, final Set<YangInstanceIdentifier> data, final Element element,
+            final Operation operation) {
         if (data == null || data.isEmpty()) {
             return;
         }
-        for (YangInstanceIdentifier path : data) {
-            Node node = createDataChangeEventElement(doc, path, null, operation);
+        for (final YangInstanceIdentifier path : data) {
+            final Node node = createDataChangeEventElement(doc, path, null, operation);
             element.appendChild(node);
         }
     }
@@ -338,13 +338,13 @@ public class ListenerAdapter implements DOMDataChangeListener {
      * @param operation
      *            {@link Operation}
      */
-    private void addValuesFromDataToElement(Document doc, Map<YangInstanceIdentifier, CompositeNode> data, Element element,
-            Operation operation) {
+    private void addValuesFromDataToElement(final Document doc, final Map<YangInstanceIdentifier, CompositeNode> data, final Element element,
+            final Operation operation) {
         if (data == null || data.isEmpty()) {
             return;
         }
-        for (Entry<YangInstanceIdentifier, CompositeNode> entry : data.entrySet()) {
-            Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), operation);
+        for (final Entry<YangInstanceIdentifier, CompositeNode> entry : data.entrySet()) {
+            final Node node = createDataChangeEventElement(doc, entry.getKey(), entry.getValue(), operation);
             element.appendChild(node);
         }
     }
@@ -364,11 +364,10 @@ public class ListenerAdapter implements DOMDataChangeListener {
      *            {@link Operation}
      * @return {@link Node} node represented by changed event element.
      */
-    private Node createDataChangeEventElement(Document doc, YangInstanceIdentifier path, CompositeNode data,
-            Operation operation) {
-        Element dataChangeEventElement = doc.createElement("data-change-event");
-
-        Element pathElement = doc.createElement("path");
+    private Node createDataChangeEventElement(final Document doc, final YangInstanceIdentifier path, final CompositeNode data,
+            final Operation operation) {
+        final Element dataChangeEventElement = doc.createElement("data-change-event");
+        final Element pathElement = doc.createElement("path");
         addPathAsValueToElement(path, pathElement);
         dataChangeEventElement.appendChild(pathElement);
 
@@ -376,14 +375,14 @@ public class ListenerAdapter implements DOMDataChangeListener {
         // storeElement.setTextContent(store.value);
         // dataChangeEventElement.appendChild(storeElement);
 
-        Element operationElement = doc.createElement("operation");
+        final Element operationElement = doc.createElement("operation");
         operationElement.setTextContent(operation.value);
         dataChangeEventElement.appendChild(operationElement);
 
         if (data != null) {
-            Element dataElement = doc.createElement("data");
-            Node dataAnyXml = translateToXml(path, data);
-            Node adoptedNode = doc.adoptNode(dataAnyXml);
+            final Element dataElement = doc.createElement("data");
+            final Node dataAnyXml = translateToXml(path, data);
+            final Node adoptedNode = doc.adoptNode(dataAnyXml);
             dataElement.appendChild(adoptedNode);
             dataChangeEventElement.appendChild(dataElement);
         }
@@ -401,7 +400,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
      * @return Data in XML format.
      */
     private Node translateToXml(final YangInstanceIdentifier path, final CompositeNode data) {
-        DataNodeContainer schemaNode = ControllerContext.getInstance().getDataNodeContainerFor(path);
+        final DataNodeContainer schemaNode = ControllerContext.getInstance().getDataNodeContainerFor(path);
         if (schemaNode == null) {
             LOG.info(
                     "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.",
@@ -409,9 +408,9 @@ public class ListenerAdapter implements DOMDataChangeListener {
             return null;
         }
         try {
-            Document xml = xmlMapper.write(data, schemaNode);
+            final Document xml = xmlMapper.write(data, schemaNode);
             return xml.getFirstChild();
-        } catch (UnsupportedDataTypeException e) {
+        } catch (final UnsupportedDataTypeException e) {
             LOG.error("Error occured during translation of notification to XML.", e);
             return null;
         }
@@ -427,18 +426,18 @@ public class ListenerAdapter implements DOMDataChangeListener {
      */
     private void addPathAsValueToElement(final YangInstanceIdentifier path, final Element element) {
         // Map< key = namespace, value = prefix>
-        Map<String, String> prefixes = new HashMap<>();
-        YangInstanceIdentifier instanceIdentifier = path;
-        StringBuilder textContent = new StringBuilder();
+        final Map<String, String> prefixes = new HashMap<>();
+        final YangInstanceIdentifier instanceIdentifier = path;
+        final StringBuilder textContent = new StringBuilder();
 
         // FIXME: BUG-1281: this is duplicated code from yangtools (BUG-1275)
-        for (PathArgument pathArgument : instanceIdentifier.getPathArguments()) {
+        for (final PathArgument pathArgument : instanceIdentifier.getPathArguments()) {
             textContent.append("/");
             writeIdentifierWithNamespacePrefix(element, textContent, pathArgument.getNodeType(), prefixes);
             if (pathArgument instanceof NodeIdentifierWithPredicates) {
-                Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
-                for (QName keyValue : predicates.keySet()) {
-                    String predicateValue = String.valueOf(predicates.get(keyValue));
+                final Map<QName, Object> predicates = ((NodeIdentifierWithPredicates) pathArgument).getKeyValues();
+                for (final QName keyValue : predicates.keySet()) {
+                    final String predicateValue = String.valueOf(predicates.get(keyValue));
                     textContent.append("[");
                     writeIdentifierWithNamespacePrefix(element, textContent, keyValue, prefixes);
                     textContent.append("='");
@@ -470,13 +469,10 @@ public class ListenerAdapter implements DOMDataChangeListener {
      */
     private static void writeIdentifierWithNamespacePrefix(final Element element, final StringBuilder textContent,
             final QName qName, final Map<String, String> prefixes) {
-        String namespace = qName.getNamespace().toString();
+        final String namespace = qName.getNamespace().toString();
         String prefix = prefixes.get(namespace);
         if (prefix == null) {
-            prefix = qName.getPrefix();
-            if (prefix == null || prefix.isEmpty() || prefixes.containsValue(prefix)) {
-                prefix = generateNewPrefix(prefixes.values());
-            }
+            prefix = generateNewPrefix(prefixes.values());
         }
 
         element.setAttribute("xmlns:" + prefix, namespace);
@@ -496,11 +492,11 @@ public class ListenerAdapter implements DOMDataChangeListener {
      */
     private static String generateNewPrefix(final Collection<String> prefixes) {
         StringBuilder result = null;
-        Random random = new Random();
+        final Random random = new Random();
         do {
             result = new StringBuilder();
             for (int i = 0; i < 4; i++) {
-                int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
+                final int randomNumber = 0x61 + (Math.abs(random.nextInt()) % 26);
                 result.append(Character.toChars(randomNumber));
             }
         } while (prefixes.contains(result.toString()));
@@ -566,7 +562,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
         if (!subscriber.isActive()) {
             LOG.debug("Channel is not active between websocket server and subscriber {}" + subscriber.remoteAddress());
         }
-        Event event = new Event(EventType.REGISTER);
+        final Event event = new Event(EventType.REGISTER);
         event.setSubscriber(subscriber);
         eventBus.post(event);
     }
@@ -579,7 +575,7 @@ public class ListenerAdapter implements DOMDataChangeListener {
      */
     public void removeSubscriber(final Channel subscriber) {
         LOG.debug("Subscriber {} is removed.", subscriber.remoteAddress());
-        Event event = new Event(EventType.DEREGISTER);
+        final Event event = new Event(EventType.DEREGISTER);
         event.setSubscriber(subscriber);
         eventBus.post(event);
     }
index 3d5fee3..4232c83 100644 (file)
@@ -70,7 +70,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
     @Test
     public void snAsYangIdentityrefWithQNamePrefixToXMLTest() {
         serializeToXml(prepareIdentityrefData("prefix", true),
-                "<lf11 xmlns:prefix=\"referenced:module\">prefix:iden</lf11>");
+                "<lf11 xmlns","=\"referenced:module\">",":iden</lf11>");
     }
 
     @Test
@@ -93,7 +93,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangInt8ToXmlTest() {
-        String elName = "lfInt8";
+        final String elName = "lfInt8";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int8.getInstance()).deserialize("14"), elName),
                 "<" + elName + ">14</" + elName + ">");
@@ -101,7 +101,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangInt16ToXmlTest() {
-        String elName = "lfInt16";
+        final String elName = "lfInt16";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int16.getInstance()).deserialize("3000"),
                         elName), "<" + elName + ">3000</" + elName + ">");
@@ -109,7 +109,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangInt32ToXmlTest() {
-        String elName = "lfInt32";
+        final String elName = "lfInt32";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Int32.getInstance()).deserialize("201234"),
                         elName), "<" + elName + ">201234</" + elName + ">");
@@ -117,7 +117,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangInt64ToXmlTest() {
-        String elName = "lfInt64";
+        final String elName = "lfInt64";
         serializeToXml(
                 prepareCnStructForYangData(
                         TypeDefinitionAwareCodec.from(Int64.getInstance()).deserialize("5123456789"), elName), "<"
@@ -126,7 +126,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangUint8ToXmlTest() {
-        String elName = "lfUint8";
+        final String elName = "lfUint8";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint8.getInstance()).deserialize("200"),
                         elName), "<" + elName + ">200</" + elName + ">");
@@ -134,7 +134,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangUint16ToXmlTest() {
-        String elName = "lfUint16";
+        final String elName = "lfUint16";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint16.getInstance()).deserialize("4000"),
                         elName), "<" + elName + ">4000</" + elName + ">");
@@ -142,7 +142,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangUint32ToXmlTest() {
-        String elName = "lfUint32";
+        final String elName = "lfUint32";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint32.getInstance())
                         .deserialize("4123456789"), elName), "<" + elName + ">4123456789</" + elName + ">");
@@ -150,7 +150,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangUint64ToXmlTest() {
-        String elName = "lfUint64";
+        final String elName = "lfUint64";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(Uint64.getInstance())
                         .deserialize("5123456789"), elName), "<" + elName + ">5123456789</" + elName + ">");
@@ -158,7 +158,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangBinaryToXmlTest() {
-        String elName = "lfBinary";
+        final String elName = "lfBinary";
         serializeToXml(
                 prepareCnStructForYangData(
                         TypeDefinitionAwareCodec.from(BinaryType.getInstance()).deserialize(
@@ -168,13 +168,13 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangBitsToXmlTest() {
-        BitsTypeDefinition.Bit mockBit1 = mock(BitsTypeDefinition.Bit.class);
+        final BitsTypeDefinition.Bit mockBit1 = mock(BitsTypeDefinition.Bit.class);
         when(mockBit1.getName()).thenReturn("one");
-        BitsTypeDefinition.Bit mockBit2 = mock(BitsTypeDefinition.Bit.class);
+        final BitsTypeDefinition.Bit mockBit2 = mock(BitsTypeDefinition.Bit.class);
         when(mockBit2.getName()).thenReturn("two");
-        List<BitsTypeDefinition.Bit> bitList = Lists.newArrayList(mockBit1, mockBit2);
+        final List<BitsTypeDefinition.Bit> bitList = Lists.newArrayList(mockBit1, mockBit2);
 
-        String elName = "lfBits";
+        final String elName = "lfBits";
         serializeToXml(
                 prepareCnStructForYangData(
                         TypeDefinitionAwareCodec.from(BitsType.create(mock(SchemaPath.class), bitList)).deserialize(
@@ -184,11 +184,11 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangEnumerationToXmlTest() {
-        EnumTypeDefinition.EnumPair mockEnum = mock(EnumTypeDefinition.EnumPair.class);
+        final EnumTypeDefinition.EnumPair mockEnum = mock(EnumTypeDefinition.EnumPair.class);
         when(mockEnum.getName()).thenReturn("enum2");
-        List<EnumPair> enumList = Lists.newArrayList(mockEnum);
+        final List<EnumPair> enumList = Lists.newArrayList(mockEnum);
 
-        String elName = "lfEnumeration";
+        final String elName = "lfEnumeration";
         serializeToXml(
                 prepareCnStructForYangData(
                         TypeDefinitionAwareCodec.from(
@@ -199,7 +199,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangEmptyToXmlTest() {
-        String elName = "lfEmpty";
+        final String elName = "lfEmpty";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(EmptyType.getInstance()).deserialize(null),
                         elName), "<" + elName + "/>");
@@ -207,7 +207,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
 
     @Test
     public void snAsYangBooleanToXmlTest() {
-        String elName = "lfBoolean";
+        final String elName = "lfBoolean";
         serializeToXml(
                 prepareCnStructForYangData(TypeDefinitionAwareCodec.from(BooleanType.getInstance()).deserialize("str"),
                         elName), "<" + elName + ">false</" + elName + ">");
@@ -220,26 +220,26 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
     @Test
     public void snAsYangUnionToXmlTest() {
 
-        BitsTypeDefinition.Bit mockBit1 = mock(BitsTypeDefinition.Bit.class);
+        final BitsTypeDefinition.Bit mockBit1 = mock(BitsTypeDefinition.Bit.class);
         when(mockBit1.getName()).thenReturn("first");
-        BitsTypeDefinition.Bit mockBit2 = mock(BitsTypeDefinition.Bit.class);
+        final BitsTypeDefinition.Bit mockBit2 = mock(BitsTypeDefinition.Bit.class);
         when(mockBit2.getName()).thenReturn("second");
-        List<BitsTypeDefinition.Bit> bitList = Lists.newArrayList(mockBit1, mockBit2);
+        final List<BitsTypeDefinition.Bit> bitList = Lists.newArrayList(mockBit1, mockBit2);
 
-        List<TypeDefinition<?>> types = Lists.<TypeDefinition<?>> newArrayList(Int8.getInstance(),
+        final List<TypeDefinition<?>> types = Lists.<TypeDefinition<?>> newArrayList(Int8.getInstance(),
                 BitsType.create(mock(SchemaPath.class), bitList), BooleanType.getInstance());
-        UnionType unionType = UnionType.create(types);
+        final UnionType unionType = UnionType.create(types);
 
-        String elName = "lfUnion";
-        String int8 = "15";
+        final String elName = "lfUnion";
+        final String int8 = "15";
         serializeToXml(prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(int8), elName),
                 "<" + elName + ">15</" + elName + ">");
 
-        String bits = "first second";
+        final String bits = "first second";
         serializeToXml(prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(bits), elName),
                 "<" + elName + ">first second</" + elName + ">");
 
-        String bool = "str";
+        final String bool = "str";
         serializeToXml(prepareCnStructForYangData(TypeDefinitionAwareCodec.from(unionType).deserialize(bool), elName),
                 "<" + elName + ">str</" + elName + ">");
     }
@@ -255,7 +255,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
         assertNotNull(xmlString);
         boolean containSearchedStr = false;
         String strRepresentation = "";
-        for (String searchedStr : xmlRepresentation) {
+        for (final String searchedStr : xmlRepresentation) {
             if (xmlString.contains(searchedStr)) {
                 containSearchedStr = true;
                 break;
@@ -267,9 +267,9 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
     }
 
     private CompositeNode prepareIdentityrefData(final String prefix, final boolean valueAsQName) {
-        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
+        final MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
                 TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null);
-        MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(
+        final MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(
                 TestUtils.buildQName("cont1", "basic:module", "2013-12-2"), cont, null, ModifyAction.CREATE, null);
         cont.getValue().add(cont1);
 
@@ -279,7 +279,7 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
         } else {
             value = "no qname value";
         }
-        MutableSimpleNode<Object> lf11 = NodeFactory.createMutableSimpleNode(
+        final MutableSimpleNode<Object> lf11 = NodeFactory.createMutableSimpleNode(
                 TestUtils.buildQName("lf11", "basic:module", "2013-12-2"), cont1, value, ModifyAction.CREATE, null);
         cont1.getValue().add(lf11);
         cont1.init();
@@ -289,10 +289,10 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
     }
 
     private CompositeNode prepareCnStructForYangData(final Object data, final String leafName) {
-        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
+        final MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
                 TestUtils.buildQName("cont", "basic:module", "2013-12-2"), null, null, ModifyAction.CREATE, null);
 
-        MutableSimpleNode<Object> lf1 = NodeFactory.createMutableSimpleNode(
+        final MutableSimpleNode<Object> lf1 = NodeFactory.createMutableSimpleNode(
                 TestUtils.buildQName(leafName, "basic:module", "2013-12-2"), cont, data, ModifyAction.CREATE, null);
         cont.getValue().add(lf1);
         cont.init();
@@ -301,12 +301,12 @@ public class CnSnToXmlTest extends YangAndXmlAndDataSchemaLoader {
     }
 
     private CompositeNode prepareLeafrefData() {
-        MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
+        final MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(TestUtils.buildQName("cont"), null, null,
                 ModifyAction.CREATE, null);
 
-        MutableSimpleNode<Object> lfBoolean = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfBoolean"),
+        final MutableSimpleNode<Object> lfBoolean = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfBoolean"),
                 cont, Boolean.TRUE, ModifyAction.CREATE, null);
-        MutableSimpleNode<Object> lfLfref = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfLfref"), cont,
+        final MutableSimpleNode<Object> lfLfref = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lfLfref"), cont,
                 "true", ModifyAction.CREATE, null);
         cont.getValue().add(lfBoolean);
         cont.getValue().add(lfLfref);
index 15d73e3..7d6da6a 100644 (file)
@@ -87,7 +87,7 @@ public final class TestUtils {
 
     private final static YangContextParser parser = new YangParserImpl();
 
-    private static Set<Module> loadModules(String resourceDirectory) throws FileNotFoundException {
+    private static Set<Module> loadModules(final String resourceDirectory) throws FileNotFoundException {
         final File testDir = new File(resourceDirectory);
         final String[] fileList = testDir.list();
         final List<File> testFiles = new ArrayList<File>();
@@ -95,7 +95,7 @@ public final class TestUtils {
             throw new FileNotFoundException(resourceDirectory);
         }
         for (int i = 0; i < fileList.length; i++) {
-            String fileName = fileList[i];
+            final String fileName = fileList[i];
             if (new File(testDir, fileName).isDirectory() == false) {
                 testFiles.add(new File(testDir, fileName));
             }
@@ -103,26 +103,26 @@ public final class TestUtils {
         return parser.parseYangModels(testFiles);
     }
 
-    public static Set<Module> loadModulesFrom(String yangPath) {
+    public static Set<Module> loadModulesFrom(final String yangPath) {
         try {
             return TestUtils.loadModules(TestUtils.class.getResource(yangPath).getPath());
-        } catch (FileNotFoundException e) {
+        } catch (final FileNotFoundException e) {
             LOG.error("Yang files at path: " + yangPath + " weren't loaded.");
         }
 
         return null;
     }
 
-    public static SchemaContext loadSchemaContext(Set<Module> modules) {
+    public static SchemaContext loadSchemaContext(final Set<Module> modules) {
         return parser.resolveSchemaContext(modules);
     }
 
-    public static SchemaContext loadSchemaContext(String resourceDirectory) throws FileNotFoundException {
+    public static SchemaContext loadSchemaContext(final String resourceDirectory) throws FileNotFoundException {
         return parser.resolveSchemaContext(loadModulesFrom(resourceDirectory));
     }
 
-    public static Module findModule(Set<Module> modules, String moduleName) {
-        for (Module module : modules) {
+    public static Module findModule(final Set<Module> modules, final String moduleName) {
+        for (final Module module : modules) {
             if (module.getName().equals(moduleName)) {
                 return module;
             }
@@ -130,10 +130,10 @@ public final class TestUtils {
         return null;
     }
 
-    public static Document loadDocumentFrom(InputStream inputStream) {
+    public static Document loadDocumentFrom(final InputStream inputStream) {
         try {
-            DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
-            DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
+            final DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
+            final DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
             return docBuilder.parse(inputStream);
         } catch (SAXException | IOException | ParserConfigurationException e) {
             LOG.error("Error during loading Document from XML", e);
@@ -141,12 +141,12 @@ public final class TestUtils {
         }
     }
 
-    public static String getDocumentInPrintableForm(Document doc) {
+    public static String getDocumentInPrintableForm(final Document doc) {
         Preconditions.checkNotNull(doc);
         try {
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            TransformerFactory tf = TransformerFactory.newInstance();
-            Transformer transformer = tf.newTransformer();
+            final ByteArrayOutputStream out = new ByteArrayOutputStream();
+            final TransformerFactory tf = TransformerFactory.newInstance();
+            final Transformer transformer = tf.newTransformer();
             transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
@@ -154,10 +154,10 @@ public final class TestUtils {
             transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
 
             transformer.transform(new DOMSource(doc), new StreamResult(new OutputStreamWriter(out, "UTF-8")));
-            byte[] charData = out.toByteArray();
+            final byte[] charData = out.toByteArray();
             return new String(charData, "UTF-8");
         } catch (IOException | TransformerException e) {
-            String msg = "Error during transformation of Document into String";
+            final String msg = "Error during transformation of Document into String";
             LOG.error(msg, e);
             return msg;
         }
@@ -170,8 +170,8 @@ public final class TestUtils {
      * {@code dataSchemaNode}. The method {@link RestconfImpl#createConfigurationData createConfigurationData} is used
      * because it contains calling of method {code normalizeNode}
      */
-    public static void normalizeCompositeNode(Node<?> node, Set<Module> modules, String schemaNodePath) {
-        RestconfImpl restconf = RestconfImpl.getInstance();
+    public static void normalizeCompositeNode(final Node<?> node, final Set<Module> modules, final String schemaNodePath) {
+        final RestconfImpl restconf = RestconfImpl.getInstance();
         ControllerContext.getInstance().setSchemas(TestUtils.loadSchemaContext(modules));
 
         prepareMocksForRestconf(modules, restconf);
@@ -183,10 +183,10 @@ public final class TestUtils {
      * module set has only one element then this element is returned.
      *
      */
-    public static Module resolveModule(String searchedModuleName, Set<Module> modules) {
+    public static Module resolveModule(final String searchedModuleName, final Set<Module> modules) {
         assertNotNull("Modules can't be null.", modules);
         if (searchedModuleName != null) {
-            for (Module m : modules) {
+            for (final Module m : modules) {
                 if (m.getName().equals(searchedModuleName)) {
                     return m;
                 }
@@ -197,11 +197,11 @@ public final class TestUtils {
         return null;
     }
 
-    public static DataSchemaNode resolveDataSchemaNode(String searchedDataSchemaName, Module module) {
+    public static DataSchemaNode resolveDataSchemaNode(final String searchedDataSchemaName, final Module module) {
         assertNotNull("Module can't be null", module);
 
         if (searchedDataSchemaName != null) {
-            for (DataSchemaNode dsn : module.getChildNodes()) {
+            for (final DataSchemaNode dsn : module.getChildNodes()) {
                 if (dsn.getQName().getLocalName().equals(searchedDataSchemaName)) {
                     return dsn;
                 }
@@ -212,39 +212,39 @@ public final class TestUtils {
         return null;
     }
 
-    public static QName buildQName(String name, String uri, String date, String prefix) {
+    public static QName buildQName(final String name, final String uri, final String date, final String prefix) {
         try {
-            URI u = new URI(uri);
+            final URI u = new URI(uri);
             Date dt = null;
             if (date != null) {
                 dt = Date.valueOf(date);
             }
-            return new QName(u, dt, prefix, name);
-        } catch (URISyntaxException e) {
+            return QName.create(u, dt, name);
+        } catch (final URISyntaxException e) {
             return null;
         }
     }
 
-    public static QName buildQName(String name, String uri, String date) {
+    public static QName buildQName(final String name, final String uri, final String date) {
         return buildQName(name, uri, date, null);
     }
 
-    public static QName buildQName(String name) {
+    public static QName buildQName(final String name) {
         return buildQName(name, "", null);
     }
 
-    private static void addDummyNamespaceToAllNodes(NodeWrapper<?> wrappedNode) throws URISyntaxException {
+    private static void addDummyNamespaceToAllNodes(final NodeWrapper<?> wrappedNode) throws URISyntaxException {
         wrappedNode.setNamespace(new URI(""));
         if (wrappedNode instanceof CompositeNodeWrapper) {
-            for (NodeWrapper<?> childNodeWrapper : ((CompositeNodeWrapper) wrappedNode).getValues()) {
+            for (final NodeWrapper<?> childNodeWrapper : ((CompositeNodeWrapper) wrappedNode).getValues()) {
                 addDummyNamespaceToAllNodes(childNodeWrapper);
             }
         }
     }
 
-    private static void prepareMocksForRestconf(Set<Module> modules, RestconfImpl restconf) {
-        ControllerContext controllerContext = ControllerContext.getInstance();
-        BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class);
+    private static void prepareMocksForRestconf(final Set<Module> modules, final RestconfImpl restconf) {
+        final ControllerContext controllerContext = ControllerContext.getInstance();
+        final BrokerFacade mockedBrokerFacade = mock(BrokerFacade.class);
 
         controllerContext.setSchemas(TestUtils.loadSchemaContext(modules));
 
@@ -255,10 +255,10 @@ public final class TestUtils {
         restconf.setBroker(mockedBrokerFacade);
     }
 
-    public static Node<?> readInputToCnSn(String path, boolean dummyNamespaces,
-            MessageBodyReader<Node<?>> reader) throws WebApplicationException {
+    public static Node<?> readInputToCnSn(final String path, final boolean dummyNamespaces,
+            final MessageBodyReader<Node<?>> reader) throws WebApplicationException {
 
-        InputStream inputStream = TestUtils.class.getResourceAsStream(path);
+        final InputStream inputStream = TestUtils.class.getResourceAsStream(path);
         try {
             final Node<?> node = reader.readFrom(null, null, null, null, null, inputStream);
             assertTrue(node instanceof CompositeNodeWrapper);
@@ -266,13 +266,13 @@ public final class TestUtils {
                 try {
                     TestUtils.addDummyNamespaceToAllNodes((CompositeNodeWrapper) node);
                     return ((CompositeNodeWrapper) node).unwrap();
-                } catch (URISyntaxException e) {
+                } catch (final URISyntaxException e) {
                     LOG.error(e.getMessage());
                     assertTrue(e.getMessage(), false);
                 }
             }
             return node;
-        } catch (IOException e) {
+        } catch (final IOException e) {
             LOG.error(e.getMessage());
             assertTrue(e.getMessage(), false);
         }
@@ -290,17 +290,17 @@ public final class TestUtils {
 //        return null;
 //    }
 
-    public static Node<?> readInputToCnSn(String path, MessageBodyReader<Node<?>> reader) {
+    public static Node<?> readInputToCnSn(final String path, final MessageBodyReader<Node<?>> reader) {
         return readInputToCnSn(path, false, reader);
     }
 
-    public static String writeCompNodeWithSchemaContextToOutput(Node<?> node, Set<Module> modules,
-            DataSchemaNode dataSchemaNode, MessageBodyWriter<StructuredData> messageBodyWriter) throws IOException,
+    public static String writeCompNodeWithSchemaContextToOutput(final Node<?> node, final Set<Module> modules,
+            final DataSchemaNode dataSchemaNode, final MessageBodyWriter<StructuredData> messageBodyWriter) throws IOException,
             WebApplicationException {
 
         assertNotNull(dataSchemaNode);
         assertNotNull("Composite node can't be null", node);
-        ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
+        final ByteArrayOutputStream byteArrayOS = new ByteArrayOutputStream();
 
         ControllerContext.getInstance().setSchemas(loadSchemaContext(modules));
 
@@ -311,12 +311,12 @@ public final class TestUtils {
         return byteArrayOS.toString();
     }
 
-    public static String loadTextFile(String filePath) throws IOException {
-        FileReader fileReader = new FileReader(filePath);
-        BufferedReader bufReader = new BufferedReader(fileReader);
+    public static String loadTextFile(final String filePath) throws IOException {
+        final FileReader fileReader = new FileReader(filePath);
+        final BufferedReader bufReader = new BufferedReader(fileReader);
 
         String line = null;
-        StringBuilder result = new StringBuilder();
+        final StringBuilder result = new StringBuilder();
         while ((line = bufReader.readLine()) != null) {
             result.append(line);
         }
@@ -324,10 +324,10 @@ public final class TestUtils {
         return result.toString();
     }
 
-    private static Pattern patternForStringsSeparatedByWhiteChars(String... substrings) {
-        StringBuilder pattern = new StringBuilder();
+    private static Pattern patternForStringsSeparatedByWhiteChars(final String... substrings) {
+        final StringBuilder pattern = new StringBuilder();
         pattern.append(".*");
-        for (String substring : substrings) {
+        for (final String substring : substrings) {
             pattern.append(substring);
             pattern.append("\\s*");
         }
@@ -335,15 +335,15 @@ public final class TestUtils {
         return Pattern.compile(pattern.toString(), Pattern.DOTALL);
     }
 
-    public static boolean containsStringData(String jsonOutput, String... substrings) {
-        Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings);
-        Matcher matcher = pattern.matcher(jsonOutput);
+    public static boolean containsStringData(final String jsonOutput, final String... substrings) {
+        final Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings);
+        final Matcher matcher = pattern.matcher(jsonOutput);
         return matcher.matches();
     }
 
     public static NormalizedNode compositeNodeToDatastoreNormalizedNode(final CompositeNode compositeNode,
             final DataSchemaNode schema) {
-        List<Node<?>> lst = new ArrayList<Node<?>>();
+        final List<Node<?>> lst = new ArrayList<Node<?>>();
         lst.add(compositeNode);
         if (schema instanceof ContainerSchemaNode) {
             return CnSnToNormalizedNodeParserFactory.getInstance().getContainerNodeParser()
@@ -359,15 +359,15 @@ public final class TestUtils {
                 "It wasn't possible to translate specified data to datastore readable form."));
     }
 
-    public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(String localName, String namespace,
-            String revision) throws ParseException {
+    public static YangInstanceIdentifier.NodeIdentifier getNodeIdentifier(final String localName, final String namespace,
+            final String revision) throws ParseException {
         return new YangInstanceIdentifier.NodeIdentifier(QName.create(namespace, revision, localName));
     }
 
-    public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName,
-            String namespace, String revision, Map<String, Object> keys) throws ParseException {
-        Map<QName, Object> predicate = new HashMap<>();
-        for (String key : keys.keySet()) {
+    public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+            final String namespace, final String revision, final Map<String, Object> keys) throws ParseException {
+        final Map<QName, Object> predicate = new HashMap<>();
+        for (final String key : keys.keySet()) {
             predicate.put(QName.create(namespace, revision, key), keys.get(key));
         }
 
@@ -376,13 +376,13 @@ public final class TestUtils {
         QName.create(namespace, revision, localName), predicate);
     }
 
-    public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(String localName,
-            String namespace, String revision, String... keysAndValues) throws ParseException {
-        java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse(revision);
+    public static YangInstanceIdentifier.NodeIdentifierWithPredicates getNodeIdentifierPredicate(final String localName,
+            final String namespace, final String revision, final String... keysAndValues) throws ParseException {
+        final java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse(revision);
         if (keysAndValues.length % 2 != 0) {
             new IllegalArgumentException("number of keys argument have to be divisible by 2 (map)");
         }
-        Map<QName, Object> predicate = new HashMap<>();
+        final Map<QName, Object> predicate = new HashMap<>();
 
         int i = 0;
         while (i < keysAndValues.length) {
@@ -394,7 +394,7 @@ public final class TestUtils {
     }
 
     public static CompositeNode prepareCompositeNodeWithIetfInterfacesInterfacesData() {
-        CompositeNodeBuilder<ImmutableCompositeNode> interfaceBuilder = ImmutableCompositeNode.builder();
+        final CompositeNodeBuilder<ImmutableCompositeNode> interfaceBuilder = ImmutableCompositeNode.builder();
         interfaceBuilder.addLeaf(buildQName("name", "dummy", "2014-07-29"), "eth0");
         interfaceBuilder.addLeaf(buildQName("type", "dummy", "2014-07-29"), "ethernetCsmacd");
         interfaceBuilder.addLeaf(buildQName("enabled", "dummy", "2014-07-29"), "false");
@@ -403,11 +403,11 @@ public final class TestUtils {
     }
 
     static NormalizedNode<?,?> prepareNormalizedNodeWithIetfInterfacesInterfacesData() throws ParseException {
-        String ietfInterfacesDate = "2013-07-04";
-        String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
-        DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryNode = ImmutableMapEntryNodeBuilder.create();
+        final String ietfInterfacesDate = "2013-07-04";
+        final String namespace = "urn:ietf:params:xml:ns:yang:ietf-interfaces";
+        final DataContainerNodeAttrBuilder<YangInstanceIdentifier.NodeIdentifierWithPredicates, MapEntryNode> mapEntryNode = ImmutableMapEntryNodeBuilder.create();
 
-        Map<String, Object> predicates = new HashMap<>();
+        final Map<String, Object> predicates = new HashMap<>();
         predicates.put("name", "eth0");
 
         mapEntryNode.withNodeIdentifier(getNodeIdentifierPredicate("interface", namespace, ietfInterfacesDate,
index 9bafe97..31a7661 100644 (file)
@@ -9,11 +9,11 @@
 package org.opendaylight.controller.netconf.client;
 
 import io.netty.channel.Channel;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.codec.MessageToByteEncoder;
 import java.util.Collection;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSession;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToEXIEncoder;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToXMLEncoder;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
 import org.slf4j.Logger;
@@ -49,10 +49,10 @@ public class NetconfClientSession extends AbstractNetconfSession<NetconfClientSe
     }
 
     @Override
-    protected void addExiHandlers(final NetconfEXICodec exiCodec) {
+    protected void addExiHandlers(final ByteToMessageDecoder decoder, final MessageToByteEncoder<NetconfMessage> encoder) {
         // TODO used only in negotiator, client supports only auto start-exi
-        replaceMessageDecoder(new NetconfEXIToMessageDecoder(exiCodec));
-        replaceMessageEncoder(new NetconfMessageToEXIEncoder(exiCodec));
+        replaceMessageDecoder(decoder);
+        replaceMessageEncoder(encoder);
     }
 
     @Override
index 850ad55..2a3ecf2 100644 (file)
@@ -12,7 +12,6 @@ import static org.junit.Assert.assertEquals;
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.mock;
-
 import com.google.common.collect.Lists;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelHandler;
@@ -24,6 +23,8 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
+import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
+import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToEXIEncoder;
 import org.openexi.proc.common.EXIOptions;
 
 public class NetconfClientSessionTest {
@@ -53,7 +54,9 @@ public class NetconfClientSessionTest {
         Mockito.doReturn("").when(channelHandler).toString();
 
         NetconfClientSession session = new NetconfClientSession(sessionListener, channel, sessId, caps);
-        session.addExiHandlers(codec);
+        final NetconfMessageToEXIEncoder exiEncoder = NetconfMessageToEXIEncoder.create(codec);
+        final NetconfEXIToMessageDecoder exiDecoder = NetconfEXIToMessageDecoder.create(codec);
+        session.addExiHandlers(exiDecoder, exiEncoder);
         session.stopExiCommunication();
 
         assertEquals(caps, session.getServerCapabilities());
index ca604a4..8f2c39d 100644 (file)
@@ -10,15 +10,15 @@ package org.opendaylight.controller.netconf.impl;
 
 import com.google.common.base.Preconditions;
 import io.netty.channel.Channel;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.codec.MessageToByteEncoder;
 import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
 import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSession;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToEXIEncoder;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToXMLEncoder;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfXMLToMessageDecoder;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
@@ -46,8 +46,8 @@ public final class NetconfServerSession extends AbstractNetconfSession<NetconfSe
     private Date loginTime;
     private long inRpcSuccess, inRpcFail, outRpcError;
 
-    public NetconfServerSession(NetconfServerSessionListener sessionListener, Channel channel, long sessionId,
-            NetconfHelloMessageAdditionalHeader header) {
+    public NetconfServerSession(final NetconfServerSessionListener sessionListener, final Channel channel, final long sessionId,
+            final NetconfHelloMessageAdditionalHeader header) {
         super(sessionListener, channel, sessionId);
         this.header = header;
         LOG.debug("Session {} created", toString());
@@ -109,7 +109,7 @@ public final class NetconfServerSession extends AbstractNetconfSession<NetconfSe
         return builder.build();
     }
 
-    private Class<? extends Transport> getTransportForString(String transport) {
+    private Class<? extends Transport> getTransportForString(final String transport) {
         switch(transport) {
         case "ssh" :
             return NetconfSsh.class;
@@ -120,7 +120,7 @@ public final class NetconfServerSession extends AbstractNetconfSession<NetconfSe
         }
     }
 
-    private String formatDateTime(Date loginTime) {
+    private String formatDateTime(final Date loginTime) {
         SimpleDateFormat dateFormat = new SimpleDateFormat(ISO_DATE_FORMAT);
         return dateFormat.format(loginTime);
     }
@@ -131,9 +131,9 @@ public final class NetconfServerSession extends AbstractNetconfSession<NetconfSe
     }
 
     @Override
-    protected void addExiHandlers(NetconfEXICodec exiCodec) {
-        replaceMessageDecoder(new NetconfEXIToMessageDecoder(exiCodec));
-        replaceMessageEncoderAfterNextMessage(new NetconfMessageToEXIEncoder(exiCodec));
+    protected void addExiHandlers(final ByteToMessageDecoder decoder, final MessageToByteEncoder<NetconfMessage> encoder) {
+        replaceMessageDecoder(decoder);
+        replaceMessageEncoderAfterNextMessage(encoder);
     }
 
     @Override
index 1a35e4d..26abdd9 100644 (file)
@@ -8,8 +8,8 @@
 
 package org.opendaylight.controller.netconf.impl.osgi;
 
-import java.util.Collections;
-import java.util.HashSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
 import java.util.Set;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationService;
 import org.opendaylight.controller.netconf.mapping.api.NetconfOperationServiceFactory;
@@ -21,17 +21,15 @@ public class NetconfOperationServiceSnapshotImpl implements NetconfOperationServ
     private final Set<NetconfOperationService> services;
     private final String netconfSessionIdForReporting;
 
-    public NetconfOperationServiceSnapshotImpl(Set<NetconfOperationServiceFactory> factories, String sessionIdForReporting) {
-        Set<NetconfOperationService> services = new HashSet<>();
+    public NetconfOperationServiceSnapshotImpl(final Set<NetconfOperationServiceFactory> factories, final String sessionIdForReporting) {
+        final Builder<NetconfOperationService> b = ImmutableSet.builder();
         netconfSessionIdForReporting = sessionIdForReporting;
         for (NetconfOperationServiceFactory factory : factories) {
-            services.add(factory.createService(netconfSessionIdForReporting));
+            b.add(factory.createService(netconfSessionIdForReporting));
         }
-        this.services = Collections.unmodifiableSet(services);
+        this.services = b.build();
     }
 
-
-
     @Override
     public String getNetconfSessionIdForReporting() {
         return netconfSessionIdForReporting;
index 7218ac7..6e4c16d 100644 (file)
       <artifactId>netconf-ssh</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+       <groupId>${project.groupId}</groupId>
+       <artifactId>netconf-testtool</artifactId>
+       <version>${project.version}</version>
+       <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>${project.groupId}</groupId>
       <artifactId>netconf-ssh</artifactId>
index 5f316d1..bd8e2ed 100644 (file)
@@ -41,8 +41,6 @@ import org.apache.sshd.server.session.ServerSession;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.auth.AuthProvider;
 import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
@@ -116,7 +114,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
     @Test
     public void testSecure() throws Exception {
         final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(new SimpleNetconfClientSessionListener()))) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(new SimpleNetconfClientSessionListener(), TLS_ADDRESS))) {
             NetconfMessage response = netconfClient.sendMessage(getGetConfig());
             assertFalse("Unexpected error message " + XmlUtil.toString(response.getDocument()),
                     NetconfMessageUtil.isErrorMessage(response));
@@ -143,7 +141,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
 
         final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(getNettyThreadgroup(), getNettyThreadgroup(), getHashedWheelTimer());
         final NetconfDeviceCommunicator sessionListener = getSessionListener();
-        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(sessionListener))) {
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, getClientConfiguration(sessionListener, TLS_ADDRESS))) {
 
             final AtomicInteger responseCounter = new AtomicInteger(0);
             final List<ListenableFuture<RpcResult<NetconfMessage>>> futures = Lists.newArrayList();
@@ -182,15 +180,15 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         }
     }
 
-    private NetconfMessage changeMessageId(final NetconfMessage getConfig, final int i) throws IOException, SAXException {
+    public static NetconfMessage changeMessageId(final NetconfMessage getConfig, final int i) throws IOException, SAXException {
         String s = XmlUtil.toString(getConfig.getDocument(), false);
         s = s.replace("101", Integer.toString(i));
         return new NetconfMessage(XmlUtil.readXmlToDocument(s));
     }
 
-    public NetconfClientConfiguration getClientConfiguration(final NetconfClientSessionListener sessionListener) throws IOException {
+    static NetconfClientConfiguration getClientConfiguration(final NetconfClientSessionListener sessionListener,final InetSocketAddress tlsAddress) throws IOException {
         final NetconfClientConfigurationBuilder b = NetconfClientConfigurationBuilder.create();
-        b.withAddress(TLS_ADDRESS);
+        b.withAddress(tlsAddress);
         // Using session listener from sal-netconf-connector since stress test cannot be performed with simple listener
         b.withSessionListener(sessionListener);
         b.withReconnectStrategy(new NeverReconnectStrategy(GlobalEventExecutor.INSTANCE, 5000));
@@ -200,11 +198,8 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         return b.build();
     }
 
-    @Mock
-    private RemoteDevice<NetconfSessionCapabilities, NetconfMessage> mockedRemoteDevice;
-
-    private NetconfDeviceCommunicator getSessionListener() {
-        MockitoAnnotations.initMocks(this);
+    static NetconfDeviceCommunicator getSessionListener() {
+        RemoteDevice<NetconfSessionCapabilities, NetconfMessage> mockedRemoteDevice = mock(RemoteDevice.class);
         doNothing().when(mockedRemoteDevice).onRemoteSessionUp(any(NetconfSessionCapabilities.class), any(RemoteDeviceCommunicator.class));
         doNothing().when(mockedRemoteDevice).onRemoteSessionDown();
         return new NetconfDeviceCommunicator(new RemoteDeviceId("secure-test"), mockedRemoteDevice);
@@ -217,7 +212,7 @@ public class NetconfITSecureTest extends AbstractNetconfConfigTest {
         return mockAuth;
     }
 
-    public AuthenticationHandler getAuthHandler() throws IOException {
+    public static AuthenticationHandler getAuthHandler() throws IOException {
         return new LoginPassword(USERNAME, PASSWORD);
     }
 
diff --git a/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTestTool.java b/opendaylight/netconf/netconf-it/src/test/java/org/opendaylight/controller/netconf/it/NetconfITSecureTestTool.java
new file mode 100644 (file)
index 0000000..0247273
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ * 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.html
+ */
+
+package org.opendaylight.controller.netconf.it;
+
+import static java.lang.Thread.sleep;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+import static org.opendaylight.controller.netconf.it.NetconfITSecureTest.getSessionListener;
+
+import com.google.common.base.Throwables;
+import com.google.common.collect.Lists;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.util.HashedWheelTimer;
+import java.net.InetSocketAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicInteger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcher;
+import org.opendaylight.controller.netconf.client.NetconfClientDispatcherImpl;
+import org.opendaylight.controller.netconf.client.TestingNetconfClient;
+import org.opendaylight.controller.netconf.test.tool.Main.Params;
+import org.opendaylight.controller.netconf.test.tool.NetconfDeviceSimulator;
+import org.opendaylight.controller.netconf.util.test.XmlFileLoader;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfDeviceCommunicator;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+
+public class NetconfITSecureTestTool
+{
+
+    //set up port both for testool device and test
+    public static final int PORT = 17833;
+    private static final InetSocketAddress TLS_ADDRESS = new InetSocketAddress("127.0.0.1", PORT);
+
+    private String xmlFile = "netconfMessages/editConfig.xml";
+
+    private ExecutorService msgExec = Executors.newFixedThreadPool(8);
+
+    Collection<Future<?>> tasks = new LinkedList<Future<?>>();
+
+    final NetconfDeviceSimulator netconfDeviceSimulator = new NetconfDeviceSimulator();
+
+    @Before
+    public void setUp() throws Exception {
+
+        //Set up parameters for testtool device
+        Params params = new Params();
+        params.debug = true;
+        params.deviceCount = 1;
+        params.startingPort = PORT;
+        params.ssh = true;
+        params.exi = true;
+
+        final List<Integer> openDevices = netconfDeviceSimulator.start(params);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+
+    }
+
+    /**
+     * Test all requests are handled properly and no mismatch occurs in listener
+     */
+    @Test(timeout = 6*60*1000)
+    public void testSecureStress() throws Exception {
+
+        final int requests = 4000;
+
+        List<Future<?>> tasks = new ArrayList<>();
+
+        final NetconfClientDispatcher dispatch = new NetconfClientDispatcherImpl(new NioEventLoopGroup(), new NioEventLoopGroup(), new HashedWheelTimer());
+
+        final NetconfDeviceCommunicator sessionListener = getSessionListener();
+
+        try (TestingNetconfClient netconfClient = new TestingNetconfClient("testing-ssh-client", dispatch, NetconfITSecureTest.getClientConfiguration(sessionListener, TLS_ADDRESS));)
+        {
+
+            final AtomicInteger responseCounter = new AtomicInteger(0);
+            final List<ListenableFuture<RpcResult<NetconfMessage>>> futures = Lists.newArrayList();
+
+            for (int i = 0; i < requests; i++) {
+
+                NetconfMessage getConfig = XmlFileLoader.xmlFileToNetconfMessage(xmlFile);
+
+                getConfig = NetconfITSecureTest.changeMessageId(getConfig,i);
+
+                Runnable worker = new NetconfITSecureTestToolRunnable(getConfig,i, sessionListener, futures, responseCounter);
+
+                tasks.add(msgExec.submit(worker));
+
+            }
+
+            msgExec.shutdown();
+
+            // Wait for every future
+            for (final Future<?> task : tasks){
+                try
+                {
+
+                    task.get(3, TimeUnit.MINUTES);
+                } catch (final TimeoutException e) {
+                    fail(String.format("Request %d is not responding", tasks.indexOf(task)));
+                }
+            }
+
+            for (final ListenableFuture<RpcResult<NetconfMessage>> future : futures) {
+                try {
+
+                    future.get(3, TimeUnit.MINUTES);
+                } catch (final TimeoutException e) {
+                    fail(String.format("Reply %d is not responding", futures.indexOf(future)));
+                }
+            }
+
+            sleep(5000);
+
+            assertEquals(requests, responseCounter.get());
+
+        }
+    }
+
+    class NetconfITSecureTestToolRunnable implements Runnable {
+
+        private NetconfMessage getConfig;
+        private int it;
+        private NetconfDeviceCommunicator sessionListener;
+        private List<ListenableFuture<RpcResult<NetconfMessage>>> futures;
+        private AtomicInteger responseCounter;
+
+        public NetconfITSecureTestToolRunnable(NetconfMessage getConfig, int it, NetconfDeviceCommunicator sessionListener, List<ListenableFuture<RpcResult<NetconfMessage>>> futures, AtomicInteger responseCounter){
+            this.getConfig = getConfig;
+            this.it = it;
+            this.sessionListener = sessionListener;
+            this.futures = futures;
+            this.responseCounter = responseCounter;
+        }
+
+        @Override
+        public void run(){
+
+            ListenableFuture<RpcResult<NetconfMessage>> netconfMessageFuture;
+
+            netconfMessageFuture = sessionListener.sendRequest(getConfig, QName.create("namespace", "2012-12-12", "get"));
+
+            futures.add(netconfMessageFuture);
+            Futures.addCallback(netconfMessageFuture, new FutureCallback<RpcResult<NetconfMessage>>() {
+
+                    @Override
+                    public void onSuccess(final RpcResult<NetconfMessage> result) {
+
+                        if(result.isSuccessful()&result.getErrors().isEmpty()) {
+                            responseCounter.incrementAndGet();
+                        } else {
+
+                            fail(String.format("Message result not ok %s", result.getErrors().toString()));
+
+                        }
+                    }
+
+                    @Override
+                    public void onFailure(final Throwable t) {
+
+                        fail(String.format("Message failed %s", Throwables.getStackTraceAsString(t)));
+
+                    }
+                }
+            );
+        }
+    }
+
+}
index 91fb805..e9ee13d 100644 (file)
@@ -6,8 +6,8 @@
         </encoder>
     </appender>
 
-  <logger name="org.opendaylight.controller.netconf" level="TRACE"/>
-  <logger name="org.opendaylight.controller.sal.connect.netconf" level="TRACE"/>
+  <logger name="org.opendaylight.controller.netconf" level="INFO"/>
+  <logger name="org.opendaylight.controller.sal.connect.netconf" level="DEBUG"/>
 
   <root level="error">
     <appender-ref ref="STDOUT" />
index fd11ce8..a59b1a0 100644 (file)
@@ -10,6 +10,8 @@ package org.opendaylight.controller.netconf.nettyutil;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelHandler;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.codec.MessageToByteEncoder;
 import java.io.IOException;
 import org.opendaylight.controller.netconf.api.NetconfExiSession;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
@@ -17,10 +19,13 @@ import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
+import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
+import org.opendaylight.controller.netconf.nettyutil.handler.NetconfMessageToEXIEncoder;
 import org.opendaylight.controller.netconf.nettyutil.handler.exi.EXIParameters;
 import org.opendaylight.controller.netconf.util.xml.XmlElement;
 import org.opendaylight.protocol.framework.AbstractProtocolSession;
 import org.openexi.proc.common.EXIOptionsException;
+import org.openexi.sax.TransmogrifierException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -117,12 +122,35 @@ public abstract class AbstractNetconfSession<S extends NetconfSession, L extends
             LOG.warn("Unable to parse EXI parameters from {} on session {}", startExiMessage, this, e);
             throw new IllegalArgumentException("Cannot parse options", e);
         }
+
         final NetconfEXICodec exiCodec = new NetconfEXICodec(exiParams.getOptions());
-        addExiHandlers(exiCodec);
+        final NetconfMessageToEXIEncoder exiEncoder;
+        try {
+            exiEncoder = NetconfMessageToEXIEncoder.create(exiCodec);
+        } catch (EXIOptionsException | TransmogrifierException e) {
+            LOG.warn("Failed to instantiate EXI encoder for {} on session {}", exiCodec, this, e);
+            throw new IllegalStateException("Cannot instantiate encoder for options", e);
+        }
+
+        final NetconfEXIToMessageDecoder exiDecoder;
+        try {
+            exiDecoder = NetconfEXIToMessageDecoder.create(exiCodec);
+        } catch (EXIOptionsException e) {
+            LOG.warn("Failed to instantiate EXI decodeer for {} on session {}", exiCodec, this, e);
+            throw new IllegalStateException("Cannot instantiate encoder for options", e);
+        }
+
+        addExiHandlers(exiDecoder, exiEncoder);
         LOG.debug("Session {} EXI handlers added to pipeline", this);
     }
 
-    protected abstract void addExiHandlers(NetconfEXICodec exiCodec);
+    /**
+     * Add a set encoder/decoder tuple into the channel pipeline as appropriate.
+     *
+     * @param decoder EXI decoder
+     * @param encoder EXI encoder
+     */
+    protected abstract void addExiHandlers(ByteToMessageDecoder decoder, MessageToByteEncoder<NetconfMessage> encoder);
 
     public final boolean isUp() {
         return up;
index 98baef0..16da7a7 100644 (file)
@@ -1,6 +1,9 @@
 package org.opendaylight.controller.netconf.nettyutil.handler;
 
 import com.google.common.base.Preconditions;
+import com.google.common.cache.CacheBuilder;
+import com.google.common.cache.CacheLoader;
+import com.google.common.cache.LoadingCache;
 import org.openexi.proc.HeaderOptionsOutputType;
 import org.openexi.proc.common.EXIOptions;
 import org.openexi.proc.common.EXIOptionsException;
@@ -8,6 +11,9 @@ import org.openexi.proc.common.GrammarOptions;
 import org.openexi.proc.grammars.GrammarCache;
 import org.openexi.sax.EXIReader;
 import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
 
 public final class NetconfEXICodec {
     /**
@@ -16,13 +22,41 @@ public final class NetconfEXICodec {
      * of the stream. This is really useful, so let's output it now.
      */
     private static final boolean OUTPUT_EXI_COOKIE = true;
+    /**
+     * OpenEXI does not allow us to directly prevent resolution of external entities. In order
+     * to prevent XXE attacks, we reuse a single no-op entity resolver.
+     */
+    private static final EntityResolver ENTITY_RESOLVER = new EntityResolver() {
+        @Override
+        public InputSource resolveEntity(final String publicId, final String systemId) {
+            return new InputSource();
+        }
+    };
+
+    /**
+     * Since we have a limited number of options we can have, instantiating a weak cache
+     * will allow us to reuse instances where possible.
+     */
+    private static final LoadingCache<Short, GrammarCache> GRAMMAR_CACHES = CacheBuilder.newBuilder().weakValues().build(new CacheLoader<Short, GrammarCache>() {
+        @Override
+        public GrammarCache load(final Short key) {
+            return new GrammarCache(key);
+        }
+    });
+
+    /**
+     * Grammar cache acts as a template and is duplicated by the Transmogrifier and the Reader
+     * before use. It is safe to reuse a single instance.
+     */
+    private final GrammarCache exiGrammarCache;
     private final EXIOptions exiOptions;
 
     public NetconfEXICodec(final EXIOptions exiOptions) {
         this.exiOptions = Preconditions.checkNotNull(exiOptions);
+        this.exiGrammarCache = createGrammarCache(exiOptions);
     }
 
-    private GrammarCache getGrammarCache() {
+    private static GrammarCache createGrammarCache(final EXIOptions exiOptions) {
         short go = GrammarOptions.DEFAULT_OPTIONS;
         if (exiOptions.getPreserveComments()) {
             go = GrammarOptions.addCM(go);
@@ -37,23 +71,25 @@ public final class NetconfEXICodec {
             go = GrammarOptions.addPI(go);
         }
 
-        return new GrammarCache(null, go);
+        return GRAMMAR_CACHES.getUnchecked(go);
     }
 
     EXIReader getReader() throws EXIOptionsException {
         final EXIReader r = new EXIReader();
         r.setPreserveLexicalValues(exiOptions.getPreserveLexicalValues());
-        r.setGrammarCache(getGrammarCache());
+        r.setGrammarCache(exiGrammarCache);
+        r.setEntityResolver(ENTITY_RESOLVER);
         return r;
     }
 
-    Transmogrifier getTransmogrifier() throws EXIOptionsException {
+    Transmogrifier getTransmogrifier() throws EXIOptionsException, TransmogrifierException {
         final Transmogrifier transmogrifier = new Transmogrifier();
         transmogrifier.setAlignmentType(exiOptions.getAlignmentType());
         transmogrifier.setBlockSize(exiOptions.getBlockSize());
-        transmogrifier.setGrammarCache(getGrammarCache());
+        transmogrifier.setGrammarCache(exiGrammarCache);
         transmogrifier.setOutputCookie(OUTPUT_EXI_COOKIE);
         transmogrifier.setOutputOptions(HeaderOptionsOutputType.all);
+        transmogrifier.setResolveExternalGeneralEntities(false);
         return transmogrifier;
     }
 }
index 77d33e1..db265de 100644 (file)
@@ -33,11 +33,19 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
 
     private static final Logger LOG = LoggerFactory.getLogger(NetconfEXIToMessageDecoder.class);
     private static final SAXTransformerFactory FACTORY = (SAXTransformerFactory) SAXTransformerFactory.newInstance();
+    /**
+     * This class is not marked as shared, so it can be attached to only a single channel,
+     * which means that {@link #decode(ChannelHandlerContext, ByteBuf, List)}
+     * cannot be invoked concurrently. Hence we can reuse the reader.
+     */
+    private final EXIReader reader;
 
-    private final NetconfEXICodec codec;
+    private NetconfEXIToMessageDecoder(final EXIReader reader) {
+        this.reader = Preconditions.checkNotNull(reader);
+    }
 
-    public NetconfEXIToMessageDecoder(final NetconfEXICodec codec) {
-        this.codec = Preconditions.checkNotNull(codec);
+    public static NetconfEXIToMessageDecoder create(final NetconfEXICodec codec) throws EXIOptionsException {
+        return new NetconfEXIToMessageDecoder(codec.getReader());
     }
 
     @Override
@@ -59,15 +67,15 @@ public final class NetconfEXIToMessageDecoder extends ByteToMessageDecoder {
             LOG.trace("Received to decode: {}", ByteBufUtil.hexDump(in));
         }
 
-        final EXIReader r = codec.getReader();
         final TransformerHandler handler = FACTORY.newTransformerHandler();
-        r.setContentHandler(handler);
+        reader.setContentHandler(handler);
 
         final DOMResult domResult = new DOMResult();
         handler.setResult(domResult);
 
         try (final InputStream is = new ByteBufInputStream(in)) {
-            r.parse(new InputSource(is));
+            // Performs internal reset before doing anything
+            reader.parse(new InputSource(is));
         }
 
         out.add(new NetconfMessage((Document) domResult.getNode()));
index f1e72ed..aceb6ac 100644 (file)
@@ -14,32 +14,49 @@ import io.netty.channel.ChannelHandlerContext;
 import io.netty.handler.codec.MessageToByteEncoder;
 import java.io.IOException;
 import java.io.OutputStream;
+import javax.xml.transform.Transformer;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.sax.SAXResult;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.openexi.proc.common.EXIOptionsException;
 import org.openexi.sax.Transmogrifier;
+import org.openexi.sax.TransmogrifierException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.xml.sax.ContentHandler;
 
 public final class NetconfMessageToEXIEncoder extends MessageToByteEncoder<NetconfMessage> {
     private static final Logger LOG = LoggerFactory.getLogger(NetconfMessageToEXIEncoder.class);
-    private final NetconfEXICodec codec;
+    /**
+     * This class is not marked as shared, so it can be attached to only a single channel,
+     * which means that {@link #encode(ChannelHandlerContext, NetconfMessage, ByteBuf)}
+     * cannot be invoked concurrently. Hence we can reuse the transmogrifier.
+     */
+    private final Transmogrifier transmogrifier;
 
-    public NetconfMessageToEXIEncoder(final NetconfEXICodec codec) {
-        this.codec = Preconditions.checkNotNull(codec);
+    private NetconfMessageToEXIEncoder(final Transmogrifier transmogrifier) {
+        this.transmogrifier = Preconditions.checkNotNull(transmogrifier);
+    }
+
+    public static NetconfMessageToEXIEncoder create(final NetconfEXICodec codec) throws EXIOptionsException, TransmogrifierException {
+        return new NetconfMessageToEXIEncoder(codec.getTransmogrifier());
     }
 
     @Override
-    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException {
+    protected void encode(final ChannelHandlerContext ctx, final NetconfMessage msg, final ByteBuf out) throws EXIOptionsException, IOException, TransformerException, TransmogrifierException {
         LOG.trace("Sent to encode : {}", msg);
 
         try (final OutputStream os = new ByteBufOutputStream(out)) {
-            final Transmogrifier transmogrifier = codec.getTransmogrifier();
             transmogrifier.setOutputStream(os);
-
-            ThreadLocalTransformers.getDefaultTransformer().transform(new DOMSource(msg.getDocument()), new SAXResult(transmogrifier.getSAXTransmogrifier()));
+            final ContentHandler handler = transmogrifier.getSAXTransmogrifier();
+            final Transformer transformer = ThreadLocalTransformers.getDefaultTransformer();
+            transformer.transform(new DOMSource(msg.getDocument()), new SAXResult(handler));
+        } finally {
+            // Make sure we do not retain any reference to state by removing
+            // the output stream reference and resetting internal state.
+            transmogrifier.setOutputStream(null);
+            transmogrifier.getSAXTransmogrifier();
         }
     }
 }
index 1e976ce..757dc1a 100644 (file)
@@ -62,12 +62,15 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
                 return;
             }
 
-            writeWithPendingDetection(ctx, promise, byteBufMsg);
+            writeWithPendingDetection(ctx, promise, byteBufMsg, false);
         }
     }
 
-    private void writeWithPendingDetection(final ChannelHandlerContext ctx, final ChannelPromise promise, final ByteBuf byteBufMsg) {
+    //sending message with pending
+    //if resending message not succesfull, then attribute wasPending is true
+    private void writeWithPendingDetection(final ChannelHandlerContext ctx, final ChannelPromise promise, final ByteBuf byteBufMsg, boolean wasPending) {
         try {
+
             if (LOG.isTraceEnabled()) {
                 LOG.trace("Writing request on channel: {}, message: {}", ctx.channel(), byteBufToString(byteBufMsg));
             }
@@ -77,7 +80,7 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
                 public void operationComplete(final IoWriteFuture future) {
                     if (LOG.isTraceEnabled()) {
                         LOG.trace("Ssh write request finished on channel: {} with result: {}: and ex:{}, message: {}",
-                                        ctx.channel(), future.isWritten(), future.getException(), byteBufToString(byteBufMsg));
+                            ctx.channel(), future.isWritten(), future.getException(), byteBufToString(byteBufMsg));
                     }
 
                     // Notify success or failure
@@ -94,30 +97,40 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
                     // Check pending queue and schedule next
                     // At this time we are guaranteed that we are not in pending state anymore so the next request should succeed
                     writePendingIfAny();
+
                 }
             });
+
+            //rescheduling message from queue after successfully sent
+            if(wasPending){
+                byteBufMsg.resetReaderIndex();
+                pending.remove();
+            }
+
         } catch (final WritePendingException e) {
-            queueRequest(ctx, byteBufMsg, promise);
+
+            if(wasPending == false){
+                queueRequest(ctx, byteBufMsg, promise);
+            }
         }
     }
 
     private synchronized void writePendingIfAny() {
+
         if (pending.peek() == null) {
             return;
         }
 
-        // In case of pending, reschedule next message from queue
-        final PendingWriteRequest pendingWrite = pending.poll();
+        final PendingWriteRequest pendingWrite = pending.peek();
         final ByteBuf msg = pendingWrite.msg;
         if (LOG.isTraceEnabled()) {
             LOG.trace("Writing pending request on channel: {}, message: {}", pendingWrite.ctx.channel(), byteBufToString(msg));
         }
 
-        writeWithPendingDetection(pendingWrite.ctx, pendingWrite.promise, msg);
+        writeWithPendingDetection(pendingWrite.ctx, pendingWrite.promise, msg, true);
     }
 
     public static String byteBufToString(final ByteBuf msg) {
-        msg.resetReaderIndex();
         final String s = msg.toString(Charsets.UTF_8);
         msg.resetReaderIndex();
         return s;
@@ -144,6 +157,7 @@ public final class AsyncSshHandlerWriter implements AutoCloseable {
 
     private Buffer toBuffer(final ByteBuf msg) {
         // TODO Buffer vs ByteBuf translate, Can we handle that better ?
+        msg.resetReaderIndex();
         final byte[] temp = new byte[msg.readableBytes()];
         msg.readBytes(temp, 0, msg.readableBytes());
         return new Buffer(temp);
index 7946afd..3a1b26d 100644 (file)
@@ -19,12 +19,13 @@ import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.verifyZeroInteractions;
-
 import com.google.common.base.Optional;
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelHandler;
 import io.netty.channel.ChannelPipeline;
+import io.netty.handler.codec.ByteToMessageDecoder;
+import io.netty.handler.codec.MessageToByteEncoder;
 import java.util.Collections;
 import org.junit.Before;
 import org.junit.Test;
@@ -34,7 +35,6 @@ import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfSessionListener;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
 import org.opendaylight.controller.netconf.nettyutil.handler.exi.NetconfStartExiMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessage;
 import org.opendaylight.controller.netconf.util.messages.NetconfHelloMessageAdditionalHeader;
@@ -115,7 +115,7 @@ public class AbstractNetconfSessionTest {
         testingNetconfSession = spy(testingNetconfSession);
 
         testingNetconfSession.startExiCommunication(NetconfStartExiMessage.create(new EXIOptions(), "4"));
-        verify(testingNetconfSession).addExiHandlers(any(NetconfEXICodec.class));
+        verify(testingNetconfSession).addExiHandlers(any(ByteToMessageDecoder.class), any(MessageToByteEncoder.class));
     }
 
     @Test
@@ -148,7 +148,7 @@ public class AbstractNetconfSessionTest {
         }
 
         @Override
-        protected void addExiHandlers(final NetconfEXICodec exiCodec) {}
+        protected void addExiHandlers(final ByteToMessageDecoder decoder, final MessageToByteEncoder<NetconfMessage> encoder) {}
 
         @Override
         public void stopExiCommunication() {}
index 4f804ab..666da8a 100644 (file)
@@ -10,7 +10,6 @@ package org.opendaylight.controller.netconf.nettyutil.handler;
 
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
-
 import com.google.common.collect.Lists;
 import io.netty.buffer.ByteBuf;
 import io.netty.buffer.Unpooled;
@@ -41,8 +40,8 @@ public class NetconfEXIHandlersTest {
     @Before
     public void setUp() throws Exception {
         final NetconfEXICodec codec = new NetconfEXICodec(new EXIOptions());
-        netconfMessageToEXIEncoder = new NetconfMessageToEXIEncoder(codec);
-        netconfEXIToMessageDecoder = new NetconfEXIToMessageDecoder(codec);
+        netconfMessageToEXIEncoder = NetconfMessageToEXIEncoder.create(codec);
+        netconfEXIToMessageDecoder = NetconfEXIToMessageDecoder.create(codec);
 
         msg = new NetconfMessage(XmlUtil.readXmlToDocument(msgAsString));
         this.msgAsExi = msgToExi(msgAsString, codec);
index e441c70..e52fce7 100644 (file)
@@ -46,7 +46,7 @@ public final class Main {
 
     private static final Logger LOG = LoggerFactory.getLogger(Main.class);
 
-    static class Params {
+    public static class Params {
 
         @Arg(dest = "schemas-dir")
         public File schemasDir;
index 5dd5a90..a0458c4 100644 (file)
@@ -1,4 +1,4 @@
-<rpc message-id="a" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
+<rpc message-id="101" a="64" xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
     <edit-config>
         <target>
             <candidate/>
diff --git a/pom.xml b/pom.xml
index 87a69e0..3bfffaa 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -7,12 +7,16 @@
     <version>1.1.0-SNAPSHOT</version>
     <relativePath>opendaylight/commons/parent</relativePath>
   </parent>
+
   <artifactId>releasepom</artifactId>
   <version>0.2.0-SNAPSHOT</version>
   <packaging>pom</packaging>
+  <name>controller</name> <!-- Used by Sonar to set project name -->
+
   <prerequisites>
     <maven>3.0</maven>
   </prerequisites>
+
   <modules>
 
     <!-- md-sal -->

©2013 OpenDaylight, A Linux Foundation Collaborative Project. All Rights Reserved.
OpenDaylight is a registered trademark of The OpenDaylight Project, Inc.
Linux Foundation and OpenDaylight are registered trademarks of the Linux Foundation.
Linux is a registered trademark of Linus Torvalds.