Merge "Bring features/neutron into the same parent dir as everything else"
authorTony Tkacik <ttkacik@cisco.com>
Fri, 13 Feb 2015 13:40:23 +0000 (13:40 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 13 Feb 2015 13:40:23 +0000 (13:40 +0000)
78 files changed:
opendaylight/adsal/adsal-enunciate-parent/enunciate.xml [new file with mode: 0644]
opendaylight/adsal/adsal-enunciate-parent/pom.xml [new file with mode: 0644]
opendaylight/adsal/northbound/connectionmanager/pom.xml
opendaylight/adsal/northbound/containermanager/pom.xml
opendaylight/adsal/northbound/controllermanager/pom.xml
opendaylight/adsal/northbound/flowprogrammer/pom.xml
opendaylight/adsal/northbound/hosttracker/pom.xml
opendaylight/adsal/northbound/java-client/pom.xml
opendaylight/adsal/northbound/networkconfiguration/bridgedomain/pom.xml
opendaylight/adsal/northbound/staticrouting/pom.xml
opendaylight/adsal/northbound/statistics/pom.xml
opendaylight/adsal/northbound/subnets/pom.xml
opendaylight/adsal/northbound/switchmanager/pom.xml
opendaylight/adsal/northbound/topology/pom.xml
opendaylight/adsal/northbound/usermanager/pom.xml
opendaylight/adsal/pom.xml
opendaylight/adsal/samples/northbound/loadbalancer/pom.xml
opendaylight/commons/enunciate-parent/enunciate.xml [new file with mode: 0644]
opendaylight/commons/enunciate-parent/pom.xml [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/RaftActorTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderElectionScenariosTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderTest.java
opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/utils/MessageCollectorActor.java
opendaylight/md-sal/sal-akka-raft/src/test/resources/simplelogger.properties [new file with mode: 0644]
opendaylight/md-sal/sal-clustering-config/src/main/resources/initial/akka.conf
opendaylight/md-sal/sal-distributed-datastore/src/test/resources/simplelogger.properties [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcAvailabilityListener.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcIdentifier.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementation.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationNotAvailableException.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcProviderService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcResult.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMRpcRoutingTableEntry.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRouter.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRoutingTable.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/GlobalDOMRpcRoutingTableEntry.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/RoutedDOMRpcRoutingTableEntry.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/UnknownDOMRpcRoutingTableEntry.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcImplementationRegistration.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcProviderService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/DefaultDOMRpcResult.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcImplementation.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcProviderService.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcResult.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcService.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/DataList.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/DataList.java with 93% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCommit.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedCommit.java with 85% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java [new file with mode: 0644]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedEditConfig.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedEditConfig.java with 91% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedGet.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGet.java with 87% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedGetConfig.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedGetConfig.java with 87% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedLock.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedLock.java with 85% similarity]
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedUnLock.java [moved from opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/SimulatedUnLock.java with 85% similarity]
opendaylight/networkconfiguration/neutron/implementation/pom.xml
opendaylight/networkconfiguration/neutron/northbound/pom.xml
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupsNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRulesNorthbound.java
opendaylight/networkconfiguration/neutron/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
opendaylight/networkconfiguration/neutron/pom.xml
pom.xml

diff --git a/opendaylight/adsal/adsal-enunciate-parent/enunciate.xml b/opendaylight/adsal/adsal-enunciate-parent/enunciate.xml
new file mode 100644 (file)
index 0000000..431ea7b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ copyright (c) 2015 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
+-->
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.28.xsd">
+</enunciate>
+
diff --git a/opendaylight/adsal/adsal-enunciate-parent/pom.xml b/opendaylight/adsal/adsal-enunciate-parent/pom.xml
new file mode 100644 (file)
index 0000000..11e3667
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ copyright (c) 2015 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
+-->
+<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">
+
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>enunciate-parent</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <relativePath>../../commons/enunciate-parent</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>adsal-enunciate-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <build>
+        <pluginManagement>
+            <plugins>
+                <plugin>
+                    <groupId>org.codehaus.enunciate</groupId>
+                    <artifactId>maven-enunciate-plugin</artifactId>
+                    <dependencies>
+                        <dependency>
+                            <groupId>org.opendaylight.controller</groupId>
+                            <artifactId>sal</artifactId>
+                            <version>${sal.version}</version>
+                        </dependency>
+                    </dependencies>
+                </plugin>
+            </plugins>
+        </pluginManagement>
+    </build>
+</project>
+
index b68bc25..7cc1248 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>connectionmanager.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 8898a06..1bc170a 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../../commons/enunciate-parent</relativePath>
   </parent>
 
   <artifactId>containermanager.northbound</artifactId>
           </instructions>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 395dd2d..20cff42 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
   <artifactId>controllermanager.northbound</artifactId>
   <version>0.1.0-SNAPSHOT</version>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index fdc7340..3c2aed1 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>flowprogrammer.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 778125a..4dea525 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
   <artifactId>hosttracker.northbound</artifactId>
   <version>0.5.0-SNAPSHOT</version>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 5a4c18e..df6b86e 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../../commons/enunciate-parent</relativePath>
   </parent>
 
   <artifactId>northbound.client</artifactId>
           </execution>
         </executions>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-      </plugin>
 
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
index f78ff96..659bfe9 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../../commons/opendaylight</relativePath>
+    <relativePath>../../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>networkconfig.bridgedomain.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 3a89369..be84c61 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>forwarding.staticrouting.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 0d42ffb..9e98a75 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>statistics.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 1eaa45d..7a96bdc 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>subnets.northbound</artifactId>
     </dependency>
   </dependencies>
   <build>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.codehaus.enunciate</groupId>
+          <artifactId>maven-enunciate-plugin</artifactId>
+          <dependencies>
+            <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>clustering.services</artifactId>
+              <version>${clustering.services.version}</version>
+            </dependency>
+            <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>configuration</artifactId>
+              <version>${configuration.version}</version>
+            </dependency>
+            <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>sal</artifactId>
+              <version>${sal.version}</version>
+            </dependency>
+            <dependency>
+              <groupId>org.opendaylight.controller</groupId>
+              <artifactId>switchmanager</artifactId>
+              <version>${switchmanager.api.version}</version>
+            </dependency>
+          </dependencies>
+        </plugin>
+      </plugins>
+    </pluginManagement>
     <plugins>
       <plugin>
         <groupId>org.apache.felix</groupId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>clustering.services</artifactId>
-            <version>${clustering.services.version}</version>
-          </dependency>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>configuration</artifactId>
-            <version>${configuration.version}</version>
-          </dependency>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>switchmanager</artifactId>
-            <version>${switchmanager.api.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index b7aaae5..c3c3804 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
   <artifactId>switchmanager.northbound</artifactId>
   <version>0.5.0-SNAPSHOT</version>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 60a1270..62399c5 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>topology.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
index e51ef2f..b08995f 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../../commons/enunciate-parent</relativePath>
   </parent>
 
   <artifactId>usermanager.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 23db4d5..682d2a0 100644 (file)
@@ -95,6 +95,7 @@
     <module>samples/northbound/loadbalancer</module>
 
     <module>dummy-console</module>
+    <module>adsal-enunciate-parent</module>
 
     <!-- features -->
     <module>features/base</module>
index e63e992..b5ca85e 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>adsal-enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../../commons/opendaylight</relativePath>
+    <relativePath>../../../adsal-enunciate-parent</relativePath>
   </parent>
 
   <artifactId>samples.loadbalancer.northbound</artifactId>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-        <dependencies>
-          <dependency>
-            <groupId>org.opendaylight.controller</groupId>
-            <artifactId>sal</artifactId>
-            <version>${sal.version}</version>
-          </dependency>
-        </dependencies>
-      </plugin>
     </plugins>
   </build>
   <scm>
diff --git a/opendaylight/commons/enunciate-parent/enunciate.xml b/opendaylight/commons/enunciate-parent/enunciate.xml
new file mode 100644 (file)
index 0000000..431ea7b
--- /dev/null
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ copyright (c) 2015 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
+-->
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.28.xsd">
+</enunciate>
+
diff --git a/opendaylight/commons/enunciate-parent/pom.xml b/opendaylight/commons/enunciate-parent/pom.xml
new file mode 100644 (file)
index 0000000..2b89137
--- /dev/null
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ copyright (c) 2015 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
+-->
+<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">
+
+    <parent>
+        <groupId>org.opendaylight.controller</groupId>
+        <artifactId>commons.opendaylight</artifactId>
+        <version>1.5.0-SNAPSHOT</version>
+        <relativePath>../opendaylight</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>enunciate-parent</artifactId>
+    <packaging>pom</packaging>
+
+    <!-- enunciate plugin does not work with JDK8 onwards -->
+    <profiles>
+        <profile>
+            <id>non-java8</id>
+            <activation>
+                <jdk>1.7</jdk>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.codehaus.enunciate</groupId>
+                        <artifactId>maven-enunciate-plugin</artifactId>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+</project>
+
index 9e0e06c..56bf620 100644 (file)
@@ -50,6 +50,7 @@ import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.cluster.DataPersistenceProvider;
 import org.opendaylight.controller.cluster.datastore.DataPersistenceProviderMonitor;
@@ -77,9 +78,16 @@ import scala.concurrent.duration.FiniteDuration;
 
 public class RaftActorTest extends AbstractActorTest {
 
+    private TestActorFactory factory;
+
+    @Before
+    public void setUp(){
+        factory = new TestActorFactory(getSystem());
+    }
 
     @After
-    public void tearDown() {
+    public void tearDown() throws Exception {
+        factory.close();
         MockAkkaJournal.clearJournal();
         MockSnapshotStore.setMockSnapshot(null);
     }
@@ -337,7 +345,7 @@ public class RaftActorTest extends AbstractActorTest {
     @Test
     public void testRaftActorRecovery() throws Exception {
         new JavaTestKit(getSystem()) {{
-            String persistenceId = "follower10";
+            String persistenceId = factory.generateActorId("follower-");
 
             DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
             // Set the heartbeat interval high to essentially disable election otherwise the test
@@ -345,8 +353,8 @@ public class RaftActorTest extends AbstractActorTest {
             // log entry.
             config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-            ActorRef followerActor = getSystem().actorOf(MockRaftActor.props(persistenceId,
-                    Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config)), persistenceId);
+            ActorRef followerActor = factory.createActor(MockRaftActor.props(persistenceId,
+                    Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config)), persistenceId);
 
             watch(followerActor);
 
@@ -358,15 +366,15 @@ public class RaftActorTest extends AbstractActorTest {
             int lastAppliedDuringSnapshotCapture = 3;
             int lastIndexDuringSnapshotCapture = 4;
 
-                // 4 messages as part of snapshot, which are applied to state
-            ByteString snapshotBytes  = fromObject(Arrays.asList(
+            // 4 messages as part of snapshot, which are applied to state
+            ByteString snapshotBytes = fromObject(Arrays.asList(
                     new MockRaftActorContext.MockPayload("A"),
                     new MockRaftActorContext.MockPayload("B"),
                     new MockRaftActorContext.MockPayload("C"),
                     new MockRaftActorContext.MockPayload("D")));
 
             Snapshot snapshot = Snapshot.create(snapshotBytes.toByteArray(),
-                    snapshotUnappliedEntries, lastIndexDuringSnapshotCapture, 1 ,
+                    snapshotUnappliedEntries, lastIndexDuringSnapshotCapture, 1,
                     lastAppliedDuringSnapshotCapture, 1);
             MockSnapshotStore.setMockSnapshot(snapshot);
             MockSnapshotStore.setPersistenceId(persistenceId);
@@ -399,8 +407,8 @@ public class RaftActorTest extends AbstractActorTest {
             unwatch(followerActor);
 
             //reinstate the actor
-            TestActorRef<MockRaftActor> ref = TestActorRef.create(getSystem(),
-                    MockRaftActor.props(persistenceId, Collections.<String,String>emptyMap(),
+            TestActorRef<MockRaftActor> ref = factory.createTestActor(
+                    MockRaftActor.props(persistenceId, Collections.<String, String>emptyMap(),
                             Optional.<ConfigParams>of(config)));
 
             ref.underlyingActor().waitForRecoveryComplete();
@@ -426,28 +434,28 @@ public class RaftActorTest extends AbstractActorTest {
     public void testHandleRecoveryWhenDataPersistenceRecoveryApplicable() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testHandleRecoveryWhenDataPersistenceRecoveryApplicable";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config)), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config)), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
                 // Wait for akka's recovery to complete so it doesn't interfere.
                 mockRaftActor.waitForRecoveryComplete();
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
                         new MockRaftActorContext.MockPayload("C"),
                         new MockRaftActorContext.MockPayload("D")));
 
                 Snapshot snapshot = Snapshot.create(snapshotBytes.toByteArray(),
-                        Lists.<ReplicatedLogEntry>newArrayList(), 3, 1 ,3, 1);
+                        Lists.<ReplicatedLogEntry>newArrayList(), 3, 13, 1);
 
                 mockRaftActor.onReceiveRecover(new SnapshotOffer(new SnapshotMetadata(persistenceId, 100, 100), snapshot));
 
@@ -480,8 +488,6 @@ public class RaftActorTest extends AbstractActorTest {
 
                 mockRaftActor.onReceiveRecover(mock(RecoveryCompleted.class));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }};
     }
 
@@ -495,28 +501,28 @@ public class RaftActorTest extends AbstractActorTest {
     public void testHandleRecoveryWhenDataPersistenceRecoveryNotApplicable() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testHandleRecoveryWhenDataPersistenceRecoveryNotApplicable";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), new DataPersistenceProviderMonitor()), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), new DataPersistenceProviderMonitor()), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
                 // Wait for akka's recovery to complete so it doesn't interfere.
                 mockRaftActor.waitForRecoveryComplete();
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
                         new MockRaftActorContext.MockPayload("C"),
                         new MockRaftActorContext.MockPayload("D")));
 
                 Snapshot snapshot = Snapshot.create(snapshotBytes.toByteArray(),
-                        Lists.<ReplicatedLogEntry>newArrayList(), 3, 1 ,3, 1);
+                        Lists.<ReplicatedLogEntry>newArrayList(), 3, 13, 1);
 
                 mockRaftActor.onReceiveRecover(new SnapshotOffer(new SnapshotMetadata(persistenceId, 100, 100), snapshot));
 
@@ -547,7 +553,6 @@ public class RaftActorTest extends AbstractActorTest {
 
                 mockRaftActor.onReceiveRecover(mock(RecoveryCompleted.class));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
             }};
     }
 
@@ -556,7 +561,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testUpdatingElectionTermCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testUpdatingElectionTermCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -566,8 +571,8 @@ public class RaftActorTest extends AbstractActorTest {
                 DataPersistenceProviderMonitor dataPersistenceProviderMonitor = new DataPersistenceProviderMonitor();
                 dataPersistenceProviderMonitor.setPersistLatch(persistLatch);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
@@ -575,9 +580,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 assertEquals("Persist called", true, persistLatch.await(5, TimeUnit.SECONDS));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
+
         };
     }
 
@@ -585,7 +589,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testAddingReplicatedLogEntryCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testAddingReplicatedLogEntryCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -593,8 +597,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
@@ -604,9 +608,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(dataPersistenceProvider).persist(eq(logEntry), any(Procedure.class));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
+
         };
     }
 
@@ -614,7 +617,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testRemovingReplicatedLogEntryCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testRemovingReplicatedLogEntryCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -622,8 +625,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
@@ -633,9 +636,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(dataPersistenceProvider, times(2)).persist(anyObject(), any(Procedure.class));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
+
         };
     }
 
@@ -643,7 +645,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testApplyLogEntriesCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testApplyLogEntriesCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -651,8 +653,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
@@ -660,9 +662,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(dataPersistenceProvider, times(1)).persist(anyObject(), any(Procedure.class));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
+
         };
     }
 
@@ -670,7 +671,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testCaptureSnapshotReplyCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testCaptureSnapshotReplyCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -678,19 +679,19 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
-                    MockRaftActor.props(persistenceId,Collections.<String,String>emptyMap(),
-                        Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
+                        MockRaftActor.props(persistenceId, Collections.<String, String>emptyMap(),
+                                Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
                         new MockRaftActorContext.MockPayload("C"),
                         new MockRaftActorContext.MockPayload("D")));
 
-                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1,1,-1,1));
+                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, -1, 1));
 
                 RaftActorContext raftActorContext = mockRaftActor.getRaftActorContext();
 
@@ -700,8 +701,6 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(dataPersistenceProvider).saveSnapshot(anyObject());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -710,7 +709,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testSaveSnapshotSuccessCallsDataPersistence() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testSaveSnapshotSuccessCallsDataPersistence";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -718,16 +717,16 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
-                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1,0, mock(Payload.class)));
-                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1,1, mock(Payload.class)));
-                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1,2, mock(Payload.class)));
-                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1,3, mock(Payload.class)));
-                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1,4, mock(Payload.class)));
+                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 0, mock(Payload.class)));
+                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 1, mock(Payload.class)));
+                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 2, mock(Payload.class)));
+                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 3, mock(Payload.class)));
+                mockRaftActor.getReplicatedLog().append(new MockRaftActorContext.MockReplicatedLogEntry(1, 4, mock(Payload.class)));
 
                 ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
