Merge "Return local shard's DataTree from ActorContext#findPrimaryShardAsync"
authorMoiz Raja <moraja@cisco.com>
Fri, 24 Apr 2015 10:02:16 +0000 (10:02 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 24 Apr 2015 10:02:16 +0000 (10:02 +0000)
14 files changed:
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingNotificationAdapterModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/NotificationBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AbstractNotificationListenerRegistration.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AbstractNotificationListenerRegistration.java with 96% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/AggregatedNotificationListenerRegistration.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/AggregatedNotificationListenerRegistration.java with 97% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/HydrogenNotificationBrokerImpl.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationBrokerImpl.java with 95% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/ListenerMapGeneration.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/ListenerMapGeneration.java with 98% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotificationListenerRegistration.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotificationListenerRegistration.java with 95% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/compat/NotifyTask.java [moved from opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/NotifyTask.java with 98% similarity]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDOMNotificationServiceAdapter.java
opendaylight/md-sal/sal-binding-broker/src/main/yang/opendaylight-binding-broker-impl.yang
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/DataBrokerTestCustomizer.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/util/BindingTestContext.java
opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataTreeListenerTest.java [new file with mode: 0644]

index 903cb27c92f52d8a6215ffd32c450f5c4039be28..971153bc7bf80dcb7858e538619b268a36b5ab28 100644 (file)
@@ -9,18 +9,17 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
 import org.opendaylight.controller.config.api.DependencyResolver;
 import org.opendaylight.controller.config.api.ModuleIdentifier;
-import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.controller.sal.core.api.Broker;
 
 public class BindingNotificationAdapterModule extends AbstractBindingNotificationAdapterModule  {
-    public BindingNotificationAdapterModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver) {
+    public BindingNotificationAdapterModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
 
-    public BindingNotificationAdapterModule(ModuleIdentifier identifier, DependencyResolver dependencyResolver, org.opendaylight.controller.config.yang.md.sal.binding.impl.BindingNotificationAdapterModule oldModule, java.lang.AutoCloseable oldInstance) {
+    public BindingNotificationAdapterModule(final ModuleIdentifier identifier, final DependencyResolver dependencyResolver, final org.opendaylight.controller.config.yang.md.sal.binding.impl.BindingNotificationAdapterModule oldModule, final java.lang.AutoCloseable oldInstance) {
         super(identifier, dependencyResolver, oldModule, oldInstance);
     }
 
@@ -34,7 +33,7 @@ public class BindingNotificationAdapterModule extends AbstractBindingNotificatio
         final BindingToNormalizedNodeCodec codec = getBindingMappingServiceDependency();
         final Broker.ProviderSession session = getDomAsyncBrokerDependency().registerProvider(new DummyDOMProvider());
         final DOMNotificationService notifService = session.getService(DOMNotificationService.class);
-        return new BindingDOMNotificationServiceAdapter(codec.getCodecRegistry(), notifService, SingletonHolder.INVOKER_FACTORY);
+        return new BindingDOMNotificationServiceAdapter(codec.getCodecRegistry(), notifService);
     }
 
 }
index 415c9783da4891bf151afed1eb4b946a0531f1cb..58d5a855658879ad242a4dc24c3d465bd82eec52 100644 (file)
@@ -7,9 +7,12 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
-import com.google.common.util.concurrent.ListeningExecutorService;
+import org.opendaylight.controller.md.sal.binding.compat.HydrogenNotificationBrokerImpl;
+
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.binding.compat.HeliumNotificationProviderServiceAdapter;
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
 
 /**
 *
@@ -17,14 +20,14 @@ import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
 public final class NotificationBrokerImplModule extends
         org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractNotificationBrokerImplModule {
 
-    public NotificationBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+    public NotificationBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
 
-    public NotificationBrokerImplModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
-            NotificationBrokerImplModule oldModule, java.lang.AutoCloseable oldInstance) {
+    public NotificationBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            final NotificationBrokerImplModule oldModule, final java.lang.AutoCloseable oldInstance) {
         super(identifier, dependencyResolver, oldModule, oldInstance);
     }
 
@@ -37,14 +40,20 @@ public final class NotificationBrokerImplModule extends
     @Override
     public java.lang.AutoCloseable createInstance() {
 
+        final NotificationPublishService notificationPublishService = getNotificationPublishAdapterDependency();
+        final NotificationService notificationService = getNotificationAdapterDependency();
+
+        if(notificationPublishService != null & notificationService != null) {
+            return new HeliumNotificationProviderServiceAdapter(notificationPublishService, notificationService);
+        }
+
         /*
          *  FIXME: Switch to new broker (which has different threading model)
          *  once this change is communicated with downstream users or
          *  we will have adapter implementation which will honor Helium
          *  threading model for notifications.
          */
-        ListeningExecutorService listeningExecutor = SingletonHolder.getDefaultNotificationExecutor();
-        NotificationBrokerImpl broker = new NotificationBrokerImpl(listeningExecutor);
-        return broker;
+
+        return new HydrogenNotificationBrokerImpl(SingletonHolder.getDefaultNotificationExecutor());
     }
 }
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.yangtools.yang.binding.Notification;
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import java.util.Set;
 import java.util.concurrent.ExecutorService;
