Merge "Implementation of ModuleShardStrategy"
authorEd Warnicke <eaw@cisco.com>
Tue, 29 Jul 2014 11:30:00 +0000 (11:30 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 29 Jul 2014 11:30:00 +0000 (11:30 +0000)
38 files changed:
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java
opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java
opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java
opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java
opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java
opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang
opendaylight/distribution/opendaylight/pom.xml
opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml
opendaylight/md-sal/sal-dom-broker/pom.xml
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java [new file with mode: 0644]
opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java
opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang
opendaylight/md-sal/sal-netconf-connector/pom.xml
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceCommitHandler.java [deleted file]
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java [new file with mode: 0644]
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataReader.java [deleted file]
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalProvider.java
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java [new file with mode: 0644]
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java [new file with mode: 0644]
opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java [moved from opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTwoPhaseCommitTransaction.java with 51% similarity]
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java
opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java
opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java

index 580a53b..12b771d 100644 (file)
@@ -32,14 +32,14 @@ public final class ReconnectImmediatelyStrategyFactoryModule extends org.openday
 
     @Override
     protected void customValidation(){
-        JmxAttributeValidationException.checkNotNull(getTimeout(), "value is not set.", timeoutJmxAttribute);
-        JmxAttributeValidationException.checkCondition(getTimeout() >= 0, "value " + getTimeout() + " is less than 0",
-                timeoutJmxAttribute);
+        JmxAttributeValidationException.checkNotNull(getReconnectTimeout(), "value is not set.", reconnectTimeoutJmxAttribute);
+        JmxAttributeValidationException.checkCondition(getReconnectTimeout() >= 0, "value " + getReconnectTimeout() + " is less than 0",
+                reconnectTimeoutJmxAttribute);
     }
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new ReconnectImmediatelyStrategyFactoryCloseable(getExecutorDependency(), getTimeout());
+        return new ReconnectImmediatelyStrategyFactoryCloseable(getReconnectExecutorDependency(), getReconnectTimeout());
     }
 
     private static final class ReconnectImmediatelyStrategyFactoryCloseable implements ReconnectStrategyFactory, AutoCloseable {
index b8849c7..0b4a7ba 100644 (file)
@@ -49,7 +49,7 @@ public final class TimedReconnectStrategyFactoryModule extends org.opendaylight.
 
     @Override
     public java.lang.AutoCloseable createInstance() {
-        return new TimedReconnectStrategyFactoryCloseable(getExecutorDependency(),
+        return new TimedReconnectStrategyFactoryCloseable(getTimedReconnectExecutorDependency(),
                 getConnectTime(), getMinSleep(), getSleepFactor().doubleValue(), getMaxSleep(), getMaxAttempts(),
                 getDeadline());
     }
index 1856369..cd84d4a 100644 (file)
@@ -77,12 +77,12 @@ module protocol-framework {
         case reconnect-immediately-strategy-factory {
             when "/config:modules/config:module/config:type = 'reconnect-immediately-strategy-factory'";
 
-            leaf timeout {
+            leaf reconnect-timeout {
                 mandatory true;
                 type int32;
             }
 
-            container executor {
+            container reconnect-executor {
                 uses config:service-ref {
                     refine type {
                         mandatory true;
@@ -138,7 +138,7 @@ module protocol-framework {
                 units "milliseconds";
             }
 
-            container executor {
+            container timed-reconnect-executor {
                 uses config:service-ref {
                     refine type {
                         mandatory true;
index 9beadc4..cfdf3bf 100644 (file)
@@ -78,7 +78,7 @@ public class ReconnectImmediatelyStrategyModuleTest extends AbstractConfigTest {
         final ReconnectImmediatelyStrategyFactoryModuleMXBean mxBean = transaction.newMBeanProxy(
                 transaction.lookupConfigBean(FACTORY_NAME, INSTANCE_NAME),
                 ReconnectImmediatelyStrategyFactoryModuleMXBean.class);
-        mxBean.setTimeout(200);
+        mxBean.setReconnectTimeout(200);
         final CommitStatus status = transaction.commit();
         assertBeanCount(1, FACTORY_NAME);
         assertStatus(status, 0, 1, 1);
@@ -99,8 +99,8 @@ public class ReconnectImmediatelyStrategyModuleTest extends AbstractConfigTest {
         final ObjectName nameCreated = transaction.createModule(FACTORY_NAME, INSTANCE_NAME);
         final ReconnectImmediatelyStrategyFactoryModuleMXBean mxBean = transaction.newMBeanProxy(nameCreated,
                 ReconnectImmediatelyStrategyFactoryModuleMXBean.class);
-        mxBean.setTimeout(timeout);
-        mxBean.setExecutor(GlobalEventExecutorUtil.create(transaction));
+        mxBean.setReconnectTimeout(timeout);
+        mxBean.setReconnectExecutor(GlobalEventExecutorUtil.create(transaction));
         return nameCreated;
     }
 
index a8cdff7..1c068a9 100644 (file)
@@ -7,6 +7,13 @@
  */
 package org.opendaylight.controller.config.yang.protocol.framework;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.math.BigDecimal;
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.ObjectName;
 import org.junit.Before;
 import org.junit.Test;
 import org.opendaylight.controller.config.api.ConflictingVersionException;
@@ -17,14 +24,6 @@ import org.opendaylight.controller.config.manager.impl.factoriesresolver.Hardcod
 import org.opendaylight.controller.config.util.ConfigTransactionJMXClient;
 import org.opendaylight.controller.config.yang.netty.eventexecutor.GlobalEventExecutorModuleFactory;
 
-import javax.management.InstanceAlreadyExistsException;
-import javax.management.ObjectName;
-import java.math.BigDecimal;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 public class TimedReconnectStrategyModuleTest extends AbstractConfigTest {
 
     private static final String INSTANCE_NAME = "timed-reconect-stategy-facotry-impl";
@@ -158,7 +157,7 @@ public class TimedReconnectStrategyModuleTest extends AbstractConfigTest {
         mxBean.setMaxSleep(maxSleep);
         mxBean.setMinSleep(minSleep);
         mxBean.setSleepFactor(sleepFactor);
-        mxBean.setExecutor(GlobalEventExecutorUtil.create(transaction));
+        mxBean.setTimedReconnectExecutor(GlobalEventExecutorUtil.create(transaction));
         return nameCreated;
     }
 
index 0fd9720..864ebdf 100644 (file)
@@ -7,12 +7,40 @@
  */
 package org.opendaylight.controller.config.yangjmxgenerator.plugin;
 
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.matchers.JUnitMatchers.containsString;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+
 import com.google.common.base.Predicate;
 import com.google.common.collect.Collections2;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.io.Files;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 import org.apache.commons.io.FileUtils;
 import org.apache.maven.plugin.logging.Log;
 import org.apache.maven.project.MavenProject;
@@ -46,35 +74,6 @@ import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXParseException;
 
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import java.io.File;
-import java.io.IOException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.is;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertThat;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.fail;
-import static org.junit.matchers.JUnitMatchers.containsString;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.doNothing;
-import static org.mockito.Mockito.doReturn;
-
 //TODO: refactor
 public class JMXGeneratorTest extends AbstractGeneratorTest {
 
@@ -85,7 +84,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
     File generatedResourcesDir;
 
     private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, FromGrouping.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
 
     private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
@@ -108,7 +107,7 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                     "NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
                     "NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
     private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
-            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+            .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, FromGrouping.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
     private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
             .toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
 
@@ -506,8 +505,9 @@ public class JMXGeneratorTest extends AbstractGeneratorTest {
                 + ".threads.java", visitor.packageName);
         assertEquals("AsyncEventBusModuleMXBean", visitor.type);
 
-        assertEquals("Incorrenct number of generated methods", 2,
+        assertEquals("Incorrenct number of generated methods", 4,
                 visitor.methods.size());
+
     }
 
     private void assertAbstractDynamicThreadPoolModule(MbeASTVisitor visitor) {
index 518a115..e9f0ac8 100644 (file)
@@ -38,6 +38,7 @@ import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListAttribu
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.ListDependenciesAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.attribute.TOAttribute;
 import org.opendaylight.controller.config.yangjmxgenerator.plugin.util.NameConflictException;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.config.rev130405.ServiceRef;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
@@ -466,7 +467,7 @@ final class ModuleMXBeanEntryBuilder {
     private Optional<? extends AbstractDependencyAttribute> extractDependency(final DataNodeContainer dataNodeContainer,
             final DataSchemaNode attrNode, final Module currentModule, final Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
             final SchemaContext schemaContext) {
-        if (dataNodeContainer.getUses().size() == 1 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+        if (isDependencyContainer(dataNodeContainer)) {
             // reference
             UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
             checkState(usesNode.getRefines().size() == 1, "Unexpected 'refine' child node size of " + dataNodeContainer);
@@ -493,6 +494,18 @@ final class ModuleMXBeanEntryBuilder {
         return Optional.absent();
     }
 
+    private boolean isDependencyContainer(final DataNodeContainer dataNodeContainer) {
+        if(dataNodeContainer.getUses().size() != 1) {
+            return false;
+        }
+        UsesNode onlyUses = dataNodeContainer.getUses().iterator().next();
+        if(onlyUses.getGroupingPath().getLastComponent().equals(ServiceRef.QNAME) == false) {
+            return false;
+        }
+
+        return getChildNodeSizeWithoutUses(dataNodeContainer) == 0;
+    }
+
     private int getChildNodeSizeWithoutUses(final DataNodeContainer csn) {
         int result = 0;
         for (DataSchemaNode dsn : csn.getChildNodes()) {
index e189ef7..a6d2fea 100644 (file)
@@ -56,6 +56,12 @@ module config-threads-java {
         }
     }
 
+    grouping async-eventbus-config-attrs {
+        leaf cfg-attr {
+            type string;
+        }
+    }
+
     augment "/config:modules/config:module/config:configuration" {
         case async-eventbus {
             when "/config:modules/config:module/config:type = 'async-eventbus'";
@@ -66,6 +72,10 @@ module config-threads-java {
                     }
                 }
             }
+
+            container from-grouping {
+                uses async-eventbus-config-attrs;
+            }
         }
     }
     augment "/config:modules/config:module/config:state" {
index 3131bd5..541c130 100644 (file)
                 </goals>
                 <phase>generate-resources</phase>
                 <configuration>
-                 <outputDirectory>${project.build.directory}/generated-resources/opendaylight/configuration</outputDirectory>
-                 <includeArtifactIds>sal-rest-connector-config</includeArtifactIds>
-                 <includes>**\/*.xml</includes>
-                 <excludeTransitive>true</excludeTransitive>
-                 <ignorePermissions>false</ignorePermissions>
+                   <outputDirectory>${project.build.directory}/configuration</outputDirectory>
+                   <includeArtifactIds>sal-rest-connector-config</includeArtifactIds>
+                   <includes>**\/*.xml</includes>
+                   <excludeTransitive>true</excludeTransitive>
+                   <ignorePermissions>false</ignorePermissions>
                 </configuration>
               </execution>
             </executions>
index 9534094..03da7f0 100644 (file)
                 <module>
                     <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">prefix:inmemory-operational-datastore-provider</type>
                     <name>operational-store-service</name>
-                    <schema-service>
+                    <operational-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>
+                    </operational-schema-service>
                 </module>
                 <!--
                      Tree-based in-memory data store. This is the data store which is currently
index 022882f..96e353b 100644 (file)
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>org.opendaylight.yangtools</groupId>
+      <artifactId>mockito-configuration</artifactId>
+      <scope>test</scope>
+    </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-simple</artifactId>
           <instructions>
             <Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
             <Bundle-Activator>org.opendaylight.controller.sal.dom.broker.osgi.SchemaServiceActivator</Bundle-Activator>
-            <Export-Package>org.opendaylight.controller.sal.dom.broker.spi</Export-Package>
-            <Private-Package>org.opendaylight.controller.sal.dom.broker,
+            <Export-Package>org.opendaylight.controller.sal.dom.broker.spi,
+                            <!--sal.broker.impl is exported for sal-netconf-connector to use SchemaAwareRpcRegistry.-->
+                            <!-- TODO Remove sal.broker.impl from export when SchemaAwareRpcRegistry is not used in connector anymore -->
                             org.opendaylight.controller.sal.dom.broker.impl,
                             org.opendaylight.controller.sal.dom.broker.impl.*,
+            </Export-Package>
+            <Private-Package>org.opendaylight.controller.sal.dom.broker,
                             org.opendaylight.controller.sal.dom.broker.osgi,
                             org.opendaylight.controller.sal.dom.broker.util,
                             org.opendaylight.controller.config.yang.md.sal.dom.impl,
-                            org.opendaylight.controller.config.yang.md.sal.dom.statistics,
+                            org.opendaylight.controller.config.yang.md.sal.dom.statistics,\
                             org.opendaylight.controller.md.sal.dom.broker.impl,
                             org.opendaylight.controller.md.sal.dom.broker.impl.*,
                             org.opendaylight.yangtools.yang.util,
index 998d884..34d231c 100644 (file)
@@ -7,8 +7,12 @@
  */
 package org.opendaylight.controller.config.yang.md.sal.dom.impl;
 
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
 import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
@@ -17,18 +21,15 @@ import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.core.api.model.SchemaService;
 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
 import org.opendaylight.controller.sal.core.api.mount.MountService;
+import org.opendaylight.controller.sal.dom.broker.BackwardsCompatibleMountPointManager;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.DataBrokerImpl;
 import org.opendaylight.controller.sal.dom.broker.GlobalBundleScanningSchemaServiceImpl;
-import org.opendaylight.controller.sal.dom.broker.MountPointManagerImpl;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
 import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProviders;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
 /**
 *
 */
@@ -72,10 +73,13 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi
         services.putInstance(DataProviderService.class,legacyData);
         services.putInstance(DataBrokerService.class, legacyData);
 
+        final DOMMountPointService mountService = new DOMMountPointServiceImpl();
+        services.putInstance(DOMMountPointService.class, mountService);
 
-        MountPointManagerImpl mountService = new MountPointManagerImpl();
-        services.putInstance(MountService.class, mountService);
-        services.putInstance(MountProvisionService.class, mountService);
+        // TODO remove backwards service, use only new DOMMountPointService
+        final MountProvisionService backwardsMountService = new BackwardsCompatibleMountPointManager(mountService);
+        services.putInstance(MountService.class, backwardsMountService);
+        services.putInstance(MountProvisionService.class, backwardsMountService);
 
         return new BrokerImpl(router, services);
     }
index cdb78fc..9dd1808 100644 (file)
@@ -8,9 +8,12 @@
 
 package org.opendaylight.controller.md.sal.dom.broker.impl.mount;
 
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ClassToInstanceMap;
+import com.google.common.collect.MutableClassToInstanceMap;
 import java.util.HashMap;
 import java.util.Map;
-
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
 import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.md.sal.dom.api.DOMService;
@@ -22,20 +25,15 @@ import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
 public class DOMMountPointServiceImpl implements DOMMountPointService {
 
-    private final Map<InstanceIdentifier, SimpleDOMMountPoint> mountPoints = new HashMap<>();
+    private final Map<InstanceIdentifier, DOMMountPoint> mountPoints = new HashMap<>();
 
     private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
 
     @Override
     public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
-        return Optional.<DOMMountPoint>fromNullable(mountPoints.get(path));
+        return Optional.fromNullable(mountPoints.get(path));
     }
 
     @Override
@@ -51,21 +49,35 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
         }
     }
 
+    public void notifyMountRemoved(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners
+                .getListeners()) {
+            listener.getInstance().onMountPointRemoved(identifier);
+        }
+    }
+
     @Override
     public ListenerRegistration<MountProvisionListener> registerProvisionListener(
             final MountProvisionListener listener) {
         return listeners.register(listener);
     }
 
-    public ObjectRegistration<DOMMountPoint> registerMountPoint(final SimpleDOMMountPoint mountPoint) {
+    public ObjectRegistration<DOMMountPoint> registerMountPoint(final DOMMountPoint mountPoint) {
         synchronized (mountPoints) {
             Preconditions.checkState(!mountPoints.containsKey(mountPoint.getIdentifier()), "Mount point already exists");
             mountPoints.put(mountPoint.getIdentifier(), mountPoint);
         }
         notifyMountCreated(mountPoint.getIdentifier());
 
-        // FIXME this shouldnt be null
-        return null;
+        return new MountRegistration(mountPoint);
+    }
+
+    public void unregisterMountPoint(final InstanceIdentifier mountPointId) {
+        synchronized (mountPoints) {
+            Preconditions.checkState(mountPoints.containsKey(mountPointId), "Mount point does not exist");
+            mountPoints.remove(mountPointId);
+        }
+        notifyMountRemoved(mountPointId);
     }
 
     public class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
@@ -98,4 +110,22 @@ public class DOMMountPointServiceImpl implements DOMMountPointService {
             return registerMountPoint(mountPoint);
         }
     }
+
+    private final class MountRegistration implements ObjectRegistration<DOMMountPoint> {
+        private final DOMMountPoint mountPoint;
+
+        public MountRegistration(final DOMMountPoint mountPoint) {
+            this.mountPoint = mountPoint;
+        }
+
+        @Override
+        public DOMMountPoint getInstance() {
+            return mountPoint;
+        }
+
+        @Override
+        public void close() throws Exception {
+            unregisterMountPoint(mountPoint.getIdentifier());
+        }
+    }
 }
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java
new file mode 100644 (file)
index 0000000..c2329ef
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+ * 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.dom.broker;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+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.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+
+public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
+
+    private final DataProviderService dataReader;
+    private final DataReader<InstanceIdentifier,CompositeNode> readWrapper;
+
+    private final InstanceIdentifier mountPath;
+    private final NotificationPublishService notificationPublishService;
+    private final RpcProvisionRegistry rpcs;
+
+    private final ListenerRegistry<SchemaServiceListener> schemaListenerRegistry = new ListenerRegistry<>();
+
+    private SchemaContext schemaContext;
+
+    public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
+        this.mountPath = Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(mountPointBuilder);
+
+        dataReader = new DataBrokerImpl();
+        readWrapper = new ReadWrapper();
+        notificationPublishService = new DelgatingNotificationPublishService();
+        rpcs = new SchemaAwareRpcBroker(path.toString(), this);
+
+        mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
+        mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
+        mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
+
+        mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
+
+        mountPointBuilder.register();
+    }
+
+    public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPoint mount) {
+        this.mountPath = Preconditions.checkNotNull(path);
+        Preconditions.checkNotNull(mount);
+
+        final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
+
+        this.schemaContext = mount.getSchemaContext();
+
+        dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
+
+        // Set schema context to provide it for BackwardsCompatibleDataBroker
+        if(schemaContext != null) {
+            setSchemaContext(schemaContext);
+        }
+
+        readWrapper = new ReadWrapper();
+
+        notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
+        rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
+    }
+
+    private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
+        final Optional<T> serviceOptional = mount.getService(type);
+        Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
+                "Cannot construct backwards compatible mount wrapper without it", type, mount);
+        return serviceOptional.get();
+    }
+
+    @Override
+    public void addModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void removeModule(final Module module) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SchemaContext getSessionContext() {
+        return getSchemaContext();
+    }
+
+    @Override
+    public SchemaContext getGlobalContext() {
+        return getSchemaContext();
+    }
+
+    @Override
+    public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
+        return schemaListenerRegistry.register(listener);
+    }
+
+    @Override
+    public void publish(final CompositeNode notification) {
+        notificationPublishService.publish(notification);
+    }
+
+    @Override
+    public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+        return notificationPublishService.addNotificationListener(notification, listener);
+    }
+
+    // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
+    public DataReader<InstanceIdentifier, CompositeNode> getReadWrapper() {
+        return readWrapper;
+    }
+
+    @Override
+    public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+        return dataReader.readConfigurationData(path);
+    }
+
+    @Override
+    public CompositeNode readOperationalData(final InstanceIdentifier path) {
+        return dataReader.readOperationalData(path);
+    }
+
+    @Override
+    public Registration registerOperationalReader(
+            final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+        return dataReader.registerOperationalReader(path, reader);
+    }
+
+    @Override
+    public Registration registerConfigurationReader(
+            final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+        return dataReader.registerConfigurationReader(path, reader);
+    }
+
+    @Override
+    public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
+        return rpcs.addRoutedRpcImplementation(rpcType, implementation);
+    }
+
+    @Override
+    public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
+        rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+    }
+
+    @Override
+    public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
+            throws IllegalArgumentException {
+        return rpcs.addRpcImplementation(rpcType, implementation);
+    }
+
+    @Override
+    public Set<QName> getSupportedRpcs() {
+        return rpcs.getSupportedRpcs();
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
+        return rpcs.invokeRpc(rpc, input);
+    }
+
+    @Override
+    public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
+        return rpcs.addRpcRegistrationListener(listener);
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
+        return rpcs.invokeRpc(type, input);
+    }
+
+    @Override
+    public DataModificationTransaction beginTransaction() {
+        return dataReader.beginTransaction();
+    }
+
+    @Override
+    public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
+            final DataChangeListener listener) {
+        return dataReader.registerDataChangeListener(path, listener);
+    }
+
+    @Override
+    public Registration registerCommitHandler(
+            final InstanceIdentifier path, final DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
+        return dataReader.registerCommitHandler(path, commitHandler);
+    }
+
+    @Override
+    public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+        // NOOP
+    }
+
+    @Override
+    public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+        // NOOP
+    }
+
+    @Override
+    public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
+        // NOOP
+    }
+    @Override
+    public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
+        // NOOP
+    }
+
+    @Override
+    public SchemaContext getSchemaContext() {
+        return schemaContext;
+    }
+
+    @Override
+    public void setSchemaContext(final SchemaContext schemaContext) {
+        this.schemaContext = schemaContext;
+        for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
+            schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
+        }
+    }
+
+    class ReadWrapper implements DataReader<InstanceIdentifier, CompositeNode> {
+        private InstanceIdentifier shortenPath(final InstanceIdentifier path) {
+            InstanceIdentifier ret = null;
+            if(mountPath.contains(path)) {
+                final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
+                ret = InstanceIdentifier.create(newArgs);
+            }
+            return ret;
+        }
+
+        @Override
+        public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+            final InstanceIdentifier newPath = shortenPath(path);
+            if(newPath == null) {
+                return null;
+            }
+            return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
+        }
+
+        @Override
+        public CompositeNode readOperationalData(final InstanceIdentifier path) {
+            final InstanceIdentifier newPath = shortenPath(path);
+            if(newPath == null) {
+                return null;
+            }
+            return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
+        }
+    }
+
+    @Override
+    public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
+            final RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
+        return dataReader.registerCommitHandlerListener(commitHandlerListener);
+    }
+
+    @Override
+    public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+            final L listener) {
+        return rpcs.registerRouteChangeListener(listener);
+    }
+
+    @VisibleForTesting
+    static final class BackwardsCompatibleDomStore implements DOMDataBroker {
+        private final DataProviderService dataReader;
+        private final SchemaContextProvider schemaContextProvider;
+
+        public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
+            this.dataReader = dataReader;
+            this.schemaContextProvider = schemaContextProvider;
+        }
+
+        @Override
+        public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
+        }
+
+        @Override
+        public DOMDataWriteTransaction newWriteOnlyTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+        }
+
+        @Override
+        public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+            throw new UnsupportedOperationException("Register data listener not supported for mount point");
+        }
+
+        @Override
+        public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+            throw new UnsupportedOperationException("Transaction chain not supported for mount point");
+        }
+
+        @Override
+        public DOMDataReadWriteTransaction newReadWriteTransaction() {
+            final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+            return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
+        }
+
+        @VisibleForTesting
+        static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
+            private final DataProviderService dataReader;
+            private final DataNormalizer normalizer;
+
+            public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
+                this.dataReader = dataReader;
+                this.normalizer = normalizer;
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public void close() {
+                // NOOP
+            }
+
+            @Override
+            public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+
+                CompositeNode rawData = null;
+
+                switch (store) {
+                    case CONFIGURATION: {
+                        rawData = dataReader.readConfigurationData(path);
+                        break;
+                    }
+                    case OPERATIONAL: {
+                        rawData = dataReader.readOperationalData(path);
+                        break;
+                    }
+                }
+                Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
+
+                final Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
+                final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
+                return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
+            }
+        }
+
+        @VisibleForTesting
+        static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
+            private DataModificationTransaction oldTx;
+            private final DataNormalizer dataNormalizer;
+
+            public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+                this.oldTx = dataReader.beginTransaction();
+                this.dataNormalizer = dataNormalizer;
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public boolean cancel() {
+                oldTx = null;
+                return true;
+            }
+
+            @Override
+            public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
+                try {
+                    final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+                    switch (store) {
+                        case CONFIGURATION: {
+                            oldTx.putConfigurationData(legacyPath, legacyData);
+                            return;
+                        }
+                    }
+
+                    throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
+                } catch (final DataNormalizationException e) {
+                    throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+                }
+            }
+
+            @Override
+            public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                // TODO not supported
+                throw new UnsupportedOperationException("Merge not supported for mount point");
+            }
+
+            @Override
+            public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                try {
+                    final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+                    switch (store) {
+                        case CONFIGURATION: {
+                            oldTx.removeConfigurationData(legacyPath);
+                            return;
+                        }
+                    }
+                    throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
+                } catch (final DataNormalizationException e) {
+                    throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+                }
+            }
+
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+                final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+                    @Override
+                    public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+                        return null;
+                    }
+                });
+
+                return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+                    @Override
+                    public TransactionCommitFailedException apply(@Nullable final Exception input) {
+                        return new TransactionCommitFailedException("Commit failed", input);
+                    }
+                });
+            }
+
+            @Override
+            public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+                return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
+            }
+        }
+
+
+        @VisibleForTesting
+        static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+            private final DataProviderService dataReader;
+            private final DataNormalizer dataNormalizer;
+            private final BackwardsCompatibleWriteTransaction delegateWriteTx;
+
+            public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+                this.dataReader = dataReader;
+                this.dataNormalizer = dataNormalizer;
+                this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+            }
+
+            @Override
+            public Object getIdentifier() {
+                return this;
+            }
+
+            @Override
+            public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
+            }
+
+            @Override
+            public boolean cancel() {
+                return delegateWriteTx.cancel();
+            }
+
+            @Override
+            public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                delegateWriteTx.put(store, path, data);
+            }
+
+            @Override
+            public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+                delegateWriteTx.merge(store, path, data);
+            }
+
+            @Override
+            public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+                delegateWriteTx.delete(store, path);
+            }
+
+            @Override
+            public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+                return delegateWriteTx.submit();
+            }
+
+            @Override
+            public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+                return delegateWriteTx.commit();
+            }
+        }
+    }
+
+    private class DelgatingNotificationPublishService implements NotificationPublishService {
+        private final NotificationRouter notificationRouter;
+
+        public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
+            this.notificationRouter = notificationRouter;
+        }
+
+        private DelgatingNotificationPublishService() {
+            this(new NotificationRouterImpl());
+        }
+
+        @Override
+        public void publish(final CompositeNode notification) {
+            notificationRouter.publish(notification);
+        }
+
+        @Override
+        public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+            return notificationRouter.addNotificationListener(notification, listener);
+        }
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java
new file mode 100644 (file)
index 0000000..5c2a8e0
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * 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.dom.broker;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class BackwardsCompatibleMountPointManager implements MountProvisionService, MountProvisionListener {
+
+    private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
+    private final ConcurrentMap<InstanceIdentifier, MountProvisionInstance> mounts = new ConcurrentHashMap<>();
+
+    private final DOMMountPointService domMountPointService;
+
+    public BackwardsCompatibleMountPointManager(final DOMMountPointService domMountPointService) {
+        this.domMountPointService = domMountPointService;
+    }
+
+    @Override
+    public MountProvisionInstance createMountPoint(final InstanceIdentifier path) {
+        checkState(!mounts.containsKey(path), "Mount already created");
+        // Create mount point instance, wrap instance of new API with BackwardsCompatibleMountPoint to preserve backwards comatibility
+        final BackwardsCompatibleMountPoint mount = new BackwardsCompatibleMountPoint(path, domMountPointService.createMountPoint(path));
+        mounts.put(path, mount);
+        return mount;
+    }
+
+    public void notifyMountCreated(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+            listener.getInstance().onMountPointCreated(identifier);
+        }
+    }
+
+    public void notifyMountRemoved(final InstanceIdentifier identifier) {
+        for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+            listener.getInstance().onMountPointRemoved(identifier);
+        }
+    }
+
+    @Override
+    public MountProvisionInstance createOrGetMountPoint(
+            final InstanceIdentifier path) {
+        final MountProvisionInstance mount = getMountPoint(path);
+        if (mount == null) {
+            return createMountPoint(path);
+        }
+        return mount;
+    }
+
+    @Override
+    public MountProvisionInstance getMountPoint(final InstanceIdentifier path) {
+        // If the mount point was created here, return directly
+        if(mounts.containsKey(path)) {
+            return mounts.get(path);
+        }
+
+        // If mount was created in underlying DOMMountService, wrap as MountProvisionInstance
+        final Optional<DOMMountPoint> mount = domMountPointService.getMountPoint(path);
+        if(mount.isPresent()) {
+            return new BackwardsCompatibleMountPoint(path, mount.get());
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+            final MountProvisionListener listener) {
+        return domMountPointService.registerProvisionListener(listener);
+    }
+
+    @Override
+    public void onMountPointCreated(final InstanceIdentifier path) {
+        notifyMountCreated(path);
+    }
+
+    @Override
+    public void onMountPointRemoved(final InstanceIdentifier path) {
+            notifyMountRemoved(path);
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java
new file mode 100644 (file)
index 0000000..4c73e0b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.dom.broker.osgi;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+
+public class DOMMountPointServiceProxy extends AbstractBrokerServiceProxy<DOMMountPointService> implements DOMMountPointService{
+
+
+    public DOMMountPointServiceProxy(final ServiceReference<DOMMountPointService> ref, final DOMMountPointService delegate) {
+        super(ref, delegate);
+    }
+
+    @Override
+    public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
+        return getDelegate().getMountPoint(path);
+    }
+
+    @Override
+    public DOMMountPointBuilder createMountPoint(final InstanceIdentifier path) {
+        return getDelegate().createMountPoint(path);
+    }
+
+    public ListenerRegistration<MountProvisionListener> registerProvisionListener(final MountProvisionListener listener) {
+        return getDelegate().registerProvisionListener(listener);
+    }
+}
index c2d6add..2ce2bac 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.dom.broker.osgi;
 
 import java.util.Arrays;
 
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.core.api.BrokerService;
 import org.osgi.framework.ServiceReference;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
@@ -66,6 +67,13 @@ public class ProxyFactory {
                 ((ServiceReference<MountProvisionService>) ref), service);
     }
 