@@ -758,8 +757,6 @@ public class RaftActorTest extends AbstractActorTest {
                 // Index 2 will not be in the log because it was removed due to snapshotting
                 assertNull(mockRaftActor.getReplicatedLog().get(2));
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -769,7 +766,7 @@ public class RaftActorTest extends AbstractActorTest {
 
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testApplyState";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -777,8 +774,8 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
@@ -789,8 +786,6 @@ public class RaftActorTest extends AbstractActorTest {
 
                 verify(mockRaftActor.delegate).applyState(eq(mockActorRef), eq("apply-state"), anyObject());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -799,7 +794,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testApplySnapshot() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testApplySnapshot";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -807,24 +802,24 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProviderMonitor dataPersistenceProviderMonitor = new DataPersistenceProviderMonitor();
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
                 ReplicatedLog oldReplicatedLog = mockRaftActor.getReplicatedLog();
 
-                oldReplicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,0,mock(Payload.class)));
-                oldReplicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1,1,mock(Payload.class)));
+                oldReplicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, 0, mock(Payload.class)));
+                oldReplicatedLog.append(new MockRaftActorContext.MockReplicatedLogEntry(1, 1, mock(Payload.class)));
                 oldReplicatedLog.append(
-                    new MockRaftActorContext.MockReplicatedLogEntry(1, 2,
-                        mock(Payload.class)));
+                        new MockRaftActorContext.MockReplicatedLogEntry(1, 2,
+                                mock(Payload.class)));
 
                 ByteString snapshotBytes = fromObject(Arrays.asList(
-                    new MockRaftActorContext.MockPayload("A"),
-                    new MockRaftActorContext.MockPayload("B"),
-                    new MockRaftActorContext.MockPayload("C"),
-                    new MockRaftActorContext.MockPayload("D")));
+                        new MockRaftActorContext.MockPayload("A"),
+                        new MockRaftActorContext.MockPayload("B"),
+                        new MockRaftActorContext.MockPayload("C"),
+                        new MockRaftActorContext.MockPayload("D")));
 
                 Snapshot snapshot = mock(Snapshot.class);
 
