Merge "Removed getClass comparison if FlowComparator."
authorTony Tkacik <ttkacik@cisco.com>
Fri, 22 Aug 2014 10:52:15 +0000 (10:52 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Fri, 22 Aug 2014 10:52:15 +0000 (10:52 +0000)
61 files changed:
features/config-netty/pom.xml
features/config/pom.xml
features/mdsal/pom.xml
features/netconf/pom.xml
opendaylight/md-sal/forwardingrules-manager/src/main/java/org/opendaylight/controller/frm/reconil/FlowNodeReconcilListener.java
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/FlowCapableInventoryProvider.java
opendaylight/md-sal/inventory-manager/src/main/java/org/opendaylight/controller/md/inventory/manager/NodeChangeCommiter.java
opendaylight/md-sal/sal-binding-broker/pom.xml
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/BindingAsyncDataBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/ForwardedCompatibleDataBrokerImplModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/RuntimeMappingModule.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractForwardedDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingToNormalizedNodeCodec.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBindingDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/codegen/impl/SingletonHolder.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java [deleted file]
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java [deleted file]
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/impl/test/BindingNormalizedCodecTest.java
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/compat/MultipleAugmentationPutsTest.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/main/java/org/opendaylight/controller/test/sal/binding/it/TestHelper.java
opendaylight/md-sal/sal-binding-it/src/test/java/org/opendaylight/controller/test/sal/binding/it/DataServiceTest.java
opendaylight/md-sal/sal-binding-it/src/test/resources/controller.xml
opendaylight/md-sal/sal-clustering-commons/src/test/java/org/opendaylight/controller/common/actor/MeteredBoundedMailboxTest.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ShardManager.java
opendaylight/md-sal/sal-distributed-datastore/src/main/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohort.java
opendaylight/md-sal/sal-distributed-datastore/src/test/java/org/opendaylight/controller/cluster/datastore/ThreePhaseCommitCohortFailureTest.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ChangeListenerNotifyTask.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/DOMImmutableDataChangeEvent.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/InMemoryDOMDataStore.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeEventsTask.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/AbstractDataChangeListenerTest.java
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/DefaultDataChangeListenerTestSuite.java
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/WildcardedScopeBaseTest.java
opendaylight/md-sal/sal-inmemory-datastore/src/test/java/org/opendaylight/controller/md/sal/dom/store/impl/WildcardedScopeOneTest.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/listener/NetconfSessionCapabilities.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/RpcRegistry.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/BucketStore.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/remote/rpc/registry/gossip/Gossiper.java
opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/utils/ConditionalProbe.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
opendaylight/md-sal/sal-remoterpc-connector/src/test/java/org/opendaylight/controller/remote/rpc/registry/gossip/GossiperTest.java
opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/application.conf
opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/logback.xml [new file with mode: 0644]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/RestconfDocumentedException.java
opendaylight/md-sal/topology-manager/src/main/java/org/opendaylight/md/controller/topology/manager/FlowCapableTopologyExporter.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSession.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientSessionNegotiator.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshClientAdapter.java
opendaylight/netconf/netconf-netty-util/src/main/java/org/opendaylight/controller/netconf/nettyutil/handler/ssh/client/SshSession.java
opendaylight/netconf/netconf-ssh/src/main/java/org/opendaylight/controller/netconf/ssh/threads/Handshaker.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/Main.java
opendaylight/netconf/netconf-testtool/src/main/java/org/opendaylight/controller/netconf/test/tool/NetconfDeviceSimulator.java
pom.xml

index 5fbc463..bf03697 100644 (file)
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>config-netty-config</artifactId>
+      <!--
+        note, the reason the type and classifier
+        are here instead of in opendaylight/commons/opendaylight/pom.xml
+        is because they are used as jars in distribution.
+      -->
+      <version>${config.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
index 8c061c2..20feceb 100644 (file)
   </properties>
 
   <dependencies>
+    <!-- dependency for opendaylight-karaf-empty for use by testing -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>opendaylight-karaf-empty</artifactId>
+      <version>1.4.2-SNAPSHOT</version>
+      <type>zip</type>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>features-yangtools</artifactId>
index e7b825c..ac6b82b 100644 (file)
@@ -83,6 +83,9 @@
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>md-sal-config</artifactId>
+      <version>${mdsal.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-connector-config</artifactId>
+      <version>${netconf.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>sal-rest-connector-config</artifactId>
+      <version>${mdsal.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller.samples</groupId>
     <dependency>
       <groupId>org.opendaylight.controller.samples</groupId>
       <artifactId>toaster-config</artifactId>
+      <version>${mdsal.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <!-- test to validate features.xml -->
     <dependency>
index 956a67e..106e54a 100644 (file)
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
       <artifactId>netconf-config</artifactId>
+      <version>${config.version}</version>
+      <type>xml</type>
+      <classifier>config</classifier>
     </dependency>
     <dependency>
       <groupId>org.opendaylight.controller</groupId>
index eb5ae4a..6308f2a 100644 (file)
@@ -8,11 +8,14 @@
 
 package org.opendaylight.controller.frm.reconil;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
 import java.util.concurrent.ExecutionException;
-
 import org.opendaylight.controller.frm.AbstractChangeListener;
 import org.opendaylight.controller.frm.FlowCookieProducer;
 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
@@ -38,10 +41,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.util.concurrent.ListenableFuture;
-
 /**
  * forwardingrules-manager
  * org.opendaylight.controller.frm
@@ -65,7 +64,7 @@ public class FlowNodeReconcilListener extends AbstractChangeListener {
     }
 
     @Override
-    public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
+    public void onDataChanged(final AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> changeEvent) {
         /* FlowCapableNode DataObjects for reconciliation */
         final Set<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> createdEntries =
                 changeEvent.getCreatedData().entrySet();
@@ -118,34 +117,46 @@ public class FlowNodeReconcilListener extends AbstractChangeListener {
             final InstanceIdentifier<Node> nodeIdent = identifier.firstIdentifierOf(Node.class);
             final NodeRef nodeRef = new NodeRef(nodeIdent);
             /* Groups - have to be first */
-            for (Group group : flowCapNode.get().getGroup()) {
-                final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
-                final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
-                groupBuilder.setGroupRef(groupRef);
-                groupBuilder.setNode(nodeRef);
-                this.provider.getSalGroupService().addGroup(groupBuilder.build());
+            List<Group> groups = flowCapNode.get().getGroup();
+            if(groups != null) {
+                for (Group group : groups) {
+                    final GroupRef groupRef = new GroupRef(flowNodeIdent.child(Group.class, group.getKey()));
+                    final AddGroupInputBuilder groupBuilder = new AddGroupInputBuilder(group);
+                    groupBuilder.setGroupRef(groupRef);
+                    groupBuilder.setNode(nodeRef);
+                    this.provider.getSalGroupService().addGroup(groupBuilder.build());
+                }
             }
             /* Meters */
-            for (Meter meter : flowCapNode.get().getMeter()) {
-                final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
-                final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
-                meterBuilder.setMeterRef(meterRef);
-                meterBuilder.setNode(nodeRef);
-                this.provider.getSalMeterService().addMeter(meterBuilder.build());
+            List<Meter> meters = flowCapNode.get().getMeter();
+            if(meters != null) {
+                for (Meter meter : meters) {
+                    final MeterRef meterRef = new MeterRef(flowNodeIdent.child(Meter.class, meter.getKey()));
+                    final AddMeterInputBuilder meterBuilder = new AddMeterInputBuilder(meter);
+                    meterBuilder.setMeterRef(meterRef);
+                    meterBuilder.setNode(nodeRef);
+                    this.provider.getSalMeterService().addMeter(meterBuilder.build());
+                }
             }
             /* Flows */
-            for (Table flowTable : flowCapNode.get().getTable()) {
-                final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
-                for (Flow flow : flowTable.getFlow()) {
-                    final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
-                    final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
-                    final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
-                    final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
-                    flowBuilder.setCookie(flowCookie);
-                    flowBuilder.setNode(nodeRef);
-                    flowBuilder.setFlowTable(flowTableRef);
-                    flowBuilder.setFlowRef(flowRef);
-                    this.provider.getSalFlowService().addFlow(flowBuilder.build());
+            List<Table> tables = flowCapNode.get().getTable();
+            if(tables != null) {
+                for (Table flowTable : tables) {
+                    final InstanceIdentifier<Table> tableIdent = flowNodeIdent.child(Table.class, flowTable.getKey());
+                    List<Flow> flows = flowTable.getFlow();
+                    if(flows != null) {
+                        for (Flow flow : flows) {
+                            final FlowCookie flowCookie = new FlowCookie(FlowCookieProducer.INSTANCE.getNewCookie(tableIdent));
+                            final FlowRef flowRef = new FlowRef(tableIdent.child(Flow.class, flow.getKey()));
+                            final FlowTableRef flowTableRef = new FlowTableRef(tableIdent);
+                            final AddFlowInputBuilder flowBuilder = new AddFlowInputBuilder(flow);
+                            flowBuilder.setCookie(flowCookie);
+                            flowBuilder.setNode(nodeRef);
+                            flowBuilder.setFlowTable(flowTableRef);
+                            flowBuilder.setFlowRef(flowRef);
+                            this.provider.getSalFlowService().addFlow(flowBuilder.build());
+                        }
+                    }
                 }
             }
         }
@@ -153,7 +164,7 @@ public class FlowNodeReconcilListener extends AbstractChangeListener {
 
     @Override
     protected void update(final InstanceIdentifier<? extends DataObject> identifier,
-                          final DataObject original, DataObject update) {
+                          final DataObject original, final DataObject update) {
         // NOOP - Listener is registered for DataChangeScope.BASE only
     }
 
index 29ac123..1e77a55 100644 (file)
@@ -13,15 +13,19 @@ import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.LinkedBlockingDeque;
+import org.opendaylight.controller.md.sal.binding.api.BindingTransactionChain;
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChain;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
+class FlowCapableInventoryProvider implements AutoCloseable, Runnable, TransactionChainListener {
     private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
     private static final int QUEUE_DEPTH = 500;
     private static final int MAX_BATCH = 100;
@@ -30,6 +34,7 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
     private final NotificationProviderService notificationService;
 
     private final DataBroker dataBroker;
+    private BindingTransactionChain txChain;
     private ListenerRegistration<?> listenerRegistration;
     private Thread thread;
 
@@ -42,6 +47,7 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
         final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
         this.listenerRegistration = this.notificationService.registerNotificationListener(changeCommiter);
 
+        this.txChain =  dataBroker.createTransactionChain(this);
         thread = new Thread(this);
         thread.setDaemon(true);
         thread.setName("FlowCapableInventoryProvider");
@@ -75,6 +81,10 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
             thread.join();
             thread = null;
         }
+        if(txChain != null) {
+            txChain.close();
+            txChain = null;
+        }
 
 
     }
@@ -85,7 +95,7 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
             for (; ; ) {
                 InventoryOperation op = queue.take();
 
-                final ReadWriteTransaction tx = dataBroker.newReadWriteTransaction();
+                final ReadWriteTransaction tx = txChain.newReadWriteTransaction();
                 LOG.debug("New operations available, starting transaction {}", tx.getIdentifier());
 
                 int ops = 0;
@@ -105,12 +115,12 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
                 final CheckedFuture<Void, TransactionCommitFailedException> result = tx.submit();
                 Futures.addCallback(result, new FutureCallback<Void>() {
                     @Override
-                    public void onSuccess(Void aVoid) {
+                    public void onSuccess(final Void aVoid) {
                         //NOOP
                     }
 
                     @Override
-                    public void onFailure(Throwable throwable) {
+                    public void onFailure(final Throwable throwable) {
                         LOG.error("Transaction {} failed.", tx.getIdentifier(), throwable);
                     }
                 });
@@ -124,4 +134,16 @@ class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
             queue.poll();
         }
     }
+
+    @Override
+    public void onTransactionChainFailed(final TransactionChain<?, ?> chain, final AsyncTransaction<?, ?> transaction,
+            final Throwable cause) {
+        LOG.error("Failed to export Flow Capable Inventory, Transaction {} failed.",transaction.getIdentifier(),cause);
+
+    }
+
+    @Override
+    public void onTransactionChainSuccessful(final TransactionChain<?, ?> chain) {
+        // NOOP
+    }
 }
index 57ec893..b14bfd4 100644 (file)
@@ -32,8 +32,6 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.No
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorBuilder;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnectorKey;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
@@ -81,7 +79,7 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
                 InstanceIdentifier<NodeConnector> value = (InstanceIdentifier<NodeConnector>) ref.getValue();
                 LOG.debug("updating node connector : {}.", value);
                 NodeConnector build = data.build();
-                tx.put(LogicalDatastoreType.OPERATIONAL, value, build);
+                tx.merge(LogicalDatastoreType.OPERATIONAL, value, build, true);
             }
         });
     }
@@ -139,13 +137,9 @@ class NodeChangeCommiter implements OpendaylightInventoryListener {
         manager.enqueue(new InventoryOperation() {
             @Override
             public void applyOperation(final ReadWriteTransaction tx) {
-                final NodeBuilder nodeBuilder = new NodeBuilder(node);
-                nodeBuilder.setKey(new NodeKey(node.getId()));
-
                 final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
-                nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
                 LOG.debug("updating node :{} ", path);
-                tx.put(LogicalDatastoreType.OPERATIONAL, path, augment);
+                tx.merge(LogicalDatastoreType.OPERATIONAL, path, augment, true);
             }
         });
     }
index 74cceb1..539f9d4 100644 (file)
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>binding-generator-impl</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>binding-data-codec</artifactId>
+      <version>0.6.2-SNAPSHOT</version>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-data-impl</artifactId>
index 018e268..93d99c8 100644 (file)
@@ -2,14 +2,13 @@ package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
 import java.util.Collection;
 import java.util.Collections;
-
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 
 public class BindingAsyncDataBrokerImplModule extends
         org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractBindingAsyncDataBrokerImplModule implements
@@ -36,7 +35,7 @@ public class BindingAsyncDataBrokerImplModule extends
     @Override
     public java.lang.AutoCloseable createInstance() {
         Broker domBroker = getDomAsyncBrokerDependency();
-        BindingIndependentMappingService mappingService = getBindingMappingServiceDependency();
+        BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency();
 
         // FIXME: Switch this to DOM Broker registration which would not require
         // BundleContext when API are updated.
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModule.java
deleted file mode 100644 (file)
index 4a4e800..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.config.yang.md.sal.binding.impl;
-
-import java.util.concurrent.ExecutorService;
-
-import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
-import org.opendaylight.controller.sal.binding.impl.forward.DomForwardedDataBrokerImpl;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-
-/**
-*
-*/
-public final class DataBrokerImplModule extends
-        org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModule {
-
-    public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
-        super(identifier, dependencyResolver);
-    }
-
-    public DataBrokerImplModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
-            final DataBrokerImplModule oldModule, final java.lang.AutoCloseable oldInstance) {
-        super(identifier, dependencyResolver, oldModule, oldInstance);
-    }
-
-    @Override
-    public void validate() {
-        super.validate();
-    }
-
-    @Override
-    public java.lang.AutoCloseable createInstance() {
-        RootDataBrokerImpl dataBindingBroker;
-
-
-        ExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor();
-        BindingIndependentMappingService potentialMapping = getMappingServiceDependency();
-        if (getDomBrokerDependency() != null && potentialMapping != null) {
-
-            dataBindingBroker = createDomConnectedBroker(listeningExecutor,potentialMapping);
-        } else {
-            dataBindingBroker = createStandAloneBroker(listeningExecutor);
-        }
-        dataBindingBroker.registerRuntimeBean(getRootRuntimeBeanRegistratorWrapper());
-        dataBindingBroker.setNotificationExecutor(SingletonHolder.getDefaultChangeEventExecutor());
-        return dataBindingBroker;
-    }
-
-
-    private RootDataBrokerImpl createStandAloneBroker(final ExecutorService listeningExecutor) {
-        RootDataBrokerImpl broker = new RootDataBrokerImpl();
-        broker.setExecutor(listeningExecutor);
-        return broker;
-    }
-
-    private RootDataBrokerImpl createDomConnectedBroker(final ExecutorService listeningExecutor, final BindingIndependentMappingService mappingService) {
-        DomForwardedDataBrokerImpl forwardedBroker = new DomForwardedDataBrokerImpl();
-        forwardedBroker.setExecutor(listeningExecutor);
-        BindingIndependentConnector connector = BindingDomConnectorDeployer.createConnector(mappingService);
-        getDomBrokerDependency().registerProvider(forwardedBroker, null);
-        ProviderSession domContext = forwardedBroker.getDomProviderContext();
-        forwardedBroker.setConnector(connector);
-        forwardedBroker.setDomProviderContext(domContext);
-        forwardedBroker.startForwarding();
-        return forwardedBroker;
-    }
-
-}
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/binding/impl/DataBrokerImplModuleFactory.java
deleted file mode 100644 (file)
index d3fc5ac..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * 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.config.yang.md.sal.binding.impl;
-
-
-/**
-*
-*/
-public class DataBrokerImplModuleFactory extends
-        org.opendaylight.controller.config.yang.md.sal.binding.impl.AbstractDataBrokerImplModuleFactory {
-
-}
index 0ea30f7..2bc673a 100644 (file)
@@ -7,9 +7,10 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
+import com.google.common.util.concurrent.ListeningExecutorService;
 import java.util.Collection;
 import java.util.Collections;
-
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
@@ -18,9 +19,6 @@ import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
 import org.opendaylight.controller.sal.core.api.Provider;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
-
-import com.google.common.util.concurrent.ListeningExecutorService;
 
 /**
 *
@@ -51,7 +49,7 @@ public final class ForwardedCompatibleDataBrokerImplModule extends
     @Override
     public java.lang.AutoCloseable createInstance() {
         ListeningExecutorService listeningExecutor = SingletonHolder.getDefaultCommitExecutor();
-        BindingIndependentMappingService mappingService = getBindingMappingServiceDependency();
+        BindingToNormalizedNodeCodec mappingService = getBindingMappingServiceDependency();
 
         Broker domBroker = getDomAsyncBrokerDependency();
         ProviderSession session = domBroker.registerProvider(this, null);
@@ -60,7 +58,7 @@ public final class ForwardedCompatibleDataBrokerImplModule extends
         ForwardedBackwardsCompatibleDataBroker dataBroker = new ForwardedBackwardsCompatibleDataBroker(domDataBroker,
                 mappingService, schemaService,listeningExecutor);
 
-        dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(getBindingMappingServiceDependency()));
+        dataBroker.setConnector(BindingDomConnectorDeployer.createConnector(mappingService.getLegacy()));
         dataBroker.setDomProviderContext(session);
         return dataBroker;
     }
index b0c2d74..a15b1d7 100644 (file)
@@ -7,12 +7,18 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.binding.impl;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
 import java.util.Hashtable;
 import java.util.Map.Entry;
 import java.util.Set;
-
+import javassist.ClassPool;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.sal.binding.codegen.impl.SingletonHolder;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
@@ -29,9 +35,6 @@ import org.osgi.framework.ServiceReference;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-
 /**
 *
 */
@@ -42,14 +45,14 @@ public final class RuntimeMappingModule extends
 
     private BundleContext bundleContext;
 
-    public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
+    public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver) {
         super(identifier, dependencyResolver);
     }
 
-    public RuntimeMappingModule(org.opendaylight.controller.config.api.ModuleIdentifier identifier,
-            org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
-            RuntimeMappingModule oldModule, java.lang.AutoCloseable oldInstance) {
+    public RuntimeMappingModule(final org.opendaylight.controller.config.api.ModuleIdentifier identifier,
+            final org.opendaylight.controller.config.api.DependencyResolver dependencyResolver,
+            final RuntimeMappingModule oldModule, final java.lang.AutoCloseable oldInstance) {
         super(identifier, dependencyResolver, oldModule, oldInstance);
     }
 
@@ -61,41 +64,48 @@ public final class RuntimeMappingModule extends
     }
 
     @Override
-    public boolean canReuseInstance(AbstractRuntimeMappingModule oldModule) {
+    public boolean canReuseInstance(final AbstractRuntimeMappingModule oldModule) {
         return true;
     }
 
     @Override
     public java.lang.AutoCloseable createInstance() {
+        final GeneratedClassLoadingStrategy classLoading = getGlobalClassLoadingStrategy();
+        final BindingIndependentMappingService legacyMapping = getGlobalLegacyMappingService(classLoading);
+        BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(new StreamWriterGenerator(SingletonHolder.JAVASSIST));
+        BindingToNormalizedNodeCodec instance = new BindingToNormalizedNodeCodec(classLoading, legacyMapping, codecRegistry);
+        bundleContext.registerService(SchemaContextListener.class, instance, new Hashtable<String,String>());
+        return instance;
+    }
 
-        RuntimeGeneratedMappingServiceProxy potential = tryToReuseGlobalInstance();
-        if(potential != null) {
-            return potential;
+    private BindingIndependentMappingService getGlobalLegacyMappingService(final GeneratedClassLoadingStrategy classLoading) {
+        BindingIndependentMappingService potential = tryToReuseGlobalMappingServiceInstance();
+        if(potential == null) {
+            potential =  new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault(),classLoading);
+            bundleContext.registerService(SchemaContextListener.class, (SchemaContextListener) potential, new Hashtable<String,String>());
         }
+        return potential;
+    }
 
-        final RuntimeGeneratedMappingServiceImpl service = new RuntimeGeneratedMappingServiceImpl(SingletonHolder.CLASS_POOL);
-        bundleContext.registerService(SchemaContextListener.class, service, new Hashtable<String,String>());
-        return service;
+    private GeneratedClassLoadingStrategy getGlobalClassLoadingStrategy() {
+        ServiceReference<GeneratedClassLoadingStrategy> ref = bundleContext.getServiceReference(GeneratedClassLoadingStrategy.class);
+        return bundleContext.getService(ref);
     }
 
-    private RuntimeGeneratedMappingServiceProxy tryToReuseGlobalInstance() {
+    private BindingIndependentMappingService tryToReuseGlobalMappingServiceInstance() {
         ServiceReference<BindingIndependentMappingService> serviceRef = getBundleContext().getServiceReference(BindingIndependentMappingService.class);
         if(serviceRef == null) {
             return null;
         }
+        return bundleContext.getService(serviceRef);
 
-        BindingIndependentMappingService delegate = bundleContext.getService(serviceRef);
-        if (delegate == null) {
-            return null;
-        }
-        return new RuntimeGeneratedMappingServiceProxy(getBundleContext(),serviceRef,delegate);
     }
 
     private BundleContext getBundleContext() {
         return bundleContext;
     }
 
-    public void setBundleContext(BundleContext bundleContext) {
+    public void setBundleContext(final BundleContext bundleContext) {
         this.bundleContext = bundleContext;
     }
 
@@ -108,9 +118,9 @@ public final class RuntimeMappingModule extends
         private ServiceReference<BindingIndependentMappingService> reference;
         private BundleContext bundleContext;
 
-        public RuntimeGeneratedMappingServiceProxy(BundleContext bundleContext,
-                ServiceReference<BindingIndependentMappingService> serviceRef,
-                BindingIndependentMappingService delegate) {
+        public RuntimeGeneratedMappingServiceProxy(final BundleContext bundleContext,
+                final ServiceReference<BindingIndependentMappingService> serviceRef,
+                final BindingIndependentMappingService delegate) {
             this.bundleContext = Preconditions.checkNotNull(bundleContext);
             this.reference = Preconditions.checkNotNull(serviceRef);
             this.delegate = Preconditions.checkNotNull(delegate);
@@ -122,47 +132,47 @@ public final class RuntimeMappingModule extends
         }
 
         @Override
-        public CompositeNode toDataDom(DataObject data) {
+        public CompositeNode toDataDom(final DataObject data) {
             return delegate.toDataDom(data);
         }
 
         @Override
         public Entry<YangInstanceIdentifier, CompositeNode> toDataDom(
-                Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
+                final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> entry) {
             return delegate.toDataDom(entry);
         }
 
         @Override
         public YangInstanceIdentifier toDataDom(
-                org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
+                final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path) {
             return delegate.toDataDom(path);
         }
 
         @Override
         public DataObject dataObjectFromDataDom(
-                org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path,
-                CompositeNode result) throws DeserializationException {
+                final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> path,
+                final CompositeNode result) throws DeserializationException {
             return delegate.dataObjectFromDataDom(path, result);
         }
 
         @Override
-        public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> fromDataDom(YangInstanceIdentifier entry)
+        public org.opendaylight.yangtools.yang.binding.InstanceIdentifier<?> fromDataDom(final YangInstanceIdentifier entry)
                 throws DeserializationException {
             return delegate.fromDataDom(entry);
         }
 
         @Override
-        public Set<QName> getRpcQNamesFor(Class<? extends RpcService> service) {
+        public Set<QName> getRpcQNamesFor(final Class<? extends RpcService> service) {
             return delegate.getRpcQNamesFor(service);
         }
 
         @Override
-        public Optional<Class<? extends RpcService>> getRpcServiceClassFor(String namespace, String revision) {
+        public Optional<Class<? extends RpcService>> getRpcServiceClassFor(final String namespace, final String revision) {
             return delegate.getRpcServiceClassFor(namespace,revision);
         }
 
         @Override
-        public DataContainer dataObjectFromDataDom(Class<? extends DataContainer> inputClass, CompositeNode domInput) {
+        public DataContainer dataObjectFromDataDom(final Class<? extends DataContainer> inputClass, final CompositeNode domInput) {
             return delegate.dataObjectFromDataDom(inputClass, domInput);
         }
 
index e632e63..f843b23 100644 (file)
@@ -9,7 +9,6 @@ package org.opendaylight.controller.md.sal.binding.impl;
 
 import com.google.common.base.Objects;
 import com.google.common.base.Optional;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
@@ -19,7 +18,6 @@ import java.util.Iterator;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Set;
-
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
@@ -37,33 +35,28 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, DomForwardedBroker, SchemaContextListener, AutoCloseable {
+public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBroker>, DomForwardedBroker,
+        SchemaContextListener, AutoCloseable {
 
     private static final Logger LOG = LoggerFactory.getLogger(AbstractForwardedDataBroker.class);
     // The Broker to whom we do all forwarding
     private final DOMDataBroker domDataBroker;
 
-    // Mapper to convert from Binding Independent objects to Binding Aware
-    // objects
-    private final BindingIndependentMappingService mappingService;
-
     private final BindingToNormalizedNodeCodec codec;
     private BindingIndependentConnector connector;
     private ProviderSession context;
     private final ListenerRegistration<SchemaContextListener> schemaListenerRegistration;
 
-    protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker,
-            final BindingIndependentMappingService mappingService,final SchemaService schemaService) {
+    protected AbstractForwardedDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec,
+            final SchemaService schemaService) {
         this.domDataBroker = domDataBroker;
-        this.mappingService = mappingService;
-        this.codec = new BindingToNormalizedNodeCodec(mappingService);
+        this.codec = codec;
         this.schemaListenerRegistration = schemaService.registerSchemaContextListener(this);
     }
 
@@ -71,10 +64,6 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         return codec;
     }
 
-    protected BindingIndependentMappingService getMappingService() {
-        return mappingService;
-    }
-
     @Override
     public DOMDataBroker getDelegate() {
         return domDataBroker;
@@ -82,12 +71,11 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
 
     @Override
     public void onGlobalContextUpdated(final SchemaContext ctx) {
-        codec.onGlobalContextUpdated(ctx);
+        // NOOP
     }
 
     public ListenerRegistration<DataChangeListener> registerDataChangeListener(final LogicalDatastoreType store,
-            final InstanceIdentifier<?> path, final DataChangeListener listener,
-            final DataChangeScope triggeringScope) {
+            final InstanceIdentifier<?> path, final DataChangeListener listener, final DataChangeScope triggeringScope) {
         DOMDataChangeListener domDataChangeListener = new TranslatingDataChangeInvoker(store, path, listener,
                 triggeringScope);
         YangInstanceIdentifier domPath = codec.toNormalized(path);
@@ -96,23 +84,16 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         return new ListenerRegistrationImpl(listener, domRegistration);
     }
 
-    protected Map<InstanceIdentifier<?>, DataObject> toBinding(
-            InstanceIdentifier<?> path,
+    protected Map<InstanceIdentifier<?>, DataObject> toBinding(final InstanceIdentifier<?> path,
             final Map<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized) {
         Map<InstanceIdentifier<?>, DataObject> newMap = new HashMap<>();
 
         for (Map.Entry<YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> entry : sortedEntries(normalized)) {
             try {
-                Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(
-                        entry);
+                Optional<Entry<InstanceIdentifier<? extends DataObject>, DataObject>> potential = getCodec().toBinding(entry);
                 if (potential.isPresent()) {
                     Entry<InstanceIdentifier<? extends DataObject>, DataObject> binding = potential.get();
                     newMap.put(binding.getKey(), binding.getValue());
-                } else if (entry.getKey().getLastPathArgument() instanceof YangInstanceIdentifier.AugmentationIdentifier) {
-                    DataObject bindingDataObject = getCodec().toBinding(path, entry.getValue());
-                    if (bindingDataObject != null) {
-                        newMap.put(path, bindingDataObject);
-                    }
                 }
             } catch (DeserializationException e) {
                 LOG.warn("Failed to transform {}, omitting it", entry, e);
@@ -123,8 +104,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
 
     private static final Comparator<Entry<YangInstanceIdentifier, ?>> MAP_ENTRY_COMPARATOR = new Comparator<Entry<YangInstanceIdentifier, ?>>() {
         @Override
-        public int compare(final Entry<YangInstanceIdentifier, ?> left,
-                final Entry<YangInstanceIdentifier, ?> right) {
+        public int compare(final Entry<YangInstanceIdentifier, ?> left, final Entry<YangInstanceIdentifier, ?> right) {
             final Iterator<?> li = left.getKey().getPathArguments().iterator();
             final Iterator<?> ri = right.getKey().getPathArguments().iterator();
 
@@ -144,7 +124,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         }
     };
 
-    private static <T> Iterable<Entry<YangInstanceIdentifier,T>> sortedEntries(final Map<YangInstanceIdentifier, T> map) {
+    private static <T> Iterable<Entry<YangInstanceIdentifier, T>> sortedEntries(final Map<YangInstanceIdentifier, T> map) {
         if (!map.isEmpty()) {
             ArrayList<Entry<YangInstanceIdentifier, T>> entries = new ArrayList<>(map.entrySet());
             Collections.sort(entries, MAP_ENTRY_COMPARATOR);
@@ -154,7 +134,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         }
     }
 
-    protected Set<InstanceIdentifier<?>> toBinding(InstanceIdentifier<?> path,
+    protected Set<InstanceIdentifier<?>> toBinding(final InstanceIdentifier<?> path,
             final Set<YangInstanceIdentifier> normalized) {
         Set<InstanceIdentifier<?>> hashSet = new HashSet<>();
         for (YangInstanceIdentifier normalizedPath : normalized) {
@@ -177,12 +157,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         if (path.isWildcarded()) {
             return Optional.absent();
         }
-
-        try {
-            return Optional.fromNullable(getCodec().toBinding(path, data));
-        } catch (DeserializationException e) {
-            return Optional.absent();
-        }
+        return (Optional) getCodec().deserializeFunction(path).apply(Optional.<NormalizedNode<?, ?>> of(data));
     }
 
     private class TranslatingDataChangeInvoker implements DOMDataChangeListener {
@@ -200,8 +175,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         }
 
         @Override
-        public void onDataChanged(
-                final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
+        public void onDataChanged(final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change) {
             bindingDataChangeListener.onDataChanged(new TranslatedDataChangeEvent(change, path));
         }
     }
@@ -261,7 +235,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         @Override
         public DataObject getOriginalSubtree() {
             if (originalDataCache == null) {
-                if(domEvent.getOriginalSubtree() != null) {
+                if (domEvent.getOriginalSubtree() != null) {
                     originalDataCache = toBindingData(path, domEvent.getOriginalSubtree());
                 } else {
                     originalDataCache = Optional.absent();
@@ -273,7 +247,7 @@ public abstract class AbstractForwardedDataBroker implements Delegator<DOMDataBr
         @Override
         public DataObject getUpdatedSubtree() {
             if (updatedDataCache == null) {
-                if(domEvent.getUpdatedSubtree() != null) {
+                if (domEvent.getUpdatedSubtree() != null) {
                     updatedDataCache = toBindingData(path, domEvent.getUpdatedSubtree());
                 } else {
                     updatedDataCache = Optional.absent();
index 66caaea..9ad35fc 100644 (file)
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
-import java.lang.reflect.Method;
-import java.util.AbstractMap.SimpleEntry;
-import java.util.Collection;
-import java.util.HashSet;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+
 import java.util.Iterator;
 import java.util.Map.Entry;
-import java.util.Set;
-
-import javax.annotation.Nullable;
 
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
-import org.opendaylight.yangtools.yang.binding.Augmentation;
-import org.opendaylight.yangtools.yang.binding.BindingMapping;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
+import org.opendaylight.yangtools.sal.binding.generator.util.BindingRuntimeContext;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
-import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
-import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
-import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
-import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException;
-import org.opendaylight.yangtools.yang.data.impl.schema.Builders;
-import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
-import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
-import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-
-public class BindingToNormalizedNodeCodec implements SchemaContextListener {
 
-    private static final Logger LOG = LoggerFactory.getLogger(BindingToNormalizedNodeCodec.class);
+public class BindingToNormalizedNodeCodec implements SchemaContextListener,AutoCloseable {
 
     private final BindingIndependentMappingService bindingToLegacy;
+    private final BindingNormalizedNodeCodecRegistry codecRegistry;
     private DataNormalizer legacyToNormalized;
+    private final GeneratedClassLoadingStrategy classLoadingStrategy;
 
-    public BindingToNormalizedNodeCodec(final BindingIndependentMappingService mappingService) {
+    public BindingToNormalizedNodeCodec(final GeneratedClassLoadingStrategy classLoadingStrategy, final BindingIndependentMappingService mappingService, final BindingNormalizedNodeCodecRegistry codecRegistry) {
         super();
         this.bindingToLegacy = mappingService;
+        this.classLoadingStrategy = classLoadingStrategy;
+        this.codecRegistry = codecRegistry;
+
     }
 
     public org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalized(
             final InstanceIdentifier<? extends DataObject> binding) {
-
-        // Used instance-identifier codec do not support serialization of last
-        // path
-        // argument if it is Augmentation (behaviour expected by old datastore)
-        // in this case, we explicitly check if last argument is augmentation
-        // to process it separately
-        if (isAugmentationIdentifier(binding)) {
-            return toNormalizedAugmented(binding);
-        }
-        return toNormalizedImpl(binding);
+        return codecRegistry.toYangInstanceIdentifier(binding);
     }
 
+    @SuppressWarnings({ "unchecked", "rawtypes" })
     public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
             final InstanceIdentifier<? extends DataObject> bindingPath, final DataObject bindingObject) {
-        return toNormalizedNode(toBindingEntry(bindingPath, bindingObject));
+        return codecRegistry.toNormalizedNode((InstanceIdentifier) bindingPath, bindingObject);
 
     }
 
     public Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toNormalizedNode(
             final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> binding) {
-        Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, CompositeNode> legacyEntry = bindingToLegacy
-                .toDataDom(binding);
-        Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> normalizedEntry = legacyToNormalized
-                .toNormalized(legacyEntry);
-        LOG.trace("Serialization of {}, Legacy Representation: {}, Normalized Representation: {}", binding,
-                legacyEntry, normalizedEntry);
-        if (isAugmentation(binding.getKey().getTargetType())) {
-
-            for (DataContainerChild<? extends PathArgument, ?> child : ((DataContainerNode<?>) normalizedEntry
-                    .getValue()).getValue()) {
-                if (child instanceof AugmentationNode) {
-                    ImmutableList<PathArgument> childArgs = ImmutableList.<PathArgument> builder()
-                            .addAll(normalizedEntry.getKey().getPathArguments()).add(child.getIdentifier()).build();
-                    org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier
-                            .create(childArgs);
-                    return toDOMEntry(childPath, child);
-                }
-            }
-
-        }
-        return normalizedEntry;
-
+        return toNormalizedNode(binding.getKey(),binding.getValue());
     }
 
     /**
@@ -125,156 +72,26 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
     public Optional<InstanceIdentifier<? extends DataObject>> toBinding(
             final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
                     throws DeserializationException {
-
-        PathArgument lastArgument = Iterables.getLast(normalized.getPathArguments());
-        // Used instance-identifier codec do not support serialization of last
-        // path
-        // argument if it is AugmentationIdentifier (behaviour expected by old
-        // datastore)
-        // in this case, we explicitly check if last argument is augmentation
-        // to process it separately
-        if (lastArgument instanceof AugmentationIdentifier) {
-            return toBindingAugmented(normalized);
-        }
-        return toBindingImpl(normalized);
-    }
-
-    private Optional<InstanceIdentifier<? extends DataObject>> toBindingAugmented(
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
-                    throws DeserializationException {
-        Optional<InstanceIdentifier<? extends DataObject>> potential = toBindingImpl(normalized);
-        // Shorthand check, if codec already supports deserialization
-        // of AugmentationIdentifier we will return
-        if (potential.isPresent() && isAugmentationIdentifier(potential.get())) {
-            return potential;
-        }
-
-        int normalizedCount = getAugmentationCount(normalized);
-        AugmentationIdentifier lastArgument = (AugmentationIdentifier) Iterables.getLast(normalized.getPathArguments());
-
-        // Here we employ small trick - Binding-aware Codec injects an pointer
-        // to augmentation class
-        // if child is referenced - so we will reference child and then shorten
-        // path.
-        LOG.trace("Looking for candidates to match {}", normalized);
-        for (QName child : lastArgument.getPossibleChildNames()) {
-            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier childPath = normalized.node(child);
-            try {
-                if (isNotRepresentable(childPath)) {
-                    LOG.trace("Path {} is not BI-representable, skipping it", childPath);
-                    continue;
-                }
-            } catch (DataNormalizationException e) {
-                LOG.warn("Failed to denormalize path {}, skipping it", childPath, e);
-                continue;
-            }
-
-            Optional<InstanceIdentifier<? extends DataObject>> baId = toBindingImpl(childPath);
-            if (!baId.isPresent()) {
-                LOG.debug("No binding-aware identifier found for path {}, skipping it", childPath);
-                continue;
-            }
-
-            InstanceIdentifier<? extends DataObject> potentialPath = shortenToLastAugment(baId.get());
-            int potentialAugmentCount = getAugmentationCount(potentialPath);
-            if (potentialAugmentCount == normalizedCount) {
-                LOG.trace("Found matching path {}", potentialPath);
-                return Optional.<InstanceIdentifier<? extends DataObject>> of(potentialPath);
-            }
-
-            LOG.trace("Skipping mis-matched potential path {}", potentialPath);
-        }
-
-        LOG.trace("Failed to find augmentation matching {}", normalized);
-        return Optional.absent();
-    }
-
-    private Optional<InstanceIdentifier<? extends DataObject>> toBindingImpl(
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
-                    throws DeserializationException {
-        org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath;
-
         try {
-            if (isNotRepresentable(normalized)) {
-                return Optional.absent();
-            }
-            legacyPath = legacyToNormalized.toLegacy(normalized);
-        } catch (DataNormalizationException e) {
-            throw new IllegalStateException("Could not denormalize path.", e);
-        }
-        LOG.trace("InstanceIdentifier Path Deserialization: Legacy representation {}, Normalized representation: {}",
-                legacyPath, normalized);
-        return Optional.<InstanceIdentifier<? extends DataObject>> of(bindingToLegacy.fromDataDom(legacyPath));
-    }
-
-    private boolean isNotRepresentable(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
-            throws DataNormalizationException {
-        DataNormalizationOperation<?> op = findNormalizationOperation(normalized);
-        if (op.isMixin() && op.getIdentifier() instanceof NodeIdentifier) {
-            return true;
-        }
-        if (op.isLeaf()) {
-            return true;
-        }
-        return false;
-    }
-
-    private DataNormalizationOperation<?> findNormalizationOperation(
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized)
-                    throws DataNormalizationException {
-        DataNormalizationOperation<?> current = legacyToNormalized.getRootOperation();
-        for (PathArgument arg : normalized.getPathArguments()) {
-            current = current.getChild(arg);
-        }
-        return current;
-    }
-
-    private static final Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject> toBindingEntry(
-            final org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject> key,
-            final DataObject value) {
-        return new SimpleEntry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>(
-                key, value);
-    }
-
-    private static final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>> toDOMEntry(
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier key, final NormalizedNode<?, ?> value) {
-        return new SimpleEntry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, NormalizedNode<?, ?>>(key,
-                value);
-    }
-
-    public DataObject toBinding(final InstanceIdentifier<?> path, final NormalizedNode<?, ?> normalizedNode)
-            throws DeserializationException {
-        CompositeNode legacy = null;
-        if (isAugmentationIdentifier(path) && normalizedNode instanceof AugmentationNode) {
-            QName augIdentifier = BindingReflections.findQName(path.getTargetType());
-            ContainerNode virtualNode = Builders.containerBuilder() //
-                    .withNodeIdentifier(new NodeIdentifier(augIdentifier)) //
-                    .withChild((DataContainerChild<?, ?>) normalizedNode) //
-                    .build();
-            legacy = (CompositeNode) DataNormalizer.toLegacy(virtualNode);
-        } else {
-            legacy = (CompositeNode) DataNormalizer.toLegacy(normalizedNode);
+            return  Optional.<InstanceIdentifier<? extends DataObject>>of(codecRegistry.fromYangInstanceIdentifier(normalized));
+        } catch (IllegalArgumentException e) {
+            return Optional.absent();
         }
-
-        return bindingToLegacy.dataObjectFromDataDom(path, legacy);
     }
 
     public DataNormalizer getDataNormalizer() {
         return legacyToNormalized;
     }
 
+    @SuppressWarnings("unchecked")
     public Optional<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>> toBinding(
             final Entry<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier, ? extends NormalizedNode<?, ?>> normalized)
                     throws DeserializationException {
-        Optional<InstanceIdentifier<? extends DataObject>> potentialPath = toBinding(normalized.getKey());
-        if (potentialPath.isPresent()) {
-            InstanceIdentifier<? extends DataObject> bindingPath = potentialPath.get();
-            DataObject bindingData = toBinding(bindingPath, normalized.getValue());
-            if (bindingData == null) {
-                LOG.warn("Failed to deserialize {} to Binding format. Binding path is: {}", normalized, bindingPath);
-            }
-            return Optional.of(toBindingEntry(bindingPath, bindingData));
-        } else {
+        try {
+            @SuppressWarnings("rawtypes")
+            Entry binding = codecRegistry.fromNormalizedNode(normalized.getKey(), normalized.getValue());
+            return Optional.<Entry<org.opendaylight.yangtools.yang.binding.InstanceIdentifier<? extends DataObject>, DataObject>>fromNullable(binding);
+        } catch (IllegalArgumentException e) {
             return Optional.absent();
         }
     }
@@ -282,269 +99,11 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
     @Override
     public void onGlobalContextUpdated(final SchemaContext arg0) {
         legacyToNormalized = new DataNormalizer(arg0);
+        codecRegistry.onBindingRuntimeContextUpdated(BindingRuntimeContext.create(classLoadingStrategy, arg0));
     }
 
-    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedAugmented(
-            final InstanceIdentifier<?> augPath) {
-        org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed = toNormalizedImpl(augPath);
-        // If used instance identifier codec added supports for deserialization
-        // of last AugmentationIdentifier we will just reuse it
-        if (isAugmentationIdentifier(processed)) {
-            return processed;
-        }
-        Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> additionalSerialized;
-        additionalSerialized = toNormalizedAugmentedUsingChildContainers(augPath, processed);
-
-        if (additionalSerialized.isPresent()) {
-            return additionalSerialized.get();
-        }
-        additionalSerialized = toNormalizedAugmentedUsingChildLeafs(augPath, processed);
-        if (additionalSerialized.isPresent()) {
-            return additionalSerialized.get();
-        }
-        throw new IllegalStateException("Unabled to construct augmentation identfier for " + augPath);
-    }
-
-    /**
-     * Tries to find correct augmentation identifier using children leafs
-     *
-     * This method uses normalized Instance Identifier of parent node to fetch
-     * schema and {@link BindingReflections#getModuleInfo(Class)} to learn about
-     * augmentation namespace, specificly, in which module it was defined.
-     *
-     * Then it uses it to filter all available augmentations for parent by
-     * module. After that it walks augmentations in particular module and
-     * pick-up first which at least one leaf name matches supplied augmentation.
-     * We could do this safely since YANG explicitly states that no any existing
-     * augmentations must differ in leaf fully qualified names.
-     *
-     *
-     * @param augPath
-     *            Binding Aware Path which ends with augment
-     * @param parentPath
-     *            Processed path
-     * @return
-     */
-    private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildLeafs(
-            final InstanceIdentifier<?> augPath,
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
-        try {
-            DataNormalizationOperation<?> parentOp = legacyToNormalized.getOperation(parentPath);
-            if(!parentOp.getDataSchemaNode().isPresent()) {
-                return Optional.absent();
-            }
-            DataSchemaNode parentSchema = parentOp.getDataSchemaNode().get();
-            if (parentSchema instanceof AugmentationTarget) {
-                Set<AugmentationSchema> augmentations = ((AugmentationTarget) parentSchema).getAvailableAugmentations();
-                LOG.info("Augmentations for {}, {}", augPath, augmentations);
-                Optional<AugmentationSchema> schema = findAugmentation(augPath.getTargetType(), augmentations);
-                if (schema.isPresent()) {
-                    AugmentationIdentifier augmentationIdentifier = DataNormalizationOperation
-                            .augmentationIdentifierFrom(schema.get());
-                    return Optional.of(parentPath.node(augmentationIdentifier));
-                }
-            }
-        } catch (DataNormalizationException e) {
-            throw new IllegalArgumentException(e);
-        }
-        return Optional.absent();
-    }
-
-    /**
-     * Creates instance identifier for augmentation child, tries to serialize it
-     * Instance Identifier is then shortened to last augmentation.
-     *
-     * This is for situations, where underlying codec is implementing hydrogen
-     * style DOM APIs (which did not supported {@link AugmentationIdentifier}.)
-     *
-     * @param augPath
-     * @param parentPath
-     *            Path to parent node
-     * @return
-     */
-    @SuppressWarnings("rawtypes")
-    private Optional<org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier> toNormalizedAugmentedUsingChildContainers(
-            final InstanceIdentifier<?> augPath,
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
-        for (Class augChild : BindingReflections.getChildrenClasses(augPath.getTargetType())) {
-            @SuppressWarnings("unchecked")
-            InstanceIdentifier<?> childPath = augPath.child(augChild);
-            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = toNormalizedImpl(childPath);
-            org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potentialDiscovered = shortenToLastAugmentation(
-                    normalized, parentPath);
-            if (potentialDiscovered != null) {
-                return Optional.of(potentialDiscovered);
-            }
-        }
-        return Optional.absent();
-    }
-
-    private Optional<AugmentationSchema> findAugmentation(final Class<?> targetType,
-            final Set<AugmentationSchema> augmentations) {
-        YangModuleInfo moduleInfo;
-        try {
-            moduleInfo = BindingReflections.getModuleInfo(targetType);
-        } catch (Exception e) {
-            throw new IllegalStateException(e);
-        }
-        Iterable<AugmentationSchema> filtered = filteredByModuleInfo(augmentations,
-                BindingReflections.getModuleQName(moduleInfo).getModule());
-        filtered.toString();
-        Set<String> targetTypeGetters = getYangModeledGetters(targetType);
-        for (AugmentationSchema schema : filtered) {
-            for (DataSchemaNode child : schema.getChildNodes()) {
-                String getterName = "get" + BindingMapping.getClassName(child.getQName());
-                if (targetTypeGetters.contains(getterName)) {
-                    return Optional.of(schema);
-                }
-            }
-        }
-        return Optional.absent();
-    }
-
-    private static Iterable<AugmentationSchema> filteredByModuleInfo(final Iterable<AugmentationSchema> augmentations,
-            final QNameModule module) {
-        return Iterables.filter(augmentations, new Predicate<AugmentationSchema>() {
-            @Override
-            public boolean apply(final AugmentationSchema schema) {
-                final Collection<DataSchemaNode> childNodes = schema.getChildNodes();
-                return !childNodes.isEmpty() && module.equals(Iterables.get(childNodes, 0).getQName().getModule());
-            }
-        });
-    }
-
-    public static final Set<String> getYangModeledGetters(final Class<?> targetType) {
-        HashSet<String> ret = new HashSet<String>();
-        for (Method method : targetType.getMethods()) {
-            if (isYangModeledGetter(method)) {
-                ret.add(method.getName());
-            }
-        }
-        return ret;
-    }
-
-    /**
-     *
-     * Returns true if supplied method represent getter for YANG modeled value
-     *
-     * @param method
-     *            Method to be tested
-     * @return true if method represent getter for YANG Modeled value.
-     */
-    private static final boolean isYangModeledGetter(final Method method) {
-        return !method.getName().equals("getClass") && !method.getName().equals("getImplementedInterface")
-                && method.getName().startsWith("get") && method.getParameterTypes().length == 0;
-    }
-
-    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier shortenToLastAugmentation(
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized,
-            final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier parentPath) {
-        int parentSize = Iterables.size(parentPath.getPathArguments());
-        int position = 0;
-        int foundPosition = -1;
-        for (PathArgument arg : normalized.getPathArguments()) {
-            position++;
-            if (arg instanceof AugmentationIdentifier) {
-                foundPosition = position;
-            }
-        }
-        if (foundPosition > 0 && foundPosition > parentSize) {
-            Iterable<PathArgument> shortened = Iterables.limit(normalized.getPathArguments(), foundPosition);
-            return org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.create(shortened);
-        }
-        return null;
-    }
-
-    private InstanceIdentifier<? extends DataObject> shortenToLastAugment(
-            final InstanceIdentifier<? extends DataObject> binding) {
-        int position = 0;
-        int foundPosition = -1;
-        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : binding.getPathArguments()) {
-            position++;
-            if (isAugmentation(arg.getType())) {
-                foundPosition = position;
-            }
-        }
-        return InstanceIdentifier.create(Iterables.limit(binding.getPathArguments(), foundPosition));
-    }
-
-    private org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier toNormalizedImpl(
-            final InstanceIdentifier<? extends DataObject> binding) {
-        final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier legacyPath = bindingToLegacy
-                .toDataDom(binding);
-        final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier normalized = legacyToNormalized
-                .toNormalized(legacyPath);
-        return normalized;
-    }
-
-    private static boolean isAugmentation(final Class<? extends DataObject> type) {
-        return Augmentation.class.isAssignableFrom(type);
-    }
-
-    private static boolean isAugmentationIdentifier(final InstanceIdentifier<?> potential) {
-        return Augmentation.class.isAssignableFrom(potential.getTargetType());
-    }
-
-    private boolean isAugmentationIdentifier(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier processed) {
-        return Iterables.getLast(processed.getPathArguments()) instanceof AugmentationIdentifier;
-    }
-
-    private static int getAugmentationCount(final InstanceIdentifier<?> potential) {
-        int count = 0;
-        for (org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument arg : potential.getPathArguments()) {
-            if (isAugmentation(arg.getType())) {
-                count++;
-            }
-
-        }
-        return count;
-    }
-
-    private static int getAugmentationCount(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier potential) {
-        int count = 0;
-        for (PathArgument arg : potential.getPathArguments()) {
-            if (arg instanceof AugmentationIdentifier) {
-                count++;
-            }
-        }
-        return count;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
     public <T extends DataObject> Function<Optional<NormalizedNode<?, ?>>, Optional<T>>  deserializeFunction(final InstanceIdentifier<T> path) {
-        return new DeserializeFunction(this, path);
-    }
-
-    private static class DeserializeFunction<T extends DataObject> implements Function<Optional<NormalizedNode<?, ?>>, Optional<T>> {
-
-        private final BindingToNormalizedNodeCodec codec;
-        private final InstanceIdentifier<?> path;
-
-        public DeserializeFunction(final BindingToNormalizedNodeCodec codec, final InstanceIdentifier<?> path) {
-            super();
-            this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
-            this.path = Preconditions.checkNotNull(path, "Path must not be null");
-        }
-
-        @SuppressWarnings("rawtypes")
-        @Nullable
-        @Override
-        public Optional apply(@Nullable final Optional<NormalizedNode<?, ?>> normalizedNode) {
-            if (normalizedNode.isPresent()) {
-                final DataObject dataObject;
-                try {
-                    dataObject = codec.toBinding(path, normalizedNode.get());
-                } catch (DeserializationException e) {
-                    LOG.warn("Failed to create dataobject from node {}", normalizedNode.get(), e);
-                    throw new IllegalStateException("Failed to create dataobject", e);
-                }
-
-                if (dataObject != null) {
-                    return Optional.of(dataObject);
-                }
-            }
-            return Optional.absent();
-        }
+        return codecRegistry.deserializeFunction(path);
     }
 
     /**
@@ -566,4 +125,13 @@ public class BindingToNormalizedNodeCodec implements SchemaContextListener {
         }
         return currentOp.createDefault(path.getLastPathArgument());
     }
+
+    public BindingIndependentMappingService getLegacy() {
+        return bindingToLegacy;
+    }
+
+    @Override
+    public void close() throws Exception {
+        // NOOP Intentionally
+    }
 }
index 237d967..52e114b 100644 (file)
@@ -7,6 +7,12 @@
  */
 package org.opendaylight.controller.md.sal.binding.impl;
 
+import com.google.common.base.Function;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.FutureCallback;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -17,7 +23,6 @@ import java.util.Set;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
-
 import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
@@ -44,17 +49,9 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.base.Function;
-import com.google.common.util.concurrent.AsyncFunction;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-import com.google.common.util.concurrent.ListeningExecutorService;
-
 @SuppressWarnings("deprecation")
 public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDataBroker implements DataProviderService, AutoCloseable {
 
@@ -64,7 +61,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
     private final ListeningExecutorService executorService;
 
     public ForwardedBackwardsCompatibleDataBroker(final DOMDataBroker domDataBroker,
-            final BindingIndependentMappingService mappingService, final SchemaService schemaService,final ListeningExecutorService executor) {
+            final BindingToNormalizedNodeCodec mappingService, final SchemaService schemaService,final ListeningExecutorService executor) {
         super(domDataBroker, mappingService,schemaService);
         executorService = executor;
         LOG.info("ForwardedBackwardsCompatibleBroker started.");
index 6359b60..ef66d80 100644 (file)
@@ -16,7 +16,6 @@ import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
 
 /**
  * The DataBrokerImpl simply defers to the DOMDataBroker for all its operations.
@@ -30,8 +29,8 @@ import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMapping
  */
 public class ForwardedBindingDataBroker extends AbstractForwardedDataBroker implements DataBroker {
 
-    public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingIndependentMappingService mappingService, final SchemaService schemaService) {
-        super(domDataBroker, mappingService,schemaService);
+    public ForwardedBindingDataBroker(final DOMDataBroker domDataBroker, final BindingToNormalizedNodeCodec codec, final SchemaService schemaService) {
+        super(domDataBroker, codec,schemaService);
     }
 
     @Override
index 1ec4aa2..f037e67 100644 (file)
@@ -7,6 +7,10 @@
  */
 package org.opendaylight.controller.sal.binding.codegen.impl;
 
+import com.google.common.util.concurrent.ForwardingBlockingQueue;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -16,24 +20,19 @@ import java.util.concurrent.RejectedExecutionHandler;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
-
 import javassist.ClassPool;
-
 import org.apache.commons.lang3.StringUtils;
 import org.opendaylight.controller.sal.binding.codegen.RuntimeCodeGenerator;
 import org.opendaylight.controller.sal.binding.spi.NotificationInvokerFactory;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.util.concurrent.ForwardingBlockingQueue;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
-
 public class SingletonHolder {
     private static final Logger logger = LoggerFactory.getLogger(SingletonHolder.class);
 
     public static final ClassPool CLASS_POOL = ClassPool.getDefault();
+    public static final JavassistUtils JAVASSIST = JavassistUtils.forClassPool(CLASS_POOL);
     public static final org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator RPC_GENERATOR_IMPL = new org.opendaylight.controller.sal.binding.codegen.impl.RuntimeCodeGenerator(
             CLASS_POOL);
     public static final RuntimeCodeGenerator RPC_GENERATOR = RPC_GENERATOR_IMPL;
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/RootDataBrokerImpl.java
deleted file mode 100644 (file)
index a1cae26..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.binding.impl;\r
-\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.Data;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeMXBean;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistration;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.DataBrokerImplRuntimeRegistrator;\r
-import org.opendaylight.controller.config.yang.md.sal.binding.impl.Transactions;\r
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;\r
-\r
-public class RootDataBrokerImpl extends DataBrokerImpl implements DataBrokerImplRuntimeMXBean {\r
-\r
-    private final Transactions transactions = new Transactions();\r
-    private final Data data = new Data();\r
-    private BindingIndependentConnector bindingIndependentConnector;\r
-    private DataBrokerImplRuntimeRegistration runtimeBeanRegistration;\r
-\r
-    public BindingIndependentConnector getBindingIndependentConnector() {\r
-        return bindingIndependentConnector;\r
-    }\r
-\r
-    public Transactions getTransactions() {\r
-        transactions.setCreated(getCreatedTransactionsCount().get());\r
-        transactions.setSubmitted(getSubmittedTransactionsCount().get());\r
-        transactions.setSuccessful(getFinishedTransactionsCount().get());\r
-        transactions.setFailed(getFailedTransactionsCount().get());\r
-        return transactions;\r
-    }\r
-\r
-    @Override\r
-    public Data getData() {\r
-        data.setTransactions(getTransactions());\r
-        return data;\r
-    }\r
-\r
-    public void setBindingIndependentConnector(BindingIndependentConnector runtimeMapping) {\r
-        this.bindingIndependentConnector = runtimeMapping;\r
-    }\r
-\r
-    public void registerRuntimeBean(DataBrokerImplRuntimeRegistrator rootRegistrator) {\r
-        runtimeBeanRegistration = rootRegistrator.register(this);\r
-    }\r
-\r
-}\r
diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedDataBrokerImpl.java
deleted file mode 100644 (file)
index 3d0e4de..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.binding.impl.forward;
-
-import java.util.Collection;
-import java.util.Collections;
-
-import org.opendaylight.controller.sal.binding.impl.RootDataBrokerImpl;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingDomConnectorDeployer;
-import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentConnector;
-import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.controller.sal.core.api.Broker.ProviderSession;
-
-public class DomForwardedDataBrokerImpl extends RootDataBrokerImpl implements Provider, DomForwardedBroker {
-
-    private BindingIndependentConnector connector;
-    private ProviderSession domProviderContext;
-
-    public void setConnector(BindingIndependentConnector connector) {
-        this.connector = connector;
-    }
-
-    @Override
-    public void onSessionInitiated(ProviderSession session) {
-        this.setDomProviderContext(session);
-    }
-
-    @Override
-    public Collection<ProviderFunctionality> getProviderFunctionality() {
-        return Collections.emptySet();
-    }
-
-    @Override
-    public BindingIndependentConnector getConnector() {
-        return connector;
-    }
-
-    @Override
-    public ProviderSession getDomProviderContext() {
-        return domProviderContext;
-    }
-
-    public void setDomProviderContext(ProviderSession domProviderContext) {
-        this.domProviderContext = domProviderContext;
-    }
-
-    @Override
-    public void startForwarding() {
-        BindingDomConnectorDeployer.startDataForwarding(getConnector(), this, getDomProviderContext());
-    }
-}
index cee4b1e..aec2723 100644 (file)
@@ -18,10 +18,9 @@ module opendaylight-sal-binding-broker-impl {
 
     identity binding-dom-mapping-service {
         base config:service-type;
-        config:java-class "org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService";
+        config:java-class "org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec";
     }
 
-
     identity binding-broker-impl {
         base config:module-type;
         config:provided-service sal:binding-broker-osgi-registry;
@@ -29,13 +28,6 @@ module opendaylight-sal-binding-broker-impl {
         config:java-name-prefix BindingBrokerImpl;
     }
 
-    identity binding-data-broker {
-        base config:module-type;
-        config:provided-service sal:binding-data-broker;
-        config:provided-service sal:binding-data-consumer-broker;
-        config:java-name-prefix DataBrokerImpl;
-    }
-
     identity binding-data-compatible-broker {
         base config:module-type;
         config:provided-service sal:binding-data-broker;
@@ -131,29 +123,6 @@ module opendaylight-sal-binding-broker-impl {
         }
     }
 
-    augment "/config:modules/config:module/config:configuration" {
-        case binding-data-broker {
-            when "/config:modules/config:module/config:type = 'binding-data-broker'";
-            container dom-broker {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity dom:dom-broker-osgi-registry;
-                    }
-                }
-            }
-
-            container mapping-service {
-                uses config:service-ref {
-                    refine type {
-                        mandatory true;
-                        config:required-identity binding-dom-mapping-service;
-                    }
-                }
-            }
-        }
-    }
-
     augment "/config:modules/config:module/config:configuration" {
         case binding-data-compatible-broker {
             when "/config:modules/config:module/config:type = 'binding-data-compatible-broker'";
@@ -178,14 +147,6 @@ module opendaylight-sal-binding-broker-impl {
         }
     }
 
-    augment "/config:modules/config:module/config:state" {
-        case binding-data-broker {
-            when "/config:modules/config:module/config:type = 'binding-data-broker'";
-            container data {
-                uses common:data-state;
-            }
-        }
-    }
     augment "/config:modules/config:module/config:state" {
         case binding-rpc-broker {
             when "/config:modules/config:module/config:type = 'binding-rpc-broker'";
index fd0a169..3e6c4c0 100644 (file)
@@ -11,7 +11,12 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
@@ -34,7 +39,9 @@ public class BindingNormalizedCodecTest extends AbstractSchemaAwareTest {
     @Override
     protected void setupWithSchema(final SchemaContext context) {
         mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
-        codec = new BindingToNormalizedNodeCodec(mappingService);
+        DataObjectSerializerGenerator streamWriter = StreamWriterGenerator.create(JavassistUtils.forClassPool(ClassPool.getDefault()));
+        BindingNormalizedNodeCodecRegistry registry = new BindingNormalizedNodeCodecRegistry(streamWriter);
+        codec = new BindingToNormalizedNodeCodec(GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy(), mappingService, registry);
         mappingService.onGlobalContextUpdated(context);
         codec.onGlobalContextUpdated(context);
     };
index 60eec55..ca04f99 100644 (file)
@@ -7,9 +7,14 @@
  */
 package org.opendaylight.controller.md.sal.binding.test;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+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.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -19,20 +24,21 @@ import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 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;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
-import org.opendaylight.yangtools.yang.data.impl.codec.BindingIndependentMappingService;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
 public class DataBrokerTestCustomizer {
 
     private DOMDataBroker domDataBroker;
     private final RuntimeGeneratedMappingServiceImpl mappingService;
     private final MockSchemaService schemaService;
     private ImmutableMap<LogicalDatastoreType, DOMStore> datastores;
+    private final BindingToNormalizedNodeCodec bindingToNormalized ;
 
     public ImmutableMap<LogicalDatastoreType, DOMStore> createDatastores() {
         return ImmutableMap.<LogicalDatastoreType, DOMStore>builder()
@@ -43,7 +49,13 @@ public class DataBrokerTestCustomizer {
 
     public DataBrokerTestCustomizer() {
         schemaService = new MockSchemaService();
-        mappingService = new RuntimeGeneratedMappingServiceImpl(ClassPool.getDefault());
+        ClassPool pool = ClassPool.getDefault();
+        mappingService = new RuntimeGeneratedMappingServiceImpl(pool);
+        DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(pool));
+        BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+        bindingToNormalized = new BindingToNormalizedNodeCodec(loading, mappingService, codecRegistry);
+        schemaService.registerSchemaContextListener(bindingToNormalized);
     }
 
     public DOMStore createConfigurationDatastore() {
@@ -69,22 +81,17 @@ public class DataBrokerTestCustomizer {
     }
 
     public DataBroker createDataBroker() {
-        return new ForwardedBindingDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService());
+        return new ForwardedBindingDataBroker(getDOMDataBroker(), bindingToNormalized, schemaService );
     }
 
     public ForwardedBackwardsCompatibleDataBroker createBackwardsCompatibleDataBroker() {
-        return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), getMappingService(), getSchemaService(), MoreExecutors.sameThreadExecutor());
+        return new ForwardedBackwardsCompatibleDataBroker(getDOMDataBroker(), bindingToNormalized, getSchemaService(), MoreExecutors.sameThreadExecutor());
     }
 
-
     private SchemaService getSchemaService() {
         return schemaService;
     }
 
-    private BindingIndependentMappingService getMappingService() {
-        return mappingService;
-    }
-
     private DOMDataBroker getDOMDataBroker() {
         if(domDataBroker == null) {
             domDataBroker = createDOMDataBroker();
@@ -92,8 +99,8 @@ public class DataBrokerTestCustomizer {
         return domDataBroker;
     }
 
-    private ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
-        if(datastores == null) {
+    private synchronized ImmutableMap<LogicalDatastoreType, DOMStore> getDatastores() {
+        if (datastores == null) {
             datastores = createDatastores();
         }
         return datastores;
index 7b67d3b..63e0e22 100644 (file)
@@ -16,7 +16,6 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
@@ -76,7 +75,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
      *
      * @throws Exception
      */
-    @Test( timeout = 15000)
+    @Test()
     public void testAugmentSerialization() throws Exception {
 
         baDataService.registerDataChangeListener(NODES_INSTANCE_ID_BA, this);
@@ -122,7 +121,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
         testNodeRemove();
     }
 
-    private <T extends Augmentation<Node>> Node createTestNode(Class<T> augmentationClass, T augmentation) {
+    private <T extends Augmentation<Node>> Node createTestNode(final Class<T> augmentationClass, final T augmentation) {
         NodeBuilder nodeBuilder = new NodeBuilder();
         nodeBuilder.setId(new NodeId(NODE_ID));
         nodeBuilder.setKey(NODE_KEY);
@@ -130,7 +129,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
         return nodeBuilder.build();
     }
 
-    private DataModificationTransaction commitNodeAndVerifyTransaction(Node original) throws Exception {
+    private DataModificationTransaction commitNodeAndVerifyTransaction(final Node original) throws Exception {
         DataModificationTransaction transaction = baDataService.beginTransaction();
         transaction.putOperationalData(NODE_INSTANCE_ID_BA, original);
         RpcResult<TransactionStatus> result = transaction.commit().get();
@@ -148,7 +147,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
         assertNull(node);
     }
 
-    private AugmentationVerifier<Node> verifyNode(Nodes nodes, Node original) {
+    private AugmentationVerifier<Node> verifyNode(final Nodes nodes, final Node original) {
         assertNotNull(nodes);
         assertNotNull(nodes.getNode());
         assertEquals(1, nodes.getNode().size());
@@ -158,7 +157,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
         return new AugmentationVerifier<Node>(readedNode);
     }
 
-    private void assertBindingIndependentVersion(org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) {
+    private void assertBindingIndependentVersion(final org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier nodeId) {
         CompositeNode node = biDataService.readOperationalData(nodeId);
         assertNotNull(node);
     }
@@ -171,7 +170,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
         return nodeMeterStatistics(10, false);
     }
 
-    private NodeMeterStatistics nodeMeterStatistics(int count, boolean setDuration) {
+    private NodeMeterStatistics nodeMeterStatistics(final int count, final boolean setDuration) {
         NodeMeterStatisticsBuilder nmsb = new NodeMeterStatisticsBuilder();
         MeterStatisticsBuilder meterStats = new MeterStatisticsBuilder();
 
@@ -207,7 +206,7 @@ public class MultipleAugmentationPutsTest extends AbstractDataServiceTest implem
     }
 
     @Override
-    public void onDataChanged(DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
+    public void onDataChanged(final DataChangeEvent<InstanceIdentifier<?>, DataObject> change) {
         receivedChangeEvent = change;
     }
 
index fef5715..d0a326a 100644 (file)
@@ -9,12 +9,19 @@ package org.opendaylight.controller.sal.binding.test.util;
 
 import static com.google.common.base.Preconditions.checkState;
 
+import com.google.common.annotations.Beta;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.ImmutableClassToInstanceMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.MutableClassToInstanceMap;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Set;
 import java.util.concurrent.Future;
-
 import javassist.ClassPool;
-
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBackwardsCompatibleDataBroker;
 import org.opendaylight.controller.md.sal.binding.impl.ForwardedBindingDataBroker;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
@@ -43,9 +50,14 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.DataObjectSerializerGenerator;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.sal.binding.generator.impl.GeneratedClassLoadingStrategy;
 import org.opendaylight.yangtools.sal.binding.generator.impl.ModuleInfoBackedContext;
 import org.opendaylight.yangtools.sal.binding.generator.impl.RuntimeGeneratedMappingServiceImpl;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
 import org.opendaylight.yangtools.yang.common.QName;
@@ -56,15 +68,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.common.annotations.Beta;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.ImmutableClassToInstanceMap;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.MutableClassToInstanceMap;
-import com.google.common.util.concurrent.ListeningExecutorService;
-import com.google.common.util.concurrent.MoreExecutors;
-
 @Beta
 public class BindingTestContext implements AutoCloseable {
 
@@ -74,6 +77,7 @@ public class BindingTestContext implements AutoCloseable {
     private static final Logger LOG = LoggerFactory.getLogger(BindingTestContext.class);
 
     private RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
+    private BindingToNormalizedNodeCodec codec;
 
     private DomForwardedBindingBrokerImpl baBrokerImpl;
     private DataBrokerImpl baDataImpl;
@@ -129,7 +133,7 @@ public class BindingTestContext implements AutoCloseable {
     public void startNewDataBroker() {
         checkState(executor != null, "Executor needs to be set");
         checkState(newDOMDataBroker != null, "DOM Data Broker must be set");
-        dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, mappingServiceImpl, mockSchemaService);
+        dataBroker = new ForwardedBindingDataBroker(newDOMDataBroker, codec, mockSchemaService);
     }
 
     public void startNewDomDataBroker() {
@@ -250,6 +254,12 @@ public class BindingTestContext implements AutoCloseable {
         checkState(classPool != null, "ClassPool needs to be present");
         mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl(classPool);
         mockSchemaService.registerSchemaContextListener(mappingServiceImpl);
+
+        DataObjectSerializerGenerator generator = StreamWriterGenerator.create(JavassistUtils.forClassPool(classPool));
+        BindingNormalizedNodeCodecRegistry codecRegistry = new BindingNormalizedNodeCodecRegistry(generator);
+        GeneratedClassLoadingStrategy loading = GeneratedClassLoadingStrategy.getTCCLClassLoadingStrategy();
+        codec = new BindingToNormalizedNodeCodec(loading, mappingServiceImpl, codecRegistry);
+        mockSchemaService.registerSchemaContextListener(codec);
     }
 
     private void updateYangSchema(final ImmutableSet<YangModuleInfo> moduleInfos) {
@@ -280,7 +290,7 @@ public class BindingTestContext implements AutoCloseable {
     }
 
     public void startNewBindingDataBroker() {
-        ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, mappingServiceImpl,mockSchemaService, executor);
+        ForwardedBackwardsCompatibleDataBroker forwarded = new ForwardedBackwardsCompatibleDataBroker(newDOMDataBroker, codec,mockSchemaService, executor);
         baData = forwarded;
     }
 
index 83a6996..3446943 100644 (file)
@@ -112,6 +112,7 @@ public class TestHelper {
                 mavenBundle(YANGTOOLS, "binding-generator-api").versionAsInProject(), mavenBundle(YANGTOOLS,
                         "binding-generator-spi").versionAsInProject(), //
                 mavenBundle(YANGTOOLS, "binding-generator-impl").versionAsInProject(),
+                mavenBundle(YANGTOOLS, "binding-data-codec").versionAsInProject(),
                 mavenBundle(YANGTOOLS + ".thirdparty", "antlr4-runtime-osgi-nohead").versionAsInProject(), // //
 
                 mavenBundle(CONTROLLER, "sal-core-api").versionAsInProject().update(), //
index 8a390b3..33039ea 100644 (file)
@@ -11,9 +11,10 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 
+import com.google.inject.Inject;
 import java.util.concurrent.Future;
-
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker.ConsumerContext;
@@ -22,7 +23,6 @@ import org.opendaylight.controller.sal.binding.api.data.DataBrokerService;
 import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeId;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeRef;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeBuilder;
@@ -31,8 +31,6 @@ import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
-import com.google.inject.Inject;
-
 public class DataServiceTest extends AbstractTest {
 
     protected DataBrokerService consumerDataService;
@@ -45,12 +43,20 @@ public class DataServiceTest extends AbstractTest {
     public void setUp() throws Exception {
     }
 
+    /*
+     *
+     * Ignored this, because classes here are constructed from
+     * very different class loader as MD-SAL is run into,
+     * this is code is run from different classloader.
+     *
+     */
     @Test
+    @Ignore
     public void test() throws Exception {
         BindingAwareConsumer consumer1 = new BindingAwareConsumer() {
 
             @Override
-            public void onSessionInitialized(ConsumerContext session) {
+            public void onSessionInitialized(final ConsumerContext session) {
                 consumerDataService = session.getSALService(DataBrokerService.class);
             }
         };
@@ -62,12 +68,12 @@ public class DataServiceTest extends AbstractTest {
         DataModificationTransaction transaction = consumerDataService.beginTransaction();
         assertNotNull(transaction);
 
-        NodeRef node1 = createNodeRef("0");
-        DataObject  node = consumerDataService.readConfigurationData(node1.getValue());
+        InstanceIdentifier<Node> node1 = createNodeRef("0");
+        DataObject  node = consumerDataService.readConfigurationData(node1);
         assertNull(node);
         Node nodeData1 = createNode("0");
 
-        transaction.putConfigurationData(node1.getValue(), nodeData1);
+        transaction.putConfigurationData(node1, nodeData1);
         Future<RpcResult<TransactionStatus>> commitResult = transaction.commit();
         assertNotNull(commitResult);
 
@@ -77,7 +83,7 @@ public class DataServiceTest extends AbstractTest {
         assertNotNull(result.getResult());
         assertEquals(TransactionStatus.COMMITED, result.getResult());
 
-        Node readedData = (Node) consumerDataService.readConfigurationData(node1.getValue());
+        Node readedData = (Node) consumerDataService.readConfigurationData(node1);
         assertNotNull(readedData);
         assertEquals(nodeData1.getKey(), readedData.getKey());
 
@@ -85,7 +91,7 @@ public class DataServiceTest extends AbstractTest {
         DataModificationTransaction transaction2 = consumerDataService.beginTransaction();
         assertNotNull(transaction);
 
-        transaction2.removeConfigurationData(node1.getValue());
+        transaction2.removeConfigurationData(node1);
 
         Future<RpcResult<TransactionStatus>> commitResult2 = transaction2.commit();
         assertNotNull(commitResult2);
@@ -96,21 +102,19 @@ public class DataServiceTest extends AbstractTest {
         assertNotNull(result2.getResult());
         assertEquals(TransactionStatus.COMMITED, result2.getResult());
 
-        DataObject readedData2 = consumerDataService.readConfigurationData(node1.getValue());
+        DataObject readedData2 = consumerDataService.readConfigurationData(node1);
         assertNull(readedData2);
 
 
     }
 
 
-    private static NodeRef createNodeRef(String string) {
+    private static InstanceIdentifier<Node> createNodeRef(final String string) {
         NodeKey key = new NodeKey(new NodeId(string));
-        InstanceIdentifier<Node> path = InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
-
-        return new NodeRef(path);
+        return  InstanceIdentifier.builder(Nodes.class).child(Node.class, key).build();
     }
 
-    private static Node createNode(String string) {
+    private static Node createNode(final String string) {
         NodeBuilder ret = new NodeBuilder();
         NodeId id = new NodeId(string);
         ret.setKey(new NodeKey(id));
index 63a921d..5e37f36 100644 (file)
                 <data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
                     <modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                                prefix:schema-service-singleton
-                            </type>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
                             <name>yang-schema-service</name>
                         </module>
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                                prefix:hash-map-data-store
-                            </type>
-                            <name>hash-map-data-store</name>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+                            <name>runtime-mapping-singleton</name>
                         </module>
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                                prefix:dom-broker-impl
-                            </type>
-                            <name>dom-broker</name>
-                            <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
-                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
-                                    dom:dom-data-store
-                                </type>
-                                <name>ref_hash-map-data-store</name>
-                            </data-store>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+                            <name>binding-notification-broker</name>
                         </module>
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                prefix:binding-broker-impl
-                            </type>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
                             <name>binding-broker-impl</name>
-                            <notification-service
-                                    xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                                    binding:binding-notification-service
-                                </type>
-                                <name>ref_binding-notification-broker</name>
+                            <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+                                <name>binding-notification-broker</name>
                             </notification-service>
                             <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                                    binding:binding-data-broker
-                                </type>
-                                <name>ref_binding-data-broker</name>
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+                                <name>binding-data-broker</name>
                             </data-broker>
                         </module>
+                        <!--
+                             Tree-based in-memory data store. This is the data store which is currently
+                             recommended for single-node deployments.
+                        -->
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                prefix:runtime-generated-mapping
-                            </type>
-                            <name>runtime-mapping-singleton</name>
+                            <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>
                         </module>
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                prefix:binding-notification-broker
-                            </type>
-                            <name>binding-notification-broker</name>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+                            <name>inmemory-dom-broker</name>
+                            <async-data-broker>
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+                                <name>inmemory-data-broker</name>
+                            </async-data-broker>
                         </module>
                         <module>
-                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                prefix:binding-data-broker
-                            </type>
-                            <name>binding-data-broker</name>
-                            <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
-                                    dom:dom-broker-osgi-registry
-                                </type>
-                                <name>ref_dom-broker</name>
-                            </dom-broker>
-                            <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                    binding:binding-dom-mapping-service
-                                </type>
-                                <name>ref_runtime-mapping-singleton</name>
-                            </mapping-service>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
+                            <name>inmemory-binding-data-broker</name>
+                            <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                                <name>dom-broker</name>
+                            </dom-async-broker>
+                            <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                                <name>runtime-mapping-singleton</name>
+                            </binding-mapping-service>
+                        </module>
+                        <module>
+                            <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+                            <name>binding-async-data-broker</name>
+                            <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+                                <dom-async-broker>
+                                    <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                                    <name>dom-broker</name>
+                                </dom-async-broker>
+                                <binding-mapping-service>
+                                    <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+                                    <name>runtime-mapping-singleton</name>
+                                </binding-mapping-service>
+                            </binding-forwarded-data-broker>
                         </module>
                     </modules>
 
                     <services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
                         <service>
-                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
-                                dom:schema-service
-                            </type>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
                             <instance>
-                                <name>ref_yang-schema-service</name>
-                                <provider>
-                                    /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']
-                                </provider>
+                                <name>yang-schema-service</name>
+                                <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
                             </instance>
                         </service>
                         <service>
-                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                                binding:binding-notification-service
-                            </type>
+                            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
                             <instance>
-                                <name>ref_binding-notification-broker</name>
-                                <provider>
-                                    /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']
-                                </provider>
+                                <name>runtime-mapping-singleton</name>
+                                <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
                             </instance>
                         </service>
                         <service>
-                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
-                                dom:dom-data-store
-                            </type>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
                             <instance>
-                                <name>ref_hash-map-data-store</name>
-                                <provider>
-                                    /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']
-                                </provider>
+                                <name>binding-notification-broker</name>
+                                <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
                             </instance>
                         </service>
-
                         <service>
-                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                                binding:binding-broker-osgi-registry
-                            </type>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
                             <instance>
-                                <name>ref_binding-broker-impl</name>
-                                <provider>
-                                    /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']
-                                </provider>
+                                <name>binding-osgi-broker</name>
+                                <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
                             </instance>
                         </service>
                         <service>
                                 <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
                             </instance>
                         </service>
+
+                        <service>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+                            <instance>
+                                <name>dom-broker</name>
+                                <provider>/modules/module[type='dom-broker-impl'][name='inmemory-dom-broker']</provider>
+                            </instance>
+                        </service>
+
                         <service>
-                            <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
-                                binding-impl:binding-dom-mapping-service
-                            </type>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
                             <instance>
-                                <name>ref_runtime-mapping-singleton</name>
-                                <provider>
-                                    /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']
-                                </provider>
+                                <name>binding-data-broker</name>
+                                <provider>/modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker']</provider>
                             </instance>
                         </service>
+
                         <service>
-                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
-                                dom:dom-broker-osgi-registry
-                            </type>
+                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
                             <instance>
-                                <name>ref_dom-broker</name>
-                                <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']
-                                </provider>
+                                <name>binding-data-broker</name>
+                                <provider>/modules/module[type='binding-forwarded-data-broker'][name='binding-async-data-broker']</provider>
                             </instance>
                         </service>
+
                         <service>
-                            <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
-                                binding:binding-data-broker
-                            </type>
+                            <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
                             <instance>
-                                <name>ref_binding-data-broker</name>
-                                <provider>
-                                    /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']
-                                </provider>
+                                <name>inmemory-data-broker</name>
+                                <provider>/modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker']</provider>
                             </instance>
                         </service>
                     </services>
index bfdb093..1e60803 100644 (file)
@@ -44,7 +44,7 @@ public class MeteredBoundedMailboxTest {
         actorSystem.eventStream().subscribe(mockReceiver.getRef(), DeadLetter.class);
 
 
-        final FiniteDuration ONE_SEC = new FiniteDuration(1, TimeUnit.SECONDS);
+        final FiniteDuration TEN_SEC = new FiniteDuration(10, TimeUnit.SECONDS);
         String boundedMailBox = actorSystem.name() + ".bounded-mailbox";
         ActorRef pingPongActor = actorSystem.actorOf(PingPongActor.props(lock).withMailbox(boundedMailBox),
                                                      "pingpongactor");
@@ -59,11 +59,11 @@ public class MeteredBoundedMailboxTest {
             pingPongActor.tell("ping", mockReceiver.getRef());
         }
 
-        mockReceiver.expectMsgClass(ONE_SEC, DeadLetter.class);
+        mockReceiver.expectMsgClass(TEN_SEC, DeadLetter.class);
 
         lock.unlock();
 
-        Object[] eleven = mockReceiver.receiveN(11, ONE_SEC);
+        Object[] eleven = mockReceiver.receiveN(11, TEN_SEC);
     }
 
     /**
index 3396eb5..2972772 100644 (file)
@@ -295,7 +295,12 @@ public class ShardManager extends AbstractUntypedActor {
             new Function<Throwable, SupervisorStrategy.Directive>() {
                 @Override
                 public SupervisorStrategy.Directive apply(Throwable t) {
-                    LOG.warning("Supervisor Strategy of resume applied {}",t);
+                    StringBuilder sb = new StringBuilder();
+                    for(StackTraceElement element : t.getStackTrace()) {
+                       sb.append("\n\tat ")
+                         .append(element.toString());
+                    }
+                    LOG.warning("Supervisor Strategy of resume applied {}",sb.toString());
                     return SupervisorStrategy.resume();
                 }
             }
index 25705bf..34d3531 100644 (file)
@@ -90,7 +90,7 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
             public void onFailure(Throwable t) {
                 LOG.error(t, "An exception happened during abort");
                 sender
-                    .tell(new akka.actor.Status.Failure(t), getSelf());
+                    .tell(new akka.actor.Status.Failure(t), self);
             }
         });
     }
@@ -119,7 +119,7 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
             public void onFailure(Throwable t) {
                 LOG.error(t, "An exception happened during pre-commit");
                 sender
-                    .tell(new akka.actor.Status.Failure(t), getSelf());
+                    .tell(new akka.actor.Status.Failure(t), self);
             }
         });
 
@@ -138,7 +138,7 @@ public class ThreePhaseCommitCohort extends AbstractUntypedActor {
             public void onFailure(Throwable t) {
                 LOG.error(t, "An exception happened during canCommit");
                 sender
-                    .tell(new akka.actor.Status.Failure(t), getSelf());
+                    .tell(new akka.actor.Status.Failure(t), self);
             }
         });
 
index 870889b..3469797 100644 (file)
@@ -63,7 +63,7 @@ public class ThreePhaseCommitCohortFailureTest extends AbstractActorTest {
         store.onGlobalContextUpdated(testSchemaContext);
     }
 
-    private FiniteDuration ASK_RESULT_DURATION = Duration.create(3000, TimeUnit.MILLISECONDS);
+    private FiniteDuration ASK_RESULT_DURATION = Duration.create(5000, TimeUnit.MILLISECONDS);
 
 
     @Test(expected = TestException.class)
index ac1f2e3..536cfa0 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.base.Preconditions;
+
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
 import org.opendaylight.yangtools.util.concurrent.NotificationManager;
@@ -16,35 +18,37 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 class ChangeListenerNotifyTask implements Runnable {
-
     private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerNotifyTask.class);
 
-    private final Iterable<? extends DataChangeListenerRegistration<?>> listeners;
-    private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
-
     @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent>
-                                                                            notificationMgr;
+    private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr;
+    private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
+    private final DataChangeListenerRegistration<?> listener;
 
     @SuppressWarnings("rawtypes")
-    public ChangeListenerNotifyTask(final Iterable<? extends DataChangeListenerRegistration<?>> listeners,
+    public ChangeListenerNotifyTask(final DataChangeListenerRegistration<?> listener,
             final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event,
             final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
-        this.listeners = listeners;
-        this.event = event;
-        this.notificationMgr = notificationMgr;
+        this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
+        this.listener = Preconditions.checkNotNull(listener);
+        this.event = Preconditions.checkNotNull(event);
     }
 
     @Override
     public void run() {
-
-        for (DataChangeListenerRegistration<?> listener : listeners) {
-            notificationMgr.submitNotification(listener.getInstance(), event);
+        final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> l = listener.getInstance();
+        if (l == null) {
+            LOG.trace("Skipping event delivery to unregistered listener {}", l);
+            return;
         }
+        LOG.trace("Listener {} event {}", l, event);
+
+        // FIXME: Yo dawg I heard you like queues, so this was queued to be queued
+        notificationMgr.submitNotification(l, event);
     }
 
     @Override
     public String toString() {
-        return "ChangeListenerNotifyTask [listeners=" + listeners + ", event=" + event + "]";
+        return "ChangeListenerNotifyTask [listener=" + listener + ", event=" + event + "]";
     }
 }
index 5faebce..f457e3b 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.base.Preconditions;
+
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
@@ -19,8 +21,6 @@ import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-import com.google.common.base.Preconditions;
-
 public final class DOMImmutableDataChangeEvent implements
         AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> {
 
@@ -184,6 +184,10 @@ public final class DOMImmutableDataChangeEvent implements
             updated.put(path, after);
             return this;
         }
+
+        public boolean isEmpty() {
+            return created.isEmpty() && removed.isEmpty() && updated.isEmpty();
+        }
     }
 
     private static final class RemoveEventFactory implements SimpleEventFactory {
index d0d3fe9..1290133 100644 (file)
@@ -49,7 +49,6 @@ import org.slf4j.LoggerFactory;
 
 import javax.annotation.concurrent.GuardedBy;
 
-import java.util.Collections;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.TimeUnit;
@@ -176,7 +175,7 @@ public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, Sch
                         .addCreated(path, data) //
                         .build();
 
-                new ChangeListenerNotifyTask(Collections.singletonList(reg), event,
+                new ChangeListenerNotifyTask(reg, event,
                         dataChangeListenerNotificationManager).run();
             }
         }
index d8feaa7..a4e8c86 100644 (file)
@@ -7,36 +7,24 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
-import static org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.builder;
-
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
-import com.google.common.collect.HashMultimap;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
+import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedList;
-import java.util.List;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.Callable;
 
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
 import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node;
 import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Walker;
 import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNodeContainer;
@@ -54,14 +42,13 @@ import org.slf4j.LoggerFactory;
  */
 final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
     private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
-    private static final DOMImmutableDataChangeEvent NO_CHANGE = builder(DataChangeScope.BASE).build();
 
-    private final Multimap<ListenerTree.Node, DOMImmutableDataChangeEvent> events = HashMultimap.create();
+    @SuppressWarnings("rawtypes")
+    private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
     private final DataTreeCandidate candidate;
     private final ListenerTree listenerRoot;
 
-    @SuppressWarnings("rawtypes")
-    private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
+    private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
 
     @SuppressWarnings("rawtypes")
     public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
@@ -81,153 +68,42 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      *         order to delivery data change events.
      */
     @Override
-    public Iterable<ChangeListenerNotifyTask> call() {
+    public synchronized Iterable<ChangeListenerNotifyTask> call() {
         try (final Walker w = listenerRoot.getWalker()) {
-            resolveAnyChangeEvent(candidate.getRootPath(), Collections.singleton(w.getRootNode()), candidate.getRootNode());
-            return createNotificationTasks();
-        }
-    }
-
-    /**
-     *
-     * Walks map of listeners to data change events, creates notification
-     * delivery tasks.
-     *
-     * Walks map of registered and affected listeners and creates notification
-     * tasks from set of listeners and events to be delivered.
-     *
-     * If set of listeners has more then one event (applicable to wildcarded
-     * listeners), merges all data change events into one, final which contains
-     * all separate updates.
-     *
-     * Dispatch between merge variant and reuse variant of notification task is
-     * done in
-     * {@link #addNotificationTask(com.google.common.collect.ImmutableList.Builder, Node, java.util.Collection)}
-     *
-     * @return Collection of notification tasks.
-     */
-    private Collection<ChangeListenerNotifyTask> createNotificationTasks() {
-        ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder = ImmutableList.builder();
-        for (Entry<ListenerTree.Node, Collection<DOMImmutableDataChangeEvent>> entry : events.asMap().entrySet()) {
-            addNotificationTask(taskListBuilder, entry.getKey(), entry.getValue());
-        }
-        return taskListBuilder.build();
-    }
-
-    /**
-     * Adds notification task to task list.
-     *
-     * If entry collection contains one event, this event is reused and added to
-     * notification tasks for listeners (see
-     * {@link #addNotificationTaskByScope(com.google.common.collect.ImmutableList.Builder, Node, DOMImmutableDataChangeEvent)}
-     * . Otherwise events are merged by scope and distributed between listeners
-     * to particular scope. See
-     * {@link #addNotificationTasksAndMergeEvents(com.google.common.collect.ImmutableList.Builder, Node, java.util.Collection)}
-     * .
-     *
-     * @param taskListBuilder
-     * @param listeners
-     * @param entries
-     */
-    private void addNotificationTask(final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder,
-            final ListenerTree.Node listeners, final Collection<DOMImmutableDataChangeEvent> entries) {
-
-        if (!entries.isEmpty()) {
-            if (entries.size() == 1) {
-                addNotificationTaskByScope(taskListBuilder, listeners, Iterables.getOnlyElement(entries));
-            } else {
-                addNotificationTasksAndMergeEvents(taskListBuilder, listeners, entries);
-            }
-        }
-    }
+            // Defensive: reset internal state
+            collectedEvents = ArrayListMultimap.create();
 
-    /**
-     *
-     * Add notification deliveries task to the listener.
-     *
-     *
-     * @param taskListBuilder
-     * @param listeners
-     * @param event
-     */
-    private void addNotificationTaskByScope(
-            final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
-            final DOMImmutableDataChangeEvent event) {
-        DataChangeScope eventScope = event.getScope();
-        for (DataChangeListenerRegistration<?> listenerReg : listeners.getListeners()) {
-            DataChangeScope listenerScope = listenerReg.getScope();
-            List<DataChangeListenerRegistration<?>> listenerSet = Collections
-                    .<DataChangeListenerRegistration<?>> singletonList(listenerReg);
-            if (eventScope == DataChangeScope.BASE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
-            } else if (eventScope == DataChangeScope.ONE && listenerScope != DataChangeScope.BASE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
-            } else if (eventScope == DataChangeScope.SUBTREE && listenerScope == DataChangeScope.SUBTREE) {
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
-            }
-        }
-    }
+            // Run through the tree
+            final ResolveDataChangeState s = ResolveDataChangeState.initial(candidate.getRootPath(), w.getRootNode());
+            resolveAnyChangeEvent(s, candidate.getRootNode());
 
-    /**
-     *
-     * Add notification tasks with merged event
-     *
-     * Separate Events by scope and creates merged notification tasks for each
-     * and every scope which is present.
-     *
-     * Adds merged events to task list based on scope requested by client.
-     *
-     * @param taskListBuilder
-     * @param listeners
-     * @param entries
-     */
-    private void addNotificationTasksAndMergeEvents(
-            final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final ListenerTree.Node listeners,
-            final Collection<DOMImmutableDataChangeEvent> entries) {
-
-        final Builder baseBuilder = builder(DataChangeScope.BASE);
-        final Builder oneBuilder = builder(DataChangeScope.ONE);
-        final Builder subtreeBuilder = builder(DataChangeScope.SUBTREE);
-
-        boolean baseModified = false;
-        boolean oneModified = false;
-        boolean subtreeModified = false;
-        for (final DOMImmutableDataChangeEvent entry : entries) {
-            switch (entry.getScope()) {
-            // Absence of breaks is intentional here. Subtree contains base and
-            // one, one also contains base
-            case BASE:
-                baseBuilder.merge(entry);
-                baseModified = true;
-            case ONE:
-                oneBuilder.merge(entry);
-                oneModified = true;
-            case SUBTREE:
-                subtreeBuilder.merge(entry);
-                subtreeModified = true;
+            /*
+             * Convert to tasks, but be mindful of multiple values -- those indicate multiple
+             * wildcard matches, which need to be merged.
+             */
+            final Collection<ChangeListenerNotifyTask> ret = new ArrayList<>();
+            for (Entry<DataChangeListenerRegistration<?>, Collection<DOMImmutableDataChangeEvent>> e : collectedEvents.asMap().entrySet()) {
+                final Collection<DOMImmutableDataChangeEvent> col = e.getValue();
+                final DOMImmutableDataChangeEvent event;
+
+                if (col.size() != 1) {
+                    final Builder b = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE);
+                    for (DOMImmutableDataChangeEvent i : col) {
+                        b.merge(i);
+                    }
+
+                    event = b.build();
+                    LOG.trace("Merged events {} into event {}", col, event);
+                } else {
+                    event = col.iterator().next();
+                }
+
+                ret.add(new ChangeListenerNotifyTask(e.getKey(), event, notificationMgr));
             }
-        }
 
-        if (baseModified) {
-            addNotificationTaskExclusively(taskListBuilder, listeners, baseBuilder.build());
-        }
-        if (oneModified) {
-            addNotificationTaskExclusively(taskListBuilder, listeners, oneBuilder.build());
-        }
-        if (subtreeModified) {
-            addNotificationTaskExclusively(taskListBuilder, listeners, subtreeBuilder.build());
-        }
-    }
-
-    private void addNotificationTaskExclusively(
-            final ImmutableList.Builder<ChangeListenerNotifyTask> taskListBuilder, final Node listeners,
-            final DOMImmutableDataChangeEvent event) {
-        for (DataChangeListenerRegistration<?> listener : listeners.getListeners()) {
-            if (listener.getScope() == event.getScope()) {
-                Set<DataChangeListenerRegistration<?>> listenerSet = Collections
-                        .<DataChangeListenerRegistration<?>> singleton(listener);
-                taskListBuilder.add(new ChangeListenerNotifyTask(listenerSet, event, notificationMgr));
-            }
+            // FIXME: so now we have tasks to submit tasks... Inception-style!
+            LOG.debug("Created tasks {}", ret);
+            return ret;
         }
     }
 
@@ -245,94 +121,90 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
      *            - Original (before) state of current node
      * @param after
      *            - After state of current node
-     * @return Data Change Event of this node and all it's children
+     * @return True if the subtree changed, false otherwise
      */
-    private DOMImmutableDataChangeEvent resolveAnyChangeEvent(final YangInstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode node) {
-
+    private boolean resolveAnyChangeEvent(final ResolveDataChangeState state, final DataTreeCandidateNode node) {
         if (node.getModificationType() != ModificationType.UNMODIFIED &&
                 !node.getDataAfter().isPresent() && !node.getDataBefore().isPresent()) {
             LOG.debug("Modification at {} has type {}, but no before- and after-data. Assuming unchanged.",
-                    path, node.getModificationType());
-            return NO_CHANGE;
+                    state.getPath(), node.getModificationType());
+            return false;
         }
 
         // no before and after state is present
 
         switch (node.getModificationType()) {
         case SUBTREE_MODIFIED:
-            return resolveSubtreeChangeEvent(path, listeners, node);
+            return resolveSubtreeChangeEvent(state, node);
         case MERGE:
         case WRITE:
             Preconditions.checkArgument(node.getDataAfter().isPresent(),
-                    "Modification at {} has type {} but no after-data", path, node.getModificationType());
-            if (node.getDataBefore().isPresent()) {
-                return resolveReplacedEvent(path, listeners, node.getDataBefore().get(), node.getDataAfter().get());
-            } else {
-                return resolveCreateEvent(path, listeners, node.getDataAfter().get());
+                    "Modification at {} has type {} but no after-data", state.getPath(), node.getModificationType());
+            if (!node.getDataBefore().isPresent()) {
+                resolveCreateEvent(state, node.getDataAfter().get());
+                return true;
             }
+
+            return resolveReplacedEvent(state, node.getDataBefore().get(), node.getDataAfter().get());
         case DELETE:
             Preconditions.checkArgument(node.getDataBefore().isPresent(),
-                    "Modification at {} has type {} but no before-data", path, node.getModificationType());
-            return resolveDeleteEvent(path, listeners, node.getDataBefore().get());
+                    "Modification at {} has type {} but no before-data", state.getPath(), node.getModificationType());
+            resolveDeleteEvent(state, node.getDataBefore().get());
+            return true;
         case UNMODIFIED:
-            return NO_CHANGE;
+            return false;
         }
 
-        throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), path));
+        throw new IllegalStateException(String.format("Unhandled node state %s at %s", node.getModificationType(), state.getPath()));
     }
 
-    private DOMImmutableDataChangeEvent resolveReplacedEvent(final YangInstanceIdentifier path,
-            final Collection<Node> listeners, final NormalizedNode<?, ?> beforeData,
-            final NormalizedNode<?, ?> afterData) {
-
-        // FIXME: BUG-1493: check the listeners to prune unneeded changes:
-        //                  for subtrees, we have to do all
-        //                  for one, we need to expand children
-        //                  for base, we just report replacement
+    private boolean resolveReplacedEvent(final ResolveDataChangeState state,
+            final NormalizedNode<?, ?> beforeData, final NormalizedNode<?, ?> afterData) {
 
         if (beforeData instanceof NormalizedNodeContainer<?, ?, ?>) {
-            // Node is container (contains child) and we have interested
-            // listeners registered for it, that means we need to do
-            // resolution of changes on children level and can not
-            // shortcut resolution.
-            LOG.trace("Resolving subtree replace event for {} before {}, after {}",path,beforeData,afterData);
+            /*
+             * Node is a container (contains a child) and we have interested
+             * listeners registered for it, that means we need to do
+             * resolution of changes on children level and can not
+             * shortcut resolution.
+             */
+            LOG.trace("Resolving subtree replace event for {} before {}, after {}", state.getPath(), beforeData, afterData);
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) beforeData;
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) afterData;
-            return resolveNodeContainerReplaced(path, listeners, beforeCont, afterCont);
-        } else if (!beforeData.equals(afterData)) {
-            // Node is Leaf type (does not contain child nodes)
-            // so normal equals method is sufficient for determining change.
-            LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
-            DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
-                    .addUpdated(path, beforeData, afterData).build();
-            addPartialTask(listeners, event);
-            return event;
-        } else {
-            return NO_CHANGE;
+            return resolveNodeContainerReplaced(state, beforeCont, afterCont);
         }
+
+        // Node is a Leaf type (does not contain child nodes)
+        // so normal equals method is sufficient for determining change.
+        if (beforeData.equals(afterData)) {
+            LOG.trace("Skipping equal leaf {}", state.getPath());
+            return false;
+        }
+
+        LOG.trace("Resolving leaf replace event for {} , before {}, after {}", state.getPath(), beforeData, afterData);
+        DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE).addUpdated(state.getPath(), beforeData, afterData).build();
+        state.addEvent(event);
+        state.collectEvents(beforeData, afterData, collectedEvents);
+        return true;
     }
 
-    private DOMImmutableDataChangeEvent resolveNodeContainerReplaced(final YangInstanceIdentifier path,
-            final Collection<Node> listeners,
+    private boolean resolveNodeContainerReplaced(final ResolveDataChangeState state,
             final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> beforeCont,
                     final NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont) {
-        final List<DOMImmutableDataChangeEvent> childChanges = new LinkedList<>();
+        if (!state.needsProcessing()) {
+            LOG.trace("Not processing replaced container {}", state.getPath());
+            return true;
+        }
 
         // We look at all children from before and compare it with after state.
+        boolean childChanged = false;
         for (NormalizedNode<PathArgument, ?> beforeChild : beforeCont.getValue()) {
             final PathArgument childId = beforeChild.getIdentifier();
 
-            YangInstanceIdentifier childPath = path.node(childId);
-            Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-            Optional<NormalizedNode<PathArgument, ?>> afterChild = afterCont.getChild(childId);
-            DOMImmutableDataChangeEvent childChange = resolveNodeContainerChildUpdated(childPath, childListeners,
-                    beforeChild, afterChild);
-            // If change is empty (equals to NO_CHANGE)
-            if (childChange != NO_CHANGE) {
-                childChanges.add(childChange);
+            if (resolveNodeContainerChildUpdated(state.child(childId), beforeChild, afterCont.getChild(childId))) {
+                childChanged = true;
             }
         }
 
@@ -345,187 +217,120 @@ final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListe
              * created.
              */
             if (!beforeCont.getChild(childId).isPresent()) {
-                Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-                YangInstanceIdentifier childPath = path.node(childId);
-                childChanges.add(resolveSameEventRecursivelly(childPath , childListeners, afterChild,
-                        DOMImmutableDataChangeEvent.getCreateEventFactory()));
+                resolveSameEventRecursivelly(state.child(childId), afterChild, DOMImmutableDataChangeEvent.getCreateEventFactory());
+                childChanged = true;
             }
         }
-        if (childChanges.isEmpty()) {
-            return NO_CHANGE;
-        }
 
-        Builder eventBuilder = builder(DataChangeScope.BASE) //
-                .setBefore(beforeCont) //
-                .setAfter(afterCont)
-                .addUpdated(path, beforeCont, afterCont);
-        for (DOMImmutableDataChangeEvent childChange : childChanges) {
-            eventBuilder.merge(childChange);
+        if (childChanged) {
+            DOMImmutableDataChangeEvent event = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE)
+                    .addUpdated(state.getPath(), beforeCont, afterCont).build();
+            state.addEvent(event);
         }
 
-        DOMImmutableDataChangeEvent replaceEvent = eventBuilder.build();
-        addPartialTask(listeners, replaceEvent);
-        return replaceEvent;
+        state.collectEvents(beforeCont, afterCont, collectedEvents);
+        return childChanged;
     }
 
-    private DOMImmutableDataChangeEvent resolveNodeContainerChildUpdated(final YangInstanceIdentifier path,
-            final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> before,
-            final Optional<NormalizedNode<PathArgument, ?>> after) {
-
+    private boolean resolveNodeContainerChildUpdated(final ResolveDataChangeState state,
+            final NormalizedNode<PathArgument, ?> before, final Optional<NormalizedNode<PathArgument, ?>> after) {
         if (after.isPresent()) {
             // REPLACE or SUBTREE Modified
-            return resolveReplacedEvent(path, listeners, before, after.get());
-
-        } else {
-            // AFTER state is not present - child was deleted.
-            return resolveSameEventRecursivelly(path, listeners, before,
-                    DOMImmutableDataChangeEvent.getRemoveEventFactory());
+            return resolveReplacedEvent(state, before, after.get());
         }
+
+        // AFTER state is not present - child was deleted.
+        resolveSameEventRecursivelly(state, before, DOMImmutableDataChangeEvent.getRemoveEventFactory());
+        return true;
     }
 
     /**
      * Resolves create events deep down the interest listener tree.
      *
-     *
      * @param path
      * @param listeners
      * @param afterState
      * @return
      */
-    private DOMImmutableDataChangeEvent resolveCreateEvent(final YangInstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> afterState) {
+    private void resolveCreateEvent(final ResolveDataChangeState state, final NormalizedNode<?, ?> afterState) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
         final NormalizedNode<PathArgument, ?> node = (NormalizedNode) afterState;
-        return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
+        resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getCreateEventFactory());
     }
 
-    private DOMImmutableDataChangeEvent resolveDeleteEvent(final YangInstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final NormalizedNode<?, ?> beforeState) {
-
+    private void resolveDeleteEvent(final ResolveDataChangeState state, final NormalizedNode<?, ?> beforeState) {
         @SuppressWarnings({ "unchecked", "rawtypes" })
         final NormalizedNode<PathArgument, ?> node = (NormalizedNode) beforeState;
-        return resolveSameEventRecursivelly(path, listeners, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
+        resolveSameEventRecursivelly(state, node, DOMImmutableDataChangeEvent.getRemoveEventFactory());
     }
 
-    private DOMImmutableDataChangeEvent resolveSameEventRecursivelly(final YangInstanceIdentifier path,
-            final Collection<Node> listeners, final NormalizedNode<PathArgument, ?> node,
-            final SimpleEventFactory eventFactory) {
-        final DOMImmutableDataChangeEvent event = eventFactory.create(path, node);
-        DOMImmutableDataChangeEvent propagateEvent = event;
+    private void resolveSameEventRecursivelly(final ResolveDataChangeState state,
+            final NormalizedNode<PathArgument, ?> node, final SimpleEventFactory eventFactory) {
+        if (!state.needsProcessing()) {
+            LOG.trace("Skipping child {}", state.getPath());
+            return;
+        }
+
         // We have listeners for this node or it's children, so we will try
         // to do additional processing
         if (node instanceof NormalizedNodeContainer<?, ?, ?>) {
-            LOG.trace("Resolving subtree recursive event for {}, type {}", path, eventFactory);
-
-            Builder eventBuilder = builder(DataChangeScope.BASE);
-            eventBuilder.merge(event);
-            eventBuilder.setBefore(event.getOriginalSubtree());
-            eventBuilder.setAfter(event.getUpdatedSubtree());
+            LOG.trace("Resolving subtree recursive event for {}, type {}", state.getPath(), eventFactory);
 
             // Node has children, so we will try to resolve it's children
             // changes.
             @SuppressWarnings("unchecked")
             NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> container = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) node;
             for (NormalizedNode<PathArgument, ?> child : container.getValue()) {
-                PathArgument childId = child.getIdentifier();
+                final PathArgument childId = child.getIdentifier();
+
                 LOG.trace("Resolving event for child {}", childId);
-                Collection<Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-                eventBuilder.merge(resolveSameEventRecursivelly(path.node(childId), childListeners, child, eventFactory));
+                resolveSameEventRecursivelly(state.child(childId), child, eventFactory);
             }
-            propagateEvent = eventBuilder.build();
         }
-        if (!listeners.isEmpty()) {
-            addPartialTask(listeners, propagateEvent);
-        }
-        return propagateEvent;
-    }
 
-    private DOMImmutableDataChangeEvent resolveSubtreeChangeEvent(final YangInstanceIdentifier path,
-            final Collection<ListenerTree.Node> listeners, final DataTreeCandidateNode modification) {
+        final DOMImmutableDataChangeEvent event = eventFactory.create(state.getPath(), node);
+        LOG.trace("Adding event {} at path {}", event, state.getPath());
+        state.addEvent(event);
+        state.collectEvents(event.getOriginalSubtree(), event.getUpdatedSubtree(), collectedEvents);
+    }
 
-        Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", path);
-        Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", path);
+    private boolean resolveSubtreeChangeEvent(final ResolveDataChangeState state, final DataTreeCandidateNode modification) {
+        Preconditions.checkArgument(modification.getDataBefore().isPresent(), "Subtree change with before-data not present at path %s", state.getPath());
+        Preconditions.checkArgument(modification.getDataAfter().isPresent(), "Subtree change with after-data not present at path %s", state.getPath());
 
-        Builder one = builder(DataChangeScope.ONE).
-                setBefore(modification.getDataBefore().get()).
-                setAfter(modification.getDataAfter().get());
-        Builder subtree = builder(DataChangeScope.SUBTREE).
-                setBefore(modification.getDataBefore().get()).
-                setAfter(modification.getDataAfter().get());
-        boolean oneModified = false;
+        DataChangeScope scope = null;
         for (DataTreeCandidateNode childMod : modification.getChildNodes()) {
-            PathArgument childId = childMod.getIdentifier();
-            YangInstanceIdentifier childPath = path.node(childId);
-            Collection<ListenerTree.Node> childListeners = getListenerChildrenWildcarded(listeners, childId);
-
+            final ResolveDataChangeState childState = state.child(childMod.getIdentifier());
 
             switch (childMod.getModificationType()) {
             case WRITE:
             case MERGE:
             case DELETE:
-                one.merge(resolveAnyChangeEvent(childPath, childListeners, childMod));
-                oneModified = true;
+                if (resolveAnyChangeEvent(childState, childMod)) {
+                    scope = DataChangeScope.ONE;
+                }
                 break;
             case SUBTREE_MODIFIED:
-                subtree.merge(resolveSubtreeChangeEvent(childPath, childListeners, childMod));
+                if (resolveSubtreeChangeEvent(childState, childMod) && scope == null) {
+                    scope = DataChangeScope.SUBTREE;
+                }
                 break;
             case UNMODIFIED:
                 // no-op
                 break;
             }
         }
-        final DOMImmutableDataChangeEvent oneChangeEvent;
-        if(oneModified) {
-            one.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
-            oneChangeEvent = one.build();
-            subtree.merge(oneChangeEvent);
-        } else {
-            oneChangeEvent = null;
-            subtree.addUpdated(path, modification.getDataBefore().get(), modification.getDataAfter().get());
-        }
-        DOMImmutableDataChangeEvent subtreeEvent = subtree.build();
-        if (!listeners.isEmpty()) {
-            if(oneChangeEvent != null) {
-                addPartialTask(listeners, oneChangeEvent);
-            }
-            addPartialTask(listeners, subtreeEvent);
-        }
-        return subtreeEvent;
-    }
 
-    private DOMImmutableDataChangeEvent addPartialTask(final Collection<ListenerTree.Node> listeners,
-            final DOMImmutableDataChangeEvent event) {
-        for (ListenerTree.Node listenerNode : listeners) {
-            if (!listenerNode.getListeners().isEmpty()) {
-                LOG.trace("Adding event {} for listeners {}",event,listenerNode);
-                events.put(listenerNode, event);
-            }
-        }
-        return event;
-    }
+        final NormalizedNode<?, ?> before = modification.getDataBefore().get();
+        final NormalizedNode<?, ?> after = modification.getDataAfter().get();
 
-    private static Collection<ListenerTree.Node> getListenerChildrenWildcarded(final Collection<ListenerTree.Node> parentNodes,
-            final PathArgument child) {
-        if (parentNodes.isEmpty()) {
-            return Collections.emptyList();
-        }
-        com.google.common.collect.ImmutableList.Builder<ListenerTree.Node> result = ImmutableList.builder();
-        if (child instanceof NodeWithValue || child instanceof NodeIdentifierWithPredicates) {
-            NodeIdentifier wildcardedIdentifier = new NodeIdentifier(child.getNodeType());
-            addChildrenNodesToBuilder(result, parentNodes, wildcardedIdentifier);
+        if (scope != null) {
+            DOMImmutableDataChangeEvent one = DOMImmutableDataChangeEvent.builder(scope).addUpdated(state.getPath(), before, after).build();
+            state.addEvent(one);
         }
-        addChildrenNodesToBuilder(result, parentNodes, child);
-        return result.build();
-    }
 
-    private static void addChildrenNodesToBuilder(final ImmutableList.Builder<ListenerTree.Node> result,
-            final Collection<ListenerTree.Node> parentNodes, final PathArgument childIdentifier) {
-        for (ListenerTree.Node node : parentNodes) {
-            Optional<ListenerTree.Node> child = node.getChild(childIdentifier);
-            if (child.isPresent()) {
-                result.add(child.get());
-            }
-        }
+        state.collectEvents(before, after, collectedEvents);
+        return scope != null;
     }
 
     @SuppressWarnings("rawtypes")
diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/md/sal/dom/store/impl/ResolveDataChangeState.java
new file mode 100644 (file)
index 0000000..dca2eff
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.md.sal.dom.store.impl;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Multimap;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
+import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree.Node;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeWithValue;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Recursion state used in {@link ResolveDataChangeEventsTask}. Instances of this
+ * method track which listeners are affected by a particular change node. It takes
+ * care of properly inheriting SUB/ONE listeners and also provides a means to
+ * understand when actual processing need not occur.
+ */
+final class ResolveDataChangeState {
+    private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeState.class);
+    /**
+     * Inherited from all parents
+     */
+    private final Iterable<Builder> inheritedSub;
+    /**
+     * Inherited from immediate parent
+     */
+    private final Iterable<Builder> inheritedOne;
+    private final YangInstanceIdentifier nodeId;
+    private final Collection<Node> nodes;
+
+    private final Map<DataChangeListenerRegistration<?>, Builder> subBuilders = new HashMap<>();
+    private final Map<DataChangeListenerRegistration<?>, Builder> oneBuilders = new HashMap<>();
+    private final Map<DataChangeListenerRegistration<?>, Builder> baseBuilders = new HashMap<>();
+
+    private ResolveDataChangeState(final YangInstanceIdentifier nodeId,
+            final Iterable<Builder> inheritedSub, final Iterable<Builder> inheritedOne,
+            final Collection<Node> nodes) {
+        this.nodeId = Preconditions.checkNotNull(nodeId);
+        this.nodes = Preconditions.checkNotNull(nodes);
+        this.inheritedSub = Preconditions.checkNotNull(inheritedSub);
+        this.inheritedOne = Preconditions.checkNotNull(inheritedOne);
+
+        /*
+         * Collect the nodes which need to be propagated from us to the child.
+         */
+        for (Node n : nodes) {
+            for (DataChangeListenerRegistration<?> l : n.getListeners()) {
+                final Builder b = DOMImmutableDataChangeEvent.builder(DataChangeScope.BASE);
+                switch (l.getScope()) {
+                case BASE:
+                    baseBuilders.put(l, b);
+                    break;
+                case ONE:
+                    oneBuilders.put(l, b);
+                    break;
+                case SUBTREE:
+                    subBuilders.put(l, b);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
+     * Create an initial state handle at a particular root node.
+     *
+     * @param rootId root instance identifier
+     * @param root root node
+     * @return
+     */
+    public static ResolveDataChangeState initial(final YangInstanceIdentifier rootId, final Node root) {
+        return new ResolveDataChangeState(rootId, Collections.<Builder>emptyList(),
+            Collections.<Builder>emptyList(), Collections.singletonList(root));
+    }
+
+    /**
+     * Create a state handle for iterating over a particular child.
+     *
+     * @param childId ID of the child
+     * @return State handle
+     */
+    public ResolveDataChangeState child(final PathArgument childId) {
+        return new ResolveDataChangeState(nodeId.node(childId),
+            Iterables.concat(inheritedSub, subBuilders.values()),
+            oneBuilders.values(), getListenerChildrenWildcarded(nodes, childId));
+    }
+
+    /**
+     * Get the current path
+     *
+     * @return Current path.
+     */
+    public YangInstanceIdentifier getPath() {
+        return nodeId;
+    }
+
+    /**
+     * Check if this child needs processing.
+     *
+     * @return True if processing needs to occur, false otherwise.
+     */
+    public boolean needsProcessing() {
+        // May have underlying listeners, so we need to process
+        if (!nodes.isEmpty()) {
+            return true;
+        }
+        // Have SUBTREE listeners
+        if (!Iterables.isEmpty(inheritedSub)) {
+            return true;
+        }
+        // Have ONE listeners
+        if (!Iterables.isEmpty(inheritedOne)) {
+            return true;
+        }
+
+        // FIXME: do we need anything else? If not, flip this to 'false'
+        return true;
+    }
+
+    /**
+     * Add an event to all current listeners.
+     *
+     * @param event
+     */
+    public void addEvent(final DOMImmutableDataChangeEvent event) {
+        // Subtree builders get always notified
+        for (Builder b : subBuilders.values()) {
+            b.merge(event);
+        }
+        for (Builder b : inheritedSub) {
+            b.merge(event);
+        }
+
+        if (event.getScope() == DataChangeScope.ONE || event.getScope() == DataChangeScope.BASE) {
+            for (Builder b : oneBuilders.values()) {
+                b.merge(event);
+            }
+        }
+
+        if (event.getScope() == DataChangeScope.BASE) {
+            for (Builder b : inheritedOne) {
+                b.merge(event);
+            }
+            for (Builder b : baseBuilders.values()) {
+                b.merge(event);
+            }
+        }
+    }
+
+    /**
+     * Gather all non-empty events into the provided map.
+     *
+     * @param before before-image
+     * @param after after-image
+     * @param map target map
+     */
+    public void collectEvents(final NormalizedNode<?, ?> before, final NormalizedNode<?, ?> after,
+            final Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> map) {
+        for (Entry<DataChangeListenerRegistration<?>, Builder> e : baseBuilders.entrySet()) {
+            final Builder b = e.getValue();
+            if (!b.isEmpty()) {
+                map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+            }
+        }
+        for (Entry<DataChangeListenerRegistration<?>, Builder> e : oneBuilders.entrySet()) {
+            final Builder b = e.getValue();
+            if (!b.isEmpty()) {
+                map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+            }
+        }
+        for (Entry<DataChangeListenerRegistration<?>, Builder> e : subBuilders.entrySet()) {
+            final Builder b = e.getValue();
+            if (!b.isEmpty()) {
+                map.put(e.getKey(), b.setBefore(before).setAfter(after).build());
+            }
+        }
+
+        LOG.trace("Collected events {}", map);
+    }
+
+    private static Collection<Node> getListenerChildrenWildcarded(final Collection<Node> parentNodes,
+            final PathArgument child) {
+        if (parentNodes.isEmpty()) {
+            return Collections.emptyList();
+        }
+
+        final List<Node> result = new ArrayList<>();
+        if (child instanceof NodeWithValue || child instanceof NodeIdentifierWithPredicates) {
+            NodeIdentifier wildcardedIdentifier = new NodeIdentifier(child.getNodeType());
+            addChildNodes(result, parentNodes, wildcardedIdentifier);
+        }
+        addChildNodes(result, parentNodes, child);
+        return result;
+    }
+
+    private static void addChildNodes(final List<Node> result, final Collection<Node> parentNodes, final PathArgument childIdentifier) {
+        for (Node node : parentNodes) {
+            Optional<Node> child = node.getChild(childIdentifier);
+            if (child.isPresent()) {
+                result.add(child.get());
+            }
+        }
+    }
+}
index 76a9354..0e064cd 100644 (file)
@@ -7,8 +7,11 @@
  */
 package org.opendaylight.controller.md.sal.dom.store.impl;
 
+import com.google.common.util.concurrent.MoreExecutors;
+
 import java.util.Collection;
 import java.util.Map;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
@@ -36,8 +39,6 @@ import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContaine
 import org.opendaylight.yangtools.yang.data.impl.schema.builder.api.DataContainerNodeBuilder;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import com.google.common.util.concurrent.MoreExecutors;
-
 public abstract class AbstractDataChangeListenerTest {
 
     protected static final YangInstanceIdentifier TOP_LEVEL = YangInstanceIdentifier
@@ -74,6 +75,13 @@ public abstract class AbstractDataChangeListenerTest {
         }
     }
 
+    /**
+     * Create a new test task. The task will operate on the backed database,
+     * and will use the proper background executor service.
+     *
+     * @return Test task initialized to clean up {@value #TOP_LEVEL} and its
+     *         children.
+     */
     public final DatastoreTestTask newTestTask() {
         return new DatastoreTestTask(datastore, dclExecutorService).cleanup(DatastoreTestTask
                 .simpleDelete(TOP_LEVEL));
index 84337de..af58f63 100644 (file)
@@ -13,10 +13,18 @@ import org.junit.Test;
 import org.opendaylight.controller.md.sal.dom.store.impl.DatastoreTestTask.WriteTransactionCustomizer;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
 
+/**
+ * Base template for a test suite for testing DataChangeListener functionality.
+ */
 public abstract class DefaultDataChangeListenerTestSuite extends AbstractDataChangeListenerTest {
 
     protected static final String FOO_SIBLING = "foo-sibling";
 
+    /**
+     * Callback invoked when the test suite can modify task parameters.
+     *
+     * @param task Update task configuration as needed
+     */
     abstract protected void customizeTask(DatastoreTestTask task);
 
     @Test
index cdf465a..ddbba76 100644 (file)
@@ -34,8 +34,11 @@ public class WildcardedScopeBaseTest extends DefaultDataChangeListenerTestSuite
 
         assertNotNull(change);
 
-        assertNotContains(change.getCreatedData(), TOP_LEVEL);
-        assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR));
+        /*
+         * Created data must not contain nested-list item, since that is two-level deep.
+         */
+        assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR));
+        assertContains(change.getCreatedData(), path(FOO) );
 
         assertEmpty(change.getUpdatedData());
         assertEmpty(change.getRemovedPaths());
@@ -48,11 +51,18 @@ public class WildcardedScopeBaseTest extends DefaultDataChangeListenerTestSuite
 
         AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change = task.getChangeEvent();
         assertNotNull(change);
-
-        assertContains(change.getCreatedData(), path(FOO, BAZ));
+        /*
+         * Created data must NOT contain nested-list item since scope is base, and change is two
+         * level deep.
+         */
+        assertNotContains(change.getCreatedData(), path(FOO, BAZ));
         assertContains(change.getUpdatedData(), path(FOO));
         assertNotContains(change.getUpdatedData(), TOP_LEVEL);
-        assertContains(change.getRemovedPaths(), path(FOO, BAR));
+        /*
+         * Removed data must NOT contain nested-list item since scope is base, and change is two
+         * level deep.
+         */
+        assertNotContains(change.getRemovedPaths(), path(FOO, BAR));
 
     }
 
@@ -64,8 +74,9 @@ public class WildcardedScopeBaseTest extends DefaultDataChangeListenerTestSuite
         assertNotNull(change);
         assertFalse(change.getCreatedData().isEmpty());
 
-        assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR), path(FOO, BAZ));
-        assertNotContains(change.getCreatedData(), TOP_LEVEL);
+        // Base event should contain only changed item, no details about child.
+        assertContains(change.getCreatedData(), path(FOO));
+        assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR), path(FOO, BAZ));
         assertEmpty(change.getUpdatedData());
         assertEmpty(change.getRemovedPaths());
 
@@ -95,7 +106,12 @@ public class WildcardedScopeBaseTest extends DefaultDataChangeListenerTestSuite
         assertEmpty(change.getUpdatedData());
 
         assertNotContains(change.getUpdatedData(), TOP_LEVEL);
-        assertContains(change.getRemovedPaths(), path(FOO),path(FOO, BAZ),path(FOO,BAR));
+        /*
+         *  Scope base listener event should contain top-level-list item and nested list path
+         *  and should not contain baz, bar which are two-level deep
+         */
+        assertContains(change.getRemovedPaths(), path(FOO));
+        assertNotContains(change.getRemovedPaths(),path(FOO, BAZ),path(FOO,BAR));
     }
 
     @Override
index 3407e0f..75f9fce 100644 (file)
@@ -14,6 +14,7 @@ import java.util.concurrent.ExecutionException;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.top.level.list.NestedList;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -34,8 +35,8 @@ public class WildcardedScopeOneTest extends DefaultDataChangeListenerTestSuite {
 
         assertNotNull(change);
 
-        assertNotContains(change.getCreatedData(), TOP_LEVEL);
-        assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR));
+        assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR));
+        assertContains(change.getCreatedData(), path(FOO), path(FOO).node(NestedList.QNAME));
 
         assertEmpty(change.getUpdatedData());
         assertEmpty(change.getRemovedPaths());
@@ -48,11 +49,18 @@ public class WildcardedScopeOneTest extends DefaultDataChangeListenerTestSuite {
 
         AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> change = task.getChangeEvent();
         assertNotNull(change);
-
-        assertContains(change.getCreatedData(), path(FOO, BAZ));
-        assertContains(change.getUpdatedData(), path(FOO));
+        /*
+         * Created data must NOT contain nested-list item since scope is base, and change is two
+         * level deep.
+         */
+        assertNotContains(change.getCreatedData(), path(FOO, BAZ));
+        assertContains(change.getUpdatedData(), path(FOO),path(FOO).node(NestedList.QNAME));
         assertNotContains(change.getUpdatedData(), TOP_LEVEL);
-        assertContains(change.getRemovedPaths(), path(FOO, BAR));
+        /*
+         * Removed data must NOT contain nested-list item since scope is base, and change is two
+         * level deep.
+         */
+        assertNotContains(change.getRemovedPaths(), path(FOO, BAR));
 
     }
 
@@ -64,8 +72,9 @@ public class WildcardedScopeOneTest extends DefaultDataChangeListenerTestSuite {
         assertNotNull(change);
         assertFalse(change.getCreatedData().isEmpty());
 
-        assertContains(change.getCreatedData(), path(FOO), path(FOO, BAR), path(FOO, BAZ));
-        assertNotContains(change.getCreatedData(), TOP_LEVEL);
+        // Base event should contain only changed item, and details about immediate child.
+        assertContains(change.getCreatedData(), path(FOO),path(FOO).node(NestedList.QNAME));
+        assertNotContains(change.getCreatedData(), TOP_LEVEL,path(FOO, BAR), path(FOO, BAZ));
         assertEmpty(change.getUpdatedData());
         assertEmpty(change.getRemovedPaths());
 
@@ -96,7 +105,8 @@ public class WildcardedScopeOneTest extends DefaultDataChangeListenerTestSuite {
         assertEmpty(change.getUpdatedData());
 
         assertNotContains(change.getUpdatedData(), TOP_LEVEL);
-        assertContains(change.getRemovedPaths(), path(FOO),path(FOO, BAZ),path(FOO,BAR));
+        assertContains(change.getRemovedPaths(), path(FOO),path(FOO).node(NestedList.QNAME));
+        assertNotContains(change.getRemovedPaths(), path(FOO, BAZ),path(FOO,BAR));
     }
 
     @Override
index 1a7d90e..0999eff 100644 (file)
@@ -7,8 +7,8 @@ import com.google.common.base.Predicate;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
-
 import com.google.common.collect.Sets;
+
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Set;
@@ -158,7 +158,7 @@ public final class NetconfSessionCapabilities {
             }
 
             // FIXME: do we really want to continue here?
-            moduleBasedCaps.add(QName.create(namespace, revision, moduleName));
+            moduleBasedCaps.add(QName.cachedReference(QName.create(namespace, revision, moduleName)));
             nonModuleCaps.remove(capability);
         }
 
index e2ebcb2..76f5930 100644 (file)
@@ -60,6 +60,8 @@ public class RpcRegistry extends UntypedActor {
 
     public RpcRegistry() {
         bucketStore = getContext().actorOf(Props.create(BucketStore.class), "store");
+
+        log.info("Bucket store path = {}", bucketStore.path().toString());
     }
 
     public RpcRegistry(ActorRef bucketStore) {
index 2f634ce..3b078aa 100644 (file)
@@ -9,12 +9,14 @@
 package org.opendaylight.controller.remote.rpc.registry.gossip;
 
 import akka.actor.ActorRef;
+import akka.actor.ActorRefProvider;
 import akka.actor.Address;
 import akka.actor.Props;
 import akka.actor.UntypedActor;
-import akka.cluster.Cluster;
+import akka.cluster.ClusterActorRefProvider;
 import akka.event.Logging;
 import akka.event.LoggingAdapter;
+import org.opendaylight.controller.utils.ConditionalProbe;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -64,25 +66,17 @@ public class BucketStore extends UntypedActor {
     /**
      * Cluster address for this node
      */
-    private final Address selfAddress = Cluster.get(getContext().system()).selfAddress();
+    private Address selfAddress;
 
-    /**
-     * Our private gossiper
-     */
-    private ActorRef gossiper;
+    private ConditionalProbe probe;
 
-    public BucketStore(){
-        gossiper = getContext().actorOf(Props.create(Gossiper.class), "gossiper");
-    }
+    @Override
+    public void preStart(){
+        ActorRefProvider provider = getContext().provider();
+        selfAddress = provider.getDefaultAddress();
 
-    /**
-     * This constructor is useful for testing.
-     * TODO: Pass Props instead of ActorRef
-     *
-     * @param gossiper
-     */
-    public BucketStore(ActorRef gossiper){
-        this.gossiper = gossiper;
+        if ( provider instanceof ClusterActorRefProvider)
+            getContext().actorOf(Props.create(Gossiper.class), "gossiper");
     }
 
     @Override
@@ -90,25 +84,28 @@ public class BucketStore extends UntypedActor {
 
         log.debug("Received message: node[{}], message[{}]", selfAddress, message);
 
-        if (message instanceof UpdateBucket)
-            receiveUpdateBucket(((UpdateBucket) message).getBucket());
+        if (probe != null) {
+            probe.tell(message, getSelf());
+        }
 
-        else if (message instanceof GetAllBuckets)
+        if (message instanceof ConditionalProbe) {
+            log.info("Received probe {} {}", getSelf(), message);
+            probe = (ConditionalProbe) message;
+        } else if (message instanceof UpdateBucket) {
+            receiveUpdateBucket(((UpdateBucket) message).getBucket());
+        } else if (message instanceof GetAllBuckets) {
             receiveGetAllBucket();
-
-        else if (message instanceof GetLocalBucket)
+        } else if (message instanceof GetLocalBucket) {
             receiveGetLocalBucket();
-
-        else if (message instanceof GetBucketsByMembers)
-            receiveGetBucketsByMembers(((GetBucketsByMembers) message).getMembers());
-
-        else if (message instanceof GetBucketVersions)
+        } 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 {
+        } else if (message instanceof UpdateRemoteBuckets) {
+            receiveUpdateRemoteBuckets(
+                ((UpdateRemoteBuckets) message).getBuckets());
+        } else {
             log.debug("Unhandled message [{}]", message);
             unhandled(message);
         }
@@ -230,7 +227,7 @@ public class BucketStore extends UntypedActor {
             if (remoteVersion == null) remoteVersion = -1L;
 
             //update only if remote version is newer
-            if ( remoteVersion > localVersion ) {
+            if ( remoteVersion.longValue() > localVersion.longValue() ) {
                 remoteBuckets.put(entry.getKey(), receivedBucket);
                 versions.put(entry.getKey(), remoteVersion);
             }
index 2320789..a8bc25c 100644 (file)
@@ -8,11 +8,13 @@
 package org.opendaylight.controller.remote.rpc.registry.gossip;
 
 import akka.actor.ActorRef;
+import akka.actor.ActorRefProvider;
 import akka.actor.ActorSelection;
 import akka.actor.Address;
 import akka.actor.Cancellable;
 import akka.actor.UntypedActor;
 import akka.cluster.Cluster;
+import akka.cluster.ClusterActorRefProvider;
 import akka.cluster.ClusterEvent;
 import akka.cluster.Member;
 import akka.dispatch.Mapper;
@@ -60,12 +62,12 @@ public class Gossiper extends UntypedActor {
 
     final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
 
-    Cluster cluster = Cluster.get(getContext().system());
+    private Cluster cluster;
 
     /**
      * ActorSystem's address for the current cluster node.
      */
-    private Address selfAddress = cluster.selfAddress();
+    private Address selfAddress;
 
     /**
      * All known cluster members
@@ -89,11 +91,16 @@ public class Gossiper extends UntypedActor {
 
     @Override
     public void preStart(){
-
-        cluster.subscribe(getSelf(),
-                          ClusterEvent.initialStateAsEvents(),
-                          ClusterEvent.MemberEvent.class,
-                          ClusterEvent.UnreachableMember.class);
+        ActorRefProvider provider = getContext().provider();
+        selfAddress = provider.getDefaultAddress();
+
+        if ( provider instanceof ClusterActorRefProvider ) {
+            cluster = Cluster.get(getContext().system());
+            cluster.subscribe(getSelf(),
+                    ClusterEvent.initialStateAsEvents(),
+                    ClusterEvent.MemberEvent.class,
+                    ClusterEvent.UnreachableMember.class);
+        }
 
         if (autoStartGossipTicks) {
             gossipTask = getContext().system().scheduler().schedule(
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/utils/ConditionalProbe.java b/opendaylight/md-sal/sal-remoterpc-connector/src/main/java/org/opendaylight/controller/utils/ConditionalProbe.java
new file mode 100644 (file)
index 0000000..13cec54
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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.utils;
+
+import akka.actor.ActorRef;
+import com.google.common.base.Predicate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ConditionalProbe {
+    private final ActorRef actorRef;
+    private final Predicate predicate;
+    Logger log = LoggerFactory.getLogger(ConditionalProbe.class);
+
+    public ConditionalProbe(ActorRef actorRef, Predicate predicate) {
+        this.actorRef = actorRef;
+        this.predicate = predicate;
+    }
+
+    public void tell(Object message, ActorRef sender){
+        if(predicate.apply(message)) {
+            log.info("sending message to probe {}", message);
+            actorRef.tell(message, sender);
+        }
+    }
+}
index da3942a..e679374 100644 (file)
@@ -1,14 +1,16 @@
 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 com.google.common.base.Predicate;
 import com.typesafe.config.ConfigFactory;
+
 import org.junit.After;
 import org.junit.AfterClass;
 import org.junit.Assert;
@@ -16,267 +18,269 @@ import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.opendaylight.controller.remote.rpc.RouteIdentifierImpl;
+import org.opendaylight.controller.remote.rpc.registry.gossip.Messages;
 import org.opendaylight.controller.sal.connector.api.RpcRouter;
+import org.opendaylight.controller.utils.ConditionalProbe;
 import org.opendaylight.yangtools.yang.common.QName;
 import scala.concurrent.Await;
 import scala.concurrent.Future;
 import scala.concurrent.duration.FiniteDuration;
 
+import javax.annotation.Nullable;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 
+import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.AddOrUpdateRoutes;
 import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.RemoveRoutes;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRouters;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.FindRoutersReply;
-import static org.opendaylight.controller.remote.rpc.registry.RpcRegistry.Messages.SetLocalRouter;
 
 public class RpcRegistryTest {
 
-    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);
-    }
+  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 {
+    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.
+   * 1. Register rpc, ensure router can be found
+   * 2. Then remove rpc, ensure its deleted
+   *
+   * @throws URISyntaxException
+   * @throws InterruptedException
+   */
+  @Test
+  public void testAddRemoveRpcOnSameNode() throws URISyntaxException, InterruptedException {
+    validateSystemStartup();
+
+    final JavaTestKit mockBroker = new JavaTestKit(node1);
+
+    final ActorPath bucketStorePath = new ChildActorPath(registry1.path(), "store");
+
+    //install probe
+    final JavaTestKit probe1 = createProbeForMessage(
+        node1, bucketStorePath, Messages.BucketStoreMessages.UpdateBucket.class);
+
+    //Add rpc on node 1
+    registry1.tell(new SetLocalRouter(mockBroker.getRef()), mockBroker.getRef());
+    registry1.tell(getAddRouteMessage(), mockBroker.getRef());
+
+    //Bucket store should get an update bucket message. Updated bucket contains added rpc.
+    probe1.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateBucket.class);
+
+    //Now remove rpc
+    registry1.tell(getRemoveRouteMessage(), mockBroker.getRef());
+
+    //Bucket store should get an update bucket message. Rpc is removed in the updated bucket
+    probe1.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateBucket.class);
+
+
+  }
+
+
+  /**
+   * Three node cluster.
+   * 1. Register rpc on 1 node, ensure 2nd node gets updated
+   * 2. Remove rpc on 1 node, ensure 2nd node gets updated
+   *
+   * @throws URISyntaxException
+   * @throws InterruptedException
+   */
+  @Test
+  public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
 
-    /**
-     * One node cluster.
-     * 1. Register rpc, ensure router can be found
-     * 2. Then remove rpc, ensure its deleted
-     *
-     * @throws URISyntaxException
-     * @throws InterruptedException
-     */
-    @Test
-    public void testAddRemoveRpcOnSameNode() 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());
-
-        //Now remove rpc
-        registry1.tell(getRemoveRouteMessage(), mockBroker.getRef());
-        Thread.sleep(1000);
-        //find the route on node 1's registry
-        registry1.tell(new FindRouters(createRouteId()), mockBroker.getRef());
-        message = mockBroker.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
-        pairs = message.getRouterWithUpdateTime();
-
-        Assert.assertTrue(pairs.isEmpty());
-    }
+    validateSystemStartup();
+
+    final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+
+    //install probe on node2's bucket store
+    final ActorPath bucketStorePath = new ChildActorPath(registry2.path(), "store");
+    final JavaTestKit probe2 = createProbeForMessage(
+        node2, bucketStorePath, Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-    /**
-     * Three node cluster.
-     * 1. Register rpc on 1 node, ensure its router can be found on other 2.
-     * 2. Remove rpc on 1 node, ensure its removed on other 2.
-     *
-     * @throws URISyntaxException
-     * @throws InterruptedException
-     */
-    @Test
-    public void testRpcAddRemoveInCluster() throws URISyntaxException, InterruptedException {
 
-        validateSystemStartup();
+    //Add rpc on node 1
+    registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
+    registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
 
-        final JavaTestKit mockBroker1 = new JavaTestKit(node1);
-        final JavaTestKit mockBroker2 = new JavaTestKit(node2);
-        final JavaTestKit mockBroker3 = new JavaTestKit(node3);
+    //Bucket store on node2 should get a message to update its local copy of remote buckets
+    probe2.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-        //Add rpc on node 1
-        registry1.tell(new SetLocalRouter(mockBroker1.getRef()), mockBroker1.getRef());
-        registry1.tell(getAddRouteMessage(), mockBroker1.getRef());
+    //Now remove
+    registry1.tell(getRemoveRouteMessage(), mockBroker1.getRef());
 
-        Thread.sleep(1000);// give some time for bucket store data sync
+    //Bucket store on node2 should get a message to update its local copy of remote buckets
+    probe2.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-        //find the route in node 2's registry
-        List<Pair<ActorRef, Long>> pairs = findRouters(registry2, mockBroker2);
-        validateRouterReceived(pairs, mockBroker1.getRef());
+  }
 
-        //find the route in node 3's registry
-        pairs = findRouters(registry3, mockBroker3);
-        validateRouterReceived(pairs, mockBroker1.getRef());
+  /**
+   * Three node cluster.
+   * Register rpc on 2 nodes. Ensure 3rd gets updated.
+   *
+   * @throws Exception
+   */
+  @Test
+  public void testRpcAddedOnMultiNodes() throws Exception {
 
-        //Now remove
-        registry1.tell(getRemoveRouteMessage(), mockBroker1.getRef());
-        Thread.sleep(1000);// give some time for bucket store data sync
+    validateSystemStartup();
 
-        pairs = findRouters(registry2, mockBroker2);
-        Assert.assertTrue(pairs.isEmpty());
+    final JavaTestKit mockBroker1 = new JavaTestKit(node1);
+    final JavaTestKit mockBroker2 = new JavaTestKit(node2);
+    final JavaTestKit mockBroker3 = new JavaTestKit(node3);
 
-        pairs = findRouters(registry3, mockBroker3);
-        Assert.assertTrue(pairs.isEmpty());
-    }
+    registry3.tell(new SetLocalRouter(mockBroker3.getRef()), mockBroker3.getRef());
 
-    /**
-     * Three node cluster.
-     * Register rpc on 2 nodes. Ensure 2 routers are found on 3rd.
-     *
-     * @throws Exception
-     */
-    @Test
-    public void testAnRpcAddedOnMultiNodesShouldReturnMultiRouter() throws Exception {
+    //install probe on node 3
+    final ActorPath bucketStorePath = new ChildActorPath(registry3.path(), "store");
+    final JavaTestKit probe3 = createProbeForMessage(
+        node3, bucketStorePath, Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-        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);//let system come up
+    probe3.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
 
-        //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());
+    //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(1000);// give some time for bucket store data sync
+    probe3.expectMsgClass(
+        FiniteDuration.apply(10, TimeUnit.SECONDS),
+        Messages.BucketStoreMessages.UpdateRemoteBuckets.class);
+  }
 
-        //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();
+  private JavaTestKit createProbeForMessage(ActorSystem node, ActorPath subjectPath, final Class clazz) {
+    final JavaTestKit probe = new JavaTestKit(node);
 
-        validateMultiRouterReceived(pairs, mockBroker1.getRef(), mockBroker2.getRef());
+    ConditionalProbe conditionalProbe =
+        new ConditionalProbe(probe.getRef(), new Predicate() {
+          @Override
+          public boolean apply(@Nullable Object input) {
+            return clazz.equals(input.getClass());
+          }
+        });
 
-    }
+    ActorSelection subject = node.actorSelection(subjectPath);
+    subject.tell(conditionalProbe, ActorRef.noSender());
 
-    private List<Pair<ActorRef, Long>> findRouters(ActorRef registry, JavaTestKit receivingActor) throws URISyntaxException {
-        registry.tell(new FindRouters(createRouteId()), receivingActor.getRef());
-        FindRoutersReply message = receivingActor.expectMsgClass(JavaTestKit.duration("10 second"), FindRoutersReply.class);
-        return message.getRouterWithUpdateTime();
-    }
+    return probe;
 
-    private void validateMultiRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef... expected) {
-        Assert.assertTrue(actual != null);
-        Assert.assertTrue(actual.size() == expected.length);
-    }
+  }
 
-    private void validateRouterReceived(List<Pair<ActorRef, Long>> actual, ActorRef expected){
-        Assert.assertTrue(actual != null);
-        Assert.assertTrue(actual.size() == 1);
+  private void validateSystemStartup() throws InterruptedException {
 
-        for (Pair<ActorRef, Long> pair : actual){
-            Assert.assertTrue(expected.path().uid() == pair.first().path().uid());
-        }
-    }
+    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");
 
-    private void validateSystemStartup() throws InterruptedException {
+    ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
+    ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
+    ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
 
-        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");
 
-        ActorSelection gossiper1 = node1.actorSelection(gossiper1Path);
-        ActorSelection gossiper2 = node2.actorSelection(gossiper2Path);
-        ActorSelection gossiper3 = node3.actorSelection(gossiper3Path);
+    if (!resolveReference(gossiper1, gossiper2, gossiper3))
+      Assert.fail("Could not find gossipers");
+  }
 
+  private Boolean resolveReference(ActorSelection... gossipers) {
 
-        if (!resolveReference(gossiper1, gossiper2, gossiper3))
-            Assert.fail("Could not find gossipers");
-    }
+    Boolean resolved = true;
+    for (int i = 0; i < 5; i++) {
 
-    private Boolean resolveReference(ActorSelection... gossipers) throws InterruptedException {
+      resolved = true;
+      System.out.println(System.currentTimeMillis() + " Resolving gossipers; trial #" + i);
 
-        Boolean resolved = true;
+      for (ActorSelection gossiper : gossipers) {
+        ActorRef ref = null;
 
-        for (int i=0; i< 5; i++) {
-            Thread.sleep(1000);
-            for (ActorSelection gossiper : gossipers) {
-                Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(5000, TimeUnit.MILLISECONDS));
+        try {
+          Future<ActorRef> future = gossiper.resolveOne(new FiniteDuration(15000, TimeUnit.MILLISECONDS));
+          ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
+        } catch (Exception e) {
+          System.out.println("Could not find gossiper in attempt#" + i + ". Got exception " + e.getMessage());
+        }
 
-                ActorRef ref = null;
-                try {
-                    ref = Await.result(future, new FiniteDuration(10000, TimeUnit.MILLISECONDS));
-                } catch (Exception e) {
-                    e.printStackTrace();
-                }
+        if (ref == null)
+          resolved = false;
+      }
 
-                if (ref == null)
-                    resolved = false;
-            }
+      if (resolved) break;
 
-            if (resolved) break;
-        }
-        return resolved;
     }
+    return resolved;
+  }
 
-    private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
-        return new AddOrUpdateRoutes(createRouteIds());
-    }
+  private AddOrUpdateRoutes getAddRouteMessage() throws URISyntaxException {
+    return new AddOrUpdateRoutes(createRouteIds());
+  }
 
-    private RemoveRoutes getRemoveRouteMessage() throws URISyntaxException {
-        return new RemoveRoutes(createRouteIds());
-    }
+  private RemoveRoutes getRemoveRouteMessage() throws URISyntaxException {
+    return new RemoveRoutes(createRouteIds());
+  }
 
-    private List<RpcRouter.RouteIdentifier<?,?,?>> createRouteIds() throws URISyntaxException {
-        QName type = new QName(new URI("/mockrpc"), "mockrpc");
-        List<RpcRouter.RouteIdentifier<?,?,?>> routeIds = new ArrayList<>();
-        routeIds.add(new RouteIdentifierImpl(null, type, null));
-        return routeIds;
-    }
+  private List<RpcRouter.RouteIdentifier<?, ?, ?>> createRouteIds() throws URISyntaxException {
+    QName type = new QName(new URI("/mockrpc"), "mockrpc");
+    List<RpcRouter.RouteIdentifier<?, ?, ?>> routeIds = new ArrayList<>();
+    routeIds.add(new RouteIdentifierImpl(null, type, null));
+    return routeIds;
+  }
 
-    private RpcRouter.RouteIdentifier<?,?,?> createRouteId() throws URISyntaxException {
-        QName type = new QName(new URI("/mockrpc"), "mockrpc");
-        return new RouteIdentifierImpl(null, type, null);
-    }
-}
\ No newline at end of file
+}
index fd6664a..78fcbd3 100644 (file)
@@ -7,34 +7,29 @@
  */
 package org.opendaylight.controller.remote.rpc.registry.gossip;
 
-import akka.actor.ActorRef;
 import akka.actor.ActorSystem;
+import akka.actor.Address;
 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;
+import java.util.HashMap;
+import java.util.Map;
 
 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("odl-cluster"));
+        system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test"));
         system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
 
         store = createStore();
@@ -45,25 +40,108 @@ public class BucketStoreTest {
         system.shutdown();
     }
 
-    @Before
-    public void createMocks(){
-        mockStore = spy(store);
-    }
-
-    @After
-    public void resetMocks(){
-        reset(mockStore);
-    }
-
+    /**
+     * Given a new local bucket
+     * Should replace
+     */
     @Test
-    public void testReceiveUpdateBucket_WhenInputBucketShouldUpdateVersion(){
+    public void testReceiveUpdateBucket(){
         Bucket bucket = new BucketImpl();
         Long expectedVersion = bucket.getVersion();
 
-        mockStore.receiveUpdateBucket(bucket);
+        store.receiveUpdateBucket(bucket);
+
+        Assert.assertEquals(bucket, store.getLocalBucket());
+        Assert.assertEquals(expectedVersion, store.getLocalBucket().getVersion());
+    }
+
+    /**
+     * Given remote buckets
+     * Should merge with local copy of remote buckets
+     */
+    @Test
+    public void testReceiveUpdateRemoteBuckets(){
+
+        Address localAddress = system.provider().getDefaultAddress();
+        Bucket localBucket = new BucketImpl();
+
+        Address a1 = new Address("tcp", "system1");
+        Address a2 = new Address("tcp", "system2");
+        Address a3 = new Address("tcp", "system3");
+
+        Bucket b1 = new BucketImpl();
+        Bucket b2 = new BucketImpl();
+        Bucket b3 = new BucketImpl();
+
+        Map<Address, Bucket> remoteBuckets = new HashMap<>(3);
+        remoteBuckets.put(a1, b1);
+        remoteBuckets.put(a2, b2);
+        remoteBuckets.put(a3, b3);
+        remoteBuckets.put(localAddress, localBucket);
+
+        //Given remote buckets
+        store.receiveUpdateRemoteBuckets(remoteBuckets);
+
+        //Should NOT contain local bucket
+        //Should contain ONLY 3 entries i.e a1, a2, a3
+        Map<Address, Bucket> remoteBucketsInStore = store.getRemoteBuckets();
+        Assert.assertFalse("remote buckets contains local bucket", remoteBucketsInStore.containsKey(localAddress));
+        Assert.assertTrue(remoteBucketsInStore.size() == 3);
+
+        //Add a new remote bucket
+        Address a4 = new Address("tcp", "system4");
+        Bucket b4 = new BucketImpl();
+        remoteBuckets.clear();
+        remoteBuckets.put(a4, b4);
+        store.receiveUpdateRemoteBuckets(remoteBuckets);
+
+        //Should contain a4
+        //Should contain 4 entries now i.e a1, a2, a3, a4
+        remoteBucketsInStore = store.getRemoteBuckets();
+        Assert.assertTrue("Does not contain a4", remoteBucketsInStore.containsKey(a4));
+        Assert.assertTrue(remoteBucketsInStore.size() == 4);
+
+        //Update a bucket
+        Bucket b3_new = new BucketImpl();
+        remoteBuckets.clear();
+        remoteBuckets.put(a3, b3_new);
+        remoteBuckets.put(a1, null);
+        remoteBuckets.put(a2, null);
+        store.receiveUpdateRemoteBuckets(remoteBuckets);
+
+        //Should only update a3
+        remoteBucketsInStore = store.getRemoteBuckets();
+        Bucket b3_inStore = remoteBucketsInStore.get(a3);
+        Assert.assertEquals(b3_new.getVersion(), b3_inStore.getVersion());
+
+        //Should NOT update a1 and a2
+        Bucket b1_inStore = remoteBucketsInStore.get(a1);
+        Bucket b2_inStore = remoteBucketsInStore.get(a2);
+        Assert.assertEquals(b1.getVersion(), b1_inStore.getVersion());
+        Assert.assertEquals(b2.getVersion(), b2_inStore.getVersion());
+        Assert.assertTrue(remoteBucketsInStore.size() == 4);
+
+        //Should update versions map
+        //versions map contains versions for all remote buckets (4) + local bucket
+        //so it should have total 5.
+        Map<Address, Long> versionsInStore = store.getVersions();
+        Assert.assertTrue(String.format("Expected:%s, Actual:%s", 5, versionsInStore.size()),
+                          versionsInStore.size() == 5);
+        Assert.assertEquals(b1.getVersion(), versionsInStore.get(a1));
+        Assert.assertEquals(b2.getVersion(), versionsInStore.get(a2));
+        Assert.assertEquals(b3_new.getVersion(), versionsInStore.get(a3));
+        Assert.assertEquals(b4.getVersion(), versionsInStore.get(a4));
+
+        //Send older version of bucket
+        remoteBuckets.clear();
+        remoteBuckets.put(a3, b3);
+        store.receiveUpdateRemoteBuckets(remoteBuckets);
+
+        //Should NOT update a3
+        remoteBucketsInStore = store.getRemoteBuckets();
+        b3_inStore = remoteBucketsInStore.get(a3);
+        Assert.assertTrue(b3_inStore.getVersion().longValue() == b3_new.getVersion().longValue());
 
-        Assert.assertEquals(bucket, mockStore.getLocalBucket());
-        Assert.assertEquals(expectedVersion, mockStore.getLocalBucket().getVersion());
     }
 
     /**
@@ -72,11 +150,8 @@ public class BucketStoreTest {
      * @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 Props props = Props.create(BucketStore.class);
         final TestActorRef<BucketStore> testRef = TestActorRef.create(system, props, "testStore");
-
         return testRef.underlyingActor();
     }
 }
\ No newline at end of file
index bb60ed6..e61b54f 100644 (file)
@@ -45,7 +45,7 @@ public class GossiperTest {
 
     @BeforeClass
     public static void setup() throws InterruptedException {
-        system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("odl-cluster"));
+        system = ActorSystem.create("opendaylight-rpc", ConfigFactory.load().getConfig("unit-test"));
         system.actorOf(Props.create(TerminationMonitor.class), "termination-monitor");
 
         gossiper = createGossiper();
index 61fab7e..8100ed3 100644 (file)
@@ -1,6 +1,6 @@
 odl-cluster{
   akka {
-    loglevel = "INFO"
+    loglevel = "DEBUG"
     #log-config-on-start = on
 
     actor {
@@ -32,10 +32,7 @@ odl-cluster{
 unit-test{
   akka {
     loglevel = "INFO"
-    loggers = ["akka.event.slf4j.Slf4jLogger"]
-    actor {
-      provider = "akka.cluster.ClusterActorRefProvider"
-    }
+    #loggers = ["akka.event.slf4j.Slf4jLogger"]
   }
 }
 
@@ -45,6 +42,9 @@ memberA{
     loggers = ["akka.event.slf4j.Slf4jLogger"]
     actor {
       provider = "akka.cluster.ClusterActorRefProvider"
+      debug {
+        #lifecycle = on
+      }
     }
     remote {
       log-received-messages = off
diff --git a/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/logback.xml b/opendaylight/md-sal/sal-remoterpc-connector/src/test/resources/logback.xml
new file mode 100644 (file)
index 0000000..5246f01
--- /dev/null
@@ -0,0 +1,13 @@
+<configuration scan="true">
+
+  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+    <encoder>
+      <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
+      </pattern>
+    </encoder>
+  </appender>
+
+  <root level="debug">
+    <appender-ref ref="STDOUT" />
+  </root>
+</configuration>
index 2ceef32..bfa987a 100644 (file)
@@ -87,7 +87,9 @@ public class RestconfDocumentedException extends WebApplicationException {
      * Constructs an instance with the given errors.
      */
     public RestconfDocumentedException(String message, Throwable cause, List<RestconfError> errors) {
-        super(message, cause);
+        // FIXME: We override getMessage so supplied message is lost for any public access
+        // this was lost also in original code.
+        super(cause);
         if(!errors.isEmpty()) {
             this.errors = ImmutableList.copyOf(errors);
         } else {
index d7ce948..451cad4 100644 (file)
@@ -91,7 +91,7 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open
                 public void applyOperation(final ReadWriteTransaction transaction) {
                     final Node node = toTopologyNode(toTopologyNodeId(notification.getId()), notification.getNodeRef());
                     final InstanceIdentifier<Node> path = getNodePath(toTopologyNodeId(notification.getId()));
-                    transaction.put(LogicalDatastoreType.OPERATIONAL, path, node);
+                    transaction.merge(LogicalDatastoreType.OPERATIONAL, path, node, true);
                 }
             });
         }
@@ -130,7 +130,7 @@ class FlowCapableTopologyExporter implements FlowTopologyDiscoveryListener, Open
                     TerminationPoint point = toTerminationPoint(toTerminationPointId(notification.getId()),
                             notification.getNodeConnectorRef());
                     final InstanceIdentifier<TerminationPoint> path = tpPath(nodeId, point.getKey().getTpId());
-                    transaction.put(LogicalDatastoreType.OPERATIONAL, path, point);
+                    transaction.merge(LogicalDatastoreType.OPERATIONAL, path, point, true);
                     if ((fcncu.getState() != null && fcncu.getState().isLinkDown())
                             || (fcncu.getConfiguration() != null && fcncu.getConfiguration().isPORTDOWN())) {
                         removeAffectedLinks(point.getTpId());
index 004a22f..bd91af5 100644 (file)
@@ -9,7 +9,9 @@
 package org.opendaylight.controller.netconf.client;
 
 import io.netty.channel.Channel;
+
 import java.util.Collection;
+
 import org.opendaylight.controller.netconf.nettyutil.AbstractNetconfSession;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXICodec;
 import org.opendaylight.controller.netconf.nettyutil.handler.NetconfEXIToMessageDecoder;
@@ -24,8 +26,16 @@ public class NetconfClientSession extends AbstractNetconfSession<NetconfClientSe
     private static final Logger logger = LoggerFactory.getLogger(NetconfClientSession.class);
     private final Collection<String> capabilities;
 
-    public NetconfClientSession(NetconfClientSessionListener sessionListener, Channel channel, long sessionId,
-            Collection<String> capabilities) {
+    /**
+     * Construct a new session.
+     *
+     * @param sessionListener
+     * @param channel
+     * @param sessionId
+     * @param capabilities set of advertised capabilities. Expected to be immutable.
+     */
+    public NetconfClientSession(final NetconfClientSessionListener sessionListener, final Channel channel, final long sessionId,
+            final Collection<String> capabilities) {
         super(sessionListener, channel, sessionId);
         this.capabilities = capabilities;
         logger.debug("Client Session {} created", toString());
@@ -41,7 +51,7 @@ public class NetconfClientSession extends AbstractNetconfSession<NetconfClientSe
     }
 
     @Override
-    protected void addExiHandlers(NetconfEXICodec exiCodec) {
+    protected void addExiHandlers(final NetconfEXICodec exiCodec) {
         // TODO used only in negotiator, client supports only auto start-exi
         replaceMessageDecoder(new NetconfEXIToMessageDecoder(exiCodec));
         replaceMessageEncoder(new NetconfMessageToEXIEncoder(exiCodec));
index 971ea39..e2ac49c 100644 (file)
@@ -8,6 +8,8 @@
 
 package org.opendaylight.controller.netconf.client;
 
+import com.google.common.collect.ImmutableList;
+
 import io.netty.channel.Channel;
 import io.netty.channel.ChannelFuture;
 import io.netty.channel.ChannelFutureListener;
@@ -48,17 +50,17 @@ public class NetconfClientSessionNegotiator extends
 
     private static final String EXI_1_0_CAPABILITY_MARKER = "exi:1.0";
 
-    protected NetconfClientSessionNegotiator(NetconfClientSessionPreferences sessionPreferences,
-                                             Promise<NetconfClientSession> promise,
-                                             Channel channel,
-                                             Timer timer,
-                                             NetconfClientSessionListener sessionListener,
-                                             long connectionTimeoutMillis) {
+    protected NetconfClientSessionNegotiator(final NetconfClientSessionPreferences sessionPreferences,
+                                             final Promise<NetconfClientSession> promise,
+                                             final Channel channel,
+                                             final Timer timer,
+                                             final NetconfClientSessionListener sessionListener,
+                                             final long connectionTimeoutMillis) {
         super(sessionPreferences, promise, channel, timer, sessionListener, connectionTimeoutMillis);
     }
 
     @Override
-    protected void handleMessage(NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
+    protected void handleMessage(final NetconfHelloMessage netconfMessage) throws NetconfDocumentedException {
         final NetconfClientSession session = getSessionForHelloMessage(netconfMessage);
         replaceHelloMessageInboundHandler(session);
 
@@ -98,7 +100,7 @@ public class NetconfClientSessionNegotiator extends
         });
     }
 
-    private boolean shouldUseExi(NetconfHelloMessage helloMsg) {
+    private boolean shouldUseExi(final NetconfHelloMessage helloMsg) {
         return containsExi10Capability(helloMsg.getDocument())
                 && containsExi10Capability(sessionPreferences.getHelloMessage().getDocument());
     }
@@ -113,7 +115,7 @@ public class NetconfClientSessionNegotiator extends
         return false;
     }
 
-    private long extractSessionId(Document doc) {
+    private long extractSessionId(final Document doc) {
         final Node sessionIdNode = (Node) XmlUtil.evaluateXPath(sessionIdXPath, doc, XPathConstants.NODE);
         String textContent = sessionIdNode.getTextContent();
         if (textContent == null || textContent.equals("")) {
@@ -124,10 +126,14 @@ public class NetconfClientSessionNegotiator extends
     }
 
     @Override
-    protected NetconfClientSession getSession(NetconfClientSessionListener sessionListener, Channel channel,
-            NetconfHelloMessage message) throws NetconfDocumentedException {
+    protected NetconfClientSession getSession(final NetconfClientSessionListener sessionListener, final Channel channel,
+            final NetconfHelloMessage message) throws NetconfDocumentedException {
         long sessionId = extractSessionId(message.getDocument());
-        Collection<String> capabilities = NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument());
+
+        // Copy here is important: it disconnects the strings from the document
+        Collection<String> capabilities = ImmutableList.copyOf(NetconfMessageUtil.extractCapabilitiesFromHello(message.getDocument()));
+
+        // FIXME: scalability: we could instantiate a cache to share the same collections
         return new NetconfClientSession(sessionListener, channel, sessionId, capabilities);
     }
 
@@ -138,15 +144,15 @@ public class NetconfClientSessionNegotiator extends
         private static final String EXI_CONFIRMED_HANDLER = "exiConfirmedHandler";
 
         private final NetconfClientSession session;
-        private NetconfStartExiMessage startExiMessage;
+        private final NetconfStartExiMessage startExiMessage;
 
-        ExiConfirmationInboundHandler(NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
+        ExiConfirmationInboundHandler(final NetconfClientSession session, final NetconfStartExiMessage startExiMessage) {
             this.session = session;
             this.startExiMessage = startExiMessage;
         }
 
         @Override
-        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+        public void channelRead(final ChannelHandlerContext ctx, final Object msg) throws Exception {
             ctx.pipeline().remove(ExiConfirmationInboundHandler.EXI_CONFIRMED_HANDLER);
 
             NetconfMessage netconfMessage = (NetconfMessage) msg;
index 1a2eb3f..4ca7bdf 100644 (file)
@@ -41,7 +41,7 @@ class SshClientAdapter implements Runnable {
 
     private OutputStream stdIn;
 
-    private Queue<ByteBuf> postponed = new LinkedList<>();
+    private final Queue<ByteBuf> postponed = new LinkedList<>();
 
     private ChannelHandlerContext ctx;
     private ChannelPromise disconnectPromise;
@@ -50,42 +50,36 @@ class SshClientAdapter implements Runnable {
 
     private final Object lock = new Object();
 
-    public SshClientAdapter(SshClient sshClient, Invoker invoker) {
+    public SshClientAdapter(final SshClient sshClient, final Invoker invoker) {
         this.sshClient = sshClient;
         this.invoker = invoker;
     }
 
-    // TODO: refactor
+    // TODO ganymed spawns a Thread that receives the data from remote inside TransportManager
+    // Get rid of this thread and reuse Ganymed internal thread (not sure if its possible without modifications in ganymed)
     public void run() {
         try {
-            SshSession session = sshClient.openSession();
+            final SshSession session = sshClient.openSession();
             invoker.invoke(session);
-            InputStream stdOut = session.getStdout();
-            session.getStderr();
+            final InputStream stdOut = session.getStdout();
 
             synchronized (lock) {
-
                 stdIn = session.getStdin();
-                ByteBuf message;
-                while ((message = postponed.poll()) != null) {
-                    writeImpl(message);
+                while (postponed.peek() != null) {
+                    writeImpl(postponed.poll());
                 }
             }
 
             while (!stopRequested.get()) {
-                byte[] readBuff = new byte[BUFFER_SIZE];
-                int c = stdOut.read(readBuff);
+                final byte[] readBuff = new byte[BUFFER_SIZE];
+                final int c = stdOut.read(readBuff);
                 if (c == -1) {
                     continue;
                 }
-                byte[] tranBuff = new byte[c];
-                System.arraycopy(readBuff, 0, tranBuff, 0, c);
 
-                ByteBuf byteBuf = Unpooled.buffer(c);
-                byteBuf.writeBytes(tranBuff);
-                ctx.fireChannelRead(byteBuf);
+                ctx.fireChannelRead(Unpooled.copiedBuffer(readBuff, 0, c));
             }
-        } catch (Exception e) {
+        } catch (final Exception e) {
             logger.error("Unexpected exception", e);
         } finally {
             sshClient.close();
@@ -99,7 +93,7 @@ class SshClientAdapter implements Runnable {
     }
 
     // TODO: needs rework to match netconf framer API.
-    public void write(ByteBuf message) throws IOException {
+    public void write(final ByteBuf message) throws IOException {
         synchronized (lock) {
             if (stdIn == null) {
                 postponed.add(message);
@@ -109,28 +103,28 @@ class SshClientAdapter implements Runnable {
         }
     }
 
-    private void writeImpl(ByteBuf message) throws IOException {
+    private void writeImpl(final ByteBuf message) throws IOException {
         message.getBytes(0, stdIn, message.readableBytes());
         message.release();
         stdIn.flush();
     }
 
-    public void stop(ChannelPromise promise) {
+    public void stop(final ChannelPromise promise) {
         synchronized (lock) {
             stopRequested.set(true);
             disconnectPromise = promise;
         }
     }
 
-    public Thread start(ChannelHandlerContext ctx, ChannelFuture channelFuture) {
+    public Thread start(final ChannelHandlerContext ctx, final ChannelFuture channelFuture) {
         checkArgument(channelFuture.isSuccess());
         checkNotNull(ctx.channel().remoteAddress());
         synchronized (this) {
             checkState(this.ctx == null);
             this.ctx = ctx;
         }
-        String threadName = toString();
-        Thread thread = new Thread(this, threadName);
+        final String threadName = toString();
+        final Thread thread = new Thread(this, threadName);
         thread.start();
         return thread;
     }
index 44893b8..9cdc592 100644 (file)
@@ -9,8 +9,6 @@
 package org.opendaylight.controller.netconf.nettyutil.handler.ssh.client;
 
 import ch.ethz.ssh2.Session;
-import ch.ethz.ssh2.StreamGobbler;
-
 import ch.ethz.ssh2.channel.Channel;
 import java.io.Closeable;
 import java.io.IOException;
@@ -23,19 +21,20 @@ import java.io.OutputStream;
 class SshSession implements Closeable {
     private final Session session;
 
-    public SshSession(Session session) {
+    public SshSession(final Session session) {
         this.session = session;
     }
 
-
-    public void startSubSystem(String name) throws IOException {
+    public void startSubSystem(final String name) throws IOException {
         session.startSubSystem(name);
     }
 
     public InputStream getStdout() {
-        return new StreamGobbler(session.getStdout());
+        return session.getStdout();
     }
 
+    // FIXME according to http://www.ganymed.ethz.ch/ssh2/FAQ.html#blocking you should read data from both stdout and stderr to prevent window filling up (since stdout and stderr share a window)
+    // FIXME stdErr is not used anywhere
     public InputStream getStderr() {
         return session.getStderr();
     }
index 6300c56..3fffbb2 100644 (file)
@@ -243,6 +243,12 @@ class ServerConnectionCallbackImpl implements ServerConnectionCallback {
                             ChannelFuture clientChannelFuture = initializeNettyConnection(localAddress, bossGroup, sshClientHandler);
                             // get channel
                             final Channel channel = clientChannelFuture.awaitUninterruptibly().channel();
+
+                            // write additional header before polling thread is started
+                            // polling thread could process and forward data before additional header is written
+                            // This will result into unexpected state:  hello message without additional header and the next message with additional header
+                            channel.writeAndFlush(Unpooled.copiedBuffer(additionalHeader.getBytes()));
+
                             new ClientInputStreamPoolingThread(session, ss.getStdout(), channel, new AutoCloseable() {
                                 @Override
                                 public void close() throws Exception {
@@ -259,9 +265,6 @@ class ServerConnectionCallbackImpl implements ServerConnectionCallback {
                                     }
                                 }
                             }, sshClientHandler.getChannelHandlerContext()).start();
-
-                            // write additional header
-                            channel.writeAndFlush(Unpooled.copiedBuffer(additionalHeader.getBytes()));
                         } else {
                             logger.debug("{} Wrong subsystem requested:'{}', closing ssh session", serverSession, subsystem);
                             String reason = "Only netconf subsystem is supported, requested:" + subsystem;
index 59e9f4c..7a4c10e 100644 (file)
@@ -19,6 +19,7 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.List;
 
+import java.util.concurrent.TimeUnit;
 import net.sourceforge.argparse4j.ArgumentParsers;
 import net.sourceforge.argparse4j.annotation.Arg;
 import net.sourceforge.argparse4j.inf.ArgumentParser;
@@ -49,6 +50,9 @@ public final class Main {
         @Arg(dest = "starting-port")
         public int startingPort;
 
+        @Arg(dest = "generate-config-connection-timeout")
+        public int generateConfigsTimeout;
+
         @Arg(dest = "generate-configs-dir")
         public File generateConfigsDir;
 
@@ -58,6 +62,9 @@ public final class Main {
         @Arg(dest = "ssh")
         public boolean ssh;
 
+        @Arg(dest = "exi")
+        public boolean exi;
+
         static ArgumentParser getParser() {
             final ArgumentParser parser = ArgumentParsers.newArgumentParser("netconf testool");
             parser.addArgument("--devices-count")
@@ -79,6 +86,12 @@ public final class Main {
                     .help("First port for simulated device. Each other device will have previous+1 port number")
                     .dest("starting-port");
 
+            parser.addArgument("--generate-config-connection-timeout")
+                    .type(Integer.class)
+                    .setDefault((int)TimeUnit.MINUTES.toMillis(5))
+                    .help("Timeout to be generated in initial config files")
+                    .dest("generate-config-connection-timeout");
+
             parser.addArgument("--generate-configs-batch-size")
                     .type(Integer.class)
                     .setDefault(100)
@@ -96,6 +109,12 @@ public final class Main {
                     .help("Whether to use ssh for transport or just pure tcp")
                     .dest("ssh");
 
+            parser.addArgument("--exi")
+                    .type(Boolean.class)
+                    .setDefault(false)
+                    .help("Whether to use exi to transport xml content")
+                    .dest("exi");
+
             return parser;
         }
 
@@ -110,6 +129,8 @@ public final class Main {
     }
 
     public static void main(final String[] args) {
+        ch.ethz.ssh2.log.Logger.enabled = true;
+
         final Params params = parseArgs(args, Params.getParser());
         params.validate();
 
@@ -117,7 +138,7 @@ public final class Main {
         try {
             final List<Integer> openDevices = netconfDeviceSimulator.start(params);
             if(params.generateConfigsDir != null) {
-                new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize);
+                new ConfigGenerator(params.generateConfigsDir, openDevices).generate(params.ssh, params.generateConfigBatchSize, params.generateConfigsTimeout);
             }
         } catch (final Exception e) {
             LOG.error("Unhandled exception", e);
@@ -164,7 +185,7 @@ public final class Main {
             this.openDevices = openDevices;
         }
 
-        public void generate(final boolean useSsh, final int batchSize) {
+        public void generate(final boolean useSsh, final int batchSize, final int generateConfigsTimeout) {
             if(directory.exists() == false) {
                 checkState(directory.mkdirs(), "Unable to create folder %s" + directory);
             }
@@ -182,7 +203,7 @@ public final class Main {
                 configBlueprint = configBlueprint.replace(NETCONF_USE_SSH, "%s");
 
                 final String before = configBlueprint.substring(0, configBlueprint.indexOf("<module>"));
-                final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>") + "</module>".length());
+                final String middleBlueprint = configBlueprint.substring(configBlueprint.indexOf("<module>"), configBlueprint.indexOf("</module>"));
                 final String after = configBlueprint.substring(configBlueprint.indexOf("</module>") + "</module>".length());
 
                 int connectorCount = 0;
@@ -196,7 +217,9 @@ public final class Main {
                     }
 
                     final String name = String.valueOf(openDevice) + SIM_DEVICE_SUFFIX;
-                    final String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh));
+                    String configContent = String.format(middleBlueprint, name, String.valueOf(openDevice), String.valueOf(!useSsh));
+                    configContent = String.format("%s%s%d%s\n%s\n", configContent, "<connection-timeout-millis>", generateConfigsTimeout, "</connection-timeout-millis>", "</module>");
+
                     b.append(configContent);
                     connectorCount++;
                     if(connectorCount == batchSize) {
index b21c02a..3a52f0a 100644 (file)
@@ -24,7 +24,6 @@ import io.netty.channel.nio.NioEventLoopGroup;
 import io.netty.util.HashedWheelTimer;
 import java.io.Closeable;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.lang.management.ManagementFactory;
 import java.net.Inet4Address;
@@ -42,6 +41,7 @@ import java.util.concurrent.ExecutionException;
 import org.antlr.v4.runtime.ParserRuleContext;
 import org.antlr.v4.runtime.tree.ParseTreeWalker;
 import org.opendaylight.controller.netconf.api.monitoring.NetconfManagementSession;
+import org.opendaylight.controller.netconf.api.xml.XmlNetconfConstants;
 import org.opendaylight.controller.netconf.impl.DefaultCommitNotificationProducer;
 import org.opendaylight.controller.netconf.impl.NetconfServerDispatcher;
 import org.opendaylight.controller.netconf.impl.NetconfServerSessionNegotiatorFactory;
@@ -91,7 +91,7 @@ public class NetconfDeviceSimulator implements Closeable {
         this.hashedWheelTimer = hashedWheelTimer;
     }
 
-    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders) {
+    private NetconfServerDispatcher createDispatcher(final Map<ModuleBuilder, String> moduleBuilders, final boolean exi) {
 
         final Set<Capability> capabilities = Sets.newHashSet(Collections2.transform(moduleBuilders.keySet(), new Function<ModuleBuilder, Capability>() {
             @Override
@@ -108,8 +108,12 @@ public class NetconfDeviceSimulator implements Closeable {
 
         final DefaultCommitNotificationProducer commitNotifier = new DefaultCommitNotificationProducer(ManagementFactory.getPlatformMBeanServer());
 
+        final Set<String> serverCapabilities = exi
+                ? NetconfServerSessionNegotiatorFactory.DEFAULT_BASE_CAPABILITIES
+                : Sets.newHashSet(XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_0, XmlNetconfConstants.URN_IETF_PARAMS_NETCONF_BASE_1_1);
+
         final NetconfServerSessionNegotiatorFactory serverNegotiatorFactory = new NetconfServerSessionNegotiatorFactory(
-                hashedWheelTimer, simulatedOperationProvider, idProvider, CONNECTION_TIMEOUT_MILLIS, commitNotifier, new LoggingMonitoringService());
+                hashedWheelTimer, simulatedOperationProvider, idProvider, CONNECTION_TIMEOUT_MILLIS, commitNotifier, new LoggingMonitoringService(), serverCapabilities);
 
         final NetconfServerDispatcher.ServerChannelInitializer serverChannelInitializer = new NetconfServerDispatcher.ServerChannelInitializer(
                 serverNegotiatorFactory);
@@ -147,7 +151,7 @@ public class NetconfDeviceSimulator implements Closeable {
     public List<Integer> start(final Main.Params params) {
         final Map<ModuleBuilder, String> moduleBuilders = parseSchemasToModuleBuilders(params);
 
-        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders);
+        final NetconfServerDispatcher dispatcher = createDispatcher(moduleBuilders, params.exi);
 
         int currentPort = params.startingPort;
 
diff --git a/pom.xml b/pom.xml
index 0bfc64f..f3f777f 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -39,6 +39,7 @@
     <module>opendaylight/statisticsmanager/api</module>
     <module>opendaylight/statisticsmanager/implementation</module>
     <module>opendaylight/topologymanager/implementation</module>
+    <module>opendaylight/topologymanager/shell</module>
     <module>opendaylight/usermanager/api</module>
     <module>opendaylight/usermanager/implementation</module>
     <module>opendaylight/connectionmanager/api</module>

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