+    private static Object _createProxyImpl(final ServiceReference<?> ref,
+            final DOMMountPointService service) {
+
+        return new DOMMountPointServiceProxy(
+                ((ServiceReference<DOMMountPointService>) ref), service);
+    }
+
     private static Object _createProxyImpl(final ServiceReference<?> ref,
             final SchemaService service) {
 
@@ -113,6 +121,8 @@ public class ProxyFactory {
             return _createProxyImpl(ref, (SchemaService) service);
         } else if (service instanceof NotificationService) {
             return _createProxyImpl(ref, (NotificationService) service);
+        } else if (service instanceof DOMMountPointService) {
+            return _createProxyImpl(ref, (DOMMountPointService) service);
         } else if (service != null) {
             return _createProxyImpl(ref, service);
         } else {
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java
new file mode 100644 (file)
index 0000000..311055f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+ * 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.dom.broker.util;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * ProxySchema Context for SchemaContextProviders
+ */
+public class ProxySchemaContext implements SchemaContext {
+
+    private final SchemaContextProvider schemaProvider;
+
+    public ProxySchemaContext(final SchemaContextProvider schemaProvider) {
+        this.schemaProvider = schemaProvider;
+    }
+
+    private SchemaContext getCurrentSchema() {
+        Preconditions.checkState(schemaProvider.getSchemaContext() != null, "Schema context unavailable from %s", schemaProvider);
+        return schemaProvider.getSchemaContext();
+    }
+
+    @Override
+    public Set<DataSchemaNode> getDataDefinitions() {
+        return getCurrentSchema().getDataDefinitions();
+    }
+
+    @Override
+    public Set<Module> getModules() {
+        return getCurrentSchema().getModules();
+    }
+
+    @Override
+    public Set<NotificationDefinition> getNotifications() {
+        return getCurrentSchema().getNotifications();
+    }
+
+    @Override
+    public Set<RpcDefinition> getOperations() {
+        return getCurrentSchema().getOperations();
+    }
+
+    @Override
+    public Set<ExtensionDefinition> getExtensions() {
+        return getCurrentSchema().getExtensions();
+    }
+
+    @Override
+    public Module findModuleByName(final String s, final Date date) {
+        return getCurrentSchema().findModuleByName(s, date);
+    }
+
+    @Override
+    public Set<Module> findModuleByNamespace(final URI uri) {
+        return getCurrentSchema().findModuleByNamespace(uri);
+    }
+
+    @Override
+    public Module findModuleByNamespaceAndRevision(final URI uri, final Date date) {
+        return getCurrentSchema().findModuleByNamespaceAndRevision(uri, date);
+    }
+
+    @Override
+    public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
+        return getCurrentSchema().getModuleSource(moduleIdentifier);
+    }
+
+    @Override
+    public Set<ModuleIdentifier> getAllModuleIdentifiers() {
+        return getCurrentSchema().getAllModuleIdentifiers();
+    }
+
+    @Override
+    public boolean isPresenceContainer() {
+        return getCurrentSchema().isPresenceContainer();
+    }
+
+    @Override
+    public Set<TypeDefinition<?>> getTypeDefinitions() {
+        return getCurrentSchema().getTypeDefinitions();
+    }
+
+    @Override
+    public Collection<DataSchemaNode> getChildNodes() {
+        return getCurrentSchema().getChildNodes();
+    }
+
+    @Override
+    public Set<GroupingDefinition> getGroupings() {
+        return getCurrentSchema().getGroupings();
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final QName qName) {
+        return getCurrentSchema().getDataChildByName(qName);
+    }
+
+    @Override
+    public DataSchemaNode getDataChildByName(final String s) {
+        return getCurrentSchema().getDataChildByName(s);
+    }
+
+    @Override
+    public Set<UsesNode> getUses() {
+        return getCurrentSchema().getUses();
+    }
+
+    @Override
+    public Set<AugmentationSchema> getAvailableAugmentations() {
+        return getCurrentSchema().getAvailableAugmentations();
+    }
+
+    @Override
+    public boolean isAugmenting() {
+        return getCurrentSchema().isAugmenting();
+    }
+
+    @Override
+    public boolean isAddedByUses() {
+        return getCurrentSchema().isAddedByUses();
+    }
+
+    @Override
+    public boolean isConfiguration() {
+        return getCurrentSchema().isConfiguration();
+    }
+
+    @Override
+    public ConstraintDefinition getConstraints() {
+        return getCurrentSchema().getConstraints();
+    }
+
+    @Override
+    public QName getQName() {
+        return getCurrentSchema().getQName();
+    }
+
+    @Override
+    public SchemaPath getPath() {
+        return getCurrentSchema().getPath();
+    }
+
+    @Override
+    public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+        return getCurrentSchema().getUnknownSchemaNodes();
+    }
+
+    @Override
+    public String getDescription() {
+        return getCurrentSchema().getDescription();
+    }
+
+    @Override
+    public String getReference() {
+        return getCurrentSchema().getReference();
+    }
+
+    @Override
+    public Status getStatus() {
+        return getCurrentSchema().getStatus();
+    }
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java
new file mode 100644 (file)
index 0000000..3b11ed0
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.broker.impl.mount.DOMMountPointServiceImpl;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Optional;
+
+public class BackwardsCompatibleMountPointManagerTest {
+    private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+    @Mock
+    private DOMMountPointServiceImpl domMountPointService;
+    @Mock
+    private DOMMountPointService.DOMMountPointBuilder mountBuilder;
+
+    private BackwardsCompatibleMountPointManager compatibleMountPointManager;
+    static final QName qName = QName.create("namespace", "12-12-1212", "mount");
+    static final InstanceIdentifier id = InstanceIdentifier.builder(qName).build();
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        stubMountService();
+        compatibleMountPointManager = new BackwardsCompatibleMountPointManager(domMountPointService);
+    }
+
+    @Test
+    public void testCreateMountpointAlreadyCreated() throws Exception {
+        compatibleMountPointManager.createMountPoint(id);
+        verify(domMountPointService).createMountPoint(id);
+        verify(mountBuilder, times(3)).addService(any(Class.class), any(DOMService.class));
+        verify(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+
+        try {
+            compatibleMountPointManager.createMountPoint(id);
+        } catch (final IllegalStateException e) {
+            log.debug("", e);
+            return;
+        }
+        fail("Should fail to create duplicate mount");
+    }
+
+    @Test
+    public void testCreateMountpointGetOrCreate() throws Exception {
+        compatibleMountPointManager = new BackwardsCompatibleMountPointManager(new DOMMountPointServiceImpl());
+
+        final MountProvisionListener listener = new MountProvisionListener() {
+            public int createdMounts = 0;
+
+            @Override
+            public void onMountPointCreated(final InstanceIdentifier path) {
+                if(createdMounts++ > 1 ) {
+                    fail("Only one mount point should have been created");
+                }
+            }
+
+            @Override
+            public void onMountPointRemoved(final InstanceIdentifier path) {}
+        };
+
+        compatibleMountPointManager.registerProvisionListener(listener);
+
+        final MountProvisionInstance m1 = compatibleMountPointManager.createOrGetMountPoint(id);
+        m1.setSchemaContext(mockSchemaContext());
+        compatibleMountPointManager.createOrGetMountPoint(id);
+        compatibleMountPointManager.createOrGetMountPoint(id);
+    }
+
+    private void stubMountService() {
+        doReturn(mockMountPointBuilder()).when(domMountPointService).createMountPoint(any(InstanceIdentifier.class));
+        doReturn(Optional.of(mockMountPoint())).when(domMountPointService).getMountPoint(any(InstanceIdentifier.class));
+    }
+
+    private DOMMountPoint mockMountPoint() {
+        final DOMMountPoint mock = mock(DOMMountPoint.class);
+        doAnswer(new Answer() {
+            @Override
+            public Object answer(final InvocationOnMock invocation) throws Throwable {
+                return Optional.of(mock(((Class<?>) invocation.getArguments()[0])));
+            }
+        }).when(mock).getService(any(Class.class));
+        doReturn(mockSchemaContext()).when(mock).getSchemaContext();
+        return mock;
+    }
+
+    static SchemaContext mockSchemaContext() {
+        final SchemaContext mock = mock(SchemaContext.class);
+        doReturn(qName).when(mock).getQName();
+        doReturn("schema").when(mock).toString();
+        doReturn(mock(DataSchemaNode.class)).when(mock).getDataChildByName(any(QName.class));
+        return mock;
+    }
+
+    private DOMMountPointService.DOMMountPointBuilder mockMountPointBuilder() {
+        doReturn(mountBuilder).when(mountBuilder).addService(any(Class.class), any(DOMService.class));
+        doReturn(mockObjectRegistration()).when(mountBuilder).register();
+        doReturn(mountBuilder).when(mountBuilder).addInitialSchemaContext(any(SchemaContext.class));
+        return mountBuilder;
+    }
+
+    private ObjectRegistration<?> mockObjectRegistration() {
+        return mock(ObjectRegistration.class);
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java
new file mode 100644 (file)
index 0000000..5a36f71
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * 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.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.AbstractMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BackwardsCompatibleMountPointTest {
+    private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+    private static final InstanceIdentifier id = BackwardsCompatibleMountPointManagerTest.id;
+    private final NormalizedNode<?, ?> normalizedNode = mockNormalizedNode();
+    private final CompositeNode compositeNode = mockCompositeNode();
+
+    @Mock
+    private DataProviderService oldBroker;
+    @Mock
+    private SchemaContextProvider schemaContextProvider;
+    @Mock
+    private DataModificationTransaction mockTx;
+
+    private BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore backwardsCompatibleDomStore;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        stubSchemaProvider();
+        stubOldBroker();
+        backwardsCompatibleDomStore = new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore(oldBroker, schemaContextProvider);
+    }
+
+    private void stubOldBroker() {
+        doReturn(compositeNode).when(oldBroker).readConfigurationData(id);
+        doReturn(compositeNode).when(oldBroker).readOperationalData(id);
+        doReturn(mockTx).when(oldBroker).beginTransaction();
+        doNothing().when(mockTx).putConfigurationData(id, compositeNode);
+        doNothing().when(mockTx).putOperationalData(id, compositeNode);
+        doReturn(com.google.common.util.concurrent.Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED))).when(mockTx).commit();
+    }
+
+    private CompositeNode mockCompositeNode() {
+        final CompositeNode mock = mock(CompositeNode.class);
+        doReturn("node").when(mock).toString();
+        return mock;
+    }
+
+    private void stubSchemaProvider() {
+        doReturn(BackwardsCompatibleMountPointManagerTest.mockSchemaContext()).when(schemaContextProvider).getSchemaContext();
+    }
+
+    @Test
+    public void testBackwardsCompatibleBroker() throws Exception {
+        backwardsCompatibleDomStore.newReadOnlyTransaction();
+        backwardsCompatibleDomStore.newWriteOnlyTransaction();
+        backwardsCompatibleDomStore.newReadWriteTransaction();
+    }
+
+    @Test
+    public void testReadTransaction() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction(oldBroker, mockNormalizer());
+
+        ListenableFuture<Optional<NormalizedNode<?, ?>>> read = tx.read(LogicalDatastoreType.CONFIGURATION, id);
+        assertEquals(normalizedNode, read.get().get());
+        verify(oldBroker).readConfigurationData(id);
+
+        read = tx.read(LogicalDatastoreType.OPERATIONAL, id);
+        assertEquals(normalizedNode, read.get().get());
+
+        verify(oldBroker).readOperationalData(id);
+    }
+
+    @Test
+    public void testReadWriteTransactionOperational() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+        verify(oldBroker).beginTransaction();
+
+        tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+        verify(mockTx).putConfigurationData(id, compositeNode);
+
+        tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+        verify(mockTx, times(2)).putConfigurationData(id, compositeNode);
+
+        tx.commit();
+        verify(mockTx).commit();
+    }
+
+
+    @Test
+    public void testCannotPutOperational() throws Exception {
+        final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+                new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+        try {
+            tx.put(LogicalDatastoreType.OPERATIONAL, id, normalizedNode);
+        } catch (IllegalArgumentException e) {
+            // Cannot put operational data
+            log.debug("", e);
+            return;
+        }
+
+        fail("Should fail when putting operational data");
+    }
+
+    private DataNormalizer mockNormalizer() throws DataNormalizationException {
+        final DataNormalizer mock = mock(DataNormalizer.class);
+        doReturn(new AbstractMap.SimpleEntry<InstanceIdentifier, NormalizedNode<?, ?>>(id, normalizedNode) {})
+                .when(mock).toNormalized(any(InstanceIdentifier.class), any(CompositeNode.class));
+        doReturn(compositeNode).when(mock).toLegacy(any(InstanceIdentifier.class), any(NormalizedNode.class));
+        doReturn(id).when(mock).toLegacy(any(InstanceIdentifier.class));
+        return mock;
+    }
+
+    private NormalizedNode<?, ?> mockNormalizedNode() {
+        final NormalizedNode mock = mock(NormalizedNode.class);
+        doReturn("mockNormalizedNode").when(mock).toString();
+        return mock;
+    }
+}
\ No newline at end of file
index 172b0db..b39c9bb 100644 (file)
@@ -23,7 +23,7 @@ public class InMemoryOperationalDataStoreProviderModule extends org.opendaylight
     @Override
     public java.lang.AutoCloseable createInstance() {
       InMemoryDOMDataStore ids = new InMemoryDOMDataStore("DOM-OPER", MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()));