@@ -28,15 +28,15 @@ import com.google.common.base.Preconditions;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Multimap;
 
-public class NotificationBrokerImpl implements NotificationProviderService, AutoCloseable {
-    private static final Logger LOG = LoggerFactory.getLogger(NotificationBrokerImpl.class);
+public class HydrogenNotificationBrokerImpl implements NotificationProviderService, AutoCloseable {
+    private static final Logger LOG = LoggerFactory.getLogger(HydrogenNotificationBrokerImpl.class);
 
     private final ListenerRegistry<NotificationInterestListener> interestListeners =
             ListenerRegistry.create();
     private final AtomicReference<ListenerMapGeneration> listeners = new AtomicReference<>(new ListenerMapGeneration());
     private final ExecutorService executor;
 
-    public NotificationBrokerImpl(final ExecutorService executor) {
+    public HydrogenNotificationBrokerImpl(final ExecutorService executor) {
         this.executor = Preconditions.checkNotNull(executor);
     }
 
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import java.util.Arrays;
 import java.util.Collection;
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import org.opendaylight.controller.sal.binding.api.NotificationListener;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -5,7 +5,7 @@
  * 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.binding.impl;
+package org.opendaylight.controller.md.sal.binding.compat;
 
 import org.opendaylight.yangtools.yang.binding.Notification;
 import org.slf4j.Logger;
index cdf03fa5527d76c911cccb30cc6b40b586f08b6f..2a31d34d016a3e86d116b9c5e9c1f57fb775bd1f 100644 (file)
@@ -14,8 +14,6 @@ import org.opendaylight.controller.md.sal.binding.api.NotificationService;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMAdapterBuilder.Factory;
 import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
 import org.opendaylight.controller.md.sal.dom.api.DOMService;
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
 import org.opendaylight.yangtools.binding.data.codec.api.BindingNormalizedNodeSerializer;
 import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
@@ -34,7 +32,7 @@ public class BindingDOMNotificationServiceAdapter implements NotificationService
     private final BindingNormalizedNodeSerializer codec;
     private final DOMNotificationService domNotifService;
 
-    public BindingDOMNotificationServiceAdapter(final BindingNormalizedNodeSerializer codec, final DOMNotificationService domNotifService, final NotificationInvokerFactory notificationInvokerFactory) {
+    public BindingDOMNotificationServiceAdapter(final BindingNormalizedNodeSerializer codec, final DOMNotificationService domNotifService) {
         this.codec = codec;
         this.domNotifService = domNotifService;
     }
@@ -72,8 +70,7 @@ public class BindingDOMNotificationServiceAdapter implements NotificationService
         protected NotificationService createInstance(final BindingToNormalizedNodeCodec codec,
                 final ClassToInstanceMap<DOMService> delegates) {
             final DOMNotificationService domNotification = delegates.getInstance(DOMNotificationService.class);
-            final NotificationInvokerFactory invokerFactory = SingletonHolder.INVOKER_FACTORY;
-            return new BindingDOMNotificationServiceAdapter(codec.getCodecRegistry(), domNotification, invokerFactory);
+            return new BindingDOMNotificationServiceAdapter(codec.getCodecRegistry(), domNotification);
         }
 
         @Override
index ee130fdeeb87502a8a15780264e0dbfd0d255280..866cb844d189711458785614edaca761f2f3f850 100644 (file)
@@ -217,6 +217,29 @@ module opendaylight-sal-binding-broker-impl {
         }
     }
 
+    augment "/config:modules/config:module/config:configuration" {
+        case binding-notification-broker {
+            when "/config:modules/config:module/config:type = 'binding-notification-broker'";
+            container notification-adapter {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity binding-new-notification-service;
+                    }
+                }
+            }
+
+            container notification-publish-adapter {
+                uses config:service-ref {
+                    refine type {
+                        mandatory false;
+                        config:required-identity binding-new-notification-publish-service;
+                    }
+                }
+            }
+        }
+    }
+
     augment "/config:modules/config:module/config:state" {
         case binding-notification-broker {
             when "/config:modules/config:module/config:type = 'binding-notification-broker'";
index 547d3498c0e7bdec59b054203d3a56682a393c05..2647477c0f3e316f51983b0ad81ac9a5fb353310 100644 (file)
@@ -23,7 +23,6 @@ import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
 import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
 import org.opendaylight.controller.sal.binding.test.util.MockSchemaService;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
@@ -77,8 +76,7 @@ public class DataBrokerTestCustomizer {
     }
 
     public NotificationService createNotificationService() {
-        return new BindingDOMNotificationServiceAdapter(bindingToNormalized.getCodecRegistry(), domNotificationRouter,
-                SingletonHolder.INVOKER_FACTORY);
+        return new BindingDOMNotificationServiceAdapter(bindingToNormalized.getCodecRegistry(), domNotificationRouter);
     }
 
     public NotificationPublishService createNotificationPublishService() {
index a439e9ea262bfdfcf321367bc78c7a6eca1b0509..1203a72dc3616805c009d3a30a74edf3630a5e53 100644 (file)
@@ -20,19 +20,27 @@ import com.google.common.util.concurrent.MoreExecutors;
 import javassist.ClassPool;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.MountPointService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationPublishService;
+import org.opendaylight.controller.md.sal.binding.api.NotificationService;
+import org.opendaylight.controller.md.sal.binding.compat.HeliumNotificationProviderServiceAdapter;
 import org.opendaylight.controller.md.sal.binding.compat.HeliumRpcProviderRegistry;
 import org.opendaylight.controller.md.sal.binding.compat.HydrogenDataBrokerAdapter;
 import org.opendaylight.controller.md.sal.binding.compat.HydrogenMountProvisionServiceAdapter;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMDataBrokerAdapter;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMMountPointServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationPublishServiceAdapter;
+import org.opendaylight.controller.md.sal.binding.impl.BindingDOMNotificationServiceAdapter;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMRpcProviderServiceAdapter;
 import org.opendaylight.controller.md.sal.binding.impl.BindingDOMRpcServiceAdapter;
 import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationPublishService;
+import org.opendaylight.controller.md.sal.dom.api.DOMNotificationService;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcProviderService;
 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
+import org.opendaylight.controller.md.sal.dom.broker.impl.DOMNotificationRouter;
 import org.opendaylight.controller.md.sal.dom.broker.impl.DOMRpcRouter;
 import org.opendaylight.controller.md.sal.dom.broker.impl.SerializedDOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
@@ -41,7 +49,6 @@ import org.opendaylight.controller.sal.binding.api.RpcConsumerRegistry;
 import org.opendaylight.controller.sal.binding.api.RpcProviderRegistry;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.api.mount.MountProviderService;
-import org.opendaylight.controller.sal.binding.impl.NotificationBrokerImpl;
 import org.opendaylight.controller.sal.binding.impl.RootBindingAwareBroker;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.BrokerService;
@@ -65,7 +72,7 @@ public class BindingTestContext implements AutoCloseable {
 
     private RootBindingAwareBroker baBrokerImpl;
 
-    private NotificationBrokerImpl baNotifyImpl;
+    private HeliumNotificationProviderServiceAdapter baNotifyImpl;
 
 
     private BrokerImpl biBrokerImpl;
@@ -93,6 +100,14 @@ public class BindingTestContext implements AutoCloseable {
     private BindingDOMRpcProviderServiceAdapter baProviderRpc;
     private DOMRpcRouter domRouter;
 
+    private NotificationPublishService publishService;
+
+    private NotificationService listenService;
+
+    private DOMNotificationPublishService domPublishService;
+
+    private DOMNotificationService domListenService;
+
 
 
     public DOMDataBroker getDomAsyncDataBroker() {
@@ -249,7 +264,12 @@ public class BindingTestContext implements AutoCloseable {
 
     public void startBindingNotificationBroker() {
         checkState(executor != null);
-        baNotifyImpl = new NotificationBrokerImpl(executor);
+        final DOMNotificationRouter router = DOMNotificationRouter.create(16);
+        domPublishService = router;
+        domListenService = router;
+        publishService = new BindingDOMNotificationPublishServiceAdapter(codec, domPublishService);
+        listenService = new BindingDOMNotificationServiceAdapter(codec, domListenService);
+        baNotifyImpl = new HeliumNotificationProviderServiceAdapter(publishService,listenService);
 
     }
 
index f9c4a043e566b00eabe5b76db8b9809e53a79f21..7bfe254b17e9aa22b3d4ea80c0d664db510acfe9 100644 (file)
                 <module>
                             <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
                             <name>binding-notification-broker</name>
+                    <notification-adapter xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                         <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-new-notification-service</type>
+                         <name>binding-notification-adapter</name>
+                    </notification-adapter>
+                    <notification-publish-adapter xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                         <type  xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-new-notification-publish-service</type>
+                         <name>binding-notification-publish-adapter</name>
+                    </notification-publish-adapter>
                         </module>
                         <module>
                             <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
                         <module>
                             <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
                             <name>inmemory-data-broker</name>
+
                             <schema-service>
                                 <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
                                 <name>yang-schema-service</name>
                             </schema-service>
+
+                   <config-data-store>
+                        <type xmlns:config-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:config-dom-store">config-dom-store-spi:config-dom-datastore</type>
+                        <name>config-store-service</name>
+                    </config-data-store>
+
+                    <operational-data-store>
+                        <type xmlns:operational-dom-store-spi="urn:opendaylight:params:xml:ns:yang:controller:md:sal:core:spi:operational-dom-store">operational-dom-store-spi:operational-dom-datastore</type>
+                        <name>operational-store-service</name>
+                    </operational-data-store>
                         </module>
                         <module>
                             <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataTreeListenerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataTreeListenerTest.java
new file mode 100644 (file)
index 0000000..c3038ca
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.broker.impl;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.CONFIGURATION;
+import static org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType.OPERATIONAL;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ForwardingExecutorService;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Nonnull;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitDeadlockException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBrokerExtension;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeChangeService;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataTreeIdentifier;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
+import org.opendaylight.controller.sal.core.spi.data.DOMStore;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.concurrent.DeadlockDetectingListeningExecutorService;
+import org.opendaylight.yangtools.util.concurrent.SpecialExecutors;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
+import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
+import org.opendaylight.yangtools.yang.data.api.schema.MapNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidateNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ModificationType;
+import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class DOMDataTreeListenerTest {
+
+    private SchemaContext schemaContext;
+    private AbstractDOMDataBroker domBroker;
+    private ListeningExecutorService executor;
+    private ExecutorService futureExecutor;
+    private CommitExecutorService commitExecutor;
+
+    private static final DataContainerChild<?, ?> OUTER_LIST = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+            .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1))
+            .build();
+
+    private static final DataContainerChild<?, ?> OUTER_LIST_2 = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+            .withChild(ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2))
+            .build();
+
+    private static final NormalizedNode<?, ?> TEST_CONTAINER = Builders.containerBuilder()
+            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+            .withChild(OUTER_LIST)
+            .build();
+
+    private static final NormalizedNode<?, ?> TEST_CONTAINER_2 = Builders.containerBuilder()
+            .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(TestModel.TEST_QNAME))
+            .withChild(OUTER_LIST_2)
+            .build();
+
+    private static DOMDataTreeIdentifier ROOT_DATA_TREE_ID = new DOMDataTreeIdentifier(
+            LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
+
+    private static DOMDataTreeIdentifier OUTER_LIST_DATA_TREE_ID = new DOMDataTreeIdentifier(
+            LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH);
+
+    @Before
+    public void setupStore() {
+        InMemoryDOMDataStore operStore = new InMemoryDOMDataStore("OPER",
+                MoreExecutors.newDirectExecutorService());
+        InMemoryDOMDataStore configStore = new InMemoryDOMDataStore("CFG",
+                MoreExecutors.newDirectExecutorService());
+        schemaContext = TestModel.createTestContext();
+
+        operStore.onGlobalContextUpdated(schemaContext);
+        configStore.onGlobalContextUpdated(schemaContext);
+
+        ImmutableMap<LogicalDatastoreType, DOMStore> stores = ImmutableMap.<LogicalDatastoreType, DOMStore>builder() //
+                .put(CONFIGURATION, configStore) //
+                .put(OPERATIONAL, operStore) //
+                .build();
+
+        commitExecutor = new CommitExecutorService(Executors.newSingleThreadExecutor());
+        futureExecutor = SpecialExecutors.newBlockingBoundedCachedThreadPool(1, 5, "FCB");
+        executor = new DeadlockDetectingListeningExecutorService(commitExecutor,
+                TransactionCommitDeadlockException.DEADLOCK_EXCEPTION_SUPPLIER, futureExecutor);
+        domBroker = new SerializedDOMDataBroker(stores, executor);
+    }
+
+    @After
+    public void tearDown() {
+        if (executor != null) {
+            executor.shutdownNow();
+        }
+
+        if (futureExecutor != null) {
+            futureExecutor.shutdownNow();
+        }
+    }
+
+    @Test
+    public void writeContainerEmptyTreeTest() throws InterruptedException {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);
+
+        final DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit();
+
+        latch.await(5, TimeUnit.SECONDS);
+
+        assertEquals(1, listener.getReceivedChanges().size());
+        final Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);
+        listenerReg.close();
+    }
+
+    @Test
+    public void replaceContainerContainerInTreeTest() throws InterruptedException, TransactionCommitFailedException {
+        CountDownLatch latch = new CountDownLatch(2);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit().checkedGet();
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);
+        writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER_2);
+        writeTx.submit();
+
+        latch.await(5, TimeUnit.SECONDS);
+
+        assertEquals(2, listener.getReceivedChanges().size());
+        Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);
+
+        changes = listener.getReceivedChanges().get(1);
+        assertEquals(1, changes.size());
+
+        candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        candidateRoot = candidate.getRootNode();
+        checkChange(TEST_CONTAINER, TEST_CONTAINER_2, ModificationType.WRITE, candidateRoot);
+        listenerReg.close();
+    }
+
+    @Test
+    public void deleteContainerContainerInTreeTest() throws InterruptedException, TransactionCommitFailedException {
+        CountDownLatch latch = new CountDownLatch(2);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit().checkedGet();
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);
+
+        writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH);
+        writeTx.submit();
+
+        latch.await(5, TimeUnit.SECONDS);
+
+        assertEquals(2, listener.getReceivedChanges().size());
+        Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);
+
+        changes = listener.getReceivedChanges().get(1);
+        assertEquals(1, changes.size());
+
+        candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        candidateRoot = candidate.getRootNode();
+        checkChange(TEST_CONTAINER, null, ModificationType.DELETE, candidateRoot);
+        listenerReg.close();
+    }
+
+    @Test
+    public void replaceChildListContainerInTreeTest() throws InterruptedException, TransactionCommitFailedException {
+        CountDownLatch latch = new CountDownLatch(2);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit().checkedGet();
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(ROOT_DATA_TREE_ID, listener);
+
+        writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH, OUTER_LIST_2);
+        writeTx.submit();
+
+        latch.await(5, TimeUnit.SECONDS);
+
+        assertEquals(2, listener.getReceivedChanges().size());
+        Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, TEST_CONTAINER, ModificationType.WRITE, candidateRoot);
+
+        changes = listener.getReceivedChanges().get(1);
+        assertEquals(1, changes.size());
+
+        candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        candidateRoot = candidate.getRootNode();
+        checkChange(TEST_CONTAINER, TEST_CONTAINER_2, ModificationType.SUBTREE_MODIFIED, candidateRoot);
+        final DataTreeCandidateNode modifiedChild = candidateRoot.getModifiedChild(
+                new YangInstanceIdentifier.NodeIdentifier(TestModel.OUTER_LIST_QNAME));
+        assertNotNull(modifiedChild);
+        checkChange(OUTER_LIST, OUTER_LIST_2, ModificationType.WRITE, modifiedChild);
+        listenerReg.close();
+    }
+
+    @Test
+    public void rootModificationChildListenerTest() throws InterruptedException, TransactionCommitFailedException {
+        CountDownLatch latch = new CountDownLatch(2);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit().checkedGet();
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(OUTER_LIST_DATA_TREE_ID, listener);
+
+        writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER_2);
+        writeTx.submit().checkedGet();
+
+        latch.await(1, TimeUnit.SECONDS);
+
+        assertEquals(2, listener.getReceivedChanges().size());
+        Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, OUTER_LIST, ModificationType.WRITE, candidateRoot);
+
+        changes = listener.getReceivedChanges().get(1);
+        assertEquals(1, changes.size());
+
+        candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        candidateRoot = candidate.getRootNode();
+        checkChange(OUTER_LIST, OUTER_LIST_2, ModificationType.WRITE, candidateRoot);
+        listenerReg.close();
+    }
+
+    @Test
+    public void listEntryChangeNonRootRegistrationTest() throws InterruptedException, TransactionCommitFailedException {
+        CountDownLatch latch = new CountDownLatch(2);
+
+        DOMDataTreeChangeService dataTreeChangeService = getDOMDataTreeChangeService();
+        assertNotNull("DOMDataTreeChangeService not found, cannot continue with test!",
+                dataTreeChangeService);
+
+        DOMDataWriteTransaction writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.TEST_PATH, TEST_CONTAINER);
+        writeTx.submit().checkedGet();
+
+        final TestDataTreeListener listener = new TestDataTreeListener(latch);
+        final ListenerRegistration<TestDataTreeListener> listenerReg =
+                dataTreeChangeService.registerDataTreeChangeListener(OUTER_LIST_DATA_TREE_ID, listener);
+
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId1 =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId2 =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
+        final YangInstanceIdentifier.NodeIdentifierWithPredicates outerListEntryId3 =
+                new YangInstanceIdentifier.NodeIdentifierWithPredicates(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);
+
+        final MapEntryNode outerListEntry1 = ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 1);
+        final MapEntryNode outerListEntry2 = ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 2);
+        final MapEntryNode outerListEntry3 = ImmutableNodes.mapEntry(TestModel.OUTER_LIST_QNAME, TestModel.ID_QNAME, 3);
+
+        final MapNode listAfter = ImmutableNodes.mapNodeBuilder(TestModel.OUTER_LIST_QNAME)
+                .withChild(outerListEntry2)
+                .withChild(outerListEntry3)
+                .build();
+
+        writeTx = domBroker.newWriteOnlyTransaction();
+        writeTx.delete(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH.node(outerListEntryId1));
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH.node(outerListEntryId2),
+                outerListEntry2);
+        writeTx.put(LogicalDatastoreType.CONFIGURATION, TestModel.OUTER_LIST_PATH.node(outerListEntryId3),
+                outerListEntry3);
+        writeTx.submit();
+
+        latch.await(5, TimeUnit.SECONDS);
+
+        assertEquals(2, listener.getReceivedChanges().size());
+        Collection<DataTreeCandidate> changes = listener.getReceivedChanges().get(0);
+        assertEquals(1, changes.size());
+
+        DataTreeCandidate candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        DataTreeCandidateNode candidateRoot = candidate.getRootNode();
+        checkChange(null, OUTER_LIST, ModificationType.WRITE, candidateRoot);
+
+        changes = listener.getReceivedChanges().get(1);
+        assertEquals(1, changes.size());
+
+        candidate = changes.iterator().next();
+        assertNotNull(candidate);
+        candidateRoot = candidate.getRootNode();
+        checkChange(OUTER_LIST, listAfter, ModificationType.SUBTREE_MODIFIED, candidateRoot);
+        final DataTreeCandidateNode entry1Canditate = candidateRoot.getModifiedChild(outerListEntryId1);
+        checkChange(outerListEntry1, null, ModificationType.DELETE, entry1Canditate);
+        final DataTreeCandidateNode entry2Canditate = candidateRoot.getModifiedChild(outerListEntryId2);
+        checkChange(null, outerListEntry2, ModificationType.WRITE, entry2Canditate);
+        final DataTreeCandidateNode entry3Canditate = candidateRoot.getModifiedChild(outerListEntryId3);
+        checkChange(null, outerListEntry3, ModificationType.WRITE, entry3Canditate);
+        listenerReg.close();
+    }
+
+    private static void checkChange(NormalizedNode<?, ?> expectedBefore,
+                                    NormalizedNode<?, ?> expectedAfter,
+                                    ModificationType expectedMod,
+                                    DataTreeCandidateNode candidateNode) {
+        if (expectedBefore != null) {
+            assertTrue(candidateNode.getDataBefore().isPresent());
+            assertEquals(expectedBefore, candidateNode.getDataBefore().get());
+        } else {
+            assertFalse(candidateNode.getDataBefore().isPresent());
+        }
+
+        if (expectedAfter != null) {
+            assertTrue(candidateNode.getDataAfter().isPresent());
+            assertEquals(expectedAfter, candidateNode.getDataAfter().get());
+        } else {
+            assertFalse(candidateNode.getDataAfter().isPresent());
+        }
+
+        assertEquals(expectedMod, candidateNode.getModificationType());
+    }
+
+    private DOMDataTreeChangeService getDOMDataTreeChangeService() {
+        final DOMDataBrokerExtension extension = domBroker.getSupportedExtensions()
+                .get(DOMDataTreeChangeService.class);
+        if (extension == null) {
+            return null;
+        }
+        DOMDataTreeChangeService dataTreeChangeService = null;
+        if (extension instanceof DOMDataTreeChangeService) {
+            dataTreeChangeService = (DOMDataTreeChangeService) extension;
+        }
+        return dataTreeChangeService;
+    }
+
+
+    static class CommitExecutorService extends ForwardingExecutorService {
+
+        ExecutorService delegate;
+
+        public CommitExecutorService(final ExecutorService delegate) {
+            this.delegate = delegate;
+        }
+
+        @Override
+        protected ExecutorService delegate() {
+            return delegate;
+        }
+    }
+
+    static class TestDataTreeListener implements DOMDataTreeChangeListener {
+
+        private List<Collection<DataTreeCandidate>> receivedChanges = new ArrayList<>();
+        private CountDownLatch latch;
+
+        public TestDataTreeListener(final CountDownLatch latch) {
+            this.latch = latch;
+        }
+
+        @Override
+        public void onDataTreeChanged(@Nonnull final Collection<DataTreeCandidate> changes) {
+            receivedChanges.add(changes);
+            latch.countDown();
+        }
+
+        public List<Collection<DataTreeCandidate>> getReceivedChanges() {
+            return receivedChanges;
+        }
+    }
+}