@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 {
@Override
public java.lang.AutoCloseable createInstance() {
- return new TimedReconnectStrategyFactoryCloseable(getExecutorDependency(),
+ return new TimedReconnectStrategyFactoryCloseable(getTimedReconnectExecutorDependency(),
getConnectTime(), getMinSleep(), getSleepFactor().doubleValue(), getMaxSleep(), getMaxAttempts(),
getDeadline());
}
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;
units "milliseconds";
}
- container executor {
+ container timed-reconnect-executor {
uses config:service-ref {
refine type {
mandatory true;
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);
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;
}
*/
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;
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";
mxBean.setMaxSleep(maxSleep);
mxBean.setMinSleep(minSleep);
mxBean.setSleepFactor(sleepFactor);
- mxBean.setExecutor(GlobalEventExecutorUtil.create(transaction));
+ mxBean.setTimedReconnectExecutor(GlobalEventExecutorUtil.create(transaction));
return nameCreated;
}
*/
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;
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 {
File generatedResourcesDir;
private static final List<String> expectedModuleFileNames = ServiceInterfaceEntryTest
- .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+ .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, FromGrouping.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, Peer.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
private static final List<String> expectedBGPNames = ServiceInterfaceEntryTest
.toFileNames("[AbstractBgpListenerImplModule.java, " + "AbstractBgpListenerImplModuleFactory.java, " +
"NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, " +
"NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java]");
private static final List<String> expectedAllFileNames = ServiceInterfaceEntryTest
- .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
+ .toFileNames("[AbstractAsyncEventBusModule.java, AbstractAsyncEventBusModuleFactory.java, AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, AbstractDynamicThreadPoolModule.java, AbstractDynamicThreadPoolModuleFactory.java, AbstractEventBusModule.java, AbstractEventBusModuleFactory.java, AbstractNamingThreadFactoryModule.java, AbstractNamingThreadFactoryModuleFactory.java, AbstractNetconfTestFileImplModule.java, AbstractNetconfTestFileImplModuleFactory.java, AbstractNetconfTestFiles1ImplModule.java, AbstractNetconfTestFiles1ImplModuleFactory.java, AbstractNetconfTestImplModule.java, AbstractNetconfTestImplModuleFactory.java, AbstractTestFileImplModule.java, AbstractTestFileImplModuleFactory.java, AbstractTestFiles1ImplModule.java, AbstractTestFiles1ImplModuleFactory.java, AbstractTestImplModule.java, AbstractTestImplModuleFactory.java, AbstractThreadPoolRegistryImplModule.java, AbstractThreadPoolRegistryImplModuleFactory.java, AsyncEventBusModule.java, AsyncEventBusModuleFactory.java, AsyncEventBusModuleMXBean.java, AsyncEventBusRuntimeMXBean.java, AsyncEventBusRuntimeRegistration.java, AsyncEventBusRuntimeRegistrator.java, AutoCloseableServiceInterface.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, ComplexDtoBInner.java, ComplexList.java, Deep.java, DtoA.java, DtoA.java, DtoA.java, DtoA1.java, DtoAInner.java, DtoAInnerInner.java, DtoB.java, DtoC.java, DynamicThreadPoolModule.java, DynamicThreadPoolModuleFactory.java, DynamicThreadPoolModuleMXBean.java, DynamicThreadPoolRuntimeMXBean.java, DynamicThreadPoolRuntimeRegistration.java, DynamicThreadPoolRuntimeRegistrator.java, EventBusModule.java, EventBusModuleFactory.java, EventBusModuleMXBean.java, EventBusServiceInterface.java, EventRuntimeMXBean.java, EventRuntimeRegistration.java, FromGrouping.java, InnerStreamList.java, NamingThreadFactoryModule.java, NamingThreadFactoryModuleFactory.java, NamingThreadFactoryModuleMXBean.java, NamingThreadFactoryRuntimeMXBean.java, NamingThreadFactoryRuntimeRegistration.java, NamingThreadFactoryRuntimeRegistrator.java, NetconfTestFileImplModule.java, NetconfTestFileImplModuleFactory.java, NetconfTestFileImplModuleMXBean.java, NetconfTestFileImplRuntimeMXBean.java, NetconfTestFileImplRuntimeRegistration.java, NetconfTestFileImplRuntimeRegistrator.java, NetconfTestFiles1ImplModule.java, NetconfTestFiles1ImplModuleFactory.java, NetconfTestFiles1ImplModuleMXBean.java, NetconfTestFiles1ImplRuntimeMXBean.java, NetconfTestFiles1ImplRuntimeRegistration.java, NetconfTestFiles1ImplRuntimeRegistrator.java, NetconfTestImplModule.java, NetconfTestImplModuleFactory.java, NetconfTestImplModuleMXBean.java, NetconfTestImplRuntimeMXBean.java, NetconfTestImplRuntimeRegistration.java, NetconfTestImplRuntimeRegistrator.java, Peer.java, Peer.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java, ScheduledThreadPoolServiceInterface.java, SimpleList.java, StreamRuntimeMXBean.java, StreamRuntimeRegistration.java, TestFileImplModule.java, TestFileImplModuleFactory.java, TestFileImplModuleMXBean.java, TestFileImplRuntimeMXBean.java, TestFileImplRuntimeRegistration.java, TestFileImplRuntimeRegistrator.java, TestFiles1ImplModule.java, TestFiles1ImplModuleFactory.java, TestFiles1ImplModuleMXBean.java, TestFiles1ImplRuntimeMXBean.java, TestFiles1ImplRuntimeRegistration.java, TestFiles1ImplRuntimeRegistrator.java, TestImplModule.java, TestImplModuleFactory.java, TestImplModuleMXBean.java, TestImplRuntimeMXBean.java, TestImplRuntimeRegistration.java, TestImplRuntimeRegistrator.java, ThreadFactoryServiceInterface.java, ThreadPoolRegistryImplModule.java, ThreadPoolRegistryImplModuleFactory.java, ThreadPoolRegistryImplModuleMXBean.java, ThreadPoolServiceInterface.java, ThreadRuntimeMXBean.java, ThreadRuntimeRegistration.java, ThreadStreamRuntimeMXBean.java, ThreadStreamRuntimeRegistration.java]");
private static final List<String> expectedGenerateMBEsListNames = ServiceInterfaceEntryTest
.toFileNames("[AbstractBgpListenerImplModule.java, AbstractBgpListenerImplModuleFactory.java, BgpListenerImplModule.java, BgpListenerImplModuleFactory.java, BgpListenerImplModuleMXBean.java, BgpListenerImplRuntimeMXBean.java, BgpListenerImplRuntimeRegistration.java, BgpListenerImplRuntimeRegistrator.java, PeersRuntimeMXBean.java, PeersRuntimeRegistration.java]");
+ ".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) {
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;
private Optional<? extends AbstractDependencyAttribute> extractDependency(final DataNodeContainer dataNodeContainer,
final DataSchemaNode attrNode, final Module currentModule, final Map<QName, ServiceInterfaceEntry> qNamesToSIEs,
final SchemaContext schemaContext) {
- if (dataNodeContainer.getUses().size() == 1 && getChildNodeSizeWithoutUses(dataNodeContainer) == 0) {
+ if (isDependencyContainer(dataNodeContainer)) {
// reference
UsesNode usesNode = dataNodeContainer.getUses().iterator().next();
checkState(usesNode.getRefines().size() == 1, "Unexpected 'refine' child node size of " + dataNodeContainer);
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()) {
}
}
+ 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'";
}
}
}
+
+ container from-grouping {
+ uses async-eventbus-config-attrs;
+ }
}
}
augment "/config:modules/config:module/config:state" {
</goals>
<phase>generate-resources</phase>
<configuration>
- <outputDirectory>${project.build.directory}/generated-resources/opendaylight/configuration</outputDirectory>
- <includeArtifactIds>sal-rest-connector-config</includeArtifactIds>
- <includes>**\/*.xml</includes>
- <excludeTransitive>true</excludeTransitive>
- <ignorePermissions>false</ignorePermissions>
+ <outputDirectory>${project.build.directory}/configuration</outputDirectory>
+ <includeArtifactIds>sal-rest-connector-config</includeArtifactIds>
+ <includes>**\/*.xml</includes>
+ <excludeTransitive>true</excludeTransitive>
+ <ignorePermissions>false</ignorePermissions>
</configuration>
</execution>
</executions>
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:inmemory-datastore-provider">prefix:inmemory-operational-datastore-provider</type>
<name>operational-store-service</name>
- <schema-service>
+ <operational-schema-service>
<type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
<name>yang-schema-service</name>
- </schema-service>
+ </operational-schema-service>
</module>
<!--
Tree-based in-memory data store. This is the data store which is currently
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.yangtools</groupId>
+ <artifactId>mockito-configuration</artifactId>
+ <scope>test</scope>
+ </dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<instructions>
<Bundle-Name>${project.groupId}.${project.artifactId}</Bundle-Name>
<Bundle-Activator>org.opendaylight.controller.sal.dom.broker.osgi.SchemaServiceActivator</Bundle-Activator>
- <Export-Package>org.opendaylight.controller.sal.dom.broker.spi</Export-Package>
- <Private-Package>org.opendaylight.controller.sal.dom.broker,
+ <Export-Package>org.opendaylight.controller.sal.dom.broker.spi,
+ <!--sal.broker.impl is exported for sal-netconf-connector to use SchemaAwareRpcRegistry.-->
+ <!-- TODO Remove sal.broker.impl from export when SchemaAwareRpcRegistry is not used in connector anymore -->
org.opendaylight.controller.sal.dom.broker.impl,
org.opendaylight.controller.sal.dom.broker.impl.*,
+ </Export-Package>
+ <Private-Package>org.opendaylight.controller.sal.dom.broker,
org.opendaylight.controller.sal.dom.broker.osgi,
org.opendaylight.controller.sal.dom.broker.util,
org.opendaylight.controller.config.yang.md.sal.dom.impl,
- org.opendaylight.controller.config.yang.md.sal.dom.statistics,
+ org.opendaylight.controller.config.yang.md.sal.dom.statistics,\
org.opendaylight.controller.md.sal.dom.broker.impl,
org.opendaylight.controller.md.sal.dom.broker.impl.*,
org.opendaylight.yangtools.yang.util,
*/
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;
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;
-
/**
*
*/
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);
}
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;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ClassToInstanceMap;
-import com.google.common.collect.MutableClassToInstanceMap;
-
public class DOMMountPointServiceImpl implements DOMMountPointService {
- private final Map<InstanceIdentifier, SimpleDOMMountPoint> mountPoints = new HashMap<>();
+ private final Map<InstanceIdentifier, DOMMountPoint> mountPoints = new HashMap<>();
private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
@Override
public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
- return Optional.<DOMMountPoint>fromNullable(mountPoints.get(path));
+ return Optional.fromNullable(mountPoints.get(path));
}
@Override
}
}
+ public void notifyMountRemoved(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners
+ .getListeners()) {
+ listener.getInstance().onMountPointRemoved(identifier);
+ }
+ }
+
@Override
public ListenerRegistration<MountProvisionListener> registerProvisionListener(
final MountProvisionListener listener) {
return listeners.register(listener);
}
- public ObjectRegistration<DOMMountPoint> registerMountPoint(final SimpleDOMMountPoint mountPoint) {
+ public ObjectRegistration<DOMMountPoint> registerMountPoint(final DOMMountPoint mountPoint) {
synchronized (mountPoints) {
Preconditions.checkState(!mountPoints.containsKey(mountPoint.getIdentifier()), "Mount point already exists");
mountPoints.put(mountPoint.getIdentifier(), mountPoint);
}
notifyMountCreated(mountPoint.getIdentifier());
- // FIXME this shouldnt be null
- return null;
+ return new MountRegistration(mountPoint);
+ }
+
+ public void unregisterMountPoint(final InstanceIdentifier mountPointId) {
+ synchronized (mountPoints) {
+ Preconditions.checkState(mountPoints.containsKey(mountPointId), "Mount point does not exist");
+ mountPoints.remove(mountPointId);
+ }
+ notifyMountRemoved(mountPointId);
}
public class DOMMountPointBuilderImpl implements DOMMountPointBuilder {
return registerMountPoint(mountPoint);
}
}
+
+ private final class MountRegistration implements ObjectRegistration<DOMMountPoint> {
+ private final DOMMountPoint mountPoint;
+
+ public MountRegistration(final DOMMountPoint mountPoint) {
+ this.mountPoint = mountPoint;
+ }
+
+ @Override
+ public DOMMountPoint getInstance() {
+ return mountPoint;
+ }
+
+ @Override
+ public void close() throws Exception {
+ unregisterMountPoint(mountPoint.getIdentifier());
+ }
+ }
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.JdkFutureAdapters;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
+import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.api.routing.RouteChangeListener;
+import org.opendaylight.controller.md.sal.common.impl.ListenerRegistry;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.md.sal.dom.api.DOMService;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.md.sal.dom.broker.impl.compat.BackwardsCompatibleDataBroker;
+import org.opendaylight.controller.sal.common.DataStoreIdentifier;
+import org.opendaylight.controller.sal.core.api.Broker.RoutedRpcRegistration;
+import org.opendaylight.controller.sal.core.api.Broker.RpcRegistration;
+import org.opendaylight.controller.sal.core.api.RoutedRpcDefaultImplementation;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.RpcRegistrationListener;
+import org.opendaylight.controller.sal.core.api.RpcRoutingContext;
+import org.opendaylight.controller.sal.core.api.data.DataChangeListener;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.core.api.data.DataValidator;
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.controller.sal.dom.broker.util.ProxySchemaContext;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.Registration;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaServiceListener;
+
+public class BackwardsCompatibleMountPoint implements MountProvisionInstance, SchemaContextProvider, SchemaService {
+
+ private final DataProviderService dataReader;
+ private final DataReader<InstanceIdentifier,CompositeNode> readWrapper;
+
+ private final InstanceIdentifier mountPath;
+ private final NotificationPublishService notificationPublishService;
+ private final RpcProvisionRegistry rpcs;
+
+ private final ListenerRegistry<SchemaServiceListener> schemaListenerRegistry = new ListenerRegistry<>();
+
+ private SchemaContext schemaContext;
+
+ public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPointService.DOMMountPointBuilder mountPointBuilder) {
+ this.mountPath = Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mountPointBuilder);
+
+ dataReader = new DataBrokerImpl();
+ readWrapper = new ReadWrapper();
+ notificationPublishService = new DelgatingNotificationPublishService();
+ rpcs = new SchemaAwareRpcBroker(path.toString(), this);
+
+ mountPointBuilder.addService(DOMDataBroker.class, new BackwardsCompatibleDomStore(dataReader, this));
+ mountPointBuilder.addService(NotificationPublishService.class, notificationPublishService);
+ mountPointBuilder.addService(RpcProvisionRegistry.class, rpcs);
+
+ mountPointBuilder.addInitialSchemaContext(new ProxySchemaContext(this));
+
+ mountPointBuilder.register();
+ }
+
+ public BackwardsCompatibleMountPoint(final InstanceIdentifier path, final DOMMountPoint mount) {
+ this.mountPath = Preconditions.checkNotNull(path);
+ Preconditions.checkNotNull(mount);
+
+ final DOMDataBroker domBroker = getServiceWithCheck(mount, DOMDataBroker.class);
+
+ this.schemaContext = mount.getSchemaContext();
+
+ dataReader = new BackwardsCompatibleDataBroker(domBroker, this);
+
+ // Set schema context to provide it for BackwardsCompatibleDataBroker
+ if(schemaContext != null) {
+ setSchemaContext(schemaContext);
+ }
+
+ readWrapper = new ReadWrapper();
+
+ notificationPublishService = getServiceWithCheck(mount, NotificationPublishService.class);
+ rpcs = getServiceWithCheck(mount, RpcProvisionRegistry.class);
+ }
+
+ private <T extends DOMService> T getServiceWithCheck(final DOMMountPoint mount, final Class<T> type) {
+ final Optional<T> serviceOptional = mount.getService(type);
+ Preconditions.checkArgument(serviceOptional.isPresent(), "Service {} has to be set in {}. " +
+ "Cannot construct backwards compatible mount wrapper without it", type, mount);
+ return serviceOptional.get();
+ }
+
+ @Override
+ public void addModule(final Module module) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeModule(final Module module) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SchemaContext getSessionContext() {
+ return getSchemaContext();
+ }
+
+ @Override
+ public SchemaContext getGlobalContext() {
+ return getSchemaContext();
+ }
+
+ @Override
+ public ListenerRegistration<SchemaServiceListener> registerSchemaServiceListener(final SchemaServiceListener listener) {
+ return schemaListenerRegistry.register(listener);
+ }
+
+ @Override
+ public void publish(final CompositeNode notification) {
+ notificationPublishService.publish(notification);
+ }
+
+ @Override
+ public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+ return notificationPublishService.addNotificationListener(notification, listener);
+ }
+
+ // TODO Read wrapper is never used ... same in org.opendaylight.controller.sal.dom.broker.MountPointImpl
+ public DataReader<InstanceIdentifier, CompositeNode> getReadWrapper() {
+ return readWrapper;
+ }
+
+ @Override
+ public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+ return dataReader.readConfigurationData(path);
+ }
+
+ @Override
+ public CompositeNode readOperationalData(final InstanceIdentifier path) {
+ return dataReader.readOperationalData(path);
+ }
+
+ @Override
+ public Registration registerOperationalReader(
+ final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return dataReader.registerOperationalReader(path, reader);
+ }
+
+ @Override
+ public Registration registerConfigurationReader(
+ final InstanceIdentifier path, final DataReader<InstanceIdentifier, CompositeNode> reader) {
+ return dataReader.registerConfigurationReader(path, reader);
+ }
+
+ @Override
+ public RoutedRpcRegistration addRoutedRpcImplementation(final QName rpcType, final RpcImplementation implementation) {
+ return rpcs.addRoutedRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public void setRoutedRpcDefaultDelegate(final RoutedRpcDefaultImplementation defaultImplementation) {
+ rpcs.setRoutedRpcDefaultDelegate(defaultImplementation);
+ }
+
+ @Override
+ public RpcRegistration addRpcImplementation(final QName rpcType, final RpcImplementation implementation)
+ throws IllegalArgumentException {
+ return rpcs.addRpcImplementation(rpcType, implementation);
+ }
+
+ @Override
+ public Set<QName> getSupportedRpcs() {
+ return rpcs.getSupportedRpcs();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
+ return rpcs.invokeRpc(rpc, input);
+ }
+
+ @Override
+ public ListenerRegistration<RpcRegistrationListener> addRpcRegistrationListener(final RpcRegistrationListener listener) {
+ return rpcs.addRpcRegistrationListener(listener);
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<CompositeNode>> rpc(final QName type, final CompositeNode input) {
+ return rpcs.invokeRpc(type, input);
+ }
+
+ @Override
+ public DataModificationTransaction beginTransaction() {
+ return dataReader.beginTransaction();
+ }
+
+ @Override
+ public ListenerRegistration<DataChangeListener> registerDataChangeListener(final InstanceIdentifier path,
+ final DataChangeListener listener) {
+ return dataReader.registerDataChangeListener(path, listener);
+ }
+
+ @Override
+ public Registration registerCommitHandler(
+ final InstanceIdentifier path, final DataCommitHandler<InstanceIdentifier, CompositeNode> commitHandler) {
+ return dataReader.registerCommitHandler(path, commitHandler);
+ }
+
+ @Override
+ public void removeRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+ // NOOP
+ }
+
+ @Override
+ public void addRefresher(final DataStoreIdentifier store, final DataRefresher refresher) {
+ // NOOP
+ }
+
+ @Override
+ public void addValidator(final DataStoreIdentifier store, final DataValidator validator) {
+ // NOOP
+ }
+ @Override
+ public void removeValidator(final DataStoreIdentifier store, final DataValidator validator) {
+ // NOOP
+ }
+
+ @Override
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+
+ @Override
+ public void setSchemaContext(final SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ for (ListenerRegistration<SchemaServiceListener> schemaServiceListenerListenerRegistration : schemaListenerRegistry.getListeners()) {
+ schemaServiceListenerListenerRegistration.getInstance().onGlobalContextUpdated(schemaContext);
+ }
+ }
+
+ class ReadWrapper implements DataReader<InstanceIdentifier, CompositeNode> {
+ private InstanceIdentifier shortenPath(final InstanceIdentifier path) {
+ InstanceIdentifier ret = null;
+ if(mountPath.contains(path)) {
+ final List<PathArgument> newArgs = path.getPath().subList(mountPath.getPath().size(), path.getPath().size());
+ ret = InstanceIdentifier.create(newArgs);
+ }
+ return ret;
+ }
+
+ @Override
+ public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+ final InstanceIdentifier newPath = shortenPath(path);
+ if(newPath == null) {
+ return null;
+ }
+ return BackwardsCompatibleMountPoint.this.readConfigurationData(newPath);
+ }
+
+ @Override
+ public CompositeNode readOperationalData(final InstanceIdentifier path) {
+ final InstanceIdentifier newPath = shortenPath(path);
+ if(newPath == null) {
+ return null;
+ }
+ return BackwardsCompatibleMountPoint.this.readOperationalData(newPath);
+ }
+ }
+
+ @Override
+ public ListenerRegistration<RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>>> registerCommitHandlerListener(
+ final RegistrationListener<DataCommitHandlerRegistration<InstanceIdentifier, CompositeNode>> commitHandlerListener) {
+ return dataReader.registerCommitHandlerListener(commitHandlerListener);
+ }
+
+ @Override
+ public <L extends RouteChangeListener<RpcRoutingContext, InstanceIdentifier>> ListenerRegistration<L> registerRouteChangeListener(
+ final L listener) {
+ return rpcs.registerRouteChangeListener(listener);
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleDomStore implements DOMDataBroker {
+ private final DataProviderService dataReader;
+ private final SchemaContextProvider schemaContextProvider;
+
+ public BackwardsCompatibleDomStore(final DataProviderService dataReader, final SchemaContextProvider schemaContextProvider) {
+ this.dataReader = dataReader;
+ this.schemaContextProvider = schemaContextProvider;
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+ throw new UnsupportedOperationException("Register data listener not supported for mount point");
+ }
+
+ @Override
+ public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+ throw new UnsupportedOperationException("Transaction chain not supported for mount point");
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ final DataNormalizer dataNormalizer = new DataNormalizer(schemaContextProvider.getSchemaContext());
+ return new BackwardsCompatibleReadWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleReadTransaction implements DOMDataReadOnlyTransaction {
+ private final DataProviderService dataReader;
+ private final DataNormalizer normalizer;
+
+ public BackwardsCompatibleReadTransaction(final DataProviderService dataReader, final DataNormalizer normalizer) {
+ this.dataReader = dataReader;
+ this.normalizer = normalizer;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+
+ CompositeNode rawData = null;
+
+ switch (store) {
+ case CONFIGURATION: {
+ rawData = dataReader.readConfigurationData(path);
+ break;
+ }
+ case OPERATIONAL: {
+ rawData = dataReader.readOperationalData(path);
+ break;
+ }
+ }
+ Preconditions.checkNotNull(rawData, "Unable to read %s data on path %s", store, path);
+
+ final Map.Entry<InstanceIdentifier, NormalizedNode<?, ?>> normalized = normalizer.toNormalized(path, rawData);
+ final Optional<NormalizedNode<?, ?>> normalizedNodeOptional = Optional.<NormalizedNode<?, ?>>fromNullable(normalized.getValue());
+ return com.google.common.util.concurrent.Futures.immediateFuture(normalizedNodeOptional);
+ }
+ }
+
+ @VisibleForTesting
+ static final class BackwardsCompatibleWriteTransaction implements DOMDataWriteTransaction {
+ private DataModificationTransaction oldTx;
+ private final DataNormalizer dataNormalizer;
+
+ public BackwardsCompatibleWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+ this.oldTx = dataReader.beginTransaction();
+ this.dataNormalizer = dataNormalizer;
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public boolean cancel() {
+ oldTx = null;
+ return true;
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ final CompositeNode legacyData = dataNormalizer.toLegacy(path, data);
+ try {
+ final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+ switch (store) {
+ case CONFIGURATION: {
+ oldTx.putConfigurationData(legacyPath, legacyData);
+ return;
+ }
+ }
+
+ throw new IllegalArgumentException("Cannot put data " + path + " to datastore " + store);
+ } catch (final DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+ }
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ // TODO not supported
+ throw new UnsupportedOperationException("Merge not supported for mount point");
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ try {
+ final InstanceIdentifier legacyPath = dataNormalizer.toLegacy(path);
+
+ switch (store) {
+ case CONFIGURATION: {
+ oldTx.removeConfigurationData(legacyPath);
+ return;
+ }
+ }
+ throw new IllegalArgumentException("Cannot delete data " + path + " from datastore " + store);
+ } catch (final DataNormalizationException e) {
+ throw new IllegalArgumentException(String.format("Cannot transform path %s to legacy format", path), e);
+ }
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ final ListenableFuture<Void> commitAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ @Override
+ public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+ return null;
+ }
+ });
+
+ return Futures.makeChecked(commitAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ @Override
+ public TransactionCommitFailedException apply(@Nullable final Exception input) {
+ return new TransactionCommitFailedException("Commit failed", input);
+ }
+ });
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return JdkFutureAdapters.listenInPoolThread(oldTx.commit());
+ }
+ }
+
+
+ @VisibleForTesting
+ static class BackwardsCompatibleReadWriteTransaction implements DOMDataReadWriteTransaction {
+
+ private final DataProviderService dataReader;
+ private final DataNormalizer dataNormalizer;
+ private final BackwardsCompatibleWriteTransaction delegateWriteTx;
+
+ public BackwardsCompatibleReadWriteTransaction(final DataProviderService dataReader, final DataNormalizer dataNormalizer) {
+ this.dataReader = dataReader;
+ this.dataNormalizer = dataNormalizer;
+ this.delegateWriteTx = new BackwardsCompatibleWriteTransaction(dataReader, dataNormalizer);
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ return new BackwardsCompatibleReadTransaction(dataReader, dataNormalizer).read(store, path);
+ }
+
+ @Override
+ public boolean cancel() {
+ return delegateWriteTx.cancel();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.put(store, path, data);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.merge(store, path, data);
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ delegateWriteTx.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ return delegateWriteTx.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return delegateWriteTx.commit();
+ }
+ }
+ }
+
+ private class DelgatingNotificationPublishService implements NotificationPublishService {
+ private final NotificationRouter notificationRouter;
+
+ public DelgatingNotificationPublishService(final NotificationRouter notificationRouter) {
+ this.notificationRouter = notificationRouter;
+ }
+
+ private DelgatingNotificationPublishService() {
+ this(new NotificationRouterImpl());
+ }
+
+ @Override
+ public void publish(final CompositeNode notification) {
+ notificationRouter.publish(notification);
+ }
+
+ @Override
+ public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+ return notificationRouter.addNotificationListener(notification, listener);
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker;
+
+import static com.google.common.base.Preconditions.checkState;
+
+import com.google.common.base.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.util.ListenerRegistry;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class BackwardsCompatibleMountPointManager implements MountProvisionService, MountProvisionListener {
+
+ private final ListenerRegistry<MountProvisionListener> listeners = ListenerRegistry.create();
+ private final ConcurrentMap<InstanceIdentifier, MountProvisionInstance> mounts = new ConcurrentHashMap<>();
+
+ private final DOMMountPointService domMountPointService;
+
+ public BackwardsCompatibleMountPointManager(final DOMMountPointService domMountPointService) {
+ this.domMountPointService = domMountPointService;
+ }
+
+ @Override
+ public MountProvisionInstance createMountPoint(final InstanceIdentifier path) {
+ checkState(!mounts.containsKey(path), "Mount already created");
+ // Create mount point instance, wrap instance of new API with BackwardsCompatibleMountPoint to preserve backwards comatibility
+ final BackwardsCompatibleMountPoint mount = new BackwardsCompatibleMountPoint(path, domMountPointService.createMountPoint(path));
+ mounts.put(path, mount);
+ return mount;
+ }
+
+ public void notifyMountCreated(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+ listener.getInstance().onMountPointCreated(identifier);
+ }
+ }
+
+ public void notifyMountRemoved(final InstanceIdentifier identifier) {
+ for (final ListenerRegistration<MountProvisionListener> listener : listeners.getListeners()) {
+ listener.getInstance().onMountPointRemoved(identifier);
+ }
+ }
+
+ @Override
+ public MountProvisionInstance createOrGetMountPoint(
+ final InstanceIdentifier path) {
+ final MountProvisionInstance mount = getMountPoint(path);
+ if (mount == null) {
+ return createMountPoint(path);
+ }
+ return mount;
+ }
+
+ @Override
+ public MountProvisionInstance getMountPoint(final InstanceIdentifier path) {
+ // If the mount point was created here, return directly
+ if(mounts.containsKey(path)) {
+ return mounts.get(path);
+ }
+
+ // If mount was created in underlying DOMMountService, wrap as MountProvisionInstance
+ final Optional<DOMMountPoint> mount = domMountPointService.getMountPoint(path);
+ if(mount.isPresent()) {
+ return new BackwardsCompatibleMountPoint(path, mount.get());
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(
+ final MountProvisionListener listener) {
+ return domMountPointService.registerProvisionListener(listener);
+ }
+
+ @Override
+ public void onMountPointCreated(final InstanceIdentifier path) {
+ notifyMountCreated(path);
+ }
+
+ @Override
+ public void onMountPointRemoved(final InstanceIdentifier path) {
+ notifyMountRemoved(path);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.dom.broker.osgi;
+
+import com.google.common.base.Optional;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint;
+import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.osgi.framework.ServiceReference;
+
+public class DOMMountPointServiceProxy extends AbstractBrokerServiceProxy<DOMMountPointService> implements DOMMountPointService{
+
+
+ public DOMMountPointServiceProxy(final ServiceReference<DOMMountPointService> ref, final DOMMountPointService delegate) {
+ super(ref, delegate);
+ }
+
+ @Override
+ public Optional<DOMMountPoint> getMountPoint(final InstanceIdentifier path) {
+ return getDelegate().getMountPoint(path);
+ }
+
+ @Override
+ public DOMMountPointBuilder createMountPoint(final InstanceIdentifier path) {
+ return getDelegate().createMountPoint(path);
+ }
+
+ public ListenerRegistration<MountProvisionListener> registerProvisionListener(final MountProvisionListener listener) {
+ return getDelegate().registerProvisionListener(listener);
+ }
+}
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;
((ServiceReference<MountProvisionService>) ref), service);
}
+ private static Object _createProxyImpl(final ServiceReference<?> ref,
+ final DOMMountPointService service) {
+
+ return new DOMMountPointServiceProxy(
+ ((ServiceReference<DOMMountPointService>) ref), service);
+ }
+
private static Object _createProxyImpl(final ServiceReference<?> ref,
final SchemaService service) {
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 {
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker.util;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
+import org.opendaylight.yangtools.yang.model.api.ConstraintDefinition;
+import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.ExtensionDefinition;
+import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.ModuleIdentifier;
+import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
+import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.model.api.SchemaPath;
+import org.opendaylight.yangtools.yang.model.api.Status;
+import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
+import org.opendaylight.yangtools.yang.model.api.UsesNode;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+
+/**
+ * ProxySchema Context for SchemaContextProviders
+ */
+public class ProxySchemaContext implements SchemaContext {
+
+ private final SchemaContextProvider schemaProvider;
+
+ public ProxySchemaContext(final SchemaContextProvider schemaProvider) {
+ this.schemaProvider = schemaProvider;
+ }
+
+ private SchemaContext getCurrentSchema() {
+ Preconditions.checkState(schemaProvider.getSchemaContext() != null, "Schema context unavailable from %s", schemaProvider);
+ return schemaProvider.getSchemaContext();
+ }
+
+ @Override
+ public Set<DataSchemaNode> getDataDefinitions() {
+ return getCurrentSchema().getDataDefinitions();
+ }
+
+ @Override
+ public Set<Module> getModules() {
+ return getCurrentSchema().getModules();
+ }
+
+ @Override
+ public Set<NotificationDefinition> getNotifications() {
+ return getCurrentSchema().getNotifications();
+ }
+
+ @Override
+ public Set<RpcDefinition> getOperations() {
+ return getCurrentSchema().getOperations();
+ }
+
+ @Override
+ public Set<ExtensionDefinition> getExtensions() {
+ return getCurrentSchema().getExtensions();
+ }
+
+ @Override
+ public Module findModuleByName(final String s, final Date date) {
+ return getCurrentSchema().findModuleByName(s, date);
+ }
+
+ @Override
+ public Set<Module> findModuleByNamespace(final URI uri) {
+ return getCurrentSchema().findModuleByNamespace(uri);
+ }
+
+ @Override
+ public Module findModuleByNamespaceAndRevision(final URI uri, final Date date) {
+ return getCurrentSchema().findModuleByNamespaceAndRevision(uri, date);
+ }
+
+ @Override
+ public Optional<String> getModuleSource(final ModuleIdentifier moduleIdentifier) {
+ return getCurrentSchema().getModuleSource(moduleIdentifier);
+ }
+
+ @Override
+ public Set<ModuleIdentifier> getAllModuleIdentifiers() {
+ return getCurrentSchema().getAllModuleIdentifiers();
+ }
+
+ @Override
+ public boolean isPresenceContainer() {
+ return getCurrentSchema().isPresenceContainer();
+ }
+
+ @Override
+ public Set<TypeDefinition<?>> getTypeDefinitions() {
+ return getCurrentSchema().getTypeDefinitions();
+ }
+
+ @Override
+ public Collection<DataSchemaNode> getChildNodes() {
+ return getCurrentSchema().getChildNodes();
+ }
+
+ @Override
+ public Set<GroupingDefinition> getGroupings() {
+ return getCurrentSchema().getGroupings();
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final QName qName) {
+ return getCurrentSchema().getDataChildByName(qName);
+ }
+
+ @Override
+ public DataSchemaNode getDataChildByName(final String s) {
+ return getCurrentSchema().getDataChildByName(s);
+ }
+
+ @Override
+ public Set<UsesNode> getUses() {
+ return getCurrentSchema().getUses();
+ }
+
+ @Override
+ public Set<AugmentationSchema> getAvailableAugmentations() {
+ return getCurrentSchema().getAvailableAugmentations();
+ }
+
+ @Override
+ public boolean isAugmenting() {
+ return getCurrentSchema().isAugmenting();
+ }
+
+ @Override
+ public boolean isAddedByUses() {
+ return getCurrentSchema().isAddedByUses();
+ }
+
+ @Override
+ public boolean isConfiguration() {
+ return getCurrentSchema().isConfiguration();
+ }
+
+ @Override
+ public ConstraintDefinition getConstraints() {
+ return getCurrentSchema().getConstraints();
+ }
+
+ @Override
+ public QName getQName() {
+ return getCurrentSchema().getQName();
+ }
+
+ @Override
+ public SchemaPath getPath() {
+ return getCurrentSchema().getPath();
+ }
+
+ @Override
+ public List<UnknownSchemaNode> getUnknownSchemaNodes() {
+ return getCurrentSchema().getUnknownSchemaNodes();
+ }
+
+ @Override
+ public String getDescription() {
+ return getCurrentSchema().getDescription();
+ }
+
+ @Override
+ public String getReference() {
+ return getCurrentSchema().getReference();
+ }
+
+ @Override
+ public Status getStatus() {
+ return getCurrentSchema().getStatus();
+ }
+}
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.dom.broker;
+
+import static junit.framework.Assert.fail;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import java.util.AbstractMap;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
+import org.opendaylight.controller.sal.core.api.data.DataProviderService;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BackwardsCompatibleMountPointTest {
+ private static final Logger log = LoggerFactory.getLogger(BackwardsCompatibleMountPointManagerTest.class);
+
+ private static final InstanceIdentifier id = BackwardsCompatibleMountPointManagerTest.id;
+ private final NormalizedNode<?, ?> normalizedNode = mockNormalizedNode();
+ private final CompositeNode compositeNode = mockCompositeNode();
+
+ @Mock
+ private DataProviderService oldBroker;
+ @Mock
+ private SchemaContextProvider schemaContextProvider;
+ @Mock
+ private DataModificationTransaction mockTx;
+
+ private BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore backwardsCompatibleDomStore;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ stubSchemaProvider();
+ stubOldBroker();
+ backwardsCompatibleDomStore = new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore(oldBroker, schemaContextProvider);
+ }
+
+ private void stubOldBroker() {
+ doReturn(compositeNode).when(oldBroker).readConfigurationData(id);
+ doReturn(compositeNode).when(oldBroker).readOperationalData(id);
+ doReturn(mockTx).when(oldBroker).beginTransaction();
+ doNothing().when(mockTx).putConfigurationData(id, compositeNode);
+ doNothing().when(mockTx).putOperationalData(id, compositeNode);
+ doReturn(com.google.common.util.concurrent.Futures.immediateFuture(RpcResultBuilder.success(TransactionStatus.COMMITED))).when(mockTx).commit();
+ }
+
+ private CompositeNode mockCompositeNode() {
+ final CompositeNode mock = mock(CompositeNode.class);
+ doReturn("node").when(mock).toString();
+ return mock;
+ }
+
+ private void stubSchemaProvider() {
+ doReturn(BackwardsCompatibleMountPointManagerTest.mockSchemaContext()).when(schemaContextProvider).getSchemaContext();
+ }
+
+ @Test
+ public void testBackwardsCompatibleBroker() throws Exception {
+ backwardsCompatibleDomStore.newReadOnlyTransaction();
+ backwardsCompatibleDomStore.newWriteOnlyTransaction();
+ backwardsCompatibleDomStore.newReadWriteTransaction();
+ }
+
+ @Test
+ public void testReadTransaction() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleReadTransaction(oldBroker, mockNormalizer());
+
+ ListenableFuture<Optional<NormalizedNode<?, ?>>> read = tx.read(LogicalDatastoreType.CONFIGURATION, id);
+ assertEquals(normalizedNode, read.get().get());
+ verify(oldBroker).readConfigurationData(id);
+
+ read = tx.read(LogicalDatastoreType.OPERATIONAL, id);
+ assertEquals(normalizedNode, read.get().get());
+
+ verify(oldBroker).readOperationalData(id);
+ }
+
+ @Test
+ public void testReadWriteTransactionOperational() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+ verify(oldBroker).beginTransaction();
+
+ tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+ verify(mockTx).putConfigurationData(id, compositeNode);
+
+ tx.put(LogicalDatastoreType.CONFIGURATION, id, normalizedNode);
+ verify(mockTx, times(2)).putConfigurationData(id, compositeNode);
+
+ tx.commit();
+ verify(mockTx).commit();
+ }
+
+
+ @Test
+ public void testCannotPutOperational() throws Exception {
+ final BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction tx =
+ new BackwardsCompatibleMountPoint.BackwardsCompatibleDomStore.BackwardsCompatibleWriteTransaction(oldBroker, mockNormalizer());
+
+ try {
+ tx.put(LogicalDatastoreType.OPERATIONAL, id, normalizedNode);
+ } catch (IllegalArgumentException e) {
+ // Cannot put operational data
+ log.debug("", e);
+ return;
+ }
+
+ fail("Should fail when putting operational data");
+ }
+
+ private DataNormalizer mockNormalizer() throws DataNormalizationException {
+ final DataNormalizer mock = mock(DataNormalizer.class);
+ doReturn(new AbstractMap.SimpleEntry<InstanceIdentifier, NormalizedNode<?, ?>>(id, normalizedNode) {})
+ .when(mock).toNormalized(any(InstanceIdentifier.class), any(CompositeNode.class));
+ doReturn(compositeNode).when(mock).toLegacy(any(InstanceIdentifier.class), any(NormalizedNode.class));
+ doReturn(id).when(mock).toLegacy(any(InstanceIdentifier.class));
+ return mock;
+ }
+
+ private NormalizedNode<?, ?> mockNormalizedNode() {
+ final NormalizedNode mock = mock(NormalizedNode.class);
+ doReturn("mockNormalizedNode").when(mock).toString();
+ return mock;
+ }
+}
\ No newline at end of file
@Override
public java.lang.AutoCloseable createInstance() {
InMemoryDOMDataStore ids = new InMemoryDOMDataStore("DOM-OPER", MoreExecutors.listeningDecorator(Executors.newSingleThreadExecutor()));
- getSchemaServiceDependency().registerSchemaServiceListener(ids);
+ getOperationalSchemaServiceDependency().registerSchemaServiceListener(ids);
return ids;
}
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;
<dependencies>
<dependency>
-
<groupId>${project.groupId}</groupId>
<artifactId>netconf-client</artifactId>
<version>${netconf.version}</version>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>yang-data-impl</artifactId>
<type>test-jar</type>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-broker-impl</artifactId>
- <type>jar</type>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<artifactId>mockito-configuration</artifactId>
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connect.netconf.sal;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler;
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.RpcError;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public final class NetconfDeviceCommitHandler implements DataCommitHandler<InstanceIdentifier,CompositeNode> {
-
- private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceCommitHandler.class);
-
- private final RemoteDeviceId id;
- private final RpcImplementation rpc;
- private final boolean rollbackSupported;
-
- public NetconfDeviceCommitHandler(final RemoteDeviceId id, final RpcImplementation rpc, final boolean rollbackSupported) {
- this.id = id;
- this.rpc = rpc;
- this.rollbackSupported = rollbackSupported;
- }
-
- @Override
- public DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
- final DataModification<InstanceIdentifier, CompositeNode> modification) {
-
- final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit = new NetconfDeviceTwoPhaseCommitTransaction(id, rpc,
- modification, true, rollbackSupported);
- try {
- twoPhaseCommit.prepare();
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(id + ": Interrupted while waiting for response", e);
- } catch (final ExecutionException e) {
- logger.warn("{}: Error executing pre commit operation on remote device", id, e);
- return new FailingTransaction(twoPhaseCommit, e);
- }
-
- return twoPhaseCommit;
- }
-
- /**
- * Always fail commit transaction that rolls back delegate transaction afterwards
- */
- private class FailingTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
- private final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit;
- private final ExecutionException e;
-
- public FailingTransaction(final NetconfDeviceTwoPhaseCommitTransaction twoPhaseCommit, final ExecutionException e) {
- this.twoPhaseCommit = twoPhaseCommit;
- this.e = e;
- }
-
- @Override
- public DataModification<InstanceIdentifier, CompositeNode> getModification() {
- return twoPhaseCommit.getModification();
- }
-
- @Override
- public RpcResult<Void> finish() throws IllegalStateException {
- return RpcResultBuilder.<Void>failed().withError( RpcError.ErrorType.APPLICATION,
- id + ": Unexpected operation error during pre-commit operations", e ).build();
- }
-
- @Override
- public RpcResult<Void> rollback() throws IllegalStateException {
- return twoPhaseCommit.rollback();
- }
- }
-}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.connect.netconf.sal;
+
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
+import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceReadOnlyTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceReadWriteTx;
+import org.opendaylight.controller.sal.connect.netconf.sal.tx.NetconfDeviceWriteOnlyTx;
+import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+final class NetconfDeviceDataBroker implements DOMDataBroker {
+ private final RemoteDeviceId id;
+ private final RpcImplementation rpc;
+ private final NetconfSessionCapabilities netconfSessionPreferences;
+ private final DataNormalizer normalizer;
+
+ public NetconfDeviceDataBroker(final RemoteDeviceId id, final RpcImplementation rpc, final SchemaContext schemaContext, NetconfSessionCapabilities netconfSessionPreferences) {
+ this.id = id;
+ this.rpc = rpc;
+ this.netconfSessionPreferences = netconfSessionPreferences;
+ normalizer = new DataNormalizer(schemaContext);
+ }
+
+ @Override
+ public DOMDataReadOnlyTransaction newReadOnlyTransaction() {
+ return new NetconfDeviceReadOnlyTx(rpc, normalizer);
+ }
+
+ @Override
+ public DOMDataReadWriteTransaction newReadWriteTransaction() {
+ return new NetconfDeviceReadWriteTx(newReadOnlyTransaction(), newWriteOnlyTransaction());
+ }
+
+ @Override
+ public DOMDataWriteTransaction newWriteOnlyTransaction() {
+ // FIXME detect if candidate is supported, true is hardcoded
+ return new NetconfDeviceWriteOnlyTx(id, rpc, normalizer, true, netconfSessionPreferences.isRollbackSupported());
+ }
+
+ @Override
+ public ListenerRegistration<DOMDataChangeListener> registerDataChangeListener(final LogicalDatastoreType store, final InstanceIdentifier path, final DOMDataChangeListener listener, final DataChangeScope triggeringScope) {
+ throw new UnsupportedOperationException("Data change listeners not supported for netconf mount point");
+ }
+
+ @Override
+ public DOMTransactionChain createTransactionChain(final TransactionChainListener listener) {
+ // TODO implement
+ throw new UnsupportedOperationException("Transaction chains not supported for netconf mount point");
+ }
+}
+++ /dev/null
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.controller.sal.connect.netconf.sal;
-
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.CONFIG_SOURCE_RUNNING;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
-import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
-
-import java.util.concurrent.ExecutionException;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataReader;
-import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
-import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
-import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.Node;
-import org.opendaylight.yangtools.yang.data.api.SimpleNode;
-
-public final class NetconfDeviceDataReader implements DataReader<InstanceIdentifier,CompositeNode> {
-
- private final RpcImplementation rpc;
- private final RemoteDeviceId id;
-
- public NetconfDeviceDataReader(final RemoteDeviceId id, final RpcImplementation rpc) {
- this.id = id;
- this.rpc = rpc;
- }
-
- @Override
- public CompositeNode readConfigurationData(final InstanceIdentifier path) {
- final RpcResult<CompositeNode> result;
- try {
- result = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME,
- NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path))).get();
- } catch (final InterruptedException e) {
- throw onInterruptedException(e);
- } catch (final ExecutionException e) {
- throw new RuntimeException(id + ": Read configuration data " + path + " failed", e);
- }
-
- final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
- return data == null ? null : (CompositeNode) findNode(data, path);
- }
-
- private RuntimeException onInterruptedException(final InterruptedException e) {
- Thread.currentThread().interrupt();
- return new RuntimeException(id + ": Interrupted while waiting for response", e);
- }
-
- @Override
- public CompositeNode readOperationalData(final InstanceIdentifier path) {
- final RpcResult<CompositeNode> result;
- try {
- result = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path))).get();
- } catch (final InterruptedException e) {
- throw onInterruptedException(e);
- } catch (final ExecutionException e) {
- throw new RuntimeException(id + ": Read operational data " + path + " failed", e);
- }
-
- final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
- return (CompositeNode) findNode(data, path);
- }
-
- private static Node<?> findNode(final CompositeNode node, final InstanceIdentifier identifier) {
-
- Node<?> current = node;
- for (final InstanceIdentifier.PathArgument arg : identifier.getPathArguments()) {
- if (current instanceof SimpleNode<?>) {
- return null;
- } else if (current instanceof CompositeNode) {
- final CompositeNode currentComposite = (CompositeNode) current;
-
- current = currentComposite.getFirstCompositeByName(arg.getNodeType());
- if (current == null) {
- current = currentComposite.getFirstCompositeByName(arg.getNodeType().withoutRevision());
- }
- if (current == null) {
- current = currentComposite.getFirstSimpleByName(arg.getNodeType());
- }
- if (current == null) {
- current = currentComposite.getFirstSimpleByName(arg.getNodeType().withoutRevision());
- }
- if (current == null) {
- return null;
- }
- }
- }
- return current;
- }
-}
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;
private static final Logger logger = LoggerFactory.getLogger(NetconfDeviceDatastoreAdapter.class);
private final RemoteDeviceId id;
- private final DataProviderService dataService;
- private final ListeningExecutorService executor;
+ private final DataBroker dataService;
- NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataProviderService dataService,
- final ExecutorService executor) {
+ NetconfDeviceDatastoreAdapter(final RemoteDeviceId deviceId, final DataBroker dataService) {
this.id = Preconditions.checkNotNull(deviceId);
this.dataService = Preconditions.checkNotNull(dataService);
- this.executor = MoreExecutors.listeningDecorator(Preconditions.checkNotNull(executor));
- // Initial data change scheduled
- submitDataChangeToExecutor(this.executor, new Runnable() {
- @Override
- public void run() {
- initDeviceData();
- }
- }, deviceId);
+ initDeviceData();
}
public void updateDeviceState(final boolean up, final Set<QName> capabilities) {
- submitDataChangeToExecutor(this.executor, new Runnable() {
- @Override
- public void run() {
- updateDeviceStateInternal(up, capabilities);
- }
- }, id);
- }
-
- private void updateDeviceStateInternal(final boolean up, final Set<QName> capabilities) {
final org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node data = buildDataForDeviceState(
up, capabilities, id);
- final DataModificationTransaction transaction = dataService.beginTransaction();
- logger.trace("{}: Update device state transaction {} putting operational data started.", id, transaction.getIdentifier());
- transaction.removeOperationalData(id.getBindingPath());
- transaction.putOperationalData(id.getBindingPath(), data);
- logger.trace("{}: Update device state transaction {} putting operational data ended.", id, transaction.getIdentifier());
+ final ReadWriteTransaction transaction = dataService.newReadWriteTransaction();
+ logger.trace("{}: Update device state transaction {} merging operational data started.", id, transaction.getIdentifier());
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, id.getBindingPath(), data);
+ logger.trace("{}: Update device state transaction {} merging operational data ended.", id, transaction.getIdentifier());
commitTransaction(transaction, "update");
}
private void removeDeviceConfigAndState() {
- final DataModificationTransaction transaction = dataService.beginTransaction();
+ final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
logger.trace("{}: Close device state transaction {} removing all data started.", id, transaction.getIdentifier());
- transaction.removeConfigurationData(id.getBindingPath());
- transaction.removeOperationalData(id.getBindingPath());
+ transaction.delete(LogicalDatastoreType.CONFIGURATION, id.getBindingPath());
+ transaction.delete(LogicalDatastoreType.OPERATIONAL, id.getBindingPath());
logger.trace("{}: Close device state transaction {} removing all data ended.", id, transaction.getIdentifier());
commitTransaction(transaction, "close");
}
private void initDeviceData() {
- final DataModificationTransaction transaction = dataService.beginTransaction();
+ final WriteTransaction transaction = dataService.newWriteOnlyTransaction();
- final InstanceIdentifier<Node> path = id.getBindingPath();
+ createNodesListIfNotPresent(transaction);
+ final InstanceIdentifier<Node> path = id.getBindingPath();
final Node nodeWithId = getNodeWithId(id);
- if (operationalNodeNotExisting(transaction, path)) {
- transaction.putOperationalData(path, nodeWithId);
- }
- if (configurationNodeNotExisting(transaction, path)) {
- transaction.putConfigurationData(path, nodeWithId);
- }
- commitTransaction(transaction, "init");
- }
+ logger.trace("{}: Init device state transaction {} putting if absent operational data started.", id, transaction.getIdentifier());
+ transaction.merge(LogicalDatastoreType.OPERATIONAL, path, nodeWithId);
+ logger.trace("{}: Init device state transaction {} putting operational data ended.", id, transaction.getIdentifier());
- private void commitTransaction(final DataModificationTransaction transaction, final String txType) {
- // attempt commit
- final RpcResult<TransactionStatus> result;
- try {
- result = transaction.commit().get();
- } catch (InterruptedException | ExecutionException e) {
- logger.error("{}: Transaction({}) failed", id, txType, e);
- throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly", e);
- }
-
- // verify success result + committed state
- if (isUpdateSuccessful(result)) {
- logger.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
- } else {
- logger.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier());
- throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly, " +
- "Errors: " + result.getErrors());
- }
- }
+ logger.trace("{}: Init device state transaction {} putting if absent config data started.", id, transaction.getIdentifier());
+ transaction.merge(LogicalDatastoreType.CONFIGURATION, path, nodeWithId);
+ logger.trace("{}: Init device state transaction {} putting config data ended.", id, transaction.getIdentifier());
- @Override
- public void close() throws Exception {
- // Remove device data from datastore
- submitDataChangeToExecutor(executor, new Runnable() {
- @Override
- public void run() {
- removeDeviceConfigAndState();
- }
- }, id);
+ commitTransaction(transaction, "init");
}
- private static boolean isUpdateSuccessful(final RpcResult<TransactionStatus> result) {
- return result.getResult() == TransactionStatus.COMMITED && result.isSuccessful();
+ private void createNodesListIfNotPresent(final WriteTransaction writeTx) {
+ final Nodes nodes = new NodesBuilder().build();
+ final InstanceIdentifier<Nodes> path = InstanceIdentifier.builder(Nodes.class).build();
+ logger.trace("{}: Merging {} container to ensure its presence", id, Nodes.QNAME, writeTx.getIdentifier());
+ writeTx.merge(LogicalDatastoreType.CONFIGURATION, path, nodes);
+ writeTx.merge(LogicalDatastoreType.OPERATIONAL, path, nodes);
}
- private static void submitDataChangeToExecutor(final ListeningExecutorService executor, final Runnable r,
- final RemoteDeviceId id) {
- // Submit data change
- final ListenableFuture<?> f = executor.submit(r);
- // Verify update execution
- Futures.addCallback(f, new FutureCallback<Object>() {
+ private void commitTransaction(final WriteTransaction transaction, final String txType) {
+ logger.trace("{}: Committing Transaction {}:{}", id, txType, transaction.getIdentifier());
+ final CheckedFuture<Void, TransactionCommitFailedException> result = transaction.submit();
+
+ Futures.addCallback(result, new FutureCallback<Void>() {
@Override
- public void onSuccess(final Object result) {
- logger.debug("{}: Device data updated successfully", id);
+ public void onSuccess(final Void result) {
+ logger.trace("{}: Transaction({}) {} SUCCESSFUL", id, txType, transaction.getIdentifier());
}
@Override
public void onFailure(final Throwable t) {
- logger.warn("{}: Device data update failed", id, t);
+ logger.error("{}: Transaction({}) {} FAILED!", id, txType, transaction.getIdentifier(), t);
+ throw new IllegalStateException(id + " Transaction(" + txType + ") not committed correctly", t);
}
});
+
+ }
+
+ @Override
+ public void close() throws Exception {
+ removeDeviceConfigAndState();
}
public static org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.Node buildDataForDeviceState(
return nodeBuilder.build();
}
- private static boolean configurationNodeNotExisting(final DataModificationTransaction transaction,
- final InstanceIdentifier<Node> path) {
- return null == transaction.readConfigurationData(path);
- }
-
- private static boolean operationalNodeNotExisting(final DataModificationTransaction transaction,
+ private static ListenableFuture<Optional<Node>> readNodeData(
+ final LogicalDatastoreType store,
+ final ReadWriteTransaction transaction,
final InstanceIdentifier<Node> path) {
- return null == transaction.readOperationalData(path);
+ return transaction.read(store, path);
}
private static Node getNodeWithId(final RemoteDeviceId id) {
return Collections.emptySet();
}
+ // TODO change this to work with NormalizedNode api. Then we can loose DataNormalizer from Transactions
+
@Override
public ListenableFuture<RpcResult<CompositeNode>> invokeRpc(final QName rpc, final CompositeNode input) {
final NetconfMessage message = transformRequest(rpc, input);
*/
package org.opendaylight.controller.sal.connect.netconf.sal;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
+
+import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
import org.opendaylight.controller.sal.binding.api.BindingAwareBroker;
import org.opendaylight.controller.sal.connect.api.RemoteDeviceHandler;
import org.opendaylight.controller.sal.connect.netconf.listener.NetconfSessionCapabilities;
import org.opendaylight.controller.sal.connect.util.RemoteDeviceId;
import org.opendaylight.controller.sal.core.api.Broker;
import org.opendaylight.controller.sal.core.api.RpcImplementation;
-import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.RpcProvisionRegistry;
+import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
+import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.controller.sal.dom.broker.impl.NotificationRouterImpl;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareRpcBroker;
+import org.opendaylight.controller.sal.dom.broker.spi.NotificationRouter;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.common.QName;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextProvider;
import org.osgi.framework.BundleContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+
public final class NetconfDeviceSalFacade implements AutoCloseable, RemoteDeviceHandler<NetconfSessionCapabilities> {
private static final Logger logger= LoggerFactory.getLogger(NetconfDeviceSalFacade.class);
- private static final InstanceIdentifier ROOT_PATH = InstanceIdentifier.builder().toInstance();
private final RemoteDeviceId id;
private final NetconfDeviceSalProvider salProvider;
@Override
public synchronized void onDeviceConnected(final SchemaContextProvider remoteSchemaContextProvider,
final NetconfSessionCapabilities netconfSessionPreferences, final RpcImplementation deviceRpc) {
- salProvider.getMountInstance().setSchemaContext(remoteSchemaContextProvider.getSchemaContext());
+ final SchemaContext schemaContext = remoteSchemaContextProvider.getSchemaContext();
+
+ // TODO remove deprecated SchemaContextProvider from SchemaAwareRpcBroker
+ // TODO move SchemaAwareRpcBroker from sal-broker-impl, now we have depend on the whole sal-broker-impl
+ final RpcProvisionRegistry rpcRegistry = new SchemaAwareRpcBroker(id.getPath().toString(), new org.opendaylight.controller.sal.dom.broker.impl.SchemaContextProvider() {
+ @Override
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+ });
+ registerRpcsToSal(schemaContext, rpcRegistry, deviceRpc);
+ final DOMDataBroker domBroker = new NetconfDeviceDataBroker(id, deviceRpc, schemaContext, netconfSessionPreferences);
+
+ // TODO NotificationPublishService and NotificationRouter have the same interface
+ final NotificationPublishService notificationService = new NotificationPublishService() {
+
+ private final NotificationRouter innerRouter = new NotificationRouterImpl();
+
+ @Override
+ public void publish(final CompositeNode notification) {
+ innerRouter.publish(notification);
+ }
+
+ @Override
+ public ListenerRegistration<NotificationListener> addNotificationListener(final QName notification, final NotificationListener listener) {
+ return innerRouter.addNotificationListener(notification, listener);
+ }
+ };
+
+ salProvider.getMountInstance().onDeviceConnected(schemaContext, domBroker, rpcRegistry, notificationService);
salProvider.getDatastoreAdapter().updateDeviceState(true, netconfSessionPreferences.getModuleBasedCaps());
- registerDataHandlersToSal(deviceRpc, netconfSessionPreferences);
- registerRpcsToSal(deviceRpc);
}
@Override
public void onDeviceDisconnected() {
salProvider.getDatastoreAdapter().updateDeviceState(false, Collections.<QName>emptySet());
+ salProvider.getMountInstance().onDeviceDisconnected();
}
- private void registerRpcsToSal(final RpcImplementation deviceRpc) {
- final MountProvisionInstance mountInstance = salProvider.getMountInstance();
-
+ private void registerRpcsToSal(final SchemaContext schemaContext, final RpcProvisionRegistry rpcRegistry, final RpcImplementation deviceRpc) {
final Map<QName, String> failedRpcs = Maps.newHashMap();
- for (final RpcDefinition rpcDef : mountInstance.getSchemaContext().getOperations()) {
+ for (final RpcDefinition rpcDef : schemaContext.getOperations()) {
try {
- salRegistrations.add(mountInstance.addRpcImplementation(rpcDef.getQName(), deviceRpc));
+ salRegistrations.add(rpcRegistry.addRpcImplementation(rpcDef.getQName(), deviceRpc));
logger.debug("{}: Rpc {} from netconf registered successfully", id, rpcDef.getQName());
} catch (final Exception e) {
// Only debug per rpc, warn for all of them at the end to pollute log a little less (e.g. routed rpcs)
}
}
- 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)) {
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;
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;
}
@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
@Override
public void onSessionInitiated(final BindingAwareBroker.ProviderContext session) {
- final DataProviderService dataBroker = session.getSALService(DataProviderService.class);
- datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker, executor);
-
logger.debug("{}: Session with sal established {}", id, session);
+
+ final DataBroker dataBroker = session.getSALService(DataBroker.class);
+ datastoreAdapter = new NetconfDeviceDatastoreAdapter(id, dataBroker);
}
@Override
- public void onSessionInitialized(final BindingAwareBroker.ConsumerContext session) {
- }
+ public void onSessionInitialized(final BindingAwareBroker.ConsumerContext session) {}
public void close() throws Exception {
- mountInstance = null;
+ mountInstance.close();
datastoreAdapter.close();
datastoreAdapter = null;
}
+ static final class MountInstance implements AutoCloseable {
+
+ private DOMMountPointService mountService;
+ private final RemoteDeviceId id;
+ private ObjectRegistration<DOMMountPoint> registration;
+ private NotificationPublishService notificationSerivce;
+
+ MountInstance(final DOMMountPointService mountService, final RemoteDeviceId id) {
+ this.mountService = Preconditions.checkNotNull(mountService);
+ this.id = Preconditions.checkNotNull(id);
+ }
+
+ synchronized void onDeviceConnected(final SchemaContext initialCtx,
+ final DOMDataBroker broker, final RpcProvisionRegistry rpc,
+ final NotificationPublishService notificationSerivce) {
+
+ Preconditions.checkNotNull(mountService, "Closed");
+ Preconditions.checkState(registration == null, "Already initialized");
+
+ final DOMMountPointService.DOMMountPointBuilder mountBuilder = mountService.createMountPoint(id.getPath());
+ mountBuilder.addInitialSchemaContext(initialCtx);
+
+ mountBuilder.addService(DOMDataBroker.class, broker);
+ mountBuilder.addService(RpcProvisionRegistry.class, rpc);
+ this.notificationSerivce = notificationSerivce;
+ mountBuilder.addService(NotificationPublishService.class, notificationSerivce);
+
+ registration = mountBuilder.register();
+ }
+
+ synchronized void onDeviceDisconnected() {
+ if(registration == null) {
+ return;
+ }
+
+ try {
+ registration.close();
+ } catch (final Exception e) {
+ // Only log and ignore
+ logger.warn("Unable to unregister mount instance for {}. Ignoring exception", id.getPath(), e);
+ } finally {
+ registration = null;
+ }
+ }
+
+ @Override
+ synchronized public void close() throws Exception {
+ if(registration != null) {
+ onDeviceDisconnected();
+ }
+ mountService = null;
+ }
+
+ public synchronized void publish(final CompositeNode domNotification) {
+ Preconditions.checkNotNull(notificationSerivce, "Device not set up yet, cannot handle notification {}", domNotification);
+ notificationSerivce.publish(domNotification);
+ }
+ }
+
}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+package org.opendaylight.controller.sal.connect.netconf.sal.tx;
+
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.CONFIG_SOURCE_RUNNING;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_DATA_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_CONFIG_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.NETCONF_GET_QNAME;
+import static org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil.toFilterStructure;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
+import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadOnlyTransaction;
+import org.opendaylight.controller.sal.connect.netconf.util.NetconfMessageTransformUtil;
+import org.opendaylight.controller.sal.core.api.RpcImplementation;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public final class NetconfDeviceReadOnlyTx implements DOMDataReadOnlyTransaction {
+
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceReadOnlyTx.class);
+
+ private final RpcImplementation rpc;
+ private final DataNormalizer normalizer;
+
+ public NetconfDeviceReadOnlyTx(final RpcImplementation rpc, final DataNormalizer normalizer) {
+ this.rpc = rpc;
+ this.normalizer = normalizer;
+ }
+
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> readConfigurationData(final InstanceIdentifier path) {
+ final ListenableFuture<RpcResult<CompositeNode>> future = rpc.invokeRpc(NETCONF_GET_CONFIG_QNAME,
+ NetconfMessageTransformUtil.wrap(NETCONF_GET_CONFIG_QNAME, CONFIG_SOURCE_RUNNING, toFilterStructure(path)));
+
+ return Futures.transform(future, new Function<RpcResult<CompositeNode>, Optional<NormalizedNode<?, ?>>>() {
+ @Override
+ public Optional<NormalizedNode<?, ?>> apply(final RpcResult<CompositeNode> result) {
+ final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
+ final CompositeNode node = (CompositeNode) findNode(data, path);
+
+ return data == null ?
+ Optional.<NormalizedNode<?, ?>>absent() :
+ transform(path, node);
+ }
+ });
+ }
+
+ private Optional<NormalizedNode<?, ?>> transform(final InstanceIdentifier path, final CompositeNode node) {
+ if(node == null) {
+ return Optional.absent();
+ }
+ try {
+ return Optional.<NormalizedNode<?, ?>>of(normalizer.toNormalized(path, node).getValue());
+ } catch (final Exception e) {
+ LOG.error("Unable to normalize data for {}, data: {}", path, node, e);
+ throw e;
+ }
+ }
+
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> readOperationalData(final InstanceIdentifier path) {
+ final ListenableFuture<RpcResult<CompositeNode>> future = rpc.invokeRpc(NETCONF_GET_QNAME, NetconfMessageTransformUtil.wrap(NETCONF_GET_QNAME, toFilterStructure(path)));
+
+ return Futures.transform(future, new Function<RpcResult<CompositeNode>, Optional<NormalizedNode<?, ?>>>() {
+ @Override
+ public Optional<NormalizedNode<?, ?>> apply(final RpcResult<CompositeNode> result) {
+ final CompositeNode data = result.getResult().getFirstCompositeByName(NETCONF_DATA_QNAME);
+ final CompositeNode node = (CompositeNode) findNode(data, path);
+
+ return data == null ?
+ Optional.<NormalizedNode<?, ?>>absent() :
+ transform(path, node);
+ }
+ });
+ }
+
+ private static Node<?> findNode(final CompositeNode node, final InstanceIdentifier identifier) {
+
+ Node<?> current = node;
+ for (final InstanceIdentifier.PathArgument arg : identifier.getPathArguments()) {
+ if (current instanceof SimpleNode<?>) {
+ return null;
+ } else if (current instanceof CompositeNode) {
+ final CompositeNode currentComposite = (CompositeNode) current;
+
+ current = currentComposite.getFirstCompositeByName(arg.getNodeType());
+ if (current == null) {
+ current = currentComposite.getFirstCompositeByName(arg.getNodeType().withoutRevision());
+ }
+ if (current == null) {
+ current = currentComposite.getFirstSimpleByName(arg.getNodeType());
+ }
+ if (current == null) {
+ current = currentComposite.getFirstSimpleByName(arg.getNodeType().withoutRevision());
+ }
+ if (current == null) {
+ return null;
+ }
+ }
+ }
+ return current;
+ }
+
+ @Override
+ public void close() {
+ // NOOP
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ final InstanceIdentifier legacyPath = toLegacyPath(normalizer, path);
+
+ switch (store) {
+ case CONFIGURATION : {
+ return readConfigurationData(legacyPath);
+ }
+ case OPERATIONAL : {
+ return readOperationalData(legacyPath);
+ }
+ }
+
+ throw new IllegalArgumentException(String.format("Cannot read data %s for %s datastore, unknown datastore type", path, store));
+ }
+
+ static InstanceIdentifier toLegacyPath(final DataNormalizer normalizer, final InstanceIdentifier path) {
+ try {
+ return normalizer.toLegacy(path);
+ } catch (final DataNormalizationException e) {
+ throw new IllegalArgumentException("Cannot normalize path " + path, e);
+ }
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html.
+ */
+
+package org.opendaylight.controller.sal.connect.netconf.sal.tx;
+
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
+import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
+import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class NetconfDeviceReadWriteTx implements DOMDataReadWriteTransaction {
+
+ private final DOMDataReadTransaction delegateReadTx;
+ private final DOMDataWriteTransaction delegateWriteTx;
+
+ public NetconfDeviceReadWriteTx(final DOMDataReadTransaction delegateReadTx, final DOMDataWriteTransaction delegateWriteTx) {
+ this.delegateReadTx = delegateReadTx;
+ this.delegateWriteTx = delegateWriteTx;
+ }
+
+ @Override
+ public boolean cancel() {
+ return delegateWriteTx.cancel();
+ }
+
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.put(store, path, data);
+ }
+
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ delegateWriteTx.merge(store, path, data);
+ }
+
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ delegateWriteTx.delete(store, path);
+ }
+
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ return delegateWriteTx.submit();
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ return delegateWriteTx.commit();
+ }
+
+ @Override
+ public ListenableFuture<Optional<NormalizedNode<?, ?>>> read(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ return delegateReadTx.read(store, path);
+ }
+
+ @Override
+ public Object getIdentifier() {
+ return this;
+ }
+}
*
* 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;
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;
import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
import org.opendaylight.yangtools.yang.data.api.ModifyAction;
import org.opendaylight.yangtools.yang.data.api.Node;
import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-/**
- * Remote transaction that delegates data change to remote device using netconf messages.
- */
-final class NetconfDeviceTwoPhaseCommitTransaction implements DataCommitTransaction<InstanceIdentifier, CompositeNode> {
+public class NetconfDeviceWriteOnlyTx implements DOMDataWriteTransaction {
- private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceTwoPhaseCommitTransaction.class);
+ private static final Logger LOG = LoggerFactory.getLogger(NetconfDeviceWriteOnlyTx.class);
- private final DataModification<InstanceIdentifier, CompositeNode> modification;
+ private final RemoteDeviceId id;
private final RpcImplementation rpc;
+ private final DataNormalizer normalizer;
private final boolean rollbackSupported;
- private final RemoteDeviceId id;
private final CompositeNode targetNode;
- public NetconfDeviceTwoPhaseCommitTransaction(final RemoteDeviceId id, final RpcImplementation rpc,
- final DataModification<InstanceIdentifier, CompositeNode> modification,
- final boolean candidateSupported, final boolean rollbackOnErrorSupported) {
+ public NetconfDeviceWriteOnlyTx(final RemoteDeviceId id, final RpcImplementation rpc, final DataNormalizer normalizer, final boolean candidateSupported, final boolean rollbackOnErrorSupported) {
this.id = id;
- this.rpc = Preconditions.checkNotNull(rpc);
- this.modification = Preconditions.checkNotNull(modification);
+ this.rpc = rpc;
+ this.normalizer = normalizer;
this.targetNode = getTargetNode(candidateSupported);
this.rollbackSupported = rollbackOnErrorSupported;
}
- /**
- * Prepare phase, sends 1 or more netconf edit config operations to modify the data
- *
- * In case of failure or unexpected error response, ExecutionException is thrown
- */
- void prepare() throws InterruptedException, ExecutionException {
- for (final InstanceIdentifier toRemove : modification.getRemovedConfigurationData()) {
- sendDelete(toRemove);
- }
- for(final Entry<InstanceIdentifier, CompositeNode> toUpdate : modification.getUpdatedConfigurationData().entrySet()) {
- sendMerge(toUpdate.getKey(),toUpdate.getValue());
+ // FIXME add logging
+
+ @Override
+ public boolean cancel() {
+ if(isCommitted()) {
+ return false;
}
+
+ return discardChanges();
}
- private void sendMerge(final InstanceIdentifier key, final CompositeNode value) throws InterruptedException, ExecutionException {
- sendEditRpc(createEditConfigStructure(key, Optional.<ModifyAction>absent(), Optional.of(value)), Optional.<ModifyAction>absent());
+ private boolean isCommitted() {
+ // TODO 732
+ return true;
}
- private void sendDelete(final InstanceIdentifier toDelete) throws InterruptedException, ExecutionException {
- sendEditRpc(createEditConfigStructure(toDelete, Optional.of(ModifyAction.DELETE), Optional.<CompositeNode>absent()), Optional.of(ModifyAction.NONE));
+ private boolean discardChanges() {
+ // TODO 732
+ return true;
}
- private void sendEditRpc(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) throws InterruptedException, ExecutionException {
- final ImmutableCompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation);
- final RpcResult<CompositeNode> rpcResult = rpc.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, editConfigRequest).get();
+ // TODO should the edit operations be blocking ?
- // Check result
- if(rpcResult.isSuccessful() == false) {
- throw new ExecutionException(
- String.format("%s: Pre-commit rpc failed, request: %s, errors: %s", id, editConfigRequest, rpcResult.getErrors()), null);
+ @Override
+ public void put(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
+
+ try {
+ final InstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path);
+ final CompositeNode legacyData = normalizer.toLegacy(path, data);
+ sendEditRpc(createEditConfigStructure(legacyPath, Optional.of(ModifyAction.REPLACE), Optional.fromNullable(legacyData)), Optional.of(ModifyAction.NONE));
+ } catch (final ExecutionException e) {
+ LOG.warn("Error putting data to {}, data: {}, discarding changes", path, data, e);
+ discardChanges();
+ throw new RuntimeException("Error while replacing " + path, e);
}
}
- private ImmutableCompositeNode createEditConfigRequest(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) {
- final CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
+ @Override
+ public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final NormalizedNode<?, ?> data) {
+ Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
- // Target
- final Node<?> targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.<Node<?>>of(targetNode));
- ret.add(targetWrapperNode);
+ try {
+ final InstanceIdentifier legacyPath = NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path);
+ final CompositeNode legacyData = normalizer.toLegacy(path, data);
+ sendEditRpc(
+ createEditConfigStructure(legacyPath, Optional.<ModifyAction> absent(), Optional.fromNullable(legacyData)), Optional.<ModifyAction> absent());
+ } catch (final ExecutionException e) {
+ LOG.warn("Error merging data to {}, data: {}, discarding changes", path, data, e);
+ discardChanges();
+ throw new RuntimeException("Error while merging " + path, e);
+ }
+ }
- // Default operation
- if(defaultOperation.isPresent()) {
- final SimpleNode<String> defOp = NodeFactory.createImmutableSimpleNode(NETCONF_DEFAULT_OPERATION_QNAME, null, modifyOperationToXmlString(defaultOperation.get()));
- ret.add(defOp);
+ @Override
+ public void delete(final LogicalDatastoreType store, final InstanceIdentifier path) {
+ Preconditions.checkArgument(store == LogicalDatastoreType.CONFIGURATION, "Can merge only configuration, not %s", store);
+
+ try {
+ sendEditRpc(createEditConfigStructure(NetconfDeviceReadOnlyTx.toLegacyPath(normalizer, path), Optional.of(ModifyAction.DELETE), Optional.<CompositeNode>absent()), Optional.of(ModifyAction.NONE));
+ } catch (final ExecutionException e) {
+ LOG.warn("Error deleting data {}, discarding changes", path, e);
+ discardChanges();
+ throw new RuntimeException("Error while deleting " + path, e);
}
+ }
- // Error option
- if(rollbackSupported) {
- ret.addLeaf(NETCONF_ERROR_OPTION_QNAME, ROLLBACK_ON_ERROR_OPTION);
+ @Override
+ public CheckedFuture<Void, TransactionCommitFailedException> submit() {
+ final ListenableFuture<Void> commmitFutureAsVoid = Futures.transform(commit(), new Function<RpcResult<TransactionStatus>, Void>() {
+ @Nullable
+ @Override
+ public Void apply(@Nullable final RpcResult<TransactionStatus> input) {
+ return null;
+ }
+ });
+
+ return Futures.makeChecked(commmitFutureAsVoid, new Function<Exception, TransactionCommitFailedException>() {
+ @Override
+ public TransactionCommitFailedException apply(final Exception input) {
+ return new TransactionCommitFailedException("Submit of transaction " + getIdentifier() + " failed", input);
+ }
+ });
+ }
+
+ @Override
+ public ListenableFuture<RpcResult<TransactionStatus>> commit() {
+ // FIXME do not allow commit if closed or failed
+
+ final ListenableFuture<RpcResult<CompositeNode>> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest());
+ return Futures.transform(rpcResult, new Function<RpcResult<CompositeNode>, RpcResult<TransactionStatus>>() {
+ @Override
+ public RpcResult<TransactionStatus> apply(@Nullable final RpcResult<CompositeNode> input) {
+ if(input.isSuccessful()) {
+ return RpcResultBuilder.success(TransactionStatus.COMMITED).build();
+ } else {
+ final RpcResultBuilder<TransactionStatus> failed = RpcResultBuilder.failed();
+ for (final RpcError rpcError : input.getErrors()) {
+ failed.withError(rpcError.getErrorType(), rpcError.getTag(), rpcError.getMessage(), rpcError.getApplicationTag(), rpcError.getInfo(), rpcError.getCause());
+ }
+ return failed.build();
+ }
+ }
+ });
+
+ // FIXME 732 detect commit failure
+ }
+
+ private void sendEditRpc(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) throws ExecutionException {
+ final CompositeNode editConfigRequest = createEditConfigRequest(editStructure, defaultOperation);
+ final RpcResult<CompositeNode> rpcResult;
+ try {
+ rpcResult = rpc.invokeRpc(NETCONF_EDIT_CONFIG_QNAME, editConfigRequest).get();
+ } catch (final InterruptedException e) {
+ Thread.currentThread().interrupt();
+ throw new RuntimeException(id + ": Interrupted while waiting for response", e);
}
- ret.setQName(NETCONF_EDIT_CONFIG_QNAME);
- // Edit content
- ret.add(editStructure);
- return ret.toInstance();
+ // Check result
+ if(rpcResult.isSuccessful() == false) {
+ throw new ExecutionException(
+ String.format("%s: Pre-commit rpc failed, request: %s, errors: %s", id, editConfigRequest, rpcResult.getErrors()), null);
+ }
}
private CompositeNode createEditConfigStructure(final InstanceIdentifier dataPath, final Optional<ModifyAction> operation,
- final Optional<CompositeNode> lastChildOverride) {
+ final Optional<CompositeNode> lastChildOverride) {
Preconditions.checkArgument(Iterables.isEmpty(dataPath.getPathArguments()) == false, "Instance identifier with empty path %s", dataPath);
- List<PathArgument> reversedPath = Lists.reverse(dataPath.getPath());
+ List<InstanceIdentifier.PathArgument> reversedPath = Lists.reverse(dataPath.getPath());
// Create deepest edit element with expected edit operation
CompositeNode previous = getDeepestEditElement(reversedPath.get(0), operation, lastChildOverride);
reversedPath.remove(0);
// Create edit structure in reversed order
- for (final PathArgument arg : reversedPath) {
+ for (final InstanceIdentifier.PathArgument arg : reversedPath) {
final CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
builder.setQName(arg.getNodeType());
}
private void addPredicatesToCompositeNodeBuilder(final Map<QName, Object> predicates, final CompositeNodeBuilder<ImmutableCompositeNode> builder) {
- for (final Entry<QName, Object> entry : predicates.entrySet()) {
+ for (final Map.Entry<QName, Object> entry : predicates.entrySet()) {
builder.addLeaf(entry.getKey(), entry.getValue());
}
}
- private Map<QName, Object> getPredicates(final PathArgument arg) {
+ private Map<QName, Object> getPredicates(final InstanceIdentifier.PathArgument arg) {
Map<QName, Object> predicates = Collections.emptyMap();
- if (arg instanceof NodeIdentifierWithPredicates) {
- predicates = ((NodeIdentifierWithPredicates) arg).getKeyValues();
+ if (arg instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
+ predicates = ((InstanceIdentifier.NodeIdentifierWithPredicates) arg).getKeyValues();
}
return predicates;
}
- private CompositeNode getDeepestEditElement(final PathArgument arg, final Optional<ModifyAction> operation, final Optional<CompositeNode> lastChildOverride) {
+ private CompositeNode getDeepestEditElement(final InstanceIdentifier.PathArgument arg, final Optional<ModifyAction> operation, final Optional<CompositeNode> lastChildOverride) {
final CompositeNodeBuilder<ImmutableCompositeNode> builder = ImmutableCompositeNode.builder();
builder.setQName(arg.getNodeType());
return builder.toInstance();
}
- private String modifyOperationToXmlString(final ModifyAction operation) {
- return operation.name().toLowerCase();
- }
+ private CompositeNode createEditConfigRequest(final CompositeNode editStructure, final Optional<ModifyAction> defaultOperation) {
+ final CompositeNodeBuilder<ImmutableCompositeNode> ret = ImmutableCompositeNode.builder();
- /**
- * Send commit rpc to finish the transaction
- * In case of failure or unexpected error response, ExecutionException is thrown
- */
- @Override
- public RpcResult<Void> finish() {
- try {
- final RpcResult<?> rpcResult = rpc.invokeRpc(NetconfMessageTransformUtil.NETCONF_COMMIT_QNAME, getCommitRequest()).get();
- return new RpcResultVoidWrapper(rpcResult);
- } catch (final InterruptedException e) {
- Thread.currentThread().interrupt();
- throw new RuntimeException(id + ": Interrupted while waiting for response", e);
- } catch (final ExecutionException e) {
- LOG.warn("{}: Failed to finish commit operation", id, e);
- return RpcResultBuilder.<Void>failed().withError( RpcError.ErrorType.APPLICATION,
- id + ": Unexpected operation error during commit operation", e ).build();
+ // Target
+ final Node<?> targetWrapperNode = ImmutableCompositeNode.create(NETCONF_TARGET_QNAME, ImmutableList.<Node<?>>of(targetNode));
+ ret.add(targetWrapperNode);
+
+ // Default operation
+ if(defaultOperation.isPresent()) {
+ final SimpleNode<String> defOp = NodeFactory.createImmutableSimpleNode(NETCONF_DEFAULT_OPERATION_QNAME, null, modifyOperationToXmlString(defaultOperation.get()));
+ ret.add(defOp);
}
- }
- private ImmutableCompositeNode getCommitRequest() {
- final CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
- commitInput.setQName(NETCONF_COMMIT_QNAME);
- return commitInput.toInstance();
- }
+ // Error option
+ if(rollbackSupported) {
+ ret.addLeaf(NETCONF_ERROR_OPTION_QNAME, ROLLBACK_ON_ERROR_OPTION);
+ }
- @Override
- public DataModification<InstanceIdentifier, CompositeNode> getModification() {
- return this.modification;
+ ret.setQName(NETCONF_EDIT_CONFIG_QNAME);
+ // Edit content
+ ret.add(editStructure);
+ return ret.toInstance();
}
- @Override
- public RpcResult<Void> rollback() throws IllegalStateException {
- // TODO BUG-732 implement rollback by sending discard changes
- return null;
+ private String modifyOperationToXmlString(final ModifyAction operation) {
+ return operation.name().toLowerCase();
}
public CompositeNode getTargetNode(final boolean candidateSupported) {
}
}
- private static final class RpcResultVoidWrapper implements RpcResult<Void> {
-
- private final RpcResult<?> rpcResult;
-
- public RpcResultVoidWrapper(final RpcResult<?> rpcResult) {
- this.rpcResult = rpcResult;
- }
-
- @Override
- public boolean isSuccessful() {
- return rpcResult.isSuccessful();
- }
+ private ImmutableCompositeNode getCommitRequest() {
+ final CompositeNodeBuilder<ImmutableCompositeNode> commitInput = ImmutableCompositeNode.builder();
+ commitInput.setQName(NETCONF_COMMIT_QNAME);
+ return commitInput.toInstance();
+ }
- @Override
- public Void getResult() {
- return null;
- }
- @Override
- public Collection<RpcError> getErrors() {
- return rpcResult.getErrors();
- }
+ @Override
+ public Object getIdentifier() {
+ return this;
}
}
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;
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);
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);
}
* string - first argument).
*/
@Test
- public void invokeRpcMtethodTest() {
+ public void invokeRpcMethodTest() {
ControllerContext contContext = controllerContext;
try {
contContext.findModuleNameByNamespace(new URI("invoke:rpc:module"));
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);
}
}
});
}
+ /**
+ *
+ * @param tagName tag name without prefix
+ * @return
+ */
public List<XmlElement> getChildElements(final String tagName) {
return getChildElementsInternal(new ElementFilteringStrategy() {
@Override
public boolean accept(Element e) {
- return e.getTagName().equals(tagName);
+ // localName returns pure localName without prefix
+ return e.getLocalName().equals(tagName);
}
});
}
public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
String namespace, String contentWithoutPrefix) {
+ return createTextElementWithNamespacedContent(document, qName, prefix, namespace, contentWithoutPrefix, Optional.<String>absent());
+ }
+
+ public static Element createTextElementWithNamespacedContent(Document document, String qName, String prefix,
+ String namespace, String contentWithoutPrefix, Optional<String> namespaceURI) {
+
String content = createPrefixedValue(XmlNetconfConstants.PREFIX, contentWithoutPrefix);
- Element element = createTextElement(document, qName, content, Optional.<String>absent());
+ Element element = createTextElement(document, qName, content, namespaceURI);
String prefixedNamespaceAttr = createPrefixedValue(XMLNS_ATTRIBUTE_KEY, prefix);
element.setAttributeNS(XMLNS_URI, prefixedNamespaceAttr, namespace);
return element;