-      getSchemaServiceDependency().registerSchemaServiceListener(ids);
+      getOperationalSchemaServiceDependency().registerSchemaServiceListener(ids);
       return ids;
     }
 
index 03220a3..d4f57b5 100644 (file)
@@ -58,7 +58,10 @@ module opendaylight-inmemory-datastore-provider {
             case inmemory-operational-datastore-provider {
                 when "/config:modules/config:module/config:type = 'inmemory-operational-datastore-provider'";
 
-                container schema-service {
+                // Yang does not allow two cases from same namespaces with same children
+                // Schema-service dependency renamed to operational-schema-service
+                // to prevent conflict with schema-service container from inmemory-config-datastore-provider
+                container operational-schema-service {
                   uses config:service-ref {
                        refine type {
                               mandatory false;
index 0bf4b32..10fe4a5 100644 (file)
@@ -13,7 +13,6 @@
 
   <dependencies>
     <dependency>
-
       <groupId>${project.groupId}</groupId>
       <artifactId>netconf-client</artifactId>
       <version>${netconf.version}</version>
       <groupId>org.opendaylight.controller.model</groupId>
       <artifactId>model-inventory</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal-broker-impl</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>yang-data-impl</artifactId>
       <type>test-jar</type>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.opendaylight.controller</groupId>
-      <artifactId>sal-broker-impl</artifactId>
-      <type>jar</type>
-      <scope>test</scope>
-    </dependency>
     <dependency>
       <groupId>org.opendaylight.yangtools</groupId>
       <artifactId>mockito-configuration</artifactId>
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceCommitHandler.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceCommitHandler.java
deleted file mode 100644 (file)
index 26c6a27..0000000
+++ /dev/null
@@ -1,85 +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.connect.netconf.sal;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class NetconfDeviceCommitHandler implements DataCommitHandler<InstanceIdentifier,CompositeNode> {
-
-    private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceCommitHandler.class);
-
-    private final RemoteDeviceId id;
-    private final RpcImplementation rpc;
-    private final boolean rollbackSupported;
-
-    public NetconfDeviceCommitHandler(final RemoteDeviceId id, final RpcImplementation rpc, final boolean rollbackSupported) {
-        this.id = id;
-        this.rpc = rpc;
-        this.rollbackSupported = rollbackSupported;
-    }
-
-    @Override
-    public DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
-            final DataModification<InstanceIdentifier, CompositeNode> modification) {
-
-        final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit = new NetconfDeviceTwoPhaseCommitTransaction(id, rpc,
-                modification, true, rollbackSupported);
-        try {
-            twoPhaseCommit.prepare();
-        } catch (final InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException(id + ": Interrupted while waiting for response", e);
-        } catch (final ExecutionException e) {
-            logger.warn("{}: Error executing pre commit operation on remote device", id, e);
-            return new FailingTransaction(twoPhaseCommit, e);
-        }
-
-        return twoPhaseCommit;
-    }
-
-    /**
-     * Always fail commit transaction that rolls back delegate transaction afterwards
-     */
-    private class FailingTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
-        private final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit;
-        private final ExecutionException e;
-
-        public FailingTransaction(final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit, final ExecutionException e) {
-            this.twoPhaseCommit = twoPhaseCommit;
-            this.e = e;
-        }
-
-        @Override
-        public DataModification<InstanceIdentifier, CompositeNode> getModification() {
-            return twoPhaseCommit.getModification();
-        }
-
-        @Override
-        public RpcResult<Void> finish() throws IllegalStateException {
-            return RpcResultBuilder.<Void>failed().withError( RpcError.ErrorType.APPLICATION,
-                    id + ": Unexpected operation error during pre-commit operations", e ).build();
-        }
-
-        @Override
-        public RpcResult<Void> rollback() throws IllegalStateException {
-            return twoPhaseCommit.rollback();
-        }
-    }
-}
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java
new file mode 100644 (file)
index 0000000..53c057e
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * 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.connect.netconf.sal;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceReadOnlyTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceReadWriteTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceWriteOnlyTx;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class NetconfDeviceDataBroker implements DOMDataBroker {
+    private final RemoteDeviceId id;
+    private final RpcImplementation rpc;
+    private final NetconfSessionCapabilities netconfSessionPreferences;
+    private final DataNormalizer normalizer;
+
+    public NetconfDeviceDataBroker(final RemoteDeviceId id, final RpcImplementation rpc, final SchemaContext schemaContext, NetconfSessionCapabilities netconfSessionPreferences) {
+        this.id = id;
+        this.rpc = rpc;
+        this.netconfSessionPreferences = netconfSessionPreferences;
+        normalizer = new DataNormalizer(schemaContext);
+    }
+
+    @Override
+    public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+        return new NetconfDeviceReadOnlyTx(rpc, normalizer);
+    }
+
+    @Override
+    public DOMDataReadWriteTransaction newReadWriteTransaction() {
+        return new NetconfDeviceReadWriteTx(newReadOnlyTransaction(), newWriteOnlyTransaction());
+    }
+
+    @Override
+    public DOMDataWriteTransaction newWriteOnlyTransaction() {
+        // FIXME detect if candidate is supported, true is hardcoded
+        return new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, true, netconfSessionPreferences.isRollbackSupported());
+    }
+
+    @Override
+    public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+        throw new UnsupportedOperationException("Data change listeners not supported for netconf mount point");
+    }
+
+    @Override
+    public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+        // TODO implement
+        throw new UnsupportedOperationException("Transaction chains not supported for netconf mount point");
+    }
+}
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataReader.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataReader.java
deleted file mode 100644 (file)
index 3535c96..0000000
+++ /dev/null
@@ -1,100 +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.connect.netconf.sal;
-
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.CONFIG_SOURCE_RUNNING;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
-import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
-
-public final class NetconfDeviceDataReader implements DataReader<InstanceIdentifier,CompositeNode> {
-
-    private final RpcImplementation rpc;
-    private final RemoteDeviceId id;
-
-    public NetconfDeviceDataReader(final RemoteDeviceId id, final RpcImplementation rpc) {
-        this.id = id;
-        this.rpc = rpc;
-    }
-
-    @Override
-    public CompositeNode readConfigurationData(final InstanceIdentifier path) {
-        final RpcResult<CompositeNode> result;
-        try {
-            result = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME,
-                    NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path))).get();
-        } catch (final InterruptedException e) {
-            throw onInterruptedException(e);
-        } catch (final ExecutionException e) {
-            throw new RuntimeException(id + ": Read configuration data " + path + " failed", e);
-        }
-
-        final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
-        return data == null ? null : (CompositeNode) findNode(data, path);
-    }
-
-    private RuntimeException onInterruptedException(final InterruptedException e) {
-        Thread.currentThread().interrupt();
-        return new RuntimeException(id + ": Interrupted while waiting for response", e);
-    }
-
-    @Override
-    public CompositeNode readOperationalData(final InstanceIdentifier path) {
-        final RpcResult<CompositeNode> result;
-        try {
-            result = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path))).get();
-        } catch (final InterruptedException e) {
-            throw onInterruptedException(e);
-        } catch (final ExecutionException e) {
-            throw new RuntimeException(id + ": Read operational data " + path + " failed", e);
-        }
-
-        final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
-        return (CompositeNode) findNode(data, path);
-    }
-
-    private static Node<?> findNode(final CompositeNode node, final InstanceIdentifier identifier) {
-
-        Node<?> current = node;
-        for (final InstanceIdentifier.PathArgument arg : identifier.getPathArguments()) {
-            if (current instanceof SimpleNode<?>) {
-                return null;
-            } else if (current instanceof CompositeNode) {
-                final CompositeNode currentComposite = (CompositeNode) current;
-
-                current = currentComposite.getFirstCompositeByName(arg.getNodeType());
-                if (current == null) {
-                    current = currentComposite.getFirstCompositeByName(arg.getNodeType().withoutRevision());
-                }
-                if (current == null) {
-                    current = currentComposite.getFirstSimpleByName(arg.getNodeType());
-                }
-                if (current == null) {
-                    current = currentComposite.getFirstSimpleByName(arg.getNodeType().withoutRevision());
-                }
-                if (current == null) {
-                    return null;
-                }
-            }
-        }
-        return current;
-    }
-}
index e491496..04d5e5e 100644 (file)
@@ -8,27 +8,28 @@
 package org.opendaylight.controller.sal.connect.netconf.sal;
 
 import com.google.common.base.Function;
