<bundle start="true" start-level="35">mvn:org.javassist/javassist/${javassist.version}</bundle>
<bundle start="true" start-level="35">mvn:commons-io/commons-io/${commons.io.version}</bundle>
<bundle start="true" start-level="35">mvn:commons-codec/commons-codec/${commons.codec.version}</bundle>
- <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang.version}</bundle>
+ <bundle start="true" start-level="35">mvn:org.apache.commons/commons-lang3/${commons.lang3.version}</bundle>
<bundle start="true" start-level="35">mvn:commons-net/commons-net/${commons.net.version}</bundle>
</feature>
<feature name="base-eclipselink-persistence" description="EclipseLink Persistence API" version="2.0.4.v201112161009">
<appauth.version>0.4.2-SNAPSHOT</appauth.version>
<archetype-app-northbound>0.0.1-SNAPSHOT</archetype-app-northbound>
<aries.util.version>1.1.0</aries.util.version>
- <!-- Controller Modules Versions -->
- <arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
<arphandler.version>0.5.2-SNAPSHOT</arphandler.version>
+ <!-- Controller Modules Versions -->
<asm.version>4.1</asm.version>
<!-- Plugin Versions -->
<bouncycastle.version>1.50</bouncycastle.version>
<bundlescanner.api.version>0.4.2-SNAPSHOT</bundlescanner.api.version>
<bundlescanner.implementation.version>0.4.2-SNAPSHOT</bundlescanner.implementation.version>
<bundlescanner.version>0.4.2-SNAPSHOT</bundlescanner.version>
- <checkstyle.version>2.10</checkstyle.version>
+ <checkstyle.version>2.12</checkstyle.version>
<clustering.services.version>0.5.1-SNAPSHOT</clustering.services.version>
<clustering.services_implementation.version>0.4.3-SNAPSHOT</clustering.services_implementation.version>
<clustering.stub.version>0.4.2-SNAPSHOT</clustering.stub.version>
<commons.io.version>2.4</commons.io.version>
<commons.jasper>7.0.32.v201211201952</commons.jasper>
<commons.juli.version>7.0.32.v201211081135</commons.juli.version>
- <commons.lang.version>3.1</commons.lang.version>
+ <commons.lang.version>2.6</commons.lang.version>
+ <commons.lang3.version>3.1</commons.lang3.version>
<commons.logback_settings.version>0.0.2-SNAPSHOT</commons.logback_settings.version>
<commons.net.version>3.0.1</commons.net.version>
<commons.opendaylight.commons.httpclient>0.1.2-SNAPSHOT</commons.opendaylight.commons.httpclient>
<felix.fileinstall.version>3.1.6</felix.fileinstall.version>
<felix.webconsole.version>4.2.0</felix.webconsole.version>
<filtervalve.version>1.4.2-SNAPSHOT</filtervalve.version>
+ <findbugs.maven.plugin.version>2.4.0</findbugs.maven.plugin.version>
<flowprogrammer.northbound.version>0.4.2-SNAPSHOT</flowprogrammer.northbound.version>
<flows.web.version>0.4.2-SNAPSHOT</flows.web.version>
<forwarding.staticrouting>0.5.2-SNAPSHOT</forwarding.staticrouting>
<java.version.target>1.7</java.version.target>
<javassist.version>3.17.1-GA</javassist.version>
<javax.annotation.version>1.2</javax.annotation.version>
+ <jdepend.maven.plugin.version>2.0-beta-2</jdepend.maven.plugin.version>
<!-- Third party version -->
<jersey-servlet.version>1.17</jersey-servlet.version>
<jersey.version>1.17</jersey.version>
<karaf.branding.version>1.0.0-SNAPSHOT</karaf.branding.version>
<karaf.shell.version>3.0.0</karaf.shell.version>
<karaf.version>3.0.1</karaf.version>
+ <lifecycle.mapping.version>1.0.0</lifecycle.mapping.version>
<logback.version>1.0.9</logback.version>
<logging.bridge.version>0.4.2-SNAPSHOT</logging.bridge.version>
<maven.compile.plugin.version>2.5.1</maven.compile.plugin.version>
<!-- Java Versions -->
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
+ <maven.plugin.api.version>3.0.5</maven.plugin.api.version>
<mdsal.version>1.1-SNAPSHOT</mdsal.version>
<mockito.version>1.9.5</mockito.version>
<netconf.version>0.2.5-SNAPSHOT</netconf.version>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
+ <!-- 3rd party dependencies needed by config-->
+ <dependency>
+ <groupId>com.jcabi</groupId>
+ <artifactId>jcabi-maven-slf4j</artifactId>
+ <version>0.8</version>
+ </dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>commons-io</artifactId>
<version>${commons.io.version}</version>
</dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>${commons.lang.version}</version>
+ </dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<artifactId>jsr311-api</artifactId>
<version>${jsr311.api.version}</version>
</dependency>
+ <dependency>
+ <groupId>net.sourceforge.pmd</groupId>
+ <artifactId>pmd</artifactId>
+ <version>5.1.0</version>
+ </dependency>
<dependency>
<groupId>orbit</groupId>
<artifactId>javax.activation</artifactId>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
- <version>${commons.lang.version}</version>
+ <version>${commons.lang3.version}</version>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>enunciate-core-annotations</artifactId>
<version>${enunciate.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.codehaus.gmaven.runtime</groupId>
+ <artifactId>gmaven-runtime-2.0</artifactId>
+ <version>1.5</version>
+ </dependency>
<dependency>
<groupId>org.codehaus.jettison</groupId>
<artifactId>jettison</artifactId>
<version>${jettison.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.eclipse</groupId>
+ <artifactId>jdt</artifactId>
+ <version>3.3.0-v20070607-1300</version>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.equinox</groupId>
+ <artifactId>app</artifactId>
+ <version>1.0.0-v20070606</version>
+ </dependency>
<!-- equinox http service bridge -->
<dependency>
<artifactId>servlet</artifactId>
<version>1.0.0-v20070606</version>
</dependency>
+ <dependency>
+ <groupId>org.eclipse.jdt</groupId>
+ <artifactId>core</artifactId>
+ <version>3.3.0-v_771</version>
+ </dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.antlr</artifactId>
<artifactId>org.eclipse.xtend.lib</artifactId>
<version>${xtend.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.test-framework.providers</groupId>
+ <artifactId>jersey-test-framework-provider-grizzly2</artifactId>
+ <version>2.4</version>
+ </dependency>
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>${javassist.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.jboss.resteasy</groupId>
+ <artifactId>jaxrs-api</artifactId>
+ <version>3.0.4.Final</version>
+ </dependency>
<dependency>
<groupId>org.jboss.spec.javax.transaction</groupId>
<artifactId>jboss-transaction-api_1.1_spec</artifactId>
<artifactId>filter-valve</artifactId>
<version>${filtervalve.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>flow-management-compatibility</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>flowprogrammer.northbound</artifactId>
<artifactId>netconf-client</artifactId>
<version>${netconf.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>netconf-client</artifactId>
+ <version>${netconf.version}</version>
+ <type>test-jar</type>
+ </dependency>
<!--Netconf config-->
<dependency>
<artifactId>protocol_plugins.stub</artifactId>
<version>${protocol_plugins.stub.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>remoterpc-routingtable.implementation</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>routing.dijkstra_implementation</artifactId>
<artifactId>model-inventory</artifactId>
<version>${mdsal.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.model</groupId>
+ <artifactId>model-topology</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.samples</groupId>
+ <artifactId>sample-toaster</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.samples</groupId>
+ <artifactId>sample-toaster-consumer</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.opendaylight.controller.samples</groupId>
+ <artifactId>sample-toaster-provider</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-consumer</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.controller.tests</groupId>
+ <artifactId>sal-remoterpc-connector-test-provider</artifactId>
+ <version>${mdsal.version}</version>
+ </dependency>
<dependency>
<groupId>org.opendaylight.controller.thirdparty</groupId>
<artifactId>com.sun.jersey.jersey-servlet</artifactId>
<artifactId>yang-ext</artifactId>
<version>${yang-ext.version}</version>
</dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>antlr4-runtime-osgi-nohead</artifactId>
+ <version>4.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.yangtools.thirdparty</groupId>
+ <artifactId>xtend-lib-osgi</artifactId>
+ <version>${xtend.version}</version>
+ </dependency>
<dependency>
<groupId>org.openexi</groupId>
<artifactId>nagasena</artifactId>
<artifactId>chameleon-mbeans</artifactId>
<version>1.0.0</version>
</dependency>
+ <dependency>
+ <groupId>org.reflections</groupId>
+ <artifactId>reflections</artifactId>
+ <version>0.9.9-RC1</version>
+ </dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>${slf4j.version}</version>
<scope>compile</scope>
</dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ <version>${slf4j.version}</version>
+ </dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>org.springframework.aop</artifactId>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
+ <version>${lifecycle.mapping.version}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
- <!--
- <dependency>
- <groupId>com.googlecode.json-simple</groupId>
- <artifactId>json-simple</artifactId>
- <version>1.1</version>
- </dependency>
- -->
+
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-client</artifactId>
- <version>${netconf.version}</version>
</dependency>
</dependencies>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
- <version>1.3</version>
+ <version>${maven.antrun.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
<executions>
<execution>
<goals>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.14.1</version>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<parallel>classes</parallel>
<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
- <version>1.0</version>
+ <version>${gmaven.plugin.version}</version>
</plugin>
<plugin>
<groupId>org.opendaylight.yangtools</groupId>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
- <version>2.12</version>
<configuration>
<failsOnError>false</failsOnError>
<failOnViolation>false</failOnViolation>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>threadpool-config-api</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>com.jcabi</groupId>
<artifactId>jcabi-maven-slf4j</artifactId>
- <version>0.8</version>
</dependency>
<dependency>
<dependency>
<groupId>org.codehaus.gmaven.runtime</groupId>
<artifactId>gmaven-runtime-2.0</artifactId>
- <version>1.5</version>
<exclusions>
<exclusion>
<groupId>org.sonatype.gossip</groupId>
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd</artifactId>
- <version>5.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse</groupId>
<artifactId>jdt</artifactId>
- <version>3.3.0-v20070607-1300</version>
<scope>test</scope>
<exclusions>
<dependency>
<groupId>org.eclipse.equinox</groupId>
<artifactId>app</artifactId>
- <version>1.0.0-v20070606</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>core</artifactId>
- <version>3.3.0-v_771</version>
<scope>test</scope>
<exclusions>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-plugin-api</artifactId>
- <version>3.0.5</version>
+ <version>${maven.plugin.api.version}</version>
</dependency>
</dependencies>
</project>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
+ <version>${lifecycle.mapping.version}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
- <artifactId>features-file</artifactId>
+ <artifactId>features-yangtools</artifactId>
<version>${yangtools.version}</version>
<classifier>features</classifier>
<type>xml</type>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
VlanIdBuilder vlanIDBuilder = new VlanIdBuilder();
vlanIDBuilder.setVlanId(new VlanId((NetUtils
.getUnsignedShort((short) vlan.getValue()))));
+ vlanIDBuilder.setVlanIdPresent(true);
vlanMatchBuild.setVlanId(vlanIDBuilder.build());
}
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>flow-management-compatibility</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
*/
package org.opendaylight.controller.md.inventory.manager;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.LinkedBlockingDeque;
+
+import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.opendaylight.yangtools.concepts.Registration;
-import org.opendaylight.yangtools.yang.binding.NotificationListener;
+import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-public class FlowCapableInventoryProvider implements AutoCloseable {
+import com.google.common.base.Preconditions;
+
+class FlowCapableInventoryProvider implements AutoCloseable, Runnable {
+ private static final Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
+ private static final int QUEUE_DEPTH = 500;
+ private static final int MAX_BATCH = 100;
+
+ private final BlockingQueue<InventoryOperation> queue = new LinkedBlockingDeque<>(QUEUE_DEPTH);
+ private final NotificationProviderService notificationService;
+ private final DataProviderService dataService;
+ private Registration<?> listenerRegistration;
+ private Thread thread;
- private final static Logger LOG = LoggerFactory.getLogger(FlowCapableInventoryProvider.class);
+ FlowCapableInventoryProvider(final DataProviderService dataService, final NotificationProviderService notificationService) {
+ this.dataService = Preconditions.checkNotNull(dataService);
+ this.notificationService = Preconditions.checkNotNull(notificationService);
+ }
+
+ void start() {
+ final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
+ this.listenerRegistration = this.notificationService.registerNotificationListener(changeCommiter);
- private DataProviderService dataService;
- private NotificationProviderService notificationService;
- private Registration<NotificationListener> listenerRegistration;
- private final NodeChangeCommiter changeCommiter = new NodeChangeCommiter(FlowCapableInventoryProvider.this);
+ thread = new Thread(this);
+ thread.setDaemon(true);
+ thread.setName("FlowCapableInventoryProvider");
+ thread.start();
- public void start() {
- this.listenerRegistration = this.notificationService.registerNotificationListener(this.changeCommiter);
LOG.info("Flow Capable Inventory Provider started.");
}
- protected DataModificationTransaction startChange() {
- DataProviderService _dataService = this.dataService;
- return _dataService.beginTransaction();
+ void enqueue(final InventoryOperation op) {
+ try {
+ queue.put(op);
+ } catch (InterruptedException e) {
+ LOG.warn("Failed to enqueue operation {}", op, e);
+ }
}
@Override
- public void close() {
- try {
- LOG.info("Flow Capable Inventory Provider stopped.");
- if (this.listenerRegistration != null) {
+ public void close() throws InterruptedException {
+ LOG.info("Flow Capable Inventory Provider stopped.");
+ if (this.listenerRegistration != null) {
+ try {
this.listenerRegistration.close();
+ } catch (Exception e) {
+ LOG.error("Failed to stop inventory provider", e);
}
- } catch (Exception e) {
- String errMsg = "Error by stop Flow Capable Inventory Provider.";
- LOG.error(errMsg, e);
- throw new RuntimeException(errMsg, e);
+ listenerRegistration = null;
}
- }
- public DataProviderService getDataService() {
- return this.dataService;
- }
+ if (thread != null) {
+ thread.interrupt();
+ thread.join();
+ thread = null;
+ }
- public void setDataService(final DataProviderService dataService) {
- this.dataService = dataService;
- }
- public NotificationProviderService getNotificationService() {
- return this.notificationService;
}
- public void setNotificationService(
- final NotificationProviderService notificationService) {
- this.notificationService = notificationService;
+ @Override
+ public void run() {
+ try {
+ for (;;) {
+ InventoryOperation op = queue.take();
+
+ final DataModificationTransaction tx = dataService.beginTransaction();
+ LOG.debug("New operations available, starting transaction {}", tx.getIdentifier());
+
+ int ops = 0;
+ do {
+ op.applyOperation(tx);
+
+ ops++;
+ if (ops < MAX_BATCH) {
+ op = queue.poll();
+ } else {
+ op = null;
+ }
+ } while (op != null);
+
+ LOG.debug("Processed {} operations, submitting transaction {}", ops, tx.getIdentifier());
+
+ try {
+ final RpcResult<TransactionStatus> result = tx.commit().get();
+ if(!result.isSuccessful()) {
+ LOG.error("Transaction {} failed", tx.getIdentifier());
+ }
+ } catch (ExecutionException e) {
+ LOG.warn("Failed to commit inventory change", e.getCause());
+ }
+ }
+ } catch (InterruptedException e) {
+ LOG.info("Processing interrupted, terminating", e);
+ }
+
+ // Drain all events, making sure any blocked threads are unblocked
+ while (!queue.isEmpty()) {
+ queue.poll();
+ }
}
}
import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
public class InventoryActivator extends AbstractBindingAwareProvider {
-
- private static FlowCapableInventoryProvider provider = new FlowCapableInventoryProvider();
+ private static final Logger LOG = LoggerFactory.getLogger(InventoryActivator.class);
+ private FlowCapableInventoryProvider provider;
@Override
public void onSessionInitiated(final ProviderContext session) {
- DataProviderService salDataService = session.<DataProviderService> getSALService(DataProviderService.class);
+ DataProviderService salDataService = session.getSALService(DataProviderService.class);
NotificationProviderService salNotifiService =
- session.<NotificationProviderService> getSALService(NotificationProviderService.class);
- InventoryActivator.provider.setDataService(salDataService);
- InventoryActivator.provider.setNotificationService(salNotifiService);
- InventoryActivator.provider.start();
+ session.getSALService(NotificationProviderService.class);
+
+ provider = new FlowCapableInventoryProvider(salDataService, salNotifiService);
+ provider.start();
}
@Override
protected void stopImpl(final BundleContext context) {
- InventoryActivator.provider.close();
+ if (provider != null) {
+ try {
+ provider.close();
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted while waiting for shutdown", e);
+ }
+ provider = null;
+ }
}
}
--- /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.md.inventory.manager;
+
+import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
+
+interface InventoryOperation {
+
+ void applyOperation(DataModificationTransaction tx);
+
+}
*/
package org.opendaylight.controller.md.inventory.manager;
-import java.util.concurrent.Future;
-
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.binding.api.data.DataModificationTransaction;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNode;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeUpdated;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorId;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRef;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorRemoved;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.NodeConnectorUpdated;
import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.nodes.NodeKey;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.InstanceIdentifierBuilder;
-import org.opendaylight.yangtools.yang.common.RpcResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Objects;
-import com.google.common.util.concurrent.FutureCallback;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.JdkFutureAdapters;
-
-public class NodeChangeCommiter implements OpendaylightInventoryListener {
+import com.google.common.base.Preconditions;
- protected final static Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class);
+class NodeChangeCommiter implements OpendaylightInventoryListener {
+ private static final Logger LOG = LoggerFactory.getLogger(NodeChangeCommiter.class);
private final FlowCapableInventoryProvider manager;
public NodeChangeCommiter(final FlowCapableInventoryProvider manager) {
- this.manager = manager;
- }
-
- public FlowCapableInventoryProvider getManager() {
- return this.manager;
+ this.manager = Preconditions.checkNotNull(manager);
}
@Override
public synchronized void onNodeConnectorRemoved(final NodeConnectorRemoved connector) {
-
- final NodeConnectorRef ref = connector.getNodeConnectorRef();
- final DataModificationTransaction it = this.getManager().startChange();
- LOG.debug("removing node connector {} ", ref.getValue());
- it.removeOperationalData(ref.getValue());
- Future<RpcResult<TransactionStatus>> commitResult = it.commit();
- listenOnTransactionState(it.getIdentifier(), commitResult, "nodeConnector removal", ref.getValue());
+ manager.enqueue(new InventoryOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction tx) {
+ final NodeConnectorRef ref = connector.getNodeConnectorRef();
+ LOG.debug("removing node connector {} ", ref.getValue());
+ tx.removeOperationalData(ref.getValue());
+ }
+ });
}
@Override
public synchronized void onNodeConnectorUpdated(final NodeConnectorUpdated connector) {
-
- final NodeConnectorRef ref = connector.getNodeConnectorRef();
- final FlowCapableNodeConnectorUpdated flowConnector = connector
- .getAugmentation(FlowCapableNodeConnectorUpdated.class);
- final DataModificationTransaction it = this.manager.startChange();
- final NodeConnectorBuilder data = new NodeConnectorBuilder(connector);
- NodeConnectorId id = connector.getId();
- NodeConnectorKey nodeConnectorKey = new NodeConnectorKey(id);
- data.setKey(nodeConnectorKey);
- boolean notEquals = (!Objects.equal(flowConnector, null));
- if (notEquals) {
- final FlowCapableNodeConnector augment = InventoryMapping.toInventoryAugment(flowConnector);
- data.addAugmentation(FlowCapableNodeConnector.class, augment);
- }
- InstanceIdentifier<? extends Object> value = ref.getValue();
- LOG.debug("updating node connector : {}.", value);
- NodeConnector build = data.build();
- it.putOperationalData((value), build);
- Future<RpcResult<TransactionStatus>> commitResult = it.commit();
- listenOnTransactionState(it.getIdentifier(), commitResult, "nodeConnector update", ref.getValue());
+ manager.enqueue(new InventoryOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction tx) {
+ final NodeConnectorRef ref = connector.getNodeConnectorRef();
+ final NodeConnectorBuilder data = new NodeConnectorBuilder(connector);
+ data.setKey(new NodeConnectorKey(connector.getId()));
+
+ final FlowCapableNodeConnectorUpdated flowConnector = connector
+ .getAugmentation(FlowCapableNodeConnectorUpdated.class);
+ if (flowConnector != null) {
+ final FlowCapableNodeConnector augment = InventoryMapping.toInventoryAugment(flowConnector);
+ data.addAugmentation(FlowCapableNodeConnector.class, augment);
+ }
+ InstanceIdentifier<? extends Object> value = ref.getValue();
+ LOG.debug("updating node connector : {}.", value);
+ NodeConnector build = data.build();
+ tx.putOperationalData(value, build);
+ }
+ });
}
@Override
public synchronized void onNodeRemoved(final NodeRemoved node) {
-
- final NodeRef ref = node.getNodeRef();
- final DataModificationTransaction it = this.manager.startChange();
- LOG.debug("removing node : {}", ref.getValue());
- it.removeOperationalData((ref.getValue()));
- Future<RpcResult<TransactionStatus>> commitResult = it.commit();
- listenOnTransactionState(it.getIdentifier(), commitResult, "node removal", ref.getValue());
+ manager.enqueue(new InventoryOperation() {
+ @Override
+ public void applyOperation(final DataModificationTransaction tx) {
+ final NodeRef ref = node.getNodeRef();
+ LOG.debug("removing node : {}", ref.getValue());
+ tx.removeOperationalData((ref.getValue()));
+ }
+ });
}
@Override
public synchronized void onNodeUpdated(final NodeUpdated node) {
-
- final NodeRef ref = node.getNodeRef();
- final FlowCapableNodeUpdated flowNode = node
- .<FlowCapableNodeUpdated> getAugmentation(FlowCapableNodeUpdated.class);
- final DataModificationTransaction it = this.manager.startChange();
- final NodeBuilder nodeBuilder = new NodeBuilder(node);
- nodeBuilder.setKey(new NodeKey(node.getId()));
- boolean equals = Objects.equal(flowNode, null);
- if (equals) {
+ final FlowCapableNodeUpdated flowNode = node.getAugmentation(FlowCapableNodeUpdated.class);
+ if (flowNode == null) {
return;
}
- final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
- nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
- InstanceIdentifier<? extends Object> value = ref.getValue();
- InstanceIdentifierBuilder<Node> builder = ((InstanceIdentifier<Node>) value).builder();
- InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder
- .<FlowCapableNode> augmentation(FlowCapableNode.class);
- final InstanceIdentifier<FlowCapableNode> path = augmentation.build();
- LOG.debug("updating node :{} ", path);
- it.putOperationalData(path, augment);
-
- Future<RpcResult<TransactionStatus>> commitResult = it.commit();
- listenOnTransactionState(it.getIdentifier(), commitResult, "node update", ref.getValue());
- }
-
- /**
- * @param txId transaction identificator
- * @param future transaction result
- * @param action performed by transaction
- * @param nodeConnectorPath target value
- */
- private static void listenOnTransactionState(final Object txId, Future<RpcResult<TransactionStatus>> future,
- final String action, final InstanceIdentifier<?> nodeConnectorPath) {
- Futures.addCallback(JdkFutureAdapters.listenInPoolThread(future),new FutureCallback<RpcResult<TransactionStatus>>() {
-
- @Override
- public void onFailure(Throwable t) {
- LOG.error("Action {} [{}] failed for Tx:{}", action, nodeConnectorPath, txId, t);
-
- }
+ manager.enqueue(new InventoryOperation() {
@Override
- public void onSuccess(RpcResult<TransactionStatus> result) {
- if(!result.isSuccessful()) {
- LOG.error("Action {} [{}] failed for Tx:{}", action, nodeConnectorPath, txId);
- }
+ public void applyOperation(final DataModificationTransaction tx) {
+ final NodeRef ref = node.getNodeRef();
+ final NodeBuilder nodeBuilder = new NodeBuilder(node);
+ nodeBuilder.setKey(new NodeKey(node.getId()));
+
+ final FlowCapableNode augment = InventoryMapping.toInventoryAugment(flowNode);
+ nodeBuilder.addAugmentation(FlowCapableNode.class, augment);
+
+ @SuppressWarnings("unchecked")
+ InstanceIdentifierBuilder<Node> builder = ((InstanceIdentifier<Node>) ref.getValue()).builder();
+ InstanceIdentifierBuilder<FlowCapableNode> augmentation = builder.augmentation(FlowCapableNode.class);
+ final InstanceIdentifier<FlowCapableNode> path = augmentation.build();
+ LOG.debug("updating node :{} ", path);
+ tx.putOperationalData(path, augment);
}
});
}
+++ /dev/null
-module opendaylight-inventory-config {
- namespace "urn:opendaylight:inventory:config";
- prefix inv-config;
-
- import yang-ext {prefix ext; revision-date "2013-07-09";}
- import opendaylight-inventory {prefix inv; revision-date "2013-08-19";}
-
-
- revision "2013-08-19" {
- description "Initial revision of Inventory model";
- }
- /** Base structure **/
- container nodes {
- list node {
- key "id";
- ext:context-instance "node-context";
-
- uses inv:node;
- }
- }
-}
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
+ <version>${lifecycle.mapping.version}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
- <version>2.4.0</version>
+ <version>${findbugs.maven.plugin.version}</version>
<configuration>
<effort>Max</effort>
<threshold>Low</threshold>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jdepend-maven-plugin</artifactId>
- <version>2.0-beta-2</version>
+ <version>${jdepend.maven.plugin.version}</version>
</plugin>
</plugins>
</reporting>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>remoterpc-routingtable.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.implementation</artifactId>
- <version>0.4.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager.it.implementation</artifactId>
- <version>0.5.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.stub</artifactId>
- <version>0.4.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>pax-exam-container-native</artifactId>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <scope>test</scope>
- </dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-link-mvn</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-connector-api</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
- </dependency>
- <dependency>
- <groupId>org.opendaylight.controller</groupId>
- <artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>0.2.3-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
- <version>3.0.0</version>
- </dependency>
- <dependency>
- <groupId>org.ops4j.pax.exam</groupId>
- <artifactId>pax-exam-junit4</artifactId>
- <version>3.0.0</version>
+ <version>${exam.version}</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam</artifactId>
- <version>3.0.0</version>
+ <version>${exam.version}</version>
</dependency>
</dependencies>
<properties>
<parent>
<artifactId>sal-remoterpc-connector-test-parent</artifactId>
<groupId>org.opendaylight.controller.tests</groupId>
- <version>1.0-SNAPSHOT</version>
+ <version>1.1-SNAPSHOT</version>
</parent>
<artifactId>remoterpc-routingtable-nb-it</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.northbound</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>remoterpc-routingtable.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
- <version>0.9.9-RC1</version>
<scope>compile</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
- <version>1.7.2</version>
<scope>test</scope>
</dependency>
</dependencies>
<artifactId>sal-binding-it</artifactId>
<properties>
- <exam.version>3.0.0</exam.version>
<sonar.jacoco.itReportPath>../sal-binding-broker/target/jacoco-it.exec</sonar.jacoco.itReportPath>
<!-- Sonar jacoco plugin to get integration test coverage info -->
<sonar.jacoco.reportPath>../sal-binding-broker/target/jacoco.exec</sonar.jacoco.reportPath>
- <url.version>1.5.0</url.version>
</properties>
<dependencies>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
</dependency>
<!--Compile scopes for all testing dependencies are intentional-->
<!--This way, all testing dependencies can be transitively used by other integration test modules-->
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.openexi</groupId>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
+ <version>${lifecycle.mapping.version}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
- <version>2.14.1</version>
<configuration>
<reuseForks>false</reuseForks>
</configuration>
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
<executions>
<execution>
<id>generate-config</id>
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.concepts.Path;
+/**
+ *
+ * Provides access to a conceptual data tree store.
+ *
+ * <p>
+ * Also provides the ability to subscribe for changes to data under a given
+ * branch of the tree.
+ *
+ * <p>
+ * All operations on data tree are performed via one of the transactions:
+ * <ul>
+ * <li>Read-Only - allocated using {@link #newReadOnlyTransaction()}
+ * <li>Write-Only - allocated using {@link #newWriteOnlyTransaction()}
+ * <li>Read-Write - allocated using {@link #newReadWriteTransaction()}
+ * </ul>
+ *
+ * <p>
+ * These transactions provide a stable isolated view of data tree, which is
+ * guaranteed to be not affected by other concurrent transactions, until
+ * transaction is committed.
+ *
+ * <p>
+ * For a detailed explanation of how transaction are isolated and how transaction-local
+ * changes are committed to global data tree, see
+ * {@link AsyncReadTransaction}, {@link AsyncWriteTransaction},
+ * {@link AsyncReadWriteTransaction} and {@link AsyncWriteTransaction#commit()}.
+ *
+ *
+ * <p>
+ * It is strongly recommended to use the type of transaction, which
+ * provides only the minimal capabilities you need. This allows for
+ * optimizations at the data broker / data store level. For example,
+ * implementations may optimize the transaction for reading if they know ahead
+ * of time that you only need to read data - such as not keeping additional meta-data,
+ * which may be required for write transactions.
+ *
+ * <p>
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
public interface AsyncDataBroker<P extends Path<P>, D, L extends AsyncDataChangeListener<P, D>> extends //
AsyncDataTransactionFactory<P, D> {
*
* Scope of Data Change
*
+ * <p>
* Represents scope of data change (addition, replacement, deletion).
*
- * The terminology for types is reused from LDAP
+ * The terminology for scope types is reused from LDAP.
+ *
+ * <h2>Examples</h2>
+ *
+ * Following is an example model with comments describing what notifications
+ * you would receive based on the scope you specify, when you are
+ * registering for changes on container a.
*
- * @see http://www.idevelopment.info/data/LDAP/LDAP_Resources/SEARCH_Setting_the_SCOPE_Parameter.shtml
+ * <pre>
+ * container a // scope BASE, ONE, SUBTREE
+ * leaf "foo" // scope ONE, SUBTREE
+ * container // scope ONE, SUBTREE
+ * leaf "bar" // scope SUBTREE
+ * list list // scope ONE, SUBTREE
+ * list [a] // scope SUBTREE
+ * id "a" // scope SUBTREE
+ * list [b] // scope SUBTREE
+ * id "b" // scope SUBTREE
+ * </pre>
+ *
+ * Following is an example model with comments describing what notifications
+ * you would receive based on the scope you specify, when you are
+ * registering for changes on list list (without specifying concrete item in
+ * the list).
+ *
+ * <pre>
+ * list list // scope BASE, ONE, SUBTREE
+ * list [a] // scope ONE, SUBTREE
+ * id "a" // scope SUBTREE
+ * list [b] // scope ONE, SUBTREE
+ * id "b" // scope SUBTREE
+ * </pre>
+ *
+ *
+ * @see http://www.idevelopment.info/data/LDAP/LDAP_Resources/
+ * SEARCH_Setting_the_SCOPE_Parameter.shtml
*/
public enum DataChangeScope {
- /**
- * Represents only a direct change of the node, such as replacement of node,
- * addition or deletion.
- *
- */
- BASE,
- /**
- * Represent a change (addition,replacement,deletion)
- * of the node or one of it's direct childs.
- *
- */
- ONE,
- /**
- * Represents a change of the node or any of it's child nodes.
- *
- */
- SUBTREE
+ /**
+ * Represents only a direct change of the node, such as replacement of a
+ * node, addition or deletion.
+ *
+ */
+ BASE,
+ /**
+ * Represent a change (addition,replacement,deletion) of the node or one
+ * of its direct children.
+ *
+ * This scope is superset of {@link #BASE}.
+ *
+ */
+ ONE,
+ /**
+ * Represents a change of the node or any of or any of its child nodes,
+ * direct and nested.
+ *
+ * This scope is superset of {@link #ONE} and {@link #BASE}.
+ *
+ */
+ SUBTREE
}
+ /**
+ * {@inheritDoc}
+ */
@Override
public AsyncReadTransaction<P, D> newReadOnlyTransaction();
+ /**
+ * {@inheritDoc}
+ */
@Override
- public AsyncReadWriteTransaction<P,D> newReadWriteTransaction();
+ public AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
+ /**
+ * {@inheritDoc}
+ */
@Override
public AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
/**
- * Registers {@link DataChangeListener} for Data Change callbacks
- * which will be triggered on which will be triggered on the store
+ * Registers a {@link AsyncDataChangeListener} to receive
+ * notifications when data changes under a given path in the conceptual data
+ * tree.
+ * <p>
+ * You are able to register for notifications for any node or subtree
+ * which can be reached via the supplied path.
+ * <p>
+ * If path type <code>P</code> allows it, you may specify paths up to the leaf nodes
+ * then it is possible to listen on leaf nodes.
+ * <p>
+ * You are able to register for data change notifications for a subtree even
+ * if it does not exist. You will receive notification once that node is
+ * created.
+ * <p>
+ * If there is any preexisting data in data tree on path for which you are
+ * registering, you will receive initial data change event, which will
+ * contain all preexisting data, marked as created.
+ *
+ * <p>
+ * You are also able to specify the scope of the changes you want to be
+ * notified.
+ * <p>
+ * Supported scopes are:
+ * <ul>
+ * <li>{@link DataChangeScope#BASE} - notification events will only be
+ * triggered when a node referenced by path is created, removed or replaced.
+ * <li>{@link DataChangeScope#ONE} - notifications events will only be
+ * triggered when a node referenced by path is created, removed or replaced,
+ * or any or any of its immediate children are created, updated or removed.
+ * <li>{@link DataChangeScope#SUBTREE} - notification events will be
+ * triggered when a node referenced by the path is created, removed
+ * or replaced or any of the children in its subtree are created, removed
+ * or replaced.
+ * </ul>
+ * See {@link DataChangeScope} for examples.
+ * <p>
+ * This method returns a {@link ListenerRegistration} object. To
+ * "unregister" your listener for changes call the "close" method on this
+ * returned object.
+ * <p>
+ * You MUST call close when you no longer need to receive notifications
+ * (such as during shutdown or for example if your bundle is shutting down).
*
- *Â @param store Logical store in which listener is registered.
- * @param path Path (subtree identifier) on which client listener will be invoked.
- * @param listener Instance of listener which should be invoked on
- * @param triggeringScope Scope of change which triggers callback.
- * @return Listener registration of the listener, call {@link ListenerRegistration#close()}
- * to stop delivery of change events.
+ * @param store
+ * Logical Data Store - Logical Datastore you want to listen for
+ * changes in. For example
+ * {@link LogicalDatastoreType#OPERATIONAL} or
+ * {@link LogicalDatastoreType#CONFIGURATION}
+ * @param path
+ * Path (subtree identifier) on which client listener will be
+ * invoked.
+ * @param listener
+ * Instance of listener which should be invoked on
+ * @param triggeringScope
+ * Scope of change which triggers callback.
+ * @return Listener registration object, which may be used to unregister
+ * your listener using {@link ListenerRegistration#close()} to stop
+ * delivery of change events.
*/
- ListenerRegistration<L> registerDataChangeListener(LogicalDatastoreType store, P path, L listener, DataChangeScope triggeringScope);
+ ListenerRegistration<L> registerDataChangeListener(LogicalDatastoreType store, P path, L listener,
+ DataChangeScope triggeringScope);
}
import org.opendaylight.yangtools.concepts.Immutable;
import org.opendaylight.yangtools.concepts.Path;
-public interface AsyncDataChangeEvent<P extends Path<P>,D> extends Immutable {
+/**
+ *
+ * An event which contains a capture of changes in a data subtree
+ *
+ * <p>
+ * Represents a notification indicating that some data at or under a particular
+ * path has changed. The notification contains a capture of the changes in the data
+ * subtree. This event is triggered by successful application of modifications
+ * from a transaction on the global data tree. Use the
+ * {@link AsyncDataBroker#registerDataChangeListener(LogicalDatastoreType, Path, AsyncDataChangeListener, AsyncDataBroker.DataChangeScope)}
+ * method to register a listener for data change events.
+ *
+ * <p>
+ * A listener will only receive notifications for changes to data under the path
+ * they register for. See
+ * {@link AsyncDataBroker#registerDataChangeListener(LogicalDatastoreType, Path, AsyncDataChangeListener, AsyncDataBroker.DataChangeScope)}
+ * to learn more about registration scopes.
+ *
+ * <p>
+ * The entire subtree under the path will be provided via instance methods of Data
+ * Change Event even if just a leaf node changes.
+ *
+ * <p>
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
+public interface AsyncDataChangeEvent<P extends Path<P>, D> extends Immutable {
/**
- * Returns a immutable map of paths and newly created objects
+ * Returns a map of paths and newly created objects, which were introduced by
+ * this change into conceptual data tree, if no new objects were introduced
+ * this map will be empty.
+ *<p>
+ * This map contains all data tree nodes (and paths to them) which were created
+ * and are in the scope of listener registration. The data tree nodes
+ * contain their whole subtree with their current state.
*
* @return map of paths and newly created objects
*/
Map<P, D> getCreatedData();
/**
- * Returns a immutable map of paths and respective updated objects after update.
- *
- * Original state of the object is in
- * {@link #getOriginalData()}
+ * Returns a map of paths and objects which were updated by this change in the
+ * conceptual data tree if no existing objects were updated
+ * this map will be empty.
+ *<p>
+ * This map contains all data tree nodes (and paths to them) which were updated
+ * and are in the scope of listener registration. The data tree nodes
+ * contain their whole subtree with their current state.
+ *<p>
+ * A Node is considered updated if it contents were replaced or one of its
+ * children was created, removed or updated.
+ *<p>
+ * Original state of the updated data tree nodes is in
+ * {@link #getOriginalData()} stored with same path.
*
* @return map of paths and newly created objects
*/
Map<P, D> getUpdatedData();
/**
- * Returns a immutable set of removed paths.
- *
- * Original state of the object is in
- * {@link #getOriginalData()}
+ * Returns an immutable set of removed paths.
+ *<p>
+ * This set contains the paths to the data tree nodes which are in the scope
+ * of the listener registration that have been removed.
+ *<p>
+ * Original state of the removed data tree nodes is in
+ * {@link #getOriginalData()} stored with same path.
*
* @return set of removed paths
*/
Set<P> getRemovedPaths();
/**
- * Return a immutable map of paths and original state of updated and removed objects.
+ * Returns an immutable map of updated or removed paths and their original
+ * states prior to this change.
*
- * This map is populated if at changed path was previous object, and captures
- * state of previous object.
+ *<p>
+ * This map contains the original version of the data tree nodes (and paths
+ * to them), which are in the scope of the listener registration.
*
* @return map of paths and original state of updated and removed objects.
*/
Map<P, ? extends D> getOriginalData();
/**
- * Returns a immutable stable view of data state, which
- * captures state of data store before the reported change.
+ * Returns an immutable stable view of data state, which captures the state of
+ * data store before the reported change.
*
+ *<p>
+ * The view is rooted at the point where the listener, to which the event is
+ * being delivered, was registered.
+ *<p>
+ * If listener used a wildcarded path (if supported by path type) during
+ * registration for change listeners this method returns null, and original
+ * state can be accessed only via {@link #getOriginalData()}
*
- * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
- *
- * @return Stable view of data before the change happened, rooted at the listener registration path.
+ * @return Stable view of data before the change happened, rooted at the
+ * listener registration path.
*
*/
D getOriginalSubtree();
/**
- * Returns a immutable stable view of data, which captures state of data store
- * after the reported change.
- *
- * The view is rooted at the point where the listener, to which the event is being delivered, was registered.
+ * Returns an immutable stable view of data, which captures the state of data
+ * store after the reported change.
+ *<p>
+ * The view is rooted at the point where the listener, to which the event is
+ * being delivered, was registered.
+ *<p>
+ * If listener used a wildcarded path (if supported by path type) during
+ * registration for change listeners this method returns null, and state
+ * can be accessed only via {@link #getCreatedData()},
+ * {@link #getUpdatedData()}, {@link #getRemovedPaths()}
*
- * @return Stable view of data after the change happened, rooted at the listener registration path.
+ * @return Stable view of data after the change happened, rooted at the
+ * listener registration path.
*/
D getUpdatedSubtree();
}
import org.opendaylight.yangtools.concepts.Path;
+/**
+ * Listener of data change events on particular subtree.
+ *
+ * <p>
+ * User-supplied implementations of this listener interface MUST register via
+ * {@link AsyncDataBroker#registerDataChangeListener(LogicalDatastoreType, Path, AsyncDataChangeListener, AsyncDataBroker.DataChangeScope)}
+ * in order to start receiving data change events, which capture state changes
+ * in a subtree.
+ *
+ * <p>
+ * <b>Implementation Note:</b> This interface is intended to be implemented
+ * by users of MD-SAL.
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
public interface AsyncDataChangeListener<P extends Path<P>, D> extends EventListener {
/**
- * Note that this method may be invoked from a shared thread pool, so
+ *
+ * Invoked when there is data change for the particular path, which was used to
+ * register this listener.
+ * <p>
+ * This method may be also invoked during registration of the listener if
+ * there is any preexisting data in the conceptual data tree for supplied path.
+ * This initial event will contain all preexisting data as created.
+ *
+ * <p>
+ * <b>Note</b> that this method may be invoked from a shared thread pool, so
* implementations SHOULD NOT perform CPU-intensive operations and they
* definitely MUST NOT invoke any potentially blocking operations.
*
- * @param change Data Change Event being delivered.
+ * @param change
+ * Data Change Event being delivered.
*/
void onDataChanged(AsyncDataChangeEvent<P, D> change);
}
import org.opendaylight.yangtools.concepts.Path;
+/**
+ * A factory which allocates new transactions to operate on the data
+ * tree.
+ *
+ * <p>
+ * <b>Note:</b> This interface is not intended to be used directly, but rather
+ * via subinterfaces which introduces additional semantics to allocated
+ * transactions.
+ * <ul>
+ * <li> {@link AsyncDataBroker}
+ * <li> {@link TransactionChain}
+ * </ul>
+ *
+ * <p>
+ * All operations on the data tree are performed via one of the transactions:
+ * <ul>
+ * <li>Read-Only - allocated using {@link #newReadOnlyTransaction()}
+ * <li>Write-Only - allocated using {@link #newWriteOnlyTransaction()}
+ * <li>Read-Write - allocated using {@link #newReadWriteTransaction()}
+ * </ul>
+ *
+ * <p>
+ * These transactions provides a stable isolated view of the data tree, which is
+ * guaranteed to be not affected by other concurrent transactions, until
+ * transaction is committed.
+ *
+ * <p>
+ * For a detailed explanation of how transaction are isolated and how transaction-local
+ * changes are committed to global data tree, see
+ * {@link AsyncReadTransaction}, {@link AsyncWriteTransaction},
+ * {@link AsyncReadWriteTransaction} and {@link AsyncWriteTransaction#commit()}.
+ *
+ * <p>
+ * It is strongly recommended to use the type of transaction, which
+ * provides only the minimal capabilities you need. This allows for
+ * optimizations at the data broker / data store level. For example,
+ * implementations may optimize the transaction for reading if they know ahead
+ * of time that you only need to read data - such as not keeping additional meta-data,
+ * which may be required for write transactions.
+ *<p>
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * @see AsyncDataBroker
+ * @see TransactionChain
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
public interface AsyncDataTransactionFactory<P extends Path<P>, D> {
+ /**
+ * Allocates a new read-only transaction which provides an immutable snapshot of
+ * the data tree.
+ *<p>
+ * The view of data tree is an immutable snapshot of current data tree state when
+ * transaction was allocated.
+ *
+ * @return new read-only transaction
+ */
AsyncReadTransaction<P, D> newReadOnlyTransaction();
+ /**
+ * Allocates new read-write transaction which provides a mutable view of the data
+ * tree.
+ *
+ * <p>
+ * Preconditions for mutation of data tree are captured from the snapshot of
+ * data tree state, when the transaction is allocated. If data was
+ * changed during transaction in an incompatible way then the commit of this transaction
+ * will fail. See {@link AsyncWriteTransaction#commit()} for more
+ * details about conflicting and not-conflicting changes and
+ * failure scenarios.
+ *
+ * @return new read-write transaction
+ */
AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
- AsyncWriteTransaction<P,D> newWriteOnlyTransaction();
+ /**
+ * Allocates new write-only transaction based on latest state of data
+ * tree.
+ *
+ * <p>
+ * Preconditions for mutation of data tree are captured from the snapshot of
+ * data tree state, when the transaction is allocated. If data was
+ * changed during transaction in an incompatible way then the commit of this transaction
+ * will fail. See {@link AsyncWriteTransaction#commit()} for more
+ * details about conflicting and not-conflicting changes and
+ * failure scenarios.
+ *
+ * <p>
+ * Since this transaction does not provide a view of the data it SHOULD BE
+ * used only by callers which are exclusive writers (exporters of data)
+ * to the subtree they modify. This prevents optimistic
+ * lock failures as described in {@link AsyncWriteTransaction#commit()}.
+ * <p>
+ * Exclusivity of writers to particular subtree SHOULD BE enforced by
+ * external locking mechanism.
+ *
+ * @return new write-only transaction
+ */
+ AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
}
import com.google.common.base.Optional;
import com.google.common.util.concurrent.ListenableFuture;
+/**
+ *
+ * Provides a stateful read-only view of the data tree.
+ *
+ * <p>
+ * View of the data tree is a stable point-in-time snapshot of the current data tree state when
+ * the transaction was created. It's state and underlying data tree
+ * is not affected by other concurrently running transactions.
+ *
+ * <p>
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * <h2>Transaction isolation example</h2> Lest assume initial state of data tree
+ * for <code>PATH</code> is <code>A</code>.
+ *
+ * <pre>
+ * txRead = broker.newReadOnlyTransaction(); // read Transaction is snapshot of data
+ * txWrite = broker.newReadWriteTransactoin(); // concurrent write transaction
+ *
+ * txRead.read(OPERATIONAL,PATH).get(); // will return Optional containing A
+ * txWrite = broker.put(OPERATIONAL,PATH,B); // writes B to PATH
+ *
+ * txRead.read(OPERATIONAL,PATH).get(); // still returns Optional containing A
+ *
+ * txWrite.commit().get(); // data tree is updated, PATH contains B
+ * txRead.read(OPERATIONAL,PATH).get(); // still returns Optional containing A
+ *
+ * txAfterCommit = broker.newReadOnlyTransaction(); // read Transaction is snapshot of new state
+ * txAfterCommit.read(OPERATIONAL,PATH).get(); // returns Optional containing B;
+ * </pre>
+ *
+ * <p>
+ * <b>Note:</b> example contains blocking calls on future only to illustrate
+ * that action happened after other asynchronous action. Use of blocking call
+ * {@link ListenableFuture#get()} is discouraged for most uses and you should
+ * use
+ * {@link com.google.common.util.concurrent.Futures#addCallback(ListenableFuture, com.google.common.util.concurrent.FutureCallback)}
+ * or other functions from {@link com.google.common.util.concurrent.Futures} to
+ * register more specific listeners.
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
public interface AsyncReadTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
/**
*
- * Reads data from provided logical data store located at provided path
- *
+ * Reads data from provided logical data store located at the provided path.
+ *<p>
+ * If the target is a subtree, then the whole subtree is read (and will be
+ * accessible from the returned data object).
*
* @param store
* Logical data store from which read should occur.
* read
* @return Listenable Future which contains read result
* <ul>
- * <li>If data at supplied path exists the {@link Future#get()}
- * returns Optional object containing data
+ * <li>If data at supplied path exists the
+ * {@link ListeblaFuture#get()} returns Optional object containing
+ * data once read is done.
* <li>If data at supplied path does not exists the
- * {@link Future#get()} returns {@link Optional#absent()}.
+ * {@link ListenbleFuture#get()} returns {@link Optional#absent()}.
* </ul>
*/
ListenableFuture<Optional<D>> read(LogicalDatastoreType store, P path);
import org.opendaylight.yangtools.concepts.Path;
/**
- * Transaction enabling client to have combined transaction,
- * which provides read and write capabilities.
+ * Transaction enabling a client to have a combined read/write capabilities.
*
+ * <p>
+ * The initial state of the write transaction is stable snapshot of current data tree
+ * state captured when transaction was created and it's state and underlying
+ * data tree are not affected by other concurrently running transactions.
*
- * @param <P> Path Type
- * @param <D> Data Type
+ * <p>
+ * Write transactions are isolated from other concurrent write transactions. All
+ * writes are local to the transaction and represents only a proposal of state
+ * change for data tree and it is not visible to any other concurrently running
+ * transactions.
+ *
+ * <p>
+ * Applications publish the changes proposed in the transaction by calling {@link #commit}
+ * on the transaction. This seals the transaction
+ * (preventing any further writes using this transaction) and submits it to be
+ * processed and applied to global conceptual data tree.
+ *
+ * <p>
+ * The transaction commit may fail due to a concurrent transaction modifying and committing data in
+ * an incompatible way. See {@link #commit()} for more concrete commit failure examples.
+ *
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * <h2>Examples</h2>
+ *
+ * <h3>Transaction local state</h3>
+ *
+ * Let assume initial state of data tree for <code>PATH</code> is <code>A</code>
+ * .
+ *
+ * <pre>
+ * txWrite = broker.newReadWriteTransaction(); // concurrent write transaction
+ *
+ * txWrite.read(OPERATIONAL,PATH).get() // will return Optional containing A
+ * txWrite.put(OPERATIONAL,PATH,B); // writes B to PATH
+ * txWrite.read(OPERATIONAL,PATH).get() // will return Optional Containing B
+ *
+ * txWrite.commit().get(); // data tree is updated, PATH contains B
+ *
+ * tx1afterCommit = broker.newReadOnlyTransaction(); // read Transaction is snapshot of new state
+ * tx1afterCommit.read(OPERATIONAL,PATH).get(); // returns Optional containing B
+ * </pre>
+ *
+ * As you could see read-write transaction provides capabilities as
+ * {@link AsyncWriteTransaction} but also allows for reading proposed changes as
+ * if they already happened.
+ *
+ * <h3>Transaction isolation (read transaction, read-write transaction)</h3> Let
+ * assume initial state of data tree for <code>PATH</code> is <code>A</code>.
+ *
+ * <pre>
+ * txRead = broker.newReadOnlyTransaction(); // read Transaction is snapshot of data
+ * txWrite = broker.newReadWriteTransaction(); // concurrent write transaction
+ *
+ * txRead.read(OPERATIONAL,PATH).get(); // will return Optional containing A
+ * txWrite.read(OPERATIONAL,PATH).get() // will return Optional containing A
+ *
+ * txWrite.put(OPERATIONAL,PATH,B); // writes B to PATH
+ * txWrite.read(OPERATIONAL,PATH).get() // will return Optional Containing B
+ *
+ * txRead.read(OPERATIONAL,PATH).get(); // concurrent read transaction still returns
+ * // Optional containing A
+ *
+ * txWrite.commit().get(); // data tree is updated, PATH contains B
+ * txRead.read(OPERATIONAL,PATH).get(); // still returns Optional containing A
+ *
+ * tx1afterCommit = broker.newReadOnlyTransaction(); // read Transaction is snapshot of new state
+ * tx1afterCommit.read(OPERATIONAL,PATH).get(); // returns Optional containing B
+ * </pre>
+ *
+ * <h3>Transaction isolation (2 concurrent read-write transactions)</h3> Let
+ * assume initial state of data tree for <code>PATH</code> is <code>A</code>.
+ *
+ * <pre>
+ * tx1 = broker.newReadWriteTransaction(); // read Transaction is snapshot of data
+ * tx2 = broker.newReadWriteTransaction(); // concurrent write transaction
+ *
+ * tx1.read(OPERATIONAL,PATH).get(); // will return Optional containing A
+ * tx2.read(OPERATIONAL,PATH).get() // will return Optional containing A
+ *
+ * tx2.put(OPERATIONAL,PATH,B); // writes B to PATH
+ * tx2.read(OPERATIONAL,PATH).get() // will return Optional Containing B
+ *
+ * tx1.read(OPERATIONAL,PATH).get(); // tx1 read-write transaction still sees Optional
+ * // containing A since is isolated from tx2
+ * tx1.put(OPERATIONAL,PATH,C); // writes C to PATH
+ * tx1.read(OPERATIONAL,PATH).get() // will return Optional Containing C
+ *
+ * tx2.read(OPERATIONAL,PATH).get() // tx2 read-write transaction still sees Optional
+ * // containing B since is isolated from tx1
+ *
+ * tx2.commit().get(); // data tree is updated, PATH contains B
+ * tx1.read(OPERATIONAL,PATH).get(); // still returns Optional containing C since is isolated from tx2
+ *
+ * tx1afterCommit = broker.newReadOnlyTransaction(); // read Transaction is snapshot of new state
+ * tx1afterCommit.read(OPERATIONAL,PATH).get(); // returns Optional containing B
+ *
+ * tx1.commit() // Will fail with OptimisticLockFailedException
+ * // which means concurrent transaction changed the same PATH
+ *
+ * </pre>
+ *
+ * <p>
+ * <b>Note:</b> examples contains blocking calls on future only to illustrate
+ * that action happened after other asynchronous action. Use of blocking call
+ * {@link com.google.common.util.concurrent.ListenableFuture#get()} is discouraged for most uses and you should
+ * use
+ * {@link com.google.common.util.concurrent.Futures#addCallback(com.google.common.util.concurrent.ListenableFuture, com.google.common.util.concurrent.FutureCallback)}
+ * or other functions from {@link com.google.common.util.concurrent.Futures} to
+ * register more specific listeners.
+ *
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
*/
public interface AsyncReadWriteTransaction<P extends Path<P>, D> extends AsyncReadTransaction<P, D>,
AsyncWriteTransaction<P, D> {
/**
*
- * @author
+ * A common parent for all transactions which operate on a conceptual data tree.
+ *
+ * See derived transaction types for more concrete behavior:
+ * <ul>
+ * <li>{@link AsyncReadTransaction} - Read capabilities, user is able to read data from data tree</li>
+ * <li>{@link AsyncWriteTransaction} - Write capabilities, user is able to propose changes to data tree</li>
+ * <li>{@link AsyncReadWriteTransaction} - Read and Write capabilities, user is able to read state and to propose changes of state.</li>
+ * </ul>
+ *
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL.
*
* @param <P> Type of path (subtree identifier), which represents location in tree
* @param <D> Type of data (payload), which represents data payload
import com.google.common.util.concurrent.ListenableFuture;
-public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
+/**
+ * Write transaction provides mutation capabilities for a data tree.
+ *
+ * <p>
+ * Initial state of write transaction is a stable snapshot of the current data tree.
+ * The state is captured when the transaction is created and its state and underlying
+ * data tree are not affected by other concurrently running transactions.
+ * <p>
+ * Write transactions are isolated from other concurrent write transactions. All
+ * writes are local to the transaction and represent only a proposal of state
+ * change for the data tree and it is not visible to any other concurrently running
+ * transaction.
+ * <p>
+ * Applications publish the changes proposed in the transaction by calling {@link #commit}
+ * on the transaction. This seals the transaction
+ * (preventing any further writes using this transaction) and submits it to be
+ * processed and applied to global conceptual data tree.
+ * <p>
+ * The transaction commit may fail due to a concurrent transaction modifying and committing data in
+ * an incompatible way. See {@link #commit()} for more concrete commit failure examples.
+ *
+ *
+ * <p>
+ * <b>Implementation Note:</b> This interface is not intended to be implemented
+ * by users of MD-SAL, but only to be consumed by them.
+ *
+ * @param <P>
+ * Type of path (subtree identifier), which represents location in
+ * tree
+ * @param <D>
+ * Type of data (payload), which represents data payload
+ */
+public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
/**
- * Cancels transaction.
+ * Cancels the transaction.
*
- * Transaction could be only cancelled if it's status
- * is {@link TransactionStatus#NEW} or {@link TransactionStatus#SUBMITED}
+ * Transactions can only be cancelled if it's status is
+ * {@link TransactionStatus#NEW} or {@link TransactionStatus#SUBMITED}
*
- * Invoking cancel() on {@link TransactionStatus#FAILED} or {@link TransactionStatus#CANCELED}
- * will have no effect.
+ * Invoking cancel() on {@link TransactionStatus#FAILED} or
+ * {@link TransactionStatus#CANCELED} will have no effect.
*
- * @throws IllegalStateException If transaction status is {@link TransactionStatus#COMMITED}
+ * @throws IllegalStateException
+ * If transaction status is {@link TransactionStatus#COMMITED}
*
*/
public void cancel();
/**
- * Store a piece of data at specified path. This acts as a add / replace operation,
- * which is to say that whole subtree will be replaced by specified path.
+ * Store a piece of data at specified path. This acts as an add / replace
+ * operation, which is to say that whole subtree will be replaced by
+ * specified path. Performing the following put operations:
+ *
+ * <pre>
+ * 1) container { list [ a ] }
+ * 2) container { list [ b ] }
+ * </pre>
+ *
+ * will result in the following data being present:
+ *
+ * <pre>
+ * container { list [ b ] }
+ * </pre>
*
- * If you need add or merge of current object with specified use {@link #merge(LogicalDatastoreType, Path, Object)}
*
- * @param store Logical data store which should be modified
- * @param path Data object path
- * @param data Data object to be written to specified path
- * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+ * If you need to make sure that a parent object exists, but you do not want modify
+ * its preexisting state by using put, consider using
+ * {@link #merge(LogicalDatastoreType, Path, Object)}
+ *
+ * @param store
+ * Logical data store which should be modified
+ * @param path
+ * Data object path
+ * @param data
+ * Data object to be written to specified path
+ * @throws IllegalStateException
+ * if the transaction is no longer {@link TransactionStatus#NEW}
*/
public void put(LogicalDatastoreType store, P path, D data);
/**
- * Store a piece of data at specified path. This acts as a merge operation,
+ * Store a piece of data at the specified path. This acts as a merge operation,
* which is to say that any pre-existing data which is not explicitly
* overwritten will be preserved. This means that if you store a container,
- * its child lists will be merged. Performing the following put operations:
+ * its child lists will be merged. Performing the following merge
+ * operations:
*
+ * <pre>
* 1) container { list [ a ] }
* 2) container { list [ b ] }
+ * </pre>
*
* will result in the following data being present:
*
+ * <pre>
* container { list [ a, b ] }
+ * </pre>
*
- * This also means that storing the container will preserve any augmentations
- * which have been attached to it.
- *
- * If you require an explicit replace operation, use {@link #put(LogicalDatastoreType, Path, Object)} instead.
+ * This also means that storing the container will preserve any
+ * augmentations which have been attached to it.
+ *<p>
+ * If you require an explicit replace operation, use
+ * {@link #put(LogicalDatastoreType, Path, Object)} instead.
*
- * @param store Logical data store which should be modified
- * @param path Data object path
- * @param data Data object to be written to specified path
- * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+ * @param store
+ * Logical data store which should be modified
+ * @param path
+ * Data object path
+ * @param data
+ * Data object to be written to specified path
+ * @throws IllegalStateException
+ * if the transaction is no longer {@link TransactionStatus#NEW}
*/
public void merge(LogicalDatastoreType store, P path, D data);
* Remove a piece of data from specified path. This operation does not fail
* if the specified path does not exist.
*
- * @param store Logical data store which should be modified
- * @param path Data object path
- * @throws IllegalStateException if the transaction is no longer {@link TransactionStatus#NEW}
+ * @param store
+ * Logical data store which should be modified
+ * @param path
+ * Data object path
+ * @throws IllegalStateException
+ * if the transaction is no longer {@link TransactionStatus#NEW}
*/
public void delete(LogicalDatastoreType store, P path);
*
* Closes transaction and resources allocated to the transaction.
*
- * This call does not change Transaction status. Client SHOULD
- * explicitly {@link #commit()} or {@link #cancel()} transaction.
+ * This call does not change Transaction status. Client SHOULD explicitly
+ * {@link #commit()} or {@link #cancel()} transaction.
*
- * @throws IllegalStateException if the transaction has not been
- * updated by invoking {@link #commit()} or {@link #cancel()}.
+ * @throws IllegalStateException
+ * if the transaction has not been updated by invoking
+ * {@link #commit()} or {@link #cancel()}.
*/
@Override
public void close();
/**
- * Initiates a commit of modification. This call logically seals the
- * transaction, preventing any the client from interacting with the
- * data stores. The transaction is marked as {@link TransactionStatus#SUBMITED}
- * and enqueued into the data store backed for processing.
+ * Submits transaction to be applied to update logical data tree.
+ * <p>
+ * This call logically seals the transaction, which prevents the client from
+ * further changing data tree using this transaction. Any subsequent calls to
+ * {@link #put(LogicalDatastoreType, Path, Object)},
+ * {@link #merge(LogicalDatastoreType, Path, Object)} or
+ * {@link #delete(LogicalDatastoreType, Path)} will fail with
+ * {@link IllegalStateException}.
+ *
+ * The transaction is marked as {@link TransactionStatus#SUBMITED} and
+ * enqueued into the data store backed for processing.
*
* <p>
- * The successful commit changes the state of the system and may affect
- * several components.
+ * Whether or not the commit is successful is determined by versioning
+ * of data tree and validation of registered commit participants
+ * {@link AsyncConfigurationCommitHandler}
+ * if transaction changes {@link LogicalDatastoreType#CONFIGURATION} data tree.
+ *<p>
+ * The effects of successful commit of data depends on
+ * other data change listeners {@link AsyncDataChangeListener} and
+ * {@link AsyncConfigurationCommitHandler}, which was registered to the
+ * same {@link AsyncDataBroker}, to which this transaction belongs.
*
+ * <h2>Failure scenarios</h2>
* <p>
- * The effects of successful commit of data are described in the
- * specifications and YANG models describing the Provider components of
- * controller. It is assumed that Consumer has an understanding of this
- * changes.
- *
- * @see DataCommitHandler for further information how two-phase commit is
- * processed.
- * @param store Identifier of the store, where commit should occur.
+ * Transaction may fail because of multiple reasons, such as
+ * <ul>
+ * <li>Another transaction finished earlier and modified the same node in
+ * non-compatible way (see below). In this case the returned future will fail with
+ * {@link OptimisticLockFailedException}. It is the responsibility of the
+ * caller to create a new transaction and submit the same modification again in
+ * order to update data tree.</li>
+ * <li>Data change introduced by this transaction did not pass validation by
+ * commit handlers or data was incorrectly structured. Returned future will
+ * fail with {@link DataValidationFailedException}. User should not retry to
+ * create new transaction with same data, since it probably will fail again.
+ * </li>
+ * </ul>
+ *
+ * <h3>Change compatibility</h3>
+ *
+ * There are several sets of changes which could be considered incompatible
+ * between two transactions which are derived from same initial state.
+ * Rules for conflict detection applies recursively for each subtree
+ * level.
+ *
+ * <h4>Change compatibility of leafs, leaf-list items</h4>
+ *
+ * Following table shows state changes and failures between two concurrent transactions,
+ * which are based on same initial state, Tx 1 completes successfully
+ * before Tx 2 is submitted.
+ *
+ * <table>
+ * <tr><th>Initial state</th><th>Tx 1</th><th>Tx 2</th><th>Result</th></tr>
+ * <tr><td>Empty</td><td>put(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, state is A=1</td></tr>
+ * <tr><td>Empty</td><td>put(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
+ *
+ * <tr><td>Empty</td><td>merge(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, state is A=1</td></tr>
+ * <tr><td>Empty</td><td>merge(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
+ *
+ *
+ * <tr><td>A=0</td><td>put(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, A=1</td></tr>
+ * <tr><td>A=0</td><td>put(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
+ * <tr><td>A=0</td><td>merge(A,1)</td><td>put(A,2)</td><td>Tx 2 will fail, A=1</td></tr>
+ * <tr><td>A=0</td><td>merge(A,1)</td><td>merge(A,2)</td><td>A=2</td></tr>
+ *
+ * <tr><td>A=0</td><td>delete(A)</td><td>put(A,2)</td><td>Tx 2 will fail, A does not exists</td></tr>
+ * <tr><td>A=0</td><td>delete(A)</td><td>merge(A,2)</td><td>A=2</td></tr>
+ * </table>
+ *
+ * <h4>Change compatibility of subtrees</h4>
+ *
+ * Following table shows state changes and failures between two concurrent transactions,
+ * which are based on same initial state, Tx 1 completes successfully
+ * before Tx 2 is submitted.
+ *
+ * <table>
+ * <tr><th>Initial state</th><th>Tx 1</th><th>Tx 2</th><th>Result</th></tr>
+ *
+ * <tr><td>Empty</td><td>put(TOP,[])</td><td>put(TOP,[])</td><td>Tx 2 will fail, state is TOP=[]</td></tr>
+ * <tr><td>Empty</td><td>put(TOP,[])</td><td>merge(TOP,[])</td><td>TOP=[]</td></tr>
+ *
+ * <tr><td>Empty</td><td>put(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
+ * <tr><td>Empty</td><td>put(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>TOP=[FOO=1,BAR=1]</td></tr>
+ *
+ * <tr><td>Empty</td><td>merge(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
+ * <tr><td>Empty</td><td>merge(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>TOP=[FOO=1,BAR=1]</td></tr>
+ *
+ * <tr><td>TOP=[]</td><td>put(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>put(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>merge(TOP,[FOO=1])</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is TOP=[FOO=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>merge(TOP,[FOO=1])</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>put(TOP,[BAR=1])</td><td>Tx 2 will fail, state is empty store</td></tr>
+ * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>merge(TOP,[BAR=1])</td><td>state is TOP=[BAR=1]</td></tr>
+ *
+ * <tr><td>TOP=[]</td><td>put(TOP/FOO,1)</td><td>put(TOP/BAR,1])</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>put(TOP/FOO,1)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>merge(TOP/FOO,1)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>merge(TOP/FOO,1)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=1,BAR=1]</td></tr>
+ * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>put(TOP/BAR,1)</td><td>Tx 2 will fail, state is empty store</td></tr>
+ * <tr><td>TOP=[]</td><td>delete(TOP)</td><td>merge(TOP/BAR,1]</td><td>Tx 2 will fail, state is empty store</td></tr>
+ *
+ * <tr><td>TOP=[FOO=1]</td><td>put(TOP/FOO,2)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
+ * <tr><td>TOP=[FOO=1]</td><td>put(TOP/FOO,2)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
+ * <tr><td>TOP=[FOO=1]</td><td>merge(TOP/FOO,2)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
+ * <tr><td>TOP=[FOO=1]</td><td>merge(TOP/FOO,2)</td><td>merge(TOP/BAR,1)</td><td>state is TOP=[FOO=2,BAR=1]</td></tr>
+ * <tr><td>TOP=[FOO=1]</td><td>delete(TOP/FOO)</td><td>put(TOP/BAR,1)</td><td>state is TOP=[BAR=1]</td></tr>
+ * <tr><td>TOP=[FOO=1]</td><td>delete(TOP/FOO)</td><td>merge(TOP/BAR,1]</td><td>state is TOP=[BAR=1]</td></tr>
+ * </table>
+ *
+ *
+ * <h3>Examples of failure scenarios</h3>
+ *
+ * <h4>Conflict of two transactions</h4>
+ *
+ * This example illustrates two concurrent transactions, which derived from
+ * same initial state of data tree and proposes conflicting modifications.
+ *
+ * <pre>
+ * txA = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
+ * txB = broker.newWriteTransaction(); // allocates new transaction, data tree is empty
+ *
+ * txA.put(CONFIGURATION, PATH, A); // writes to PATH value A
+ * txB.put(CONFIGURATION, PATH, B) // writes to PATH value B
+ *
+ * ListenableFuture futureA = txA.commit(); // transaction A is sealed and committed
+ * ListenebleFuture futureB = txB.commit(); // transaction B is sealed and committed
+ * </pre>
+ *
+ * Commit of transaction A will be processed asynchronously and data tree
+ * will be updated to contain value <code>A</code> for <code>PATH</code>.
+ * Returned {@link ListenableFuture} will successfully complete once
+ * state is applied to data tree.
+ *
+ * Commit of Transaction B will fail, because previous transaction also
+ * modified path in a concurrent way. The state introduced by transaction B
+ * will not be applied. Returned {@link ListenableFuture} object will fail
+ * with {@link OptimisticLockFailedException} exception, which indicates to
+ * client that concurrent transaction prevented the submitted transaction from being
+ * applied.
+ *
* @return Result of the Commit, containing success information or list of
* encountered errors, if commit was not successful. The Future
* blocks until {@link TransactionStatus#COMMITED} is reached.
- * Future will fail with {@link TransactionCommitFailedException}
- * if Commit of this transaction failed.
+ * Future will fail with {@link TransactionCommitFailedException} if
+ * Commit of this transaction failed. TODO: Usability: Consider
+ * change from ListenableFuture to
+ * {@link com.google.common.util.concurrent.CheckedFuture} which
+ * will throw {@link TransactionCommitFailedException}.
*
- * @throws IllegalStateException if the transaction is not {@link TransactionStatus#NEW}
+ * @throws IllegalStateException
+ * if the transaction is not {@link TransactionStatus#NEW}
*/
public ListenableFuture<RpcResult<TransactionStatus>> commit();
<artifactId>sal-binding-config</artifactId>
</dependency>
+ <!--
+ Adding a temporary dependency on the sal-broker-impl so that we can use InMemoryDOMDataStore
+
+ InMemoryDOMDataStore needs to be moved into its own module and be wired up using config subsystem before
+ this bundle can use it
+ -->
+ <dependency>
+ <groupId>org.opendaylight.controller</groupId>
+ <artifactId>sal-broker-impl</artifactId>
+ </dependency>
+
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-api</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.cluster.datastore;
+
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.japi.Creator;
+import org.opendaylight.controller.cluster.datastore.messages.CloseListenerRegistration;
+import org.opendaylight.controller.cluster.datastore.messages.CloseListenerRegistrationReply;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ListenerRegistration extends UntypedActor{
+
+ private final org.opendaylight.yangtools.concepts.ListenerRegistration<AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> registration;
+
+ public ListenerRegistration(org.opendaylight.yangtools.concepts.ListenerRegistration<AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> registration) {
+ this.registration = registration;
+ }
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ if(message instanceof CloseListenerRegistration){
+ closeListenerRegistration((CloseListenerRegistration) message);
+ }
+ }
+
+ public static Props props(final org.opendaylight.yangtools.concepts.ListenerRegistration<AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> registration){
+ return Props.create(new Creator<ListenerRegistration>(){
+
+ @Override
+ public ListenerRegistration create() throws Exception {
+ return new ListenerRegistration(registration);
+ }
+ });
+ }
+
+ private void closeListenerRegistration(CloseListenerRegistration message){
+ registration.close();
+ getSender().tell(new CloseListenerRegistrationReply(), getSelf());
+ }
+}
--- /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.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.persistence.UntypedProcessor;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply;
+import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
+import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
+import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import java.util.concurrent.Executors;
+
+/**
+ * A Shard represents a portion of the logical data tree
+ * <p/>
+ * Our Shard uses InMemoryDataStore as it's internal representation and delegates all requests it
+ *
+ */
+public class Shard extends UntypedProcessor {
+
+ ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(2));
+
+ private final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", storeExecutor);
+
+ LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ if (message instanceof CreateTransactionChain) {
+ createTransactionChain();
+ } else if(message instanceof RegisterChangeListener){
+ registerChangeListener((RegisterChangeListener) message);
+ } else if(message instanceof UpdateSchemaContext){
+ updateSchemaContext((UpdateSchemaContext) message);
+ }
+ }
+
+ private void updateSchemaContext(UpdateSchemaContext message) {
+ store.onGlobalContextUpdated(message.getSchemaContext());
+ }
+
+ private void registerChangeListener(RegisterChangeListener registerChangeListener) {
+ org.opendaylight.yangtools.concepts.ListenerRegistration<AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>> registration =
+ store.registerChangeListener(registerChangeListener.getPath(), registerChangeListener.getListener(), registerChangeListener.getScope());
+ ActorRef listenerRegistration = getContext().actorOf(ListenerRegistration.props(registration));
+ getSender().tell(new RegisterChangeListenerReply(listenerRegistration.path()), getSelf());
+ }
+
+ private void createTransactionChain() {
+ DOMStoreTransactionChain chain = store.createTransactionChain();
+ ActorRef transactionChain = getContext().actorOf(ShardTransactionChain.props(chain));
+ getSender().tell(new CreateTransactionChainReply(transactionChain.path()), getSelf());
+ }
+}
--- /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.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.event.Logging;
+import akka.event.LoggingAdapter;
+import akka.japi.Creator;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.ListenableFuture;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
+import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.MergeData;
+import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ReadData;
+import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.WriteData;
+import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import java.util.concurrent.ExecutionException;
+
+/**
+ * The ShardTransaction Actor represents a remote transaction
+ *
+ * The ShardTransaction Actor delegates all actions to DOMDataReadWriteTransaction
+ *
+ * Even though the DOMStore and the DOMStoreTransactionChain implement multiple types of transactions
+ * the ShardTransaction Actor only works with read-write transactions. This is just to keep the logic simple. At this
+ * time there are no known advantages for creating a read-only or write-only transaction which may change over time
+ * at which point we can optimize things in the distributed store as well.
+ *
+ * Handles Messages
+ * ----------------
+ * {@link org.opendaylight.controller.cluster.datastore.messages.ReadData}
+ * {@link org.opendaylight.controller.cluster.datastore.messages.WriteData}
+ * {@link org.opendaylight.controller.cluster.datastore.messages.MergeData}
+ * {@link org.opendaylight.controller.cluster.datastore.messages.DeleteData}
+ * {@link org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction}
+ * {@link org.opendaylight.controller.cluster.datastore.messages.CloseTransaction}
+ */
+public class ShardTransaction extends UntypedActor {
+
+ private final DOMStoreReadWriteTransaction transaction;
+
+ private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
+
+ public ShardTransaction(DOMStoreReadWriteTransaction transaction) {
+ this.transaction = transaction;
+ }
+
+
+ public static Props props(final DOMStoreReadWriteTransaction transaction){
+ return Props.create(new Creator<ShardTransaction>(){
+
+ @Override
+ public ShardTransaction create() throws Exception {
+ return new ShardTransaction(transaction);
+ }
+ });
+ }
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ if(message instanceof ReadData){
+ readData((ReadData) message);
+ } else if(message instanceof WriteData){
+ writeData((WriteData) message);
+ } else if(message instanceof MergeData){
+ mergeData((MergeData) message);
+ } else if(message instanceof DeleteData){
+ deleteData((DeleteData) message);
+ } else if(message instanceof ReadyTransaction){
+ readyTransaction((ReadyTransaction) message);
+ } else if(message instanceof CloseTransaction){
+ closeTransaction((CloseTransaction) message);
+ }
+ }
+
+ private void readData(ReadData message) {
+ final ActorRef sender = getSender();
+ final ActorRef self = getSelf();
+ final InstanceIdentifier path = message.getPath();
+ final ListenableFuture<Optional<NormalizedNode<?, ?>>> future = transaction.read(path);
+
+ future.addListener(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Optional<NormalizedNode<?, ?>> optional = future.get();
+ if(optional.isPresent()){
+ sender.tell(new ReadDataReply(optional.get()), self);
+ } else {
+ //TODO : Need to decide what to do here
+ }
+ } catch (InterruptedException | ExecutionException e) {
+ log.error(e, "An exception happened when reading data from path : " + path.toString());
+ }
+
+ }
+ }, getContext().dispatcher());
+ }
+
+
+ private void writeData(WriteData message){
+ transaction.write(message.getPath(), message.getData());
+ getSender().tell(new WriteDataReply(), getSelf());
+ }
+
+ private void mergeData(MergeData message){
+ transaction.merge(message.getPath(), message.getData());
+ getSender().tell(new MergeDataReply(), getSelf());
+ }
+
+ private void deleteData(DeleteData message){
+ transaction.delete(message.getPath());
+ getSender().tell(new DeleteDataReply(), getSelf());
+ }
+
+ private void readyTransaction(ReadyTransaction message){
+ DOMStoreThreePhaseCommitCohort cohort = transaction.ready();
+ ActorRef cohortActor = getContext().actorOf(ThreePhaseCommitCohort.props(cohort));
+ getSender().tell(new ReadyTransactionReply(cohortActor.path()), getSelf());
+
+ }
+
+ private void closeTransaction(CloseTransaction message){
+ transaction.close();
+ getSender().tell(new CloseTransactionReply(), getSelf());
+ }
+}
--- /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.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.japi.Creator;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChainReply;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
+
+/**
+ * The ShardTransactionChain Actor represents a remote TransactionChain
+ */
+public class ShardTransactionChain extends UntypedActor{
+
+ private final DOMStoreTransactionChain chain;
+
+ public ShardTransactionChain(DOMStoreTransactionChain chain) {
+ this.chain = chain;
+ }
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ if(message instanceof CreateTransaction){
+ DOMStoreReadWriteTransaction transaction = chain.newReadWriteTransaction();
+ ActorRef transactionActor = getContext().actorOf(ShardTransaction.props(transaction));
+ getSender().tell(new CreateTransactionReply(transactionActor.path()), getSelf());
+ } else if (message instanceof CloseTransactionChain){
+ chain.close();
+ getSender().tell(new CloseTransactionChainReply(), getSelf());
+ }
+ }
+
+ public static Props props(final DOMStoreTransactionChain chain){
+ return Props.create(new Creator<ShardTransactionChain>(){
+
+ @Override
+ public ShardTransactionChain create() throws Exception {
+ return new ShardTransactionChain(chain);
+ }
+ });
+ }
+}
--- /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.cluster.datastore;
+
+import akka.actor.Props;
+import akka.actor.UntypedActor;
+import akka.japi.Creator;
+import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
+
+public class ThreePhaseCommitCohort extends UntypedActor{
+ private final DOMStoreThreePhaseCommitCohort cohort;
+
+ public ThreePhaseCommitCohort(DOMStoreThreePhaseCommitCohort cohort) {
+
+ this.cohort = cohort;
+ }
+
+ @Override
+ public void onReceive(Object message) throws Exception {
+ throw new UnsupportedOperationException("onReceive");
+ }
+
+ public static Props props(final DOMStoreThreePhaseCommitCohort cohort) {
+ return Props.create(new Creator<ThreePhaseCommitCohort>(){
+ @Override
+ public ThreePhaseCommitCohort create() throws Exception {
+ return new ThreePhaseCommitCohort(cohort);
+ }
+ });
+ }
+}
--- /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.cluster.datastore.messages;
+
+public class CloseListenerRegistration {
+}
--- /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.cluster.datastore.messages;
+
+public class CloseListenerRegistrationReply {
+}
--- /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.cluster.datastore.messages;
+
+public class CloseTransaction {
+}
--- /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.cluster.datastore.messages;
+
+public class CloseTransactionChain {
+}
--- /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.cluster.datastore.messages;
+
+public class CloseTransactionChainReply {
+}
--- /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.cluster.datastore.messages;
+
+public class CloseTransactionReply {
+}
--- /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.cluster.datastore.messages;
+
+public class CreateTransaction {
+
+}
--- /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.cluster.datastore.messages;
+
+public class CreateTransactionChain {
+
+}
--- /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.cluster.datastore.messages;
+
+import akka.actor.ActorPath;
+
+public class CreateTransactionChainReply {
+ private final ActorPath transactionChainPath;
+
+ public CreateTransactionChainReply(ActorPath transactionChainPath) {
+ this.transactionChainPath = transactionChainPath;
+ }
+
+ public ActorPath getTransactionChainPath() {
+ return transactionChainPath;
+ }
+}
--- /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.cluster.datastore.messages;
+
+import akka.actor.ActorPath;
+
+public class CreateTransactionReply {
+ private final ActorPath transactionPath;
+
+ public CreateTransactionReply(ActorPath transactionPath) {
+ this.transactionPath = transactionPath;
+ }
+
+ public ActorPath getTransactionPath() {
+ return transactionPath;
+ }
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class DeleteData {
+ private final InstanceIdentifier path;
+
+ public DeleteData(InstanceIdentifier path) {
+ this.path = path;
+ }
+
+ public InstanceIdentifier getPath() {
+ return 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.cluster.datastore.messages;
+
+public class DeleteDataReply {
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class MergeData extends ModifyData {
+ public MergeData(InstanceIdentifier path, NormalizedNode<?, ?> data) {
+ super(path, data);
+ }
+}
--- /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.cluster.datastore.messages;
+
+public class MergeDataReply {
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public abstract class ModifyData {
+ private final InstanceIdentifier path;
+ private final NormalizedNode<?,?> data;
+
+ public ModifyData(InstanceIdentifier path, NormalizedNode<?, ?> data) {
+ this.path = path;
+ this.data = data;
+ }
+
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+ public NormalizedNode<?, ?> getData() {
+ return data;
+ }
+
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class ReadData {
+ private final InstanceIdentifier path;
+
+ public ReadData(InstanceIdentifier path) {
+ this.path = path;
+ }
+
+ public InstanceIdentifier getPath() {
+ return 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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class ReadDataReply {
+ private final NormalizedNode<?, ?> normalizedNode;
+
+ public ReadDataReply(NormalizedNode<?, ?> normalizedNode){
+
+ this.normalizedNode = normalizedNode;
+ }
+
+ public NormalizedNode<?, ?> getNormalizedNode() {
+ return normalizedNode;
+ }
+}
--- /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.cluster.datastore.messages;
+
+public class ReadyTransaction {
+}
--- /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.cluster.datastore.messages;
+
+import akka.actor.ActorPath;
+
+public class ReadyTransactionReply {
+ private final ActorPath path;
+
+ public ReadyTransactionReply(ActorPath path) {
+
+ this.path = path;
+ }
+
+ public ActorPath getPath() {
+ return 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.cluster.datastore.messages;
+
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class RegisterChangeListener {
+ private final InstanceIdentifier path;
+ private final AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> listener;
+ private final AsyncDataBroker.DataChangeScope scope;
+
+
+ public RegisterChangeListener(InstanceIdentifier path, AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> listener, AsyncDataBroker.DataChangeScope scope) {
+ this.path = path;
+ this.listener = listener;
+ this.scope = scope;
+ }
+
+ public InstanceIdentifier getPath() {
+ return path;
+ }
+
+ public AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> getListener() {
+ return listener;
+ }
+
+ public AsyncDataBroker.DataChangeScope getScope() {
+ return scope;
+ }
+}
--- /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.cluster.datastore.messages;
+
+import akka.actor.ActorPath;
+
+public class RegisterChangeListenerReply {
+ private final ActorPath listenerRegistrationPath;
+
+ public RegisterChangeListenerReply(ActorPath listenerRegistrationPath) {
+ this.listenerRegistrationPath = listenerRegistrationPath;
+ }
+
+ public ActorPath getListenerRegistrationPath() {
+ return listenerRegistrationPath;
+ }
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class UpdateSchemaContext {
+ private final SchemaContext schemaContext;
+
+ public UpdateSchemaContext(SchemaContext schemaContext) {
+ this.schemaContext = schemaContext;
+ }
+
+ public SchemaContext getSchemaContext() {
+ return schemaContext;
+ }
+}
--- /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.cluster.datastore.messages;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+public class WriteData extends ModifyData{
+
+ public WriteData(InstanceIdentifier path, NormalizedNode<?, ?> data) {
+ super(path, data);
+ }
+}
--- /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.cluster.datastore.messages;
+
+public class WriteDataReply {
+}
--- /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.cluster.datastore.shardstrategy;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * The DefaultShardStrategy basically puts all data into the default Shard
+ * <p>
+ * The default shard stores data for all modules for which a specific set of shards has not been configured
+ * </p>
+ */
+public class DefaultShardStrategy implements ShardStrategy{
+
+ public static final String NAME = "default";
+ public static final String DEFAULT_SHARD = "default";
+
+ @Override
+ public String findShard(InstanceIdentifier path) {
+ return DEFAULT_SHARD;
+ }
+}
--- /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.cluster.datastore.shardstrategy;
+
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+/**
+ * The role of ShardStrategy is to figure out which Shards a given piece of data belongs to
+ */
+public interface ShardStrategy {
+ /**
+ * Find the name of the shard in which the data pointed to by the specified path belongs in
+ *
+ * @param path The location of the data in the logical tree
+ * @return
+ */
+ String findShard(InstanceIdentifier 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.cluster.datastore.shardstrategy;
+
+import com.google.common.base.Preconditions;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class ShardStrategyFactory {
+ private static final Map<String, ShardStrategy> moduleNameToStrategyMap = new ConcurrentHashMap();
+
+ private static final String UNKNOWN_MODULE_NAME = "unknown";
+
+ public static ShardStrategy getStrategy(InstanceIdentifier path){
+ Preconditions.checkNotNull(path, "path should not be null");
+
+ String moduleName = getModuleName(path);
+ ShardStrategy shardStrategy = moduleNameToStrategyMap.get(moduleName);
+ if(shardStrategy == null){
+ return new DefaultShardStrategy();
+ }
+
+ return shardStrategy;
+ }
+
+
+ private static String getModuleName(InstanceIdentifier path){
+ return UNKNOWN_MODULE_NAME;
+ }
+
+ /**
+ * This is to be used in the future to register a custom shard strategy
+ *
+ * @param moduleName
+ * @param shardStrategy
+ */
+ public static void registerShardStrategy(String moduleName, ShardStrategy shardStrategy){
+ throw new UnsupportedOperationException("registering a custom shard strategy not supported yet");
+ }
+}
--- /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.cluster.datastore;
+
+import akka.actor.ActorSystem;
+import akka.testkit.JavaTestKit;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+public abstract class AbstractActorTest {
+ private static ActorSystem system;
+
+ @BeforeClass
+ public static void setUp(){
+ system = ActorSystem.create("test");
+ }
+
+ @AfterClass
+ public static void tearDown(){
+ JavaTestKit.shutdownActorSystem(system);
+ system = null;
+ }
+
+ protected ActorSystem getSystem(){
+ return system;
+ }
+
+}
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.CloseListenerRegistration;
+import org.opendaylight.controller.cluster.datastore.messages.CloseListenerRegistrationReply;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import static org.junit.Assert.assertEquals;
+
+public class ListenerRegistrationTest extends AbstractActorTest {
+ private static ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor());
+
+ private static final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", storeExecutor);
+
+ static {
+ store.onGlobalContextUpdated(TestModel.createTestContext());
+ }
+
+
+ @Test
+ public void testOnReceiveCloseListenerRegistration() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ListenerRegistration.props(store.registerChangeListener(TestModel.TEST_PATH, noOpDataChangeListener(), AsyncDataBroker.DataChangeScope.BASE));
+ final ActorRef subject = getSystem().actorOf(props, "testCloseListenerRegistration");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new CloseListenerRegistration(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof CloseListenerRegistrationReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ private AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> noOpDataChangeListener(){
+ return new AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>() {
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change) {
+
+ }
+ };
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChain;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionChainReply;
+import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListener;
+import org.opendaylight.controller.cluster.datastore.messages.RegisterChangeListenerReply;
+import org.opendaylight.controller.cluster.datastore.messages.UpdateSchemaContext;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
+import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+
+import static org.junit.Assert.assertTrue;
+
+public class ShardTest extends AbstractActorTest{
+ @Test
+ public void testOnReceiveCreateTransactionChain() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = Props.create(Shard.class);
+ final ActorRef subject = getSystem().actorOf(props, "testCreateTransactionChain");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new CreateTransactionChain(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof CreateTransactionChainReply) {
+ CreateTransactionChainReply reply = (CreateTransactionChainReply) in;
+ return reply.getTransactionChainPath().toString();
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertTrue(out.matches("akka:\\/\\/test\\/user\\/testCreateTransactionChain\\/\\$.*"));
+ // Will wait for the rest of the 3 seconds
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ @Test
+ public void testOnReceiveRegisterListener() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = Props.create(Shard.class);
+ final ActorRef subject = getSystem().actorOf(props, "testRegisterChangeListener");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new UpdateSchemaContext(TestModel.createTestContext()), getRef());
+
+ subject.tell(new RegisterChangeListener(InstanceIdentifier.builder().build(), noOpDataChangeListener() , AsyncDataBroker.DataChangeScope.BASE), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof RegisterChangeListenerReply) {
+ RegisterChangeListenerReply reply = (RegisterChangeListenerReply) in;
+ return reply.getListenerRegistrationPath().toString();
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertTrue(out.matches("akka:\\/\\/test\\/user\\/testRegisterChangeListener\\/\\$.*"));
+ // Will wait for the rest of the 3 seconds
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ private AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>> noOpDataChangeListener(){
+ return new AsyncDataChangeListener<InstanceIdentifier, NormalizedNode<?, ?>>() {
+ @Override
+ public void onDataChanged(AsyncDataChangeEvent<InstanceIdentifier, NormalizedNode<?, ?>> change) {
+
+ }
+ };
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChain;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionChainReply;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CreateTransactionReply;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class ShardTransactionChainTest extends AbstractActorTest {
+
+ private static ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor());
+
+ private static final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", storeExecutor);
+
+ static {
+ store.onGlobalContextUpdated(TestModel.createTestContext());
+ }
+ @Test
+ public void testOnReceiveCreateTransaction() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransactionChain.props(store.createTransactionChain());
+ final ActorRef subject = getSystem().actorOf(props, "testCreateTransaction");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new CreateTransaction(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof CreateTransactionReply) {
+ return ((CreateTransactionReply) in).getTransactionPath().toString();
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertTrue(out.matches("akka:\\/\\/test\\/user\\/testCreateTransaction\\/\\$.*"));
+ // Will wait for the rest of the 3 seconds
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ @Test
+ public void testOnReceiveCloseTransactionChain() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransactionChain.props(store.createTransactionChain());
+ final ActorRef subject = getSystem().actorOf(props, "testCloseTransactionChain");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new CloseTransactionChain(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof CloseTransactionChainReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+ // Will wait for the rest of the 3 seconds
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore;
+
+import akka.actor.ActorRef;
+import akka.actor.Props;
+import akka.testkit.JavaTestKit;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import org.junit.Test;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.CloseTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.DeleteData;
+import org.opendaylight.controller.cluster.datastore.messages.DeleteDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.MergeData;
+import org.opendaylight.controller.cluster.datastore.messages.MergeDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ReadData;
+import org.opendaylight.controller.cluster.datastore.messages.ReadDataReply;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransaction;
+import org.opendaylight.controller.cluster.datastore.messages.ReadyTransactionReply;
+import org.opendaylight.controller.cluster.datastore.messages.WriteData;
+import org.opendaylight.controller.cluster.datastore.messages.WriteDataReply;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+
+import static org.junit.Assert.assertEquals;
+
+public class ShardTransactionTest extends AbstractActorTest {
+ private static ListeningExecutorService storeExecutor = MoreExecutors.listeningDecorator(MoreExecutors.sameThreadExecutor());
+
+ private static final InMemoryDOMDataStore store = new InMemoryDOMDataStore("OPER", storeExecutor);
+
+ static {
+ store.onGlobalContextUpdated(TestModel.createTestContext());
+ }
+
+ @Test
+ public void testOnReceiveReadData() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testReadData");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new ReadData(InstanceIdentifier.builder().build()), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof ReadDataReply) {
+ if (((ReadDataReply) in).getNormalizedNode() != null) {
+ return "match";
+ }
+ return null;
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ @Test
+ public void testOnReceiveWriteData() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testWriteData");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new WriteData(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof WriteDataReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ @Test
+ public void testOnReceiveMergeData() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testMergeData");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new MergeData(TestModel.TEST_PATH, ImmutableNodes.containerNode(TestModel.TEST_QNAME)), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof MergeDataReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+ @Test
+ public void testOnReceiveDeleteData() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testDeleteData");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new DeleteData(TestModel.TEST_PATH), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof DeleteDataReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+ }
+
+
+ @Test
+ public void testOnReceiveReadyTransaction() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testReadyTransaction");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new ReadyTransaction(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof ReadyTransactionReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+
+ }
+
+ @Test
+ public void testOnReceiveCloseTransaction() throws Exception {
+ new JavaTestKit(getSystem()) {{
+ final Props props = ShardTransaction.props(store.newReadWriteTransaction());
+ final ActorRef subject = getSystem().actorOf(props, "testCloseTransaction");
+
+ new Within(duration("1 seconds")) {
+ protected void run() {
+
+ subject.tell(new CloseTransaction(), getRef());
+
+ final String out = new ExpectMsg<String>("match hint") {
+ // do not put code outside this method, will run afterwards
+ protected String match(Object in) {
+ if (in instanceof CloseTransactionReply) {
+ return "match";
+ } else {
+ throw noMatch();
+ }
+ }
+ }.get(); // this extracts the received message
+
+ assertEquals("match", out);
+
+ expectNoMsg();
+ }
+
+
+ };
+ }};
+
+ }
+
+
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore.shardstrategy;
+
+import junit.framework.Assert;
+import org.junit.Test;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+
+public class DefaultShardStrategyTest {
+
+ @Test
+ public void testFindShard() throws Exception {
+ String shard = new DefaultShardStrategy().findShard(TestModel.TEST_PATH);
+ Assert.assertEquals(DefaultShardStrategy.DEFAULT_SHARD, shard);
+ }
+}
\ No newline at end of file
--- /dev/null
+package org.opendaylight.controller.cluster.datastore.shardstrategy;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.opendaylight.controller.md.cluster.datastore.model.TestModel;
+
+import static junit.framework.Assert.assertNotNull;
+
+public class ShardStrategyFactoryTest {
+
+ @Rule
+ public ExpectedException expectedEx = ExpectedException.none();
+
+ @Test
+ public void testGetStrategy(){
+ ShardStrategy strategy = ShardStrategyFactory.getStrategy(TestModel.TEST_PATH);
+ assertNotNull(strategy);
+ }
+
+ @Test
+ public void testGetStrategyNullPointerExceptionWhenPathIsNull(){
+ expectedEx.expect(NullPointerException.class);
+ expectedEx.expectMessage("path should not be null");
+
+ ShardStrategyFactory.getStrategy(null);
+ }
+
+}
\ No newline at end of file
--- /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.md.cluster.datastore.model;
+
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
+
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.Set;
+
+public class TestModel {
+
+ public static final QName TEST_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test", "2014-03-13",
+ "test");
+ public static final QName OUTER_LIST_QNAME = QName.create(TEST_QNAME, "outer-list");
+ public static final QName INNER_LIST_QNAME = QName.create(TEST_QNAME, "inner-list");
+ public static final QName OUTER_CHOICE_QNAME = QName.create(TEST_QNAME, "outer-choice");
+ public static final QName ID_QNAME = QName.create(TEST_QNAME, "id");
+ public static final QName NAME_QNAME = QName.create(TEST_QNAME, "name");
+ public static final QName VALUE_QNAME = QName.create(TEST_QNAME, "value");
+ private static final String DATASTORE_TEST_YANG = "/odl-datastore-test.yang";
+
+ public static final InstanceIdentifier TEST_PATH = InstanceIdentifier.of(TEST_QNAME);
+ public static final InstanceIdentifier OUTER_LIST_PATH = InstanceIdentifier.builder(TEST_PATH).node(OUTER_LIST_QNAME).build();
+ public static final QName TWO_QNAME = QName.create(TEST_QNAME,"two");
+ public static final QName THREE_QNAME = QName.create(TEST_QNAME,"three");
+
+
+ public static final InputStream getDatastoreTestInputStream() {
+ return getInputStream(DATASTORE_TEST_YANG);
+ }
+
+ private static InputStream getInputStream(final String resourceName) {
+ return TestModel.class.getResourceAsStream(DATASTORE_TEST_YANG);
+ }
+
+ public static SchemaContext createTestContext() {
+ YangParserImpl parser = new YangParserImpl();
+ Set<Module> modules = parser.parseYangModelsFromStreams(Collections.singletonList(getDatastoreTestInputStream()));
+ return parser.resolveSchemaContext(modules);
+ }
+}
--- /dev/null
+module odl-datastore-test {
+ yang-version 1;
+ namespace "urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:store:test";
+ prefix "store-test";
+
+ revision "2014-03-13" {
+ description "Initial revision.";
+ }
+
+ container test {
+ list outer-list {
+ key id;
+ leaf id {
+ type uint16;
+ }
+ choice outer-choice {
+ case one {
+ leaf one {
+ type string;
+ }
+ }
+ case two-three {
+ leaf two {
+ type string;
+ }
+ leaf three {
+ type string;
+ }
+ }
+ }
+ list inner-list {
+ key name;
+ leaf name {
+ type string;
+ }
+ leaf value {
+ type string;
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>> afterCont = (NormalizedNodeContainer<?, PathArgument, NormalizedNode<PathArgument, ?>>) afterData;
return resolveNodeContainerReplaced(path, listeners, beforeCont, afterCont);
} else if (!beforeData.equals(afterData)) {
- // Node is either of Leaf type (does not contain child nodes)
- // or we do not have listeners, so normal equals method is
- // sufficient for determining change.
+ // Node is Leaf type (does not contain child nodes)
+ // so normal equals method is sufficient for determining change.
LOG.trace("Resolving leaf replace event for {} , before {}, after {}",path,beforeData,afterData);
DOMImmutableDataChangeEvent event = builder(DataChangeScope.BASE).setBefore(beforeData).setAfter(afterData)
.addUpdated(path, beforeData, afterData).build();
eventBuilder.merge(resolveSameEventRecursivelly(path.node(childId), childListeners, child, eventFactory));
}
propagateEvent = eventBuilder.build();
- } else {
- // We do not dispatch leaf events since Binding Aware components do not support them.
- propagateEvent = builder(DataChangeScope.BASE).build();
}
if (!listeners.isEmpty()) {
addPartialTask(listeners, propagateEvent);
*/
package org.opendaylight.controller.md.sal.dom.store.impl.tree.data;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTree;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeCandidate;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataTreeModification;
+import org.opendaylight.controller.md.sal.dom.store.impl.tree.DataValidationFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ModificationType;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.StoreUtils;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.spi.TreeNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import com.google.common.base.Optional;
-import com.google.common.base.Preconditions;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* Read-only snapshot of the data tree.
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.8.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.8.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-remoterpc-connector</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
</dependencies>
<url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:MD-SAL</url>
</scm>
- <properties>
- <jackson.version>2.3.0</jackson.version>
- <exam.version>3.0.0</exam.version>
- <url.version>1.5.0</url.version>
- </properties>
-
- <dependencyManagement>
- <dependencies>
- <dependency>
- <groupId>commons-codec</groupId>
- <artifactId>commons-codec</artifactId>
- <version>1.7</version>
- </dependency>
- </dependencies>
- </dependencyManagement>
-
<build>
<plugins>
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
<executions>
<execution>
<id>generate-config</id>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
- <version>1.0.0</version>
+ <version>${lifecycle.mapping.version}</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.tests</groupId>
<artifactId>sal-remoterpc-connector-test-provider</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.tests</groupId>
<artifactId>sal-remoterpc-connector-test-consumer</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<dependency>
<groupId>org.ops4j.pax.url</groupId>
<artifactId>pax-url-aether</artifactId>
- <version>1.5.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-api</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-remoterpc-connector</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.osgi</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
</dependency>
<!-- routing table dependencies -->
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>zeromq-routingtable.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.osgi</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal.implementation</artifactId>
- <version>0.4.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.osgi</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager.it.implementation</artifactId>
- <version>0.5.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.stub</artifactId>
- <version>0.4.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.dependencymanager.shell</artifactId>
- <version>3.0.1</version>
<exclusions>
<exclusion>
<groupId>org.osgi</groupId>
<dependency>
<groupId>eclipselink</groupId>
<artifactId>javax.resource</artifactId>
- <version>1.5.0.v200906010428</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>ietf-netconf-monitoring</artifactId>
- <version>0.2.5-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>yang-ext</artifactId>
- <version>2013.09.07.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.model</groupId>
<artifactId>opendaylight-l2-types</artifactId>
- <version>2013.08.27.3</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-it</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-config</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-inventory</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-connector-api</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-common-util</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>clustering.services</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
</dependency>
<dependency>
<dependency>
<groupId>org.zeromq</groupId>
<artifactId>jeromq</artifactId>
- <version>0.3.1</version>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>xtend-lib-osgi</artifactId>
- <version>2.4.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-binding-broker-impl</artifactId>
- <version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
- <version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
- <version>1.0.9</version>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-service</artifactId>
- <version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>config-manager</artifactId>
- <version>0.2.3-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-flow-management</artifactId>
- <version>1.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.opendaylight.yangtools.thirdparty</groupId>
<artifactId>antlr4-runtime-osgi-nohead</artifactId>
- <version>4.0</version>
</dependency>
</dependencies>
</project>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>containermanager</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>commons.northbound</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal</artifactId>
- <version>0.5.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.tests</groupId>
<artifactId>sal-remoterpc-connector-test-provider</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.tests</groupId>
<artifactId>sal-remoterpc-connector-test-consumer</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>sal-remoterpc-connector</artifactId>
- <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
- <version>5.0.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<artifactId>remoterpc-routingtable.implementation</artifactId>
- <version>0.4.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>sal-core-api</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>jaxrs-api</artifactId>
- <version>3.0.4.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
- <version>2.4</version>
<scope>test</scope>
</dependency>
<dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
- <version>3.3.2</version>
- <!--$NO-MVN-MAN-VER$ -->
</dependency>
<!-- Jax rs -->
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.samples.l2switch.md</groupId>
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<artifactId>sample-toaster</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<artifactId>sample-toaster-consumer</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller.samples</groupId>
<artifactId>sample-toaster-provider</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.openexi</groupId>
<dependency>
<groupId>equinoxSDK381</groupId>
<artifactId>org.eclipse.osgi</artifactId>
- <version>3.8.1.v20120830-144521</version>
<scope>test</scope>
</dependency>
<dependency>
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
<executions>
<execution>
<id>generate-config</id>
<?xml version="1.0" encoding="UTF-8"?>
+<!-- vi: set et smarttab sw=4 tabstop=4: -->
+<!--
+ Copyright (c) 2013 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
+-->
+
<persisted-snapshots>
<snapshots>
<snapshot>
- <required-capabilities>
- <!-- <capability>urn:opendaylight:l2:types?module=opendaylight-l2-types&revision=2013-08-27</capability>-->
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28
- </capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:config?module=config&revision=2013-04-05
- </capability>
- <capability>urn:ietf:params:netconf:capability:candidate:1.0</capability>
- <capability>urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring?module=ietf-netconf-monitoring&revision=2010-10-04</capability>
- <capability>urn:ietf:params:xml:ns:yang:rpc-context?module=rpc-context&revision=2013-06-17
- </capability>
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28
- </capability>
- <capability>urn:ietf:params:xml:ns:yang:ietf-inet-types?module=ietf-inet-types&revision=2010-09-24
- </capability>
- <capability>urn:ietf:params:netconf:capability:rollback-on-error:1.0</capability>
- <capability>urn:ietf:params:xml:ns:yang:ietf-yang-types?module=ietf-yang-types&revision=2010-09-24
- </capability>
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28
- </capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:logback:config?module=config-logging&revision=2013-07-16</capability>
- <!-- <capability>urn:opendaylight:yang:extension:yang-ext?module=yang-ext&revision=2013-07-09</capability>-->
- <capability>
- urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28
- </capability>
- <capability>http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
- <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
-
- </required-capabilities>
<configuration>
-
<data xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
<modules xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:schema-service-singleton</type>
+ <name>yang-schema-service</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:runtime-generated-mapping</type>
+ <name>runtime-mapping-singleton</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-notification-broker</type>
+ <name>binding-notification-broker</name>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-broker-impl</type>
+ <name>binding-broker-impl</name>
+ <notification-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
+ <name>binding-notification-broker</name>
+ </notification-service>
+ <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
+ <name>binding-data-broker</name>
+ </data-broker>
+ </module>
+
+ <!--
+ Tree-based in-memory data store. This is the data store which is currently
+ recommended for single-node deployments.
+ -->
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-inmemory-data-broker</type>
+ <name>inmemory-data-broker</name>
+ <schema-service>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <name>yang-schema-service</name>
+ </schema-service>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">prefix:dom-broker-impl</type>
+ <name>inmemory-dom-broker</name>
+ <async-data-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
+ <name>inmemory-data-broker</name>
+ </async-data-broker>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-data-compatible-broker</type>
+ <name>inmemory-binding-data-broker</name>
+ <dom-async-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-async-broker>
+ <binding-mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </module>
+ <module>
+ <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">prefix:binding-forwarded-data-broker</type>
+ <name>binding-async-data-broker</name>
+ <binding-forwarded-data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
+ <dom-async-broker>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
+ <name>dom-broker</name>
+ </dom-async-broker>
+ <binding-mapping-service>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding:binding-dom-mapping-service</type>
+ <name>runtime-mapping-singleton</name>
+ </binding-mapping-service>
+ </binding-forwarded-data-broker>
+ </module>
+
+ <!-- Toaster Congiguration -->
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl">
prefix:toaster-provider-impl
<data-broker>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
- <name>ref_binding-data-broker</name>
+ <name>binding-data-broker</name>
</data-broker>
<notification-service>
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</type>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
</notification-service>
</module>
+ <!-- Kitchen Service -->
<module>
<type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
prefix:kitchen-service-impl
<type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
binding:binding-notification-service
</type>
- <name>ref_binding-notification-broker</name>
- </notification-service>
- </module>
-
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:schema-service-singleton
- </type>
- <name>yang-schema-service</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:hash-map-data-store
- </type>
- <name>hash-map-data-store</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- prefix:dom-broker-impl
- </type>
- <name>dom-broker</name>
- <data-store xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-data-store
- </type>
- <name>ref_hash-map-data-store</name>
- </data-store>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-broker-impl
- </type>
- <name>binding-broker-impl</name>
- <notification-service
- xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-notification-service
- </type>
- <name>ref_binding-notification-broker</name>
+ <name>binding-notification-broker</name>
</notification-service>
- <data-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-data-broker
- </type>
- <name>ref_binding-data-broker</name>
- </data-broker>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:runtime-generated-mapping
- </type>
- <name>runtime-mapping-singleton</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-notification-broker
- </type>
- <name>binding-notification-broker</name>
- </module>
- <module>
- <type xmlns:prefix="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- prefix:binding-data-broker
- </type>
- <name>binding-data-broker</name>
- <dom-broker xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-broker-osgi-registry
- </type>
- <name>ref_dom-broker</name>
- </dom-broker>
- <mapping-service xmlns="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- binding:binding-dom-mapping-service
- </type>
- <name>ref_runtime-mapping-singleton</name>
- </mapping-service>
</module>
</modules>
-
<services xmlns="urn:opendaylight:params:xml:ns:yang:controller:config">
<service>
- <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
- kitchen:kitchen-service
- </type>
- <instance>
- <name>kitchen-service</name>
- <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
- </instance>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:schema-service</type>
+ <instance>
+ <name>yang-schema-service</name>
+ <provider>/modules/module[type='schema-service-singleton'][name='yang-schema-service']</provider>
+ </instance>
</service>
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:schema-service
- </type>
+ <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">binding-impl:binding-dom-mapping-service</type>
<instance>
- <name>ref_yang-schema-service</name>
- <provider>
- /config/modules/module[name='schema-service-singleton']/instance[name='yang-schema-service']
- </provider>
+ <name>runtime-mapping-singleton</name>
+ <provider>/modules/module[type='runtime-generated-mapping'][name='runtime-mapping-singleton']</provider>
</instance>
</service>
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-notification-service
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-notification-service</type>
<instance>
- <name>ref_binding-notification-broker</name>
- <provider>
- /config/modules/module[name='binding-notification-broker']/instance[name='binding-notification-broker']
- </provider>
+ <name>binding-notification-broker</name>
+ <provider>/modules/module[type='binding-notification-broker'][name='binding-notification-broker']</provider>
</instance>
</service>
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-data-store
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-broker-osgi-registry</type>
<instance>
- <name>ref_hash-map-data-store</name>
- <provider>
- /config/modules/module[name='hash-map-data-store']/instance[name='hash-map-data-store']
- </provider>
+ <name>binding-osgi-broker</name>
+ <provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
<service>
<provider>/modules/module[type='binding-broker-impl'][name='binding-broker-impl']</provider>
</instance>
</service>
+
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-broker-osgi-registry
- </type>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-broker-osgi-registry</type>
<instance>
- <name>ref_binding-broker-impl</name>
- <provider>
- /config/modules/module[name='binding-broker-impl']/instance[name='binding-broker-impl']
- </provider>
+ <name>dom-broker</name>
+ <provider>/modules/module[type='dom-broker-impl'][name='inmemory-dom-broker']</provider>
</instance>
</service>
+
<service>
- <type xmlns:binding-impl="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl">
- binding-impl:binding-dom-mapping-service
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-data-broker</type>
<instance>
- <name>ref_runtime-mapping-singleton</name>
- <provider>
- /config/modules/module[name='runtime-generated-mapping']/instance[name='runtime-mapping-singleton']
- </provider>
+ <name>binding-data-broker</name>
+ <provider>/modules/module[type='binding-data-compatible-broker'][name='inmemory-binding-data-broker']</provider>
</instance>
</service>
+
<service>
- <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">
- dom:dom-broker-osgi-registry
- </type>
+ <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">binding:binding-async-data-broker</type>
<instance>
- <name>ref_dom-broker</name>
- <provider>/config/modules/module[name='dom-broker-impl']/instance[name='dom-broker']
- </provider>
+ <name>binding-data-broker</name>
+ <provider>/modules/module[type='binding-forwarded-data-broker'][name='binding-async-data-broker']</provider>
</instance>
</service>
+
<service>
- <type xmlns:binding="urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding">
- binding:binding-data-broker
- </type>
+ <type xmlns:dom="urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom">dom:dom-async-data-broker</type>
<instance>
- <name>ref_binding-data-broker</name>
- <provider>
- /config/modules/module[name='binding-data-broker']/instance[name='binding-data-broker']
- </provider>
+ <name>inmemory-data-broker</name>
+ <provider>/modules/module[type='dom-inmemory-data-broker'][name='inmemory-data-broker']</provider>
</instance>
</service>
+
+ <!-- Toaster samples -->
+ <service>
+ <type xmlns:kitchen="urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl">
+ kitchen:kitchen-service
+ </type>
+ <instance>
+ <name>kitchen-service</name>
+ <provider>/modules/module[type='kitchen-service-impl'][name='kitchen-service-impl']</provider>
+ </instance>
+ </service>
</services>
</data>
-
</configuration>
- </snapshot>
+ <required-capabilities>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding?module=opendaylight-md-sal-binding&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom?module=opendaylight-md-sal-dom&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:binding:impl?module=opendaylight-sal-binding-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:dom:impl?module=opendaylight-sal-dom-broker-impl&revision=2013-10-28</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:md:sal:common?module=opendaylight-md-sal-common&revision=2013-10-28</capability>
+ <!-- Toaster capabilities -->
+ <capability>http://netconfcentral.org/ns/toaster?module=toaster&revision=2009-11-20</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:kitchen-service:impl?module=kitchen-service-impl&revision=2014-01-31</capability>
+ <capability>urn:opendaylight:params:xml:ns:yang:controller:config:toaster-provider:impl?module=toaster-provider-impl&revision=2014-01-31</capability>
+
+ </required-capabilities>
+ </snapshot>
</snapshots>
</persisted-snapshots>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
- <version>2.4</version>
</dependency>
<dependency>
<groupId>equinoxSDK381</groupId>
<dependency>
<groupId>org.opendaylight.controller.model</groupId>
<artifactId>model-topology</artifactId>
- <version>1.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
- <version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.opendaylight.controller</groupId>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
<executions>
<execution>
<goals>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>ietf-netconf-monitoring-extension</artifactId>
- <version>${project.version}</version>
</dependency>
<!-- compile dependencies -->
<dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>netconf-client</artifactId>
- <version>${project.version}</version>
<type>test-jar</type>
<scope>test</scope>
</dependency>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.impl.osgi.NetconfImplActivator</Bundle-Activator>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
<executions>
<execution>
<goals>
<artifactId>netconf-it</artifactId>
<name>${project.artifactId}</name>
- <properties>
- <tinybundles.version>2.0.0</tinybundles.version>
- </properties>
<dependencies>
<dependency>
<plugin>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>maven-paxexam-plugin</artifactId>
- <version>1.2.4</version>
<executions>
<execution>
<id>generate-config</id>
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
-
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
import org.opendaylight.controller.netconf.nettyutil.handler.ssh.virtualsocket.VirtualSocketException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* pipeline.
*/
public class SshClientAdapter implements Runnable {
+ private static final Logger logger = LoggerFactory.getLogger(SshClientAdapter.class);
+
private static final int BUFFER_SIZE = 1024;
private final SshClient sshClient;
}
public void run() {
+ SshSession session;
+ try {
+ session = sshClient.openSession();
+ } catch (IOException e) {
+ logger.error("Cannot establish session", e);
+ sshClient.close();
+ return;
+ }
try {
- SshSession session = sshClient.openSession();
invoker.invoke(session);
InputStream stdOut = session.getStdout();
session.getStderr();
// Netty closed connection prematurely.
// Just pass and move on.
} catch (Exception e) {
- throw new IllegalStateException(e);
+ logger.error("Unexpected exception", e);
} finally {
sshClient.close();
synchronized(lock) {
this.bb.discardReadBytes();
this.bb.writeBytes((ByteBuf) o);
+ ((ByteBuf) o).release();
lock.notifyAll();
}
}
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.ssh.osgi.NetconfSSHActivator</Bundle-Activator>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
<executions>
<execution>
<goals>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
<configuration>
<instructions>
<Bundle-Activator>org.opendaylight.controller.netconf.tcp.osgi.NetconfTCPActivator</Bundle-Activator>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <version>2.3.7</version>
<configuration>
<instructions>
<Import-Package>com.google.common.base, com.google.common.collect, io.netty.channel,
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
- <version>2.4</version>
<executions>
<execution>
<goals>