@@ -837,15 +832,13 @@ public class RaftActorTest extends AbstractActorTest {
                 verify(mockRaftActor.delegate).applySnapshot(eq(snapshot.getState()));
 
                 assertTrue("The replicatedLog should have changed",
-                    oldReplicatedLog != mockRaftActor.getReplicatedLog());
+                        oldReplicatedLog != mockRaftActor.getReplicatedLog());
 
                 assertEquals("lastApplied should be same as in the snapshot",
-                    (Long) 3L, mockRaftActor.getLastApplied());
+                        (Long) 3L, mockRaftActor.getLastApplied());
 
                 assertEquals(0, mockRaftActor.getReplicatedLog().size());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -854,7 +847,7 @@ public class RaftActorTest extends AbstractActorTest {
     public void testSaveSnapshotFailure() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "testSaveSnapshotFailure";
+                String persistenceId = factory.generateActorId("leader-");
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
 
@@ -862,12 +855,12 @@ public class RaftActorTest extends AbstractActorTest {
 
                 DataPersistenceProviderMonitor dataPersistenceProviderMonitor = new DataPersistenceProviderMonitor();
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(persistenceId,
-                        Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(MockRaftActor.props(persistenceId,
+                        Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), dataPersistenceProviderMonitor), persistenceId);
 
                 MockRaftActor mockRaftActor = mockActorRef.underlyingActor();
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("A"),
                         new MockRaftActorContext.MockPayload("B"),
                         new MockRaftActorContext.MockPayload("C"),
@@ -877,7 +870,7 @@ public class RaftActorTest extends AbstractActorTest {
 
                 mockRaftActor.setCurrentBehavior(new Leader(raftActorContext));
 
-                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1,1,-1,1));
+                mockRaftActor.onReceiveCommand(new CaptureSnapshot(-1, 1, -1, 1));
 
                 mockRaftActor.onReceiveCommand(new CaptureSnapshotReply(snapshotBytes.toByteArray()));
 
@@ -887,8 +880,6 @@ public class RaftActorTest extends AbstractActorTest {
                 assertEquals("Snapshot index should not have advanced because save snapshot failed", -1,
                         mockRaftActor.getReplicatedLog().getSnapshotIndex());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -896,35 +887,35 @@ public class RaftActorTest extends AbstractActorTest {
     @Test
     public void testRaftRoleChangeNotifier() throws Exception {
         new JavaTestKit(getSystem()) {{
-            ActorRef notifierActor = getSystem().actorOf(Props.create(MessageCollectorActor.class));
+            ActorRef notifierActor = factory.createActor(Props.create(MessageCollectorActor.class));
             DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
-            String id = "testRaftRoleChangeNotifier";
+            String persistenceId = factory.generateActorId("notifier-");
 
-            TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(), MockRaftActor.props(id,
-                Collections.<String,String>emptyMap(), Optional.<ConfigParams>of(config), notifierActor), id);
+            factory.createTestActor(MockRaftActor.props(persistenceId,
+                    Collections.<String, String>emptyMap(), Optional.<ConfigParams>of(config), notifierActor), persistenceId);
 
             // sleeping for a minimum of 2 seconds, if it spans more its fine.
             Uninterruptibles.sleepUninterruptibly(2, TimeUnit.SECONDS);
 
-            List<Object> matches =  MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
+            List<Object> matches = MessageCollectorActor.getAllMatching(notifierActor, RoleChanged.class);
             assertNotNull(matches);
             assertEquals(3, matches.size());
 
             // check if the notifier got a role change from null to Follower
             RoleChanged raftRoleChanged = (RoleChanged) matches.get(0);
-            assertEquals(id, raftRoleChanged.getMemberId());
+            assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertNull(raftRoleChanged.getOldRole());
             assertEquals(RaftState.Follower.name(), raftRoleChanged.getNewRole());
 
             // check if the notifier got a role change from Follower to Candidate
             raftRoleChanged = (RoleChanged) matches.get(1);
-            assertEquals(id, raftRoleChanged.getMemberId());
+            assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertEquals(RaftState.Follower.name(), raftRoleChanged.getOldRole());
             assertEquals(RaftState.Candidate.name(), raftRoleChanged.getNewRole());
 
             // check if the notifier got a role change from Candidate to Leader
             raftRoleChanged = (RoleChanged) matches.get(2);
-            assertEquals(id, raftRoleChanged.getMemberId());
+            assertEquals(persistenceId, raftRoleChanged.getMemberId());
             assertEquals(RaftState.Candidate.name(), raftRoleChanged.getOldRole());
             assertEquals(RaftState.Leader.name(), raftRoleChanged.getNewRole());
         }};
@@ -934,10 +925,11 @@ public class RaftActorTest extends AbstractActorTest {
     public void testFakeSnapshotsForLeaderWithInRealSnapshots() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "leader1";
+                String persistenceId = factory.generateActorId("leader-");
+                String follower1Id = factory.generateActorId("follower-");
 
                 ActorRef followerActor1 =
-                        getSystem().actorOf(Props.create(MessageCollectorActor.class));
+                        factory.createActor(Props.create(MessageCollectorActor.class));
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
@@ -946,7 +938,7 @@ public class RaftActorTest extends AbstractActorTest {
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
                 Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1", followerActor1.path().toString());
+                peerAddresses.put(follower1Id, followerActor1.path().toString());
 
                 TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
                         MockRaftActor.props(persistenceId, peerAddresses,
@@ -970,7 +962,7 @@ public class RaftActorTest extends AbstractActorTest {
 
                 assertEquals(8, leaderActor.getReplicatedLog().size());
 
-                leaderActor.onReceiveCommand(new CaptureSnapshot(6,1,4,1));
+                leaderActor.onReceiveCommand(new CaptureSnapshot(6, 1, 4, 1));
                 leaderActor.getRaftActorContext().setSnapshotCaptureInitiated(true);
                 verify(leaderActor.delegate).createSnapshot();
 
@@ -978,20 +970,20 @@ public class RaftActorTest extends AbstractActorTest {
 
                 assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
                 //fake snapshot on index 5
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-1", 1, true, 5, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 5, 1));
 
                 assertEquals(8, leaderActor.getReplicatedLog().size());
 
                 //fake snapshot on index 6
                 assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-1", 1, true, 6, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 6, 1));
                 assertEquals(8, leaderActor.getReplicatedLog().size());
 
                 assertEquals(RaftState.Leader, leaderActor.getCurrentBehavior().state());
 
                 assertEquals(8, leaderActor.getReplicatedLog().size());
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("foo-0"),
                         new MockRaftActorContext.MockPayload("foo-1"),
                         new MockRaftActorContext.MockPayload("foo-2"),
@@ -1009,12 +1001,10 @@ public class RaftActorTest extends AbstractActorTest {
                         new ReplicatedLogImplEntry(8, 1, new MockRaftActorContext.MockPayload("foo-8")));
 
                 //fake snapshot on index 7, since lastApplied = 7 , we would keep the last applied
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-1", 1, true, 7, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 7, 1));
                 assertEquals(2, leaderActor.getReplicatedLog().size());
                 assertEquals(8, leaderActor.getReplicatedLog().lastIndex());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -1023,10 +1013,12 @@ public class RaftActorTest extends AbstractActorTest {
     public void testFakeSnapshotsForFollowerWithInRealSnapshots() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "follower1";
+                String persistenceId = factory.generateActorId("follower-");
+                String leaderId = factory.generateActorId("leader-");
+
 
                 ActorRef leaderActor1 =
-                        getSystem().actorOf(Props.create(MessageCollectorActor.class));
+                        factory.createActor(Props.create(MessageCollectorActor.class));
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
@@ -1035,7 +1027,7 @@ public class RaftActorTest extends AbstractActorTest {
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
                 Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("leader", leaderActor1.path().toString());
+                peerAddresses.put(leaderId, leaderActor1.path().toString());
 
                 TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
                         MockRaftActor.props(persistenceId, peerAddresses,
@@ -1060,7 +1052,7 @@ public class RaftActorTest extends AbstractActorTest {
                 assertEquals(6, followerActor.getReplicatedLog().size());
 
                 //snapshot on 4
-                followerActor.onReceiveCommand(new CaptureSnapshot(5,1,4,1));
+                followerActor.onReceiveCommand(new CaptureSnapshot(5, 1, 4, 1));
                 followerActor.getRaftActorContext().setSnapshotCaptureInitiated(true);
                 verify(followerActor.delegate).createSnapshot();
 
@@ -1072,7 +1064,7 @@ public class RaftActorTest extends AbstractActorTest {
                                 (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(1, 6,
                                         new MockRaftActorContext.MockPayload("foo-6"))
                         );
-                followerActor.onReceiveCommand(new AppendEntries(1, "leader", 5, 1, entries , 5, 5));
+                followerActor.onReceiveCommand(new AppendEntries(1, leaderId, 5, 1, entries, 5, 5));
                 assertEquals(7, followerActor.getReplicatedLog().size());
 
                 //fake snapshot on index 7
@@ -1083,13 +1075,13 @@ public class RaftActorTest extends AbstractActorTest {
                                 (ReplicatedLogEntry) new MockRaftActorContext.MockReplicatedLogEntry(1, 7,
                                         new MockRaftActorContext.MockPayload("foo-7"))
                         );
-                followerActor.onReceiveCommand(new AppendEntries(1, "leader", 6, 1, entries, 6, 6));
+                followerActor.onReceiveCommand(new AppendEntries(1, leaderId, 6, 1, entries, 6, 6));
                 assertEquals(8, followerActor.getReplicatedLog().size());
 
                 assertEquals(RaftState.Follower, followerActor.getCurrentBehavior().state());
 
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("foo-0"),
                         new MockRaftActorContext.MockPayload("foo-1"),
                         new MockRaftActorContext.MockPayload("foo-2"),
@@ -1108,13 +1100,11 @@ public class RaftActorTest extends AbstractActorTest {
                                         new MockRaftActorContext.MockPayload("foo-7"))
                         );
                 // send an additional entry 8 with leaderCommit = 7
-                followerActor.onReceiveCommand(new AppendEntries(1, "leader", 7, 1, entries , 7, 7));
+                followerActor.onReceiveCommand(new AppendEntries(1, leaderId, 7, 1, entries, 7, 7));
 
                 // 7 and 8, as lastapplied is 7
                 assertEquals(2, followerActor.getReplicatedLog().size());
 
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
@@ -1123,12 +1113,14 @@ public class RaftActorTest extends AbstractActorTest {
     public void testFakeSnapshotsForLeaderWithInInitiateSnapshots() throws Exception {
         new JavaTestKit(getSystem()) {
             {
-                String persistenceId = "leader1";
+                String persistenceId = factory.generateActorId("leader-");
+                String follower1Id = factory.generateActorId("follower-");
+                String follower2Id = factory.generateActorId("follower-");
 
                 ActorRef followerActor1 =
-                        getSystem().actorOf(Props.create(MessageCollectorActor.class));
+                        factory.createActor(Props.create(MessageCollectorActor.class), follower1Id);
                 ActorRef followerActor2 =
-                        getSystem().actorOf(Props.create(MessageCollectorActor.class));
+                        factory.createActor(Props.create(MessageCollectorActor.class), follower2Id);
 
                 DefaultConfigParamsImpl config = new DefaultConfigParamsImpl();
                 config.setHeartBeatInterval(new FiniteDuration(1, TimeUnit.DAYS));
@@ -1137,10 +1129,10 @@ public class RaftActorTest extends AbstractActorTest {
                 DataPersistenceProvider dataPersistenceProvider = mock(DataPersistenceProvider.class);
 
                 Map<String, String> peerAddresses = new HashMap<>();
-                peerAddresses.put("follower-1", followerActor1.path().toString());
-                peerAddresses.put("follower-2", followerActor2.path().toString());
+                peerAddresses.put(follower1Id, followerActor1.path().toString());
+                peerAddresses.put(follower2Id, followerActor2.path().toString());
 
-                TestActorRef<MockRaftActor> mockActorRef = TestActorRef.create(getSystem(),
+                TestActorRef<MockRaftActor> mockActorRef = factory.createTestActor(
                         MockRaftActor.props(persistenceId, peerAddresses,
                                 Optional.<ConfigParams>of(config), dataPersistenceProvider), persistenceId);
 
@@ -1162,26 +1154,26 @@ public class RaftActorTest extends AbstractActorTest {
                 leaderActor.getRaftActorContext().getReplicatedLog().setSnapshotIndex(4);
                 assertEquals(5, leaderActor.getReplicatedLog().size());
 
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-1", 1, true, 9, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower1Id, 1, true, 9, 1));
                 assertEquals(5, leaderActor.getReplicatedLog().size());
 
                 // set the 2nd follower nextIndex to 1 which has been snapshotted
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-2", 1, true, 0, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 0, 1));
                 assertEquals(5, leaderActor.getReplicatedLog().size());
 
                 // simulate a real snapshot
                 leaderActor.onReceiveCommand(new InitiateInstallSnapshot());
                 assertEquals(5, leaderActor.getReplicatedLog().size());
                 assertEquals(String.format("expected to be Leader but was %s. Current Leader = %s ",
-                        leaderActor.getCurrentBehavior().state(),leaderActor.getLeaderId())
+                        leaderActor.getCurrentBehavior().state(), leaderActor.getLeaderId())
                         , RaftState.Leader, leaderActor.getCurrentBehavior().state());
 
 
                 //reply from a slow follower does not initiate a fake snapshot
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-2", 1, true, 9, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 9, 1));
                 assertEquals("Fake snapshot should not happen when Initiate is in progress", 5, leaderActor.getReplicatedLog().size());
 
-                ByteString snapshotBytes  = fromObject(Arrays.asList(
+                ByteString snapshotBytes = fromObject(Arrays.asList(
                         new MockRaftActorContext.MockPayload("foo-0"),
                         new MockRaftActorContext.MockPayload("foo-1"),
                         new MockRaftActorContext.MockPayload("foo-2"),
@@ -1193,17 +1185,12 @@ public class RaftActorTest extends AbstractActorTest {
                 assertEquals("Real snapshot didn't clear the log till lastApplied", 0, leaderActor.getReplicatedLog().size());
 
                 //reply from a slow follower after should not raise errors
-                leaderActor.onReceiveCommand(new AppendEntriesReply("follower-2", 1, true, 5, 1));
+                leaderActor.onReceiveCommand(new AppendEntriesReply(follower2Id, 1, true, 5, 1));
                 assertEquals(0, leaderActor.getReplicatedLog().size());
-
-                mockActorRef.tell(PoisonPill.getInstance(), getRef());
-
             }
         };
     }
 
-
-
     private ByteString fromObject(Object snapshot) throws Exception {
         ByteArrayOutputStream b = null;
         ObjectOutputStream o = null;
@@ -1223,4 +1210,5 @@ public class RaftActorTest extends AbstractActorTest {
             }
         }
     }
+
 }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/TestActorFactory.java
new file mode 100644 (file)
index 0000000..6872c8f
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * 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;
+
+/*
+ * 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
+ */
+
+import akka.actor.Actor;
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.PoisonPill;
+import akka.actor.Props;
+import akka.testkit.TestActorRef;
+import java.util.LinkedList;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * TestActorFactory provides methods to create both normal and test actors and to kill them when the factory is closed
+ * The ideal usage for TestActorFactory is with try with resources, <br/>
+ * For example <br/>
+ * <pre>
+ *     try (TestActorFactory factory = new TestActorFactory(getSystem())){
+ *         factory.createActor(props);
+ *         factory.createTestActor(props);
+ *         factory.generateActorId("leader-");
+ *     }
+ * </pre>
+ */
+public class TestActorFactory implements AutoCloseable {
+    private final ActorSystem system;
+    List<ActorRef> createdActors = new LinkedList<>();
+    Logger LOG = LoggerFactory.getLogger(getClass());
+    private static int actorCount = 1;
+
+    public TestActorFactory(ActorSystem system){
+        this.system = system;
+    }
+
+    /**
+     * Create a normal actor with an auto-generated name
+     *
+     * @param props
+     * @return
+     */
+    public ActorRef createActor(Props props){
+        ActorRef actorRef = system.actorOf(props);
+        createdActors.add(actorRef);
+        return actorRef;
+    }
+
+    /**
+     * Create a normal actor with the passed in name
+     * @param props
+     * @param actorId name of actor
+     * @return
+     */
+    public ActorRef createActor(Props props, String actorId){
+        ActorRef actorRef = system.actorOf(props, actorId);
+        createdActors.add(actorRef);
+        return actorRef;
+    }
+
+    /**
+     * Create a test actor with the passed in name
+     * @param props
+     * @param actorId
+     * @param <T>
+     * @return
+     */
+    public <T extends Actor> TestActorRef<T> createTestActor(Props props, String actorId){
+        TestActorRef<T> actorRef = TestActorRef.create(system, props, actorId);
+        createdActors.add(actorRef);
+        return actorRef;
+    }
+
+    /**
+     * Create a test actor with an auto-generated name
+     * @param props
+     * @param <T>
+     * @return
+     */
+    public <T extends Actor> TestActorRef<T> createTestActor(Props props){
+        TestActorRef<T> actorRef = TestActorRef.create(system, props);
+        createdActors.add(actorRef);
+        return actorRef;
+    }
+
+    /**
+     * Generate a friendly but unique actor id/name
+     * @param prefix
+     * @return
+     */
+    public String generateActorId(String prefix){
+        return prefix + actorCount++;
+    }
+
+    @Override
+    public void close() throws Exception {
+        for(ActorRef actor : createdActors){
+            LOG.info("Killing actor {}", actor);
+            actor.tell(PoisonPill.getInstance(), null);
+        }
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderElectionScenariosTest.java b/opendaylight/md-sal/sal-akka-raft/src/test/java/org/opendaylight/controller/cluster/raft/behaviors/LeaderElectionScenariosTest.java
new file mode 100644 (file)
index 0000000..3aac005
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+ * Copyright (c) 2015 Brocade Communications 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.behaviors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.dispatch.Dispatchers;
+import akka.testkit.JavaTestKit;
+import akka.testkit.TestActorRef;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.Uninterruptibles;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.raft.DefaultConfigParamsImpl;
+import org.opendaylight.controller.cluster.raft.MockRaftActorContext;
+import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockPayload;
+import org.opendaylight.controller.cluster.raft.MockRaftActorContext.MockReplicatedLogEntry;
+import org.opendaylight.controller.cluster.raft.MockRaftActorContext.SimpleReplicatedLog;
+import org.opendaylight.controller.cluster.raft.RaftActorContext;
+import org.opendaylight.controller.cluster.raft.RaftState;
+import org.opendaylight.controller.cluster.raft.base.messages.ElectionTimeout;
+import org.opendaylight.controller.cluster.raft.base.messages.SendHeartBeat;
+import org.opendaylight.controller.cluster.raft.messages.AppendEntries;
+import org.opendaylight.controller.cluster.raft.messages.AppendEntriesReply;
+import org.opendaylight.controller.cluster.raft.messages.RequestVote;
+import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
+import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.impl.SimpleLogger;
+import scala.concurrent.duration.FiniteDuration;
+
+/**
+ * Tests various leader election scenarios.
+ *
+ * @author Thomas Pantelis
+ */
+public class LeaderElectionScenariosTest {
+
+    private static final int HEARTBEAT_INTERVAL = 50;
+
+    public static class MemberActor extends MessageCollectorActor {
+
+        volatile RaftActorBehavior behavior;
+        Map<Class<?>, CountDownLatch> messagesReceivedLatches = new ConcurrentHashMap<>();
+        Map<Class<?>, Boolean> dropMessagesToBehavior = new ConcurrentHashMap<>();
+        CountDownLatch behaviorStateChangeLatch;
+
+        public static Props props() {
+            return Props.create(MemberActor.class).withDispatcher(Dispatchers.DefaultDispatcherId());
+        }
+
+        @Override
+        public void onReceive(Object message) throws Exception {
+            // Ignore scheduled SendHeartBeat messages.
+            if(message instanceof SendHeartBeat) {
+                return;
+            }
+
+            try {
+                if(behavior != null && !dropMessagesToBehavior.containsKey(message.getClass())) {
+                    RaftActorBehavior oldBehavior = behavior;
+                    behavior = behavior.handleMessage(getSender(), message);
+                    if(behavior != oldBehavior && behaviorStateChangeLatch != null) {
+                        behaviorStateChangeLatch.countDown();
+                    }
+                }
+            } finally {
+                super.onReceive(message);
+
+                CountDownLatch latch = messagesReceivedLatches.get(message.getClass());
+                if(latch != null) {
+                    latch.countDown();
+                }
+            }
+        }
+
+        void expectBehaviorStateChange() {
+            behaviorStateChangeLatch = new CountDownLatch(1);
+        }
+
+        void waitForBehaviorStateChange() {
+            assertTrue("Expected behavior state change",
+                    Uninterruptibles.awaitUninterruptibly(behaviorStateChangeLatch, 5, TimeUnit.SECONDS));
+        }
+
+        void expectMessageClass(Class<?> expClass, int expCount) {
+            messagesReceivedLatches.put(expClass, new CountDownLatch(expCount));
+        }
+
+        void waitForExpectedMessages(Class<?> expClass) {
+            CountDownLatch latch = messagesReceivedLatches.get(expClass);
+            assertNotNull("No messages received for " + expClass, latch);
+            assertTrue("Missing messages of type " + expClass,
+                    Uninterruptibles.awaitUninterruptibly(latch, 5, TimeUnit.SECONDS));
+        }
+
+        void dropMessagesToBehavior(Class<?> msgClass) {
+            dropMessagesToBehavior(msgClass, 1);
+        }
+
+        void dropMessagesToBehavior(Class<?> msgClass, int expCount) {
+            expectMessageClass(msgClass, expCount);
+            dropMessagesToBehavior.put(msgClass, Boolean.TRUE);
+        }
+
+        void clearDropMessagesToBehavior() {
+            dropMessagesToBehavior.clear();
+        }
+
+        @Override
+        public void clear() {
+            behaviorStateChangeLatch = null;
+            clearDropMessagesToBehavior();
+            messagesReceivedLatches.clear();
+            super.clear();
+        }
+
+        void forwardCapturedMessageToBehavior(Class<?> msgClass, ActorRef sender) throws Exception {
+            Object message = getFirstMatching(getSelf(), msgClass);
+            assertNotNull("Message of type " + msgClass + " not received", message);
+            getSelf().tell(message, sender);
+        }
+
+        void forwardCapturedMessagesToBehavior(Class<?> msgClass, ActorRef sender) throws Exception {
+            for(Object m: getAllMatching(getSelf(), msgClass)) {
+                getSelf().tell(m, sender);
+            }
+        }
+
+        <T> T getCapturedMessage(Class<T> msgClass) throws Exception {
+            Object message = getFirstMatching(getSelf(), msgClass);
+            assertNotNull("Message of type " + msgClass + " not received", message);
+            return (T) message;
+        }
+    }
+
+    static {
+        System.setProperty(SimpleLogger.LOG_KEY_PREFIX + MockRaftActorContext.class.getName(), "trace");
+    }
+
+    private final Logger testLog = LoggerFactory.getLogger(MockRaftActorContext.class);
+    private final ActorSystem system = ActorSystem.create("test");
+
+    @After
+    public void tearDown() {
+        JavaTestKit.shutdownActorSystem(system);
+    }
+
+    private DefaultConfigParamsImpl newConfigParams() {
+        DefaultConfigParamsImpl configParams = new DefaultConfigParamsImpl();
+        configParams.setHeartBeatInterval(new FiniteDuration(HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS));
+        configParams.setElectionTimeoutFactor(100000);
+        configParams.setIsolatedLeaderCheckInterval(new FiniteDuration(1, TimeUnit.DAYS));
+        return configParams;
+    }
+
+    private MockRaftActorContext newRaftActorContext(String id, ActorRef actor,
+            Map<String, String> peerAddresses) {
+        MockRaftActorContext context = new MockRaftActorContext(id, system, actor);
+        context.setPeerAddresses(peerAddresses);
+        context.getTermInformation().updateAndPersist(1, "");
+        return context;
+    }
+
+    private void verifyBehaviorState(String name, TestActorRef<MemberActor> actor, RaftState expState) {
+        assertEquals(name + " behavior state", expState, actor.underlyingActor().behavior.state());
+    }
+
+    private void initializeLeaderBehavior(TestActorRef<MemberActor> actor, RaftActorContext context,
+            int numActiveFollowers) throws Exception {
+        // Leader sends immediate heartbeats - we don't care about it so ignore it.
+
+        actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, numActiveFollowers);
+        Leader leader = new Leader(context);
+        actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+        actor.underlyingActor().behavior = leader;
+
+        actor.underlyingActor().forwardCapturedMessagesToBehavior(AppendEntriesReply.class, ActorRef.noSender());
+        actor.underlyingActor().clear();
+    }
+
+    private TestActorRef<MemberActor> newMemberActor(String name) throws Exception {
+        TestActorRef<MemberActor> actor = TestActorRef.create(system, MemberActor.props(), name);
+        MessageCollectorActor.waitUntilReady(actor);
+        return actor;
+    }
+
+    private void sendHeartbeat(TestActorRef<MemberActor> leaderActor) {
+        Uninterruptibles.sleepUninterruptibly(HEARTBEAT_INTERVAL, TimeUnit.MILLISECONDS);
+        leaderActor.underlyingActor().behavior.handleMessage(leaderActor, new SendHeartBeat());
+    }
+
+    @Test
+    public void testDelayedMessagesScenario() throws Exception {
+        testLog.info("Starting testDelayedMessagesScenario");
+
+        TestActorRef<MemberActor> member1Actor = newMemberActor("member1");
+        TestActorRef<MemberActor> member2Actor = newMemberActor("member2");
+        TestActorRef<MemberActor> member3Actor = newMemberActor("member3");
+
+        // Create member 2's behavior initially as Follower
+
+        MockRaftActorContext member2Context = newRaftActorContext("member2", member2Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member2ConfigParams = newConfigParams();
+        member2Context.setConfigParams(member2ConfigParams);
+
+        Follower member2Behavior = new Follower(member2Context);
+        member2Actor.underlyingActor().behavior = member2Behavior;
+
+        // Create member 3's behavior initially as Follower
+
+        MockRaftActorContext member3Context = newRaftActorContext("member3", member3Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member2", member2Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member3ConfigParams = newConfigParams();
+        member3Context.setConfigParams(member3ConfigParams);
+
+        Follower member3Behavior = new Follower(member3Context);
+        member3Actor.underlyingActor().behavior = member3Behavior;
+
+        // Create member 1's behavior initially as Leader
+
+        MockRaftActorContext member1Context = newRaftActorContext("member1", member1Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member2", member2Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member1ConfigParams = newConfigParams();
+        member1Context.setConfigParams(member1ConfigParams);
+
+        initializeLeaderBehavior(member1Actor, member1Context, 2);
+
+        member2Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().clear();
+
+        // Send ElectionTimeout to member 2 to simulate missing heartbeat from the Leader. member 2
+        // should switch to Candidate and send out RequestVote messages. Set member 1 and 3 actors
+        // to capture RequestVote but not to forward to the behavior just yet as we want to
+        // control the order of RequestVote messages to member 1 and 3.
+
+        member1Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class);
+
+        member2Actor.underlyingActor().expectBehaviorStateChange();
+
+        member3Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class);
+
+        member2Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        member2Actor.underlyingActor().waitForBehaviorStateChange();
+        verifyBehaviorState("member 2", member2Actor, RaftState.Candidate);
+
+        assertEquals("member 1 election term", 1, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 2, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 1, member3Context.getTermInformation().getCurrentTerm());
+
+        // At this point member 1 and 3 actors have captured the RequestVote messages. First
+        // forward the RequestVote message to member 1's behavior. Since the RequestVote term
+        // is greater than member 1's term, member 1 should switch to Follower without replying
+        // to RequestVote and update its term to 2.
+
+        member1Actor.underlyingActor().clearDropMessagesToBehavior();
+        member1Actor.underlyingActor().expectBehaviorStateChange();
+        member1Actor.underlyingActor().forwardCapturedMessageToBehavior(RequestVote.class, member2Actor);
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        member1Actor.underlyingActor().waitForBehaviorStateChange();
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+
+        // Now forward member 3's captured RequestVote message to its behavior. Since member 3 is
+        // already a Follower, it should update its term to 2 and send a RequestVoteReply back to
+        // member 2 granting the vote b/c the RequestVote's term, lastLogTerm, and lastLogIndex
+        // should satisfy the criteria for granting the vote. However, we'll delay sending the
+        // RequestVoteReply to member 2's behavior to simulate network latency.
+
+        member2Actor.underlyingActor().dropMessagesToBehavior(RequestVoteReply.class);
+
+        member3Actor.underlyingActor().clearDropMessagesToBehavior();
+        member3Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+        member3Actor.underlyingActor().forwardCapturedMessageToBehavior(RequestVote.class, member2Actor);
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Follower);
+
+        assertEquals("member 1 election term", 2, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 2, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 2, member3Context.getTermInformation().getCurrentTerm());
+
+        // Send ElectionTimeout to member 3 to simulate missing heartbeat from a Leader. member 3
+        // should switch to Candidate and send out RequestVote messages. member 1 should grant the
+        // vote and send a reply. After receiving the RequestVoteReply, member 3 should switch to leader.
+
+        member2Actor.underlyingActor().expectBehaviorStateChange();
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().expectMessageClass(RequestVoteReply.class, 1);
+        member3Actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, 2);
+
+        member3Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+        RequestVoteReply requestVoteReply = member3Actor.underlyingActor().getCapturedMessage(RequestVoteReply.class);
+        assertEquals("getTerm", member3Context.getTermInformation().getCurrentTerm(), requestVoteReply.getTerm());
+        assertEquals("isVoteGranted", true, requestVoteReply.isVoteGranted());
+
+        verifyBehaviorState("member 3", member3Actor, RaftState.Leader);
+
+        // member 2 should've switched to Follower as member 3's RequestVote term (3) was greater
+        // than member 2's term (2).
+
+        member2Actor.underlyingActor().waitForBehaviorStateChange();
+        verifyBehaviorState("member 2", member2Actor, RaftState.Follower);
+
+        // The switch to leader should cause an immediate AppendEntries heartbeat from member 3.
+
+        member3Actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 3, member3Context.getTermInformation().getCurrentTerm());
+
+        // Now forward the original delayed RequestVoteReply from member 3 to member 2 that granted
+        // the vote. Since member 2 is now a Follower, the RequestVoteReply should be ignored.
+
+        member2Actor.underlyingActor().clearDropMessagesToBehavior();
+        member2Actor.underlyingActor().forwardCapturedMessageToBehavior(RequestVoteReply.class, member3Actor);
+
+        member2Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Follower);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Leader);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 3, member3Context.getTermInformation().getCurrentTerm());
+
+        testLog.info("testDelayedMessagesScenario done");
+    }
+
+    @Test
+    public void testPartitionedLeadersScenario() throws Exception {
+        testLog.info("Starting testPartitionedLeadersScenario");
+
+        TestActorRef<MemberActor> member1Actor = newMemberActor("member1");
+        TestActorRef<MemberActor> member2Actor = newMemberActor("member2");
+        TestActorRef<MemberActor> member3Actor = newMemberActor("member3");
+
+        // Create member 2's behavior initially as Follower
+
+        MockRaftActorContext member2Context = newRaftActorContext("member2", member2Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member2ConfigParams = newConfigParams();
+        member2Context.setConfigParams(member2ConfigParams);
+
+        Follower member2Behavior = new Follower(member2Context);
+        member2Actor.underlyingActor().behavior = member2Behavior;
+
+        // Create member 3's behavior initially as Follower
+
+        MockRaftActorContext member3Context = newRaftActorContext("member3", member3Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member2", member2Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member3ConfigParams = newConfigParams();
+        member3Context.setConfigParams(member3ConfigParams);
+
+        Follower member3Behavior = new Follower(member3Context);
+        member3Actor.underlyingActor().behavior = member3Behavior;
+
+        // Create member 1's behavior initially as Leader
+
+        MockRaftActorContext member1Context = newRaftActorContext("member1", member1Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member2", member2Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member1ConfigParams = newConfigParams();
+        member1Context.setConfigParams(member1ConfigParams);
+
+        initializeLeaderBehavior(member1Actor, member1Context, 2);
+
+        member2Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().clear();
+
+        // Send ElectionTimeout to member 2 to simulate no heartbeat from the Leader (member 1).
+        // member 2 should switch to Candidate, start new term 2 and send out RequestVote messages.
+        // member 1 will switch to Follower b/c its term is less than the RequestVote term, also it
+        // won't send back a reply. member 3 will drop the message (ie won't forward it to its behavior) to
+        // simulate loss of network connectivity between member 2 and 3.
+
+        member1Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+
+        member2Actor.underlyingActor().expectBehaviorStateChange();
+
+        member3Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class);
+
+        member2Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        // member 1 should switch to Follower as the RequestVote term is greater than its term. It
+        // won't send back a RequestVoteReply in this case.
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+
+        // member 2 should switch to Candidate since member 1 didn't reply.
+
+        member2Actor.underlyingActor().waitForBehaviorStateChange();
+        verifyBehaviorState("member 2", member2Actor, RaftState.Candidate);
+
+        assertEquals("member 1 election term", 2, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 2, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 1, member3Context.getTermInformation().getCurrentTerm());
+
+        // Send ElectionTimeout to member 3 to simulate no heartbeat from the Leader (member 1).
+        // member 2 should switch to Candidate and send out RequestVote messages. member 1 will reply and
+        // grant the vote but member 2 will drop the message to simulate loss of network connectivity.
+
+        member1Actor.underlyingActor().clear();
+        member1Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+        member1Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        member2Actor.underlyingActor().clear();
+        member2Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class);
+        member2Actor.underlyingActor().dropMessagesToBehavior(AppendEntries.class);
+
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().expectMessageClass(RequestVoteReply.class, 1);
+        member3Actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, 1);
+
+        member3Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member2Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+        RequestVoteReply requestVoteReply = member3Actor.underlyingActor().getCapturedMessage(RequestVoteReply.class);
+        assertEquals("getTerm", member3Context.getTermInformation().getCurrentTerm(), requestVoteReply.getTerm());
+        assertEquals("isVoteGranted", true, requestVoteReply.isVoteGranted());
+
+        // when member 3 switches to Leader it will immediately send out heartbeat AppendEntries to
+        // the followers. Wait for AppendEntries to member 1 and its AppendEntriesReply. The
+        // AppendEntries message to member 2 is dropped.
+
+        member1Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+        member2Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Candidate);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Leader);
+
+        assertEquals("member 1 election term", 2, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 2, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 2, member3Context.getTermInformation().getCurrentTerm());
+
+        // member 2 is partitioned from the Leader (member 3) and hasn't received any messages. It
+        // would get another ElectionTimeout so simulate that. member 1 should send back a reply
+        // granting the vote. Messages (RequestVote and AppendEntries) from member 2 to member 3
+        // are dropped to simulate loss of network connectivity. Note member 2 will increment its
+        // election term to 3.
+
+        member1Actor.underlyingActor().clear();
+        member1Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        member2Actor.underlyingActor().clear();
+        member2Actor.underlyingActor().expectMessageClass(RequestVoteReply.class, 1);
+        member2Actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, 1);
+
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().dropMessagesToBehavior(AppendEntries.class);
+        member3Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class);
+
+        member2Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member2Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+        requestVoteReply = member2Actor.underlyingActor().getCapturedMessage(RequestVoteReply.class);
+        assertEquals("getTerm", member2Context.getTermInformation().getCurrentTerm(), requestVoteReply.getTerm());
+        assertEquals("isVoteGranted", true, requestVoteReply.isVoteGranted());
+
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        member1Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+        member2Actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+
+        // We end up with 2 partitioned leaders both leading member 1. The term for member 1 and 3
+        // is 3 and member 3's term is 2.
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Leader);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Leader);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 2, member3Context.getTermInformation().getCurrentTerm());
+
+        // Re-establish connectivity between member 2 and 3, ie stop dropping messages between
+        // the 2. Send heartbeats (AppendEntries) from member 3. Both member 1 and 2 should send back
+        // an unsuccessful AppendEntriesReply b/c their term (3) is greater than member 3's term (2).
+        // This should cause member 3 to switch to Follower.
+
+        RaftActorBehavior savedMember1Behavior = member1Actor.underlyingActor().behavior;
+        RaftActorBehavior savedMember2Behavior = member2Actor.underlyingActor().behavior;
+        RaftActorBehavior savedMember3Behavior = member3Actor.underlyingActor().behavior;
+        long savedMember3Term = member3Context.getTermInformation().getCurrentTerm();
+        String savedMember3VoterFor = member3Context.getTermInformation().getVotedFor();
+
+        member1Actor.underlyingActor().clear();
+        member1Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        member2Actor.underlyingActor().clear();
+        member2Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, 1);
+
+        sendHeartbeat(member3Actor);
+
+        member3Actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+
+        AppendEntriesReply appendEntriesReply = member3Actor.underlyingActor().
+                getCapturedMessage(AppendEntriesReply.class);
+        assertEquals("isSuccess", false, appendEntriesReply.isSuccess());
+        assertEquals("getTerm", 3, appendEntriesReply.getTerm());
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Leader);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Follower);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 3, member3Context.getTermInformation().getCurrentTerm());
+
+        // Revert back to the partitioned leaders state to test the other sequence where member 2
+        // sends heartbeats first before member 3. member 1 should return a successful
+        // AppendEntriesReply b/c his term matches member 2's. member 3 should switch to Follower
+        // as his term is less than member 2's.
+
+        member1Actor.underlyingActor().behavior = savedMember1Behavior;
+        member2Actor.underlyingActor().behavior = savedMember2Behavior;
+        member3Actor.underlyingActor().behavior = savedMember3Behavior;
+
+        member3Context.getTermInformation().update(savedMember3Term, savedMember3VoterFor);
+
+        member1Actor.underlyingActor().clear();
+        member1Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        member2Actor.underlyingActor().clear();
+        member2Actor.underlyingActor().expectMessageClass(AppendEntriesReply.class, 1);
+
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().expectMessageClass(AppendEntries.class, 1);
+
+        sendHeartbeat(member2Actor);
+
+        member1Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(AppendEntries.class);
+
+        member2Actor.underlyingActor().waitForExpectedMessages(AppendEntriesReply.class);
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Leader);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Follower);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", 3, member3Context.getTermInformation().getCurrentTerm());
+
+        testLog.info("testPartitionedLeadersScenario done");
+    }
+
+    @Test
+    public void testPartitionedCandidateOnStartupScenario() throws Exception {
+        testLog.info("Starting testPartitionedCandidateOnStartupScenario");
+
+        TestActorRef<MemberActor> member1Actor = newMemberActor("member1") ;
+        TestActorRef<MemberActor> member2Actor = newMemberActor("member2");
+        TestActorRef<MemberActor> member3Actor = newMemberActor("member3");
+
+        // Create member 2's behavior as Follower.
+
+        MockRaftActorContext member2Context = newRaftActorContext("member2", member2Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member2ConfigParams = newConfigParams();
+        member2Context.setConfigParams(member2ConfigParams);
+
+        Follower member2Behavior = new Follower(member2Context);
+        member2Actor.underlyingActor().behavior = member2Behavior;
+
+        // Create member 1's behavior as Leader.
+
+        MockRaftActorContext member1Context = newRaftActorContext("member1", member1Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member2", member2Actor.path().toString()).
+                    put("member3", member3Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member1ConfigParams = newConfigParams();
+        member1Context.setConfigParams(member1ConfigParams);
+
+        initializeLeaderBehavior(member1Actor, member1Context, 1);
+
+        member2Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().clear();
+
+        // Initialize the ReplicatedLog and election term info for member 1 and 2. The current term
+        // will be 3 and the last term will be 2.
+
+        SimpleReplicatedLog replicatedLog = new SimpleReplicatedLog();
+        replicatedLog.append(new MockReplicatedLogEntry(2, 1, new MockPayload("")));
+        replicatedLog.append(new MockReplicatedLogEntry(3, 1, new MockPayload("")));
+
+        member1Context.setReplicatedLog(replicatedLog);
+        member1Context.getTermInformation().update(3, "");
+
+        member2Context.setReplicatedLog(replicatedLog);
+        member2Context.getTermInformation().update(3, member1Context.getId());
+
+        // Create member 3's behavior initially as a Candidate.
+
+        MockRaftActorContext member3Context = newRaftActorContext("member3", member3Actor,
+                ImmutableMap.<String,String>builder().
+                    put("member1", member1Actor.path().toString()).
+                    put("member2", member2Actor.path().toString()).build());
+
+        DefaultConfigParamsImpl member3ConfigParams = newConfigParams();
+        member3Context.setConfigParams(member3ConfigParams);
+
+        // Initialize the ReplicatedLog and election term info for Candidate member 3. The current term
+        // will be 2 and the last term will be 1 so it is behind the leader's log.
+
+        SimpleReplicatedLog candidateReplicatedLog = new SimpleReplicatedLog();
+        candidateReplicatedLog.append(new MockReplicatedLogEntry(1, 1, new MockPayload("")));
+        candidateReplicatedLog.append(new MockReplicatedLogEntry(2, 1, new MockPayload("")));
+
+        member3Context.setReplicatedLog(candidateReplicatedLog);
+        member3Context.getTermInformation().update(2, member1Context.getId());
+
+        // The member 3 Candidate will start a new term and send RequestVotes. However it will be
+        // partitioned from the cluster by having member 1 and 2 drop its RequestVote messages.
+
+        int numCandidateElections = 5;
+        long candidateElectionTerm = member3Context.getTermInformation().getCurrentTerm() + numCandidateElections;
+
+        member1Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class, numCandidateElections);
+
+        member2Actor.underlyingActor().dropMessagesToBehavior(RequestVote.class, numCandidateElections);
+
+        Candidate member3Behavior = new Candidate(member3Context);
+        member3Actor.underlyingActor().behavior = member3Behavior;
+
+        // Send several additional ElectionTimeouts to Candidate member 3. Each ElectionTimeout will
+        // start a new term so Candidate member 3's current term will be greater than the leader's
+        // current term.
+
+        for(int i = 0; i < numCandidateElections - 1; i++) {
+            member3Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+        }
+
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member2Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Leader);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Follower);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Candidate);
+
+        assertEquals("member 1 election term", 3, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", 3, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", candidateElectionTerm,
+                member3Context.getTermInformation().getCurrentTerm());
+
+        // Now send a couple more ElectionTimeouts to Candidate member 3 with the partition resolved.
+        //
+        // On the first RequestVote, Leader member 1 should switch to Follower as its term (s) is less than
+        // the RequestVote's term (8) from member 3. No RequestVoteReply should be sent by member 1.
+        // Follower member 2 should update its term since it less than the RequestVote's term and
+        // should return a RequestVoteReply but should not grant the vote as its last term and index
+        // is greater than the RequestVote's lastLogTerm and lastLogIndex, ie member 2's log is later
+        // or more up to date than member 3's.
+        //
+        // On the second RequestVote, both member 1 and 2 are followers so they should update their
+        // term and return a RequestVoteReply but should not grant the vote.
+
+        candidateElectionTerm += 2;
+        for(int i = 0; i < 2; i++) {
+            member1Actor.underlyingActor().clear();
+            member1Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+            member2Actor.underlyingActor().clear();
+            member2Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+            member3Actor.underlyingActor().clear();
+            member3Actor.underlyingActor().expectMessageClass(RequestVoteReply.class, 1);
+
+            member3Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+            member1Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+            member2Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+            member3Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+            RequestVoteReply requestVoteReply = member3Actor.underlyingActor().getCapturedMessage(RequestVoteReply.class);
+            assertEquals("getTerm", member3Context.getTermInformation().getCurrentTerm(), requestVoteReply.getTerm());
+            assertEquals("isVoteGranted", false, requestVoteReply.isVoteGranted());
+        }
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Follower);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Follower);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Candidate);
+
+        // Even though member 3 didn't get voted for, member 1 and 2 should have updated their term
+        // to member 3's.
+
+        assertEquals("member 1 election term", candidateElectionTerm,
+                member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", candidateElectionTerm,
+                member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", candidateElectionTerm,
+                member3Context.getTermInformation().getCurrentTerm());
+
+        // At this point we have no leader. Candidate member 3 would continue to start new elections
+        // but wouldn't be granted a vote. One of the 2 followers would eventually time out from
+        // not having received a heartbeat from a leader and switch to candidate and start a new
+        // election. We'll simulate that here by sending an ElectionTimeout to member 1.
+
+        member1Actor.underlyingActor().clear();
+        member1Actor.underlyingActor().expectMessageClass(RequestVoteReply.class, 1);
+        member2Actor.underlyingActor().clear();
+        member2Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+        member3Actor.underlyingActor().clear();
+        member3Actor.underlyingActor().expectMessageClass(RequestVote.class, 1);
+        member3Actor.underlyingActor().expectBehaviorStateChange();
+
+        member1Actor.tell(new ElectionTimeout(), ActorRef.noSender());
+
+        member2Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+        member3Actor.underlyingActor().waitForExpectedMessages(RequestVote.class);
+
+        // The RequestVoteReply should come from Follower member 2 and the vote should be granted
+        // since member 2's last term and index matches member 1's.
+
+        member1Actor.underlyingActor().waitForExpectedMessages(RequestVoteReply.class);
+
+        RequestVoteReply requestVoteReply = member1Actor.underlyingActor().getCapturedMessage(RequestVoteReply.class);
+        assertEquals("getTerm", member1Context.getTermInformation().getCurrentTerm(), requestVoteReply.getTerm());
+        assertEquals("isVoteGranted", true, requestVoteReply.isVoteGranted());
+
+        // Candidate member 3 should change to follower as its term should be less than the
+        // RequestVote term (member 1 started a new term higher than the other member's terms).
+
+        member3Actor.underlyingActor().waitForBehaviorStateChange();
+
+        verifyBehaviorState("member 1", member1Actor, RaftState.Leader);
+        verifyBehaviorState("member 2", member2Actor, RaftState.Follower);
+        verifyBehaviorState("member 3", member3Actor, RaftState.Follower);
+
+        // newTerm should be 10.
+
+        long newTerm = candidateElectionTerm + 1;
+        assertEquals("member 1 election term", newTerm, member1Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 2 election term", newTerm, member2Context.getTermInformation().getCurrentTerm());
+        assertEquals("member 3 election term", newTerm, member3Context.getTermInformation().getCurrentTerm());
+
+        testLog.info("testPartitionedCandidateOnStartupScenario done");
+    }
+}
index 3f551b3..8251c6b 100644 (file)
@@ -44,16 +44,10 @@ import org.opendaylight.controller.cluster.raft.messages.RequestVoteReply;
 import org.opendaylight.controller.cluster.raft.utils.DoNothingActor;
 import org.opendaylight.controller.cluster.raft.utils.MessageCollectorActor;
 import org.opendaylight.controller.protobuff.messages.cluster.raft.InstallSnapshotMessages;