+import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.FluentIterable;
+import com.google.common.util.concurrent.CheckedFuture;
 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 com.google.common.util.concurrent.MoreExecutors;
 import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
-import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
+import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.Nodes;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodesBuilder;
 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.netconf.node.inventory.rev140108.NetconfNode;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.netconf.node.inventory.rev140108.NetconfNodeBuilder;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.QName;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -42,123 +43,86 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
     private static final Logger logger  = LoggerFactory.getLogger(NetconfDeviceDatastoreAdapter.class);
 
     private final RemoteDeviceId id;
-    private final DataProviderService dataService;
-    private final ListeningExecutorService executor;
+    private final DataBroker dataService;
 
-    NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataProviderService dataService,
-            final ExecutorService executor) {
+    NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataBroker dataService) {
         this.id = Preconditions.checkNotNull(deviceId);
         this.dataService = Preconditions.checkNotNull(dataService);
-        this.executor = MoreExecutors.listeningDecorator(Preconditions.checkNotNull(executor));
 
-        // Initial data change scheduled
-        submitDataChangeToExecutor(this.executor, new Runnable() {
-            @Override
-            public void run() {
-                initDeviceData();
-            }
-        }, deviceId);
+        initDeviceData();
     }
 
     public void updateDeviceState(final boolean up, final Set<QName> capabilities) {
-        submitDataChangeToExecutor(this.executor, new Runnable() {
-            @Override
-            public void run() {
-                updateDeviceStateInternal(up, capabilities);
-            }
-        }, id);
-    }
-
-    private void updateDeviceStateInternal(final boolean up, final Set<QName> capabilities) {
         final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node data = buildDataForDeviceState(
                 up, capabilities, id);
 
-        final DataModificationTransaction transaction = dataService.beginTransaction();
-        logger.trace("{}: Update device state transaction {} putting operational data started.", id, transaction.getIdentifier());
-        transaction.removeOperationalData(id.getBindingPath());
-        transaction.putOperationalData(id.getBindingPath(), data);
-        logger.trace("{}: Update device state transaction {} putting operational data ended.", id, transaction.getIdentifier());
+        final ReadWriteTransaction transaction = dataService.newReadWriteTransaction();
+        logger.trace("{}: Update device state transaction {} merging operational data started.", id, transaction.getIdentifier());
+        transaction.merge(LogicalDatastoreType.OPERATIONAL, id.getBindingPath(), data);
+        logger.trace("{}: Update device state transaction {} merging operational data ended.", id, transaction.getIdentifier());
 
         commitTransaction(transaction, "update");
     }
 
     private void removeDeviceConfigAndState() {
-        final DataModificationTransaction transaction = dataService.beginTransaction();
+        final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
         logger.trace("{}: Close device state transaction {} removing all data started.", id, transaction.getIdentifier());
-        transaction.removeConfigurationData(id.getBindingPath());
-        transaction.removeOperationalData(id.getBindingPath());
+        transaction.delete(LogicalDatastoreType.CONFIGURATION, id.getBindingPath());
+        transaction.delete(LogicalDatastoreType.OPERATIONAL, id.getBindingPath());
         logger.trace("{}: Close device state transaction {} removing all data ended.", id, transaction.getIdentifier());
 
         commitTransaction(transaction, "close");
     }
 
     private void initDeviceData() {
-        final DataModificationTransaction transaction = dataService.beginTransaction();
+        final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
 
-        final InstanceIdentifier<Node> path = id.getBindingPath();
+        createNodesListIfNotPresent(transaction);
 
+        final InstanceIdentifier<Node> path = id.getBindingPath();
         final Node nodeWithId = getNodeWithId(id);
-        if (operationalNodeNotExisting(transaction, path)) {
-            transaction.putOperationalData(path, nodeWithId);
-        }
-        if (configurationNodeNotExisting(transaction, path)) {
-            transaction.putConfigurationData(path, nodeWithId);
-        }
 
-        commitTransaction(transaction, "init");
-    }
+        logger.trace("{}: Init device state transaction {} putting if absent operational data started.", id, transaction.getIdentifier());
+        transaction.merge(LogicalDatastoreType.OPERATIONAL, path, nodeWithId);
+        logger.trace("{}: Init device state transaction {} putting operational data ended.", id, transaction.getIdentifier());
 
