From: Ed Warnicke Date: Tue, 29 Jul 2014 11:30:00 +0000 (+0000) Subject: Merge "Implementation of ModuleShardStrategy" X-Git-Tag: release/helium~400 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=a6a97a57081df63432dde5a6b1613eb779b74d79;hp=d83a4d45f6ddbd66842a43dcb230f2c81af91696 Merge "Implementation of ModuleShardStrategy" --- diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java index 580a53be94..12b771df80 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyFactoryModule.java @@ -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 { diff --git a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java index b8849c7a1d..0b4a7baf6f 100644 --- a/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java +++ b/opendaylight/commons/protocol-framework/src/main/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyFactoryModule.java @@ -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()); } diff --git a/opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang b/opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang index 1856369178..cd84d4a95e 100644 --- a/opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang +++ b/opendaylight/commons/protocol-framework/src/main/yang/odl-protocol-framework-cfg.yang @@ -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; diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java index 9beadc4dbb..cfdf3bff28 100644 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java +++ b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/ReconnectImmediatelyStrategyModuleTest.java @@ -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; } diff --git a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java index a8cdff7119..1c068a98e7 100644 --- a/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java +++ b/opendaylight/commons/protocol-framework/src/test/java/org/opendaylight/controller/config/yang/protocol/framework/TimedReconnectStrategyModuleTest.java @@ -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; } diff --git a/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java index 0fd9720f79..864ebdf954 100644 --- a/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java +++ b/opendaylight/config/yang-jmx-generator-plugin/src/test/java/org/opendaylight/controller/config/yangjmxgenerator/plugin/JMXGeneratorTest.java @@ -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 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 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 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 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) { diff --git a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java index 518a11540e..e9f0ac8176 100644 --- a/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java +++ b/opendaylight/config/yang-jmx-generator/src/main/java/org/opendaylight/controller/config/yangjmxgenerator/ModuleMXBeanEntryBuilder.java @@ -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 extractDependency(final DataNodeContainer dataNodeContainer, final DataSchemaNode attrNode, final Module currentModule, final Map 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()) { diff --git a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang index e189ef7d66..a6d2feaf04 100644 --- a/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang +++ b/opendaylight/config/yang-jmx-generator/src/test/resources/test-config-threads-java.yang @@ -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" { diff --git a/opendaylight/distribution/opendaylight/pom.xml b/opendaylight/distribution/opendaylight/pom.xml index 3131bd5edd..541c1300f3 100644 --- a/opendaylight/distribution/opendaylight/pom.xml +++ b/opendaylight/distribution/opendaylight/pom.xml @@ -1317,11 +1317,11 @@ generate-resources - ${project.build.directory}/generated-resources/opendaylight/configuration - sal-rest-connector-config - **\/*.xml - true - false + ${project.build.directory}/configuration + sal-rest-connector-config + **\/*.xml + true + false diff --git a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml index 9534094fa8..03da7f0ccd 100644 --- a/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml +++ b/opendaylight/distribution/opendaylight/src/main/resources/configuration/initial/01-md-sal.xml @@ -86,10 +86,10 @@ prefix:inmemory-operational-datastore-provider operational-store-service - + dom:schema-service yang-schema-service - + + org.opendaylight.controller.sal.dom.broker.impl, org.opendaylight.controller.sal.dom.broker.impl.*, + + 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, diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java index 998d884b0c..34d231cf2a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java @@ -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); } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java index cdb78fc592..9dd180866a 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java @@ -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 mountPoints = new HashMap<>(); + private final Map mountPoints = new HashMap<>(); private final ListenerRegistry listeners = ListenerRegistry.create(); @Override public Optional getMountPoint(final InstanceIdentifier path) { - return Optional.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 listener : listeners + .getListeners()) { + listener.getInstance().onMountPointRemoved(identifier); + } + } + @Override public ListenerRegistration registerProvisionListener( final MountProvisionListener listener) { return listeners.register(listener); } - public ObjectRegistration registerMountPoint(final SimpleDOMMountPoint mountPoint) { + public ObjectRegistration 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 { + 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 index 0000000000..c2329ef4b0 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPoint.java @@ -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 readWrapper; + + private final InstanceIdentifier mountPath; + private final NotificationPublishService notificationPublishService; + private final RpcProvisionRegistry rpcs; + + private final ListenerRegistry 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 getServiceWithCheck(final DOMMountPoint mount, final Class type) { + final Optional 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 registerSchemaServiceListener(final SchemaServiceListener listener) { + return schemaListenerRegistry.register(listener); + } + + @Override + public void publish(final CompositeNode notification) { + notificationPublishService.publish(notification); + } + + @Override + public ListenerRegistration 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 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 reader) { + return dataReader.registerOperationalReader(path, reader); + } + + @Override + public Registration registerConfigurationReader( + final InstanceIdentifier path, final DataReader 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 getSupportedRpcs() { + return rpcs.getSupportedRpcs(); + } + + @Override + public ListenableFuture> invokeRpc(final QName rpc, final CompositeNode input) { + return rpcs.invokeRpc(rpc, input); + } + + @Override + public ListenerRegistration addRpcRegistrationListener(final RpcRegistrationListener listener) { + return rpcs.addRpcRegistrationListener(listener); + } + + @Override + public ListenableFuture> rpc(final QName type, final CompositeNode input) { + return rpcs.invokeRpc(type, input); + } + + @Override + public DataModificationTransaction beginTransaction() { + return dataReader.beginTransaction(); + } + + @Override + public ListenerRegistration registerDataChangeListener(final InstanceIdentifier path, + final DataChangeListener listener) { + return dataReader.registerDataChangeListener(path, listener); + } + + @Override + public Registration registerCommitHandler( + final InstanceIdentifier path, final DataCommitHandler 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 schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) { + schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext); + } + } + + class ReadWrapper implements DataReader { + private InstanceIdentifier shortenPath(final InstanceIdentifier path) { + InstanceIdentifier ret = null; + if(mountPath.contains(path)) { + final List 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>> registerCommitHandlerListener( + final RegistrationListener> commitHandlerListener) { + return dataReader.registerCommitHandlerListener(commitHandlerListener); + } + + @Override + public > ListenerRegistration 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 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>> 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> normalized = normalizer.toNormalized(path, rawData); + final Optional> normalizedNodeOptional = Optional.>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 submit() { + final ListenableFuture commitAsVoid = Futures.transform(commit(), new Function, Void>() { + @Override + public Void apply(@Nullable final RpcResult input) { + return null; + } + }); + + return Futures.makeChecked(commitAsVoid, new Function() { + @Override + public TransactionCommitFailedException apply(@Nullable final Exception input) { + return new TransactionCommitFailedException("Commit failed", input); + } + }); + } + + @Override + public ListenableFuture> 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>> 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 submit() { + return delegateWriteTx.submit(); + } + + @Override + public ListenableFuture> 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 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 index 0000000000..5c2a8e0725 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManager.java @@ -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 listeners = ListenerRegistry.create(); + private final ConcurrentMap 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 listener : listeners.getListeners()) { + listener.getInstance().onMountPointCreated(identifier); + } + } + + public void notifyMountRemoved(final InstanceIdentifier identifier) { + for (final ListenerRegistration 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 mount = domMountPointService.getMountPoint(path); + if(mount.isPresent()) { + return new BackwardsCompatibleMountPoint(path, mount.get()); + } else { + return null; + } + } + + @Override + public ListenerRegistration 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 index 0000000000..4c73e0b70a --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/DOMMountPointServiceProxy.java @@ -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 implements DOMMountPointService{ + + + public DOMMountPointServiceProxy(final ServiceReference ref, final DOMMountPointService delegate) { + super(ref, delegate); + } + + @Override + public Optional getMountPoint(final InstanceIdentifier path) { + return getDelegate().getMountPoint(path); + } + + @Override + public DOMMountPointBuilder createMountPoint(final InstanceIdentifier path) { + return getDelegate().createMountPoint(path); + } + + public ListenerRegistration registerProvisionListener(final MountProvisionListener listener) { + return getDelegate().registerProvisionListener(listener); + } +} diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java index c2d6add17a..2ce2bac862 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/ProxyFactory.java @@ -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) ref), service); } + private static Object _createProxyImpl(final ServiceReference ref, + final DOMMountPointService service) { + + return new DOMMountPointServiceProxy( + ((ServiceReference) 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 index 0000000000..311055f4b4 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/util/ProxySchemaContext.java @@ -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 getDataDefinitions() { + return getCurrentSchema().getDataDefinitions(); + } + + @Override + public Set getModules() { + return getCurrentSchema().getModules(); + } + + @Override + public Set getNotifications() { + return getCurrentSchema().getNotifications(); + } + + @Override + public Set getOperations() { + return getCurrentSchema().getOperations(); + } + + @Override + public Set getExtensions() { + return getCurrentSchema().getExtensions(); + } + + @Override + public Module findModuleByName(final String s, final Date date) { + return getCurrentSchema().findModuleByName(s, date); + } + + @Override + public Set 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 getModuleSource(final ModuleIdentifier moduleIdentifier) { + return getCurrentSchema().getModuleSource(moduleIdentifier); + } + + @Override + public Set getAllModuleIdentifiers() { + return getCurrentSchema().getAllModuleIdentifiers(); + } + + @Override + public boolean isPresenceContainer() { + return getCurrentSchema().isPresenceContainer(); + } + + @Override + public Set> getTypeDefinitions() { + return getCurrentSchema().getTypeDefinitions(); + } + + @Override + public Collection getChildNodes() { + return getCurrentSchema().getChildNodes(); + } + + @Override + public Set 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 getUses() { + return getCurrentSchema().getUses(); + } + + @Override + public Set 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 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 index 0000000000..3b11ed0566 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointManagerTest.java @@ -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 index 0000000000..5a36f710ff --- /dev/null +++ b/opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/sal/dom/broker/BackwardsCompatibleMountPointTest.java @@ -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>> 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>(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 diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java index 172b0dbc01..b39c9bbbd8 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/java/org/opendaylight/controller/config/yang/inmemory_datastore_provider/InMemoryOperationalDataStoreProviderModule.java @@ -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; } diff --git a/opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang b/opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang index 03220a3e5d..d4f57b53fe 100644 --- a/opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang +++ b/opendaylight/md-sal/sal-inmemory-datastore/src/main/yang/opendaylight-inmemory-datastore-provider.yang @@ -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; diff --git a/opendaylight/md-sal/sal-netconf-connector/pom.xml b/opendaylight/md-sal/sal-netconf-connector/pom.xml index 0bf4b3238d..10fe4a587a 100644 --- a/opendaylight/md-sal/sal-netconf-connector/pom.xml +++ b/opendaylight/md-sal/sal-netconf-connector/pom.xml @@ -13,7 +13,6 @@ - ${project.groupId} netconf-client ${netconf.version} @@ -62,6 +61,10 @@ org.opendaylight.controller.model model-inventory + + org.opendaylight.controller + sal-broker-impl + org.opendaylight.yangtools yang-data-impl @@ -161,12 +164,6 @@ test-jar test - - org.opendaylight.controller - sal-broker-impl - jar - test - org.opendaylight.yangtools mockito-configuration 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 index 26c6a2758c..0000000000 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceCommitHandler.java +++ /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 { - - 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 requestCommit( - final DataModification 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 { - 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 getModification() { - return twoPhaseCommit.getModification(); - } - - @Override - public RpcResult finish() throws IllegalStateException { - return RpcResultBuilder.failed().withError( RpcError.ErrorType.APPLICATION, - id + ": Unexpected operation error during pre-commit operations", e ).build(); - } - - @Override - public RpcResult 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 index 0000000000..53c057eaa3 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataBroker.java @@ -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 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 index 3535c96c80..0000000000 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDataReader.java +++ /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 { - - 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 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 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; - } -} diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java index e491496eed..04d5e5e449 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceDatastoreAdapter.java @@ -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 capabilities) { - submitDataChangeToExecutor(this.executor, new Runnable() { - @Override - public void run() { - updateDeviceStateInternal(up, capabilities); - } - }, id); - } - - private void updateDeviceStateInternal(final boolean up, final Set 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 path = id.getBindingPath(); + createNodesListIfNotPresent(transaction); + final InstanceIdentifier 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 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 result) { - return result.getResult() == TransactionStatus.COMMITED && result.isSuccessful(); + private void createNodesListIfNotPresent(final WriteTransaction writeTx) { + final Nodes nodes = new NodesBuilder().build(); + final InstanceIdentifier 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() { + private void commitTransaction(final WriteTransaction transaction, final String txType) { + logger.trace("{}: Committing Transaction {}:{}", id, txType, transaction.getIdentifier()); + final CheckedFuture result = transaction.submit(); + + Futures.addCallback(result, new FutureCallback() { @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 path) { - return null == transaction.readConfigurationData(path); - } - - private static boolean operationalNodeNotExisting(final DataModificationTransaction transaction, + private static ListenableFuture> readNodeData( + final LogicalDatastoreType store, + final ReadWriteTransaction transaction, final InstanceIdentifier path) { - return null == transaction.readOperationalData(path); + return transaction.read(store, path); } private static Node getNodeWithId(final RemoteDeviceId id) { diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java index 8d5b7aed2f..a0453bce55 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceRpc.java @@ -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> invokeRpc(final QName rpc, final CompositeNode input) { final NetconfMessage message = transformRequest(rpc, input); diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java index 37b87045d5..dbef290197 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalFacade.java @@ -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 { 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 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.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 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)) { diff --git a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalProvider.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalProvider.java index fc54bfbc3d..cf9174dd50 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalProvider.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceSalProvider.java @@ -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 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 index 0000000000..142ee4484b --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadOnlyTx.java @@ -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>> readConfigurationData(final InstanceIdentifier path) { + final ListenableFuture> future = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME, + NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path))); + + return Futures.transform(future, new Function, Optional>>() { + @Override + public Optional> apply(final RpcResult result) { + final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME); + final CompositeNode node = (CompositeNode) findNode(data, path); + + return data == null ? + Optional.>absent() : + transform(path, node); + } + }); + } + + private Optional> transform(final InstanceIdentifier path, final CompositeNode node) { + if(node == null) { + return Optional.absent(); + } + try { + return Optional.>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>> readOperationalData(final InstanceIdentifier path) { + final ListenableFuture> future = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path))); + + return Futures.transform(future, new Function, Optional>>() { + @Override + public Optional> apply(final RpcResult result) { + final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME); + final CompositeNode node = (CompositeNode) findNode(data, path); + + return data == null ? + Optional.>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>> 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 index 0000000000..9313ccbfb4 --- /dev/null +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceReadWriteTx.java @@ -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 submit() { + return delegateWriteTx.submit(); + } + + @Override + public ListenableFuture> commit() { + return delegateWriteTx.commit(); + } + + @Override + public ListenableFuture>> read(final LogicalDatastoreType store, final InstanceIdentifier path) { + return delegateReadTx.read(store, path); + } + + @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/NetconfDeviceTwoPhaseCommitTransaction.java b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java similarity index 51% rename from opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTwoPhaseCommitTransaction.java rename to opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java index 960f2ef2e8..43897aef84 100644 --- a/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/NetconfDeviceTwoPhaseCommitTransaction.java +++ b/opendaylight/md-sal/sal-netconf-connector/src/main/java/org/opendaylight/controller/sal/connect/netconf/sal/tx/NetconfDeviceWriteOnlyTx.java @@ -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 { +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 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 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 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.absent(), Optional.of(value)), Optional.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.absent()), Optional.of(ModifyAction.NONE)); + private boolean discardChanges() { + // TODO 732 + return true; } - private void sendEditRpc(final CompositeNode editStructure, final Optional defaultOperation) throws InterruptedException, ExecutionException { - final ImmutableCompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation); - final RpcResult 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 defaultOperation) { - final CompositeNodeBuilder 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.>of(targetNode)); - ret.add(targetWrapperNode); + try { + final InstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path); + final CompositeNode legacyData = normalizer.toLegacy(path, data); + sendEditRpc( + createEditConfigStructure(legacyPath, Optional. absent(), Optional.fromNullable(legacyData)), Optional. 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 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.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 submit() { + final ListenableFuture commmitFutureAsVoid = Futures.transform(commit(), new Function, Void>() { + @Nullable + @Override + public Void apply(@Nullable final RpcResult input) { + return null; + } + }); + + return Futures.makeChecked(commmitFutureAsVoid, new Function() { + @Override + public TransactionCommitFailedException apply(final Exception input) { + return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input); + } + }); + } + + @Override + public ListenableFuture> commit() { + // FIXME do not allow commit if closed or failed + + final ListenableFuture> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest()); + return Futures.transform(rpcResult, new Function, RpcResult>() { + @Override + public RpcResult apply(@Nullable final RpcResult input) { + if(input.isSuccessful()) { + return RpcResultBuilder.success(TransactionStatus.COMMITED).build(); + } else { + final RpcResultBuilder 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 defaultOperation) throws ExecutionException { + final CompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation); + final RpcResult 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 operation, - final Optional lastChildOverride) { + final Optional lastChildOverride) { Preconditions.checkArgument(Iterables.isEmpty(dataPath.getPathArguments()) == false, "Instance identifier with empty path %s", dataPath); - List reversedPath = Lists.reverse(dataPath.getPath()); + List 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 builder = ImmutableCompositeNode.builder(); builder.setQName(arg.getNodeType()); @@ -160,20 +227,20 @@ final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransact } private void addPredicatesToCompositeNodeBuilder(final Map predicates, final CompositeNodeBuilder builder) { - for (final Entry entry : predicates.entrySet()) { + for (final Map.Entry entry : predicates.entrySet()) { builder.addLeaf(entry.getKey(), entry.getValue()); } } - private Map getPredicates(final PathArgument arg) { + private Map getPredicates(final InstanceIdentifier.PathArgument arg) { Map 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 operation, final Optional lastChildOverride) { + private CompositeNode getDeepestEditElement(final InstanceIdentifier.PathArgument arg, final Optional operation, final Optional lastChildOverride) { final CompositeNodeBuilder 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 defaultOperation) { + final CompositeNodeBuilder ret = ImmutableCompositeNode.builder(); - /** - * Send commit rpc to finish the transaction - * In case of failure or unexpected error response, ExecutionException is thrown - */ - @Override - public RpcResult 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.failed().withError( RpcError.ErrorType.APPLICATION, - id + ": Unexpected operation error during commit operation", e ).build(); + // Target + final Node targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.>of(targetNode)); + ret.add(targetWrapperNode); + + // Default operation + if(defaultOperation.isPresent()) { + final SimpleNode defOp = NodeFactory.createImmutableSimpleNode(NETCONF_DEFAULT_OPERATION_QNAME, null, modifyOperationToXmlString(defaultOperation.get())); + ret.add(defOp); } - } - private ImmutableCompositeNode getCommitRequest() { - final CompositeNodeBuilder 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 getModification() { - return this.modification; + ret.setQName(NETCONF_EDIT_CONFIG_QNAME); + // Edit content + ret.add(editStructure); + return ret.toInstance(); } - @Override - public RpcResult 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 { - - private final RpcResult rpcResult; - - public RpcResultVoidWrapper(final RpcResult rpcResult) { - this.rpcResult = rpcResult; - } - - @Override - public boolean isSuccessful() { - return rpcResult.isSuccessful(); - } + private ImmutableCompositeNode getCommitRequest() { + final CompositeNodeBuilder commitInput = ImmutableCompositeNode.builder(); + commitInput.setQName(NETCONF_COMMIT_QNAME); + return commitInput.toInstance(); + } - @Override - public Void getResult() { - return null; - } - @Override - public Collection getErrors() { - return rpcResult.getErrors(); - } + @Override + public Object getIdentifier() { + return this; } } diff --git a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java index 8f9913d30d..16bbf9a4b1 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java +++ b/opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java @@ -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); } diff --git a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java index 2adf9b5530..9aab841546 100644 --- a/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java +++ b/opendaylight/md-sal/sal-rest-connector/src/test/java/org/opendaylight/controller/sal/restconf/impl/test/InvokeRpcMethodTest.java @@ -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")); diff --git a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java index a2b8e0bfdf..104bf4df94 100644 --- a/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java +++ b/opendaylight/netconf/config-netconf-connector/src/main/java/org/opendaylight/controller/netconf/confignetconfconnector/mapping/attributes/toxml/SimpleIdentityRefAttributeWritingStrategy.java @@ -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); } } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java index 8780925eb1..4e3a66b7ec 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlElement.java @@ -224,11 +224,17 @@ public final class XmlElement { }); } + /** + * + * @param tagName tag name without prefix + * @return + */ public List 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); } }); } diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java index 01b1c8d564..9e227ee05d 100644 --- a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java +++ b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/xml/XmlUtil.java @@ -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.absent()); + } + + public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix, + String namespace, String contentWithoutPrefix, Optional namespaceURI) { + String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix); - Element element = createTextElement(document, qName, content, Optional.absent()); + Element element = createTextElement(document, qName, content, namespaceURI); String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix); element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace); return element;