-import org.slf4j.impl.SimpleLogger;
 import scala.concurrent.duration.FiniteDuration;
 
 public class LeaderTest extends AbstractRaftActorBehaviorTest {
 
-    static {
-        // This enables trace logging for the tests.
-        System.setProperty(SimpleLogger.LOG_KEY_PREFIX + MockRaftActorContext.class.getName(), "trace");
-    }
-
     private final ActorRef leaderActor =
         getSystem().actorOf(Props.create(DoNothingActor.class));
     private final ActorRef senderActor =
index c5acb1f..79c90cf 100644 (file)
@@ -17,6 +17,7 @@ import com.google.common.util.concurrent.Uninterruptibles;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.Duration;
@@ -24,14 +25,21 @@ import scala.concurrent.duration.FiniteDuration;
 
 
 public class MessageCollectorActor extends UntypedActor {
+    private static final String ARE_YOU_READY = "ARE_YOU_READY";
+
     private final List<Object> messages = new ArrayList<>();
 
     @Override public void onReceive(Object message) throws Exception {
+        if(message.equals(ARE_YOU_READY)) {
+            getSender().tell("yes", getSelf());
+            return;
+        }
+
         if(message instanceof String){
             if("get-all-messages".equals(message)){
-                getSender().tell(new ArrayList(messages), getSelf());
+                getSender().tell(new ArrayList<>(messages), getSelf());
             }
-        } else {
+        } else if(message != null) {
             messages.add(message);
         }
     }
@@ -45,11 +53,7 @@ public class MessageCollectorActor extends UntypedActor {
         Timeout operationTimeout = new Timeout(operationDuration);
         Future<Object> future = Patterns.ask(actor, "get-all-messages", operationTimeout);
 
-        try {
-            return (List<Object>) Await.result(future, operationDuration);
-        } catch (Exception e) {
-            throw e;
-        }
+        return (List<Object>) Await.result(future, operationDuration);
     }
 
     /**
@@ -88,4 +92,17 @@ public class MessageCollectorActor extends UntypedActor {
         return output;
     }
 
+    public static void waitUntilReady(ActorRef actor) throws Exception {
+        long timeout = 500;
+        FiniteDuration duration = Duration.create(timeout, TimeUnit.MILLISECONDS);
+        for(int i = 0; i < 10; i++) {
+            try {
+                Await.ready(Patterns.ask(actor, ARE_YOU_READY, timeout), duration);
+                return;
+            } catch (TimeoutException e) {
+            }
+        }
+
+        throw new TimeoutException("Actor not ready in time.");
+    }
 }
diff --git a/opendaylight/md-sal/sal-akka-raft/src/test/resources/simplelogger.properties b/opendaylight/md-sal/sal-akka-raft/src/test/resources/simplelogger.properties
new file mode 100644 (file)
index 0000000..4e79807
--- /dev/null
@@ -0,0 +1,6 @@
+org.slf4j.simpleLogger.showDateTime=true
+org.slf4j.simpleLogger.dateTimeFormat=hh:mm:ss,S a
+org.slf4j.simpleLogger.logFile=System.out
+org.slf4j.simpleLogger.showShortLogName=true
+org.slf4j.simpleLogger.levelInBrackets=true
+org.slf4j.simpleLogger.org.opendaylight.controller.cluster.raft=trace
\ No newline at end of file
index 10f6a42..9da6a3b 100644 (file)
@@ -71,6 +71,9 @@ odl-cluster-rpc {
       netty.tcp {
         hostname = "127.0.0.1"
         port = 2551
+        maximum-frame-size = 419430400
+        send-buffer-size = 52428800
+        receive-buffer-size = 52428800
       }
     }
 
diff --git a/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/simplelogger.properties b/opendaylight/md-sal/sal-distributed-datastore/src/test/resources/simplelogger.properties
new file mode 100644 (file)
index 0000000..9ed3d27
--- /dev/null
@@ -0,0 +1,6 @@
+org.slf4j.simpleLogger.showDateTime=true
+org.slf4j.simpleLogger.dateTimeFormat=hh:mm:ss,S a
+org.slf4j.simpleLogger.logFile=System.out
+org.slf4j.simpleLogger.showShortLogName=true
+org.slf4j.simpleLogger.levelInBrackets=true
+org.slf4j.simpleLogger.log.org.opendaylight.controller.cluster.datastore=trace
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcAvailabilityListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcAvailabilityListener.java
new file mode 100644 (file)
index 0000000..77d42a4
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015 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 java.util.EventListener;
+import javax.annotation.Nonnull;
+
+/**
+ * An {@link EventListener} used to track RPC implementations becoming (un)available
+ * to a {@link DOMRpcService}.
+ */
+public interface DOMRpcAvailabilityListener extends EventListener {
+    /**
+     * Method invoked whenever an RPC type becomes available.
+     *
+     * @param rpcs RPC types newly available
+     */
+    void onRpcAvailable(@Nonnull Collection<DOMRpcIdentifier> rpcs);
+
+    /**
+     * Method invoked whenever an RPC type becomes unavailable.
+     *
+     * @param rpcs RPC types which became unavailable
+     */
+    void onRpcUnavailable(@Nonnull Collection<DOMRpcIdentifier> rpcs);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcException.java
new file mode 100644 (file)
index 0000000..7ea4f4c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 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;
+
+/**
+ * Base class for failures that can occur during RPC invocation. This covers
+ * transport and protocol-level failures.
+ */
+public abstract class DOMRpcException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Construct an new instance with a message and an empty cause.
+     *
+     * @param message Exception message
+     */
+    protected DOMRpcException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Construct an new instance with a message and a cause.
+     *
+     * @param message Exception message
+     * @param cause Chained cause
+     */
+    protected DOMRpcException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcIdentifier.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcIdentifier.java
new file mode 100644 (file)
index 0000000..1976913
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2015 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.base.Preconditions;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Identifier of a RPC context. This is an extension of the YANG RPC, which
+ * always has global context. It allows an RPC to have a instance identifier
+ * attached, so that there can be multiple implementations bound to different
+ * contexts concurrently.
+ */
+public abstract class DOMRpcIdentifier {
+    private static final class Global extends DOMRpcIdentifier {
+        private Global(final @Nonnull SchemaPath type) {
+            super(type);
+        }
+
+        @Override
+        public YangInstanceIdentifier getContextReference() {
+            return null;
+        }
+    }
+
+    private static final class Local extends DOMRpcIdentifier {
+        private final YangInstanceIdentifier contextReference;
+
+        private Local(final @Nonnull SchemaPath type, final @Nonnull YangInstanceIdentifier contextReference) {
+            super(type);
+            this.contextReference = Preconditions.checkNotNull(contextReference);
+        }
+
+        @Override
+        public YangInstanceIdentifier getContextReference() {
+            return contextReference;
+        }
+    }
+
+    private final SchemaPath type;
+
+    private DOMRpcIdentifier(final SchemaPath type) {
+        this.type = Preconditions.checkNotNull(type);
+    }
+
+    /**
+     * Create a global RPC identifier.
+     *
+     * @param type RPC type, SchemaPath of its definition, may not be null
+     * @return A global RPC identifier, guaranteed to be non-null.
+     */
+    public static @Nonnull DOMRpcIdentifier create(final @Nonnull SchemaPath type) {
+        return new Global(type);
+    }
+
+    /**
+     * Create an RPC identifier with a particular context reference.
+     *
+     * @param type RPC type, SchemaPath of its definition, may not be null
+     * @param contextReference Context reference, null means a global RPC identifier.
+     * @return A global RPC identifier, guaranteed to be non-null.
+     */
+    public static @Nonnull DOMRpcIdentifier create(final @Nonnull SchemaPath type, final @Nullable YangInstanceIdentifier contextReference) {
+        if (contextReference == null) {
+            return new Global(type);
+        } else {
+            return new Local(type, contextReference);
+        }
+    }
+
+    /**
+     * Return the RPC type.
+     *
+     * @return RPC type.
+     */
+    public final @Nonnull SchemaPath getType() {
+        return type;
+    }
+
+    /**
+     * Return the RPC context reference. Null value indicates global context.
+     *
+     * @return RPC context reference.
+     */
+    public abstract @Nullable YangInstanceIdentifier getContextReference();
+
+    @Override
+    public final int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + type.hashCode();
+        result = prime * result + (getContextReference() == null ? 0 : getContextReference().hashCode());
+        return result;
+    }
+
+    @Override
+    public final boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof DOMRpcIdentifier)) {
+            return false;
+        }
+        DOMRpcIdentifier other = (DOMRpcIdentifier) obj;
+        if (!type.equals(other.type)) {
+            return false;
+        }
+        return Objects.equals(getContextReference(), other.getContextReference());
+    }
+
+    @Override
+    public final String toString() {
+        return com.google.common.base.Objects.toStringHelper(this).omitNullValues().add("type", type).add("contextReference", getContextReference()).toString();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementation.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementation.java
new file mode 100644 (file)
index 0000000..c246c76
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 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.CheckedFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface implemented by an individual RPC implementation. This API allows for dispatch
+ * implementations, e.g. an individual object handling a multitude of RPCs.
+ */
+public interface DOMRpcImplementation {
+    /**
+     * Initiate invocation of the RPC. Implementations of this method are
+     * expected to not block on external resources.
+     *
+     * @param rpc RPC identifier which was invoked
+     * @param input Input arguments, null if the RPC does not take any.
+     * @return A {@link CheckedFuture} which will return either a result structure,
+     *         or report a subclass of {@link DOMRpcException} reporting a transport
+     *         error.
+     */
+    @Nonnull CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull DOMRpcIdentifier rpc, @Nullable NormalizedNode<?, ?> input);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationNotAvailableException.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationNotAvailableException.java
new file mode 100644 (file)
index 0000000..cca9a45
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2015 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.base.Preconditions;
+import javax.annotation.Nonnull;
+
+/**
+ * Exception indicating that no implementation of the requested RPC service is available.
+ */
+public class DOMRpcImplementationNotAvailableException extends DOMRpcException {
+    private static final long serialVersionUID = 1L;
+
+    public DOMRpcImplementationNotAvailableException(@Nonnull final String format, final Object... args) {
+        super(String.format(format, args));
+    }
+
+    public DOMRpcImplementationNotAvailableException(@Nonnull final Throwable cause, @Nonnull final String format, final Object... args) {
+        super(String.format(format, args), Preconditions.checkNotNull(cause));
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationRegistration.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcImplementationRegistration.java
new file mode 100644 (file)
index 0000000..0b8dff5
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 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.ObjectRegistration;
+
+/**
+ * A registration of a {@link DOMRpcImplementation}. Used to track and revoke a registration
+ * with a {@link DOMRpcProviderService}.
+ *
+ * @param <T> RPC implementation type
+ */
+public interface DOMRpcImplementationRegistration<T extends DOMRpcImplementation> extends ObjectRegistration<T> {
+    @Override
+    void close();
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcProviderService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcProviderService.java
new file mode 100644 (file)
index 0000000..4a4f965
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 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.Set;
+import javax.annotation.Nonnull;
+
+/**
+ * A {@link DOMService} which allows registration of RPC implementations with a conceptual
+ * router. The client counterpart of this service is {@link DOMRpcService}.
+ */
+public interface DOMRpcProviderService extends DOMService {
+    /**
+     * Register an {@link DOMRpcImplementation} object with this service.
+     *
+     * @param implementation RPC implementation, must not be null
+     * @param rpcs Array of supported RPC identifiers. Must not be null, empty, or contain a null element.
+     *             Each identifier is added exactly once, no matter how many times it occurs.
+     * @return A {@link DOMRpcImplementationRegistration} object, guaranteed to be non-null.
+     * @throws NullPointerException if implementation or types is null
+     * @throws IllegalArgumentException if types is empty or contains a null element.
+     */
+    @Nonnull <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(@Nonnull T implementation, @Nonnull DOMRpcIdentifier... rpcs);
+
+    /**
+     * Register an {@link DOMRpcImplementation} object with this service.
+     *
+     * @param implementation RPC implementation, must not be null
+     * @param rpcs Set of supported RPC identifiers. Must not be null, empty, or contain a null element.
+     * @return A {@link DOMRpcImplementationRegistration} object, guaranteed to be non-null.
+     * @throws NullPointerException if implementation or types is null
+     * @throws IllegalArgumentException if types is empty or contains a null element.
+     */
+    @Nonnull <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(@Nonnull T implementation, @Nonnull Set<DOMRpcIdentifier> rpcs);
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcResult.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcResult.java
new file mode 100644 (file)
index 0000000..5893688
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2015 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 javax.annotation.Nullable;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Interface defining a result of an RPC call.
+ */
+public interface DOMRpcResult {
+    /**
+     * Returns a set of errors and warnings which occurred during processing
+     * the call.
+     *
+     * @return a Collection of {@link RpcError}, guaranteed to be non-null. In case
+     *         no errors are reported, an empty collection is returned.
+     */
+    @Nonnull Collection<RpcError> getErrors();
+
+    /**
+     * Returns the value result of the call or null if no result is available.
+     *
+     * @return Invocation result, null if the operation has not produced a result. This might
+     *         be the case if the operation does not produce a result, or if it failed.
+     */
+    @Nullable NormalizedNode<?, ?> getResult();
+}
diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMRpcService.java
new file mode 100644 (file)
index 0000000..48f6ab6
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2015 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.CheckedFuture;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * A {@link DOMService} which allows clients to invoke RPCs. The conceptual model of this
+ * service is that of a dynamic router, where the set of available RPC services can change
+ * dynamically. The service allows users to add a listener to track the process of
+ * RPCs becoming available.
+ */
+public interface DOMRpcService extends DOMService {
+    /**
+     * Initiate invocation of an RPC. This method is guaranteed to not block on any external
+     * resources.
+     *
+     * @param type SchemaPath of the RPC to be invoked
+     * @param input Input arguments, null if the RPC does not take any.
+     * @return A {@link CheckedFuture} which will return either a result structure,
+     *         or report a subclass of {@link DOMRpcException} reporting a transport
+     *         error.
+     */
+    @Nonnull CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(@Nonnull SchemaPath type, @Nullable NormalizedNode<?, ?> input);
+
+    /**
+     * Register a {@link DOMRpcAvailabilityListener} with this service to receive notifications
+     * about RPC implementations becoming (un)available. The listener will be invoked with the
+     * current implementations reported and will be kept uptodate as implementations come and go.
+     *
+     * Users should note that using a listener does not necessarily mean that {@link #invokeRpc(SchemaPath, NormalizedNode)}
+     * will not report a failure due to {@link DOMRpcImplementationNotAvailableException} and
+     * need to be ready to handle it. Implementations are encouraged to take reasonable precautions
+     * to prevent this scenario from occurring.
+     *
+     * @param listener {@link DOMRpcAvailabilityListener} instance to register
+     * @return A {@link DOMRpcAvailabilityListenerRegistration} representing this registration. Performing
+     *         a {@link DOMRpcAvailabilityListenerRegistration#close()} will cancel it. Returned object
+     *         is guaranteed to be non-null.
+     */
+    @Nonnull <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(@Nonnull T listener);
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMRpcRoutingTableEntry.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMRpcRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..09c4f4f
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+abstract class AbstractDOMRpcRoutingTableEntry {
+    private final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls;
+    private final SchemaPath schemaPath;
+
+    protected AbstractDOMRpcRoutingTableEntry(final SchemaPath schemaPath, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        this.schemaPath = Preconditions.checkNotNull(schemaPath);
+        this.impls = Preconditions.checkNotNull(impls);
+    }
+
+    protected final SchemaPath getSchemaPath() {
+        return schemaPath;
+    }
+
+    protected final List<DOMRpcImplementation> getImplementations(final YangInstanceIdentifier context) {
+        return impls.get(context);
+    }
+
+    final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> getImplementations() {
+        return impls;
+    }
+
+    public boolean containsContext(final YangInstanceIdentifier contextReference) {
+        return impls.containsKey(contextReference);
+    }
+
+    final Set<YangInstanceIdentifier> registeredIdentifiers() {
+        return impls.keySet();
+    }
+
+    final AbstractDOMRpcRoutingTableEntry add(final DOMRpcImplementation implementation, final List<YangInstanceIdentifier> newRpcs) {
+        final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
+        for (Entry<YangInstanceIdentifier, List<DOMRpcImplementation>> ve : impls.entrySet()) {
+            if (newRpcs.remove(ve.getKey())) {
+                final ArrayList<DOMRpcImplementation> i = new ArrayList<>(ve.getValue().size() + 1);
+                i.addAll(ve.getValue());
+                i.add(implementation);
+                vb.put(ve.getKey(), i);
+            } else {
+                vb.put(ve);
+            }
+        }
+
+        return newInstance(vb.build());
+    }
+
+    final AbstractDOMRpcRoutingTableEntry remove(final DOMRpcImplementation implementation, final List<YangInstanceIdentifier> removed) {
+        final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
+        for (Entry<YangInstanceIdentifier, List<DOMRpcImplementation>> ve : impls.entrySet()) {
+            if (removed.remove(ve.getKey())) {
+                final ArrayList<DOMRpcImplementation> i = new ArrayList<>(ve.getValue());
+                i.remove(implementation);
+                // We could trimToSize(), but that may perform another copy just to get rid
+                // of a single element. That is probably not worth the trouble.
+                if (!i.isEmpty()) {
+                    vb.put(ve.getKey(), i);
+                }
+            } else {
+                vb.put(ve);
+            }
+        }
+
+        final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> v = vb.build();
+        return v.isEmpty() ? null : newInstance(v);
+    }
+
+    protected abstract CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final NormalizedNode<?, ?> input);
+    protected abstract AbstractDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls);
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRouter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRouter.java
new file mode 100644 (file)
index 0000000..d72f714
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.base.Function;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Collections2;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableList.Builder;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import javax.annotation.concurrent.GuardedBy;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.spi.AbstractDOMRpcImplementationRegistration;
+import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+public final class DOMRpcRouter implements AutoCloseable, DOMRpcService, DOMRpcProviderService, SchemaContextListener {
+    private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder().setNameFormat("DOMRpcRouter-listener-%s").setDaemon(true).build();
+    private final ExecutorService listenerNotifier = Executors.newSingleThreadExecutor(THREAD_FACTORY);
+    @GuardedBy("this")
+    private Collection<ListenerRegistration<? extends DOMRpcAvailabilityListener>> listeners = Collections.emptyList();
+    private volatile DOMRpcRoutingTable routingTable = DOMRpcRoutingTable.EMPTY;
+
+    @Override
+    public <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(final T implementation, final DOMRpcIdentifier... rpcs) {
+        return registerRpcImplementation(implementation, ImmutableSet.copyOf(rpcs));
+    }
+
+    private static Collection<DOMRpcIdentifier> notPresentRpcs(final DOMRpcRoutingTable table, final Collection<DOMRpcIdentifier> candidates) {
+        return ImmutableSet.copyOf(Collections2.filter(candidates, new Predicate<DOMRpcIdentifier>() {
+            @Override
+            public boolean apply(final DOMRpcIdentifier input) {
+                return !table.contains(input);
+            }
+        }));
+    }
+
+    private synchronized void removeRpcImplementation(final DOMRpcImplementation implementation, final Set<DOMRpcIdentifier> rpcs) {
+        final DOMRpcRoutingTable oldTable = routingTable;
+        final DOMRpcRoutingTable newTable = oldTable.remove(implementation, rpcs);
+
+        final Collection<DOMRpcIdentifier> removedRpcs = notPresentRpcs(newTable, rpcs);
+        final Collection<ListenerRegistration<? extends DOMRpcAvailabilityListener>> capturedListeners = listeners;
+        routingTable = newTable;
+
+        listenerNotifier.execute(new Runnable() {
+            @Override
+            public void run() {
+                for (ListenerRegistration<? extends DOMRpcAvailabilityListener> l : capturedListeners) {
+                    // Need to ensure removed listeners do not get notified
+                    synchronized (DOMRpcRouter.this) {
+                        if (listeners.contains(l)) {
+                            l.getInstance().onRpcUnavailable(removedRpcs);
+                        }
+                    }
+                }
+            }
+        });
+    }
+
+    @Override
+    public synchronized <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(final T implementation, final Set<DOMRpcIdentifier> rpcs) {
+        final DOMRpcRoutingTable oldTable = routingTable;
+        final DOMRpcRoutingTable newTable = oldTable.add(implementation, rpcs);
+
+        final Collection<DOMRpcIdentifier> addedRpcs = notPresentRpcs(oldTable, rpcs);
+        final Collection<ListenerRegistration<? extends DOMRpcAvailabilityListener>> capturedListeners = listeners;
+        routingTable = newTable;
+
+        listenerNotifier.execute(new Runnable() {
+            @Override
+            public void run() {
+                for (ListenerRegistration<? extends DOMRpcAvailabilityListener> l : capturedListeners) {
+                    // Need to ensure removed listeners do not get notified
+                    synchronized (DOMRpcRouter.this) {
+                        if (listeners.contains(l)) {
+                            l.getInstance().onRpcAvailable(addedRpcs);
+                        }
+                    }
+                }
+            }
+        });
+
+        return new AbstractDOMRpcImplementationRegistration<T>(implementation) {
+            @Override
+            protected void removeRegistration() {
+                removeRpcImplementation(getInstance(), rpcs);
+            }
+        };
+    }
+
+    @Override
+    public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
+        return routingTable.invokeRpc(type, input);
+    }
+
+    private synchronized void removeListener(final ListenerRegistration<? extends DOMRpcAvailabilityListener> reg) {
+        listeners = ImmutableList.copyOf(Collections2.filter(listeners, new Predicate<Object>() {
+            @Override
+            public boolean apply(final Object input) {
+                return !reg.equals(input);
+            }
+        }));
+    }
+
+    @Override
+    public synchronized <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
+        final ListenerRegistration<T> ret = new AbstractListenerRegistration<T>(listener) {
+            @Override
+            protected void removeRegistration() {
+                removeListener(this);
+            }
+        };
+
+        final Builder<ListenerRegistration<? extends DOMRpcAvailabilityListener>> b = ImmutableList.builder();
+        b.addAll(listeners);
+        b.add(ret);
+        listeners = b.build();
+        final Map<SchemaPath, Set<YangInstanceIdentifier>> capturedRpcs = routingTable.getRpcs();
+
+        listenerNotifier.execute(new Runnable() {
+            @Override
+            public void run() {
+                for (final Entry<SchemaPath, Set<YangInstanceIdentifier>> e : capturedRpcs.entrySet()) {
+                    listener.onRpcAvailable(Collections2.transform(e.getValue(), new Function<YangInstanceIdentifier, DOMRpcIdentifier>() {
+                        @Override
+                        public DOMRpcIdentifier apply(final YangInstanceIdentifier input) {
+                            return DOMRpcIdentifier.create(e.getKey(), input);
+                        }
+                    }));
+                }
+            }
+        });
+
+        return ret;
+    }
+
+    @Override
+    public synchronized void onGlobalContextUpdated(final SchemaContext context) {
+        final DOMRpcRoutingTable oldTable = routingTable;
+        final DOMRpcRoutingTable newTable = oldTable.setSchemaContext(context);
+        routingTable = newTable;
+    }
+
+    @Override
+    public void close() {
+        listenerNotifier.shutdown();
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRoutingTable.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMRpcRoutingTable.java
new file mode 100644 (file)
index 0000000..0e5ce27
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMap.Builder;
+import com.google.common.collect.LinkedListMultimap;
+import com.google.common.collect.ListMultimap;
+import com.google.common.collect.Maps;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+
+final class DOMRpcRoutingTable {
+    private static final QName CONTEXT_REFERENCE = QName.cachedReference(QName.create("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", "context-reference"));
+
+    static final DOMRpcRoutingTable EMPTY = new DOMRpcRoutingTable();
+    private static final Function<AbstractDOMRpcRoutingTableEntry, Set<YangInstanceIdentifier>> EXTRACT_IDENTIFIERS =
+            new Function<AbstractDOMRpcRoutingTableEntry, Set<YangInstanceIdentifier>>() {
+                @Override
+                public Set<YangInstanceIdentifier> apply(final AbstractDOMRpcRoutingTableEntry input) {
+                    return input.registeredIdentifiers();
+                }
+    };
+    private final Map<SchemaPath, AbstractDOMRpcRoutingTableEntry> rpcs;
+    private final SchemaContext schemaContext;
+
+    private DOMRpcRoutingTable() {
+        rpcs = Collections.emptyMap();
+        schemaContext = null;
+    }
+
+    private DOMRpcRoutingTable(final Map<SchemaPath, AbstractDOMRpcRoutingTableEntry> rpcs, final SchemaContext schemaContext) {
+        this.rpcs = Preconditions.checkNotNull(rpcs);
+        this.schemaContext = schemaContext;
+    }
+
+    private static ListMultimap<SchemaPath, YangInstanceIdentifier> decomposeIdentifiers(final Set<DOMRpcIdentifier> rpcs) {
+        final ListMultimap<SchemaPath, YangInstanceIdentifier> ret = LinkedListMultimap.create();
+        for (DOMRpcIdentifier i : rpcs) {
+            ret.put(i.getType(), i.getContextReference());
+        }
+        return ret;
+    }
+
+    DOMRpcRoutingTable add(final DOMRpcImplementation implementation, final Set<DOMRpcIdentifier> rpcs) {
+        if (rpcs.isEmpty()) {
+            return this;
+        }
+
+        // First decompose the identifiers to a multimap
+        final ListMultimap<SchemaPath, YangInstanceIdentifier> toAdd = decomposeIdentifiers(rpcs);
+
+        // Now iterate over existing entries, modifying them as appropriate...
+        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> mb = ImmutableMap.builder();
+        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> re : this.rpcs.entrySet()) {
+            List<YangInstanceIdentifier> newRpcs = toAdd.removeAll(re.getKey());
+            if (!newRpcs.isEmpty()) {
+                final AbstractDOMRpcRoutingTableEntry ne = re.getValue().add(implementation, newRpcs);
+                mb.put(re.getKey(), ne);
+            } else {
+                mb.put(re);
+            }
+        }
+
+        // Finally add whatever is left in the decomposed multimap
+        for (Entry<SchemaPath, Collection<YangInstanceIdentifier>> e : toAdd.asMap().entrySet()) {
+            final Builder<YangInstanceIdentifier, List<DOMRpcImplementation>> vb = ImmutableMap.builder();
+            final List<DOMRpcImplementation> v = Collections.singletonList(implementation);
+            for (YangInstanceIdentifier i : e.getValue()) {
+                vb.put(i, v);
+            }
+
+            mb.put(e.getKey(), createRpcEntry(schemaContext, e.getKey(), vb.build()));
+        }
+
+        return new DOMRpcRoutingTable(mb.build(), schemaContext);
+    }
+
+    DOMRpcRoutingTable remove(final DOMRpcImplementation implementation, final Set<DOMRpcIdentifier> rpcs) {
+        if (rpcs.isEmpty()) {
+            return this;
+        }
+
+        // First decompose the identifiers to a multimap
+        final ListMultimap<SchemaPath, YangInstanceIdentifier> toRemove = decomposeIdentifiers(rpcs);
+
+        // Now iterate over existing entries, modifying them as appropriate...
+        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> b = ImmutableMap.builder();
+        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> e : this.rpcs.entrySet()) {
+            final List<YangInstanceIdentifier> removed = toRemove.removeAll(e.getKey());
+            if (!removed.isEmpty()) {
+                final AbstractDOMRpcRoutingTableEntry ne = e.getValue().remove(implementation, removed);
+                if (ne != null) {
+                    b.put(e.getKey(), ne);
+                }
+            } else {
+                b.put(e);
+            }
+        }
+
+        // All done, whatever is in toRemove, was not there in the first place
+        return new DOMRpcRoutingTable(b.build(), schemaContext);
+    }
+
+    boolean contains(final DOMRpcIdentifier input) {
+        final AbstractDOMRpcRoutingTableEntry contexts = rpcs.get(input.getType());
+        return contexts != null && contexts.containsContext(input.getContextReference());
+    }
+
+    Map<SchemaPath, Set<YangInstanceIdentifier>> getRpcs() {
+        return Maps.transformValues(rpcs, EXTRACT_IDENTIFIERS);
+    }
+
+    private static RpcDefinition findRpcDefinition(final SchemaContext context, final SchemaPath schemaPath) {
+        if (context != null) {
+            final QName qname = schemaPath.getPathFromRoot().iterator().next();
+            final Module module = context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
+            if (module != null && module.getRpcs() != null) {
+                for (RpcDefinition rpc : module.getRpcs()) {
+                    if (qname.equals(rpc.getQName())) {
+                        return rpc;
+                    }
+                }
+            }
+        }
+
+        return null;
+    }
+
+    private static AbstractDOMRpcRoutingTableEntry createRpcEntry(final SchemaContext context, final SchemaPath key, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> implementations) {
+        final RpcDefinition rpcDef = findRpcDefinition(context, key);
+        if (rpcDef != null) {
+            final ContainerSchemaNode input = rpcDef.getInput();
+            if (input != null) {
+                for (DataSchemaNode c : input.getChildNodes()) {
+                    for (UnknownSchemaNode extension : c.getUnknownSchemaNodes()) {
+                        if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
+                            final YangInstanceIdentifier keyId = YangInstanceIdentifier.builder().node(input.getQName()).node(c.getQName()).build();
+                            return new RoutedDOMRpcRoutingTableEntry(rpcDef, keyId, implementations);
+                        }
+                    }
+                }
+            }
+
+            return new GlobalDOMRpcRoutingTableEntry(rpcDef, implementations);
+        } else {
+            return new UnknownDOMRpcRoutingTableEntry(key, implementations);
+        }
+    }
+
+    CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
+        final AbstractDOMRpcRoutingTableEntry entry = rpcs.get(type);
+        if (entry == null) {
+            return Futures.<DOMRpcResult, DOMRpcException>immediateFailedCheckedFuture(new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available", type));
+        }
+
+        return entry.invokeRpc(input);
+    }
+
+    DOMRpcRoutingTable setSchemaContext(final SchemaContext context) {
+        final Builder<SchemaPath, AbstractDOMRpcRoutingTableEntry> b = ImmutableMap.builder();
+
+        for (Entry<SchemaPath, AbstractDOMRpcRoutingTableEntry> e : rpcs.entrySet()) {
+            b.put(e.getKey(), createRpcEntry(context, e.getKey(), e.getValue().getImplementations()));
+        }
+
+        return new DOMRpcRoutingTable(b.build(), context);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/GlobalDOMRpcRoutingTableEntry.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/GlobalDOMRpcRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..3b0d5df
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+
+final class GlobalDOMRpcRoutingTableEntry extends AbstractDOMRpcRoutingTableEntry {
+    private final DOMRpcIdentifier rpcId;
+
+    private GlobalDOMRpcRoutingTableEntry(final DOMRpcIdentifier rpcId, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        super(rpcId.getType(), impls);
+        this.rpcId = Preconditions.checkNotNull(rpcId);
+    }
+
+    // We do not need the RpcDefinition, but this makes sure we do not
+    // forward something we don't know to be an RPC.
+    GlobalDOMRpcRoutingTableEntry(final RpcDefinition def, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        super(def.getPath(), impls);
+        this.rpcId = DOMRpcIdentifier.create(def.getPath());
+    }
+
+    @Override
+    protected CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final NormalizedNode<?, ?> input) {
+        return getImplementations(null).get(0).invokeRpc(rpcId, input);
+    }
+
+    @Override
+    protected GlobalDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        return new GlobalDOMRpcRoutingTableEntry(rpcId, impls);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/RoutedDOMRpcRoutingTableEntry.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/RoutedDOMRpcRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..e6df966
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodes;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+final class RoutedDOMRpcRoutingTableEntry extends AbstractDOMRpcRoutingTableEntry {
+    private static final Logger LOG = LoggerFactory.getLogger(RoutedDOMRpcRoutingTableEntry.class);
+    private final DOMRpcIdentifier globalRpcId;
+    private final YangInstanceIdentifier keyId;
+
+    private RoutedDOMRpcRoutingTableEntry(final DOMRpcIdentifier globalRpcId, final YangInstanceIdentifier keyId, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        super(globalRpcId.getType(), impls);
+        this.keyId = Preconditions.checkNotNull(keyId);
+        this.globalRpcId = Preconditions.checkNotNull(globalRpcId);
+    }
+
+    RoutedDOMRpcRoutingTableEntry(final RpcDefinition def, final YangInstanceIdentifier keyId, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        super(def.getPath(), impls);
+        this.keyId = Preconditions.checkNotNull(keyId);
+        this.globalRpcId = DOMRpcIdentifier.create(def.getPath());
+    }
+
+    @Override
+    protected CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final NormalizedNode<?, ?> input) {
+        final Optional<NormalizedNode<?, ?>> maybeKey = NormalizedNodes.findNode(input, keyId);
+
+        // Routing key is present, attempt to deliver as a routed RPC
+        if (maybeKey.isPresent()) {
+            final NormalizedNode<?, ?> key = maybeKey.get();
+            final Object value = key.getValue();
+            if (value instanceof YangInstanceIdentifier) {
+                final YangInstanceIdentifier iid = (YangInstanceIdentifier) value;
+                final List<DOMRpcImplementation> impls = getImplementations(iid);
+                if (impls != null) {
+                    return impls.get(0).invokeRpc(DOMRpcIdentifier.create(getSchemaPath(), iid), input);
+                }
+                LOG.debug("No implementation for context {} found", iid);
+            } else {
+                LOG.warn("Ignoring wrong context value {}", value);
+            }
+        }
+
+        final List<DOMRpcImplementation> impls = getImplementations(null);
+        if (impls != null) {
+            return impls.get(0).invokeRpc(globalRpcId, input);
+        } else {
+            return Futures.<DOMRpcResult, DOMRpcException>immediateFailedCheckedFuture(new DOMRpcImplementationNotAvailableException("No implementation of RPC %s available", getSchemaPath()));
+        }
+    }
+
+    @Override
+    protected RoutedDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        return new RoutedDOMRpcRoutingTableEntry(globalRpcId, keyId, impls);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/UnknownDOMRpcRoutingTableEntry.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/UnknownDOMRpcRoutingTableEntry.java
new file mode 100644 (file)
index 0000000..aadfa4a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2015 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.broker.impl;
+
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import java.util.List;
+import java.util.Map;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationNotAvailableException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+final class UnknownDOMRpcRoutingTableEntry extends AbstractDOMRpcRoutingTableEntry {
+    private final CheckedFuture<DOMRpcResult, DOMRpcException> unknownRpc;
+
+    UnknownDOMRpcRoutingTableEntry(final SchemaPath schemaPath, final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        super(schemaPath, impls);
+        unknownRpc = Futures.<DOMRpcResult, DOMRpcException>immediateFailedCheckedFuture(
+            new DOMRpcImplementationNotAvailableException("SchemaPath %s is not resolved to an RPC", schemaPath));
+    }
+
+    @Override
+    protected CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final NormalizedNode<?, ?> input) {
+        return unknownRpc;
+    }
+
+    @Override
+    protected UnknownDOMRpcRoutingTableEntry newInstance(final Map<YangInstanceIdentifier, List<DOMRpcImplementation>> impls) {
+        return new UnknownDOMRpcRoutingTableEntry(getSchemaPath(), impls);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcImplementationRegistration.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcImplementationRegistration.java
new file mode 100644 (file)
index 0000000..f0ce2b6
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (c) 2015 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 org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
+import org.opendaylight.yangtools.concepts.AbstractObjectRegistration;
+
+/**
+ * Abstract base class for {@link DOMRpcImplementationRegistration} implementations.
+ */
+public abstract class AbstractDOMRpcImplementationRegistration<T extends DOMRpcImplementation> extends AbstractObjectRegistration<T> implements DOMRpcImplementationRegistration<T> {
+    protected AbstractDOMRpcImplementationRegistration(final T instance) {
+        super(instance);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcProviderService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/AbstractDOMRpcProviderService.java
new file mode 100644 (file)
index 0000000..c137426
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2015 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.ImmutableSet;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService;
+
+/**
+ * Convenience abstract base class for {@link DOMRpcProviderService} implementations.
+ */
+public abstract class AbstractDOMRpcProviderService implements DOMRpcProviderService {
+    @Override
+    public final <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(final T implementation, final DOMRpcIdentifier... types) {
+        return registerRpcImplementation(implementation, ImmutableSet.copyOf(types));
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/DefaultDOMRpcResult.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/DefaultDOMRpcResult.java
new file mode 100644 (file)
index 0000000..269fd35
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2015 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.annotations.Beta;
+import com.google.common.base.Preconditions;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.concepts.Immutable;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Utility class implementing {@link DefaultDOMRpcResult}.
+ */
+@Beta
+public final class DefaultDOMRpcResult implements DOMRpcResult, Immutable, Serializable {
+    private static final long serialVersionUID = 1L;
+    private final Collection<RpcError> errors;
+    private final NormalizedNode<?, ?> result;
+
+    private static Collection<RpcError> asCollection(final RpcError... errors) {
+        if (errors.length == 0) {
+            return Collections.emptyList();
+        } else {
+            return Arrays.asList(errors);
+        }
+    }
+
+    public DefaultDOMRpcResult(final NormalizedNode<?, ?> result, final RpcError... errors) {
+        this(result, asCollection(errors));
+    }
+
+    public DefaultDOMRpcResult(final RpcError... errors) {
+        this(null, asCollection(errors));
+    }
+
+    public DefaultDOMRpcResult(final NormalizedNode<?, ?> result) {
+        this(result, Collections.<RpcError>emptyList());
+    }
+
+    public DefaultDOMRpcResult(final NormalizedNode<?, ?> result, final @Nonnull Collection<RpcError> errors) {
+        this.result = result;
+        this.errors = Preconditions.checkNotNull(errors);
+    }
+
+    public DefaultDOMRpcResult(final @Nonnull Collection<RpcError> errors) {
+        this(null, errors);
+    }
+
+    @Override
+    public @Nonnull Collection<RpcError> getErrors() {
+        return errors;
+    }
+
+    @Override
+    public NormalizedNode<?, ?> getResult() {
+        return result;
+    }
+
+    @Override
+    public int hashCode() {
+        int ret = errors.hashCode();
+        if (result != null) {
+            ret = 31 * ret + result.hashCode();
+        }
+        return ret;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (!(obj instanceof DefaultDOMRpcResult)) {
+            return false;
+        }
+
+        final DefaultDOMRpcResult other = (DefaultDOMRpcResult) obj;
+        if (!errors.equals(other.errors)) {
+            return false;
+        }
+        return Objects.equals(result, other.result);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcImplementation.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcImplementation.java
new file mode 100644 (file)
index 0000000..e93f941
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2015 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.CheckedFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Utility implementation which implements {@link DOMRpcImplementation} by forwarding it to
+ * a backing delegate.
+ */
+public abstract class ForwardingDOMRpcImplementation extends ForwardingObject implements DOMRpcImplementation {
+    @Override
+    protected abstract @Nonnull DOMRpcImplementation delegate();
+
+    @Override
+    public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final DOMRpcIdentifier type, final NormalizedNode<?, ?> input) {
+        return delegate().invokeRpc(type, input);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcProviderService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcProviderService.java
new file mode 100644 (file)
index 0000000..99c4cad
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2015 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.Set;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementation;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcImplementationRegistration;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService;
+
+/**
+ * Utility class which implements {@link DOMRpcProviderService} by forwarding
+ * requests to a backing instance.
+ */
+public abstract class ForwardingDOMRpcProviderService extends ForwardingObject implements DOMRpcProviderService {
+    @Override
+    protected abstract @Nonnull DOMRpcProviderService delegate();
+
+    @Override
+    public <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(final T implementation, final DOMRpcIdentifier... types) {
+        return delegate().registerRpcImplementation(implementation, types);
+    }
+
+    @Override
+    public <T extends DOMRpcImplementation> DOMRpcImplementationRegistration<T> registerRpcImplementation(final T implementation, final Set<DOMRpcIdentifier> types) {
+        return delegate().registerRpcImplementation(implementation, types);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcResult.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcResult.java
new file mode 100644 (file)
index 0000000..ba46d3f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2015 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 javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+/**
+ * Utility class which implements {@link DOMRpcResult} by forwarding all methods
+ * to a backing instance.
+ */
+public abstract class ForwardingDOMRpcResult extends ForwardingObject implements DOMRpcResult {
+    @Override
+    protected abstract @Nonnull DOMRpcResult delegate();
+
+    @Override
+    public Collection<RpcError> getErrors() {
+        return delegate().getErrors();
+    }
+
+    @Override
+    public NormalizedNode<?, ?> getResult() {
+        return delegate().getResult();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcService.java b/opendaylight/md-sal/sal-dom-spi/src/main/java/org/opendaylight/controller/md/sal/dom/spi/ForwardingDOMRpcService.java
new file mode 100644 (file)
index 0000000..976d086
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2015 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.CheckedFuture;
+import javax.annotation.Nonnull;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcAvailabilityListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcException;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcResult;
+import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+
+/**
+ * Utility {@link DOMRpcService} which forwards all requests to a backing delegate instance.
+ */
+public abstract class ForwardingDOMRpcService extends ForwardingObject implements DOMRpcService {
+    @Override
+    protected abstract @Nonnull DOMRpcService delegate();
+
+    @Override
+    public CheckedFuture<DOMRpcResult, DOMRpcException> invokeRpc(final SchemaPath type, final NormalizedNode<?, ?> input) {
+        return delegate().invokeRpc(type, input);
+    }
+
+    @Override
+    public <T extends DOMRpcAvailabilityListener> ListenerRegistration<T> registerRpcListener(final T listener) {
+        return delegate().registerRpcListener(listener);
+    }
+}
index e52fce7..e4cc80f 100644 (file)
@@ -78,6 +78,9 @@ public final class Main {
         @Arg(dest = "debug")
         public boolean debug;
 
+        @Arg(dest = "notification-file")
+        public File notificationFile;
+
         static ArgumentParser getParser() {
             final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
 
@@ -95,6 +98,11 @@ public final class Main {
                     .help("Directory containing yang schemas to describe simulated devices. Some schemas e.g. netconf monitoring and inet types are included by default")
                     .dest("schemas-dir");
 
+            parser.addArgument("--notification-file")
+                    .type(File.class)
+                    .help("Xml file containing notifications that should be sent to clients after create subscription is called")
+                    .dest("notification-file");
+
             parser.addArgument("--starting-port")
                     .type(Integer.class)
                     .setDefault(17830)
index a5f4947..0d7ee3b 100644 (file)
@@ -26,6 +26,7 @@ import io.netty.channel.local.LocalAddress;
 import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import java.io.Closeable;
+import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -71,6 +72,14 @@ import org.opendaylight.controller.netconf.monitoring.osgi.NetconfMonitoringOper
 import org.opendaylight.controller.netconf.ssh.SshProxyServer;
 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfiguration;
 import org.opendaylight.controller.netconf.ssh.SshProxyServerConfigurationBuilder;
+import org.opendaylight.controller.netconf.test.tool.rpc.DataList;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedCommit;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedCreateSubscription;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedEditConfig;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedGet;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedGetConfig;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedLock;
+import org.opendaylight.controller.netconf.test.tool.rpc.SimulatedUnLock;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceException;
 import org.opendaylight.yangtools.yang.model.repo.api.SchemaSourceRepresentation;
@@ -116,7 +125,7 @@ public class NetconfDeviceSimulator implements Closeable {
         this.nioExecutor = nioExecutor;
     }
 
-    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout) {
+    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi, final int generateConfigsTimeout, final Optional<File> notificationsFile) {
 
         final Set<Capability> capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function<ModuleBuilder, Capability>() {
             @Override
@@ -132,7 +141,7 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final SessionIdProvider idProvider = new SessionIdProvider();
 
-        final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities);
+        final SimulatedOperationProvider simulatedOperationProvider = new SimulatedOperationProvider(idProvider, capabilities, notificationsFile);
         final NetconfMonitoringOperationService monitoringService = new NetconfMonitoringOperationService(new NetconfMonitoringServiceImpl(simulatedOperationProvider));
         simulatedOperationProvider.addService(monitoringService);
 
@@ -183,7 +192,7 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
 
-        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout);
+        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi, params.generateConfigsTimeout, Optional.fromNullable(params.notificationFile));
 
         int currentPort = params.startingPort;
 
@@ -392,9 +401,9 @@ public class NetconfDeviceSimulator implements Closeable {
         private final Set<NetconfOperationService> netconfOperationServices;
 
 
-        public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set<Capability> caps) {
+        public SimulatedOperationProvider(final SessionIdProvider idProvider, final Set<Capability> caps, final Optional<File> notificationsFile) {
             this.idProvider = idProvider;
-            final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId());
+            final SimulatedOperationService simulatedOperationService = new SimulatedOperationService(caps, idProvider.getCurrentSessionId(), notificationsFile);
             this.netconfOperationServices = Sets.<NetconfOperationService>newHashSet(simulatedOperationService);
         }
 
@@ -433,10 +442,12 @@ public class NetconfDeviceSimulator implements Closeable {
         static class SimulatedOperationService implements NetconfOperationService {
             private final Set<Capability> capabilities;
             private final long currentSessionId;
+            private final Optional<File> notificationsFile;
 
-            public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId) {
+            public SimulatedOperationService(final Set<Capability> capabilities, final long currentSessionId, final Optional<File> notificationsFile) {
                 this.capabilities = capabilities;
                 this.currentSessionId = currentSessionId;
+                this.notificationsFile = notificationsFile;
             }
 
             @Override
@@ -453,7 +464,8 @@ public class NetconfDeviceSimulator implements Closeable {
                 final SimulatedCommit sCommit = new SimulatedCommit(String.valueOf(currentSessionId));
                 final SimulatedLock sLock = new SimulatedLock(String.valueOf(currentSessionId));
                 final SimulatedUnLock sUnlock = new SimulatedUnLock(String.valueOf(currentSessionId));
-                return Sets.<NetconfOperation>newHashSet(sGet,  sGetConfig, sEditConfig, sCommit, sLock, sUnlock);
+                final SimulatedCreateSubscription sCreateSubs = new SimulatedCreateSubscription(String.valueOf(currentSessionId), notificationsFile);
+                return Sets.<NetconfOperation>newHashSet(sGet,  sGetConfig, sEditConfig, sCommit, sLock, sUnlock, sCreateSubs);
             }
 
             @Override
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedCommit extends AbstractConfigNetconfOperation {
+public class SimulatedCommit extends AbstractConfigNetconfOperation {
 
-    SimulatedCommit(final String netconfSessionIdForReporting) {
+    public SimulatedCommit(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }
 
diff --git a/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java b/opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/rpc/SimulatedCreateSubscription.java
new file mode 100644 (file)
index 0000000..abf51c4
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2015 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.netconf.test.tool.rpc;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import java.io.File;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlRootElement;
+import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
+import org.opendaylight.controller.netconf.impl.NetconfServerSession;
+import org.opendaylight.controller.netconf.impl.mapping.operations.DefaultNetconfOperation;
+import org.opendaylight.controller.netconf.util.mapping.AbstractLastNetconfOperation;
+import org.opendaylight.controller.netconf.util.xml.XmlElement;
+import org.opendaylight.controller.netconf.util.xml.XmlUtil;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.xml.sax.SAXException;
+
+public class SimulatedCreateSubscription extends AbstractLastNetconfOperation implements DefaultNetconfOperation {
+
+    private NetconfServerSession session;
+    private final Optional<Notifications> notifications;
+    private ScheduledExecutorService scheduledExecutorService;
+
+    public SimulatedCreateSubscription(final String id, final Optional<File> notificationsFile) {
+        super(id);
+        if(notificationsFile.isPresent()) {
+            notifications = Optional.of(loadNotifications(notificationsFile.get()));
+            scheduledExecutorService = Executors.newScheduledThreadPool(1);
+        } else {
+            notifications = Optional.absent();
+        }
+    }
+
+    private Notifications loadNotifications(final File file) {
+        try {
+            final JAXBContext jaxbContext = JAXBContext.newInstance(Notifications.class);
+            final Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
+            return (Notifications) jaxbUnmarshaller.unmarshal(file);
+        } catch (final JAXBException e) {
+            throw new IllegalArgumentException("Canot parse file " + file + " as a notifications file", e);
+        }
+    }
+
+    @Override
+    protected String getOperationName() {
+        return "create-subscription";
+    }
+
+    @Override
+    protected String getOperationNamespace() {
+        return "urn:ietf:params:xml:ns:netconf:notification:1.0";
+    }
+
+    @Override
+    protected Element handleWithNoSubsequentOperations(final Document document, final XmlElement operationElement) throws NetconfDocumentedException {
+
+
+        if(notifications.isPresent()) {
+            long delayAggregator = 0;
+            System.console().writer().println("Scheduling notifications " + notifications.get());
+
+            for (final Notification notification : notifications.get().getNotificationList()) {
+                for (int i = 0; i <= notification.getTimes(); i++) {
+
+                    delayAggregator += notification.getDelayInSeconds();
+
+                    System.console().writer().println("Times " + notification.getTimes());
+                    scheduledExecutorService.schedule(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                System.console().writer().println("Sending actual notification " + notification);
+                                Preconditions.checkState(session != null, "Session is not set, cannot process notifications");
+                                session.sendMessage(parseNetconfNotification(notification.getContent()));
+                            } catch (IOException | SAXException e) {
+                                throw new IllegalStateException("Unable to process notification " + notification, e);
+                            }
+                        }
+                    }, delayAggregator, TimeUnit.SECONDS);
+                }
+            }
+        }
+        return XmlUtil.createElement(document, XmlNetconfConstants.OK, Optional.<String>absent());
+    }
+
+    private static NetconfMessage parseNetconfNotification(String content) throws IOException, SAXException {
+        final int startEventTime = content.indexOf("<eventTime>") + "<eventTime>".length();
+        final int endEventTime = content.indexOf("</eventTime>");
+        final String eventTime = content.substring(startEventTime, endEventTime);
+        if(eventTime.equals("XXXX")) {
+            content = content.replace(eventTime, new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX").format(new Date()));
+        }
+
+        return new NetconfMessage(XmlUtil.readXmlToDocument(content));
+    }
+
+    @Override
+    public void setNetconfSession(final NetconfServerSession s) {
+        this.session = s;
+    }
+
+    @XmlRootElement(name = "notifications")
+    public static final class Notifications {
+
+        @javax.xml.bind.annotation.XmlElement(nillable =  false, name = "notification", required = true)
+        private List<Notification> notificationList;
+
+        public List<Notification> getNotificationList() {
+            return notificationList;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("Notifications{");
+            sb.append("notificationList=").append(notificationList);
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+
+    public static final class Notification {
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "delay")
+        private long delayInSeconds;
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "times")
+        private long times;
+
+        @javax.xml.bind.annotation.XmlElement(nillable = false, name = "content", required = true)
+        private String content;
+
+        public long getDelayInSeconds() {
+            return delayInSeconds;
+        }
+
+        public long getTimes() {
+            return times;
+        }
+
+        public String getContent() {
+            return content;
+        }
+
+        @Override
+        public String toString() {
+            final StringBuffer sb = new StringBuffer("Notification{");
+            sb.append("delayInSeconds=").append(delayInSeconds);
+            sb.append(", times=").append(times);
+            sb.append(", content='").append(content).append('\'');
+            sb.append('}');
+            return sb.toString();
+        }
+    }
+}
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -19,13 +19,13 @@ import org.w3c.dom.Attr;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedEditConfig extends AbstractConfigNetconfOperation {
+public class SimulatedEditConfig extends AbstractConfigNetconfOperation {
     private static final String DELETE_EDIT_CONFIG = "delete";
     private static final String OPERATION = "operation";
     private static final String REMOVE_EDIT_CONFIG = "remove";
     private final DataList storage;
 
-    SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedEditConfig(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,11 +17,11 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedGet extends AbstractConfigNetconfOperation {
+public class SimulatedGet extends AbstractConfigNetconfOperation {
 
     private final DataList storage;
 
-    SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedGet(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,11 +17,11 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedGetConfig extends AbstractConfigNetconfOperation {
+public class SimulatedGetConfig extends AbstractConfigNetconfOperation {
 
     private final DataList storage;
 
-    SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) {
+    public SimulatedGetConfig(final String netconfSessionIdForReporting, final DataList storage) {
         super(null, netconfSessionIdForReporting);
         this.storage = storage;
     }
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedLock extends AbstractConfigNetconfOperation {
+public class SimulatedLock extends AbstractConfigNetconfOperation {
 
-    SimulatedLock(final String netconfSessionIdForReporting) {
+    public SimulatedLock(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }
 
@@ -6,7 +6,7 @@
  * and is available at http://www.eclipse.org/legal/epl-v10.html
  */
 
-package org.opendaylight.controller.netconf.test.tool;
+package org.opendaylight.controller.netconf.test.tool.rpc;
 
 import com.google.common.base.Optional;
 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
@@ -17,9 +17,9 @@ import org.opendaylight.controller.netconf.util.xml.XmlUtil;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
-class SimulatedUnLock extends AbstractConfigNetconfOperation {
+public class SimulatedUnLock extends AbstractConfigNetconfOperation {
 
-    SimulatedUnLock(final String netconfSessionIdForReporting) {
+    public SimulatedUnLock(final String netconfSessionIdForReporting) {
         super(null, netconfSessionIdForReporting);
     }
 
index 1607408..9eaebb2 100644 (file)
@@ -10,9 +10,6 @@
   <artifactId>networkconfig.neutron.implementation</artifactId>
   <version>0.5.0-SNAPSHOT</version>
   <packaging>bundle</packaging>
-  <properties>
-    <enunciate.version>1.26.2</enunciate.version>
-  </properties>
   <dependencies>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
index 0eecca0..e61a8e5 100644 (file)
@@ -3,9 +3,9 @@
   <modelVersion>4.0.0</modelVersion>
   <parent>
     <groupId>org.opendaylight.controller</groupId>
-    <artifactId>commons.opendaylight</artifactId>
+    <artifactId>enunciate-parent</artifactId>
     <version>1.5.0-SNAPSHOT</version>
-    <relativePath>../../../commons/opendaylight</relativePath>
+    <relativePath>../../../commons/enunciate-parent</relativePath>
   </parent>
   <artifactId>networkconfig.neutron.northbound</artifactId>
   <version>0.5.0-SNAPSHOT</version>
           <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
         </configuration>
       </plugin>
-      <plugin>
-        <groupId>org.codehaus.enunciate</groupId>
-        <artifactId>maven-enunciate-plugin</artifactId>
-      </plugin>
     </plugins>
   </build>
   <scm>
index 33043d4..b97a554 100644 (file)
@@ -187,13 +187,19 @@ public class NeutronFirewallNorthbound {
             firewallInterface.addNeutronFirewall(singleton);
             Object[] instances = NeutronUtil.getInstances(INeutronFirewallAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronFirewallAware service = (INeutronFirewallAware) instance;
-                    int status = service.canCreateNeutronFirewall(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                        int status = service.canCreateNeutronFirewall(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             firewallInterface.addNeutronFirewall(singleton);
             if (instances != null) {
@@ -220,13 +226,19 @@ public class NeutronFirewallNorthbound {
                     throw new BadRequestException("Firewall UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronFirewallAware service = (INeutronFirewallAware) instance;
-                        int status = service.canCreateNeutronFirewall(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                            int status = service.canCreateNeutronFirewall(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
 
@@ -298,13 +310,19 @@ public class NeutronFirewallNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallAware service = (INeutronFirewallAware) instance;
-                int status = service.canUpdateNeutronFirewall(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                    int status = service.canUpdateNeutronFirewall(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -352,13 +370,19 @@ public class NeutronFirewallNorthbound {
         NeutronFirewall singleton = firewallInterface.getNeutronFirewall(firewallUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallAware service = (INeutronFirewallAware) instance;
-                int status = service.canDeleteNeutronFirewall(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                    int status = service.canDeleteNeutronFirewall(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
index 08e5631..e9b813d 100644 (file)
@@ -184,13 +184,19 @@ public class NeutronFirewallPolicyNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronFirewallPolicyAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
-                    int status = service.canCreateNeutronFirewallPolicy(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                        int status = service.canCreateNeutronFirewallPolicy(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             firewallPolicyInterface.addNeutronFirewallPolicy(singleton);
             if (instances != null) {
@@ -218,13 +224,19 @@ public class NeutronFirewallPolicyNorthbound {
                     throw new BadRequestException("Firewall Policy UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
-                        int status = service.canCreateNeutronFirewallPolicy(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                            int status = service.canCreateNeutronFirewallPolicy(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -295,13 +307,19 @@ public class NeutronFirewallPolicyNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallPolicyAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
-                int status = service.canUpdateNeutronFirewallPolicy(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                    int status = service.canUpdateNeutronFirewallPolicy(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -349,13 +367,19 @@ public class NeutronFirewallPolicyNorthbound {
         NeutronFirewallPolicy singleton = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallPolicyAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
-                int status = service.canDeleteNeutronFirewallPolicy(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                    int status = service.canDeleteNeutronFirewallPolicy(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         firewallPolicyInterface.removeNeutronFirewallPolicy(firewallPolicyUUID);
index 5e51711..40b830d 100644 (file)
@@ -220,13 +220,19 @@ public class NeutronFirewallRulesNorthbound {
             firewallRuleInterface.addNeutronFirewallRule(singleton);
             Object[] instances = NeutronUtil.getInstances(INeutronFirewallRuleAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
-                    int status = service.canCreateNeutronFirewallRule(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                        int status = service.canCreateNeutronFirewallRule(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             // add rule to cache
             singleton.initDefaults();
@@ -256,13 +262,19 @@ public class NeutronFirewallRulesNorthbound {
                     throw new BadRequestException("Firewall Rule UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
-                        int status = service.canCreateNeutronFirewallRule(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                            int status = service.canCreateNeutronFirewallRule(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -342,13 +354,19 @@ public class NeutronFirewallRulesNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallRuleAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
-                int status = service.canUpdateNeutronFirewallRule(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                    int status = service.canUpdateNeutronFirewallRule(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -399,13 +417,19 @@ public class NeutronFirewallRulesNorthbound {
         NeutronFirewallRule singleton = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronFirewallRuleAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
-                int status = service.canDeleteNeutronFirewallRule(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                    int status = service.canDeleteNeutronFirewallRule(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
index 812a09a..3e6c2a4 100644 (file)
@@ -242,12 +242,18 @@ public class NeutronFloatingIPsNorthbound {
             }
             Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
-                    int status = service.canCreateFloatingIP(singleton);
-                    if (status < 200 || status > 299)
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                        int status = service.canCreateFloatingIP(singleton);
+                        if (status < 200 || status > 299)
+                            return Response.status(status).build();
+                    }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             floatingIPInterface.addFloatingIP(singleton);
             if (instances != null) {
@@ -363,12 +369,18 @@ public class NeutronFloatingIPsNorthbound {
         NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
-                int status = service.canUpdateFloatingIP(singleton, target);
-                if (status < 200 || status > 299)
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                    int status = service.canUpdateFloatingIP(singleton, target);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);
         target = floatingIPInterface.getFloatingIP(floatingipUUID);
@@ -406,12 +418,18 @@ public class NeutronFloatingIPsNorthbound {
         NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronFloatingIPAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
-                int status = service.canDeleteFloatingIP(singleton);
-                if (status < 200 || status > 299)
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                    int status = service.canDeleteFloatingIP(singleton);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         floatingIPInterface.removeFloatingIP(floatingipUUID);
         if (instances != null) {
index 85aba5d..aa30e94 100644 (file)
@@ -210,13 +210,19 @@ public class NeutronLoadBalancerHealthMonitorNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerHealthMonitorAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
-                    int status = service.canCreateNeutronLoadBalancerHealthMonitor(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerHealthMonitor(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(singleton);
             if (instances != null) {
@@ -245,13 +251,19 @@ public class NeutronLoadBalancerHealthMonitorNorthbound {
                     throw new BadRequestException("LoadBalancerHealthMonitor UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
-                        int status = service.canCreateNeutronLoadBalancerHealthMonitor(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                            int status = service.canCreateNeutronLoadBalancerHealthMonitor(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -328,13 +340,19 @@ public class NeutronLoadBalancerHealthMonitorNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerHealthMonitorAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
-                int status = service.canUpdateNeutronLoadBalancerHealthMonitor(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                    int status = service.canUpdateNeutronLoadBalancerHealthMonitor(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -386,13 +404,19 @@ public class NeutronLoadBalancerHealthMonitorNorthbound {
         NeutronLoadBalancerHealthMonitor singleton = loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerHealthMonitorAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
-                int status = service.canDeleteNeutronLoadBalancerHealthMonitor(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                    int status = service.canDeleteNeutronLoadBalancerHealthMonitor(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         loadBalancerHealthMonitorInterface.removeNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
         if (instances != null) {
index 345c7ee..5d877c5 100644 (file)
@@ -198,13 +198,19 @@ public class NeutronLoadBalancerListenerNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerListenerAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
-                    int status = service.canCreateNeutronLoadBalancerListener(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerListener(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             loadBalancerListenerInterface.addNeutronLoadBalancerListener(singleton);
             if (instances != null) {
@@ -232,13 +238,19 @@ public class NeutronLoadBalancerListenerNorthbound {
                     throw new BadRequestException("LoadBalancerListener UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
-                        int status = service.canCreateNeutronLoadBalancerListener(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                            int status = service.canCreateNeutronLoadBalancerListener(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -312,13 +324,19 @@ public class NeutronLoadBalancerListenerNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerListenerAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
-                int status = service.canUpdateNeutronLoadBalancerListener(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                    int status = service.canUpdateNeutronLoadBalancerListener(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -366,13 +384,19 @@ public class NeutronLoadBalancerListenerNorthbound {
         NeutronLoadBalancerListener singleton = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerListenerAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
-                int status = service.canDeleteNeutronLoadBalancerListener(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                    int status = service.canDeleteNeutronLoadBalancerListener(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         loadBalancerListenerInterface.removeNeutronLoadBalancerListener(loadBalancerListenerID);
index 308041f..67557ce 100644 (file)
@@ -186,14 +186,21 @@ public class NeutronLoadBalancerNorthbound {
             }
             Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
-                    int status = service.canCreateNeutronLoadBalancer(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                        int status = service.canCreateNeutronLoadBalancer(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
+
             loadBalancerInterface.addNeutronLoadBalancer(singleton);
             if (instances != null) {
                 for (Object instance : instances) {
@@ -220,13 +227,19 @@ public class NeutronLoadBalancerNorthbound {
                     throw new BadRequestException("Load Balancer Pool UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
-                        int status = service.canCreateNeutronLoadBalancer(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                            int status = service.canCreateNeutronLoadBalancer(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -298,13 +311,19 @@ public class NeutronLoadBalancerNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
-                int status = service.canUpdateNeutronLoadBalancer(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                    int status = service.canUpdateNeutronLoadBalancer(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -355,15 +374,22 @@ public class NeutronLoadBalancerNorthbound {
         NeutronLoadBalancer singleton = loadBalancerInterface.getNeutronLoadBalancer(loadBalancerID);
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
-                int status = service.canDeleteNeutronLoadBalancer(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                    int status = service.canDeleteNeutronLoadBalancer(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
+
         loadBalancerInterface.removeNeutronLoadBalancer(loadBalancerID);
         if (instances != null) {
             for (Object instance : instances) {
index f954067..22d118a 100644 (file)
@@ -200,14 +200,21 @@ public Response createLoadBalancerPoolMember(
 
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerPoolMemberAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
-                int status = service.canCreateNeutronLoadBalancerPoolMember(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                    int status = service.canCreateNeutronLoadBalancerPoolMember(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
+
         if (instances != null) {
             for (Object instance : instances) {
                 INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
@@ -242,13 +249,19 @@ public Response createLoadBalancerPoolMember(
                 throw new BadRequestException("Load Balancer PoolMember UUID already exists");
             }
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
-                    int status = service.canCreateNeutronLoadBalancerPoolMember(test);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerPoolMember(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
         }
         /*
@@ -334,13 +347,19 @@ public Response deleteLoadBalancerPoolMember(
 
     Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerPoolMemberAware.class, this);
     if (instances != null) {
-        for (Object instance : instances) {
-            INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
-            int status = service.canDeleteNeutronLoadBalancerPoolMember(singleton);
-            if (status < 200 || status > 299) {
-                return Response.status(status).build();
+        if (instances.length > 0) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                int status = service.canDeleteNeutronLoadBalancerPoolMember(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
             }
+        } else {
+            throw new ServiceUnavailableException("No providers registered.  Please try again later");
         }
+    } else {
+        throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
     }
 
     if (instances != null) {
index 77bb525..ea4e2d1 100644 (file)
@@ -198,13 +198,19 @@ public class NeutronLoadBalancerPoolNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
-                    int status = service.canCreateNeutronLoadBalancerPool(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerPool(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
             loadBalancerPoolInterface.addNeutronLoadBalancerPool(singleton);
             if (instances != null) {
@@ -232,13 +238,19 @@ public class NeutronLoadBalancerPoolNorthbound {
                     throw new BadRequestException("Load Balancer Pool UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
-                        int status = service.canCreateNeutronLoadBalancerPool(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                            int status = service.canCreateNeutronLoadBalancerPool(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
             /*
@@ -311,13 +323,19 @@ public class NeutronLoadBalancerPoolNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
-                int status = service.canUpdateNeutronLoadBalancerPool(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                    int status = service.canUpdateNeutronLoadBalancerPool(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
@@ -366,13 +384,19 @@ public class NeutronLoadBalancerPoolNorthbound {
         NeutronLoadBalancerPool singleton = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronLoadBalancerPoolAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
-                int status = service.canDeleteNeutronLoadBalancerPool(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                    int status = service.canDeleteNeutronLoadBalancerPool(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         /*
index 9c99f34..3a3c657 100644 (file)
@@ -204,13 +204,19 @@ public class NeutronNetworksNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronNetworkAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronNetworkAware service = (INeutronNetworkAware) instance;
-                    int status = service.canCreateNetwork(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                        int status = service.canCreateNetwork(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
 
             // add network to cache
@@ -242,13 +248,19 @@ public class NeutronNetworksNorthbound {
                     throw new BadRequestException("network UUID already exists");
                 }
                 if (instances != null) {
-                    for (Object instance: instances) {
-                        INeutronNetworkAware service = (INeutronNetworkAware) instance;
-                        int status = service.canCreateNetwork(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance: instances) {
+                            INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                            int status = service.canCreateNetwork(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
                 testMap.put(test.getID(),test);
             }
@@ -312,14 +324,20 @@ public class NeutronNetworksNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronNetworkAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronNetworkAware service = (INeutronNetworkAware) instance;
-                NeutronNetwork original = networkInterface.getNetwork(netUUID);
-                int status = service.canUpdateNetwork(delta, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                    NeutronNetwork original = networkInterface.getNetwork(netUUID);
+                    int status = service.canUpdateNetwork(delta, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         // update network object and return the modified object
@@ -366,14 +384,21 @@ public class NeutronNetworksNorthbound {
         NeutronNetwork singleton = networkInterface.getNetwork(netUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronNetworkAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronNetworkAware service = (INeutronNetworkAware) instance;
-                int status = service.canDeleteNetwork(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                    int status = service.canDeleteNetwork(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
+
         networkInterface.removeNetwork(netUUID);
         if (instances != null) {
             for (Object instance : instances) {
index 23f4979..5ff3de5 100644 (file)
@@ -259,16 +259,21 @@ public class NeutronPortsNorthbound {
 
             Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronPortAware service = (INeutronPortAware) instance;
-                    int status = service.canCreatePort(singleton);
-                    if (status < 200 || status > 299) {
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronPortAware service = (INeutronPortAware) instance;
+                        int status = service.canCreatePort(singleton);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
                     }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
 
-
             // add the port to the cache
             portInterface.addPort(singleton);
             if (instances != null) {
@@ -353,13 +358,19 @@ public class NeutronPortsNorthbound {
                     }
                 }
                 if (instances != null) {
-                    for (Object instance : instances) {
-                        INeutronPortAware service = (INeutronPortAware) instance;
-                        int status = service.canCreatePort(test);
-                        if (status < 200 || status > 299) {
-                            return Response.status(status).build();
+                    if (instances.length > 0) {
+                        for (Object instance : instances) {
+                            INeutronPortAware service = (INeutronPortAware) instance;
+                            int status = service.canCreatePort(test);
+                            if (status < 200 || status > 299) {
+                                return Response.status(status).build();
+                            }
                         }
+                    } else {
+                        throw new ServiceUnavailableException("No providers registered.  Please try again later");
                     }
+                } else {
+                    throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
                 }
             }
 
@@ -429,13 +440,19 @@ public class NeutronPortsNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronPortAware service = (INeutronPortAware) instance;
-                int status = service.canUpdatePort(singleton, original);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronPortAware service = (INeutronPortAware) instance;
+                    int status = service.canUpdatePort(singleton, original);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
 
         // Verify the new fixed ips are valid
@@ -511,13 +528,19 @@ public class NeutronPortsNorthbound {
         NeutronPort singleton = portInterface.getPort(portUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronPortAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronPortAware service = (INeutronPortAware) instance;
-                int status = service.canDeletePort(singleton);
-                if (status < 200 || status > 299) {
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronPortAware service = (INeutronPortAware) instance;
+                    int status = service.canDeletePort(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
                 }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         portInterface.removePort(portUUID);
         if (instances != null) {
index 45e84f4..ccf5ddd 100644 (file)
@@ -194,12 +194,18 @@ public class NeutronRoutersNorthbound {
             }
             Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
             if (instances != null) {
-                for (Object instance : instances) {
-                    INeutronRouterAware service = (INeutronRouterAware) instance;
-                    int status = service.canCreateRouter(singleton);
-                    if (status < 200 || status > 299)
-                        return Response.status(status).build();
+                if (instances.length > 0) {
+                    for (Object instance : instances) {
+                        INeutronRouterAware service = (INeutronRouterAware) instance;
+                        int status = service.canCreateRouter(singleton);
+                        if (status < 200 || status > 299)
+                            return Response.status(status).build();
+                    }
+                } else {
+                    throw new ServiceUnavailableException("No providers registered.  Please try again later");
                 }
+            } else {
+                throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
             }
 
             /*
@@ -270,12 +276,18 @@ public class NeutronRoutersNorthbound {
 
         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronRouterAware service = (INeutronRouterAware) instance;
-                int status = service.canUpdateRouter(singleton, original);
-                if (status < 200 || status > 299)
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    int status = service.canUpdateRouter(singleton, original);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         /*
          * if the external gateway info is being changed, verify that the new network
@@ -335,12 +347,18 @@ public class NeutronRoutersNorthbound {
         NeutronRouter singleton = routerInterface.getRouter(routerUUID);
         Object[] instances = NeutronUtil.getInstances(INeutronRouterAware.class, this);
         if (instances != null) {
-            for (Object instance : instances) {
-                INeutronRouterAware service = (INeutronRouterAware) instance;
-                int status = service.canDeleteRouter(singleton);
-                if (status < 200 || status > 299)
-                    return Response.status(status).build();
+            if (instances.length > 0) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    int status = service.canDeleteRouter(singleton);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            } else {
+                throw new ServiceUnavailableException("No providers registered.  Please try again later");
             }
+        } else {
+            throw new ServiceUnavailableException("Couldn't get providers list.  Please try again later");
         }
         routerInterface.removeRouter(routerUUID);
         if (instances != null) {
@@