-    private void commitTransaction(final DataModificationTransaction transaction, final String txType) {
-        // attempt commit
-        final RpcResult<TransactionStatus> result;
-        try {
-            result = transaction.commit().get();
-        } catch (InterruptedException | ExecutionException e) {
-            logger.error("{}: Transaction({}) failed", id, txType, e);
-            throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly", e);
-        }
-
-        // verify success result + committed state
-        if (isUpdateSuccessful(result)) {
-            logger.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
-        } else {
-            logger.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier());
-            throw new IllegalStateException(id + "  Transaction(" + txType + ") not committed correctly, " +
-                    "Errors: " + result.getErrors());
-        }
-    }
+        logger.trace("{}: Init device state transaction {} putting if absent config data started.", id, transaction.getIdentifier());
+        transaction.merge(LogicalDatastoreType.CONFIGURATION, path, nodeWithId);
+        logger.trace("{}: Init device state transaction {} putting config data ended.", id, transaction.getIdentifier());
 
-    @Override
-    public void close() throws Exception {
-        // Remove device data from datastore
-        submitDataChangeToExecutor(executor, new Runnable() {
-            @Override
-            public void run() {
-                removeDeviceConfigAndState();
-            }
-        }, id);
+        commitTransaction(transaction, "init");
     }
 
