Merge "Bug 1430: Off-load notifications from single commit thread"
authorDevin Avery <devin.avery@brocade.com>
Mon, 11 Aug 2014 15:28:26 +0000 (15:28 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 11 Aug 2014 15:28:26 +0000 (15:28 +0000)
80 files changed:
opendaylight/commons/opendaylight/pom.xml
opendaylight/md-sal/sal-clustering-commons/src/main/java/org/opendaylight/controller/cluster/datastore/node/utils/PathUtils.java
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/cluster/datastore/node/NormalizedNodeToNodeCodecTest.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/AbortTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CanCommitTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CloseDataChangeListenerRegistration.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CommitTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/CreateTransactionChain.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/PreCommitTransaction.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/messages/PreCommitTransactionReply.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/utils/InstanceIdentifierUtils.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/tree/ListenerTree.java
opendaylight/md-sal/sal-remoterpc-connector/pom.xml
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/RpcManager.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTable.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Bucket.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Copier.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Messages.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/RpcBrokerTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOldTest.java [moved from opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableTest.java with 97% similarity]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfImpl.java
opendaylight/md-sal/sal-rest-docgen/pom.xml
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGenerator.java
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/BaseYangSwaggerGenerator.java
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/impl/ModelGenerator.java
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java
opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/util/RestDocgenUtil.java [new file with mode: 0644]
opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/ApiDocGeneratorTest.java
opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/DocGenTestHelper.java
opendaylight/md-sal/sal-rest-docgen/src/test/java/org/opendaylight/controller/sal/rest/doc/impl/MountPointSwaggerTest.java
opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_augmented.yang [new file with mode: 0644]
opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_short.yang
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/Activator.java
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerHealthMonitorInterface.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerInterface.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerListenerInterface.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolInterface.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolMemberInterface.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerAware.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerCRUD.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorAware.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorCRUD.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerAware.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerCRUD.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolAware.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolCRUD.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberAware.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberCRUD.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberRequest.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronCRUDInterfaces.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancer.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerHealthMonitor.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerListener.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPool.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPoolMember.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronLoadBalancerPoolMemberRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java

index 4f678f685473f5289dd73bae023ae5a0a4c271c5..8797c7e85c7c0abbb06fc82df8f06783fc74b2d2 100644 (file)
             <artifactId>akka-osgi_${scala.version}</artifactId>
             <version>${akka.version}</version>
         </dependency>
+        <dependency>
+            <groupId>com.typesafe.akka</groupId>
+            <artifactId>akka-slf4j_${scala.version}</artifactId>
+            <version>${akka.version}</version>
+        </dependency>
       <dependency>
         <groupId>commons-codec</groupId>
         <artifactId>commons-codec</artifactId>
index cf5174319d2128518f70391d0d459ad5af26b2cf..1dd0f3b8278407752b91afbb24548eb857385cbc 100644 (file)
@@ -12,18 +12,19 @@ package org.opendaylight.controller.cluster.datastore.node.utils;
 
 public class PathUtils {
     public static String getParentPath(String currentElementPath){
-        String parentPath = "";
+        StringBuilder parentPath = new StringBuilder();
 
         if(currentElementPath != null){
             String[] parentPaths = currentElementPath.split("/");
             if(parentPaths.length > 2){
                 for(int i=0;i<parentPaths.length-1;i++){
                     if(parentPaths[i].length() > 0){
-                        parentPath += "/" + parentPaths[i];
+                        parentPath.append("/");
+                        parentPath.append(parentPaths[i]);
                     }
                 }
             }
         }
-        return parentPath;
+        return parentPath.toString();
     }
 }
index 1b85d46fc6ebdfa9b13de079db728b9dadf2beac..bdad86ddc1e8fb5521607fbb91a575a99e677d38 100644 (file)
@@ -78,8 +78,12 @@ public class NormalizedNodeToNodeCodecTest {
 
     NormalizedNodeToNodeCodec codec =
         new NormalizedNodeToNodeCodec(schemaContext);
+    long start = System.currentTimeMillis();
     Container container =
         codec.encode(instanceIdentifierFromString(id), output);
+    long end = System.currentTimeMillis();
+
+    System.out.println("Timetaken to encode :"+(end-start));
 
     assertNotNull(container);
     assertEquals(id, container.getParentPath() + "/"
@@ -89,8 +93,12 @@ public class NormalizedNodeToNodeCodecTest {
     // first get the node representation of normalized node
     final Node node = container.getNormalizedNode();
 
+    start = System.currentTimeMillis();
     NormalizedNode<?, ?> normalizedNode =
         codec.decode(instanceIdentifierFromString(id), node);
+    end = System.currentTimeMillis();
+
+    System.out.println("Timetaken to decode :"+(end-start));
 
     assertEquals(normalizedNode.getValue().toString(), output.getValue()
         .toString());
index 4515bd70427a6eca892bb61115817941684d0a1c..c639064036e82ff80ea5556f769af60bcecbec51 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class AbortTransaction implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransaction.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransaction.class;
 
   @Override
   public Object toSerializable() {
index 31a06fe4c51f66329dd2b85dc49bad38afeb7b25..88e26401f700a449094960aaa784f984e9a27253 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class AbortTransactionReply implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransactionReply.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.AbortTransactionReply.class;
 
 
   @Override
index 2c032aff65ea569567b09595f76b9b52a1108124..08f81c121f1d115b991005e945f2f03c4a8c1892 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CanCommitTransaction implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CanCommitTransaction.class;
 
   @Override
   public Object toSerializable() {
index 57237bcbe219d0a93ba0de4d25001683ed425bed..a54ee6209c8d75b36681cfec470f44a7bcbae593 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.registration.ListenerRegistrationMessages;
 
 public class CloseDataChangeListenerRegistration implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ListenerRegistrationMessages.CloseDataChangeListenerRegistration.class;
+  public static final Class SERIALIZABLE_CLASS = ListenerRegistrationMessages.CloseDataChangeListenerRegistration.class;
   @Override
   public Object toSerializable() {
     return ListenerRegistrationMessages.CloseDataChangeListenerRegistration.newBuilder().build();
index 14187139aafefd1758dd0dff444882b1ae4c54c9..92138a769c1b4b0d3b3a7f4749313cc4c458002a 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommitCohortMessages;
 
 public class CommitTransaction implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransaction.class;
+  public static final  Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransaction.class;
 
   @Override
   public Object toSerializable() {
index afeba298797ea2aead2879ec98d4100bde0996cd..5751b71037ba84e97a68834c8e28a1399e7c1d36 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommit
 
 public class CommitTransactionReply implements SerializableMessage {
 
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransactionReply.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.CommitTransactionReply.class;
 
   @Override
   public Object toSerializable() {
index b27ad86be987097b9bb9c37713a50116bfa5116e..d5c9e21611af20df37bb1999d00ead9a44495fda 100644 (file)
@@ -13,7 +13,7 @@ import org.opendaylight.controller.protobuff.messages.transaction.ShardTransacti
 
 
 public class CreateTransaction implements SerializableMessage {
-  public static Class SERIALIZABLE_CLASS = ShardTransactionMessages.CreateTransaction.class;
+  public static final Class SERIALIZABLE_CLASS = ShardTransactionMessages.CreateTransaction.class;
   private final String transactionId;
   private final int transactionType;
 
index 6339749f7bb298f27238493dfa999035f48d70ad..8dd04e540e881baf2ac1aefa60671b8803e96280 100644 (file)
@@ -11,7 +11,7 @@ package org.opendaylight.controller.cluster.datastore.messages;
 import org.opendaylight.controller.protobuff.messages.transaction.ShardTransactionChainMessages;
 
 public class CreateTransactionChain implements SerializableMessage{
-  public static Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChain.class;
+  public static final Class SERIALIZABLE_CLASS = ShardTransactionChainMessages.CreateTransactionChain.class;
 
   @Override
   public Object toSerializable() {
index 1e5a05329b72c38b72637a6ceaeee3002741b64e..dae4cec3c3a606c059771e9335317d1d75c233d7 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommit
 
 public class PreCommitTransaction implements SerializableMessage{
 
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.PreCommitTransaction.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.PreCommitTransaction.class;
 
   @Override
   public Object toSerializable() {
index 1aedae3ae72fb51b0794e12ee338c0ca478c97f4..fc07bfcb4b786793f02125bfad01f77088bcfe33 100644 (file)
@@ -12,7 +12,7 @@ import org.opendaylight.controller.protobuff.messages.cohort3pc.ThreePhaseCommit
 
 public class PreCommitTransactionReply implements SerializableMessage{
 
-  public static Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.PreCommitTransactionReply.class;
+  public static final Class SERIALIZABLE_CLASS = ThreePhaseCommitCohortMessages.PreCommitTransactionReply.class;
 
   @Override
   public Object toSerializable() {
index 20268a67449d2ff1bcddeef240b91ef4f287a774..c154b81e3567d19e6be40db61dbe41690ebca78e 100644 (file)
@@ -18,19 +18,21 @@ public class InstanceIdentifierUtils {
         .getLogger(InstanceIdentifierUtils.class);
 
     public static String getParentPath(String currentElementPath) {
-        String parentPath = "";
+
+        StringBuilder parentPath = new StringBuilder();
 
         if (currentElementPath != null) {
             String[] parentPaths = currentElementPath.split("/");
             if (parentPaths.length > 2) {
                 for (int i = 0; i < parentPaths.length - 1; i++) {
                     if (parentPaths[i].length() > 0) {
-                        parentPath += "/" + parentPaths[i];
+                        parentPath.append( "/");
+                        parentPath.append( parentPaths[i]);
                     }
                 }
             }
         }
-        return parentPath;
+        return parentPath.toString();
     }
 
     @Deprecated
index 39152767dd0b063c373adaed9fd5704b8702719c..ac7a31818720dcc494bfa2df714ea862bed2ba45 100644 (file)
@@ -144,7 +144,10 @@ public final class ListenerTree  {
 
     /**
      * A walking context, pretty much equivalent to an iterator, but it
-     * exposes the undelying tree structure.
+     * exposes the underlying tree structure.
+     */
+    /*
+     * FIXME: BUG-1511: split this class out as ListenerWalker.
      */
     public static final class Walker implements AutoCloseable {
         private final Lock lock;
@@ -177,6 +180,9 @@ public final class ListenerTree  {
      * only as long as the {@link org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker} instance through which it is reached remains
      * unclosed.
      */
+    /*
+     * FIXME: BUG-1511: split this class out as ListenerNode.
+     */
     public static final class Node implements StoreTreeNode<Node>, Identifiable<PathArgument> {
         private final Collection<DataChangeListenerRegistration<?>> listeners = new ArrayList<>();
         private final Map<PathArgument, Node> children = new HashMap<>();
index a2bee8ffee7295c8c086365fafa1651235f4efdc..674c5bf5a596bb03a34f785d854ffdb305aac12b 100644 (file)
       <groupId>com.typesafe.akka</groupId>
       <artifactId>akka-osgi_${scala.version}</artifactId>
     </dependency>
+
+  <dependency>
+     <groupId>com.typesafe.akka</groupId>
+     <artifactId>akka-slf4j_${scala.version}</artifactId>
+  </dependency>
     <!-- SAL Dependencies -->
 
     <dependency>
       <scope>test</scope>
     </dependency>
 
-    <dependency>
+      <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
       <version>${slf4j.version}</version>
index 5c56455bd0c208a40709b4a221fb6a22ed0b65a1..514a2f141daea13e5e71ec1f0f0a8acf9eadcf9d 100644 (file)
@@ -17,7 +17,7 @@ import akka.japi.Creator;
 import akka.japi.Function;
 import org.opendaylight.controller.remote.rpc.messages.UpdateSchemaContext;
 import org.opendaylight.controller.remote.rpc.registry.ClusterWrapper;
-import org.opendaylight.controller.remote.rpc.registry.RpcRegistry;
+import org.opendaylight.controller.remote.rpc.registry.RpcRegistryOld;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -72,7 +72,7 @@ public class RpcManager extends AbstractUntypedActor {
   private void createRpcActors() {
     LOG.debug("Create rpc registry and broker actors");
 
-    rpcRegistry = getContext().actorOf(RpcRegistry.props(clusterWrapper), ActorConstants.RPC_REGISTRY);
+    rpcRegistry = getContext().actorOf(RpcRegistryOld.props(clusterWrapper), ActorConstants.RPC_REGISTRY);
     rpcBroker = getContext().actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext), ActorConstants.RPC_BROKER);
   }
 
index 5e19653a22d21ed83ae3eec370290dc37f50c1ce..c25aa523e2e0823769a28e9dc01b32da711b0ae5 100644 (file)
  * 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.remote.rpc.registry;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableSet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import akka.actor.ActorRef;
+import akka.japi.Option;
+import akka.japi.Pair;
+import org.opendaylight.controller.remote.rpc.registry.gossip.Copier;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
 
+import java.io.Serializable;
 import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-public class RoutingTable<I, R> {
-
-  private final Logger LOG = LoggerFactory.getLogger(RoutingTable.class);
-
-  private ConcurrentMap<I,R> globalRpcMap = new ConcurrentHashMap<>();
-  private ConcurrentMap<I, LinkedHashSet<R>> routedRpcMap = new ConcurrentHashMap<>();
-
-  public ConcurrentMap<I, R> getGlobalRpcMap() {
-    return globalRpcMap;
-  }
-
-  public ConcurrentMap<I, LinkedHashSet<R>> getRoutedRpcMap() {
-    return routedRpcMap;
-  }
-
-  public R getGlobalRoute(final I routeId) {
-    Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!");
-    return globalRpcMap.get(routeId);
-  }
-
-  public void addGlobalRoute(final I routeId, final R route) {
-    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
-    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
-    LOG.debug("addGlobalRoute: adding  a new route with id[{}] and value [{}]", routeId, route);
-    if(globalRpcMap.putIfAbsent(routeId, route) != null) {
-      LOG.debug("A route already exist for route id [{}] ", routeId);
-    }
-  }
+import java.util.HashMap;
+import java.util.Map;
 
-  public void removeGlobalRoute(final I routeId) {
-    Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
-    LOG.debug("removeGlobalRoute: removing  a new route with id [{}]", routeId);
-    globalRpcMap.remove(routeId);
-  }
+public class RoutingTable implements Copier<RoutingTable>, Serializable {
 
-  public Set<R> getRoutedRpc(final I routeId) {
-    Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!");
-    Set<R> routes = routedRpcMap.get(routeId);
-
-    if (routes == null) {
-      return Collections.emptySet();
-    }
+    private Map<RpcRouter.RouteIdentifier<?, ?, ?>, Long> table = new HashMap<>();
+    private ActorRef router;
 
-    return ImmutableSet.copyOf(routes);
-  }
+    @Override
+    public RoutingTable copy() {
+        RoutingTable copy = new RoutingTable();
+        copy.setTable(Collections.unmodifiableMap(table));
+        copy.setRouter(this.getRouter());
 
-  public R getLastAddedRoutedRpc(final I routeId) {
+        return copy;
+    }
 
-    Set<R> routes = getRoutedRpc(routeId);
+    public Option<Pair<ActorRef, Long>> getRouterFor(RpcRouter.RouteIdentifier<?, ?, ?> routeId){
+        Long updatedTime = table.get(routeId);
 
-    if (routes.isEmpty()) {
-      return null;
+        if (updatedTime == null || router == null)
+            return Option.none();
+        else
+            return Option.option(new Pair<>(router, updatedTime));
     }
 
-    R route = null;
-    Iterator<R> iter = routes.iterator();
-    while (iter.hasNext()) {
-      route = iter.next();
+    public void addRoute(RpcRouter.RouteIdentifier<?,?,?> routeId){
+        table.put(routeId, System.currentTimeMillis());
     }
 
-    return route;
-  }
-
-  public void addRoutedRpc(final I routeId, final R route)   {
-    Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null");
-    Preconditions.checkNotNull(route, "addRoute: route cannot be null");
-    LOG.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route);
-    threadSafeAdd(routeId, route);
-  }
-
-  public void addRoutedRpcs(final Set<I> routeIds, final R route) {
-    Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null");
-    for (I routeId : routeIds){
-      addRoutedRpc(routeId, route);
+    public void removeRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeId){
+        table.remove(routeId);
     }
-  }
 
-  public void removeRoute(final I routeId, final R route) {
-    Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!");
-    Preconditions.checkNotNull(route, "removeRoute: route cannot be null!");
-
-    LinkedHashSet<R> routes = routedRpcMap.get(routeId);
-    if (routes == null) {
-      return;
-    }
-    LOG.debug("removeRoute: removing  a new route with k/v [{}/{}]", routeId, route);
-    threadSafeRemove(routeId, route);
-  }
-
-  public void removeRoutes(final Set<I> routeIds, final R route) {
-    Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null");
-    for (I routeId : routeIds){
-      removeRoute(routeId, route);
+    public Boolean contains(RpcRouter.RouteIdentifier<?, ?, ?> routeId){
+        return table.containsKey(routeId);
     }
-  }
-
-  /**
-   * This method guarantees that no 2 thread over write each other's changes.
-   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
-   */
-  private void threadSafeAdd(final I routeId, final R route) {
 
-    for (int i=0;i<100;i++){
+    ///
+    /// Getter, Setters
+    ///
+    //TODO: Remove public
+    public Map<RpcRouter.RouteIdentifier<?, ?, ?>, Long> getTable() {
+        return table;
+    }
 
-      LinkedHashSet<R> updatedRoutes = new LinkedHashSet<>();
-      updatedRoutes.add(route);
-      LinkedHashSet<R> oldRoutes = routedRpcMap.putIfAbsent(routeId, updatedRoutes);
-      if (oldRoutes == null) {
-        return;
-      }
+    void setTable(Map<RpcRouter.RouteIdentifier<?, ?, ?>, Long> table) {
+        this.table = table;
+    }
 
-      updatedRoutes = new LinkedHashSet<>(oldRoutes);
-      updatedRoutes.add(route);
+    public ActorRef getRouter() {
+        return router;
+    }
 
-      if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) {
-        return;
-      }
+    public void setRouter(ActorRef router) {
+        this.router = router;
     }
-    //the method did not already return means it failed to add route in 100 attempts
-    throw new IllegalStateException("Failed to add route [" + routeId + "]");
-  }
-
-  /**
-   * This method guarantees that no 2 thread over write each other's changes.
-   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
-   */
-  private void threadSafeRemove(final I routeId, final R route) {
-    LinkedHashSet<R> updatedRoutes = null;
-    for (int i=0;i<100;i++){
-      LinkedHashSet<R> oldRoutes = routedRpcMap.get(routeId);
-
-      // if route to be deleted is the only entry in the set then remove routeId from the cache
-      if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){
-        routedRpcMap.remove(routeId);
-        return;
-      }
-
-      // if there are multiple routes for this routeId, remove the route to be deleted only from the set.
-      updatedRoutes = new LinkedHashSet<>(oldRoutes);
-      updatedRoutes.remove(route);
-      if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) {
-        return;
-      }
 
+    @Override
+    public String toString() {
+        return "RoutingTable{" +
+                "table=" + table +
+                ", router=" + router +
+                '}';
     }
-    //the method did not already return means it failed to remove route in 100 attempts
-    throw new IllegalStateException("Failed to remove route [" + routeId + "]");
-  }
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RoutingTableOld.java
new file mode 100644 (file)
index 0000000..5951776
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ * 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.remote.rpc.registry;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableSet;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+public class RoutingTableOld<I, R> {
+
+  private final Logger LOG = LoggerFactory.getLogger(RoutingTableOld.class);
+
+  private ConcurrentMap<I,R> globalRpcMap = new ConcurrentHashMap<>();
+  private ConcurrentMap<I, LinkedHashSet<R>> routedRpcMap = new ConcurrentHashMap<>();
+
+  public ConcurrentMap<I, R> getGlobalRpcMap() {
+    return globalRpcMap;
+  }
+
+  public ConcurrentMap<I, LinkedHashSet<R>> getRoutedRpcMap() {
+    return routedRpcMap;
+  }
+
+  public R getGlobalRoute(final I routeId) {
+    Preconditions.checkNotNull(routeId, "getGlobalRoute: routeId cannot be null!");
+    return globalRpcMap.get(routeId);
+  }
+
+  public void addGlobalRoute(final I routeId, final R route) {
+    Preconditions.checkNotNull(routeId, "addGlobalRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "addGlobalRoute: route cannot be null!");
+    LOG.debug("addGlobalRoute: adding  a new route with id[{}] and value [{}]", routeId, route);
+    if(globalRpcMap.putIfAbsent(routeId, route) != null) {
+      LOG.debug("A route already exist for route id [{}] ", routeId);
+    }
+  }
+
+  public void removeGlobalRoute(final I routeId) {
+    Preconditions.checkNotNull(routeId, "removeGlobalRoute: routeId cannot be null!");
+    LOG.debug("removeGlobalRoute: removing  a new route with id [{}]", routeId);
+    globalRpcMap.remove(routeId);
+  }
+
+  public Set<R> getRoutedRpc(final I routeId) {
+    Preconditions.checkNotNull(routeId, "getRoutes: routeId cannot be null!");
+    Set<R> routes = routedRpcMap.get(routeId);
+
+    if (routes == null) {
+      return Collections.emptySet();
+    }
+
+    return ImmutableSet.copyOf(routes);
+  }
+
+  public R getLastAddedRoutedRpc(final I routeId) {
+
+    Set<R> routes = getRoutedRpc(routeId);
+
+    if (routes.isEmpty()) {
+      return null;
+    }
+
+    R route = null;
+    Iterator<R> iter = routes.iterator();
+    while (iter.hasNext()) {
+      route = iter.next();
+    }
+
+    return route;
+  }
+
+  public void addRoutedRpc(final I routeId, final R route)   {
+    Preconditions.checkNotNull(routeId, "addRoute: routeId cannot be null");
+    Preconditions.checkNotNull(route, "addRoute: route cannot be null");
+    LOG.debug("addRoute: adding a route with k/v [{}/{}]", routeId, route);
+    threadSafeAdd(routeId, route);
+  }
+
+  public void addRoutedRpcs(final Set<I> routeIds, final R route) {
+    Preconditions.checkNotNull(routeIds, "addRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      addRoutedRpc(routeId, route);
+    }
+  }
+
+  public void removeRoute(final I routeId, final R route) {
+    Preconditions.checkNotNull(routeId, "removeRoute: routeId cannot be null!");
+    Preconditions.checkNotNull(route, "removeRoute: route cannot be null!");
+
+    LinkedHashSet<R> routes = routedRpcMap.get(routeId);
+    if (routes == null) {
+      return;
+    }
+    LOG.debug("removeRoute: removing  a new route with k/v [{}/{}]", routeId, route);
+    threadSafeRemove(routeId, route);
+  }
+
+  public void removeRoutes(final Set<I> routeIds, final R route) {
+    Preconditions.checkNotNull(routeIds, "removeRoutes: routeIds must not be null");
+    for (I routeId : routeIds){
+      removeRoute(routeId, route);
+    }
+  }
+
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
+   */
+  private void threadSafeAdd(final I routeId, final R route) {
+
+    for (int i=0;i<100;i++){
+
+      LinkedHashSet<R> updatedRoutes = new LinkedHashSet<>();
+      updatedRoutes.add(route);
+      LinkedHashSet<R> oldRoutes = routedRpcMap.putIfAbsent(routeId, updatedRoutes);
+      if (oldRoutes == null) {
+        return;
+      }
+
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.add(route);
+
+      if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) {
+        return;
+      }
+    }
+    //the method did not already return means it failed to add route in 100 attempts
+    throw new IllegalStateException("Failed to add route [" + routeId + "]");
+  }
+
+  /**
+   * This method guarantees that no 2 thread over write each other's changes.
+   * Just so that we dont end up in infinite loop, it tries for 100 times then throw
+   */
+  private void threadSafeRemove(final I routeId, final R route) {
+    LinkedHashSet<R> updatedRoutes = null;
+    for (int i=0;i<100;i++){
+      LinkedHashSet<R> oldRoutes = routedRpcMap.get(routeId);
+
+      // if route to be deleted is the only entry in the set then remove routeId from the cache
+      if ((oldRoutes.size() == 1) && oldRoutes.contains(route)){
+        routedRpcMap.remove(routeId);
+        return;
+      }
+
+      // if there are multiple routes for this routeId, remove the route to be deleted only from the set.
+      updatedRoutes = new LinkedHashSet<>(oldRoutes);
+      updatedRoutes.remove(route);
+      if (routedRpcMap.replace(routeId, oldRoutes, updatedRoutes)) {
+        return;
+      }
+
+    }
+    //the method did not already return means it failed to remove route in 100 attempts
+    throw new IllegalStateException("Failed to remove route [" + routeId + "]");
+  }
+}
index e36060cc13ece309f04f10adebdb74a62f158146..51609870cc4aad1c8789dfdcd0b68f04563b5cdf 100644 (file)
  */
 package org.opendaylight.controller.remote.rpc.registry;
 
-import akka.actor.ActorSelection;
+import akka.actor.ActorRef;
 import akka.actor.Address;
 import akka.actor.Props;
-import akka.cluster.ClusterEvent;
-import akka.cluster.Member;
-import akka.japi.Creator;
-import org.opendaylight.controller.remote.rpc.AbstractUntypedActor;
-import org.opendaylight.controller.remote.rpc.ActorConstants;
-import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.AddRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply;
-import org.opendaylight.controller.remote.rpc.messages.GetRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRpcReply;
-import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.RemoveRpc;
-import org.opendaylight.controller.remote.rpc.messages.RoutingTableData;
+import akka.actor.UntypedActor;
+import akka.dispatch.Mapper;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.japi.Option;
+import akka.japi.Pair;
+import akka.pattern.Patterns;
+import com.google.common.base.Preconditions;
+import org.opendaylight.controller.remote.rpc.registry.gossip.Bucket;
+import org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import scala.collection.JavaConversions;
+import scala.concurrent.Future;
 
-import java.util.LinkedHashSet;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.Executors;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledFuture;
-import java.util.concurrent.TimeUnit;
+
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoute;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoute;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBuckets;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBucketsReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetLocalBucket;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetLocalBucketReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.UpdateBucket;
 
 /**
- * This Actor maintains the routing table state and sync it with other nodes in the cluster.
- *
- * A scheduler runs after an interval of time, which pick a random member from the cluster
- * and send the current state of routing table to the member.
+ * Registry to look up cluster nodes that have registered for a given rpc.
+ * <p>
+ * It uses {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} to maintain this
+ * cluster wide information.
  *
- * when a message of routing table data is received, it gets merged with the local routing table
- * to keep the latest data.
  */
+public class RpcRegistry extends UntypedActor {
+
+    final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+    /**
+     * Store to keep the registry. Bucket store sync's it across nodes in the cluster
+     */
+    private ActorRef bucketStore;
+
+    /**
+     * Rpc broker that would use the registry to route requests.
+     */
+    private ActorRef localRouter;
 
-public class RpcRegistry extends AbstractUntypedActor {
-
-  private static final Logger LOG = LoggerFactory.getLogger(RpcRegistry.class);
-  private RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable;
-  private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
-  private final ClusterWrapper clusterWrapper;
-  private final ScheduledFuture<?> syncScheduler;
-
-  private RpcRegistry(ClusterWrapper clusterWrapper){
-    this.routingTable = new RoutingTable<>();
-    this.clusterWrapper = clusterWrapper;
-    this.syncScheduler = scheduler.scheduleAtFixedRate(new SendRoutingTable(), 10, 10, TimeUnit.SECONDS);
-  }
-
-  public static Props props(final ClusterWrapper clusterWrapper){
-    return Props.create(new Creator<RpcRegistry>(){
-
-      @Override
-      public RpcRegistry create() throws Exception {
-        return new RpcRegistry(clusterWrapper);
-      }
-    });
-  }
-
-  @Override
-  protected void handleReceive(Object message) throws Exception {
-    LOG.debug("Received message {}", message);
-    if(message instanceof RoutingTableData) {
-      syncRoutingTable((RoutingTableData) message);
-    } else if(message instanceof GetRoutedRpc) {
-      getRoutedRpc((GetRoutedRpc) message);
-    } else if(message instanceof GetRpc) {
-      getRpc((GetRpc) message);
-    } else if(message instanceof AddRpc) {
-      addRpc((AddRpc) message);
-    } else if(message instanceof RemoveRpc) {
-      removeRpc((RemoveRpc) message);
-    } else if(message instanceof AddRoutedRpc) {
-      addRoutedRpc((AddRoutedRpc) message);
-    } else if(message instanceof RemoveRoutedRpc) {
-      removeRoutedRpc((RemoveRoutedRpc) message);
+    public RpcRegistry() {
+        bucketStore = getContext().actorOf(Props.create(BucketStore.class), "store");
     }
-  }
 
-  private void getRoutedRpc(GetRoutedRpc rpcMsg){
-    LOG.debug("Get latest routed Rpc location from routing table {}", rpcMsg);
-    String remoteActorPath = routingTable.getLastAddedRoutedRpc(rpcMsg.getRouteId());
-    GetRoutedRpcReply routedRpcReply = new GetRoutedRpcReply(remoteActorPath);
+    public RpcRegistry(ActorRef bucketStore) {
+        this.bucketStore = bucketStore;
+    }
+
+    @Override
+    public void onReceive(Object message) throws Exception {
 
-    getSender().tell(routedRpcReply, self());
-  }
+        log.debug("Received message: message [{}]", message);
 
-  private void getRpc(GetRpc rpcMsg) {
-    LOG.debug("Get global Rpc location from routing table {}", rpcMsg);
-    String remoteActorPath = routingTable.getGlobalRoute(rpcMsg.getRouteId());
-    GetRpcReply rpcReply = new GetRpcReply(remoteActorPath);
+        //TODO: if sender is remote, reject message
 
-    getSender().tell(rpcReply, self());
-  }
+        if (message instanceof SetLocalRouter)
+            receiveSetLocalRouter((SetLocalRouter) message);
 
-  private void addRpc(AddRpc rpcMsg) {
-    LOG.debug("Add Rpc to routing table {}", rpcMsg);
-    routingTable.addGlobalRoute(rpcMsg.getRouteId(), rpcMsg.getActorPath());
+        if (message instanceof AddOrUpdateRoute)
+            receiveAddRoute((AddOrUpdateRoute) message);
 
-    getSender().tell("Success", self());
-  }
+        else if (message instanceof RemoveRoute)
+            receiveRemoveRoute((RemoveRoute) message);
 
-  private void removeRpc(RemoveRpc rpcMsg) {
-    LOG.debug("Removing Rpc to routing table {}", rpcMsg);
-    routingTable.removeGlobalRoute(rpcMsg.getRouteId());
+        else if (message instanceof Messages.FindRouters)
+            receiveGetRouter((Messages.FindRouters) message);
+
+        else
+            unhandled(message);
+    }
 
-    getSender().tell("Success", self());
-  }
+    /**
+     * Register's rpc broker
+     *
+     * @param message contains {@link akka.actor.ActorRef} for rpc broker
+     */
+    private void receiveSetLocalRouter(SetLocalRouter message) {
+        if (message == null || message.getRouter() == null)
+            return;//ignore
 
-  private void addRoutedRpc(AddRoutedRpc rpcMsg) {
-    routingTable.addRoutedRpcs(rpcMsg.getAnnouncements(), rpcMsg.getActorPath());
-    getSender().tell("Success", self());
-  }
+        localRouter = message.getRouter();
+    }
 
-  private void removeRoutedRpc(RemoveRoutedRpc rpcMsg) {
-    routingTable.removeRoutes(rpcMsg.getAnnouncements(), rpcMsg.getActorPath());
-    getSender().tell("Success", self());
-  }
+    /**
+     * //TODO: update this to accept multiple route registration
+     * @param msg
+     */
+    private void receiveAddRoute(AddOrUpdateRoute msg) {
+        if (msg.getRouteIdentifier() == null)
+            return;//ignore
 
-  private void syncRoutingTable(RoutingTableData routingTableData) {
-    LOG.debug("Syncing routing table {}", routingTableData);
+        Preconditions.checkState(localRouter != null, "Router must be set first");
 
-    Map<RpcRouter.RouteIdentifier<?, ?, ?>, String> newRpcMap = routingTableData.getRpcMap();
-    Set<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = newRpcMap.keySet();
-    for(RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
-      routingTable.addGlobalRoute(routeId, newRpcMap.get(routeId));
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
+        futureReply.map(getMapperToAddRoute(msg.getRouteIdentifier()), getContext().dispatcher());
     }
 
-    Map<RpcRouter.RouteIdentifier<?, ?, ?>, LinkedHashSet<String>> newRoutedRpcMap =
-        routingTableData.getRoutedRpcMap();
-    routeIds = newRoutedRpcMap.keySet();
+    /**
+     * //TODO: update this to accept multiple routes
+     * @param msg
+     */
+    private void receiveRemoveRoute(RemoveRoute msg) {
+        if (msg.getRouteIdentifier() == null)
+            return;//ignore
+
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetLocalBucket(), 1000);
+        futureReply.map(getMapperToRemoveRoute(msg.getRouteIdentifier()), getContext().dispatcher());
 
-    for(RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
-      Set<String> routeAddresses = newRoutedRpcMap.get(routeId);
-      for(String routeAddress : routeAddresses) {
-        routingTable.addRoutedRpc(routeId, routeAddress);
-      }
     }
-  }
-
-  private ActorSelection getRandomRegistryActor() {
-    ClusterEvent.CurrentClusterState clusterState = clusterWrapper.getState();
-    ActorSelection actor = null;
-    Set<Member> members = JavaConversions.asJavaSet(clusterState.members());
-    int memberSize = members.size();
-    // Don't select yourself
-    if(memberSize > 1) {
-      Address currentNodeAddress = clusterWrapper.getAddress();
-      int index = new Random().nextInt(memberSize);
-      int i = 0;
-      // keeping previous member, in case when random index member is same as current actor
-      // and current actor member is last in set
-      Member previousMember = null;
-      for(Member member : members){
-        if(i == index-1) {
-          previousMember = member;
+
+    /**
+     * Finds routers for the given rpc.
+     * @param msg
+     */
+    private void receiveGetRouter(Messages.FindRouters msg) {
+        final ActorRef sender = getSender();
+
+        //if empty message, return empty list
+        if (msg.getRouteIdentifier() == null) {
+            sender.tell(createEmptyReply(), getSelf());
+            return;
         }
-        if(i == index) {
-          if(!currentNodeAddress.equals(member.address())) {
-            actor = this.context().actorSelection(member.address() + ActorConstants.RPC_REGISTRY_PATH);
-            break;
-          } else if(index < memberSize-1){ // pick the next element in the set
-            index++;
-          }
+
+        Future<Object> futureReply = Patterns.ask(bucketStore, new GetAllBuckets(), 1000);
+        futureReply.map(getMapperToGetRouter(msg.getRouteIdentifier(), sender), getContext().dispatcher());
+
+    }
+
+    /**
+     * Helper to create empty reply when no routers are found
+     *
+     * @return
+     */
+    private Messages.FindRoutersReply createEmptyReply() {
+        List<Pair<ActorRef, Long>> routerWithUpdateTime = Collections.emptyList();
+        return new Messages.FindRoutersReply(routerWithUpdateTime);
+    }
+
+    /**
+     * Helper to create a reply when routers are found for the given rpc
+     * @param buckets
+     * @param routeId
+     * @return
+     */
+    private Messages.FindRoutersReply createReplyWithRouters(Map<Address, Bucket> buckets, RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
+
+        List<Pair<ActorRef, Long>> routers = new ArrayList<>();
+
+        Option<Pair<ActorRef, Long>> routerWithUpdateTime = null;
+
+        for (Bucket bucket : buckets.values()) {
+
+            RoutingTable table = (RoutingTable) bucket.getData();
+
+            if (table == null)
+                continue;
+
+            routerWithUpdateTime = table.getRouterFor(routeId);
+
+            if (routerWithUpdateTime.isEmpty())
+                continue;
+
+            routers.add(routerWithUpdateTime.get());
         }
-        i++;
-      }
-      if(actor == null && previousMember != null) {
-        actor = this.context().actorSelection(previousMember.address() + ActorConstants.RPC_REGISTRY_PATH);
-      }
+
+        return new Messages.FindRoutersReply(routers);
     }
-    return actor;
-  }
 
-  private class SendRoutingTable implements Runnable {
 
-    @Override
-    public void run() {
-      RoutingTableData routingTableData =
-          new RoutingTableData(routingTable.getGlobalRpcMap(), routingTable.getRoutedRpcMap());
-      LOG.debug("Sending routing table for sync {}", routingTableData);
-      ActorSelection actor = getRandomRegistryActor();
-      if(actor != null) {
-        actor.tell(routingTableData, self());
-      }
+    ///
+    ///private factories to create Mapper
+    ///
+
+    /**
+     *  Receives all buckets returned from bucket store and finds routers for the buckets where given rpc(routeId) is found
+     *
+     * @param routeId the rpc
+     * @param sender  client who asked to find the routers.
+     * @return
+     */
+    private Mapper<Object, Void> getMapperToGetRouter(final RpcRouter.RouteIdentifier<?, ?, ?> routeId, final ActorRef sender) {
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object replyMessage) {
+
+                if (replyMessage instanceof GetAllBucketsReply) {
+
+                    GetAllBucketsReply reply = (GetAllBucketsReply) replyMessage;
+                    Map<Address, Bucket> buckets = reply.getBuckets();
+
+                    if (buckets == null || buckets.isEmpty()) {
+                        sender.tell(createEmptyReply(), getSelf());
+                        return null;
+                    }
+
+                    sender.tell(createReplyWithRouters(buckets, routeId), getSelf());
+                }
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Receives local bucket from bucket store and updates routing table in it by removing the route. Subsequently,
+     * it updates the local bucket in bucket store.
+     *
+     * @param routeId rpc to remote
+     * @return
+     */
+    private Mapper<Object, Void> getMapperToRemoveRoute(final RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object replyMessage) {
+                if (replyMessage instanceof GetLocalBucketReply) {
+
+                    GetLocalBucketReply reply = (GetLocalBucketReply) replyMessage;
+                    Bucket<RoutingTable> bucket = reply.getBucket();
+
+                    if (bucket == null) {
+                        log.debug("Local bucket is null");
+                        return null;
+                    }
+
+                    RoutingTable table = bucket.getData();
+                    if (table == null)
+                        table = new RoutingTable();
+
+                    table.setRouter(localRouter);
+                    table.removeRoute(routeId);
+
+                    bucket.setData(table);
+
+                    UpdateBucket updateBucketMessage = new UpdateBucket(bucket);
+                    bucketStore.tell(updateBucketMessage, getSelf());
+                }
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Receives local bucket from bucket store and updates routing table in it by adding the route. Subsequently,
+     * it updates the local bucket in bucket store.
+     *
+     * @param routeId rpc to add
+     * @return
+     */
+    private Mapper<Object, Void> getMapperToAddRoute(final RpcRouter.RouteIdentifier<?, ?, ?> routeId) {
+
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object replyMessage) {
+                if (replyMessage instanceof GetLocalBucketReply) {
+
+                    GetLocalBucketReply reply = (GetLocalBucketReply) replyMessage;
+                    Bucket<RoutingTable> bucket = reply.getBucket();
+
+                    if (bucket == null) {
+                        log.debug("Local bucket is null");
+                        return null;
+                    }
+
+                    RoutingTable table = bucket.getData();
+                    if (table == null)
+                        table = new RoutingTable();
+
+                    table.setRouter(localRouter);
+                    table.addRoute(routeId);
+
+                    bucket.setData(table);
+
+                    UpdateBucket updateBucketMessage = new UpdateBucket(bucket);
+                    bucketStore.tell(updateBucketMessage, getSelf());
+                }
+
+                return null;
+            }
+        };
+    }
+
+    /**
+     * All messages used by the RpcRegistry
+     */
+    public static class Messages {
+
+
+        public static class ContainsRoute {
+            final RpcRouter.RouteIdentifier<?,?,?> routeIdentifier;
+
+            public ContainsRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
+                Preconditions.checkArgument(routeIdentifier != null);
+                this.routeIdentifier = routeIdentifier;
+            }
+
+            public RpcRouter.RouteIdentifier<?,?,?> getRouteIdentifier(){
+                return this.routeIdentifier;
+            }
+
+            @Override
+            public String toString() {
+                return this.getClass().getSimpleName() + "{" +
+                        "routeIdentifier=" + routeIdentifier +
+                        '}';
+            }
+        }
+
+        public static class AddOrUpdateRoute extends ContainsRoute{
+
+            public AddOrUpdateRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
+                super(routeIdentifier);
+            }
+        }
+
+        public static class RemoveRoute extends ContainsRoute {
+
+            public RemoveRoute(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
+                super(routeIdentifier);
+            }
+        }
+
+        public static class SetLocalRouter{
+            private final ActorRef router;
+
+            public SetLocalRouter(ActorRef router) {
+                this.router = router;
+            }
+
+            public ActorRef getRouter(){
+                return this.router;
+            }
+
+            @Override
+            public String toString() {
+                return "SetLocalRouter{" +
+                        "router=" + router +
+                        '}';
+            }
+        }
+
+        public static class FindRouters extends ContainsRoute {
+            public FindRouters(RpcRouter.RouteIdentifier<?, ?, ?> routeIdentifier) {
+                super(routeIdentifier);
+            }
+        }
+
+        public static class FindRoutersReply {
+            final List<Pair<ActorRef, Long>> routerWithUpdateTime;
+
+            public FindRoutersReply(List<Pair<ActorRef, Long>> routerWithUpdateTime) {
+                this.routerWithUpdateTime = routerWithUpdateTime;
+            }
+
+            public List<Pair<ActorRef, Long>> getRouterWithUpdateTime(){
+                return routerWithUpdateTime;
+            }
+
+            @Override
+            public String toString() {
+                return "FindRoutersReply{" +
+                        "routerWithUpdateTime=" + routerWithUpdateTime +
+                        '}';
+            }
+        }
     }
-  }
 }
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOld.java
new file mode 100644 (file)
index 0000000..96c8802
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * 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.remote.rpc.registry;
+
+import akka.actor.ActorSelection;
+import akka.actor.Address;
+import akka.actor.Props;
+import akka.cluster.ClusterEvent;
+import akka.cluster.Member;
+import akka.japi.Creator;
+import org.opendaylight.controller.remote.rpc.AbstractUntypedActor;
+import org.opendaylight.controller.remote.rpc.ActorConstants;
+import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.AddRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply;
+import org.opendaylight.controller.remote.rpc.messages.GetRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRpcReply;
+import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.RemoveRpc;
+import org.opendaylight.controller.remote.rpc.messages.RoutingTableData;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import scala.collection.JavaConversions;
+
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledFuture;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * This Actor maintains the routing table state and sync it with other nodes in the cluster.
+ *
+ * A scheduler runs after an interval of time, which pick a random member from the cluster
+ * and send the current state of routing table to the member.
+ *
+ * when a message of routing table data is received, it gets merged with the local routing table
+ * to keep the latest data.
+ */
+
+public class RpcRegistryOld extends AbstractUntypedActor {
+
+  private static final Logger LOG = LoggerFactory.getLogger(RpcRegistryOld.class);
+  private RoutingTableOld<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable;
+  private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
+  private final ClusterWrapper clusterWrapper;
+  private final ScheduledFuture<?> syncScheduler;
+
+  private RpcRegistryOld(ClusterWrapper clusterWrapper){
+    this.routingTable = new RoutingTableOld<>();
+    this.clusterWrapper = clusterWrapper;
+    this.syncScheduler = scheduler.scheduleAtFixedRate(new SendRoutingTable(), 10, 10, TimeUnit.SECONDS);
+  }
+
+  public static Props props(final ClusterWrapper clusterWrapper){
+    return Props.create(new Creator<RpcRegistryOld>(){
+
+      @Override
+      public RpcRegistryOld create() throws Exception {
+        return new RpcRegistryOld(clusterWrapper);
+      }
+    });
+  }
+
+  @Override
+  protected void handleReceive(Object message) throws Exception {
+    LOG.debug("Received message {}", message);
+    if(message instanceof RoutingTableData) {
+      syncRoutingTable((RoutingTableData) message);
+    } else if(message instanceof GetRoutedRpc) {
+      getRoutedRpc((GetRoutedRpc) message);
+    } else if(message instanceof GetRpc) {
+      getRpc((GetRpc) message);
+    } else if(message instanceof AddRpc) {
+      addRpc((AddRpc) message);
+    } else if(message instanceof RemoveRpc) {
+      removeRpc((RemoveRpc) message);
+    } else if(message instanceof AddRoutedRpc) {
+      addRoutedRpc((AddRoutedRpc) message);
+    } else if(message instanceof RemoveRoutedRpc) {
+      removeRoutedRpc((RemoveRoutedRpc) message);
+    }
+  }
+
+  private void getRoutedRpc(GetRoutedRpc rpcMsg){
+    LOG.debug("Get latest routed Rpc location from routing table {}", rpcMsg);
+    String remoteActorPath = routingTable.getLastAddedRoutedRpc(rpcMsg.getRouteId());
+    GetRoutedRpcReply routedRpcReply = new GetRoutedRpcReply(remoteActorPath);
+
+    getSender().tell(routedRpcReply, self());
+  }
+
+  private void getRpc(GetRpc rpcMsg) {
+    LOG.debug("Get global Rpc location from routing table {}", rpcMsg);
+    String remoteActorPath = routingTable.getGlobalRoute(rpcMsg.getRouteId());
+    GetRpcReply rpcReply = new GetRpcReply(remoteActorPath);
+
+    getSender().tell(rpcReply, self());
+  }
+
+  private void addRpc(AddRpc rpcMsg) {
+    LOG.debug("Add Rpc to routing table {}", rpcMsg);
+    routingTable.addGlobalRoute(rpcMsg.getRouteId(), rpcMsg.getActorPath());
+
+    getSender().tell("Success", self());
+  }
+
+  private void removeRpc(RemoveRpc rpcMsg) {
+    LOG.debug("Removing Rpc to routing table {}", rpcMsg);
+    routingTable.removeGlobalRoute(rpcMsg.getRouteId());
+
+    getSender().tell("Success", self());
+  }
+
+  private void addRoutedRpc(AddRoutedRpc rpcMsg) {
+    routingTable.addRoutedRpcs(rpcMsg.getAnnouncements(), rpcMsg.getActorPath());
+    getSender().tell("Success", self());
+  }
+
+  private void removeRoutedRpc(RemoveRoutedRpc rpcMsg) {
+    routingTable.removeRoutes(rpcMsg.getAnnouncements(), rpcMsg.getActorPath());
+    getSender().tell("Success", self());
+  }
+
+  private void syncRoutingTable(RoutingTableData routingTableData) {
+    LOG.debug("Syncing routing table {}", routingTableData);
+
+    Map<RpcRouter.RouteIdentifier<?, ?, ?>, String> newRpcMap = routingTableData.getRpcMap();
+    Set<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = newRpcMap.keySet();
+    for(RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
+      routingTable.addGlobalRoute(routeId, newRpcMap.get(routeId));
+    }
+
+    Map<RpcRouter.RouteIdentifier<?, ?, ?>, LinkedHashSet<String>> newRoutedRpcMap =
+        routingTableData.getRoutedRpcMap();
+    routeIds = newRoutedRpcMap.keySet();
+
+    for(RpcRouter.RouteIdentifier<?, ?, ?> routeId : routeIds) {
+      Set<String> routeAddresses = newRoutedRpcMap.get(routeId);
+      for(String routeAddress : routeAddresses) {
+        routingTable.addRoutedRpc(routeId, routeAddress);
+      }
+    }
+  }
+
+  private ActorSelection getRandomRegistryActor() {
+    ClusterEvent.CurrentClusterState clusterState = clusterWrapper.getState();
+    ActorSelection actor = null;
+    Set<Member> members = JavaConversions.asJavaSet(clusterState.members());
+    int memberSize = members.size();
+    // Don't select yourself
+    if(memberSize > 1) {
+      Address currentNodeAddress = clusterWrapper.getAddress();
+      int index = new Random().nextInt(memberSize);
+      int i = 0;
+      // keeping previous member, in case when random index member is same as current actor
+      // and current actor member is last in set
+      Member previousMember = null;
+      for(Member member : members){
+        if(i == index-1) {
+          previousMember = member;
+        }
+        if(i == index) {
+          if(!currentNodeAddress.equals(member.address())) {
+            actor = this.context().actorSelection(member.address() + ActorConstants.RPC_REGISTRY_PATH);
+            break;
+          } else if(index < memberSize-1){ // pick the next element in the set
+            index++;
+          }
+        }
+        i++;
+      }
+      if(actor == null && previousMember != null) {
+        actor = this.context().actorSelection(previousMember.address() + ActorConstants.RPC_REGISTRY_PATH);
+      }
+    }
+    return actor;
+  }
+
+  private class SendRoutingTable implements Runnable {
+
+    @Override
+    public void run() {
+      RoutingTableData routingTableData =
+          new RoutingTableData(routingTable.getGlobalRpcMap(), routingTable.getRoutedRpcMap());
+      LOG.debug("Sending routing table for sync {}", routingTableData);
+      ActorSelection actor = getRandomRegistryActor();
+      if(actor != null) {
+        actor.tell(routingTableData, self());
+      }
+    }
+  }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Bucket.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Bucket.java
new file mode 100644 (file)
index 0000000..f5dfbc5
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+
+public interface Bucket<T extends Copier<T>> {
+    public Long getVersion();
+    public T getData();
+    public void setData(T data);
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketImpl.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketImpl.java
new file mode 100644 (file)
index 0000000..3cdd924
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import java.io.Serializable;
+
+public class BucketImpl<T extends Copier<T>> implements Bucket<T>, Serializable {
+
+    private Long version = System.currentTimeMillis();;
+
+    private T data;
+
+    @Override
+    public Long getVersion() {
+        return version;
+    }
+
+    @Override
+    public T getData() {
+        if (this.data == null)
+            return null;
+
+        return data.copy();
+    }
+
+    public void setData(T data){
+        this.version = System.currentTimeMillis()+1;
+        this.data = data;
+    }
+
+    @Override
+    public String toString() {
+        return "BucketImpl{" +
+                "version=" + version +
+                ", data=" + data +
+                '}';
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java
new file mode 100644 (file)
index 0000000..2f634ce
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import akka.actor.ActorRef;
+import akka.actor.Address;
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.cluster.Cluster;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBuckets;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetAllBucketsReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketVersions;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketVersionsReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketsByMembers;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketsByMembersReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetLocalBucket;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetLocalBucketReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.UpdateBucket;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.UpdateRemoteBuckets;
+
+/**
+ * A store that syncs its data across nodes in the cluster.
+ * It maintains a {@link org.opendaylight.controller.remote.rpc.registry.gossip.Bucket} per node. Buckets are versioned.
+ * A node can write ONLY to its bucket. This way, write conflicts are avoided.
+ * <p>
+ * Buckets are sync'ed across nodes using Gossip protocol (http://en.wikipedia.org/wiki/Gossip_protocol)<p>
+ * This store uses a {@link org.opendaylight.controller.remote.rpc.registry.gossip.Gossiper}.
+ *
+ */
+public class BucketStore extends UntypedActor {
+
+    final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+    /**
+     * Bucket owned by the node
+     */
+    private BucketImpl localBucket = new BucketImpl();;
+
+    /**
+     * Buckets ownded by other known nodes in the cluster
+     */
+    private ConcurrentMap<Address, Bucket> remoteBuckets = new ConcurrentHashMap<>();
+
+    /**
+     * Bucket version for every known node in the cluster including this node
+     */
+    private ConcurrentMap<Address, Long> versions = new ConcurrentHashMap<>();
+
+    /**
+     * Cluster address for this node
+     */
+    private final Address selfAddress = Cluster.get(getContext().system()).selfAddress();
+
+    /**
+     * Our private gossiper
+     */
+    private ActorRef gossiper;
+
+    public BucketStore(){
+        gossiper = getContext().actorOf(Props.create(Gossiper.class), "gossiper");
+    }
+
+    /**
+     * This constructor is useful for testing.
+     * TODO: Pass Props instead of ActorRef
+     *
+     * @param gossiper
+     */
+    public BucketStore(ActorRef gossiper){
+        this.gossiper = gossiper;
+    }
+
+    @Override
+    public void onReceive(Object message) throws Exception {
+
+        log.debug("Received message: node[{}], message[{}]", selfAddress, message);
+
+        if (message instanceof UpdateBucket)
+            receiveUpdateBucket(((UpdateBucket) message).getBucket());
+
+        else if (message instanceof GetAllBuckets)
+            receiveGetAllBucket();
+
+        else if (message instanceof GetLocalBucket)
+            receiveGetLocalBucket();
+
+        else if (message instanceof GetBucketsByMembers)
+            receiveGetBucketsByMembers(((GetBucketsByMembers) message).getMembers());
+
+        else if (message instanceof GetBucketVersions)
+            receiveGetBucketVersions();
+
+        else if (message instanceof UpdateRemoteBuckets)
+            receiveUpdateRemoteBuckets(((UpdateRemoteBuckets) message).getBuckets());
+
+        else {
+            log.debug("Unhandled message [{}]", message);
+            unhandled(message);
+        }
+
+    }
+
+    /**
+     * Returns a copy of bucket owned by this node
+     */
+    private void receiveGetLocalBucket() {
+        final ActorRef sender = getSender();
+        GetLocalBucketReply reply = new GetLocalBucketReply(localBucket);
+        sender.tell(reply, getSelf());
+    }
+
+    /**
+     * Updates the bucket owned by this node
+     *
+     * @param updatedBucket
+     */
+    void receiveUpdateBucket(Bucket updatedBucket){
+
+        localBucket = (BucketImpl) updatedBucket;
+        versions.put(selfAddress, localBucket.getVersion());
+    }
+
+    /**
+     * Returns all the buckets the this node knows about, self owned + remote
+     */
+    void receiveGetAllBucket(){
+        final ActorRef sender = getSender();
+        sender.tell(new GetAllBucketsReply(getAllBuckets()), getSelf());
+    }
+
+    /**
+     * Helper to collect all known buckets
+     *
+     * @return self owned + remote buckets
+     */
+    Map<Address, Bucket> getAllBuckets(){
+        Map<Address, Bucket> all = new HashMap<>(remoteBuckets.size() + 1);
+
+        //first add the local bucket
+        all.put(selfAddress, localBucket);
+
+        //then get all remote buckets
+        all.putAll(remoteBuckets);
+
+        return all;
+    }
+
+    /**
+     * Returns buckets for requested members that this node knows about
+     *
+     * @param members requested members
+     */
+    void receiveGetBucketsByMembers(Set<Address> members){
+        final ActorRef sender = getSender();
+        Map<Address, Bucket> buckets = getBucketsByMembers(members);
+        sender.tell(new GetBucketsByMembersReply(buckets), getSelf());
+    }
+
+    /**
+     * Helper to collect buckets for requested memebers
+     *
+     * @param members requested members
+     * @return buckets for requested memebers
+     */
+    Map<Address, Bucket> getBucketsByMembers(Set<Address> members) {
+        Map<Address, Bucket> buckets = new HashMap<>();
+
+        //first add the local bucket if asked
+        if (members.contains(selfAddress))
+            buckets.put(selfAddress, localBucket);
+
+        //then get buckets for requested remote nodes
+        for (Address address : members){
+            if (remoteBuckets.containsKey(address))
+                buckets.put(address, remoteBuckets.get(address));
+        }
+
+        return buckets;
+    }
+
+    /**
+     * Returns versions for all buckets known
+     */
+    void receiveGetBucketVersions(){
+        final ActorRef sender = getSender();
+        GetBucketVersionsReply reply = new GetBucketVersionsReply(versions);
+        sender.tell(reply, getSelf());
+    }
+
+    /**
+     * Update local copy of remote buckets where local copy's version is older
+     *
+     * @param receivedBuckets buckets sent by remote
+     *                        {@link org.opendaylight.controller.remote.rpc.registry.gossip.Gossiper}
+     */
+    void receiveUpdateRemoteBuckets(Map<Address, Bucket> receivedBuckets){
+
+        if (receivedBuckets == null || receivedBuckets.isEmpty())
+            return; //nothing to do
+
+        //Remote cant update self's bucket
+        receivedBuckets.remove(selfAddress);
+
+        for (Map.Entry<Address, Bucket> entry : receivedBuckets.entrySet()){
+
+            Long localVersion = versions.get(entry.getKey());
+            if (localVersion == null) localVersion = -1L;
+
+            Bucket receivedBucket = entry.getValue();
+
+            if (receivedBucket == null)
+                continue;
+
+            Long remoteVersion = receivedBucket.getVersion();
+            if (remoteVersion == null) remoteVersion = -1L;
+
+            //update only if remote version is newer
+            if ( remoteVersion > localVersion ) {
+                remoteBuckets.put(entry.getKey(), receivedBucket);
+                versions.put(entry.getKey(), remoteVersion);
+            }
+        }
+
+        log.debug("State after update - Local Bucket [{}], Remote Buckets [{}]", localBucket, remoteBuckets);
+    }
+
+    ///
+    ///Getter Setters
+    ///
+
+    BucketImpl getLocalBucket() {
+        return localBucket;
+    }
+
+    void setLocalBucket(BucketImpl localBucket) {
+        this.localBucket = localBucket;
+    }
+
+    ConcurrentMap<Address, Bucket> getRemoteBuckets() {
+        return remoteBuckets;
+    }
+
+    void setRemoteBuckets(ConcurrentMap<Address, Bucket> remoteBuckets) {
+        this.remoteBuckets = remoteBuckets;
+    }
+
+    ConcurrentMap<Address, Long> getVersions() {
+        return versions;
+    }
+
+    void setVersions(ConcurrentMap<Address, Long> versions) {
+        this.versions = versions;
+    }
+
+    Address getSelfAddress() {
+        return selfAddress;
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Copier.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Copier.java
new file mode 100644 (file)
index 0000000..45279eb
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+/**
+ * Type of data that goes in {@link org.opendaylight.controller.remote.rpc.registry.gossip.Bucket}.
+ * The implementers should do deep cloning in copy() method.
+ */
+public interface Copier<T> {
+    public T copy();
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java
new file mode 100644 (file)
index 0000000..0b64136
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSelection;
+import akka.actor.Address;
+import akka.actor.Cancellable;
+import akka.actor.UntypedActor;
+import akka.cluster.Cluster;
+import akka.cluster.ClusterEvent;
+import akka.cluster.Member;
+import akka.dispatch.Mapper;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.pattern.Patterns;
+import scala.concurrent.Future;
+import scala.concurrent.duration.FiniteDuration;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+import java.util.concurrent.TimeUnit;
+
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketVersions;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketVersionsReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketsByMembers;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.GetBucketsByMembersReply;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.BucketStoreMessages.UpdateRemoteBuckets;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipTick;
+
+/**
+ * Gossiper that syncs bucket store across nodes in the cluster.
+ * <p>
+ * It keeps a local scheduler that periodically sends Gossip ticks to itself to send bucket store's bucket versions
+ * to a randomly selected remote gossiper.
+ * <p>
+ * When bucket versions are received from a remote gossiper, it is compared with bucket store's bucket versions.
+ * Which ever buckets are newer locally, are sent to remote gossiper. If any bucket is older in bucket store, a
+ * gossip status is sent to remote gossiper so that it can send the newer buckets.
+ * <p>
+ * When a bucket is received from a remote gossiper, its sent to the bucket store for update.
+ *
+ */
+
+public class Gossiper extends UntypedActor {
+
+    final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+    Cluster cluster = Cluster.get(getContext().system());
+
+    /**
+     * ActorSystem's address for the current cluster node.
+     */
+    private Address selfAddress = cluster.selfAddress();
+
+    /**
+     * All known cluster members
+     */
+    private List<Address> clusterMembers = new ArrayList<>();
+
+    private Cancellable gossipTask;
+
+    private Boolean autoStartGossipTicks = true;
+
+    public Gossiper(){}
+
+    /**
+     * Helpful for testing
+     * @param autoStartGossipTicks used for turning off gossip ticks during testing. Gossip tick can be manually sent.
+     */
+    public Gossiper(Boolean autoStartGossipTicks){
+        this.autoStartGossipTicks = autoStartGossipTicks;
+    }
+
+    @Override
+    public void preStart(){
+
+        cluster.subscribe(getSelf(),
+                          ClusterEvent.initialStateAsEvents(),
+                          ClusterEvent.MemberEvent.class,
+                          ClusterEvent.UnreachableMember.class);
+
+        if (autoStartGossipTicks) {
+            gossipTask = getContext().system().scheduler().schedule(
+                    new FiniteDuration(1, TimeUnit.SECONDS),        //initial delay
+                    new FiniteDuration(500, TimeUnit.MILLISECONDS),         //interval
+                    getSelf(),                                       //target
+                    new Messages.GossiperMessages.GossipTick(),      //message
+                    getContext().dispatcher(),                       //execution context
+                    getSelf()                                        //sender
+            );
+        }
+    }
+
+    @Override
+    public void postStop(){
+        if (cluster != null)
+            cluster.unsubscribe(getSelf());
+        if (gossipTask != null)
+            gossipTask.cancel();
+    }
+
+    @Override
+    public void onReceive(Object message) throws Exception {
+
+        log.debug("Received message: node[{}], message[{}]", selfAddress, message);
+
+        //Usually sent by self via gossip task defined above. But its not enforced.
+        //These ticks can be sent by another actor as well which is esp. useful while testing
+        if (message instanceof GossipTick)
+            receiveGossipTick();
+
+        //Message from remote gossiper with its bucket versions
+        else if (message instanceof GossipStatus)
+            receiveGossipStatus((GossipStatus) message);
+
+        //Message from remote gossiper with buckets. This is usually in response to GossipStatus message
+        //The contained buckets are newer as determined by the remote gossiper by comparing the GossipStatus
+        //message with its local versions
+        else if (message instanceof GossipEnvelope)
+            receiveGossip((GossipEnvelope) message);
+
+        else if (message instanceof ClusterEvent.MemberUp) {
+            receiveMemberUp(((ClusterEvent.MemberUp) message).member());
+
+        } else if (message instanceof ClusterEvent.MemberRemoved) {
+            receiveMemberRemoveOrUnreachable(((ClusterEvent.MemberRemoved) message).member());
+
+        } else if ( message instanceof ClusterEvent.UnreachableMember){
+            receiveMemberRemoveOrUnreachable(((ClusterEvent.UnreachableMember) message).member());
+
+        } else
+            unhandled(message);
+    }
+
+    /**
+     * Remove member from local copy of member list. If member down is self, then stop the actor
+     *
+     * @param member who went down
+     */
+    void receiveMemberRemoveOrUnreachable(Member member) {
+        //if its self, then stop itself
+        if (selfAddress.equals(member.address())){
+            getContext().stop(getSelf());
+            return;
+        }
+
+        clusterMembers.remove(member.address());
+        log.debug("Removed member [{}], Active member list [{}]", member.address(), clusterMembers);
+    }
+
+    /**
+     * Add member to the local copy of member list if it doesnt already
+     * @param member
+     */
+    void receiveMemberUp(Member member) {
+
+        if (selfAddress.equals(member.address()))
+            return; //ignore up notification for self
+
+        if (!clusterMembers.contains(member.address()))
+            clusterMembers.add(member.address());
+
+        log.debug("Added member [{}], Active member list [{}]", member.address(), clusterMembers);
+    }
+
+    /**
+     * Sends Gossip status to other members in the cluster. <br/>
+     * 1. If there are no member, ignore the tick. </br>
+     * 2. If there's only 1 member, send gossip status (bucket versions) to it. <br/>
+     * 3. If there are more than one member, randomly pick one and send gossip status (bucket versions) to it.
+     */
+    void receiveGossipTick(){
+        if (clusterMembers.size() == 0) return; //no members to send gossip status to
+
+        Address remoteMemberToGossipTo = null;
+
+        if (clusterMembers.size() == 1)
+            remoteMemberToGossipTo = clusterMembers.get(0);
+        else {
+            Integer randomIndex = ThreadLocalRandom.current().nextInt(0, clusterMembers.size());
+            remoteMemberToGossipTo = clusterMembers.get(randomIndex);
+        }
+
+        log.debug("Gossiping to [{}]", remoteMemberToGossipTo);
+        getLocalStatusAndSendTo(remoteMemberToGossipTo);
+    }
+
+    /**
+     * Process gossip status received from a remote gossiper. Remote versions are compared with
+     * the local copy. <p>
+     *
+     * For each bucket
+     * <ul>
+     *  <li>If local copy is newer, the newer buckets are sent in GossipEnvelope to remote</li>
+     *  <li>If local is older, GossipStatus is sent to remote so that it can reply with GossipEnvelope</li>
+     *  <li>If both are same, noop</li>
+     * </ul>
+     *
+     * @param status bucket versions from a remote member
+     */
+    void receiveGossipStatus(GossipStatus status){
+        //Dont want to accept messages from non-members
+        if (!clusterMembers.contains(status.from()))
+            return;
+
+        final ActorRef sender = getSender();
+
+        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
+
+        futureReply.map(getMapperToProcessRemoteStatus(sender, status), getContext().dispatcher());
+
+    }
+
+    /**
+     * Sends the received buckets in the envelope to the parent Bucket store.
+     *
+     * @param envelope contains buckets from a remote gossiper
+     */
+    void receiveGossip(GossipEnvelope envelope){
+        //TODO: Add more validations
+        if (!selfAddress.equals(envelope.to())) {
+            log.info("Ignoring message intended for someone else. From [{}] to [{}]", envelope.from(), envelope.to());
+            return;
+        }
+        if (envelope.getBuckets() == null)
+            return; //nothing to do
+
+        updateRemoteBuckets(envelope.getBuckets());
+
+    }
+
+    /**
+     * Helper to send received buckets to bucket store
+     *
+     * @param buckets
+     */
+    void updateRemoteBuckets(Map<Address, Bucket> buckets) {
+
+        if (buckets == null || buckets.isEmpty())
+            return; //nothing to merge
+
+        UpdateRemoteBuckets updateRemoteBuckets = new UpdateRemoteBuckets(buckets);
+
+        getContext().parent().tell(updateRemoteBuckets, getSelf());
+    }
+
+    /**
+     * Gets the buckets from bucket store for the given node addresses and sends them to remote gossiper
+     *
+     * @param remote     remote node to send Buckets to
+     * @param addresses  node addresses whose buckets needs to be sent
+     */
+    void sendGossipTo(final ActorRef remote, final Set<Address> addresses){
+
+        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketsByMembers(addresses), 1000);
+
+        futureReply.map(getMapperToSendGossip(remote), getContext().dispatcher());
+
+    }
+
+    /**
+     * Gets bucket versions from bucket store and sends to the supplied address
+     *
+     * @param remoteActorSystemAddress remote gossiper to send to
+     */
+    void getLocalStatusAndSendTo(Address remoteActorSystemAddress){
+
+        //Get local status from bucket store and send to remote
+        Future<Object> futureReply = Patterns.ask(getContext().parent(), new GetBucketVersions(), 1000);
+
+        ActorSelection remoteRef = getContext().system().actorSelection(
+                remoteActorSystemAddress.toString() + getSelf().path().toStringWithoutAddress());
+
+        log.debug("Sending bucket versions to [{}]", remoteRef);
+
+        futureReply.map(getMapperToSendLocalStatus(remoteRef), getContext().dispatcher());
+
+    }
+
+    /**
+     * Helper to send bucket versions received from local store
+     * @param remote        remote gossiper to send versions to
+     * @param localVersions bucket versions received from local store
+     */
+    void sendGossipStatusTo(ActorRef remote, Map<Address, Long> localVersions){
+
+        GossipStatus status = new GossipStatus(selfAddress, localVersions);
+        remote.tell(status, getSelf());
+    }
+
+    void sendGossipStatusTo(ActorSelection remote, Map<Address, Long> localVersions){
+
+        GossipStatus status = new GossipStatus(selfAddress, localVersions);
+        remote.tell(status, getSelf());
+    }
+
+    ///
+    /// Private factories to create mappers
+    ///
+
+    private Mapper<Object, Void> getMapperToSendLocalStatus(final ActorSelection remote){
+
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object replyMessage) {
+                if (replyMessage instanceof GetBucketVersionsReply) {
+                    GetBucketVersionsReply reply = (GetBucketVersionsReply) replyMessage;
+                    Map<Address, Long> localVersions = reply.getVersions();
+
+                    sendGossipStatusTo(remote, localVersions);
+
+                }
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Process bucket versions received from {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore}.
+     * Then this method compares remote bucket versions with local bucket versions.
+     * <ul>
+     *     <li>The buckets that are newer locally, send
+     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope} to remote
+     *     <li>The buckets that are older locally, send
+     *     {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus} to remote so that
+     *     remote sends GossipEnvelop.
+     * </ul>
+     *
+     * @param sender the remote member
+     * @param status bucket versions from a remote member
+     * @return a {@link akka.dispatch.Mapper} that gets evaluated in future
+     *
+     */
+    private Mapper<Object, Void> getMapperToProcessRemoteStatus(final ActorRef sender, final GossipStatus status){
+
+        final Map<Address, Long> remoteVersions = status.getVersions();
+
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object replyMessage) {
+                if (replyMessage instanceof GetBucketVersionsReply) {
+                    GetBucketVersionsReply reply = (GetBucketVersionsReply) replyMessage;
+                    Map<Address, Long> localVersions = reply.getVersions();
+
+                    //diff between remote list and local
+                    Set<Address> localIsOlder = new HashSet<>();
+                    localIsOlder.addAll(remoteVersions.keySet());
+                    localIsOlder.removeAll(localVersions.keySet());
+
+                    //diff between local list and remote
+                    Set<Address> localIsNewer = new HashSet<>();
+                    localIsNewer.addAll(localVersions.keySet());
+                    localIsNewer.removeAll(remoteVersions.keySet());
+
+
+                    for (Address address : remoteVersions.keySet()){
+
+                        if (localVersions.get(address) == null || remoteVersions.get(address) == null)
+                            continue; //this condition is taken care of by above diffs
+                        if (localVersions.get(address) <  remoteVersions.get(address))
+                            localIsOlder.add(address);
+                        else if (localVersions.get(address) > remoteVersions.get(address))
+                            localIsNewer.add(address);
+                        else
+                            continue;
+                    }
+
+                    if (!localIsOlder.isEmpty())
+                        sendGossipStatusTo(sender, localVersions );
+
+                    if (!localIsNewer.isEmpty())
+                        sendGossipTo(sender, localIsNewer);//send newer buckets to remote
+
+                }
+                return null;
+            }
+        };
+    }
+
+    /**
+     * Processes the message from {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} that contains
+     * {@link org.opendaylight.controller.remote.rpc.registry.gossip.Bucket}. These buckets are sent to a remote member encapsulated
+     * in {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope}
+     *
+     * @param sender the remote member that sent
+     *               {@link org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus}
+     *               in reply to which bucket is being sent back
+     * @return a {@link akka.dispatch.Mapper} that gets evaluated in future
+     *
+     */
+    private Mapper<Object, Void> getMapperToSendGossip(final ActorRef sender) {
+
+        return new Mapper<Object, Void>() {
+            @Override
+            public Void apply(Object msg) {
+                if (msg instanceof GetBucketsByMembersReply) {
+                    Map<Address, Bucket> buckets = ((GetBucketsByMembersReply) msg).getBuckets();
+                    log.info("Buckets to send from {}: {}", selfAddress, buckets);
+                    GossipEnvelope envelope = new GossipEnvelope(selfAddress, sender.path().address(), buckets);
+                    sender.tell(envelope, getSelf());
+                }
+                return null;
+            }
+        };
+    }
+
+    ///
+    ///Getter Setters
+    ///
+    List<Address> getClusterMembers() {
+        return clusterMembers;
+    }
+
+    void setClusterMembers(List<Address> clusterMembers) {
+        this.clusterMembers = clusterMembers;
+    }
+
+    Address getSelfAddress() {
+        return selfAddress;
+    }
+
+    void setSelfAddress(Address selfAddress) {
+        this.selfAddress = selfAddress;
+    }
+}
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Messages.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Messages.java
new file mode 100644 (file)
index 0000000..9a247d9
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import akka.actor.Address;
+import com.google.common.base.Preconditions;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * These messages are used by {@link org.opendaylight.controller.remote.rpc.registry.gossip.BucketStore} and
+ * {@link org.opendaylight.controller.remote.rpc.registry.gossip.Gossiper} actors.
+ */
+public class Messages {
+
+    public static class BucketStoreMessages{
+
+        public static class GetLocalBucket implements Serializable{}
+
+        public static class ContainsBucket implements Serializable {
+            final private Bucket bucket;
+
+            public ContainsBucket(Bucket bucket){
+                Preconditions.checkArgument(bucket != null, "bucket can not be null");
+                this.bucket = bucket;
+            }
+
+            public Bucket getBucket(){
+                return bucket;
+            }
+
+        }
+
+        public static class UpdateBucket extends ContainsBucket implements Serializable {
+            public UpdateBucket(Bucket bucket){
+                super(bucket);
+            }
+        }
+
+        public static class GetLocalBucketReply extends ContainsBucket implements Serializable {
+            public GetLocalBucketReply(Bucket bucket){
+                super(bucket);
+            }
+        }
+
+        public static class GetAllBuckets implements Serializable{}
+
+        public static class GetBucketsByMembers implements Serializable{
+            private Set<Address> members;
+
+            public GetBucketsByMembers(Set<Address> members){
+                Preconditions.checkArgument(members != null, "members can not be null");
+                this.members = members;
+            }
+
+            public Set<Address> getMembers() {
+                return new HashSet<>(members);
+            }
+        }
+
+        public static class ContainsBuckets implements Serializable{
+            private Map<Address, Bucket> buckets;
+
+            public ContainsBuckets(Map<Address, Bucket> buckets){
+                Preconditions.checkArgument(buckets != null, "buckets can not be null");
+                this.buckets = buckets;
+            }
+
+            public Map<Address, Bucket> getBuckets() {
+                Map<Address, Bucket> copy = new HashMap<>(buckets.size());
+
+                for (Map.Entry<Address, Bucket> entry : buckets.entrySet()){
+                    //ignore null entries
+                    if ( (entry.getKey() == null) || (entry.getValue() == null) )
+                        continue;
+                    copy.put(entry.getKey(), entry.getValue());
+                }
+                return new HashMap<>(copy);
+            }
+        }
+
+        public static class GetAllBucketsReply extends ContainsBuckets implements Serializable{
+            public GetAllBucketsReply(Map<Address, Bucket> buckets) {
+                super(buckets);
+            }
+        }
+
+        public static class GetBucketsByMembersReply extends ContainsBuckets implements Serializable{
+            public GetBucketsByMembersReply(Map<Address, Bucket> buckets) {
+                super(buckets);
+            }
+        }
+
+        public static class GetBucketVersions implements Serializable{}
+
+        public static class ContainsBucketVersions implements Serializable{
+            Map<Address, Long> versions;
+
+            public ContainsBucketVersions(Map<Address, Long> versions) {
+                Preconditions.checkArgument(versions != null, "versions can not be null");
+                this.versions = versions;
+            }
+
+            public Map<Address, Long> getVersions() {
+                return Collections.unmodifiableMap(versions);
+            }
+
+        }
+
+        public static class GetBucketVersionsReply extends ContainsBucketVersions implements Serializable{
+            public GetBucketVersionsReply(Map<Address, Long> versions) {
+                super(versions);
+            }
+        }
+
+        public static class UpdateRemoteBuckets extends ContainsBuckets implements Serializable{
+            public UpdateRemoteBuckets(Map<Address, Bucket> buckets) {
+                super(buckets);
+            }
+        }
+    }
+
+    public static class GossiperMessages{
+        public static class Tick implements Serializable {}
+
+        public static final class GossipTick extends Tick {}
+
+        public static final class GossipStatus extends BucketStoreMessages.ContainsBucketVersions implements Serializable{
+            private Address from;
+
+            public GossipStatus(Address from, Map<Address, Long> versions) {
+                super(versions);
+                this.from = from;
+            }
+
+            public Address from() {
+                return from;
+            }
+        }
+
+        public static final class GossipEnvelope extends BucketStoreMessages.ContainsBuckets implements Serializable {
+            private final Address from;
+            private final Address to;
+
+            public GossipEnvelope(Address from, Address to, Map<Address, Bucket> buckets) {
+                super(buckets);
+                this.to = to;
+                this.from = from;
+            }
+
+            public Address from() {
+                return from;
+            }
+
+            public Address to() {
+                return to;
+            }
+        }
+    }
+}
index 392c1e637d848e1ccc47d43b3a951011a2e25a72..55aa1d6c871d252d0a89ce1772fd078e45cac101 100644 (file)
@@ -25,7 +25,7 @@ import org.opendaylight.controller.remote.rpc.messages.InvokeRoutedRpc;
 import org.opendaylight.controller.remote.rpc.messages.InvokeRpc;
 import org.opendaylight.controller.remote.rpc.messages.RpcResponse;
 import org.opendaylight.controller.remote.rpc.registry.ClusterWrapper;
-import org.opendaylight.controller.remote.rpc.registry.RpcRegistry;
+import org.opendaylight.controller.remote.rpc.registry.RpcRegistryOld;
 import org.opendaylight.controller.sal.common.util.Rpcs;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.controller.sal.core.api.Broker;
@@ -69,7 +69,7 @@ public class RpcBrokerTest {
   @Test
   public void testInvokeRpcError() throws URISyntaxException {
     new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(Mockito.mock(ClusterWrapper.class)));
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class)));
       Broker.ProviderSession brokerSession = Mockito.mock(Broker.ProviderSession.class);
       SchemaContext schemaContext = mock(SchemaContext.class);
       ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext));
@@ -100,7 +100,7 @@ public class RpcBrokerTest {
   @Test
   public void testInvokeRpc() throws URISyntaxException {
     new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(mock(ClusterWrapper.class)));
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(mock(ClusterWrapper.class)));
       Broker.ProviderSession brokerSession = mock(Broker.ProviderSession.class);
       SchemaContext schemaContext = mock(SchemaContext.class);
       ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext));
@@ -141,7 +141,7 @@ public class RpcBrokerTest {
   @Test
   public void testInvokeRoutedRpcError() throws URISyntaxException {
     new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(Mockito.mock(ClusterWrapper.class)));
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class)));
       Broker.ProviderSession brokerSession = Mockito.mock(Broker.ProviderSession.class);
       SchemaContext schemaContext = mock(SchemaContext.class);
       ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext));
@@ -172,7 +172,7 @@ public class RpcBrokerTest {
   @Test
   public void testInvokeRoutedRpc() throws URISyntaxException {
     new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(mock(ClusterWrapper.class)));
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(mock(ClusterWrapper.class)));
       Broker.ProviderSession brokerSession = mock(Broker.ProviderSession.class);
       SchemaContext schemaContext = mock(SchemaContext.class);
       ActorRef rpcBroker = system.actorOf(RpcBroker.props(brokerSession, rpcRegistry, schemaContext));
@@ -19,10 +19,10 @@ import java.net.URISyntaxException;
 import java.util.HashSet;
 import java.util.Set;
 
-public class RoutingTableTest {
+public class RoutingTableOldTest {
 
-  private RoutingTable<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable =
-      new RoutingTable<>();
+  private RoutingTableOld<RpcRouter.RouteIdentifier<?, ?, ?>, String> routingTable =
+      new RoutingTableOld<>();
 
   @Test
   public void addGlobalRouteNullRouteIdTest() {
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistryOldTest.java
new file mode 100644 (file)
index 0000000..0f711b4
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * 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.remote.rpc.registry;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.testkit.JavaTestKit;
+import junit.framework.Assert;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl;
+import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.AddRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply;
+import org.opendaylight.controller.remote.rpc.messages.GetRpc;
+import org.opendaylight.controller.remote.rpc.messages.GetRpcReply;
+import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc;
+import org.opendaylight.controller.remote.rpc.messages.RemoveRpc;
+import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.yangtools.yang.common.QName;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.HashSet;
+import java.util.Set;
+
+public class RpcRegistryOldTest {
+
+  static ActorSystem system;
+
+
+  @BeforeClass
+  public static void setup() {
+    system = ActorSystem.create();
+  }
+
+  @AfterClass
+  public static void teardown() {
+    JavaTestKit.shutdownActorSystem(system);
+    system = null;
+  }
+
+  /**
+   This test add, read and remove an entry in global rpc
+   */
+  @Test
+  public void testGlobalRpc() throws URISyntaxException {
+    new JavaTestKit(system) {{
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class)));
+      QName type = new QName(new URI("actor1"), "actor1");
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null);
+      final String route = "actor1";
+
+      AddRpc rpcMsg = new AddRpc(routeId, route);
+      rpcRegistry.tell(rpcMsg, getRef());
+      expectMsgEquals(duration("2 second"), "Success");
+
+      GetRpc getRpc = new GetRpc(routeId);
+      rpcRegistry.tell(getRpc, getRef());
+
+      Boolean getMsg = new ExpectMsg<Boolean>("GetRpcReply") {
+        protected Boolean match(Object in) {
+          if (in instanceof GetRpcReply) {
+            GetRpcReply reply = (GetRpcReply)in;
+            return route.equals(reply.getRoutePath());
+          } else {
+            throw noMatch();
+          }
+        }
+      }.get(); // this extracts the received message
+
+      Assert.assertTrue(getMsg);
+
+      RemoveRpc removeMsg = new RemoveRpc(routeId);
+      rpcRegistry.tell(removeMsg, getRef());
+      expectMsgEquals(duration("2 second"), "Success");
+
+      rpcRegistry.tell(getRpc, getRef());
+
+      Boolean getNullMsg = new ExpectMsg<Boolean>("GetRpcReply") {
+        protected Boolean match(Object in) {
+          if (in instanceof GetRpcReply) {
+            GetRpcReply reply = (GetRpcReply)in;
+            return reply.getRoutePath() == null;
+          } else {
+            throw noMatch();
+          }
+        }
+      }.get();
+      Assert.assertTrue(getNullMsg);
+    }};
+
+  }
+
+  /**
+   This test add, read and remove an entry in routed rpc
+   */
+  @Test
+  public void testRoutedRpc() throws URISyntaxException {
+    new JavaTestKit(system) {{
+      ActorRef rpcRegistry = system.actorOf(RpcRegistryOld.props(Mockito.mock(ClusterWrapper.class)));
+      QName type = new QName(new URI("actor1"), "actor1");
+      RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null);
+      final String route = "actor1";
+
+      Set<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = new HashSet<>();
+      routeIds.add(routeId);
+
+      AddRoutedRpc rpcMsg = new AddRoutedRpc(routeIds, route);
+      rpcRegistry.tell(rpcMsg, getRef());
+      expectMsgEquals(duration("2 second"), "Success");
+
+      GetRoutedRpc getRpc = new GetRoutedRpc(routeId);
+      rpcRegistry.tell(getRpc, getRef());
+
+      Boolean getMsg = new ExpectMsg<Boolean>("GetRoutedRpcReply") {
+        protected Boolean match(Object in) {
+          if (in instanceof GetRoutedRpcReply) {
+            GetRoutedRpcReply reply = (GetRoutedRpcReply)in;
+            return route.equals(reply.getRoutePath());
+          } else {
+            throw noMatch();
+          }
+        }
+      }.get(); // this extracts the received message
+
+      Assert.assertTrue(getMsg);
+
+      RemoveRoutedRpc removeMsg = new RemoveRoutedRpc(routeIds, route);
+      rpcRegistry.tell(removeMsg, getRef());
+      expectMsgEquals(duration("2 second"), "Success");
+
+      rpcRegistry.tell(getRpc, getRef());
+
+      Boolean getNullMsg = new ExpectMsg<Boolean>("GetRoutedRpcReply") {
+        protected Boolean match(Object in) {
+          if (in instanceof GetRoutedRpcReply) {
+            GetRoutedRpcReply reply = (GetRoutedRpcReply)in;
+            return reply.getRoutePath() == null;
+          } else {
+            throw noMatch();
+          }
+        }
+      }.get();
+      Assert.assertTrue(getNullMsg);
+    }};
+
+  }
+
+}
index d011d331a684e4f0bcbbbf395e18145364dfdf4a..ab609413dd82731466495365d0c46f28731fcdc0 100644 (file)
-/*
- * 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.remote.rpc.registry;
 
+import akka.actor.ActorPath;
 import akka.actor.ActorRef;
+import akka.actor.ActorSelection;
 import akka.actor.ActorSystem;
+import akka.actor.ChildActorPath;
+import akka.actor.Props;
+import akka.japi.Pair;
 import akka.testkit.JavaTestKit;
-import junit.framework.Assert;
+import com.typesafe.config.ConfigFactory;
+import org.junit.After;
 import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
-import org.mockito.Mockito;
 import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl;
-import org.opendaylight.controller.remote.rpc.messages.AddRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.AddRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRoutedRpcReply;
-import org.opendaylight.controller.remote.rpc.messages.GetRpc;
-import org.opendaylight.controller.remote.rpc.messages.GetRpcReply;
-import org.opendaylight.controller.remote.rpc.messages.RemoveRoutedRpc;
-import org.opendaylight.controller.remote.rpc.messages.RemoveRpc;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
 import org.opendaylight.yangtools.yang.common.QName;
+import scala.concurrent.Await;
+import scala.concurrent.Future;
+import scala.concurrent.duration.FiniteDuration;
 
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.HashSet;
-import java.util.Set;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoute;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRoutersReply;
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 
 public class RpcRegistryTest {
 
-  static ActorSystem system;
-
-
-  @BeforeClass
-  public static void setup() {
-    system = ActorSystem.create();
-  }
-
-  @AfterClass
-  public static void teardown() {
-    JavaTestKit.shutdownActorSystem(system);
-    system = null;
-  }
-
-  /**
-   This test add, read and remove an entry in global rpc
-   */
-  @Test
-  public void testGlobalRpc() throws URISyntaxException {
-    new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(Mockito.mock(ClusterWrapper.class)));
-      QName type = new QName(new URI("actor1"), "actor1");
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null);
-      final String route = "actor1";
-
-      AddRpc rpcMsg = new AddRpc(routeId, route);
-      rpcRegistry.tell(rpcMsg, getRef());
-      expectMsgEquals(duration("2 second"), "Success");
-
-      GetRpc getRpc = new GetRpc(routeId);
-      rpcRegistry.tell(getRpc, getRef());
-
-      Boolean getMsg = new ExpectMsg<Boolean>("GetRpcReply") {
-        protected Boolean match(Object in) {
-          if (in instanceof GetRpcReply) {
-            GetRpcReply reply = (GetRpcReply)in;
-            return route.equals(reply.getRoutePath());
-          } else {
-            throw noMatch();
-          }
-        }
-      }.get(); // this extracts the received message
+    private static ActorSystem node1;
+    private static ActorSystem node2;
+    private static ActorSystem node3;
+
+    private ActorRef registry1;
+    private ActorRef registry2;
+    private ActorRef registry3;
+
+    @BeforeClass
+    public static void setup() throws InterruptedException {
+        Thread.sleep(1000); //give some time for previous test to close netty ports
+        node1 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberA"));
+        node2 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberB"));
+        node3 = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("memberC"));
+    }
+
+    @AfterClass
+    public static void teardown(){
+        JavaTestKit.shutdownActorSystem(node1);
+        JavaTestKit.shutdownActorSystem(node2);
+        JavaTestKit.shutdownActorSystem(node3);
+        if (node1 != null)
+            node1.shutdown();
+        if (node2 != null)
+            node2.shutdown();
+        if (node3 != null)
+            node3.shutdown();
+
+    }
+
+    @Before
+    public void createRpcRegistry() throws InterruptedException {
+        registry1 = node1.actorOf(Props.create(RpcRegistry.class));
+        registry2 = node2.actorOf(Props.create(RpcRegistry.class));
+        registry3 = node3.actorOf(Props.create(RpcRegistry.class));
+    }
+
+    @After
+    public void stopRpcRegistry() throws InterruptedException {
+        if (registry1 != null)
+            node1.stop(registry1);
+        if (registry2 != null)
+            node2.stop(registry2);
+        if (registry3 != null)
+            node3.stop(registry3);
+    }
+
+    /**
+     * One node cluster.
+     * Register rpc. Ensure router can be found
+     *
+     * @throws URISyntaxException
+     * @throws InterruptedException
+     */
+    @Test
+    public void testWhenRpcAddedOneNodeShouldAppearOnSameNode() throws URISyntaxException, InterruptedException {
+
+        final JavaTestKit mockBroker = new JavaTestKit(node1);
+
+        //Add rpc on node 1
+        registry1.tell(new SetLocalRouter(mockBroker.getRef()), mockBroker.getRef());
+        registry1.tell(getAddRouteMessage(), mockBroker.getRef());
+
+        Thread.sleep(1000);//
+
+        //find the route on node 1's registry
+        registry1.tell(new FindRouters(createRouteId()), mockBroker.getRef());
+        FindRoutersReply message = mockBroker.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
+
+        validateRouterReceived(pairs, mockBroker.getRef());
+    }
+
+    /**
+     * Three node cluster.
+     * Register rpc on 1 node. Ensure its router can be found on other 2.
+     *
+     * @throws URISyntaxException
+     * @throws InterruptedException
+     */
+    @Test
+    public void testWhenRpcAddedOneNodeShouldAppearOnAnother() throws URISyntaxException, InterruptedException {
+
+        validateSystemStartup();
+
+        final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+        final JavaTestKit mockBroker2 = new JavaTestKit(node2);
+        final JavaTestKit mockBroker3 = new JavaTestKit(node3);
+
+        //Add rpc on node 1
+        registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
+        registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
+
+        Thread.sleep(5000);// give some time for bucket store data sync
+
+        //find the route in node 2's registry
+        registry2.tell(new FindRouters(createRouteId()), mockBroker2.getRef());
+        FindRoutersReply message = mockBroker2.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
+
+        validateRouterReceived(pairs, mockBroker1.getRef());
+
+        //find the route in node 3's registry
+        registry3.tell(new FindRouters(createRouteId()), mockBroker3.getRef());
+        message = mockBroker3.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        pairs = message.getRouterWithUpdateTime();
+
+        validateRouterReceived(pairs, mockBroker1.getRef());
+
+    }
+
+    /**
+     * Three node cluster.
+     * Register rpc on 2 nodes. Ensure 2 routers are found on 3rd.
+     *
+     * @throws Exception
+     */
+    @Test
+    public void testAnRpcAddedOnMultiNodesShouldReturnMultiRouter() throws Exception {
+
+        validateSystemStartup();
+
+        final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+        final JavaTestKit mockBroker2 = new JavaTestKit(node2);
+        final JavaTestKit mockBroker3 = new JavaTestKit(node3);
+
+        //Thread.sleep(5000);//let system come up
+
+        //Add rpc on node 1
+        registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
+        registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
+
+        //Add same rpc on node 2
+        registry2.tell(new SetLocalRouter(mockBroker2.getRef()), mockBroker2.getRef());
+        registry2.tell(getAddRouteMessage(), mockBroker2.getRef());
+
+        registry3.tell(new SetLocalRouter(mockBroker3.getRef()), mockBroker3.getRef());
+        Thread.sleep(5000);// give some time for bucket store data sync
+
+        //find the route in node 3's registry
+        registry3.tell(new FindRouters(createRouteId()), mockBroker3.getRef());
+        FindRoutersReply message = mockBroker3.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
+        List<Pair<ActorRef, Long>> pairs = message.getRouterWithUpdateTime();
 
-      Assert.assertTrue(getMsg);
+        validateMultiRouterReceived(pairs, mockBroker1.getRef(), mockBroker2.getRef());
 
-      RemoveRpc removeMsg = new RemoveRpc(routeId);
-      rpcRegistry.tell(removeMsg, getRef());
-      expectMsgEquals(duration("2 second"), "Success");
+    }
 
-      rpcRegistry.tell(getRpc, getRef());
+    private void validateMultiRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef... expected) {
+        Assert.assertTrue(actual != null);
+        Assert.assertTrue(actual.size() == expected.length);
+    }
 
-      Boolean getNullMsg = new ExpectMsg<Boolean>("GetRpcReply") {
-        protected Boolean match(Object in) {
-          if (in instanceof GetRpcReply) {
-            GetRpcReply reply = (GetRpcReply)in;
-            return reply.getRoutePath() == null;
-          } else {
-            throw noMatch();
-          }
-        }
-      }.get();
-      Assert.assertTrue(getNullMsg);
-    }};
-
-  }
-
-  /**
-   This test add, read and remove an entry in routed rpc
-   */
-  @Test
-  public void testRoutedRpc() throws URISyntaxException {
-    new JavaTestKit(system) {{
-      ActorRef rpcRegistry = system.actorOf(RpcRegistry.props(Mockito.mock(ClusterWrapper.class)));
-      QName type = new QName(new URI("actor1"), "actor1");
-      RouteIdentifierImpl routeId = new RouteIdentifierImpl(null, type, null);
-      final String route = "actor1";
-
-      Set<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = new HashSet<>();
-      routeIds.add(routeId);
-
-      AddRoutedRpc rpcMsg = new AddRoutedRpc(routeIds, route);
-      rpcRegistry.tell(rpcMsg, getRef());
-      expectMsgEquals(duration("2 second"), "Success");
-
-      GetRoutedRpc getRpc = new GetRoutedRpc(routeId);
-      rpcRegistry.tell(getRpc, getRef());
-
-      Boolean getMsg = new ExpectMsg<Boolean>("GetRoutedRpcReply") {
-        protected Boolean match(Object in) {
-          if (in instanceof GetRoutedRpcReply) {
-            GetRoutedRpcReply reply = (GetRoutedRpcReply)in;
-            return route.equals(reply.getRoutePath());
-          } else {
-            throw noMatch();
-          }
+    private void validateRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef expected){
+        Assert.assertTrue(actual != null);
+        Assert.assertTrue(actual.size() == 1);
+
+        for (Pair<ActorRef, Long> pair : actual){
+            Assert.assertTrue(expected.path().uid() == pair.first().path().uid());
         }
-      }.get(); // this extracts the received message
+    }
 
-      Assert.assertTrue(getMsg);
+    private void validateSystemStartup() throws InterruptedException {
 
-      RemoveRoutedRpc removeMsg = new RemoveRoutedRpc(routeIds, route);
-      rpcRegistry.tell(removeMsg, getRef());
-      expectMsgEquals(duration("2 second"), "Success");
+        Thread.sleep(5000);
+        ActorPath gossiper1Path = new ChildActorPath(new ChildActorPath(registry1.path(), "store"), "gossiper");
+        ActorPath gossiper2Path = new ChildActorPath(new ChildActorPath(registry2.path(), "store"), "gossiper");
+        ActorPath gossiper3Path = new ChildActorPath(new ChildActorPath(registry3.path(), "store"), "gossiper");
 
-      rpcRegistry.tell(getRpc, getRef());
+        ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
+        ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
+        ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
 
-      Boolean getNullMsg = new ExpectMsg<Boolean>("GetRoutedRpcReply") {
-        protected Boolean match(Object in) {
-          if (in instanceof GetRoutedRpcReply) {
-            GetRoutedRpcReply reply = (GetRoutedRpcReply)in;
-            return reply.getRoutePath() == null;
-          } else {
-            throw noMatch();
-          }
-        }
-      }.get();
-      Assert.assertTrue(getNullMsg);
-    }};
 
-  }
+        if (!resolveReference(gossiper1, gossiper2, gossiper3))
+            Assert.fail("Could not find gossipers");
+    }
 
-}
+    private Boolean resolveReference(ActorSelection... gossipers) throws InterruptedException {
+
+        Boolean resolved = true;
+
+        for (int i=0; i< 5; i++) {
+            Thread.sleep(1000);
+            for (ActorSelection gossiper : gossipers) {
+                Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(5000, TimeUnit.MILLISECONDS));
+
+                ActorRef ref = null;
+                try {
+                    ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+
+                if (ref == null)
+                    resolved = false;
+            }
+
+            if (resolved) break;
+        }
+        return resolved;
+    }
+
+    private AddOrUpdateRoute getAddRouteMessage() throws URISyntaxException {
+        return new AddOrUpdateRoute(createRouteId());
+    }
+
+    private RpcRouter.RouteIdentifier<?,?,?> createRouteId() throws URISyntaxException {
+        QName type = new QName(new URI("/mockrpc"), "mockrpc");
+        return new RouteIdentifierImpl(null, type, null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStoreTest.java
new file mode 100644 (file)
index 0000000..7e87da0
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import akka.actor.ActorRef;
+import akka.actor.ActorSystem;
+import akka.actor.Props;
+import akka.testkit.TestActorRef;
+import akka.testkit.TestProbe;
+import com.typesafe.config.ConfigFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.remote.rpc.TerminationMonitor;
+
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+
+public class BucketStoreTest {
+
+    private static ActorSystem system;
+    private static BucketStore store;
+
+    private BucketStore mockStore;
+
+    @BeforeClass
+    public static void setup() {
+
+        system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test"));
+        system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
+
+        store = createStore();
+    }
+
+    @AfterClass
+    public static void teardown() {
+        system.shutdown();
+    }
+
+    @Before
+    public void createMocks(){
+        mockStore = spy(store);
+    }
+
+    @After
+    public void resetMocks(){
+        reset(mockStore);
+    }
+
+    @Test
+    public void testReceiveUpdateBucket_WhenInputBucketShouldUpdateVersion(){
+        Bucket bucket = new BucketImpl();
+        Long expectedVersion = bucket.getVersion();
+
+        mockStore.receiveUpdateBucket(bucket);
+
+        Assert.assertEquals(bucket, mockStore.getLocalBucket());
+        Assert.assertEquals(expectedVersion, mockStore.getLocalBucket().getVersion());
+    }
+
+    /**
+     * Create BucketStore actor and returns the underlying instance of BucketStore class.
+     *
+     * @return instance of BucketStore class
+     */
+    private static BucketStore createStore(){
+        TestProbe mockActor = new TestProbe(system);
+        ActorRef mockGossiper = mockActor.ref();
+        final Props props = Props.create(BucketStore.class, mockGossiper);
+        final TestActorRef<BucketStore> testRef = TestActorRef.create(system, props, "testStore");
+
+        return testRef.underlyingActor();
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java b/opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java
new file mode 100644 (file)
index 0000000..d862dcb
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * 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.remote.rpc.registry.gossip;
+
+import akka.actor.ActorSystem;
+import akka.actor.Address;
+import akka.actor.Props;
+import akka.testkit.TestActorRef;
+import com.typesafe.config.ConfigFactory;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.opendaylight.controller.remote.rpc.TerminationMonitor;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipEnvelope;
+import static org.opendaylight.controller.remote.rpc.registry.gossip.Messages.GossiperMessages.GossipStatus;
+
+
+public class GossiperTest {
+
+    private static ActorSystem system;
+    private static Gossiper gossiper;
+
+    private Gossiper mockGossiper;
+
+    @BeforeClass
+    public static void setup() throws InterruptedException {
+        Thread.sleep(1000);//give some time for previous test to stop the system. Netty port conflict arises otherwise.
+        system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test"));
+        system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
+
+        gossiper = createGossiper();
+    }
+
+    @AfterClass
+    public static void teardown() {
+        if (system != null)
+            system.shutdown();
+    }
+
+    @Before
+    public void createMocks(){
+        mockGossiper = spy(gossiper);
+    }
+
+    @After
+    public void resetMocks(){
+        reset(mockGossiper);
+
+    }
+
+    @Test
+    public void testReceiveGossipTick_WhenNoRemoteMemberShouldIgnore(){
+
+        mockGossiper.setClusterMembers(Collections.EMPTY_LIST);
+        doNothing().when(mockGossiper).getLocalStatusAndSendTo(any(Address.class));
+        mockGossiper.receiveGossipTick();
+        verify(mockGossiper, times(0)).getLocalStatusAndSendTo(any(Address.class));
+    }
+
+    @Test
+    public void testReceiveGossipTick_WhenRemoteMemberExistsShouldSendStatus(){
+        List<Address> members = new ArrayList<>();
+        Address remote = new Address("tcp", "member");
+        members.add(remote);
+
+        mockGossiper.setClusterMembers(members);
+        doNothing().when(mockGossiper).getLocalStatusAndSendTo(any(Address.class));
+        mockGossiper.receiveGossipTick();
+        verify(mockGossiper, times(1)).getLocalStatusAndSendTo(any(Address.class));
+    }
+
+    @Test
+    public void testReceiveGossipStatus_WhenSenderIsNonMemberShouldIgnore(){
+
+        Address nonMember = new Address("tcp", "non-member");
+        GossipStatus remoteStatus = new GossipStatus(nonMember, mock(Map.class));
+
+        //add a member
+        List<Address> members = new ArrayList<>();
+        members.add(new Address("tcp", "member"));
+
+        mockGossiper.setClusterMembers(members);
+        mockGossiper.receiveGossipStatus(remoteStatus);
+        verify(mockGossiper, times(0)).getSender();
+    }
+
+    @Test
+    public void testReceiveGossip_WhenNotAddressedToSelfShouldIgnore(){
+        Address notSelf = new Address("tcp", "not-self");
+
+        GossipEnvelope envelope = new GossipEnvelope(notSelf, notSelf, mock(Map.class));
+        doNothing().when(mockGossiper).updateRemoteBuckets(anyMap());
+        mockGossiper.receiveGossip(envelope);
+        verify(mockGossiper, times(0)).updateRemoteBuckets(anyMap());
+    }
+
+    @Test
+    public void testUpdateRemoteBuckets_WhenNoBucketShouldIgnore(){
+
+        mockGossiper.updateRemoteBuckets(null);
+        verify(mockGossiper, times(0)).getContext();
+
+        Map<Address, Bucket> empty = Collections.emptyMap();
+        mockGossiper.updateRemoteBuckets(empty);
+        verify(mockGossiper, times(0)).getContext();
+    }
+
+    /**
+     * Create Gossiper actor and return the underlying instance of Gossiper class.
+     *
+     * @return instance of Gossiper class
+     */
+    private static Gossiper createGossiper(){
+
+        final Props props = Props.create(Gossiper.class, false);
+        final TestActorRef<Gossiper> testRef = TestActorRef.create(system, props, "testGossiper");
+
+        return testRef.underlyingActor();
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf b/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf
new file mode 100644 (file)
index 0000000..874d3fc
--- /dev/null
@@ -0,0 +1,116 @@
+odl-cluster{
+  akka {
+    loglevel = "INFO"
+    #log-config-on-start = on
+
+    actor {
+      provider = "akka.cluster.ClusterActorRefProvider"
+      debug{
+        #autoreceive = on
+        #lifecycle = on
+
+      }
+    }
+    remote {
+      log-received-messages = on
+      log-sent-messages = on
+
+      log-remote-lifecycle-events = off
+      netty.tcp {
+        hostname = "localhost"
+        port = 2551
+      }
+    }
+
+    cluster {
+      seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+
+      auto-down-unreachable-after = 10s
+    }
+  }
+}
+unit-test{
+  akka {
+    loglevel = "INFO"
+    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    actor {
+      provider = "akka.cluster.ClusterActorRefProvider"
+    }
+  }
+}
+
+memberA{
+  akka {
+    loglevel = "INFO"
+    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    actor {
+      provider = "akka.cluster.ClusterActorRefProvider"
+    }
+    remote {
+      log-received-messages = off
+      log-sent-messages = off
+
+      log-remote-lifecycle-events = off
+      netty.tcp {
+        hostname = "localhost"
+        port = 2551
+      }
+    }
+
+    cluster {
+      seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+
+      auto-down-unreachable-after = 10s
+    }
+  }
+}
+memberB{
+  akka {
+    loglevel = "INFO"
+    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    actor {
+      provider = "akka.cluster.ClusterActorRefProvider"
+    }
+    remote {
+      log-received-messages = off
+      log-sent-messages = off
+
+      log-remote-lifecycle-events = off
+      netty.tcp {
+        hostname = "localhost"
+        port = 2552
+      }
+    }
+
+    cluster {
+      seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+
+      auto-down-unreachable-after = 10s
+    }
+  }
+}
+memberC{
+  akka {
+    loglevel = "INFO"
+    loggers = ["akka.event.slf4j.Slf4jLogger"]
+    actor {
+      provider = "akka.cluster.ClusterActorRefProvider"
+    }
+    remote {
+      log-received-messages = off
+      log-sent-messages = off
+
+      log-remote-lifecycle-events = off
+      netty.tcp {
+        hostname = "localhost"
+        port = 2553
+      }
+    }
+
+    cluster {
+      seed-nodes = ["akka.tcp://opendaylight-rpc@localhost:2551"]
+
+      auto-down-unreachable-after = 10s
+    }
+  }
+}
\ No newline at end of file
index 73ca02c505f47741ca4e38c071a780a0f32e1cdf..fac6c80564784759e08aef3db46ebada1dba69fe 100644 (file)
@@ -632,7 +632,8 @@ public class RestconfImpl implements RestconfService {
         NormalizedNode<?, ?> data = null;
         YangInstanceIdentifier normalizedII;
         if (mountPoint != null) {
-            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                    .getInstanceIdentifier());
             data = broker.readConfigurationData(mountPoint, normalizedII);
         } else {
             normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
@@ -695,7 +696,8 @@ public class RestconfImpl implements RestconfService {
         NormalizedNode<?, ?> data = null;
         YangInstanceIdentifier normalizedII;
         if (mountPoint != null) {
-            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+            normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                    .getInstanceIdentifier());
             data = broker.readOperationalData(mountPoint, normalizedII);
         } else {
             normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
@@ -730,7 +732,8 @@ public class RestconfImpl implements RestconfService {
 
         try {
             if (mountPoint != null) {
-                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                        .getInstanceIdentifier());
                 broker.commitConfigurationDataPut(mountPoint, normalizedII, datastoreNormalizedNode).get();
             } else {
                 normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
@@ -842,7 +845,8 @@ public class RestconfImpl implements RestconfService {
 
         try {
             if (mountPoint != null) {
-                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                        .getInstanceIdentifier());
                 broker.commitConfigurationDataPost(mountPoint, normalizedII, datastoreNormalizedData);
             } else {
                 normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
@@ -886,7 +890,8 @@ public class RestconfImpl implements RestconfService {
 
         try {
             if (mountPoint != null) {
-                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                        .getInstanceIdentifier());
                 broker.commitConfigurationDataPost(mountPoint, normalizedII, datastoreNormalizedData);
 
             } else {
@@ -908,7 +913,8 @@ public class RestconfImpl implements RestconfService {
 
         try {
             if (mountPoint != null) {
-                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData.getInstanceIdentifier());
+                normalizedII = new DataNormalizer(mountPoint.getSchemaContext()).toNormalized(iiWithData
+                        .getInstanceIdentifier());
                 broker.commitConfigurationDataDelete(mountPoint, normalizedII);
             } else {
                 normalizedII = controllerContext.toNormalized(iiWithData.getInstanceIdentifier());
@@ -1082,7 +1088,12 @@ public class RestconfImpl implements RestconfService {
             iiBuilder = YangInstanceIdentifier.builder(iiOriginal);
         }
 
-        iiBuilder.node(schemaOfData.getQName());
+        if ((schemaOfData instanceof ListSchemaNode)) {
+            HashMap<QName, Object> keys = this.resolveKeysFromData(((ListSchemaNode) schemaOfData), data);
+            iiBuilder.nodeWithKey(schemaOfData.getQName(), keys);
+        } else {
+            iiBuilder.node(schemaOfData.getQName());
+        }
 
         YangInstanceIdentifier instance = iiBuilder.toInstance();
         DOMMountPoint mountPoint = null;
@@ -1093,6 +1104,34 @@ public class RestconfImpl implements RestconfService {
         return new InstanceIdWithSchemaNode(instance, schemaOfData, mountPoint);
     }
 
+    private HashMap<QName, Object> resolveKeysFromData(final ListSchemaNode listNode, final CompositeNode dataNode) {
+        final HashMap<QName, Object> keyValues = new HashMap<QName, Object>();
+        List<QName> _keyDefinition = listNode.getKeyDefinition();
+        for (final QName key : _keyDefinition) {
+            SimpleNode<? extends Object> head = null;
+            String localName = key.getLocalName();
+            List<SimpleNode<? extends Object>> simpleNodesByName = dataNode.getSimpleNodesByName(localName);
+            if (simpleNodesByName != null) {
+                head = Iterables.getFirst(simpleNodesByName, null);
+            }
+
+            Object dataNodeKeyValueObject = null;
+            if (head != null) {
+                dataNodeKeyValueObject = head.getValue();
+            }
+
+            if (dataNodeKeyValueObject == null) {
+                throw new RestconfDocumentedException("Data contains list \"" + dataNode.getNodeType().getLocalName()
+                        + "\" which does not contain key: \"" + key.getLocalName() + "\"", ErrorType.PROTOCOL,
+                        ErrorTag.INVALID_VALUE);
+            }
+
+            keyValues.put(key, dataNodeKeyValueObject);
+        }
+
+        return keyValues;
+    }
+
     private boolean endsWithMountPoint(final String identifier) {
         return identifier.endsWith(ControllerContext.MOUNT) || identifier.endsWith(ControllerContext.MOUNT + "/");
     }
@@ -1431,7 +1470,8 @@ public class RestconfImpl implements RestconfService {
                 "It wasn't possible to correctly interpret data."));
     }
 
-    private NormalizedNode<?, ?> compositeNodeToDatastoreNormalizedNode(final CompositeNode compNode, final DataSchemaNode schema) {
+    private NormalizedNode<?, ?> compositeNodeToDatastoreNormalizedNode(final CompositeNode compNode,
+            final DataSchemaNode schema) {
         List<Node<?>> lst = new ArrayList<Node<?>>();
         lst.add(compNode);
         if (schema instanceof ContainerSchemaNode) {
@@ -1448,7 +1488,8 @@ public class RestconfImpl implements RestconfService {
                 "It wasn't possible to translate specified data to datastore readable form."));
     }
 
-    private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(final InstanceIdWithSchemaNode iiWithSchemaNode) {
+    private InstanceIdWithSchemaNode normalizeInstanceIdentifierWithSchemaNode(
+            final InstanceIdWithSchemaNode iiWithSchemaNode) {
         return normalizeInstanceIdentifierWithSchemaNode(iiWithSchemaNode, false);
     }
 
@@ -1459,8 +1500,8 @@ public class RestconfImpl implements RestconfService {
                 iiWithSchemaNode.getMountPoint());
     }
 
-    private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(final YangInstanceIdentifier instIdentifier,
-            final boolean unwrapLastListNode) {
+    private YangInstanceIdentifier instanceIdentifierToReadableFormForNormalizeNode(
+            final YangInstanceIdentifier instIdentifier, final boolean unwrapLastListNode) {
         Preconditions.checkNotNull(instIdentifier, "Instance identifier can't be null");
         final List<PathArgument> result = new ArrayList<PathArgument>();
         final Iterator<PathArgument> iter = instIdentifier.getPathArguments().iterator();
index 0c8b4d5a2ada924025aa40ff805d9c4613606e66..1141e1d72e212204ed21ffcf725e4226835e427b 100644 (file)
       <artifactId>mockito-all</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>yang-data-api</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index 82409d2e4033050833c7285927e5db23d0d20fc6..633d419fa9ae4219e2d276eb530fe4780514a88d 100644 (file)
@@ -7,8 +7,8 @@
  */
 package org.opendaylight.controller.sal.rest.doc.impl;
 
+import com.google.common.base.Preconditions;
 import javax.ws.rs.core.UriInfo;
-
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration;
 import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
@@ -16,11 +16,8 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Preconditions;
-
 /**
- * This class gathers all yang defined {@link Module}s and generates Swagger
- * compliant documentation.
+ * This class gathers all yang defined {@link Module}s and generates Swagger compliant documentation.
  */
 public class ApiDocGenerator extends BaseYangSwaggerGenerator {
 
index 5ba8b26bc1eb6bb69ac0d5e3564dbbfe5f8c27cf..1b2718251446dde021d3cc62b794b990f8852dc4 100644 (file)
@@ -7,6 +7,12 @@
  */
 package org.opendaylight.controller.sal.rest.doc.impl;
 
+import static org.opendaylight.controller.sal.rest.doc.util.RestDocgenUtil.resolvePathArgumentsName;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
+import com.google.common.base.Preconditions;
 import java.io.IOException;
 import java.net.URI;
 import java.text.DateFormat;
@@ -22,9 +28,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.SortedSet;
 import java.util.TreeSet;
-
 import javax.ws.rs.core.UriInfo;
-
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder;
@@ -46,11 +50,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
-import com.google.common.base.Preconditions;
-
 public class BaseYangSwaggerGenerator {
 
     private static Logger _logger = LoggerFactory.getLogger(BaseYangSwaggerGenerator.class);
@@ -75,8 +74,7 @@ public class BaseYangSwaggerGenerator {
      * @param operType
      * @return list of modules converted to swagger compliant resource list.
      */
-    public ResourceList getResourceListing(UriInfo uriInfo, SchemaContext schemaContext,
-            String context) {
+    public ResourceList getResourceListing(UriInfo uriInfo, SchemaContext schemaContext, String context) {
 
         ResourceList resourceList = createResourceList();
 
@@ -88,11 +86,9 @@ public class BaseYangSwaggerGenerator {
 
         for (Module module : modules) {
             String revisionString = SIMPLE_DATE_FORMAT.format(module.getRevision());
-
             Resource resource = new Resource();
             _logger.debug("Working on [{},{}]...", module.getName(), revisionString);
-            ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo,
-                    schemaContext, context);
+            ApiDeclaration doc = getApiDeclaration(module.getName(), revisionString, uriInfo, schemaContext, context);
 
             if (doc != null) {
                 resource.setPath(generatePath(uriInfo, module.getName(), revisionString));
@@ -119,8 +115,7 @@ public class BaseYangSwaggerGenerator {
         return uri.toASCIIString();
     }
 
-    public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo,
-            SchemaContext schemaContext, String context) {
+    public ApiDeclaration getApiDeclaration(String module, String revision, UriInfo uriInfo, SchemaContext schemaContext, String context) {
         Date rev = null;
         try {
             rev = SIMPLE_DATE_FORMAT.parse(revision);
@@ -128,17 +123,15 @@ public class BaseYangSwaggerGenerator {
             throw new IllegalArgumentException(e);
         }
         Module m = schemaContext.findModuleByName(module, rev);
-        Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module
-                + "," + revision);
+        Preconditions.checkArgument(m != null, "Could not find module by name,revision: " + module + "," + revision);
 
-        return getApiDeclaration(m, rev, uriInfo, schemaContext, context);
+        return getApiDeclaration(m, rev, uriInfo, context, schemaContext);
     }
 
-    public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo,
-            SchemaContext schemaContext, String context) {
+    public ApiDeclaration getApiDeclaration(Module module, Date revision, UriInfo uriInfo, String context, SchemaContext schemaContext) {
         String basePath = createBasePathFromUriInfo(uriInfo);
 
-        ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context);
+        ApiDeclaration doc = getSwaggerDocSpec(module, basePath, context, schemaContext);
         if (doc != null) {
             return doc;
         }
@@ -152,12 +145,12 @@ public class BaseYangSwaggerGenerator {
             portPart = ":" + port;
         }
         String basePath = new StringBuilder(uriInfo.getBaseUri().getScheme()).append("://")
-                .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/")
-                .append(RESTCONF_CONTEXT_ROOT).toString();
+                .append(uriInfo.getBaseUri().getHost()).append(portPart).append("/").append(RESTCONF_CONTEXT_ROOT)
+                .toString();
         return basePath;
     }
 
-    public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context) {
+    public ApiDeclaration getSwaggerDocSpec(Module m, String basePath, String context, SchemaContext schemaContext) {
         ApiDeclaration doc = createApiDeclaration(basePath);
 
         List<Api> apis = new ArrayList<Api>();
@@ -167,22 +160,21 @@ public class BaseYangSwaggerGenerator {
         for (DataSchemaNode node : dataSchemaNodes) {
             if ((node instanceof ListSchemaNode) || (node instanceof ContainerSchemaNode)) {
 
-                _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node
-                        .getQName().getLocalName());
+                _logger.debug("Is Configuration node [{}] [{}]", node.isConfiguration(), node.getQName().getLocalName());
 
                 List<Parameter> pathParams = new ArrayList<Parameter>();
-                String resourcePath = getDataStorePath("/config/", context) + m.getName() + ":";
-                addApis(node, apis, resourcePath, pathParams, true);
+                String resourcePath = getDataStorePath("/config/", context);
+                addApis(node, apis, resourcePath, pathParams, schemaContext, true);
 
                 pathParams = new ArrayList<Parameter>();
-                resourcePath = getDataStorePath("/operational/", context) + m.getName() + ":";
-                addApis(node, apis, resourcePath, pathParams, false);
+                resourcePath = getDataStorePath("/operational/", context);
+                addApis(node, apis, resourcePath, pathParams, schemaContext, false);
             }
 
             Set<RpcDefinition> rpcs = m.getRpcs();
             for (RpcDefinition rpcDefinition : rpcs) {
-                String resourcePath = getDataStorePath("/operations/", context) + m.getName() + ":";
-                addRpcs(rpcDefinition, apis, resourcePath);
+                String resourcePath = getDataStorePath("/operations/", context);
+                addRpcs(rpcDefinition, apis, resourcePath, schemaContext);
             }
         }
 
@@ -193,7 +185,7 @@ public class BaseYangSwaggerGenerator {
             JSONObject models = null;
 
             try {
-                models = jsonConverter.convertToJsonSchema(m);
+                models = jsonConverter.convertToJsonSchema(m, schemaContext);
                 doc.setModels(models);
                 if (_logger.isDebugEnabled()) {
                     _logger.debug(mapper.writeValueAsString(doc));
@@ -228,13 +220,13 @@ public class BaseYangSwaggerGenerator {
         return module + "(" + revision + ")";
     }
 
-    private void addApis(DataSchemaNode node, List<Api> apis, String parentPath,
-            List<Parameter> parentPathParams, boolean addConfigApi) {
+    private void addApis(DataSchemaNode node, List<Api> apis, String parentPath, List<Parameter> parentPathParams, SchemaContext schemaContext,
+            boolean addConfigApi) {
 
         Api api = new Api();
         List<Parameter> pathParams = new ArrayList<Parameter>(parentPathParams);
 
-        String resourcePath = parentPath + createPath(node, pathParams) + "/";
+        String resourcePath = parentPath + createPath(node, pathParams, schemaContext) + "/";
         _logger.debug("Adding path: [{}]", resourcePath);
         api.setPath(resourcePath);
         api.setOperations(operations(node, pathParams, addConfigApi));
@@ -248,7 +240,7 @@ public class BaseYangSwaggerGenerator {
                 if (childNode instanceof ListSchemaNode || childNode instanceof ContainerSchemaNode) {
                     // keep config and operation attributes separate.
                     if (childNode.isConfiguration() == addConfigApi) {
-                        addApis(childNode, apis, resourcePath, pathParams, addConfigApi);
+                        addApis(childNode, apis, resourcePath, pathParams, schemaContext, addConfigApi);
                     }
                 }
             }
@@ -261,8 +253,7 @@ public class BaseYangSwaggerGenerator {
      * @param pathParams
      * @return
      */
-    private List<Operation> operations(DataSchemaNode node, List<Parameter> pathParams,
-            boolean isConfig) {
+    private List<Operation> operations(DataSchemaNode node, List<Parameter> pathParams, boolean isConfig) {
         List<Operation> operations = new ArrayList<>();
 
         OperationBuilder.Get getBuilder = new OperationBuilder.Get(node, isConfig);
@@ -281,41 +272,37 @@ public class BaseYangSwaggerGenerator {
         return operations;
     }
 
-    private String createPath(final DataSchemaNode schemaNode, List<Parameter> pathParams) {
+    private String createPath(final DataSchemaNode schemaNode, List<Parameter> pathParams, SchemaContext schemaContext) {
         ArrayList<LeafSchemaNode> pathListParams = new ArrayList<LeafSchemaNode>();
         StringBuilder path = new StringBuilder();
-        QName _qName = schemaNode.getQName();
-        String localName = _qName.getLocalName();
+        String localName = resolvePathArgumentsName(schemaNode, schemaContext);
         path.append(localName);
 
         if ((schemaNode instanceof ListSchemaNode)) {
             final List<QName> listKeys = ((ListSchemaNode) schemaNode).getKeyDefinition();
             for (final QName listKey : listKeys) {
-                {
-                    DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode)
-                            .getDataChildByName(listKey);
-                    pathListParams.add(((LeafSchemaNode) _dataChildByName));
-
-                    String pathParamIdentifier = new StringBuilder("/{")
-                            .append(listKey.getLocalName()).append("}").toString();
-                    path.append(pathParamIdentifier);
-
-                    Parameter pathParam = new Parameter();
-                    pathParam.setName(listKey.getLocalName());
-                    pathParam.setDescription(_dataChildByName.getDescription());
-                    pathParam.setType("string");
-                    pathParam.setParamType("path");
-
-                    pathParams.add(pathParam);
-                }
+                DataSchemaNode _dataChildByName = ((DataNodeContainer) schemaNode).getDataChildByName(listKey);
+                pathListParams.add(((LeafSchemaNode) _dataChildByName));
+
+                String pathParamIdentifier = new StringBuilder("/{").append(listKey.getLocalName()).append("}")
+                        .toString();
+                path.append(pathParamIdentifier);
+
+                Parameter pathParam = new Parameter();
+                pathParam.setName(listKey.getLocalName());
+                pathParam.setDescription(_dataChildByName.getDescription());
+                pathParam.setType("string");
+                pathParam.setParamType("path");
+
+                pathParams.add(pathParam);
             }
         }
         return path.toString();
     }
 
-    protected void addRpcs(RpcDefinition rpcDefn, List<Api> apis, String parentPath) {
+    protected void addRpcs(RpcDefinition rpcDefn, List<Api> apis, String parentPath, SchemaContext schemaContext) {
         Api rpc = new Api();
-        String resourcePath = parentPath + rpcDefn.getQName().getLocalName();
+        String resourcePath = parentPath + resolvePathArgumentsName(rpcDefn, schemaContext);
         rpc.setPath(resourcePath);
 
         Operation operationSpec = new Operation();
@@ -364,4 +351,5 @@ public class BaseYangSwaggerGenerator {
         }
         return sortedModules;
     }
+
 }
index 95bb1a094371db4f17d38c310c0043b07006c5c3..819892f6477b2994e53c927cf1ab3a8dd2c2b545 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.sal.rest.doc.impl;
 
+import static org.opendaylight.controller.sal.rest.doc.util.RestDocgenUtil.resolveNodesName;
+
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -19,6 +21,7 @@ import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.opendaylight.controller.sal.rest.doc.model.builder.OperationBuilder;
+import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
@@ -31,6 +34,7 @@ import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
 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.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
@@ -86,8 +90,8 @@ public class ModelGenerator {
     private static final String NUMBER = "number";
     private static final String BOOLEAN = "boolean";
     private static final String STRING = "string";
-  private static final String ID_KEY = "id";
-  private static final String SUB_TYPES_KEY = "subTypes";
+    private static final String ID_KEY = "id";
+    private static final String SUB_TYPES_KEY = "subTypes";
 
     private static final Map<Class<? extends TypeDefinition<?>>, String> YANG_TYPE_TO_JSON_TYPE_MAPPING;
 
@@ -111,18 +115,21 @@ public class ModelGenerator {
         YANG_TYPE_TO_JSON_TYPE_MAPPING = Collections.unmodifiableMap(tempMap1);
     }
 
+    private Module topLevelModule;
+
     public ModelGenerator() {
     }
 
-    public JSONObject convertToJsonSchema(Module module) throws IOException, JSONException {
+    public JSONObject convertToJsonSchema(Module module, SchemaContext schemaContext) throws IOException, JSONException {
         JSONObject models = new JSONObject();
-        processContainers(module, models);
-        processRPCs(module, models);
-    processIdentities(module, models);
+        topLevelModule = module;
+        processContainers(module, models, schemaContext);
+        processRPCs(module, models, schemaContext);
+        processIdentities(module, models);
         return models;
     }
 
-    private void processContainers(Module module, JSONObject models) throws IOException,
+    private void processContainers(Module module, JSONObject models, SchemaContext schemaContext) throws IOException,
             JSONException {
 
         String moduleName = module.getName();
@@ -136,10 +143,10 @@ public class ModelGenerator {
              * For every container in the module
              */
             if (childNode instanceof ContainerSchemaNode) {
-                configModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName,
-                        true, models, true);
-                operationalModuleJSON = processContainer((ContainerSchemaNode) childNode,
-                        moduleName, true, models, false);
+                configModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models, true,
+                        schemaContext);
+                operationalModuleJSON = processContainer((ContainerSchemaNode) childNode, moduleName, true, models,
+                        false, schemaContext);
             }
 
             if (configModuleJSON != null) {
@@ -157,15 +164,15 @@ public class ModelGenerator {
     }
 
     /**
-     * Process the RPCs for a Module Spits out a file each of the name
-     * <rpcName>-input.json and <rpcName>-output.json for each RPC that contains
-     * input & output elements
+     * Process the RPCs for a Module Spits out a file each of the name <rpcName>-input.json and <rpcName>-output.json
+     * for each RPC that contains input & output elements
      *
      * @param module
      * @throws JSONException
      * @throws IOException
      */
-    private void processRPCs(Module module, JSONObject models) throws JSONException, IOException {
+    private void processRPCs(Module module, JSONObject models, SchemaContext schemaContext) throws JSONException,
+            IOException {
 
         Set<RpcDefinition> rpcs = module.getRpcs();
         String moduleName = module.getName();
@@ -173,7 +180,7 @@ public class ModelGenerator {
 
             ContainerSchemaNode input = rpc.getInput();
             if (input != null) {
-                JSONObject inputJSON = processContainer(input, moduleName, true, models);
+                JSONObject inputJSON = processContainer(input, moduleName, true, models, schemaContext);
                 String filename = "(" + rpc.getQName().getLocalName() + ")input";
                 inputJSON.put("id", filename);
                 // writeToFile(filename, inputJSON.toString(2), moduleName);
@@ -182,7 +189,7 @@ public class ModelGenerator {
 
             ContainerSchemaNode output = rpc.getOutput();
             if (output != null) {
-                JSONObject outputJSON = processContainer(output, moduleName, true, models);
+                JSONObject outputJSON = processContainer(output, moduleName, true, models, schemaContext);
                 String filename = "(" + rpc.getQName().getLocalName() + ")output";
                 outputJSON.put("id", filename);
                 models.put(filename, outputJSON);
@@ -190,58 +197,59 @@ public class ModelGenerator {
         }
     }
 
-  /**
-   * Processes the 'identity' statement in a yang model
-   * and maps it to a 'model' in the Swagger JSON spec.
-   *
-   * @param module The module from which the identity stmt will be processed
-   * @param models The JSONObject in which the parsed identity will be put as a 'model' obj
-   * @throws JSONException
-   */
-  private void processIdentities(Module module, JSONObject models) throws JSONException {
-
-    String moduleName = module.getName();
-    Set<IdentitySchemaNode> idNodes =  module.getIdentities();
-    _logger.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
-
-    for(IdentitySchemaNode idNode : idNodes){
-      JSONObject identityObj=new JSONObject();
-      String identityName = idNode.getQName().getLocalName();
-      _logger.debug("Processing Identity: {}", identityName);
-
-      identityObj.put(ID_KEY, identityName);
-      identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
-
-      JSONObject props = new JSONObject();
-      IdentitySchemaNode baseId = idNode.getBaseIdentity();
+    /**
+     * Processes the 'identity' statement in a yang model and maps it to a 'model' in the Swagger JSON spec.
+     *
+     * @param module
+     *            The module from which the identity stmt will be processed
+     * @param models
+     *            The JSONObject in which the parsed identity will be put as a 'model' obj
+     * @throws JSONException
+     */
+    private void processIdentities(Module module, JSONObject models) throws JSONException {
 
+        String moduleName = module.getName();
+        Set<IdentitySchemaNode> idNodes = module.getIdentities();
+        _logger.debug("Processing Identities for module {} . Found {} identity statements", moduleName, idNodes.size());
+
+        for (IdentitySchemaNode idNode : idNodes) {
+            JSONObject identityObj = new JSONObject();
+            String identityName = idNode.getQName().getLocalName();
+            _logger.debug("Processing Identity: {}", identityName);
+
+            identityObj.put(ID_KEY, identityName);
+            identityObj.put(DESCRIPTION_KEY, idNode.getDescription());
+
+            JSONObject props = new JSONObject();
+            IdentitySchemaNode baseId = idNode.getBaseIdentity();
+
+            if (baseId == null) {
+                /**
+                 * This is a base identity. So lets see if it has sub types. If it does, then add them to the model
+                 * definition.
+                 */
+                Set<IdentitySchemaNode> derivedIds = idNode.getDerivedIdentities();
+
+                if (derivedIds != null) {
+                    JSONArray subTypes = new JSONArray();
+                    for (IdentitySchemaNode derivedId : derivedIds) {
+                        subTypes.put(derivedId.getQName().getLocalName());
+                    }
+                    identityObj.put(SUB_TYPES_KEY, subTypes);
+                }
+            } else {
+                /**
+                 * This is a derived entity. Add it's base type & move on.
+                 */
+                props.put(TYPE_KEY, baseId.getQName().getLocalName());
+            }
 
-      if(baseId==null) {
-        /**
-         * This is a base identity. So lets see if
-         * it has sub types. If it does, then add them to the model definition.
-         */
-        Set<IdentitySchemaNode> derivedIds = idNode.getDerivedIdentities();
-
-        if(derivedIds != null) {
-          JSONArray subTypes = new JSONArray();
-          for(IdentitySchemaNode derivedId : derivedIds){
-            subTypes.put(derivedId.getQName().getLocalName());
-          }
-          identityObj.put(SUB_TYPES_KEY, subTypes);
+            // Add the properties. For a base type, this will be an empty object as required by the Swagger spec.
+            identityObj.put(PROPERTIES_KEY, props);
+            models.put(identityName, identityObj);
         }
-      } else {
-        /**
-         * This is a derived entity. Add it's base type & move on.
-         */
-        props.put(TYPE_KEY, baseId.getQName().getLocalName());
-      }
-
-      //Add the properties. For a base type, this will be an empty object as required by the Swagger spec.
-      identityObj.put(PROPERTIES_KEY, props);
-      models.put(identityName, identityObj);
     }
-  }
+
     /**
      * Processes the container node and populates the moduleJSON
      *
@@ -251,14 +259,13 @@ public class ModelGenerator {
      * @throws JSONException
      * @throws IOException
      */
-    private JSONObject processContainer(ContainerSchemaNode container, String moduleName,
-            boolean addSchemaStmt, JSONObject models) throws JSONException, IOException {
-        return processContainer(container, moduleName, addSchemaStmt, models, (Boolean) null);
+    private JSONObject processContainer(ContainerSchemaNode container, String moduleName, boolean addSchemaStmt,
+            JSONObject models, SchemaContext schemaContext) throws JSONException, IOException {
+        return processContainer(container, moduleName, addSchemaStmt, models, (Boolean) null, schemaContext);
     }
 
-    private JSONObject processContainer(ContainerSchemaNode container, String moduleName,
-            boolean addSchemaStmt, JSONObject models, Boolean isConfig) throws JSONException,
-            IOException {
+    private JSONObject processContainer(ContainerSchemaNode container, String moduleName, boolean addSchemaStmt,
+            JSONObject models, Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
         JSONObject moduleJSON = getSchemaTemplate();
         if (addSchemaStmt) {
             moduleJSON = getSchemaTemplate();
@@ -270,57 +277,58 @@ public class ModelGenerator {
         String containerDescription = container.getDescription();
         moduleJSON.put(DESCRIPTION_KEY, containerDescription);
 
-        JSONObject properties = processChildren(container.getChildNodes(), moduleName, models, isConfig);
+        JSONObject properties = processChildren(container.getChildNodes(), container.getQName(), moduleName, models,
+                isConfig, schemaContext);
         moduleJSON.put(PROPERTIES_KEY, properties);
         return moduleJSON;
     }
 
-    private JSONObject processChildren(Iterable<DataSchemaNode> nodes, String moduleName,
-            JSONObject models) throws JSONException, IOException {
-        return processChildren(nodes, moduleName, models, null);
+    private JSONObject processChildren(Iterable<DataSchemaNode> nodes, QName parentQName, String moduleName,
+            JSONObject models, SchemaContext schemaContext) throws JSONException, IOException {
+        return processChildren(nodes, parentQName, moduleName, models, null, schemaContext);
     }
 
     /**
      * Processes the nodes
      *
      * @param nodes
+     * @param parentQName
      * @param moduleName
      * @param isConfig
      * @return
      * @throws JSONException
      * @throws IOException
      */
-    private JSONObject processChildren(Iterable<DataSchemaNode> nodes, String moduleName,
-            JSONObject models, Boolean isConfig) throws JSONException, IOException {
+    private JSONObject processChildren(Iterable<DataSchemaNode> nodes, QName parentQName, String moduleName,
+            JSONObject models, Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
 
         JSONObject properties = new JSONObject();
 
         for (DataSchemaNode node : nodes) {
             if (isConfig == null || node.isConfiguration() == isConfig) {
 
-                String name = node.getQName().getLocalName();
+                String name = resolveNodesName(node, topLevelModule, schemaContext);
                 JSONObject property = null;
                 if (node instanceof LeafSchemaNode) {
                     property = processLeafNode((LeafSchemaNode) node);
                 } else if (node instanceof ListSchemaNode) {
-                    property = processListSchemaNode((ListSchemaNode) node, moduleName, models, isConfig);
+                    property = processListSchemaNode((ListSchemaNode) node, moduleName, models, isConfig, schemaContext);
 
                 } else if (node instanceof LeafListSchemaNode) {
                     property = processLeafListNode((LeafListSchemaNode) node);
 
                 } else if (node instanceof ChoiceNode) {
-                    property = processChoiceNode((ChoiceNode) node, moduleName, models);
+                    property = processChoiceNode((ChoiceNode) node, moduleName, models, schemaContext);
 
                 } else if (node instanceof AnyXmlSchemaNode) {
                     property = processAnyXMLNode((AnyXmlSchemaNode) node);
 
                 } else if (node instanceof ContainerSchemaNode) {
-                    property = processContainer((ContainerSchemaNode) node, moduleName, false,
-                            models, isConfig);
+                    property = processContainer((ContainerSchemaNode) node, moduleName, false, models, isConfig,
+                            schemaContext);
 
                 } else {
-                    throw new IllegalArgumentException("Unknown DataSchemaNode type: "
-                            + node.getClass());
+                    throw new IllegalArgumentException("Unknown DataSchemaNode type: " + node.getClass());
                 }
 
                 property.putOpt(DESCRIPTION_KEY, node.getDescription());
@@ -356,15 +364,16 @@ public class ModelGenerator {
      * @throws JSONException
      * @throws IOException
      */
-    private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models)
-            throws JSONException, IOException {
+    private JSONObject processChoiceNode(ChoiceNode choiceNode, String moduleName, JSONObject models,
+            SchemaContext schemaContext) throws JSONException, IOException {
 
         Set<ChoiceCaseNode> cases = choiceNode.getCases();
 
         JSONArray choiceProps = new JSONArray();
         for (ChoiceCaseNode choiceCase : cases) {
             String choiceName = choiceCase.getQName().getLocalName();
-            JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), moduleName, models);
+            JSONObject choiceProp = processChildren(choiceCase.getChildNodes(), choiceCase.getQName(), moduleName,
+                    models, schemaContext);
             JSONObject choiceObj = new JSONObject();
             choiceObj.put(choiceName, choiceProp);
             choiceObj.put(TYPE_KEY, OBJECT_TYPE);
@@ -384,8 +393,7 @@ public class ModelGenerator {
      * @param props
      * @throws JSONException
      */
-    private void processConstraints(ConstraintDefinition constraints, JSONObject props)
-            throws JSONException {
+    private void processConstraints(ConstraintDefinition constraints, JSONObject props) throws JSONException {
         boolean isMandatory = constraints.isMandatory();
         props.put(REQUIRED_KEY, isMandatory);
 
@@ -402,9 +410,8 @@ public class ModelGenerator {
     /**
      * Parses a ListSchema node.
      *
-     * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in
-     * a separate JSON schema file. Hence, we have to write some properties to a
-     * new file, while continuing to process the rest.
+     * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in a separate JSON schema file. Hence, we
+     * have to write some properties to a new file, while continuing to process the rest.
      *
      * @param listNode
      * @param moduleName
@@ -413,21 +420,21 @@ public class ModelGenerator {
      * @throws JSONException
      * @throws IOException
      */
-    private JSONObject processListSchemaNode(ListSchemaNode listNode, String moduleName,
-            JSONObject models, Boolean isConfig) throws JSONException, IOException {
+    private JSONObject processListSchemaNode(ListSchemaNode listNode, String moduleName, JSONObject models,
+            Boolean isConfig, SchemaContext schemaContext) throws JSONException, IOException {
 
-        String fileName = (BooleanUtils.isNotFalse(isConfig)?OperationBuilder.CONFIG:OperationBuilder.OPERATIONAL) +
-                                                                listNode.getQName().getLocalName();
+        String fileName = (BooleanUtils.isNotFalse(isConfig) ? OperationBuilder.CONFIG : OperationBuilder.OPERATIONAL)
+                + listNode.getQName().getLocalName();
 
-        JSONObject childSchemaProperties = processChildren(listNode.getChildNodes(), moduleName, models);
+        JSONObject childSchemaProperties = processChildren(listNode.getChildNodes(), listNode.getQName(), moduleName,
+                models, schemaContext);
         JSONObject childSchema = getSchemaTemplate();
         childSchema.put(TYPE_KEY, OBJECT_TYPE);
         childSchema.put(PROPERTIES_KEY, childSchemaProperties);
 
         /*
-         * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must
-         * be in a separate JSON schema file. Hence, we have to write some
-         * properties to a new file, while continuing to process the rest.
+         * Due to a limitation of the RAML--->JAX-RS tool, sub-properties must be in a separate JSON schema file. Hence,
+         * we have to write some properties to a new file, while continuing to process the rest.
          */
         // writeToFile(fileName, childSchema.toString(2), moduleName);
         childSchema.put("id", fileName);
@@ -483,8 +490,7 @@ public class ModelGenerator {
      * @param property
      * @throws JSONException
      */
-    private void processTypeDef(TypeDefinition<?> leafTypeDef, JSONObject property)
-            throws JSONException {
+    private void processTypeDef(TypeDefinition<?> leafTypeDef, JSONObject property) throws JSONException {
 
         if (leafTypeDef instanceof ExtendedType) {
             processExtendedType(leafTypeDef, property);
@@ -498,7 +504,7 @@ public class ModelGenerator {
             processUnionType((UnionTypeDefinition) leafTypeDef, property);
 
         } else if (leafTypeDef instanceof IdentityrefTypeDefinition) {
-      property.putOpt(TYPE_KEY, ((IdentityrefTypeDefinition) leafTypeDef).getIdentity().getQName().getLocalName());
+            property.putOpt(TYPE_KEY, ((IdentityrefTypeDefinition) leafTypeDef).getIdentity().getQName().getLocalName());
         } else if (leafTypeDef instanceof BinaryTypeDefinition) {
             processBinaryType((BinaryTypeDefinition) leafTypeDef, property);
         } else {
@@ -517,15 +523,13 @@ public class ModelGenerator {
      * @param property
      * @throws JSONException
      */
-    private void processExtendedType(TypeDefinition<?> leafTypeDef, JSONObject property)
-            throws JSONException {
+    private void processExtendedType(TypeDefinition<?> leafTypeDef, JSONObject property) throws JSONException {
         Object leafBaseType = leafTypeDef.getBaseType();
         if (leafBaseType instanceof ExtendedType) {
             // recursively process an extended type until we hit a base type
             processExtendedType((TypeDefinition<?>) leafBaseType, property);
         } else {
-            List<LengthConstraint> lengthConstraints = ((ExtendedType) leafTypeDef)
-                    .getLengthConstraints();
+            List<LengthConstraint> lengthConstraints = ((ExtendedType) leafTypeDef).getLengthConstraints();
             for (LengthConstraint lengthConstraint : lengthConstraints) {
                 Number min = lengthConstraint.getMin();
                 Number max = lengthConstraint.getMax();
@@ -541,8 +545,7 @@ public class ModelGenerator {
     /*
    *
    */
-    private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property)
-            throws JSONException {
+    private void processBinaryType(BinaryTypeDefinition binaryType, JSONObject property) throws JSONException {
         property.put(TYPE_KEY, STRING);
         JSONObject media = new JSONObject();
         media.put(BINARY_ENCODING_KEY, BASE_64);
@@ -555,8 +558,7 @@ public class ModelGenerator {
      * @param property
      * @throws JSONException
      */
-    private void processEnumType(EnumerationType enumLeafType, JSONObject property)
-            throws JSONException {
+    private void processEnumType(EnumerationType enumLeafType, JSONObject property) throws JSONException {
         List<EnumPair> enumPairs = enumLeafType.getValues();
         List<String> enumNames = new ArrayList<String>();
         for (EnumPair enumPair : enumPairs) {
@@ -571,8 +573,7 @@ public class ModelGenerator {
      * @param property
      * @throws JSONException
      */
-    private void processBitsType(BitsTypeDefinition bitsType, JSONObject property)
-            throws JSONException {
+    private void processBitsType(BitsTypeDefinition bitsType, JSONObject property) throws JSONException {
         property.put(TYPE_KEY, ARRAY_TYPE);
         property.put(MIN_ITEMS, 0);
         property.put(UNIQUE_ITEMS_KEY, true);
@@ -593,18 +594,17 @@ public class ModelGenerator {
      * @param property
      * @throws JSONException
      */
-    private void processUnionType(UnionTypeDefinition unionType, JSONObject property)
-            throws JSONException {
+    private void processUnionType(UnionTypeDefinition unionType, JSONObject property) throws JSONException {
 
         StringBuilder type = new StringBuilder();
-        for (TypeDefinition<?> typeDef : unionType.getTypes() ) {
-            if( type.length() > 0 ){
-                type.append( " or " );
+        for (TypeDefinition<?> typeDef : unionType.getTypes()) {
+            if (type.length() > 0) {
+                type.append(" or ");
             }
             type.append(YANG_TYPE_TO_JSON_TYPE_MAPPING.get(typeDef.getClass()));
         }
 
-        property.put(TYPE_KEY, type );
+        property.put(TYPE_KEY, type);
     }
 
     /**
@@ -619,4 +619,5 @@ public class ModelGenerator {
 
         return schemaJSON;
     }
+
 }
index 29ada12c6f8737a3d61fc5e68abde7cece17fad1..7e8707110fb757e9fae69fb2e02837d34d5b22cf 100644 (file)
@@ -17,9 +17,7 @@ import java.util.Map.Entry;
 import java.util.TreeMap;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
-
 import javax.ws.rs.core.UriInfo;
-
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/util/RestDocgenUtil.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/util/RestDocgenUtil.java
new file mode 100644 (file)
index 0000000..9e1d82a
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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.sal.rest.doc.util;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaNode;
+
+public class RestDocgenUtil {
+
+    private RestDocgenUtil() {
+    }
+
+    private static Map<URI, Map<Date, Module>> namespaceAndRevisionToModule = new HashMap<URI, Map<Date, Module>>();
+
+    /**
+     * Resolve path argument name for {@code node}.
+     *
+     * The name can contain also prefix which consists of module name followed by colon. The module prefix is presented
+     * if namespace of {@code node} and its parent is different. In other cases only name of {@code node} is returned.
+     *
+     * @return name of {@code node}
+     */
+    public static String resolvePathArgumentsName(final SchemaNode node, final SchemaContext schemaContext) {
+        Iterable<QName> schemaPath = node.getPath().getPathTowardsRoot();
+        Iterator<QName> it = schemaPath.iterator();
+        QName nodeQName = it.next();
+
+        QName parentQName = null;
+        if (it.hasNext()) {
+            parentQName = it.next();
+        }
+        if (isEqualNamespaceAndRevision(parentQName, nodeQName)) {
+            return node.getQName().getLocalName();
+        } else {
+            return resolveFullNameFromNode(node, schemaContext);
+        }
+    }
+
+    private synchronized static String resolveFullNameFromNode(final SchemaNode node, final SchemaContext schemaContext) {
+        final URI namespace = node.getQName().getNamespace();
+        final Date revision = node.getQName().getRevision();
+
+        Map<Date, Module> revisionToModule = namespaceAndRevisionToModule.get(namespace);
+        if (revisionToModule == null) {
+            revisionToModule = new HashMap<>();
+            namespaceAndRevisionToModule.put(namespace, revisionToModule);
+        }
+        Module module = revisionToModule.get(revision);
+        if (module == null) {
+            module = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
+            revisionToModule.put(revision, module);
+        }
+        if (module != null) {
+            return module.getName() + ":" + node.getQName().getLocalName();
+        }
+        return node.getQName().getLocalName();
+    }
+
+    public static String resolveNodesName(final SchemaNode node, final Module module, final SchemaContext schemaContext) {
+        if (node.getQName().getNamespace().equals(module.getQNameModule().getNamespace())
+                && node.getQName().getRevision().equals(module.getQNameModule().getRevision())) {
+            return node.getQName().getLocalName();
+        } else {
+            return resolveFullNameFromNode(node, schemaContext);
+        }
+    }
+
+    private static boolean isEqualNamespaceAndRevision(QName parentQName, QName nodeQName) {
+        if (parentQName == null) {
+            if (nodeQName == null) {
+                return true;
+            }
+            return false;
+        }
+        return parentQName.getNamespace().equals(nodeQName.getNamespace())
+                && parentQName.getRevision().equals(nodeQName.getRevision());
+    }
+}
index 07c9378439d2f66551672d8a08ec20785a0a074b..19f82b53867b603af20576759485999ca1fe28c4 100644 (file)
@@ -5,16 +5,17 @@ import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import com.google.common.base.Preconditions;
 import java.io.File;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.TreeSet;
-
 import javax.ws.rs.core.UriInfo;
-
 import junit.framework.Assert;
-
+import org.json.JSONException;
+import org.json.JSONObject;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -25,8 +26,8 @@ import org.opendaylight.controller.sal.rest.doc.swagger.Operation;
 import org.opendaylight.controller.sal.rest.doc.swagger.Resource;
 import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
 import org.opendaylight.yangtools.yang.model.api.Module;
-
-import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
 /**
  *
@@ -36,12 +37,14 @@ public class ApiDocGeneratorTest {
     public static final String HTTP_HOST = "http://host";
     private ApiDocGenerator generator;
     private DocGenTestHelper helper;
+    private SchemaContext schemaContext;
 
     @Before
     public void setUp() throws Exception {
         generator = new ApiDocGenerator();
         helper = new DocGenTestHelper();
         helper.setUp();
+        schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet<Module>(helper.getModules().values()));
     }
 
     @After
@@ -59,8 +62,9 @@ public class ApiDocGeneratorTest {
         for (Entry<File, Module> m : helper.getModules().entrySet()) {
             if (m.getKey().getAbsolutePath().endsWith("toaster_short.yang")) {
                 ApiDeclaration doc = generator.getSwaggerDocSpec(m.getValue(),
-                        "http://localhost:8080/restconf", "");
+                        "http://localhost:8080/restconf", "",schemaContext);
                 validateToaster(doc);
+                validateTosterDocContainsModulePrefixes(doc);
                 Assert.assertNotNull(doc);
             }
         }
@@ -73,7 +77,7 @@ public class ApiDocGeneratorTest {
         for (Entry<File, Module> m : helper.getModules().entrySet()) {
             if (m.getKey().getAbsolutePath().endsWith("toaster.yang")) {
                 ApiDeclaration doc = generator.getSwaggerDocSpec(m.getValue(),
-                        "http://localhost:8080/restconf", "");
+                        "http://localhost:8080/restconf", "",schemaContext);
                 Assert.assertNotNull(doc);
 
                 //testing bugs.opendaylight.org bug 1290. UnionType model type.
@@ -84,11 +88,21 @@ public class ApiDocGeneratorTest {
         }
     }
 
+    /**
+     * Tests whether from yang files are generated all required paths for HTTP operations (GET, DELETE, PUT, POST)
+     *
+     * If container | list is augmented then in path there should be specified module name followed with collon (e. g.
+     * "/config/module1:element1/element2/module2:element3")
+     *
+     * @param doc
+     * @throws Exception
+     */
     private void validateToaster(ApiDeclaration doc) throws Exception {
         Set<String> expectedUrls = new TreeSet<>(Arrays.asList(new String[] {
                 "/config/toaster2:toaster/", "/operational/toaster2:toaster/",
                 "/operations/toaster2:cancel-toast", "/operations/toaster2:make-toast",
-                "/operations/toaster2:restock-toaster" }));
+                "/operations/toaster2:restock-toaster",
+                "/config/toaster2:toaster/toasterSlot/{slotId}/toaster-augmented:slotInfo/" }));
 
         Set<String> actualUrls = new TreeSet<>();
 
@@ -130,7 +144,7 @@ public class ApiDocGeneratorTest {
     @Test
     public void testGetResourceListing() throws Exception {
         UriInfo info = helper.createMockUriInfo(HTTP_HOST);
-        SchemaService mockSchemaService = helper.createMockSchemaService();
+        SchemaService mockSchemaService = helper.createMockSchemaService(schemaContext);
 
         generator.setSchemaService(mockSchemaService);
 
@@ -154,4 +168,30 @@ public class ApiDocGeneratorTest {
         assertEquals(HTTP_HOST + "/toaster2(2009-11-20)", toaster2.getPath());
     }
 
+    private void validateTosterDocContainsModulePrefixes(ApiDeclaration doc) {
+        JSONObject topLevelJson = doc.getModels();
+        try {
+            JSONObject configToaster = topLevelJson.getJSONObject("(config)toaster");
+            assertNotNull("(config)toaster JSON object missing", configToaster);
+            //without module prefix
+            containsProperties(configToaster, "toasterSlot");
+
+            JSONObject toasterSlot = topLevelJson.getJSONObject("(config)toasterSlot");
+            assertNotNull("(config)toasterSlot JSON object missing", toasterSlot);
+            //with module prefix
+            containsProperties(toasterSlot, "toaster-augmented:slotInfo");
+
+        } catch (JSONException e) {
+            fail("Json exception while reading JSON object. Original message "+e.getMessage());
+        }
+    }
+
+    private void containsProperties(final JSONObject jsonObject,final String...properties) throws JSONException {
+        for (String property : properties) {
+            JSONObject propertiesObject = jsonObject.getJSONObject("properties");
+            assertNotNull("Properties object missing in ", propertiesObject);
+            JSONObject concretePropertyObject = propertiesObject.getJSONObject(property);
+            assertNotNull(property + " is missing",concretePropertyObject);
+        }
+    }
 }
index 0f15d00e79f53ecb3815d915b55454274dff7c93..7701d2a735e1af1304139e383b556ee8f8a53492 100644 (file)
@@ -10,6 +10,9 @@ package org.opendaylight.controller.sal.rest.doc.impl;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.net.URI;
@@ -19,23 +22,17 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
-
 import org.mockito.ArgumentCaptor;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import org.opendaylight.yangtools.yang.model.parser.api.YangModelParser;
+import org.opendaylight.yangtools.yang.model.parser.api.YangContextParser;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.datatype.jsonorg.JsonOrgModule;
-
 public class DocGenTestHelper {
 
     private Map<File, Module> modules;
@@ -45,7 +42,7 @@ public class DocGenTestHelper {
             URISyntaxException {
 
         URI resourceDirUri = getClass().getResource(resourceDirectory).toURI();
-        final YangModelParser parser = new YangParserImpl();
+        final YangContextParser parser = new YangParserImpl();
         final File testDir = new File(resourceDirUri);
         final String[] fileList = testDir.list();
         final List<File> testFiles = new ArrayList<>();
@@ -90,6 +87,7 @@ public class DocGenTestHelper {
 
         final ArgumentCaptor<String> moduleCapture = ArgumentCaptor.forClass(String.class);
         final ArgumentCaptor<Date> dateCapture = ArgumentCaptor.forClass(Date.class);
+        final ArgumentCaptor<URI> namespaceCapture = ArgumentCaptor.forClass(URI.class);
         when(mockContext.findModuleByName(moduleCapture.capture(), dateCapture.capture())).then(
                 new Answer<Module>() {
                     @Override
@@ -104,6 +102,20 @@ public class DocGenTestHelper {
                         return null;
                     }
                 });
+        when(mockContext.findModuleByNamespaceAndRevision(namespaceCapture.capture(), dateCapture.capture())).then(
+                new Answer<Module>() {
+                    @Override
+                    public Module answer(InvocationOnMock invocation) throws Throwable {
+                        URI namespace = namespaceCapture.getValue();
+                        Date date = dateCapture.getValue();
+                        for (Module m : modules.values()) {
+                            if (m.getNamespace().equals(namespace) && m.getRevision().equals(date)) {
+                                return m;
+                            }
+                        }
+                        return null;
+                    }
+                });
         return mockContext;
     }
 
index bba8ed9ca6fcf557bb972af2d3c55c68bf1f3f13..940b99fd997fe919cf889c8f4902a5c748592636 100644 (file)
@@ -14,12 +14,11 @@ import static org.mockito.Mockito.when;
 
 import java.net.URISyntaxException;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.TreeSet;
-
 import javax.ws.rs.core.UriInfo;
-
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
@@ -33,7 +32,9 @@ import org.opendaylight.controller.sal.rest.doc.swagger.Resource;
 import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 
 public class MountPointSwaggerTest {
 
@@ -44,12 +45,14 @@ public class MountPointSwaggerTest {
     private static final String INSTANCE_URL = "nodes/node/123/";
     private MountPointSwagger swagger;
     private DocGenTestHelper helper;
+    private SchemaContext schemaContext;
 
     @Before
     public void setUp() throws Exception {
         swagger = new MountPointSwagger();
         helper = new DocGenTestHelper();
         helper.setUp();
+        schemaContext = new YangParserImpl().resolveSchemaContext(new HashSet<Module>(helper.getModules().values()));
     }
 
     @Test()
diff --git a/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_augmented.yang b/opendaylight/md-sal/sal-rest-docgen/src/test/resources/yang/toaster_augmented.yang
new file mode 100644 (file)
index 0000000..4db7897
--- /dev/null
@@ -0,0 +1,21 @@
+module toaster-augmented {
+
+    yang-version 1;
+
+    namespace
+      "http://netconfcentral.org/ns/toaster/augmented";
+
+    prefix toast;
+    import toaster2 {prefix tst; revision-date 2009-11-20;}
+
+    revision "2014-7-14" {
+    }
+
+    augment "/tst:toaster/tst:toasterSlot" {
+        container slotInfo {
+            leaf numberOfToastPrepared {
+                type uint32;
+            }
+        }
+    }
+}
\ No newline at end of file
index a1d5ab0a129fa92d362b4faa7d1e416fd367b7ab..6884076d5daafa1a8ced3753d1460754b950e1a1 100644 (file)
                 Microsoft Toaster.";
       }
 
+      list toasterSlot {
+        key "slotId";
+        leaf slotId {
+            type string;
+        }
+      }
+
       leaf toasterModelNumber {
         type DisplayString;
         config false;
index 45070ca8b01e64331381f67f28b367e2f80bc483..2723a3c205b6b02da2c2e6a4a460a046fda51929 100644 (file)
@@ -16,6 +16,11 @@ import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
 import org.opendaylight.controller.networkconfig.neutron.INeutronRouterCRUD;
@@ -74,7 +79,12 @@ public class Activator extends ComponentActivatorAbstractBase {
                 NeutronSecurityRuleInterface.class,
                 NeutronFirewallInterface.class,
                 NeutronFirewallPolicyInterface.class,
-                NeutronFirewallRuleInterface.class};
+                NeutronFirewallRuleInterface.class,
+                NeutronLoadBalancerInterface.class,
+                NeutronLoadBalancerPoolInterface.class,
+                NeutronLoadBalancerListenerInterface.class,
+                NeutronLoadBalancerHealthMonitorInterface.class,
+                NeutronLoadBalancerPoolMemberInterface.class};
         return res;
     }
 
@@ -253,5 +263,85 @@ public class Activator extends ComponentActivatorAbstractBase {
                     "setConfigurationContainerService",
                     "unsetConfigurationContainerService").setRequired(true));
         }
+        if (imp.equals(NeutronLoadBalancerInterface.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { INeutronLoadBalancerCRUD.class.getName(),
+                            IConfigurationContainerAware.class.getName()}, null);
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "neutron");
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService",
+                            "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IConfigurationContainerService.class).setCallbacks(
+                    "setConfigurationContainerService",
+                    "unsetConfigurationContainerService").setRequired(true));
+        }
+        if (imp.equals(NeutronLoadBalancerListenerInterface.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { INeutronLoadBalancerListenerCRUD.class.getName(),
+                            IConfigurationContainerAware.class.getName()}, null);
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "neutron");
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService",
+                            "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IConfigurationContainerService.class).setCallbacks(
+                    "setConfigurationContainerService",
+                    "unsetConfigurationContainerService").setRequired(true));
+        }
+        if (imp.equals(NeutronLoadBalancerPoolInterface.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { INeutronLoadBalancerPoolCRUD.class.getName(),
+                            IConfigurationContainerAware.class.getName()}, null);
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "neutron");
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService",
+                            "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IConfigurationContainerService.class).setCallbacks(
+                    "setConfigurationContainerService",
+                    "unsetConfigurationContainerService").setRequired(true));
+        }
+        if (imp.equals(NeutronLoadBalancerHealthMonitorInterface.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { INeutronLoadBalancerHealthMonitorCRUD.class.getName(),
+                            IConfigurationContainerAware.class.getName()}, null);
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "neutron");
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService",
+                            "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IConfigurationContainerService.class).setCallbacks(
+                    "setConfigurationContainerService",
+                    "unsetConfigurationContainerService").setRequired(true));
+        }
+        if (imp.equals(NeutronLoadBalancerPoolMemberInterface.class)) {
+            // export the service
+            c.setInterface(
+                    new String[] { INeutronLoadBalancerPoolMemberCRUD.class.getName(),
+                            IConfigurationContainerAware.class.getName()}, null);
+            Dictionary<String, String> props = new Hashtable<String, String>();
+            props.put("salListenerName", "neutron");
+            c.add(createContainerServiceDependency(containerName)
+                    .setService(IClusterContainerServices.class)
+                    .setCallbacks("setClusterContainerService",
+                            "unsetClusterContainerService").setRequired(true));
+            c.add(createContainerServiceDependency(containerName).setService(
+                    IConfigurationContainerService.class).setCallbacks(
+                    "setConfigurationContainerService",
+                    "unsetConfigurationContainerService").setRequired(true));
+        }
     }
 }
diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerHealthMonitorInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerHealthMonitorInterface.java
new file mode 100644 (file)
index 0000000..b0beddf
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class NeutronLoadBalancerHealthMonitorInterface implements INeutronLoadBalancerHealthMonitorCRUD, IConfigurationContainerAware,
+        IObjectReader {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancerHealthMonitorInterface.class);
+    private static final String FILE_NAME = "neutron.loadBalancerHealthMonitor.conf";
+    private String containerName = null;
+
+    private IClusterContainerServices clusterContainerService = null;
+    private IConfigurationContainerService configurationService;
+    private ConcurrentMap<String, NeutronLoadBalancerHealthMonitor> loadBalancerHealthMonitorDB;
+
+    // methods needed for creating caches
+    void setClusterContainerService(IClusterContainerServices s) {
+        logger.debug("Cluster Service set");
+        clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (clusterContainerService == s) {
+            logger.debug("Cluster Service removed!");
+            clusterContainerService = null;
+        }
+    }
+
+    public void setConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service set: {}", service);
+        configurationService = service;
+    }
+
+    public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service removed: {}", service);
+        configurationService = null;
+    }
+
+    private void allocateCache() {
+        if (this.clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        logger.debug("Creating Cache for Neutron LoadBalancerHealthMonitor");
+        try {
+            // neutron caches
+            this.clusterContainerService.createCache("neutronLoadBalancerHealthMonitors",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException cce) {
+            logger.error("Cache couldn't be created for Neutron LoadBalancerHealthMonitor -  check cache mode");
+        } catch (CacheExistException cce) {
+            logger.error("Cache for Neutron LoadBalancerHealthMonitor already exists, destroy and recreate");
+        }
+        logger.debug("Cache successfully created for Neutron LoadBalancerHealthMonitor");
+    }
+
+    @SuppressWarnings ({"unchecked"})
+    private void retrieveCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't retrieve cache");
+            return;
+        }
+
+        logger.debug("Retrieving cache for Neutron LoadBalancerHealthMonitor");
+        loadBalancerHealthMonitorDB = (ConcurrentMap<String, NeutronLoadBalancerHealthMonitor>) clusterContainerService
+                .getCache("neutronLoadBalancerHealthMonitors");
+        if (loadBalancerHealthMonitorDB == null) {
+            logger.error("Cache couldn't be retrieved for Neutron LoadBalancerHealthMonitor");
+        }
+        logger.debug("Cache was successfully retrieved for Neutron LoadBalancerHealthMonitor");
+    }
+
+    private void destroyCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterMger, can't destroy cache");
+            return;
+        }
+        logger.debug("Destroying Cache for LoadBalancerHealthMonitor");
+        clusterContainerService.destroyCache("neutronLoadBalancerHealthMonitors");
+    }
+
+    private void startUp() {
+        allocateCache();
+        retrieveCache();
+        loadConfiguration();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            logger.debug("Running containerName: {}", this.containerName);
+        } else {
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     */
+    void destroy() {
+        destroyCache();
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     */
+    void stop() {
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    private boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for (Method toMethod : methods) {
+            if (toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")) {
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[]) null);
+                    if (value != null) {
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorExists(String uuid) {
+        return loadBalancerHealthMonitorDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(String uuid) {
+        if (!neutronLoadBalancerHealthMonitorExists(uuid)) {
+            logger.debug("No LoadBalancerHealthMonitor has Been Defined");
+            return null;
+        }
+        return loadBalancerHealthMonitorDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors() {
+        Set<NeutronLoadBalancerHealthMonitor> allLoadBalancerHealthMonitors = new HashSet<NeutronLoadBalancerHealthMonitor>();
+        for (Entry<String, NeutronLoadBalancerHealthMonitor> entry : loadBalancerHealthMonitorDB.entrySet()) {
+            NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor = entry.getValue();
+            allLoadBalancerHealthMonitors.add(loadBalancerHealthMonitor);
+        }
+        logger.debug("Exiting getLoadBalancerHealthMonitors, Found {} OpenStackLoadBalancerHealthMonitor", allLoadBalancerHealthMonitors.size());
+        List<NeutronLoadBalancerHealthMonitor> ans = new ArrayList<NeutronLoadBalancerHealthMonitor>();
+        ans.addAll(allLoadBalancerHealthMonitors);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor input) {
+        if (neutronLoadBalancerHealthMonitorExists(input.getLoadBalancerHealthMonitorID())) {
+            return false;
+        }
+        loadBalancerHealthMonitorDB.putIfAbsent(input.getLoadBalancerHealthMonitorID(), input);
+        //TODO: add code to find INeutronLoadBalancerHealthMonitorAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerHealthMonitor(String uuid) {
+        if (!neutronLoadBalancerHealthMonitorExists(uuid)) {
+            return false;
+        }
+        loadBalancerHealthMonitorDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerHealthMonitorAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerHealthMonitor(String uuid, NeutronLoadBalancerHealthMonitor delta) {
+        if (!neutronLoadBalancerHealthMonitorExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerHealthMonitor target = loadBalancerHealthMonitorDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerHealthMonitorInUse(String loadBalancerHealthMonitorUUID) {
+        return !neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorUUID);
+    }
+
+    private void loadConfiguration() {
+        for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+            NeutronLoadBalancerHealthMonitor nn = (NeutronLoadBalancerHealthMonitor) conf;
+            loadBalancerHealthMonitorDB.put(nn.getLoadBalancerHealthMonitorID(), nn);
+        }
+    }
+
+    @Override
+    public Status saveConfiguration() {
+        return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(loadBalancerHealthMonitorDB.values()),
+                FILE_NAME);
+    }
+
+    @Override
+    public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+        return ois.readObject();
+    }
+}
diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerInterface.java
new file mode 100644 (file)
index 0000000..aa7280b
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class NeutronLoadBalancerInterface implements INeutronLoadBalancerCRUD, IConfigurationContainerAware,
+        IObjectReader {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancerInterface.class);
+    private static final String FILE_NAME = "neutron.loadBalancer.conf";
+    private String containerName = null;
+
+    private IClusterContainerServices clusterContainerService = null;
+    private IConfigurationContainerService configurationService;
+    private ConcurrentMap<String, NeutronLoadBalancer> loadBalancerDB;
+
+    // methods needed for creating caches
+    void setClusterContainerService(IClusterContainerServices s) {
+        logger.debug("Cluster Service set");
+        clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (clusterContainerService == s) {
+            logger.debug("Cluster Service removed!");
+            clusterContainerService = null;
+        }
+    }
+
+    public void setConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service set: {}", service);
+        configurationService = service;
+    }
+
+    public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service removed: {}", service);
+        configurationService = null;
+    }
+
+    private void allocateCache() {
+        if (this.clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        logger.debug("Creating Cache for Neutron LoadBalancer");
+        try {
+            // neutron caches
+            this.clusterContainerService.createCache("neutronLoadBalancers",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException cce) {
+            logger.error("Cache couldn't be created for Neutron LoadBalancer -  check cache mode");
+        } catch (CacheExistException cce) {
+            logger.error("Cache for Neutron LoadBalancer already exists, destroy and recreate");
+        }
+        logger.debug("Cache successfully created for Neutron LoadBalancer");
+    }
+
+    @SuppressWarnings ({"unchecked"})
+    private void retrieveCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't retrieve cache");
+            return;
+        }
+
+        logger.debug("Retrieving cache for Neutron LoadBalancer");
+        loadBalancerDB = (ConcurrentMap<String, NeutronLoadBalancer>) clusterContainerService
+                .getCache("neutronLoadBalancers");
+        if (loadBalancerDB == null) {
+            logger.error("Cache couldn't be retrieved for Neutron LoadBalancer");
+        }
+        logger.debug("Cache was successfully retrieved for Neutron LoadBalancer");
+    }
+
+    private void destroyCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterMger, can't destroy cache");
+            return;
+        }
+        logger.debug("Destroying Cache for LoadBalancer");
+        clusterContainerService.destroyCache("neutronLoadBalancers");
+    }
+
+    private void startUp() {
+        allocateCache();
+        retrieveCache();
+        loadConfiguration();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            logger.debug("Running containerName: {}", this.containerName);
+        } else {
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     */
+    void destroy() {
+        destroyCache();
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     */
+    void stop() {
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    private boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for (Method toMethod : methods) {
+            if (toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")) {
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[]) null);
+                    if (value != null) {
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerExists(String uuid) {
+        return loadBalancerDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancer getNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            logger.debug("No LoadBalancer Have Been Defined");
+            return null;
+        }
+        return loadBalancerDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancer> getAllNeutronLoadBalancers() {
+        Set<NeutronLoadBalancer> allLoadBalancers = new HashSet<NeutronLoadBalancer>();
+        for (Entry<String, NeutronLoadBalancer> entry : loadBalancerDB.entrySet()) {
+            NeutronLoadBalancer loadBalancer = entry.getValue();
+            allLoadBalancers.add(loadBalancer);
+        }
+        logger.debug("Exiting getLoadBalancers, Found {} OpenStackLoadBalancer", allLoadBalancers.size());
+        List<NeutronLoadBalancer> ans = new ArrayList<NeutronLoadBalancer>();
+        ans.addAll(allLoadBalancers);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancer(NeutronLoadBalancer input) {
+        if (neutronLoadBalancerExists(input.getLoadBalancerID())) {
+            return false;
+        }
+        loadBalancerDB.putIfAbsent(input.getLoadBalancerID(), input);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancer(String uuid) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        loadBalancerDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta) {
+        if (!neutronLoadBalancerExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancer target = loadBalancerDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerInUse(String loadBalancerUUID) {
+        return !neutronLoadBalancerExists(loadBalancerUUID);
+    }
+
+    private void loadConfiguration() {
+        for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+            NeutronLoadBalancer nn = (NeutronLoadBalancer) conf;
+            loadBalancerDB.put(nn.getLoadBalancerID(), nn);
+        }
+    }
+
+    @Override
+    public Status saveConfiguration() {
+        return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(loadBalancerDB.values()),
+                FILE_NAME);
+    }
+
+    @Override
+    public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+        return ois.readObject();
+    }
+}
diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerListenerInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerListenerInterface.java
new file mode 100644 (file)
index 0000000..3779863
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerListener;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class NeutronLoadBalancerListenerInterface implements INeutronLoadBalancerListenerCRUD, IConfigurationContainerAware,
+        IObjectReader {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancerListenerInterface.class);
+    private static final String FILE_NAME = "neutron.loadBalancerListener.conf";
+    private String containerName = null;
+
+    private IClusterContainerServices clusterContainerService = null;
+    private IConfigurationContainerService configurationService;
+    private ConcurrentMap<String, NeutronLoadBalancerListener> loadBalancerListenerDB;
+
+    // methods needed for creating caches
+    void setClusterContainerService(IClusterContainerServices s) {
+        logger.debug("Cluster Service set");
+        clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (clusterContainerService == s) {
+            logger.debug("Cluster Service removed!");
+            clusterContainerService = null;
+        }
+    }
+
+    public void setConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service set: {}", service);
+        configurationService = service;
+    }
+
+    public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service removed: {}", service);
+        configurationService = null;
+    }
+
+    private void allocateCache() {
+        if (this.clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        logger.debug("Creating Cache for Neutron LoadBalancerListener");
+        try {
+            // neutron caches
+            this.clusterContainerService.createCache("neutronLoadBalancerListeners",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException cce) {
+            logger.error("Cache couldn't be created for Neutron LoadBalancerListener -  check cache mode");
+        } catch (CacheExistException cce) {
+            logger.error("Cache for Neutron LoadBalancerListener already exists, destroy and recreate");
+        }
+        logger.debug("Cache successfully created for Neutron LoadBalancerListener");
+    }
+
+    @SuppressWarnings ({"unchecked"})
+    private void retrieveCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't retrieve cache");
+            return;
+        }
+
+        logger.debug("Retrieving cache for Neutron LoadBalancerListener");
+        loadBalancerListenerDB = (ConcurrentMap<String, NeutronLoadBalancerListener>) clusterContainerService
+                .getCache("neutronLoadBalancerListeners");
+        if (loadBalancerListenerDB == null) {
+            logger.error("Cache couldn't be retrieved for Neutron LoadBalancerListener");
+        }
+        logger.debug("Cache was successfully retrieved for Neutron LoadBalancerListener");
+    }
+
+    private void destroyCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterMger, can't destroy cache");
+            return;
+        }
+        logger.debug("Destroying Cache for LoadBalancerListener");
+        clusterContainerService.destroyCache("neutronLoadBalancerListeners");
+    }
+
+    private void startUp() {
+        allocateCache();
+        retrieveCache();
+        loadConfiguration();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            logger.debug("Running containerName: {}", this.containerName);
+        } else {
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     */
+    void destroy() {
+        destroyCache();
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     */
+    void stop() {
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    private boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for (Method toMethod : methods) {
+            if (toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")) {
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[]) null);
+                    if (value != null) {
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerExists(String uuid) {
+        return loadBalancerListenerDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerListener getNeutronLoadBalancerListener(String uuid) {
+        if (!neutronLoadBalancerListenerExists(uuid)) {
+            logger.debug("No LoadBalancerListener Have Been Defined");
+            return null;
+        }
+        return loadBalancerListenerDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners() {
+        Set<NeutronLoadBalancerListener> allLoadBalancerListeners = new HashSet<NeutronLoadBalancerListener>();
+        for (Entry<String, NeutronLoadBalancerListener> entry : loadBalancerListenerDB.entrySet()) {
+            NeutronLoadBalancerListener loadBalancerListener = entry.getValue();
+            allLoadBalancerListeners.add(loadBalancerListener);
+        }
+        logger.debug("Exiting getLoadBalancerListeners, Found {} OpenStackLoadBalancerListener", allLoadBalancerListeners.size());
+        List<NeutronLoadBalancerListener> ans = new ArrayList<NeutronLoadBalancerListener>();
+        ans.addAll(allLoadBalancerListeners);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerListener(NeutronLoadBalancerListener input) {
+        if (neutronLoadBalancerListenerExists(input.getLoadBalancerListenerID())) {
+            return false;
+        }
+        loadBalancerListenerDB.putIfAbsent(input.getLoadBalancerListenerID(), input);
+        //TODO: add code to find INeutronLoadBalancerListenerAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerListener(String uuid) {
+        if (!neutronLoadBalancerListenerExists(uuid)) {
+            return false;
+        }
+        loadBalancerListenerDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerListenerAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerListener(String uuid, NeutronLoadBalancerListener delta) {
+        if (!neutronLoadBalancerListenerExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerListener target = loadBalancerListenerDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerListenerInUse(String loadBalancerListenerUUID) {
+        return !neutronLoadBalancerListenerExists(loadBalancerListenerUUID);
+    }
+
+    private void loadConfiguration() {
+        for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+            NeutronLoadBalancerListener nn = (NeutronLoadBalancerListener) conf;
+            loadBalancerListenerDB.put(nn.getLoadBalancerListenerID(), nn);
+        }
+    }
+
+    @Override
+    public Status saveConfiguration() {
+        return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(loadBalancerListenerDB.values()),
+                FILE_NAME);
+    }
+
+    @Override
+    public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+        return ois.readObject();
+    }
+}
diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolInterface.java
new file mode 100644 (file)
index 0000000..34cdba3
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class NeutronLoadBalancerPoolInterface implements INeutronLoadBalancerPoolCRUD, IConfigurationContainerAware,
+        IObjectReader {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancerPoolInterface.class);
+    private static final String FILE_NAME = "neutron.loadBalancerPool.conf";
+    private String containerName = null;
+
+    private IClusterContainerServices clusterContainerService = null;
+    private IConfigurationContainerService configurationService;
+    private ConcurrentMap<String, NeutronLoadBalancerPool> loadBalancerPoolDB;
+
+    // methods needed for creating caches
+    void setClusterContainerService(IClusterContainerServices s) {
+        logger.debug("Cluster Service set");
+        clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (clusterContainerService == s) {
+            logger.debug("Cluster Service removed!");
+            clusterContainerService = null;
+        }
+    }
+
+    public void setConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service set: {}", service);
+        configurationService = service;
+    }
+
+    public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service removed: {}", service);
+        configurationService = null;
+    }
+
+    private void allocateCache() {
+        if (this.clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        logger.debug("Creating Cache for Neutron LoadBalancerPool");
+        try {
+            // neutron caches
+            this.clusterContainerService.createCache("neutronLoadBalancerPools",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch (CacheConfigException cce) {
+            logger.error("Cache couldn't be created for Neutron LoadBalancerPool -  check cache mode");
+        } catch (CacheExistException cce) {
+            logger.error("Cache for Neutron LoadBalancerPool already exists, destroy and recreate");
+        }
+        logger.debug("Cache successfully created for Neutron LoadBalancerPool");
+    }
+
+    @SuppressWarnings ({"unchecked"})
+    private void retrieveCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't retrieve cache");
+            return;
+        }
+
+        logger.debug("Retrieving cache for Neutron LoadBalancerPool");
+        loadBalancerPoolDB = (ConcurrentMap<String, NeutronLoadBalancerPool>) clusterContainerService
+                .getCache("neutronLoadBalancerPools");
+        if (loadBalancerPoolDB == null) {
+            logger.error("Cache couldn't be retrieved for Neutron LoadBalancerPool");
+        }
+        logger.debug("Cache was successfully retrieved for Neutron LoadBalancerPool");
+    }
+
+    private void destroyCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterMger, can't destroy cache");
+            return;
+        }
+        logger.debug("Destroying Cache for LoadBalancerPool");
+        clusterContainerService.destroyCache("neutronLoadBalancerPools");
+    }
+
+    private void startUp() {
+        allocateCache();
+        retrieveCache();
+        loadConfiguration();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            logger.debug("Running containerName: {}", this.containerName);
+        } else {
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     */
+    void destroy() {
+        destroyCache();
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     */
+    void stop() {
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    private boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for (Method toMethod : methods) {
+            if (toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")) {
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[]) null);
+                    if (value != null) {
+                        toMethod.invoke(target, value);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolExists(String uuid) {
+        return loadBalancerPoolDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            logger.debug("No LoadBalancerPool has Been Defined");
+            return null;
+        }
+        return loadBalancerPoolDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools() {
+        Set<NeutronLoadBalancerPool> allLoadBalancerPools = new HashSet<NeutronLoadBalancerPool>();
+        for (Entry<String, NeutronLoadBalancerPool> entry : loadBalancerPoolDB.entrySet()) {
+            NeutronLoadBalancerPool loadBalancerPool = entry.getValue();
+            allLoadBalancerPools.add(loadBalancerPool);
+        }
+        logger.debug("Exiting getLoadBalancerPools, Found {} OpenStackLoadBalancerPool", allLoadBalancerPools.size());
+        List<NeutronLoadBalancerPool> ans = new ArrayList<NeutronLoadBalancerPool>();
+        ans.addAll(allLoadBalancerPools);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input) {
+        if (neutronLoadBalancerPoolExists(input.getLoadBalancerPoolID())) {
+            return false;
+        }
+        loadBalancerPoolDB.putIfAbsent(input.getLoadBalancerPoolID(), input);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkCreated on them
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPool(String uuid) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        loadBalancerPoolDB.remove(uuid);
+        //TODO: add code to find INeutronLoadBalancerPoolAware services and call newtorkDeleted on them
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta) {
+        if (!neutronLoadBalancerPoolExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerPool target = loadBalancerPoolDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolInUse(String loadBalancerPoolUUID) {
+        return !neutronLoadBalancerPoolExists(loadBalancerPoolUUID);
+    }
+
+    private void loadConfiguration() {
+        for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+            NeutronLoadBalancerPool nn = (NeutronLoadBalancerPool) conf;
+            loadBalancerPoolDB.put(nn.getLoadBalancerPoolID(), nn);
+        }
+    }
+
+    @Override
+    public Status saveConfiguration() {
+        return configurationService.persistConfiguration(new ArrayList<ConfigurationObject>(loadBalancerPoolDB.values()),
+                FILE_NAME);
+    }
+
+    @Override
+    public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+        return ois.readObject();
+    }
+}
diff --git a/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolMemberInterface.java b/opendaylight/networkconfiguration/neutron/implementation/src/main/java/org/opendaylight/controller/networkconfig/neutron/implementation/NeutronLoadBalancerPoolMemberInterface.java
new file mode 100644 (file)
index 0000000..7418bb2
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.implementation;
+
+import org.apache.felix.dm.Component;
+import org.opendaylight.controller.clustering.services.CacheConfigException;
+import org.opendaylight.controller.clustering.services.CacheExistException;
+import org.opendaylight.controller.clustering.services.IClusterContainerServices;
+import org.opendaylight.controller.clustering.services.IClusterServices;
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.opendaylight.controller.configuration.IConfigurationContainerAware;
+import org.opendaylight.controller.configuration.IConfigurationContainerService;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+import org.opendaylight.controller.sal.utils.IObjectReader;
+import org.opendaylight.controller.sal.utils.Status;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+public class NeutronLoadBalancerPoolMemberInterface
+        implements INeutronLoadBalancerPoolMemberCRUD, IConfigurationContainerAware,
+        IObjectReader {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancerPoolMemberInterface.class);
+    private static final String FILE_NAME = "neutron.loadBalancerPoolMember.conf";
+    private String containerName = null;
+
+    private IClusterContainerServices clusterContainerService = null;
+    private IConfigurationContainerService configurationService;
+    private ConcurrentMap<String, NeutronLoadBalancerPoolMember> loadBalancerPoolMemberDB;
+
+    // methods needed for creating caches
+    void setClusterContainerService(IClusterContainerServices s) {
+        logger.debug("Cluster Service set");
+        clusterContainerService = s;
+    }
+
+    void unsetClusterContainerService(IClusterContainerServices s) {
+        if (clusterContainerService == s) {
+            logger.debug("Cluster Service removed!");
+            clusterContainerService = null;
+        }
+    }
+
+    public void setConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service set: {}", service);
+        configurationService = service;
+    }
+
+    public void unsetConfigurationContainerService(IConfigurationContainerService service) {
+        logger.trace("Configuration service removed: {}", service);
+        configurationService = null;
+    }
+
+    private void allocateCache() {
+        if (this.clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't create cache");
+            return;
+        }
+        logger.debug("Creating Cache for Neutron LoadBalancerPoolMember");
+        try {
+            // neutron caches
+            this.clusterContainerService.createCache("neutronLoadBalancerPoolMembers",
+                    EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL));
+        } catch(CacheConfigException cce) {
+            logger.error("Cache couldn't be created for Neutron LoadBalancerPoolMember -  check cache mode");
+        } catch(CacheExistException cce) {
+            logger.error("Cache for Neutron LoadBalancerPoolMember already exists, destroy and recreate");
+        }
+        logger.debug("Cache successfully created for Neutron LoadBalancerPoolMember");
+    }
+
+    @SuppressWarnings({"unchecked"})
+    private void retrieveCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterContainerService, can't retrieve cache");
+            return;
+        }
+
+        logger.debug("Retrieving cache for Neutron LoadBalancerPoolMember");
+        loadBalancerPoolMemberDB = (ConcurrentMap<String, NeutronLoadBalancerPoolMember>) clusterContainerService
+                .getCache("neutronLoadBalancerPoolMembers");
+        if (loadBalancerPoolMemberDB == null) {
+            logger.error("Cache couldn't be retrieved for Neutron LoadBalancerPoolMember");
+        }
+        logger.debug("Cache was successfully retrieved for Neutron LoadBalancerPoolMember");
+    }
+
+    private void destroyCache() {
+        if (clusterContainerService == null) {
+            logger.error("un-initialized clusterMger, can't destroy cache");
+            return;
+        }
+        logger.debug("Destroying Cache for HostTracker");
+        clusterContainerService.destroyCache("neutronLoadBalancerPoolMembers");
+    }
+
+    private void startUp() {
+        allocateCache();
+        retrieveCache();
+        loadConfiguration();
+    }
+
+    /**
+     * Function called by the dependency manager when all the required
+     * dependencies are satisfied
+     */
+    void init(Component c) {
+        Dictionary<?, ?> props = c.getServiceProperties();
+        if (props != null) {
+            this.containerName = (String) props.get("containerName");
+            logger.debug("Running containerName: {}", this.containerName);
+        } else {
+            // In the Global instance case the containerName is empty
+            this.containerName = "";
+        }
+        startUp();
+    }
+
+    /**
+     * Function called by the dependency manager when at least one dependency
+     * become unsatisfied or when the component is shutting down because for
+     * example bundle is being stopped.
+     */
+    void destroy() {
+        destroyCache();
+    }
+
+    /**
+     * Function called by dependency manager after "init ()" is called and after
+     * the services provided by the class are registered in the service registry
+     */
+    void start() {
+    }
+
+    /**
+     * Function called by the dependency manager before the services exported by
+     * the component are unregistered, this will be followed by a "destroy ()"
+     * calls
+     */
+    void stop() {
+    }
+
+    // this method uses reflection to update an object from it's delta.
+
+    private boolean overwrite(Object target, Object delta) {
+        Method[] methods = target.getClass().getMethods();
+
+        for (Method toMethod : methods) {
+            if (toMethod.getDeclaringClass().equals(target.getClass())
+                    && toMethod.getName().startsWith("set")) {
+
+                String toName = toMethod.getName();
+                String fromName = toName.replace("set", "get");
+
+                try {
+                    Method fromMethod = delta.getClass().getMethod(fromName);
+                    Object value = fromMethod.invoke(delta, (Object[]) null);
+                    if (value != null) {
+                        toMethod.invoke(target, value);
+                    }
+                } catch(Exception e) {
+                    e.printStackTrace();
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberExists(String uuid) {
+        return loadBalancerPoolMemberDB.containsKey(uuid);
+    }
+
+    @Override
+    public NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(String uuid) {
+        if (!neutronLoadBalancerPoolMemberExists(uuid)) {
+            logger.debug("No LoadBalancerPoolMember Have Been Defined");
+            return null;
+        }
+        return loadBalancerPoolMemberDB.get(uuid);
+    }
+
+    @Override
+    public List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers() {
+        Set<NeutronLoadBalancerPoolMember> allLoadBalancerPoolMembers = new HashSet<NeutronLoadBalancerPoolMember>();
+        for (Map.Entry<String, NeutronLoadBalancerPoolMember> entry : loadBalancerPoolMemberDB.entrySet()) {
+            NeutronLoadBalancerPoolMember loadBalancerPoolMember = entry.getValue();
+            allLoadBalancerPoolMembers.add(loadBalancerPoolMember);
+        }
+        logger.debug("Exiting getLoadBalancerPoolMembers, Found {} OpenStackLoadBalancerPoolMember",
+                allLoadBalancerPoolMembers.size());
+        List<NeutronLoadBalancerPoolMember> ans = new ArrayList<NeutronLoadBalancerPoolMember>();
+        ans.addAll(allLoadBalancerPoolMembers);
+        return ans;
+    }
+
+    @Override
+    public boolean addNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember input) {
+        if (neutronLoadBalancerPoolMemberExists(input.getPoolMemberID())) {
+            return false;
+        }
+        loadBalancerPoolMemberDB.putIfAbsent(input.getPoolMemberID(), input);
+        return true;
+    }
+
+    @Override
+    public boolean removeNeutronLoadBalancerPoolMember(String uuid) {
+        if (!neutronLoadBalancerPoolMemberExists(uuid)) {
+            return false;
+        }
+        loadBalancerPoolMemberDB.remove(uuid);
+        return true;
+    }
+
+    @Override
+    public boolean updateNeutronLoadBalancerPoolMember(String uuid, NeutronLoadBalancerPoolMember delta) {
+        if (!neutronLoadBalancerPoolMemberExists(uuid)) {
+            return false;
+        }
+        NeutronLoadBalancerPoolMember target = loadBalancerPoolMemberDB.get(uuid);
+        return overwrite(target, delta);
+    }
+
+    @Override
+    public boolean neutronLoadBalancerPoolMemberInUse(String loadBalancerPoolMemberID) {
+        return !neutronLoadBalancerPoolMemberExists(loadBalancerPoolMemberID);
+    }
+
+    private void loadConfiguration() {
+        for (ConfigurationObject conf : configurationService.retrieveConfiguration(this, FILE_NAME)) {
+            NeutronLoadBalancerPoolMember nn = (NeutronLoadBalancerPoolMember) conf;
+            loadBalancerPoolMemberDB.put(nn.getPoolMemberID(), nn);
+        }
+    }
+
+    @Override
+    public Status saveConfiguration() {
+        return configurationService.persistConfiguration(
+                new ArrayList<ConfigurationObject>(loadBalancerPoolMemberDB.values()),
+                FILE_NAME);
+    }
+
+    @Override
+    public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException {
+        return ois.readObject();
+    }
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerAware.java
new file mode 100644 (file)
index 0000000..e4aa5f3
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancer Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be created
+     *
+     * @param loadBalancer
+     *            instance of proposed new LoadBalancer object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canCreateNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been created
+     *
+     * @param loadBalancer
+     *            instance of new LoadBalancer object
+     * @return void
+     */
+    public void neutronLoadBalancerCreated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancer object using patch semantics
+     * @param original
+     *            instance of the LoadBalancer object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canUpdateNeutronLoadBalancer(NeutronLoadBalancer delta, NeutronLoadBalancer original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been updated
+     *
+     * @param loadBalancer
+     *            instance of modified LoadBalancer object
+     * @return void
+     */
+    public void neutronLoadBalancerUpdated(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancer can be deleted
+     *
+     * @param loadBalancer
+     *            instance of the LoadBalancer object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canDeleteNeutronLoadBalancer(NeutronLoadBalancer loadBalancer);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancer has been deleted
+     *
+     * @param loadBalancer
+     *            instance of deleted LoadBalancer object
+     * @return void
+     */
+    public void neutronLoadBalancerDeleted(NeutronLoadBalancer loadBalancer);
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerCRUD.java
new file mode 100644 (file)
index 0000000..a2ce41e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancer objects
+ *
+ */
+
+public interface INeutronLoadBalancerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return boolean
+     */
+
+    public boolean neutronLoadBalancerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancer object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancer object
+     * @return {@link NeutronLoadBalancer}
+     *          OpenStackLoadBalancer class
+     */
+
+    public NeutronLoadBalancer getNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancer objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    public List<NeutronLoadBalancer> getAllNeutronLoadBalancers();
+
+    /**
+     * Applications call this interface method to add a LoadBalancer object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    public boolean addNeutronLoadBalancer(NeutronLoadBalancer input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancer object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancer object
+     * @return boolean on whether the object was removed or not
+     */
+
+    public boolean removeNeutronLoadBalancer(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancer object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @param delta
+     *            OpenStackLoadBalancer object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    public boolean updateNeutronLoadBalancer(String uuid, NeutronLoadBalancer delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancer object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    public boolean neutronLoadBalancerInUse(String uuid);
+
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorAware.java
new file mode 100644 (file)
index 0000000..7194da3
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerHealthMonitor Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of proposed new LoadBalancerHealthMonitor object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canCreateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been created
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of new LoadBalancerHealthMonitor object
+     * @return void
+     */
+    public void neutronLoadBalancerHealthMonitorCreated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerHealthMonitor object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerHealthMonitor object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canUpdateNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor delta,
+            NeutronLoadBalancerHealthMonitor original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been updated
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of modified LoadBalancerHealthMonitor object
+     * @return void
+     */
+    public void neutronLoadBalancerHealthMonitorUpdated(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerHealthMonitor can be deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of the LoadBalancerHealthMonitor object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canDeleteNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerHealthMonitor has been deleted
+     *
+     * @param loadBalancerHealthMonitor
+     *            instance of deleted LoadBalancerHealthMonitor object
+     * @return void
+     */
+    public void neutronLoadBalancerHealthMonitorDeleted(NeutronLoadBalancerHealthMonitor loadBalancerHealthMonitor);
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerHealthMonitorCRUD.java
new file mode 100644 (file)
index 0000000..7838000
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerHealthMonitor objects
+ *
+ */
+
+public interface INeutronLoadBalancerHealthMonitorCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return boolean
+     */
+
+    public boolean neutronLoadBalancerHealthMonitorExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerHealthMonitor object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerHealthMonitor object
+     * @return {@link NeutronLoadBalancerHealthMonitor}
+     *          OpenStackLoadBalancerHealthMonitor class
+     */
+
+    public NeutronLoadBalancerHealthMonitor getNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerHealthMonitor objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    public List<NeutronLoadBalancerHealthMonitor> getAllNeutronLoadBalancerHealthMonitors();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    public boolean addNeutronLoadBalancerHealthMonitor(NeutronLoadBalancerHealthMonitor input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerHealthMonitor object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerHealthMonitor object
+     * @return boolean on whether the object was removed or not
+     */
+
+    public boolean removeNeutronLoadBalancerHealthMonitor(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerHealthMonitor object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @param delta
+     *            OpenStackLoadBalancerHealthMonitor object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    public boolean updateNeutronLoadBalancerHealthMonitor(String uuid, NeutronLoadBalancerHealthMonitor delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerHealthMonitor object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    public boolean neutronLoadBalancerHealthMonitorInUse(String uuid);
+
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerAware.java
new file mode 100644 (file)
index 0000000..417419f
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerListener Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerListenerAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be created
+     *
+     * @param loadBalancerListener
+     *            instance of proposed new LoadBalancerListener object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canCreateNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been created
+     *
+     * @param loadBalancerListener
+     *            instance of new LoadBalancerListener object
+     * @return void
+     */
+    public void neutronLoadBalancerListenerCreated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerListener object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerListener object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canUpdateNeutronLoadBalancerListener(NeutronLoadBalancerListener delta,
+            NeutronLoadBalancerListener original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been updated
+     *
+     * @param loadBalancerListener
+     *            instance of modified LoadBalancerListener object
+     * @return void
+     */
+    public void neutronLoadBalancerListenerUpdated(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerListener can be deleted
+     *
+     * @param loadBalancerListener
+     *            instance of the LoadBalancerListener object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canDeleteNeutronLoadBalancerListener(NeutronLoadBalancerListener loadBalancerListener);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerListener has been deleted
+     *
+     * @param loadBalancerListener
+     *            instance of deleted LoadBalancerListener object
+     * @return void
+     */
+    public void neutronLoadBalancerListenerDeleted(NeutronLoadBalancerListener loadBalancerListener);
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerListenerCRUD.java
new file mode 100644 (file)
index 0000000..c160f8e
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerListener objects
+ *
+ */
+
+public interface INeutronLoadBalancerListenerCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return boolean
+     */
+
+    public boolean neutronLoadBalancerListenerExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerListener object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerListener object
+     * @return {@link NeutronLoadBalancerListener}
+     *          OpenStackLoadBalancerListener class
+     */
+
+    public NeutronLoadBalancerListener getNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerListener objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    public List<NeutronLoadBalancerListener> getAllNeutronLoadBalancerListeners();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    public boolean addNeutronLoadBalancerListener(NeutronLoadBalancerListener input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerListener object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerListener object
+     * @return boolean on whether the object was removed or not
+     */
+
+    public boolean removeNeutronLoadBalancerListener(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerListener object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @param delta
+     *            OpenStackLoadBalancerListener object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    public boolean updateNeutronLoadBalancerListener(String uuid, NeutronLoadBalancerListener delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerListener object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    public boolean neutronLoadBalancerListenerInUse(String uuid);
+
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolAware.java
new file mode 100644 (file)
index 0000000..16c7d37
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+/**
+ * This interface defines the methods a service that wishes to be aware of LoadBalancerPool Rules needs to implement
+ *
+ */
+
+public interface INeutronLoadBalancerPoolAware {
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be created
+     *
+     * @param loadBalancerPool
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canCreateNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been created
+     *
+     * @param loadBalancerPool
+     *            instance of new LoadBalancerPool object
+     * @return void
+     */
+    public void neutronLoadBalancerPoolCreated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPool object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canUpdateNeutronLoadBalancerPool(NeutronLoadBalancerPool delta, NeutronLoadBalancerPool original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been updated
+     *
+     * @param loadBalancerPool
+     *            instance of modified LoadBalancerPool object
+     * @return void
+     */
+    public void neutronLoadBalancerPoolUpdated(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPool can be deleted
+     *
+     * @param loadBalancerPool
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canDeleteNeutronLoadBalancerPool(NeutronLoadBalancerPool loadBalancerPool);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPool has been deleted
+     *
+     * @param loadBalancerPool
+     *            instance of deleted LoadBalancerPool object
+     * @return void
+     */
+    public void neutronLoadBalancerPoolDeleted(NeutronLoadBalancerPool loadBalancerPool);
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolCRUD.java
new file mode 100644 (file)
index 0000000..9614448
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+/**
+ * This interface defines the methods for CRUD of NB OpenStack LoadBalancerPool objects
+ *
+ */
+
+public interface INeutronLoadBalancerPoolCRUD {
+    /**
+     * Applications call this interface method to determine if a particular
+     *LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return boolean
+     */
+
+    public boolean neutronLoadBalancerPoolExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * LoadBalancerPool object exists
+     *
+     * @param uuid
+     *            UUID of the LoadBalancerPool object
+     * @return {@link NeutronLoadBalancerPool}
+     *          OpenStackLoadBalancerPool class
+     */
+
+    public NeutronLoadBalancerPool getNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to return all LoadBalancerPool objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    public List<NeutronLoadBalancerPool> getAllNeutronLoadBalancerPools();
+
+    /**
+     * Applications call this interface method to add a LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    public boolean addNeutronLoadBalancerPool(NeutronLoadBalancerPool input);
+
+    /**
+     * Applications call this interface method to remove a Neutron LoadBalancerPool object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the LoadBalancerPool object
+     * @return boolean on whether the object was removed or not
+     */
+
+    public boolean removeNeutronLoadBalancerPool(String uuid);
+
+    /**
+     * Applications call this interface method to edit a LoadBalancerPool object
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @param delta
+     *            OpenStackLoadBalancerPool object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    public boolean updateNeutronLoadBalancerPool(String uuid, NeutronLoadBalancerPool delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the LoadBalancerPool object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    public boolean neutronLoadBalancerPoolInUse(String uuid);
+
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberAware.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberAware.java
new file mode 100644 (file)
index 0000000..0a1da77
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+public interface INeutronLoadBalancerPoolMemberAware {
+
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of proposed new LoadBalancerPool object
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the create operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canCreateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been created
+     *
+     * @param loadBalancerPoolMember
+     *            instance of new LoadBalancerPool object
+     * @return void
+     */
+    public void neutronLoadBalancerPoolMemberCreated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be changed using the specified
+     * delta
+     *
+     * @param delta
+     *            updates to the loadBalancerPoolMember object using patch semantics
+     * @param original
+     *            instance of the LoadBalancerPool object to be updated
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the update operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canUpdateNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember delta,
+            NeutronLoadBalancerPoolMember original);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been updated
+     *
+     * @param loadBalancerPoolMember
+     *            instance of modified LoadBalancerPool object
+     * @return void
+     */
+    public void neutronLoadBalancerPoolMemberUpdated(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method to indicate if the specified loadBalancerPoolMember can be deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of the LoadBalancerPool object to be deleted
+     * @return integer
+     *            the return value is understood to be a HTTP status code.  A return value outside of 200 through 299
+     *            results in the delete operation being interrupted and the returned status value reflected in the
+     *            HTTP response.
+     */
+    public int canDeleteNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+
+    /**
+     * Services provide this interface method for taking action after a loadBalancerPoolMember has been deleted
+     *
+     * @param loadBalancerPoolMember
+     *            instance of deleted LoadBalancerPool object
+     * @return void
+     */
+    public void NeutronLoadBalancerPoolMemberDeleted(NeutronLoadBalancerPoolMember loadBalancerPoolMember);
+}
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberCRUD.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberCRUD.java
new file mode 100644 (file)
index 0000000..c1f5c70
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import java.util.List;
+
+public interface INeutronLoadBalancerPoolMemberCRUD {
+
+    /**
+     * Applications call this interface method to determine if a particular
+     *NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return boolean
+     */
+
+    public boolean neutronLoadBalancerPoolMemberExists(String uuid);
+
+    /**
+     * Applications call this interface method to return if a particular
+     * NeutronLoadBalancerPoolMember object exists
+     *
+     * @param uuid
+     *            UUID of the NeutronLoadBalancerPoolMember object
+     * @return {@link org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember}
+     *          OpenStackNeutronLoadBalancerPoolMember class
+     */
+
+    public NeutronLoadBalancerPoolMember getNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to return all NeutronLoadBalancerPoolMember objects
+     *
+     * @return List of OpenStackNetworks objects
+     */
+
+    public List<NeutronLoadBalancerPoolMember> getAllNeutronLoadBalancerPoolMembers();
+
+    /**
+     * Applications call this interface method to add a NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param input
+     *            OpenStackNetwork object
+     * @return boolean on whether the object was added or not
+     */
+
+    public boolean addNeutronLoadBalancerPoolMember(NeutronLoadBalancerPoolMember input);
+
+    /**
+     * Applications call this interface method to remove a Neutron NeutronLoadBalancerPoolMember object to the
+     * concurrent map
+     *
+     * @param uuid
+     *            identifier for the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the object was removed or not
+     */
+
+    public boolean removeNeutronLoadBalancerPoolMember(String uuid);
+
+    /**
+     * Applications call this interface method to edit a NeutronLoadBalancerPoolMember object
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @param delta
+     *            OpenStackNeutronLoadBalancerPoolMember object containing changes to apply
+     * @return boolean on whether the object was updated or not
+     */
+
+    public boolean updateNeutronLoadBalancerPoolMember(String uuid, NeutronLoadBalancerPoolMember delta);
+
+    /**
+     * Applications call this interface method to see if a MAC address is in use
+     *
+     * @param uuid
+     *            identifier of the NeutronLoadBalancerPoolMember object
+     * @return boolean on whether the macAddress is already associated with a
+     * port or not
+     */
+
+    public boolean neutronLoadBalancerPoolMemberInUse(String uuid);
+
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberRequest.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronLoadBalancerPoolMemberRequest.java
new file mode 100644 (file)
index 0000000..d8c5eb9
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
+
+public class INeutronLoadBalancerPoolMemberRequest {
+
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="member")
+    NeutronLoadBalancerPoolMember singletonLoadBalancerPoolMember;
+
+    @XmlElement(name="members")
+    List<NeutronLoadBalancerPoolMember> bulkRequest;
+
+    INeutronLoadBalancerPoolMemberRequest() {
+    }
+
+    public INeutronLoadBalancerPoolMemberRequest(List<NeutronLoadBalancerPoolMember> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerPoolMember = null;
+    }
+
+    INeutronLoadBalancerPoolMemberRequest(NeutronLoadBalancerPoolMember group) {
+        singletonLoadBalancerPoolMember = group;
+    }
+
+    public List<NeutronLoadBalancerPoolMember> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerPoolMember getSingleton() {
+        return singletonLoadBalancerPoolMember;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerPoolMember != null);
+    }
+}
\ No newline at end of file
index 6ce5499cdf9a2cc99ffda04d75d13a11d4c11bbb..472debe38312b45df11094b2646b39cfc485d19c 100644 (file)
@@ -61,4 +61,29 @@ public class NeutronCRUDInterfaces {
         INeutronFirewallRuleCRUD answer = (INeutronFirewallRuleCRUD) ServiceHelper.getGlobalInstance(INeutronFirewallRuleCRUD.class, o);
         return answer;
     }
+
+    public static INeutronLoadBalancerCRUD getINeutronLoadBalancerCRUD(Object o) {
+        INeutronLoadBalancerCRUD answer = (INeutronLoadBalancerCRUD) ServiceHelper.getGlobalInstance(INeutronLoadBalancerCRUD.class, o);
+        return answer;
+    }
+
+    public static INeutronLoadBalancerPoolCRUD getINeutronLoadBalancerPoolCRUD(Object o) {
+        INeutronLoadBalancerPoolCRUD answer = (INeutronLoadBalancerPoolCRUD) ServiceHelper.getGlobalInstance(INeutronLoadBalancerPoolCRUD.class, o);
+        return answer;
+    }
+
+    public static INeutronLoadBalancerListenerCRUD getINeutronLoadBalancerListenerCRUD(Object o) {
+        INeutronLoadBalancerListenerCRUD answer = (INeutronLoadBalancerListenerCRUD) ServiceHelper.getGlobalInstance(INeutronLoadBalancerListenerCRUD.class, o);
+        return answer;
+    }
+
+    public static INeutronLoadBalancerHealthMonitorCRUD getINeutronLoadBalancerHealthMonitorCRUD(Object o) {
+        INeutronLoadBalancerHealthMonitorCRUD answer = (INeutronLoadBalancerHealthMonitorCRUD) ServiceHelper.getGlobalInstance(INeutronLoadBalancerHealthMonitorCRUD.class, o);
+        return answer;
+    }
+
+    public static INeutronLoadBalancerPoolMemberCRUD getINeutronLoadBalancerPoolMemberCRUD(Object o) {
+        INeutronLoadBalancerPoolMemberCRUD answer = (INeutronLoadBalancerPoolMemberCRUD) ServiceHelper.getGlobalInstance(INeutronLoadBalancerPoolMemberCRUD.class, o);
+        return answer;
+    }
 }
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancer.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancer.java
new file mode 100644 (file)
index 0000000..15544f0
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * status             String
+ * vip_address        IP address
+ * vip_subnet         uuid-str
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancer extends ConfigurationObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name="id")
+    String loadBalancerID;
+
+    @XmlElement (name="tenant_id")
+    String loadBalancerTenantID;
+
+    @XmlElement (name="name")
+    String loadBalancerName;
+
+    @XmlElement (name="description")
+    String loadBalancerDescription;
+
+    @XmlElement (name="status")
+    String loadBalancerStatus;
+
+    @XmlElement (name="vip_address")
+    String loadBalancerVipAddress;
+
+    @XmlElement (name="vip_subnet_id")
+    String loadBalancerVipSubnetID;
+
+    public String getLoadBalancerID() {
+        return loadBalancerID;
+    }
+
+    public void setLoadBalancerID(String loadBalancerID) {
+        this.loadBalancerID = loadBalancerID;
+    }
+
+    public String getLoadBalancerTenantID() {
+        return loadBalancerTenantID;
+    }
+
+    public void setLoadBalancerTenantID(String loadBalancerTenantID) {
+        this.loadBalancerTenantID = loadBalancerTenantID;
+    }
+
+    public String getLoadBalancerName() {
+        return loadBalancerName;
+    }
+
+    public void setLoadBalancerName(String loadBalancerName) {
+        this.loadBalancerName = loadBalancerName;
+    }
+
+    public String getLoadBalancerDescription() {
+        return loadBalancerDescription;
+    }
+
+    public void setLoadBalancerDescription(String loadBalancerDescription) {
+        this.loadBalancerDescription = loadBalancerDescription;
+    }
+
+    public String getLoadBalancerStatus() {
+        return loadBalancerStatus;
+    }
+
+    public void setLoadBalancerStatus(String loadBalancerStatus) {
+        this.loadBalancerStatus = loadBalancerStatus;
+    }
+
+    public String getLoadBalancerVipAddress() {
+        return loadBalancerVipAddress;
+    }
+
+    public void setLoadBalancerVipAddress(String loadBalancerVipAddress) {
+        this.loadBalancerVipAddress = loadBalancerVipAddress;
+    }
+
+    public String getLoadBalancerVipSubnetID() {
+        return loadBalancerVipSubnetID;
+    }
+
+    public void setLoadBalancerVipSubnetID(String loadBalancerVipSubnetID) {
+        this.loadBalancerVipSubnetID = loadBalancerVipSubnetID;
+    }
+
+    public NeutronLoadBalancer extractFields(List<String> fields) {
+        NeutronLoadBalancer ans = new NeutronLoadBalancer();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setLoadBalancerID(this.getLoadBalancerID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerTenantID(this.getLoadBalancerTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerName(this.getLoadBalancerName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerDescription(this.getLoadBalancerDescription());
+            }
+            if (s.equals("vip_address")) {
+                ans.setLoadBalancerVipAddress(this.getLoadBalancerVipAddress());
+            }
+            if (s.equals("vip_subnet_id")) {
+                ans.setLoadBalancerVipSubnetID(this.getLoadBalancerVipSubnetID());
+            }
+            if (s.equals("status")) {
+                ans.setLoadBalancerStatus(this.getLoadBalancerStatus());
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancer{" +
+                "loadBalancerID='" + loadBalancerID + '\'' +
+                ", loadBalancerTenantID='" + loadBalancerTenantID + '\'' +
+                ", loadBalancerName='" + loadBalancerName + '\'' +
+                ", loadBalancerDescription='" + loadBalancerDescription + '\'' +
+                ", loadBalancerStatus='" + loadBalancerStatus + '\'' +
+                ", loadBalancerVipAddress='" + loadBalancerVipAddress + '\'' +
+                ", loadBalancerVipSubnetID='" + loadBalancerVipSubnetID + '\'' +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerHealthMonitor.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerHealthMonitor.java
new file mode 100644 (file)
index 0000000..0e9e1af
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * type               String
+ * delay              Integer
+ * timeout            Integer
+ * max_retries        Integer
+ * http_method        String
+ * url_path           String
+ * expected_codes     String
+ * admin_state_up     Boolean
+ * status             String
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerHealthMonitor extends ConfigurationObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancer.class);
+
+    @XmlElement(name="id")
+    String loadBalancerHealthMonitorID;
+
+    @XmlElement (name="tenant_id")
+    String loadBalancerHealthMonitorTenantID;
+
+    @XmlElement (name="type")
+    String loadBalancerHealthMonitorType;
+
+    @XmlElement (name="delay")
+    Integer loadBalancerHealthMonitorDelay;
+
+    @XmlElement (name="timeout")
+    Integer loadBalancerHealthMonitorTimeout;
+
+    @XmlElement (name="max_retries")
+    Integer loadBalancerHealthMonitorMaxRetries;
+
+    @XmlElement (name="http_method")
+    String loadBalancerHealthMonitorHttpMethod;
+
+    @XmlElement (name="url_path")
+    String loadBalancerHealthMonitorUrlPath;
+
+    @XmlElement (name="expected_codes")
+    String loadBalancerHealthMonitorExpectedCodes;
+
+    @XmlElement (defaultValue="true", name="admin_state_up")
+    Boolean loadBalancerHealthMonitorAdminStateIsUp;
+
+    @XmlElement (name="status")
+    String loadBalancerHealthMonitorStatus;
+
+    public String getLoadBalancerHealthMonitorID() {
+        return loadBalancerHealthMonitorID;
+    }
+
+    public void setLoadBalancerHealthMonitorID(String loadBalancerHealthMonitorID) {
+        this.loadBalancerHealthMonitorID = loadBalancerHealthMonitorID;
+    }
+
+    public String getLoadBalancerHealthMonitorTenantID() {
+        return loadBalancerHealthMonitorTenantID;
+    }
+
+    public void setLoadBalancerHealthMonitorTenantID(String loadBalancerHealthMonitorTenantID) {
+        this.loadBalancerHealthMonitorTenantID = loadBalancerHealthMonitorTenantID;
+    }
+
+    public String getLoadBalancerHealthMonitorType() {
+        return loadBalancerHealthMonitorType;
+    }
+
+    public void setLoadBalancerHealthMonitorType(String loadBalancerHealthMonitorType) {
+        this.loadBalancerHealthMonitorType = loadBalancerHealthMonitorType;
+    }
+
+    public Integer getLoadBalancerHealthMonitorDelay() {
+        return loadBalancerHealthMonitorDelay;
+    }
+
+    public void setLoadBalancerHealthMonitorDelay(Integer loadBalancerHealthMonitorDelay) {
+        this.loadBalancerHealthMonitorDelay = loadBalancerHealthMonitorDelay;
+    }
+
+    public Integer getLoadBalancerHealthMonitorTimeout() {
+        return loadBalancerHealthMonitorTimeout;
+    }
+
+    public void setLoadBalancerHealthMonitorTimeout(Integer loadBalancerHealthMonitorTimeout) {
+        this.loadBalancerHealthMonitorTimeout = loadBalancerHealthMonitorTimeout;
+    }
+
+    public Integer getLoadBalancerHealthMonitorMaxRetries() {
+        return loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public void setLoadBalancerHealthMonitorMaxRetries(Integer loadBalancerHealthMonitorMaxRetries) {
+        this.loadBalancerHealthMonitorMaxRetries = loadBalancerHealthMonitorMaxRetries;
+    }
+
+    public String getLoadBalancerHealthMonitorHttpMethod() {
+        return loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public void setLoadBalancerHealthMonitorHttpMethod(String loadBalancerHealthMonitorHttpMethod) {
+        this.loadBalancerHealthMonitorHttpMethod = loadBalancerHealthMonitorHttpMethod;
+    }
+
+    public String getLoadBalancerHealthMonitorUrlPath() {
+        return loadBalancerHealthMonitorUrlPath;
+    }
+
+    public void setLoadBalancerHealthMonitorUrlPath(String loadBalancerHealthMonitorUrlPath) {
+        this.loadBalancerHealthMonitorUrlPath = loadBalancerHealthMonitorUrlPath;
+    }
+
+    public String getLoadBalancerHealthMonitorExpectedCodes() {
+        return loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public void setLoadBalancerHealthMonitorExpectedCodes(String loadBalancerHealthMonitorExpectedCodes) {
+        this.loadBalancerHealthMonitorExpectedCodes = loadBalancerHealthMonitorExpectedCodes;
+    }
+
+    public Boolean getLoadBalancerHealthMonitorAdminStateIsUp() {
+        return loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public void setLoadBalancerHealthMonitorAdminStateIsUp(Boolean loadBalancerHealthMonitorAdminStateIsUp) {
+        this.loadBalancerHealthMonitorAdminStateIsUp = loadBalancerHealthMonitorAdminStateIsUp;
+    }
+
+    public String getLoadBalancerHealthMonitorStatus() {
+        return loadBalancerHealthMonitorStatus;
+    }
+
+    public void setLoadBalancerHealthMonitorStatus(String loadBalancerHealthMonitorStatus) {
+        this.loadBalancerHealthMonitorStatus = loadBalancerHealthMonitorStatus;
+    }
+
+    public NeutronLoadBalancerHealthMonitor extractFields(List<String> fields) {
+        NeutronLoadBalancerHealthMonitor ans = new NeutronLoadBalancerHealthMonitor();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setLoadBalancerHealthMonitorID(this.getLoadBalancerHealthMonitorID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerHealthMonitorTenantID(this.getLoadBalancerHealthMonitorTenantID());
+            }
+            if (s.equals("type")) {
+                ans.setLoadBalancerHealthMonitorType(this.getLoadBalancerHealthMonitorType());
+            }
+            if (s.equals("delay")) {
+                ans.setLoadBalancerHealthMonitorDelay(this.getLoadBalancerHealthMonitorDelay());
+            }
+            if (s.equals("timeout")) {
+                ans.setLoadBalancerHealthMonitorTimeout(this.getLoadBalancerHealthMonitorTimeout());
+            }
+            if (s.equals("max_retries")) {
+                ans.setLoadBalancerHealthMonitorMaxRetries(this.getLoadBalancerHealthMonitorMaxRetries());
+            }
+            if (s.equals("http_method")) {
+                ans.setLoadBalancerHealthMonitorHttpMethod(this.getLoadBalancerHealthMonitorHttpMethod());
+            }
+            if(s.equals("url_path")) {
+                ans.setLoadBalancerHealthMonitorUrlPath(this.getLoadBalancerHealthMonitorUrlPath());
+            }
+            if (s.equals("expected_codes")) {
+                ans.setLoadBalancerHealthMonitorExpectedCodes(this.getLoadBalancerHealthMonitorExpectedCodes());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerHealthMonitorAdminStateIsUp(loadBalancerHealthMonitorAdminStateIsUp);
+            }
+            if (s.equals("status")) {
+                ans.setLoadBalancerHealthMonitorStatus(this.getLoadBalancerHealthMonitorStatus());
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerHealthMonitor{" +
+                "loadBalancerHealthMonitorID='" + loadBalancerHealthMonitorID + '\'' +
+                ", loadBalancerHealthMonitorTenantID='" + loadBalancerHealthMonitorTenantID + '\'' +
+                ", loadBalancerHealthMonitorType='" + loadBalancerHealthMonitorType + '\'' +
+                ", loadBalancerHealthMonitorDelay=" + loadBalancerHealthMonitorDelay +
+                ", loadBalancerHealthMonitorTimeout=" + loadBalancerHealthMonitorTimeout +
+                ", loadBalancerHealthMonitorMaxRetries=" + loadBalancerHealthMonitorMaxRetries +
+                ", loadBalancerHealthMonitorHttpMethod='" + loadBalancerHealthMonitorHttpMethod + '\'' +
+                ", loadBalancerHealthMonitorUrlPath='" + loadBalancerHealthMonitorUrlPath + '\'' +
+                ", loadBalancerHealthMonitorExpectedCodes='" + loadBalancerHealthMonitorExpectedCodes + '\'' +
+                ", loadBalancerHealthMonitorAdminStateIsUp=" + loadBalancerHealthMonitorAdminStateIsUp +
+                ", loadBalancerHealthMonitorStatus='" + loadBalancerHealthMonitorStatus + '\'' +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerListener.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerListener.java
new file mode 100644 (file)
index 0000000..3989709
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * default_pool_id    String
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * shared             Bool
+ * protocol           String
+ * protocol_port      String
+ * load_balancer_id   String
+ * admin_state_up     Boolean
+ * status             String
+ *
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerListener extends ConfigurationObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name="id")
+    String loadBalancerListenerID;
+
+    @XmlElement (name="default_pool_id")
+    String neutronLoadBalancerListenerDefaultPoolID;
+
+    @XmlElement (name="tenant_id")
+    String loadBalancerListenerTenantID;
+
+    @XmlElement (name="name")
+    String loadBalancerListenerName;
+
+    @XmlElement (name="description")
+    String loadBalancerListenerDescription;
+
+    @XmlElement (defaultValue="true", name="admin_state_up")
+    Boolean loadBalancerListenerAdminStateIsUp;
+
+    @XmlElement (name="status")
+    String loadBalancerListenerStatus;
+
+    @XmlElement (defaultValue="false", name="shared")
+    Boolean loadBalancerListenerIsShared;
+
+    @XmlElement (name="protocol")
+    String neutronLoadBalancerListenerProtocol;
+
+    @XmlElement (name="protocol_port")
+    String neutronLoadBalancerListenerProtocolPort;
+
+    @XmlElement (name="load_balancer_id")
+    String neutronLoadBalancerListenerLoadBalancerID;
+
+
+    public String getLoadBalancerListenerID() {
+        return loadBalancerListenerID;
+    }
+
+    public void setLoadBalancerListenerID(String loadBalancerListenerID) {
+        this.loadBalancerListenerID = loadBalancerListenerID;
+    }
+
+    public String getLoadBalancerListenerTenantID() {
+        return loadBalancerListenerTenantID;
+    }
+
+    public void setLoadBalancerListenerTenantID(String loadBalancerListenerTenantID) {
+        this.loadBalancerListenerTenantID = loadBalancerListenerTenantID;
+    }
+
+    public String getLoadBalancerListenerName() {
+        return loadBalancerListenerName;
+    }
+
+    public void setLoadBalancerListenerName(String loadBalancerListenerName) {
+        this.loadBalancerListenerName = loadBalancerListenerName;
+    }
+
+    public String getLoadBalancerListenerDescription() {
+        return loadBalancerListenerDescription;
+    }
+
+    public void setLoadBalancerListenerDescription(String loadBalancerListenerDescription) {
+        this.loadBalancerListenerDescription = loadBalancerListenerDescription;
+    }
+
+    public Boolean getLoadBalancerListenerAdminStateIsUp() {
+        return loadBalancerListenerAdminStateIsUp;
+    }
+
+    public void setLoadBalancerListenerAdminStateIsUp(Boolean loadBalancerListenerAdminStateIsUp) {
+        this.loadBalancerListenerAdminStateIsUp = loadBalancerListenerAdminStateIsUp;
+    }
+
+    public String getLoadBalancerListenerStatus() {
+        return loadBalancerListenerStatus;
+    }
+
+    public void setLoadBalancerListenerStatus(String loadBalancerListenerStatus) {
+        this.loadBalancerListenerStatus = loadBalancerListenerStatus;
+    }
+
+    public Boolean getLoadBalancerListenerIsShared() {
+        return loadBalancerListenerIsShared;
+    }
+
+    public void setLoadBalancerListenerIsShared(Boolean loadBalancerListenerIsShared) {
+        this.loadBalancerListenerIsShared = loadBalancerListenerIsShared;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocol() {
+        return neutronLoadBalancerListenerProtocol;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocol(String neutronLoadBalancerListenerProtocol) {
+        this.neutronLoadBalancerListenerProtocol = neutronLoadBalancerListenerProtocol;
+    }
+
+    public String getNeutronLoadBalancerListenerProtocolPort() {
+        return neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public void setNeutronLoadBalancerListenerProtocolPort(String neutronLoadBalancerListenerProtocolPort) {
+        this.neutronLoadBalancerListenerProtocolPort = neutronLoadBalancerListenerProtocolPort;
+    }
+
+    public String getNeutronLoadBalancerListenerDefaultPoolID() {
+        return neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public void setNeutronLoadBalancerListenerDefaultPoolID(String neutronLoadBalancerListenerDefaultPoolID) {
+        this.neutronLoadBalancerListenerDefaultPoolID = neutronLoadBalancerListenerDefaultPoolID;
+    }
+
+    public String getNeutronLoadBalancerListenerLoadBalancerID() {
+        return neutronLoadBalancerListenerLoadBalancerID;
+    }
+
+    public void setNeutronLoadBalancerListenerLoadBalancerID(String neutronLoadBalancerListenerLoadBalancerID) {
+        this.neutronLoadBalancerListenerLoadBalancerID = neutronLoadBalancerListenerLoadBalancerID;
+    }
+
+    public NeutronLoadBalancerListener extractFields(List<String> fields) {
+        NeutronLoadBalancerListener ans = new NeutronLoadBalancerListener();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setLoadBalancerListenerID(this.getLoadBalancerListenerID());
+            }
+            if(s.equals("default_pool_id")) {
+                ans.setNeutronLoadBalancerListenerDefaultPoolID(this.getNeutronLoadBalancerListenerDefaultPoolID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerListenerTenantID(this.getLoadBalancerListenerTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerListenerName(this.getLoadBalancerListenerName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerListenerDescription(this.getLoadBalancerListenerDescription());
+            }
+            if (s.equals("shared")) {
+                ans.setLoadBalancerListenerIsShared(loadBalancerListenerIsShared);
+            }
+            if (s.equals("protocol")) {
+                ans.setNeutronLoadBalancerListenerProtocol(this.getNeutronLoadBalancerListenerProtocol());
+            }
+            if (s.equals("protocol_port")) {
+                ans.setNeutronLoadBalancerListenerProtocolPort(this.getNeutronLoadBalancerListenerProtocolPort());
+            }
+            if (s.equals("load_balancer_id")) {
+                ans.setNeutronLoadBalancerListenerLoadBalancerID(this.getNeutronLoadBalancerListenerLoadBalancerID());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerListenerAdminStateIsUp(loadBalancerListenerAdminStateIsUp);
+            }
+            if (s.equals("status")) {
+                ans.setLoadBalancerListenerStatus(this.getLoadBalancerListenerStatus());
+            }
+        }
+        return ans;
+    }
+
+    @Override public String toString() {
+        return "NeutronLoadBalancerListener{" +
+                "loadBalancerListenerID='" + loadBalancerListenerID + '\'' +
+                ", neutronLoadBalancerListenerDefaultPoolID='" + neutronLoadBalancerListenerDefaultPoolID + '\'' +
+                ", loadBalancerListenerTenantID='" + loadBalancerListenerTenantID + '\'' +
+                ", loadBalancerListenerName='" + loadBalancerListenerName + '\'' +
+                ", loadBalancerListenerDescription='" + loadBalancerListenerDescription + '\'' +
+                ", loadBalancerListenerAdminStateIsUp=" + loadBalancerListenerAdminStateIsUp +
+                ", loadBalancerListenerStatus='" + loadBalancerListenerStatus + '\'' +
+                ", loadBalancerListenerIsShared=" + loadBalancerListenerIsShared +
+                ", neutronLoadBalancerListenerProtocol='" + neutronLoadBalancerListenerProtocol + '\'' +
+                ", neutronLoadBalancerListenerProtocolPort='" + neutronLoadBalancerListenerProtocolPort + '\'' +
+                ", neutronLoadBalancerListenerLoadBalancerID='" + neutronLoadBalancerListenerLoadBalancerID + '\'' +
+                '}';
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPool.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPool.java
new file mode 100644 (file)
index 0000000..12c80fe
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * OpenStack Neutron v2.0 Load Balancer as a service
+ * (LBaaS) bindings. See OpenStack Network API
+ * v2.0 Reference for description of  the fields:
+ * Implemented fields are as follows:
+ *
+ * id                 uuid-str
+ * tenant_id          uuid-str
+ * name               String
+ * description        String
+ * protocol           String
+ * lb_algorithm       String
+ * healthmonitor_id   String
+ * admin_state_up     Bool
+ * status             String
+ * members            List <String>
+ * http://docs.openstack.org/api/openstack-network/2.0/openstack-network.pdf
+ */
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPool extends ConfigurationObject implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @XmlElement(name="id")
+    String loadBalancerPoolID;
+
+    @XmlElement (name="tenant_id")
+    String loadBalancerPoolTenantID;
+
+    @XmlElement (name="name")
+    String loadBalancerPoolName;
+
+    @XmlElement (name="description")
+    String loadBalancerPoolDescription;
+
+    @XmlElement (name="protocol")
+    String loadBalancerPoolProtocol;
+
+    @XmlElement (name="lb_algorithm")
+    String loadBalancerPoolLbAlgorithm;
+
+    @XmlElement (name="healthmonitor_id")
+    String neutronLoadBalancerPoolHealthMonitorID;
+
+    @XmlElement (defaultValue="true", name="admin_state_up")
+    Boolean loadBalancerPoolAdminStateIsUp;
+
+    @XmlElement (name="status")
+    String loadBalancerPoolStatus;
+
+    @XmlElement (name="members")
+    List loadBalancerPoolMembers;
+
+    HashMap<String, NeutronLoadBalancerPoolMember> member;
+
+    public NeutronLoadBalancerPool() {
+        member = new HashMap<String, NeutronLoadBalancerPoolMember>();
+    }
+
+    public String getLoadBalancerPoolID() {
+        return loadBalancerPoolID;
+    }
+
+    public void setLoadBalancerPoolID(String loadBalancerPoolID) {
+        this.loadBalancerPoolID = loadBalancerPoolID;
+    }
+
+    public String getLoadBalancerPoolTenantID() {
+        return loadBalancerPoolTenantID;
+    }
+
+    public void setLoadBalancerPoolTenantID(String loadBalancerPoolTenantID) {
+        this.loadBalancerPoolTenantID = loadBalancerPoolTenantID;
+    }
+
+    public String getLoadBalancerPoolName() {
+        return loadBalancerPoolName;
+    }
+
+    public void setLoadBalancerPoolName(String loadBalancerPoolName) {
+        this.loadBalancerPoolName = loadBalancerPoolName;
+    }
+
+    public String getLoadBalancerPoolDescription() {
+        return loadBalancerPoolDescription;
+    }
+
+    public void setLoadBalancerPoolDescription(String loadBalancerPoolDescription) {
+        this.loadBalancerPoolDescription = loadBalancerPoolDescription;
+    }
+
+    public String getLoadBalancerPoolProtocol() {
+        return loadBalancerPoolProtocol;
+    }
+
+    public void setLoadBalancerPoolProtocol(String loadBalancerPoolProtocol) {
+        this.loadBalancerPoolProtocol = loadBalancerPoolProtocol;
+    }
+
+    public String getLoadBalancerPoolLbAlgorithm() {
+        return loadBalancerPoolLbAlgorithm;
+    }
+
+    public void setLoadBalancerPoolLbAlgorithm(String loadBalancerPoolLbAlgorithm) {
+        this.loadBalancerPoolLbAlgorithm = loadBalancerPoolLbAlgorithm;
+    }
+
+    public String getNeutronLoadBalancerPoolHealthMonitorID() {
+        return neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public void setNeutronLoadBalancerPoolHealthMonitorID(String neutronLoadBalancerPoolHealthMonitorID) {
+        this.neutronLoadBalancerPoolHealthMonitorID = neutronLoadBalancerPoolHealthMonitorID;
+    }
+
+    public Boolean getLoadBalancerPoolAdminIsStateIsUp() {
+        return loadBalancerPoolAdminStateIsUp;
+    }
+
+    public void setLoadBalancerPoolAdminStateIsUp(Boolean loadBalancerPoolAdminStateIsUp) {
+        this.loadBalancerPoolAdminStateIsUp = loadBalancerPoolAdminStateIsUp;
+    }
+
+    public String getLoadBalancerPoolStatus() {
+        return loadBalancerPoolStatus;
+    }
+
+    public void setLoadBalancerPoolStatus(String loadBalancerPoolStatus) {
+        this.loadBalancerPoolStatus = loadBalancerPoolStatus;
+    }
+
+    public List getLoadBalancerPoolMembers() {
+        return loadBalancerPoolMembers;
+    }
+
+    public void setLoadBalancerPoolMembers(List loadBalancerPoolMembers) {
+        this.loadBalancerPoolMembers = loadBalancerPoolMembers;
+    }
+
+    public NeutronLoadBalancerPool extractFields(List<String> fields) {
+        NeutronLoadBalancerPool ans = new NeutronLoadBalancerPool();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setLoadBalancerPoolID(this.getLoadBalancerPoolID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setLoadBalancerPoolTenantID(this.getLoadBalancerPoolTenantID());
+            }
+            if (s.equals("name")) {
+                ans.setLoadBalancerPoolName(this.getLoadBalancerPoolName());
+            }
+            if(s.equals("description")) {
+                ans.setLoadBalancerPoolDescription(this.getLoadBalancerPoolDescription());
+            }
+            if(s.equals("protocol")) {
+                ans.setLoadBalancerPoolProtocol(this.getLoadBalancerPoolProtocol());
+            }
+            if(s.equals("lb_algorithm")) {
+                ans.setLoadBalancerPoolLbAlgorithm(this.getLoadBalancerPoolLbAlgorithm());
+            }
+            if(s.equals("healthmonitor_id")) {
+                ans.setNeutronLoadBalancerPoolHealthMonitorID(this.getNeutronLoadBalancerPoolHealthMonitorID());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setLoadBalancerPoolAdminStateIsUp(loadBalancerPoolAdminStateIsUp);
+            }
+            if (s.equals("status")) {
+                ans.setLoadBalancerPoolStatus(this.getLoadBalancerPoolStatus());
+            }
+            if (s.equals("members")) {
+                ans.setLoadBalancerPoolMembers(getLoadBalancerPoolMembers());
+            }
+        }
+        return ans;
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPoolMember.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronLoadBalancerPoolMember.java
new file mode 100644 (file)
index 0000000..577c3bb
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron;
+
+import org.opendaylight.controller.configuration.ConfigurationObject;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.io.Serializable;
+import java.util.Iterator;
+import java.util.List;
+
+public class NeutronLoadBalancerPoolMember  extends ConfigurationObject implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * TODO: Plumb into LBaaS Pool. Members are nested underneath Pool CRUD.
+     */
+    @XmlElement (name="id")
+    String poolMemberID;
+
+    @XmlElement (name="tenant_id")
+    String poolMemberTenantID;
+
+    @XmlElement (name="address")
+    String poolMemberAddress;
+
+    @XmlElement (name="protocol_port")
+    Integer poolMemberProtoPort;
+
+    @XmlElement (name="admin_state_up")
+    Boolean poolMemberAdminStateIsUp;
+
+    @XmlElement (name="weight")
+    Integer poolMemberWeight;
+
+    @XmlElement (name="subnet_id")
+    String poolMemberSubnetID;
+
+    @XmlElement (name="status")
+    String poolMemberStatus;
+
+    public NeutronLoadBalancerPoolMember() {
+    }
+
+    public String getPoolMemberID() {
+        return poolMemberID;
+    }
+
+    public void setPoolMemberID(String poolMemberID) {
+        this.poolMemberID = poolMemberID;
+    }
+
+    public String getPoolMemberTenantID() {
+        return poolMemberTenantID;
+    }
+
+    public void setPoolMemberTenantID(String poolMemberTenantID) {
+        this.poolMemberTenantID = poolMemberTenantID;
+    }
+
+    public String getPoolMemberAddress() {
+        return poolMemberAddress;
+    }
+
+    public void setPoolMemberAddress(String poolMemberAddress) {
+        this.poolMemberAddress = poolMemberAddress;
+    }
+
+    public Integer getPoolMemberProtoPort() {
+        return poolMemberProtoPort;
+    }
+
+    public void setPoolMemberProtoPort(Integer poolMemberProtoPort) {
+        this.poolMemberProtoPort = poolMemberProtoPort;
+    }
+
+    public Boolean getPoolMemberAdminStateIsUp() {
+        return poolMemberAdminStateIsUp;
+    }
+
+    public void setPoolMemberAdminStateIsUp(Boolean poolMemberAdminStateIsUp) {
+        this.poolMemberAdminStateIsUp = poolMemberAdminStateIsUp;
+    }
+
+    public Integer getPoolMemberWeight() {
+        return poolMemberWeight;
+    }
+
+    public void setPoolMemberWeight(Integer poolMemberWeight) {
+        this.poolMemberWeight = poolMemberWeight;
+    }
+
+    public String getPoolMemberSubnetID() {
+        return poolMemberSubnetID;
+    }
+
+    public void setPoolMemberSubnetID(String poolMemberSubnetID) {
+        this.poolMemberSubnetID = poolMemberSubnetID;
+    }
+
+    public String getPoolMemberStatus() {
+        return poolMemberStatus;
+    }
+
+    public void setPoolMemberStatus(String poolMemberStatus) {
+        this.poolMemberStatus = poolMemberStatus;
+    }
+
+    public NeutronLoadBalancerPoolMember extractFields(List<String> fields) {
+        NeutronLoadBalancerPoolMember ans = new NeutronLoadBalancerPoolMember();
+        Iterator<String> i = fields.iterator();
+        while (i.hasNext()) {
+            String s = i.next();
+            if (s.equals("id")) {
+                ans.setPoolMemberID(this.getPoolMemberID());
+            }
+            if (s.equals("tenant_id")) {
+                ans.setPoolMemberTenantID(this.getPoolMemberTenantID());
+            }
+            if (s.equals("address")) {
+                ans.setPoolMemberAddress(this.getPoolMemberAddress());
+            }
+            if(s.equals("protocol_port")) {
+                ans.setPoolMemberProtoPort(this.getPoolMemberProtoPort());
+            }
+            if (s.equals("admin_state_up")) {
+                ans.setPoolMemberAdminStateIsUp(poolMemberAdminStateIsUp);
+            }
+            if(s.equals("weight")) {
+                ans.setPoolMemberWeight(this.getPoolMemberWeight());
+            }
+            if(s.equals("subnet_id")) {
+                ans.setPoolMemberSubnetID(this.getPoolMemberSubnetID());
+            }
+            if (s.equals("status")) {
+                ans.setPoolMemberStatus(this.getPoolMemberStatus());
+            }
+        }
+        return ans;
+    }
+    @Override public String toString() {
+        return "NeutronLoadBalancerPoolMember{" +
+                "poolMemberID='" + poolMemberID + '\'' +
+                ", poolMemberTenantID='" + poolMemberTenantID + '\'' +
+                ", poolMemberAddress='" + poolMemberAddress + '\'' +
+                ", poolMemberProtoPort=" + poolMemberProtoPort +
+                ", poolMemberAdminStateIsUp=" + poolMemberAdminStateIsUp +
+                ", poolMemberWeight=" + poolMemberWeight +
+                ", poolMemberSubnetID='" + poolMemberSubnetID + '\'' +
+                ", poolMemberStatus='" + poolMemberStatus + '\'' +
+                '}';
+    }
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronLoadBalancerPoolMemberRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronLoadBalancerPoolMemberRequest.java
new file mode 100644 (file)
index 0000000..9d66163
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
+
+public class INeutronLoadBalancerPoolMemberRequest {
+
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="member")
+    NeutronLoadBalancerPoolMember singletonLoadBalancerPoolMember;
+
+    @XmlElement(name="members")
+    List<NeutronLoadBalancerPoolMember> bulkRequest;
+
+    INeutronLoadBalancerPoolMemberRequest() {
+    }
+
+    INeutronLoadBalancerPoolMemberRequest(List<NeutronLoadBalancerPoolMember> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerPoolMember = null;
+    }
+
+    INeutronLoadBalancerPoolMemberRequest(NeutronLoadBalancerPoolMember group) {
+        singletonLoadBalancerPoolMember = group;
+    }
+
+    public List<NeutronLoadBalancerPoolMember> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerPoolMember getSingleton() {
+        return singletonLoadBalancerPoolMember;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerPoolMember != null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java
new file mode 100644 (file)
index 0000000..6cd2673
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for Load Balancer HealthMonitor.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerHealthMonitor
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/healthmonitors")
+public class NeutronLoadBalancerHealthMonitorNorthbound {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancer.class);
+
+    private NeutronLoadBalancerHealthMonitor extractFields(NeutronLoadBalancerHealthMonitor o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerHealthMonitor */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerHealthMonitor attributes
+            @QueryParam("id") String queryLoadBalancerHealthMonitorID,
+            @QueryParam("tenant_id") String queryLoadBalancerHealthMonitorTenantID,
+            // TODO "type" is being a property by the JSON parser.
+            @QueryParam("type") String queryLoadBalancerHealthMonitorType,
+            @QueryParam("delay") Integer queryLoadBalancerHealthMonitorDelay,
+            @QueryParam("timeout") Integer queryLoadBalancerHealthMonitorTimeout,
+            @QueryParam("max_retries") Integer queryLoadBalancerHealthMonitorMaxRetries,
+            @QueryParam("http_method") String queryLoadBalancerHealthMonitorHttpMethod,
+            @QueryParam("url_path") String queryLoadBalancerHealthMonitorUrlPath,
+            @QueryParam("expected_codes") String queryLoadBalancerHealthMonitorExpectedCodes,
+            @QueryParam("admin_state_up") Boolean queryLoadBalancerHealthMonitorIsAdminStateUp,
+            @QueryParam("status") String queryLoadBalancerHealthMonitorStatus,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces
+                .getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerHealthMonitor> allLoadBalancerHealthMonitors = loadBalancerHealthMonitorInterface.getAllNeutronLoadBalancerHealthMonitors();
+        List<NeutronLoadBalancerHealthMonitor> ans = new ArrayList<NeutronLoadBalancerHealthMonitor>();
+        Iterator<NeutronLoadBalancerHealthMonitor> i = allLoadBalancerHealthMonitors.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerHealthMonitor nsg = i.next();
+            if ((queryLoadBalancerHealthMonitorID == null ||
+                    queryLoadBalancerHealthMonitorID.equals(nsg.getLoadBalancerHealthMonitorID())) &&
+                    (queryLoadBalancerHealthMonitorTenantID == null ||
+                            queryLoadBalancerHealthMonitorTenantID.equals
+                                    (nsg.getLoadBalancerHealthMonitorTenantID())) &&
+                    (queryLoadBalancerHealthMonitorType == null ||
+                            queryLoadBalancerHealthMonitorType.equals
+                                    (nsg.getLoadBalancerHealthMonitorType())) &&
+                    (queryLoadBalancerHealthMonitorDelay == null ||
+                            queryLoadBalancerHealthMonitorDelay.equals
+                                    (nsg.getLoadBalancerHealthMonitorDelay())) &&
+                    (queryLoadBalancerHealthMonitorTimeout == null ||
+                            queryLoadBalancerHealthMonitorTimeout.equals
+                                    (nsg.getLoadBalancerHealthMonitorTimeout())) &&
+                    (queryLoadBalancerHealthMonitorMaxRetries == null ||
+                            queryLoadBalancerHealthMonitorMaxRetries.equals
+                                    (nsg.getLoadBalancerHealthMonitorMaxRetries())) &&
+                    (queryLoadBalancerHealthMonitorHttpMethod == null ||
+                            queryLoadBalancerHealthMonitorHttpMethod.equals
+                                    (nsg.getLoadBalancerHealthMonitorHttpMethod())) &&
+                    (queryLoadBalancerHealthMonitorUrlPath == null ||
+                            queryLoadBalancerHealthMonitorUrlPath.equals
+                                    (nsg.getLoadBalancerHealthMonitorUrlPath())) &&
+                    (queryLoadBalancerHealthMonitorExpectedCodes == null ||
+                            queryLoadBalancerHealthMonitorExpectedCodes.equals
+                                    (nsg.getLoadBalancerHealthMonitorExpectedCodes())) &&
+                    (queryLoadBalancerHealthMonitorIsAdminStateUp == null ||
+                            queryLoadBalancerHealthMonitorIsAdminStateUp.equals
+                                    (nsg.getLoadBalancerHealthMonitorAdminStateIsUp())) &&
+                    (queryLoadBalancerHealthMonitorStatus == null ||
+                            queryLoadBalancerHealthMonitorStatus.equals
+                                    (nsg.getLoadBalancerHealthMonitorStatus()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerHealthMonitorRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerHealthMonitor */
+
+    @Path("{loadBalancerHealthMonitorID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerHealthMonitor(@PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerHealthMonitor ans = loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerHealthMonitorRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerHealthMonitorRequest(loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerHealthMonitor */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerHealthMonitors(final NeutronLoadBalancerHealthMonitorRequest input) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerHealthMonitor singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerHealthMonitor doesn't already exist.
+             */
+            if (loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(singleton.getLoadBalancerHealthMonitorID())) {
+                throw new BadRequestException("LoadBalancerHealthMonitor UUID already exists");
+            }
+            loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+            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();
+                    }
+                }
+            }
+            loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                    service.neutronLoadBalancerHealthMonitorCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerHealthMonitor> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerHealthMonitor> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerHealthMonitor> testMap = new HashMap<String, NeutronLoadBalancerHealthMonitor>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerHealthMonitor test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (loadBalancerHealthMonitorInterface
+                        .neutronLoadBalancerHealthMonitorExists(test.getLoadBalancerHealthMonitorID())) {
+                    throw new BadRequestException("LoadBalancerHealthMonitor UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerHealthMonitorID())) {
+                    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();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerHealthMonitor test = i.next();
+                loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                        service.neutronLoadBalancerHealthMonitorCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerHealthMonitor Policy
+     */
+    @Path("{loadBalancerHealthMonitorID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerHealthMonitor(
+            @PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID,
+            final NeutronLoadBalancerHealthMonitorRequest input) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces
+                .getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerHealthMonitor exists and there is only one delta provided
+         */
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerHealthMonitor delta = input.getSingleton();
+        NeutronLoadBalancerHealthMonitor original = loadBalancerHealthMonitorInterface
+                .getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerHealthMonitorID() != null ||
+                delta.getLoadBalancerHealthMonitorTenantID() != null ||
+                delta.getLoadBalancerHealthMonitorType() != null ||
+                delta.getLoadBalancerHealthMonitorDelay() != null ||
+                delta.getLoadBalancerHealthMonitorTimeout() != null ||
+                delta.getLoadBalancerHealthMonitorMaxRetries() != null ||
+                delta.getLoadBalancerHealthMonitorHttpMethod() != null ||
+                delta.getLoadBalancerHealthMonitorUrlPath() != null ||
+                delta.getLoadBalancerHealthMonitorExpectedCodes() != null ||
+                delta.getLoadBalancerHealthMonitorAdminStateIsUp() != null ||
+                delta.getLoadBalancerHealthMonitorStatus() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerHealthMonitorInterface.updateNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID, delta);
+        NeutronLoadBalancerHealthMonitor updatedLoadBalancerHealthMonitor = loadBalancerHealthMonitorInterface
+                .getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                service.neutronLoadBalancerHealthMonitorUpdated(updatedLoadBalancerHealthMonitor);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerHealthMonitorRequest
+                (loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor
+                        (loadBalancerHealthMonitorID))).build();
+    }
+
+
+
+    /**
+     * Deletes a LoadBalancerHealthMonitor
+     * */
+    @Path("{loadBalancerHealthMonitorID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancerHealthMonitor(
+            @PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        /*
+         * verify the LoadBalancerHealthMonitor exists and it isn't currently in use
+         */
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorInUse(loadBalancerHealthMonitorID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancerHealthMonitor singleton = loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+        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();
+                }
+            }
+        }
+        loadBalancerHealthMonitorInterface.removeNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                service.neutronLoadBalancerHealthMonitorDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java
new file mode 100644 (file)
index 0000000..dc4af2f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerHealthMonitor;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerHealthMonitorRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="healthmonitor")
+    NeutronLoadBalancerHealthMonitor singletonLoadBalancerHealthMonitor;
+
+    @XmlElement(name="healthmonitors")
+    List<NeutronLoadBalancerHealthMonitor> bulkRequest;
+
+    NeutronLoadBalancerHealthMonitorRequest() {
+    }
+
+    NeutronLoadBalancerHealthMonitorRequest(List<NeutronLoadBalancerHealthMonitor> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerHealthMonitor = null;
+    }
+
+    NeutronLoadBalancerHealthMonitorRequest(NeutronLoadBalancerHealthMonitor group) {
+        singletonLoadBalancerHealthMonitor = group;
+    }
+
+    public List<NeutronLoadBalancerHealthMonitor> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerHealthMonitor getSingleton() {
+        return singletonLoadBalancerHealthMonitor;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerHealthMonitor != null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java
new file mode 100644 (file)
index 0000000..f3ef39f
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerListener;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancerListener Policies.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerListener Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/listeners")
+public class NeutronLoadBalancerListenerNorthbound {
+
+    private NeutronLoadBalancerListener extractFields(NeutronLoadBalancerListener o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerListener */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerListener attributes
+            @QueryParam("id") String queryLoadBalancerListenerID,
+            @QueryParam("default_pool_id") String queryLoadBalancerListenerDefaultPoolID,
+            @QueryParam("tenant_id") String queryLoadBalancerListenerTenantID,
+            @QueryParam("name") String queryLoadBalancerListenerName,
+            @QueryParam("description") String queryLoadBalancerListenerDescription,
+            @QueryParam("shared") String queryLoadBalancerListenerIsShared,
+            @QueryParam("protocol") String queryLoadBalancerListenerProtocol,
+            @QueryParam("protocol_port") String queryLoadBalancerListenerProtocolPort,
+            @QueryParam("load_balancer_id") String queryLoadBalancerListenerLoadBalancerID,
+            @QueryParam("admin_state_up") String queryLoadBalancerListenerAdminIsUp,
+            @QueryParam("status") String queryLoadBalancerListenerStatus,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        //        INeutronLoadBalancerListenerRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerRuleCRUD(this);
+
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerListener> allLoadBalancerListeners = loadBalancerListenerInterface.getAllNeutronLoadBalancerListeners();
+        //        List<NeutronLoadBalancerListenerRule> allLoadBalancerListenerRules = firewallRuleInterface.getAllNeutronLoadBalancerListenerRules();
+        List<NeutronLoadBalancerListener> ans = new ArrayList<NeutronLoadBalancerListener>();
+        //        List<NeutronLoadBalancerListenerRule> rules = new ArrayList<NeutronLoadBalancerListenerRule>();
+        Iterator<NeutronLoadBalancerListener> i = allLoadBalancerListeners.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerListener nsg = i.next();
+            if ((queryLoadBalancerListenerID == null ||
+                    queryLoadBalancerListenerID.equals(nsg.getLoadBalancerListenerID())) &&
+                    (queryLoadBalancerListenerDefaultPoolID == null ||
+                            queryLoadBalancerListenerDefaultPoolID.equals(nsg.getNeutronLoadBalancerListenerDefaultPoolID())) &&
+                    (queryLoadBalancerListenerTenantID == null ||
+                            queryLoadBalancerListenerTenantID.equals(nsg.getLoadBalancerListenerTenantID())) &&
+                    (queryLoadBalancerListenerName == null ||
+                            queryLoadBalancerListenerName.equals(nsg.getLoadBalancerListenerName())) &&
+                    (queryLoadBalancerListenerDescription == null ||
+                            queryLoadBalancerListenerDescription.equals(nsg.getLoadBalancerListenerDescription())) &&
+                    (queryLoadBalancerListenerIsShared == null ||
+                            queryLoadBalancerListenerIsShared.equals(nsg.getLoadBalancerListenerIsShared())) &&
+                    (queryLoadBalancerListenerProtocol == null ||
+                            queryLoadBalancerListenerProtocol.equals(nsg.getNeutronLoadBalancerListenerProtocol())) &&
+                    (queryLoadBalancerListenerProtocolPort == null ||
+                            queryLoadBalancerListenerProtocolPort.equals(nsg.getNeutronLoadBalancerListenerProtocolPort())) &&
+                    (queryLoadBalancerListenerLoadBalancerID == null ||
+                            queryLoadBalancerListenerLoadBalancerID.equals(nsg.getNeutronLoadBalancerListenerLoadBalancerID())) &&
+                    (queryLoadBalancerListenerAdminIsUp == null ||
+                            queryLoadBalancerListenerAdminIsUp.equals(nsg.getLoadBalancerListenerAdminStateIsUp())) &&
+                    (queryLoadBalancerListenerStatus == null ||
+                            queryLoadBalancerListenerStatus.equals(nsg.getLoadBalancerListenerStatus()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerListenerRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerListener */
+
+    @Path("{loadBalancerListenerID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerListener(@PathParam("loadBalancerListenerID") String loadBalancerListenerID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerListener ans = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerListenerRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerListenerRequest(loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerListener */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerListeners(final NeutronLoadBalancerListenerRequest input) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerListener singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerListener doesn't already exist.
+             */
+            if (loadBalancerListenerInterface.neutronLoadBalancerListenerExists(singleton.getLoadBalancerListenerID())) {
+                throw new BadRequestException("LoadBalancerListener UUID already exists");
+            }
+            loadBalancerListenerInterface.addNeutronLoadBalancerListener(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+            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();
+                    }
+                }
+            }
+            loadBalancerListenerInterface.addNeutronLoadBalancerListener(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                    service.neutronLoadBalancerListenerCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerListener> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerListener> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerListener> testMap = new HashMap<String, NeutronLoadBalancerListener>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerListener test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (loadBalancerListenerInterface.neutronLoadBalancerListenerExists(test.getLoadBalancerListenerID())) {
+                    throw new BadRequestException("LoadBalancerListener UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerListenerID())) {
+                    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();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerListener test = i.next();
+                loadBalancerListenerInterface.addNeutronLoadBalancerListener(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                        service.neutronLoadBalancerListenerCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerListener Policy
+     */
+    @Path("{loadBalancerListenerID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerListener(
+            @PathParam("loadBalancerListenerID") String loadBalancerListenerID, final NeutronLoadBalancerListenerRequest input) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerListener exists and there is only one delta provided
+         */
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerListener delta = input.getSingleton();
+        NeutronLoadBalancerListener original = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerListenerID() != null ||
+                delta.getNeutronLoadBalancerListenerDefaultPoolID() != null ||
+                delta.getLoadBalancerListenerTenantID() != null ||
+                delta.getLoadBalancerListenerName() != null ||
+                delta.getLoadBalancerListenerDescription() != null ||
+                delta.getLoadBalancerListenerIsShared() != null ||
+                delta.getNeutronLoadBalancerListenerProtocol() != null ||
+                delta.getNeutronLoadBalancerListenerProtocolPort() != null ||
+                delta.getNeutronLoadBalancerListenerLoadBalancerID() != null ||
+                delta.getLoadBalancerListenerAdminStateIsUp() != null ||
+                delta.getLoadBalancerListenerStatus() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerListenerInterface.updateNeutronLoadBalancerListener(loadBalancerListenerID, delta);
+        NeutronLoadBalancerListener updatedLoadBalancerListener = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                service.neutronLoadBalancerListenerUpdated(updatedLoadBalancerListener);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerListenerRequest(loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID))).build();
+    }
+
+    /**
+     * Deletes a LoadBalancerListener */
+
+    @Path("{loadBalancerListenerID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancerListener(
+            @PathParam("loadBalancerListenerID") String loadBalancerListenerID) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerListener exists and it isn't currently in use
+         */
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (loadBalancerListenerInterface.neutronLoadBalancerListenerInUse(loadBalancerListenerID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancerListener singleton = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        loadBalancerListenerInterface.removeNeutronLoadBalancerListener(loadBalancerListenerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                service.neutronLoadBalancerListenerDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java
new file mode 100644 (file)
index 0000000..ba375af
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerListener;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerListenerRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="listener")
+    NeutronLoadBalancerListener singletonLoadBalancerListener;
+
+    @XmlElement(name="listeners")
+    List<NeutronLoadBalancerListener> bulkRequest;
+
+    NeutronLoadBalancerListenerRequest() {
+    }
+
+    NeutronLoadBalancerListenerRequest(List<NeutronLoadBalancerListener> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerListener = null;
+    }
+
+    NeutronLoadBalancerListenerRequest(NeutronLoadBalancerListener group) {
+        singletonLoadBalancerListener = group;
+    }
+
+    public List<NeutronLoadBalancerListener> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerListener getSingleton() {
+        return singletonLoadBalancerListener;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerListener != null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java
new file mode 100644 (file)
index 0000000..748dffc
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancer Policies.<br>
+ * This class provides REST APIs for managing neutron LoadBalancer Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/loadbalancers")
+public class NeutronLoadBalancerNorthbound {
+
+    private NeutronLoadBalancer extractFields(NeutronLoadBalancer o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancer */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancer attributes
+            @QueryParam("id") String queryLoadBalancerID,
+            @QueryParam("tenant_id") String queryLoadBalancerTenantID,
+            @QueryParam("name") String queryLoadBalancerName,
+            @QueryParam("description") String queryLoadBalancerDescription,
+            @QueryParam("status") String queryLoadBalancerStatus,
+            @QueryParam("vip_address") String queryLoadBalancerVipAddress,
+            @QueryParam("vip_subnet") String queryLoadBalancerVipSubnet,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        //        INeutronLoadBalancerRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerRuleCRUD(this);
+
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancer> allLoadBalancers = loadBalancerPoolInterface.getAllNeutronLoadBalancers();
+        //        List<NeutronLoadBalancerRule> allLoadBalancerRules = firewallRuleInterface.getAllNeutronLoadBalancerRules();
+        List<NeutronLoadBalancer> ans = new ArrayList<NeutronLoadBalancer>();
+        //        List<NeutronLoadBalancerRule> rules = new ArrayList<NeutronLoadBalancerRule>();
+        Iterator<NeutronLoadBalancer> i = allLoadBalancers.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancer nsg = i.next();
+            if ((queryLoadBalancerID == null ||
+                    queryLoadBalancerID.equals(nsg.getLoadBalancerID())) &&
+                    (queryLoadBalancerTenantID == null ||
+                            queryLoadBalancerTenantID.equals(nsg.getLoadBalancerTenantID())) &&
+                    (queryLoadBalancerName == null ||
+                            queryLoadBalancerName.equals(nsg.getLoadBalancerName())) &&
+                    (queryLoadBalancerDescription == null ||
+                            queryLoadBalancerDescription.equals(nsg.getLoadBalancerDescription())) &&
+                    (queryLoadBalancerVipAddress == null ||
+                            queryLoadBalancerVipAddress.equals(nsg.getLoadBalancerVipAddress())) &&
+                    (queryLoadBalancerVipSubnet == null ||
+                            queryLoadBalancerVipSubnet.equals(nsg.getLoadBalancerVipSubnetID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancer */
+
+    @Path("{loadBalancerPoolID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancer(@PathParam("loadBalancerPoolID") String loadBalancerPoolID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerPoolInterface.neutronLoadBalancerExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancer ans = loadBalancerPoolInterface.getNeutronLoadBalancer(loadBalancerPoolID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerRequest(loadBalancerPoolInterface.getNeutronLoadBalancer(
+                    loadBalancerPoolID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancer */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancers(final NeutronLoadBalancerRequest input) {
+        INeutronLoadBalancerCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancer singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancer doesn't already exist.
+             */
+            if (loadBalancerPoolInterface.neutronLoadBalancerExists(singleton.getLoadBalancerID())) {
+                throw new BadRequestException("LoadBalancer UUID already exists");
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancer(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+            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();
+                    }
+                }
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancer(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                    service.neutronLoadBalancerCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancer> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancer> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancer> testMap = new HashMap<String, NeutronLoadBalancer>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancer test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (loadBalancerPoolInterface.neutronLoadBalancerExists(test.getLoadBalancerID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerID())) {
+                    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();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancer test = i.next();
+                loadBalancerPoolInterface.addNeutronLoadBalancer(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                        service.neutronLoadBalancerCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancer Policy
+     */
+    @Path("{loadBalancerPoolID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancer(
+            @PathParam("loadBalancerPoolID") String loadBalancerPoolID, final NeutronLoadBalancerRequest input) {
+        INeutronLoadBalancerCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancer exists and there is only one delta provided
+         */
+        if (!loadBalancerPoolInterface.neutronLoadBalancerExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancer delta = input.getSingleton();
+        NeutronLoadBalancer original = loadBalancerPoolInterface.getNeutronLoadBalancer(loadBalancerPoolID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerID() != null ||
+                delta.getLoadBalancerTenantID() != null ||
+                delta.getLoadBalancerName() != null ||
+                delta.getLoadBalancerDescription() != null ||
+                delta.getLoadBalancerStatus() != null ||
+                delta.getLoadBalancerVipAddress() != null ||
+                delta.getLoadBalancerVipSubnetID() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerPoolInterface.updateNeutronLoadBalancer(loadBalancerPoolID, delta);
+        NeutronLoadBalancer updatedLoadBalancer = loadBalancerPoolInterface.getNeutronLoadBalancer(
+                loadBalancerPoolID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                service.neutronLoadBalancerUpdated(updatedLoadBalancer);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerRequest(loadBalancerPoolInterface.getNeutronLoadBalancer(
+                loadBalancerPoolID))).build();
+    }
+
+    /**
+     * Deletes a LoadBalancer */
+
+    @Path("{loadBalancerPoolID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancer(
+            @PathParam("loadBalancerPoolID") String loadBalancerPoolID) {
+        INeutronLoadBalancerCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancer exists and it isn't currently in use
+         */
+        if (!loadBalancerPoolInterface.neutronLoadBalancerExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (loadBalancerPoolInterface.neutronLoadBalancerInUse(loadBalancerPoolID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancer singleton = loadBalancerPoolInterface.getNeutronLoadBalancer(loadBalancerPoolID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        loadBalancerPoolInterface.removeNeutronLoadBalancer(loadBalancerPoolID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                service.neutronLoadBalancerDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java
new file mode 100644 (file)
index 0000000..ff56fa0
--- /dev/null
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+
+@Path("/pools/{loadBalancerPoolID}/members")
+public class NeutronLoadBalancerPoolMembersNorthbound {
+
+    private NeutronLoadBalancerPoolMember extractFields(NeutronLoadBalancerPoolMember o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+/**
+ * Returns a list of all LoadBalancerPool
+ */
+@GET
+@Produces({MediaType.APPLICATION_JSON})
+@StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 501, condition = "Not Implemented")})
+
+public Response listMembers(
+        // return fields
+        @QueryParam("fields") List<String> fields,
+        // OpenStack LoadBalancerPool attributes
+        @QueryParam("id") String queryLoadBalancerPoolMemberID,
+        @QueryParam("tenant_id") String queryLoadBalancerPoolMemberTenantID,
+        @QueryParam("address") String queryLoadBalancerPoolMemberAddress,
+        @QueryParam("protocol_port") String queryLoadBalancerPoolMemberProtoPort,
+        @QueryParam("admin_state_up") String queryLoadBalancerPoolMemberAdminStateUp,
+        @QueryParam("weight") String queryLoadBalancerPoolMemberWeight,
+        @QueryParam("subnet_id") String queryLoadBalancerPoolMemberSubnetID,
+        @QueryParam("status") String queryLoadBalancerPoolMemberStatus,
+
+        // pagination
+        @QueryParam("limit") String limit,
+        @QueryParam("marker") String marker,
+        @QueryParam("page_reverse") String pageReverse
+        // sorting not supported
+) {
+    INeutronLoadBalancerPoolMemberCRUD loadBalancerPoolMemberInterface = NeutronCRUDInterfaces
+            .getINeutronLoadBalancerPoolMemberCRUD(this);
+    if (loadBalancerPoolMemberInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+    List<NeutronLoadBalancerPoolMember> allLoadBalancerPoolMembers = loadBalancerPoolMemberInterface
+            .getAllNeutronLoadBalancerPoolMembers();
+    List<NeutronLoadBalancerPoolMember> ans = new ArrayList<NeutronLoadBalancerPoolMember>();
+    Iterator<NeutronLoadBalancerPoolMember> i = allLoadBalancerPoolMembers.iterator();
+    while (i.hasNext()) {
+        NeutronLoadBalancerPoolMember nsg = i.next();
+        if ((queryLoadBalancerPoolMemberID == null ||
+                queryLoadBalancerPoolMemberID.equals(nsg.getPoolMemberID())) &&
+                (queryLoadBalancerPoolMemberTenantID == null ||
+                        queryLoadBalancerPoolMemberTenantID.equals(nsg.getPoolMemberTenantID())) &&
+                (queryLoadBalancerPoolMemberAddress == null ||
+                        queryLoadBalancerPoolMemberAddress.equals(nsg.getPoolMemberAddress())) &&
+                (queryLoadBalancerPoolMemberAdminStateUp == null ||
+                        queryLoadBalancerPoolMemberAdminStateUp.equals(nsg.getPoolMemberAdminStateIsUp())) &&
+                (queryLoadBalancerPoolMemberWeight == null ||
+                        queryLoadBalancerPoolMemberWeight.equals(nsg.getPoolMemberWeight())) &&
+                (queryLoadBalancerPoolMemberSubnetID == null ||
+                        queryLoadBalancerPoolMemberSubnetID.equals(nsg.getPoolMemberSubnetID())) &&
+                (queryLoadBalancerPoolMemberStatus == null ||
+                        queryLoadBalancerPoolMemberStatus.equals(nsg.getPoolMemberStatus()))) {
+            if (fields.size() > 0) {
+                ans.add(extractFields(nsg, fields));
+            } else {
+                ans.add(nsg);
+            }
+        }
+    }
+    return Response.status(200).entity(
+            new INeutronLoadBalancerPoolMemberRequest(ans)).build();
+}
+
+/**
+ * Adds a Member to an LBaaS Pool member
+ */
+@Path("/pools/{loadBalancerPoolID}/members")
+@PUT
+@Produces({MediaType.APPLICATION_JSON})
+@Consumes({MediaType.APPLICATION_JSON})
+@StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 501, condition = "Not Implemented")})
+public Response createLoadBalancerPoolMember(  INeutronLoadBalancerPoolMemberRequest input) {
+
+    INeutronLoadBalancerPoolMemberCRUD loadBalancerPoolMemberInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolMemberCRUD(
+            this);
+    if (loadBalancerPoolMemberInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPoolMember CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+    if (input.isSingleton()) {
+        NeutronLoadBalancerPoolMember singleton = input.getSingleton();
+
+        /*
+         *  Verify that the LoadBalancerPoolMember doesn't already exist.
+         */
+        if (loadBalancerPoolMemberInterface.neutronLoadBalancerPoolMemberExists(
+                singleton.getPoolMemberID())) {
+            throw new BadRequestException("LoadBalancerPoolMember UUID already exists");
+        }
+        loadBalancerPoolMemberInterface.addNeutronLoadBalancerPoolMember(singleton);
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolMemberAware.class, this, null);
+        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();
+                }
+            }
+        }
+        loadBalancerPoolMemberInterface.addNeutronLoadBalancerPoolMember(singleton);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                service.neutronLoadBalancerPoolMemberCreated(singleton);
+            }
+        }
+    } else {
+        List<NeutronLoadBalancerPoolMember> bulk = input.getBulk();
+        Iterator<NeutronLoadBalancerPoolMember> i = bulk.iterator();
+        HashMap<String, NeutronLoadBalancerPoolMember> testMap = new HashMap<String, NeutronLoadBalancerPoolMember>();
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolMemberAware.class, this, null);
+        while (i.hasNext()) {
+            NeutronLoadBalancerPoolMember test = i.next();
+
+            /*
+             *  Verify that the firewall doesn't already exist
+             */
+
+            if (loadBalancerPoolMemberInterface.neutronLoadBalancerPoolMemberExists(
+                    test.getPoolMemberID())) {
+                throw new BadRequestException("Load Balancer PoolMember UUID already is already created");
+            }
+            if (testMap.containsKey(test.getPoolMemberID())) {
+                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();
+                    }
+                }
+            }
+        }
+        /*
+         * now, each element of the bulk request can be added to the cache
+         */
+        i = bulk.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerPoolMember test = i.next();
+            loadBalancerPoolMemberInterface.addNeutronLoadBalancerPoolMember(test);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                    service.neutronLoadBalancerPoolMemberCreated(test);
+                }
+            }
+        }
+    }
+    return Response.status(201).entity(input).build();
+}
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java
new file mode 100644 (file)
index 0000000..fc5357c
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancerPool Policies.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerPool Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/pools")
+public class NeutronLoadBalancerPoolNorthbound {
+
+    private NeutronLoadBalancerPool extractFields(NeutronLoadBalancerPool o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerPool
+     * */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerPool attributes
+            @QueryParam("id") String queryLoadBalancerPoolID,
+            @QueryParam("tenant_id") String queryLoadBalancerPoolTenantID,
+            @QueryParam("name") String queryLoadBalancerPoolName,
+            @QueryParam("description") String queryLoadBalancerDescription,
+            @QueryParam("protocol") String queryLoadBalancerProtocol,
+            @QueryParam("lb_algorithm") String queryLoadBalancerPoolLbAlgorithm,
+            @QueryParam("healthmonitor_id") String queryLoadBalancerPoolHealthMonitorID,
+            @QueryParam("admin_state_up") String queryLoadBalancerIsAdminStateUp,
+            @QueryParam("status") String queryLoadBalancerPoolStatus,
+            @QueryParam("members") List queryLoadBalancerPoolMembers,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerPool> allLoadBalancerPools = loadBalancerPoolInterface.getAllNeutronLoadBalancerPools();
+        List<NeutronLoadBalancerPool> ans = new ArrayList<NeutronLoadBalancerPool>();
+        Iterator<NeutronLoadBalancerPool> i = allLoadBalancerPools.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerPool nsg = i.next();
+            if ((queryLoadBalancerPoolID == null ||
+                    queryLoadBalancerPoolID.equals(nsg.getLoadBalancerPoolID())) &&
+                    (queryLoadBalancerPoolTenantID == null ||
+                            queryLoadBalancerPoolTenantID.equals(nsg.getLoadBalancerPoolTenantID())) &&
+                    (queryLoadBalancerPoolName == null ||
+                            queryLoadBalancerPoolName.equals(nsg.getLoadBalancerPoolName())) &&
+                    (queryLoadBalancerDescription == null ||
+                            queryLoadBalancerDescription.equals(nsg.getLoadBalancerPoolDescription())) &&
+                    (queryLoadBalancerPoolLbAlgorithm == null ||
+                            queryLoadBalancerPoolLbAlgorithm.equals(nsg.getLoadBalancerPoolLbAlgorithm())) &&
+                    (queryLoadBalancerPoolHealthMonitorID == null ||
+                            queryLoadBalancerPoolHealthMonitorID.equals(nsg.getNeutronLoadBalancerPoolHealthMonitorID())) &&
+                    (queryLoadBalancerIsAdminStateUp == null ||
+                            queryLoadBalancerIsAdminStateUp.equals(nsg.getLoadBalancerPoolAdminIsStateIsUp())) &&
+                    (queryLoadBalancerPoolStatus == null ||
+                            queryLoadBalancerPoolStatus.equals(nsg.getLoadBalancerPoolStatus())) &&
+                    (queryLoadBalancerPoolMembers.size() == 0 ||
+                            queryLoadBalancerPoolMembers.equals(nsg.getLoadBalancerPoolMembers()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerPoolRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerPool */
+
+    @Path("{loadBalancerPoolID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerPool(@PathParam("loadBalancerPoolID") String loadBalancerPoolID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancerPool UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerPool ans = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerPoolRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerPoolRequest(loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerPool */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerPools(final NeutronLoadBalancerPoolRequest input) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerPool singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerPool doesn't already exist.
+             */
+            if (loadBalancerPoolInterface.neutronLoadBalancerPoolExists(singleton.getLoadBalancerPoolID())) {
+                throw new BadRequestException("LoadBalancerPool UUID already exists");
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancerPool(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+            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();
+                    }
+                }
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancerPool(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                    service.neutronLoadBalancerPoolCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerPool> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerPool> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerPool> testMap = new HashMap<String, NeutronLoadBalancerPool>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerPool test = i.next();
+
+                /*
+                 *  Verify that the firewall doesn't already exist
+                 */
+
+                if (loadBalancerPoolInterface.neutronLoadBalancerPoolExists(test.getLoadBalancerPoolID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerPoolID())) {
+                    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();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerPool test = i.next();
+                loadBalancerPoolInterface.addNeutronLoadBalancerPool(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                        service.neutronLoadBalancerPoolCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerPool Policy
+     */
+    @Path("{loadBalancerPoolID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerPool(
+            @PathParam("loadBalancerPoolID") String loadBalancerPoolID, final NeutronLoadBalancerPoolRequest input) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerPool exists and there is only one delta provided
+         */
+        if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancerPool UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerPool delta = input.getSingleton();
+        NeutronLoadBalancerPool original = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerPoolID() != null ||
+                delta.getLoadBalancerPoolTenantID() != null ||
+                delta.getLoadBalancerPoolName() != null ||
+                delta.getLoadBalancerPoolDescription() != null ||
+                delta.getLoadBalancerPoolProtocol() != null ||
+                delta.getLoadBalancerPoolLbAlgorithm() != null ||
+                delta.getNeutronLoadBalancerPoolHealthMonitorID() != null ||
+                delta.getLoadBalancerPoolAdminIsStateIsUp() != null ||
+                delta.getLoadBalancerPoolStatus() != null ||
+                delta.getLoadBalancerPoolMembers() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+        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();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerPoolInterface.updateNeutronLoadBalancerPool(loadBalancerPoolID, delta);
+        NeutronLoadBalancerPool updatedLoadBalancerPool = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                service.neutronLoadBalancerPoolUpdated(updatedLoadBalancerPool);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerPoolRequest(loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID))).build();
+    }
+}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java
new file mode 100644 (file)
index 0000000..a1cdc41
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerPoolRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="pool")
+    NeutronLoadBalancerPool singletonLoadBalancerPool;
+
+    @XmlElement(name="pools")
+    List<NeutronLoadBalancerPool> bulkRequest;
+
+    NeutronLoadBalancerPoolRequest() {
+    }
+
+    NeutronLoadBalancerPoolRequest(List<NeutronLoadBalancerPool> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerPool = null;
+    }
+
+    NeutronLoadBalancerPoolRequest(NeutronLoadBalancerPool group) {
+        singletonLoadBalancerPool = group;
+    }
+
+    public List<NeutronLoadBalancerPool> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerPool getSingleton() {
+        return singletonLoadBalancerPool;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerPool != null);
+    }
+}
\ No newline at end of file
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java
new file mode 100644 (file)
index 0000000..1cf4e70
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.util.List;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronLoadBalancerRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="loadbalancer")
+    NeutronLoadBalancer singletonLoadBalancer;
+
+    @XmlElement(name="loadbalancers")
+    List<NeutronLoadBalancer> bulkRequest;
+
+    NeutronLoadBalancerRequest() {
+    }
+
+    NeutronLoadBalancerRequest(List<NeutronLoadBalancer> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancer = null;
+    }
+
+    NeutronLoadBalancerRequest(NeutronLoadBalancer group) {
+        singletonLoadBalancer = group;
+    }
+
+    public List<NeutronLoadBalancer> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancer getSingleton() {
+        return singletonLoadBalancer;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancer != null);
+    }
+}
\ No newline at end of file
index 9abcca7c53466880de769f93324ad09577142bf8..96d72cb9262657565973651a46a5940355db1064 100644 (file)
@@ -38,6 +38,11 @@ public class NeutronNorthboundRSApplication extends Application {
         classes.add(NeutronFirewallNorthbound.class);
         classes.add(NeutronFirewallPolicyNorthbound.class);
         classes.add(NeutronFirewallRulesNorthbound.class);
+        classes.add(NeutronLoadBalancerNorthbound.class);
+        classes.add(NeutronLoadBalancerListenerNorthbound.class);
+        classes.add(NeutronLoadBalancerPoolNorthbound.class);
+        classes.add(NeutronLoadBalancerHealthMonitorNorthbound.class);
+        classes.add(NeutronLoadBalancerPoolMembersNorthbound.class);
         return classes;
     }