-    private static boolean isUpdateSuccessful(final RpcResult<TransactionStatus> result) {
-        return result.getResult() == TransactionStatus.COMMITED && result.isSuccessful();
+    private void createNodesListIfNotPresent(final WriteTransaction writeTx) {
+        final Nodes nodes = new NodesBuilder().build();
+        final InstanceIdentifier<Nodes> path = InstanceIdentifier.builder(Nodes.class).build();
+        logger.trace("{}: Merging {} container to ensure its presence", id, Nodes.QNAME, writeTx.getIdentifier());
+        writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, nodes);
+        writeTx.merge(LogicalDatastoreType.OPERATIONAL, path, nodes);
     }
 
-    private static void submitDataChangeToExecutor(final ListeningExecutorService executor, final Runnable r,
-            final RemoteDeviceId id) {
-        // Submit data change
-        final ListenableFuture<?> f = executor.submit(r);
-        // Verify update execution
-        Futures.addCallback(f, new FutureCallback<Object>() {
+    private void commitTransaction(final WriteTransaction transaction, final String txType) {
+        logger.trace("{}: Committing Transaction {}:{}", id, txType, transaction.getIdentifier());
+        final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
+
+        Futures.addCallback(result, new FutureCallback<Void>() {
             @Override
-            public void onSuccess(final Object result) {
-                logger.debug("{}: Device data updated successfully", id);
+            public void onSuccess(final Void result) {
+                logger.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
             }
 
             @Override
             public void onFailure(final Throwable t) {
-                logger.warn("{}: Device data update failed", id, t);
+                logger.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier(), t);
+                throw new IllegalStateException(id + "  Transaction(" + txType + ") not committed correctly", t);
             }
         });
+
+    }
+
+    @Override
+    public void close() throws Exception {
+        removeDeviceConfigAndState();
     }
 
     public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildDataForDeviceState(
@@ -179,14 +143,11 @@ final class NetconfDeviceDatastoreAdapter implements AutoCloseable {
         return nodeBuilder.build();
     }
 
-    private static boolean configurationNodeNotExisting(final DataModificationTransaction transaction,
-            final InstanceIdentifier<Node> path) {
-        return null == transaction.readConfigurationData(path);
-    }
-
-    private static boolean operationalNodeNotExisting(final DataModificationTransaction transaction,
+    private static ListenableFuture<Optional<Node>> readNodeData(
+            final LogicalDatastoreType store,
+            final ReadWriteTransaction transaction,
             final InstanceIdentifier<Node> path) {
-        return null == transaction.readOperationalData(path);
+        return transaction.read(store, path);
     }
 
     private static Node getNodeWithId(final RemoteDeviceId id) {
index 8d5b7ae..a0453bc 100644 (file)
@@ -44,6 +44,8 @@ public final class NetconfDeviceRpc implements RpcImplementation {
         return Collections.emptySet();
     }
 
+    // TODO change this to work with NormalizedNode api. Then we can loose DataNormalizer from Transactions
+
     @Override
     public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
         final NetconfMessage message = transformRequest(rpc, input);
index 37b8704..dbef290 100644 (file)
@@ -7,32 +7,40 @@
  */
 package org.opendaylight.controller.sal.connect.netconf.sal;
 
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
 import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
 import org.osgi.framework.BundleContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
 public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionCapabilities> {
 
     private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceSalFacade.class);
-    private static final InstanceIdentifier ROOT_PATH = InstanceIdentifier.builder().toInstance();
 
     private final RemoteDeviceId id;
     private final NetconfDeviceSalProvider salProvider;
@@ -58,24 +66,50 @@ public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDevice
     @Override
     public synchronized void onDeviceConnected(final SchemaContextProvider remoteSchemaContextProvider,
                                                final NetconfSessionCapabilities netconfSessionPreferences, final RpcImplementation deviceRpc) {
-        salProvider.getMountInstance().setSchemaContext(remoteSchemaContextProvider.getSchemaContext());
+        final SchemaContext schemaContext = remoteSchemaContextProvider.getSchemaContext();
+
+        // TODO remove deprecated SchemaContextProvider from SchemaAwareRpcBroker
+        // TODO move SchemaAwareRpcBroker from sal-broker-impl, now we have depend on the whole sal-broker-impl
+        final RpcProvisionRegistry rpcRegistry = new SchemaAwareRpcBroker(id.getPath().toString(), new org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider() {
+            @Override
+            public SchemaContext getSchemaContext() {
+                return schemaContext;
+            }
+        });
+        registerRpcsToSal(schemaContext, rpcRegistry, deviceRpc);
+        final DOMDataBroker domBroker = new NetconfDeviceDataBroker(id, deviceRpc, schemaContext, netconfSessionPreferences);
+
+        // TODO NotificationPublishService and NotificationRouter have the same interface
+        final NotificationPublishService notificationService = new NotificationPublishService() {
+
+            private final NotificationRouter innerRouter = new NotificationRouterImpl();
+
+            @Override
+            public void publish(final CompositeNode notification) {
+                innerRouter.publish(notification);
+            }
+
+            @Override
+            public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+                return innerRouter.addNotificationListener(notification, listener);
+            }
+        };
+
+        salProvider.getMountInstance().onDeviceConnected(schemaContext, domBroker, rpcRegistry, notificationService);
         salProvider.getDatastoreAdapter().updateDeviceState(true, netconfSessionPreferences.getModuleBasedCaps());
-        registerDataHandlersToSal(deviceRpc, netconfSessionPreferences);
-        registerRpcsToSal(deviceRpc);
     }
 
     @Override
     public void onDeviceDisconnected() {
         salProvider.getDatastoreAdapter().updateDeviceState(false, Collections.<QName>emptySet());
+        salProvider.getMountInstance().onDeviceDisconnected();
     }
 
-    private void registerRpcsToSal(final RpcImplementation deviceRpc) {
-        final MountProvisionInstance mountInstance = salProvider.getMountInstance();
-
+    private void registerRpcsToSal(final SchemaContext schemaContext, final RpcProvisionRegistry rpcRegistry, final RpcImplementation deviceRpc) {
         final Map<QName, String> failedRpcs = Maps.newHashMap();
-        for (final RpcDefinition rpcDef : mountInstance.getSchemaContext().getOperations()) {
+        for (final RpcDefinition rpcDef : schemaContext.getOperations()) {
             try {
-                salRegistrations.add(mountInstance.addRpcImplementation(rpcDef.getQName(), deviceRpc));
+                salRegistrations.add(rpcRegistry.addRpcImplementation(rpcDef.getQName(), deviceRpc));
                 logger.debug("{}: Rpc {} from netconf registered successfully", id, rpcDef.getQName());
             } catch (final Exception e) {
                 // Only debug per rpc, warn for all of them at the end to pollute log a little less (e.g. routed rpcs)
@@ -94,18 +128,6 @@ public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDevice
         }
     }
 
-    private void registerDataHandlersToSal(final RpcImplementation deviceRpc,
-            final NetconfSessionCapabilities netconfSessionPreferences) {
-        final NetconfDeviceDataReader dataReader = new NetconfDeviceDataReader(id, deviceRpc);
-        final NetconfDeviceCommitHandler commitHandler = new NetconfDeviceCommitHandler(id, deviceRpc,
-                netconfSessionPreferences.isRollbackSupported());
-
-        final MountProvisionInstance mountInstance = salProvider.getMountInstance();
-        salRegistrations.add(mountInstance.registerConfigurationReader(ROOT_PATH, dataReader));
-        salRegistrations.add(mountInstance.registerOperationalReader(ROOT_PATH, dataReader));
-        salRegistrations.add(mountInstance.registerCommitHandler(ROOT_PATH, commitHandler));
-    }
-
     @Override
     public void close() {
         for (final AutoCloseable reg : Lists.reverse(salRegistrations)) {
index fc54bfb..cf9174d 100644 (file)
@@ -11,15 +11,21 @@ import com.google.common.base.Preconditions;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.concurrent.ExecutorService;
+import org.opendaylight.controller.md.sal.binding.api.DataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
 import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
 import org.opendaylight.controller.sal.binding.api.BindingAwareProvider;
-import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.controller.sal.core.api.Broker;
 import org.opendaylight.controller.sal.core.api.Provider;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
 import org.opendaylight.yangtools.yang.binding.RpcService;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,17 +35,17 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     private final RemoteDeviceId id;
     private final ExecutorService executor;
-    private volatile MountProvisionInstance mountInstance;
     private volatile NetconfDeviceDatastoreAdapter datastoreAdapter;
+    private MountInstance mountInstance;
 
     public NetconfDeviceSalProvider(final RemoteDeviceId deviceId, final ExecutorService executor) {
         this.id = deviceId;
         this.executor = executor;
     }
 
-    public MountProvisionInstance getMountInstance() {
+    public MountInstance getMountInstance() {
         Preconditions.checkState(mountInstance != null,
-                "%s: Sal provider was not initialized by sal. Cannot get mount instance", id);
+                "%s: Mount instance was not initialized by sal. Cannot get mount instance", id);
         return mountInstance;
     }
 
@@ -51,12 +57,12 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     @Override
     public void onSessionInitiated(final Broker.ProviderSession session) {
-        final MountProvisionService mountService = session.getService(MountProvisionService.class);
+        logger.debug("{}: (BI)Session with sal established {}", id, session);
+
+        final DOMMountPointService mountService = session.getService(DOMMountPointService.class);
         if (mountService != null) {
-            mountInstance = mountService.createOrGetMountPoint(id.getPath());
+            mountInstance = new MountInstance(mountService, id);
         }
-
-        logger.debug("{}: (BI)Session with sal established {}", id, session);
     }
 
     @Override
@@ -76,20 +82,78 @@ final class NetconfDeviceSalProvider implements AutoCloseable, Provider, Binding
 
     @Override
     public void onSessionInitiated(final BindingAwareBroker.ProviderContext session) {
-        final DataProviderService dataBroker = session.getSALService(DataProviderService.class);
-        datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker, executor);
-
         logger.debug("{}: Session with sal established {}", id, session);
+
+        final DataBroker dataBroker = session.getSALService(DataBroker.class);
+        datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker);
     }
 
     @Override
-    public void onSessionInitialized(final BindingAwareBroker.ConsumerContext session) {
-    }
+    public void onSessionInitialized(final BindingAwareBroker.ConsumerContext session) {}
 
     public void close() throws Exception {
-        mountInstance = null;
+        mountInstance.close();
         datastoreAdapter.close();
         datastoreAdapter = null;
     }
 
+    static final class MountInstance implements AutoCloseable {
+
+        private DOMMountPointService mountService;
+        private final RemoteDeviceId id;
+        private ObjectRegistration<DOMMountPoint> registration;
+        private NotificationPublishService notificationSerivce;
+
+        MountInstance(final DOMMountPointService mountService, final RemoteDeviceId id) {
+            this.mountService = Preconditions.checkNotNull(mountService);
+            this.id = Preconditions.checkNotNull(id);
+        }
+
+        synchronized void onDeviceConnected(final SchemaContext initialCtx,
+                final DOMDataBroker broker, final RpcProvisionRegistry rpc,
+                final NotificationPublishService notificationSerivce) {
+
+            Preconditions.checkNotNull(mountService, "Closed");
+            Preconditions.checkState(registration == null, "Already initialized");
+
+            final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getPath());
+            mountBuilder.addInitialSchemaContext(initialCtx);
+
+            mountBuilder.addService(DOMDataBroker.class, broker);
+            mountBuilder.addService(RpcProvisionRegistry.class, rpc);
+            this.notificationSerivce = notificationSerivce;
+            mountBuilder.addService(NotificationPublishService.class, notificationSerivce);
+
+            registration = mountBuilder.register();
+        }
+
+        synchronized void onDeviceDisconnected() {
+            if(registration == null) {
+                return;
+            }
+
+            try {
+                registration.close();
+            } catch (final Exception e) {
+                // Only log and ignore
+                logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getPath(), e);
+            } finally {
+                registration = null;
+            }
+        }
+
+        @Override
+        synchronized public void close() throws Exception {
+            if(registration != null) {
+                onDeviceDisconnected();
+            }
+            mountService = null;
+        }
+
+        public synchronized void publish(final CompositeNode domNotification) {
+            Preconditions.checkNotNull(notificationSerivce, "Device not set up yet, cannot handle notification {}", domNotification);
+            notificationSerivce.publish(domNotification);
+        }
+    }
+
 }
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java
new file mode 100644 (file)
index 0000000..142ee44
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+ * 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.connect.netconf.sal.tx;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.CONFIG_SOURCE_RUNNING;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction {
+
+    private static final Logger LOG  = LoggerFactory.getLogger(NetconfDeviceReadOnlyTx.class);
+
+    private final RpcImplementation rpc;
+    private final DataNormalizer normalizer;
+
+    public NetconfDeviceReadOnlyTx(final RpcImplementation rpc, final DataNormalizer normalizer) {
+        this.rpc = rpc;
+        this.normalizer = normalizer;
+    }
+
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> readConfigurationData(final InstanceIdentifier path) {
+        final ListenableFuture<RpcResult<CompositeNode>> future = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME,
+                NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path)));
+
+        return Futures.transform(future, new Function<RpcResult<CompositeNode>, Optional<NormalizedNode<?, ?>>>() {
+            @Override
+            public Optional<NormalizedNode<?, ?>> apply(final RpcResult<CompositeNode> result) {
+                final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
+                final CompositeNode node = (CompositeNode) findNode(data, path);
+
+                return data == null ?
+                        Optional.<NormalizedNode<?, ?>>absent() :
+                        transform(path, node);
+            }
+        });
+    }
+
+    private Optional<NormalizedNode<?, ?>> transform(final InstanceIdentifier path, final CompositeNode node) {
+        if(node == null) {
+            return Optional.absent();
+        }
+        try {
+            return Optional.<NormalizedNode<?, ?>>of(normalizer.toNormalized(path, node).getValue());
+        } catch (final Exception e) {
+            LOG.error("Unable to normalize data for {}, data: {}", path, node, e);
+            throw e;
+        }
+    }
+
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> readOperationalData(final InstanceIdentifier path) {
+        final ListenableFuture<RpcResult<CompositeNode>> future = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path)));
+
+        return Futures.transform(future, new Function<RpcResult<CompositeNode>, Optional<NormalizedNode<?, ?>>>() {
+            @Override
+            public Optional<NormalizedNode<?, ?>> apply(final RpcResult<CompositeNode> result) {
+                final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
+                final CompositeNode node = (CompositeNode) findNode(data, path);
+
+                return data == null ?
+                        Optional.<NormalizedNode<?, ?>>absent() :
+                        transform(path, node);
+            }
+        });
+    }
+
+    private static Node<?> findNode(final CompositeNode node, final InstanceIdentifier identifier) {
+
+        Node<?> current = node;
+        for (final InstanceIdentifier.PathArgument arg : identifier.getPathArguments()) {
+            if (current instanceof SimpleNode<?>) {
+                return null;
+            } else if (current instanceof CompositeNode) {
+                final CompositeNode currentComposite = (CompositeNode) current;
+
+                current = currentComposite.getFirstCompositeByName(arg.getNodeType());
+                if (current == null) {
+                    current = currentComposite.getFirstCompositeByName(arg.getNodeType().withoutRevision());
+                }
+                if (current == null) {
+                    current = currentComposite.getFirstSimpleByName(arg.getNodeType());
+                }
+                if (current == null) {
+                    current = currentComposite.getFirstSimpleByName(arg.getNodeType().withoutRevision());
+                }
+                if (current == null) {
+                    return null;
+                }
+            }
+        }
+        return current;
+    }
+
+    @Override
+    public void close() {
+        // NOOP
+    }
+
+    @Override
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+        final InstanceIdentifier legacyPath = toLegacyPath(normalizer, path);
+
+        switch (store) {
+            case CONFIGURATION : {
+                return readConfigurationData(legacyPath);
+            }
+            case OPERATIONAL : {
+                return readOperationalData(legacyPath);
+            }
+        }
+
+        throw new IllegalArgumentException(String.format("Cannot read data %s for %s datastore, unknown datastore type", path, store));
+    }
+
+    static InstanceIdentifier toLegacyPath(final DataNormalizer normalizer, final InstanceIdentifier path) {
+        try {
+            return normalizer.toLegacy(path);
+        } catch (final DataNormalizationException e) {
+            throw new IllegalArgumentException("Cannot normalize path " + path, e);
+        }
+    }
+
+    @Override
+    public Object getIdentifier() {
+        return this;
+    }
+}
diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java
new file mode 100644 (file)
index 0000000..9313ccb
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * 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.connect.netconf.sal.tx;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class NetconfDeviceReadWriteTx implements DOMDataReadWriteTransaction {
+
+    private final DOMDataReadTransaction delegateReadTx;
+    private final DOMDataWriteTransaction delegateWriteTx;
+
+    public NetconfDeviceReadWriteTx(final DOMDataReadTransaction delegateReadTx, final DOMDataWriteTransaction delegateWriteTx) {
+        this.delegateReadTx = delegateReadTx;
+        this.delegateWriteTx = delegateWriteTx;
+    }
+
+    @Override
+    public boolean cancel() {
+        return delegateWriteTx.cancel();
+    }
+
+    @Override
+    public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        delegateWriteTx.put(store, path, data);
+    }
+
+    @Override
+    public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        delegateWriteTx.merge(store, path, data);
+    }
+
+    @Override
+    public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+        delegateWriteTx.delete(store, path);
+    }
+
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        return delegateWriteTx.submit();
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        return delegateWriteTx.commit();
+    }
+
+    @Override
+    public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+        return delegateReadTx.read(store, path);
+    }
+
+    @Override
+    public Object getIdentifier() {
+        return this;
+    }
+}
@@ -3,9 +3,10 @@
  *
  * 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
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
  */
-package org.opendaylight.controller.sal.connect.netconf.sal;
+
+package org.opendaylight.controller.sal.connect.netconf.sal.tx;
 
 import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_CANDIDATE_QNAME;
 import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME;
@@ -18,21 +19,25 @@ import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessag
 import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_TARGET_QNAME;
 import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.ROLLBACK_ON_ERROR_OPTION;
 
+import com.google.common.base.Function;
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
-
-import java.util.Collection;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.Map.Entry;
 import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
 import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
 import org.opendaylight.controller.sal.core.api.RpcImplementation;
@@ -42,102 +47,164 @@ import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.ModifyAction;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- *  Remote transaction that delegates data change to remote device using netconf messages.
- */
-final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
+public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction {
 
-    private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTwoPhaseCommitTransaction.class);
+    private static final Logger LOG  = LoggerFactory.getLogger(NetconfDeviceWriteOnlyTx.class);
 
-    private final DataModification<InstanceIdentifier, CompositeNode> modification;
+    private final RemoteDeviceId id;
     private final RpcImplementation rpc;
+    private final DataNormalizer normalizer;
     private final boolean rollbackSupported;
-    private final RemoteDeviceId id;
     private final CompositeNode targetNode;
 
-    public NetconfDeviceTwoPhaseCommitTransaction(final RemoteDeviceId id, final RpcImplementation rpc,
-            final DataModification<InstanceIdentifier, CompositeNode> modification,
-            final boolean candidateSupported, final boolean rollbackOnErrorSupported) {
+    public NetconfDeviceWriteOnlyTx(final RemoteDeviceId id, final RpcImplementation rpc, final DataNormalizer normalizer, final boolean candidateSupported, final boolean rollbackOnErrorSupported) {
         this.id = id;
-        this.rpc = Preconditions.checkNotNull(rpc);
-        this.modification = Preconditions.checkNotNull(modification);
+        this.rpc = rpc;
+        this.normalizer = normalizer;
         this.targetNode = getTargetNode(candidateSupported);
         this.rollbackSupported = rollbackOnErrorSupported;
     }
 
-    /**
-     * Prepare phase, sends 1 or more netconf edit config operations to modify the data
-     *
-     * In case of failure or unexpected error response, ExecutionException is thrown
-     */
-    void prepare() throws InterruptedException, ExecutionException {
-        for (final InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
-            sendDelete(toRemove);
-        }
-        for(final Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
-            sendMerge(toUpdate.getKey(),toUpdate.getValue());
+    // FIXME add logging
+
+    @Override
+    public boolean cancel() {
+        if(isCommitted()) {
+            return false;
         }
+
+        return discardChanges();
     }
 
-    private void sendMerge(final InstanceIdentifier key, final CompositeNode value) throws InterruptedException, ExecutionException {
-        sendEditRpc(createEditConfigStructure(key, Optional.<ModifyAction>absent(), Optional.of(value)), Optional.<ModifyAction>absent());
+    private boolean isCommitted() {
+        // TODO 732
+        return true;
     }
 
-    private void sendDelete(final InstanceIdentifier toDelete) throws InterruptedException, ExecutionException {
-        sendEditRpc(createEditConfigStructure(toDelete, Optional.of(ModifyAction.DELETE), Optional.<CompositeNode>absent()), Optional.of(ModifyAction.NONE));
+    private boolean discardChanges() {
+        // TODO 732
+        return true;
     }
 
-    private void sendEditRpc(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) throws InterruptedException, ExecutionException {
-        final ImmutableCompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation);
-        final RpcResult<CompositeNode> rpcResult = rpc.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, editConfigRequest).get();
+    // TODO should the edit operations be blocking ?
 
-        // Check result
-        if(rpcResult.isSuccessful() == false) {
-            throw new ExecutionException(
-                    String.format("%s: Pre-commit rpc failed, request: %s, errors: %s", id, editConfigRequest, rpcResult.getErrors()), null);
+    @Override
+    public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
+
+        try {
+            final InstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path);
+            final CompositeNode legacyData = normalizer.toLegacy(path, data);
+            sendEditRpc(createEditConfigStructure(legacyPath, Optional.of(ModifyAction.REPLACE), Optional.fromNullable(legacyData)), Optional.of(ModifyAction.NONE));
+        } catch (final ExecutionException e) {
+            LOG.warn("Error putting data to {}, data: {}, discarding changes", path, data, e);
+            discardChanges();
+            throw new RuntimeException("Error while replacing " + path, e);
         }
     }
 
-    private ImmutableCompositeNode createEditConfigRequest(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) {
-        final CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
+    @Override
+    public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+        Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
 
-        // Target
-        final Node<?> targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.<Node<?>>of(targetNode));
-        ret.add(targetWrapperNode);
+        try {
+            final InstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path);
+            final CompositeNode legacyData = normalizer.toLegacy(path, data);
+            sendEditRpc(
+                    createEditConfigStructure(legacyPath, Optional.<ModifyAction> absent(), Optional.fromNullable(legacyData)), Optional.<ModifyAction> absent());
+        } catch (final ExecutionException e) {
+            LOG.warn("Error merging data to {}, data: {}, discarding changes", path, data, e);
+            discardChanges();
+            throw new RuntimeException("Error while merging " + path, e);
+        }
+    }
 
-        // Default operation
-        if(defaultOperation.isPresent()) {
-            final SimpleNode<String> defOp = NodeFactory.createImmutableSimpleNode(NETCONF_DEFAULT_OPERATION_QNAME, null, modifyOperationToXmlString(defaultOperation.get()));
-            ret.add(defOp);
+    @Override
+    public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+        Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
+
+        try {
+            sendEditRpc(createEditConfigStructure(NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path), Optional.of(ModifyAction.DELETE), Optional.<CompositeNode>absent()), Optional.of(ModifyAction.NONE));
+        } catch (final ExecutionException e) {
+            LOG.warn("Error deleting data {}, discarding changes", path, e);
+            discardChanges();
+            throw new RuntimeException("Error while deleting " + path, e);
         }
+    }
 
-        // Error option
-        if(rollbackSupported) {
-            ret.addLeaf(NETCONF_ERROR_OPTION_QNAME, ROLLBACK_ON_ERROR_OPTION);
+    @Override
+    public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+        final ListenableFuture<Void> commmitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+            @Nullable
+            @Override
+            public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+                return null;
+            }
+        });
+
+        return Futures.makeChecked(commmitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+            @Override
+            public TransactionCommitFailedException apply(final Exception input) {
+                return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input);
+            }
+        });
+    }
+
+    @Override
+    public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        // FIXME do not allow commit if closed or failed
+
+        final ListenableFuture<RpcResult<CompositeNode>> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest());
+        return Futures.transform(rpcResult, new Function<RpcResult<CompositeNode>, RpcResult<TransactionStatus>>() {
+            @Override
+            public RpcResult<TransactionStatus> apply(@Nullable final RpcResult<CompositeNode> input) {
+                if(input.isSuccessful()) {
+                    return RpcResultBuilder.success(TransactionStatus.COMMITED).build();
+                } else {
+                    final RpcResultBuilder<TransactionStatus> failed = RpcResultBuilder.failed();
+                    for (final RpcError rpcError : input.getErrors()) {
+                        failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(), rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause());
+                    }
+                    return failed.build();
+                }
+            }
+        });
+
+        // FIXME 732 detect commit failure
+    }
+
+    private void sendEditRpc(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) throws ExecutionException {
+        final CompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation);
+        final RpcResult<CompositeNode> rpcResult;
+        try {
+            rpcResult = rpc.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, editConfigRequest).get();
+        } catch (final InterruptedException e) {
+            Thread.currentThread().interrupt();
+            throw new RuntimeException(id + ": Interrupted while waiting for response", e);
         }
 
-        ret.setQName(NETCONF_EDIT_CONFIG_QNAME);
-        // Edit content
-        ret.add(editStructure);
-        return ret.toInstance();
+        // Check result
+        if(rpcResult.isSuccessful() == false) {
+            throw new ExecutionException(
+                    String.format("%s: Pre-commit rpc failed, request: %s, errors: %s", id, editConfigRequest, rpcResult.getErrors()), null);
+        }
     }
 
     private CompositeNode createEditConfigStructure(final InstanceIdentifier dataPath, final Optional<ModifyAction> operation,
-            final Optional<CompositeNode> lastChildOverride) {
+                                                    final Optional<CompositeNode> lastChildOverride) {
         Preconditions.checkArgument(Iterables.isEmpty(dataPath.getPathArguments()) == false, "Instance identifier with empty path %s", dataPath);
 
-        List<PathArgument> reversedPath = Lists.reverse(dataPath.getPath());
+        List<InstanceIdentifier.PathArgument> reversedPath = Lists.reverse(dataPath.getPath());
 
         // Create deepest edit element with expected edit operation
         CompositeNode previous = getDeepestEditElement(reversedPath.get(0), operation, lastChildOverride);
@@ -147,7 +214,7 @@ final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransact
         reversedPath.remove(0);
 
         // Create edit structure in reversed order
-        for (final PathArgument arg : reversedPath) {
+        for (final InstanceIdentifier.PathArgument arg : reversedPath) {
             final CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
             builder.setQName(arg.getNodeType());
 
@@ -160,20 +227,20 @@ final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransact
     }
 
     private void addPredicatesToCompositeNodeBuilder(final Map<QName, Object> predicates, final CompositeNodeBuilder<ImmutableCompositeNode> builder) {
-        for (final Entry<QName, Object> entry : predicates.entrySet()) {
+        for (final Map.Entry<QName, Object> entry : predicates.entrySet()) {
             builder.addLeaf(entry.getKey(), entry.getValue());
         }
     }
 
-    private Map<QName, Object> getPredicates(final PathArgument arg) {
+    private Map<QName, Object> getPredicates(final InstanceIdentifier.PathArgument arg) {
         Map<QName, Object> predicates = Collections.emptyMap();
-        if (arg instanceof NodeIdentifierWithPredicates) {
-            predicates = ((NodeIdentifierWithPredicates) arg).getKeyValues();
+        if (arg instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
+            predicates = ((InstanceIdentifier.NodeIdentifierWithPredicates) arg).getKeyValues();
         }
         return predicates;
     }
 
-    private CompositeNode getDeepestEditElement(final PathArgument arg, final Optional<ModifyAction> operation, final Optional<CompositeNode> lastChildOverride) {
+    private CompositeNode getDeepestEditElement(final InstanceIdentifier.PathArgument arg, final Optional<ModifyAction> operation, final Optional<CompositeNode> lastChildOverride) {
         final CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
         builder.setQName(arg.getNodeType());
 
@@ -195,44 +262,32 @@ final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransact
         return builder.toInstance();
     }
 
-    private String modifyOperationToXmlString(final ModifyAction operation) {
-        return operation.name().toLowerCase();
-    }
+    private CompositeNode createEditConfigRequest(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) {
+        final CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
 
-    /**
-     * Send commit rpc to finish the transaction
-     * In case of failure or unexpected error response, ExecutionException is thrown
-     */
-    @Override
-    public RpcResult<Void> finish() {
-        try {
-            final RpcResult<?> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest()).get();
-            return new RpcResultVoidWrapper(rpcResult);
-        } catch (final InterruptedException e) {
-            Thread.currentThread().interrupt();
-            throw new RuntimeException(id + ": Interrupted while waiting for response", e);
-        } catch (final ExecutionException e) {
-            LOG.warn("{}: Failed to finish commit operation", id, e);
-            return RpcResultBuilder.<Void>failed().withError( RpcError.ErrorType.APPLICATION,
-                            id + ": Unexpected operation error during commit operation", e ).build();
+        // Target
+        final Node<?> targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.<Node<?>>of(targetNode));
+        ret.add(targetWrapperNode);
+
+        // Default operation
+        if(defaultOperation.isPresent()) {
+            final SimpleNode<String> defOp = NodeFactory.createImmutableSimpleNode(NETCONF_DEFAULT_OPERATION_QNAME, null, modifyOperationToXmlString(defaultOperation.get()));
+            ret.add(defOp);
         }
-    }
 
-    private ImmutableCompositeNode getCommitRequest() {
-        final CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
-        commitInput.setQName(NETCONF_COMMIT_QNAME);
-        return commitInput.toInstance();
-    }
+        // Error option
+        if(rollbackSupported) {
+            ret.addLeaf(NETCONF_ERROR_OPTION_QNAME, ROLLBACK_ON_ERROR_OPTION);
+        }
 
-    @Override
-    public DataModification<InstanceIdentifier, CompositeNode> getModification() {
-        return this.modification;
+        ret.setQName(NETCONF_EDIT_CONFIG_QNAME);
+        // Edit content
+        ret.add(editStructure);
+        return ret.toInstance();
     }
 
-    @Override
-    public RpcResult<Void> rollback() throws IllegalStateException {
-        // TODO BUG-732 implement rollback by sending discard changes
-        return null;
+    private String modifyOperationToXmlString(final ModifyAction operation) {
+        return operation.name().toLowerCase();
     }
 
     public CompositeNode getTargetNode(final boolean candidateSupported) {
@@ -243,27 +298,15 @@ final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransact
         }
     }
 
-    private static final class RpcResultVoidWrapper implements RpcResult<Void> {
-
-        private final RpcResult<?> rpcResult;
-
-        public RpcResultVoidWrapper(final RpcResult<?> rpcResult) {
-            this.rpcResult = rpcResult;
-        }
-
-        @Override
-        public boolean isSuccessful() {
-            return rpcResult.isSuccessful();
-        }
+    private ImmutableCompositeNode getCommitRequest() {
+        final CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
+        commitInput.setQName(NETCONF_COMMIT_QNAME);
+        return commitInput.toInstance();
+    }
 
-        @Override
-        public Void getResult() {
-            return null;
-        }
 
-        @Override
-        public Collection<RpcError> getErrors() {
-            return rpcResult.getErrors();
-        }
+    @Override
+    public Object getIdentifier() {
+        return this;
     }
 }
index 8f9913d..16bbf9a 100644 (file)
@@ -259,7 +259,7 @@ public class ControllerContext implements SchemaContextListener {
         for (final PathArgument element : elements) {
             QName _nodeType = element.getNodeType();
             final DataSchemaNode potentialNode = ControllerContext.childByQName(node, _nodeType);
-            if (potentialNode == null || !this.isListOrContainer(potentialNode)) {
+            if (potentialNode == null || !ControllerContext.isListOrContainer(potentialNode)) {
                 return null;
             }
             node = (DataNodeContainer) potentialNode;
@@ -281,7 +281,7 @@ public class ControllerContext implements SchemaContextListener {
         for (final PathArgument element : elements) {
             QName _nodeType = element.getNodeType();
             final DataSchemaNode potentialNode = ControllerContext.childByQName(node, _nodeType);
-            if (!this.isListOrContainer(potentialNode)) {
+            if (!ControllerContext.isListOrContainer(potentialNode)) {
                 return null;
             }
             node = ((DataNodeContainer) potentialNode);
@@ -647,7 +647,7 @@ public class ControllerContext implements SchemaContextListener {
             targetNode = potentialSchemaNodes.iterator().next();
         }
 
-        if (!this.isListOrContainer(targetNode)) {
+        if (!ControllerContext.isListOrContainer(targetNode)) {
             throw new RestconfDocumentedException("URI has bad format. Node \"" + head
                     + "\" must be Container or List yang type.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE);
         }
index 2adf9b5..9aab841 100644 (file)
@@ -93,7 +93,7 @@ public class InvokeRpcMethodTest {
      * string - first argument).
      */
     @Test
-    public void invokeRpcMtethodTest() {
+    public void invokeRpcMethodTest() {
         ControllerContext contContext = controllerContext;
         try {
             contContext.findModuleNameByNamespace(new URI("invoke:rpc:module"));
index a2b8e0b..104bf4d 100644 (file)
@@ -45,6 +45,6 @@ public class SimpleIdentityRefAttributeWritingStrategy extends SimpleAttributeWr
         QName qName = QName.create(value);
         String identityValue = qName.getLocalName();
         String identityNamespace = qName.getNamespace().toString();
-        return XmlUtil.createTextElementWithNamespacedContent(doc, key, PREFIX, identityNamespace, identityValue);
+        return XmlUtil.createTextElementWithNamespacedContent(doc, key, PREFIX, identityNamespace, identityValue, namespace);
     }
 }
index 8780925..4e3a66b 100644 (file)
@@ -224,11 +224,17 @@ public final class XmlElement {
         });
     }
 
+    /**
+     *
+     * @param tagName tag name without prefix
+     * @return
+     */
     public List<XmlElement> getChildElements(final String tagName) {
         return getChildElementsInternal(new ElementFilteringStrategy() {
             @Override
             public boolean accept(Element e) {
-                return e.getTagName().equals(tagName);
+                // localName returns pure localName without prefix
+                return e.getLocalName().equals(tagName);
             }
         });
     }
index 01b1c8d..9e227ee 100644 (file)
@@ -124,8 +124,14 @@ public final class XmlUtil {
     public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
                                                                  String namespace, String contentWithoutPrefix) {
 
+       return createTextElementWithNamespacedContent(document, qName, prefix, namespace, contentWithoutPrefix, Optional.<String>absent());
+    }
+
+    public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
+                                                                 String namespace, String contentWithoutPrefix, Optional<String> namespaceURI) {
+
         String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
-        Element element = createTextElement(document, qName, content, Optional.<String>absent());
+        Element element = createTextElement(document, qName, content, namespaceURI);
         String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix);
         element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace);
         return element;