--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import java.util.function.BiConsumer;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
+
+/**
+ * Write transaction that provides cursor's with write access to the data tree.
+ */
+@Beta
+public interface CursorAwareWriteTransaction extends DataTreeCursorProvider {
+
+ /**
+ * Create a {@link DataTreeWriteCursor} anchored at the specified path.
+ * There can only be one cursor open at a time.
+ *
+ * <p>
+ * @param path Path at which the cursor is to be anchored
+ * @return write cursor at the desired location.
+ * @throws IllegalStateException when there's an open cursor, or this transaction is closed already.
+ */
+ @Nullable
+ @Override
+ <T extends TreeNode> DataTreeCursor createCursor(@Nonnull DataTreeIdentifier<T> path);
+
+ /**
+ * Cancels the transaction.
+ *
+ * <p>
+ * Transactions can only be cancelled if it was not yet submited.
+ *
+ * <p>
+ * Invoking cancel() on failed or already canceled will have no effect, and transaction is
+ * considered cancelled.
+ *
+ * <p>
+ * Invoking cancel() on finished transaction (future returned by {@link #submit(BiConsumer)} already
+ * successfully completed) will always fail (return false).
+ *
+ * @return <tt>false</tt> if the task could not be cancelled, typically because it has already
+ * completed normally; <tt>true</tt> otherwise
+ *
+ */
+ boolean cancel();
+
+ /**
+ * Submits this transaction to be asynchronously applied to update the logical data tree. Callback
+ * conveys the result of applying the data changes.
+ *
+ * <p>
+ * This call logically seals the transaction, which prevents the client from further changing
+ * data tree using this transaction's cursor. Any subsequent calls to
+ * <code>createCursorCursor(DOMDataTreeIdentifier</code>
+ * or any of the cursor's methods will fail with {@link IllegalStateException}.
+ *
+ * <p>
+ * The transaction is marked as submitted and enqueued into the shard back-end for
+ * processing.
+ *
+ * @param callback result callback
+ * @param <T> result type
+ */
+ <T extends TreeNode> void submit(BiConsumer<TransactionCommitFailedException, T> callback);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+import org.opendaylight.mdsal.common.api.AsyncDataBroker;
+import org.opendaylight.mdsal.common.api.TransactionChainFactory;
+import org.opendaylight.mdsal.common.api.TransactionChainListener;
+
+/**
+ * Provides access to a conceptual data tree store and also provides the ability to
+ * subscribe for changes to data under a given branch of the tree.
+ *
+ * <p>
+ * For more information on usage, please see the documentation in {@link AsyncDataBroker}.
+ *
+ * @see AsyncDataBroker
+ * @see TransactionChainFactory
+ */
+@Beta
+public interface DataBroker extends AsyncDataBroker<InstanceIdentifier<?>, TreeNode>, BindingService,
+ TransactionFactory, DataTreeService, TransactionChainFactory<InstanceIdentifier<?>, TreeNode> {
+
+ @Override
+ ReadTransaction newReadOnlyTransaction();
+
+ @Override
+ WriteTransaction newWriteOnlyTransaction();
+
+ @Override
+ BindingTransactionChain createTransactionChain(TransactionChainListener listener);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+
+/**
+ * Provides access to {#link DataTreeCursor}'s anchored at the specified path.
+ */
+@Beta
+public interface DataTreeCursorProvider {
+
+ /**
+ * Create a new {@link DataTreeCursor} at specified path. May fail if specified path
+ * does not exist.
+ *
+ * @param path Path at which the cursor is to be anchored
+ * @param <T> data tree type
+ * @return A new cursor, or null if the path does not exist.
+ * @throws IllegalStateException if there is another cursor currently open, or the transaction
+ * is already closed (closed or submitted).
+ */
+ @Nullable
+ <T extends TreeNode> DataTreeCursor createCursor(@Nonnull DataTreeIdentifier<T> path);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+import java.util.EventListener;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
+
+/**
+ * Interface implemented by data consumers, e.g. processes wanting to act on data after it has been
+ * introduced to the conceptual data tree.
+ */
+@Beta
+public interface DataTreeListener extends EventListener {
+
+ /**
+ * Invoked whenever one or more registered subtrees change. The logical changes are reported, as
+ * well as the roll up of new state for all subscribed subtrees.
+ *
+ * @param changes The set of changes being reported. Each subscribed subtree may be present at
+ * most once.
+ * @param subtrees Per-subtree state as visible after the reported changes have been applied.
+ * This includes all the subtrees this listener is subscribed to, even those which have
+ * not changed.
+ */
+ void onDataTreeChanged(@Nonnull Collection<DataTreeModification<?>> changes,
+ @Nonnull Map<DataTreeIdentifier<?>, TreeNode> subtrees);
+
+ /**
+ * Invoked when a subtree listening failure occurs. This can be triggered, for example, when a
+ * connection to external subtree source is broken. The listener will not receive any other
+ * callbacks, but its registration still needs to be closed to prevent resource leak.
+ *
+ * @param causes Collection of failure causes, may not be null or empty.
+ */
+ void onDataTreeFailed(@Nonnull Collection<DataTreeListeningException> causes);
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+/**
+ * Base exception for various causes why and {@link DataTreeListener} may be terminated by the
+ * {@link DataTreeService} implementation.
+ */
+@Beta
+public class DataTreeListeningException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public DataTreeListeningException(@Nonnull String message, @Nullable Throwable cause) {
+ super(Preconditions.checkNotNull(message, "message"), cause);
+ }
+
+ public DataTreeListeningException(@Nonnull String message) {
+ super(Preconditions.checkNotNull(message, "message"));
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+
+/**
+ * Exception thrown when a loop is detected in the way {@link DataTreeListener} and
+ * {@link DataTreeProducer} instances would be connected.
+ */
+@Beta
+public class DataTreeLoopException extends DataTreeProducerException {
+
+ private static final long serialVersionUID = 1L;
+
+ public DataTreeLoopException(@Nonnull final String message, @Nonnull final Throwable cause) {
+ super(message, cause);
+ }
+
+ public DataTreeLoopException(@Nonnull final String message) {
+ super(message);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+
+/**
+ * A data producer context. It allows transactions to be submitted to the subtrees specified at
+ * instantiation time. At any given time there may be a single transaction open. It needs to be
+ * either submitted or cancelled before another one can be open. Once a transaction is submitted, it
+ * will proceed to be committed asynchronously.
+ *
+ *<p>
+ * Each instance has an upper bound on the number of transactions which can be in-flight, once that
+ * capacity is exceeded, an attempt to create a new transaction will block until some transactions
+ * complete.
+ *
+ *<p>
+ * Each {@link DataTreeProducer} can be in two logical states, bound and unbound, which define the
+ * lifecycle rules for when is it legal to create and submit transactions in relationship with
+ * {@link DataTreeListener} callbacks.
+ *
+ *<p>
+ * When a producer is first created, it is unbound. In this state the producer can be accessed by
+ * any application thread to allocate or submit transactions, as long as the 'single open
+ * transaction' rule is maintained. The producer and any transaction object MUST NOT be accessed,
+ * directly or indirectly, from a {@link DataTreeListener} callback.
+ *
+ * <p>
+ * When a producer is referenced in a call to
+ * {@link DataTreeService#registerListener(DataTreeListener, java.util.Collection, boolean, java.util.Collection)}
+ * , an attempt will be made to bind the producer to the specified {@link DataTreeListener}. Such an
+ * attempt will fail the producer is already bound, or it has an open transaction. Once bound, the
+ * producer can only be accessed from within the {@link DataTreeListener} callback on that
+ * particular instance. Any transaction which is not submitted by the time the callback returns will
+ * be implicitly cancelled. A producer becomes unbound when the listener it is bound to becomes
+ * unregistered.
+ *
+ */
+@Beta
+public interface DataTreeProducer extends DataTreeProducerFactory, AutoCloseable {
+
+ /**
+ * Allocate a new open transaction on this producer. Any and all transactions previously
+ * allocated must have been either submitted or cancelled by the time this method is invoked.
+ *
+ * @param isolated Indicates whether this transaction should be a barrier. A barrier transaction
+ * is processed separately from any preceding transactions. Non-barrier transactions may
+ * be merged and processed in a batch, such that any observers see the modifications
+ * contained in them as if the modifications were made in a single transaction.
+ * @return A new {@link CursorAwareWriteTransaction}
+ * @throws IllegalStateException if a previous transaction was not closed.
+ * @throws IllegalThreadStateException if the calling thread context does not match the
+ * lifecycle rules enforced by the producer state (e.g. bound or unbound). This
+ * exception is thrown on a best effort basis and programs should not rely on it for
+ * correct operation.
+ */
+ @Nonnull
+ CursorAwareWriteTransaction createTransaction(boolean isolated);
+
+ /**
+ * {@inheritDoc}.
+ *
+ *<p>
+ * When invoked on a {@link DataTreeProducer}, this method has additional restrictions. There
+ * may not be an open transaction from this producer. The method needs to be invoked in
+ * appropriate context, e.g. bound or unbound.
+ *
+ *<p>
+ * Specified subtrees must be accessible by this producer. Accessible means they are a subset of
+ * the subtrees specified when the producer is instantiated. The set is further reduced as child
+ * producers are instantiated -- if you create a producer for /a and then a child for /a/b, /a/b
+ * is not accessible from the first producer.
+ *
+ *<p>
+ * Once this method returns successfully, this (parent) producer loses the ability to access the
+ * specified paths until the resulting (child) producer is shut down.
+ *
+ * @throws IllegalStateException if there is an open transaction
+ * @throws IllegalArgumentException if subtrees contains a subtree which is not accessible by
+ * this producer
+ * @throws IllegalThreadStateException if the calling thread context does not match the
+ * lifecycle rules enforced by the producer state (e.g. bound or unbound). This
+ * exception is thrown on a best effort basis and programs should not rely on it for
+ * correct operation.
+ */
+ @Override
+ @Nonnull
+ DataTreeProducer createProducer(@Nonnull Collection<DataTreeIdentifier<?>> subtrees);
+
+ /**
+ * {@inheritDoc}.
+ *
+ * @throws DataTreeProducerBusyException when there is an open transaction.
+ */
+ @Override
+ void close() throws DataTreeProducerException;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import javax.annotation.Nonnull;
+
+/**
+ * Exception indicating that the {@link DataTreeProducer} has an open user transaction and cannot be
+ * closed.
+ */
+@Beta
+public class DataTreeProducerBusyException extends DataTreeProducerException {
+
+ private static final long serialVersionUID = 1L;
+
+
+ public DataTreeProducerBusyException(@Nonnull final String message, @Nonnull final Throwable cause) {
+ super(Preconditions.checkNotNull(message, "message"), cause);
+ }
+
+ public DataTreeProducerBusyException(@Nonnull final String message) {
+ super(Preconditions.checkNotNull(message, "message"));
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import javax.annotation.Nonnull;
+
+@Beta
+public class DataTreeProducerException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public DataTreeProducerException(@Nonnull final String message, @Nonnull final Throwable cause) {
+ super(message, cause);
+ }
+
+ public DataTreeProducerException(@Nonnull final String message) {
+ super(message);
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+
+/**
+ * Factory which allows a creation of producer.
+ */
+@Beta
+public interface DataTreeProducerFactory {
+
+ /**
+ * Create a producer, which is able to access to a set of trees.
+ *
+ * @param subtrees The collection of subtrees the resulting producer should have access to.
+ * @return A {@link DataTreeProducer} instance.
+ * @throws IllegalArgumentException if subtrees is empty.
+ */
+ DataTreeProducer createProducer(Collection<DataTreeIdentifier<?>> subtrees);
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import com.google.common.annotations.Beta;
+import java.util.Collection;
+import javax.annotation.Nonnull;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+
+/**
+ * A {@link BindingService} providing access to the conceptual data tree. Interactions with the data
+ * tree are split into data producers and consumers (listeners). Each of them operate on a set of
+ * subtrees, which need to be declared at instantiation time.
+ *
+ *<p>
+ * Returned instances are not thread-safe and expected to be used by a single thread at a time.
+ * Furthermore, producers may not be accessed from consumer callbacks unless they were specified
+ * when the listener is registered.
+ *
+ *<p>
+ * The service maintains a loop-free topology of producers and consumers. What this means is that a
+ * consumer is not allowed to access a producer, which affects any of the subtrees it is subscribed
+ * to. This restriction is in place to ensure the system does not go into a feedback loop, where it
+ * is impossible to block either a producer or a consumer without accumulating excess work in the
+ * backlog stemming from its previous activity.
+ */
+@Beta
+public interface DataTreeService extends DataTreeProducerFactory, BindingService {
+
+ /**
+ * Register a {@link DataTreeListener} instance. Once registered, the listener will start
+ * receiving changes on the selected subtrees. If the listener cannot keep up with the rate of
+ * changes, and allowRxMerges is set to true, this service is free to merge the changes, so that
+ * a smaller number of them will be reported, possibly hiding some data transitions (like
+ * flaps).
+ *
+ *<p>
+ * If the listener wants to write into any producer, that producer has to be mentioned in the
+ * call to this method. Those producers will be bound exclusively to the registration, so that
+ * accessing them outside of this listener's callback will trigger an error. Any producers
+ * mentioned must be idle, e.g. they may not have an open transaction at the time this method is
+ * invoked.
+ *
+ *<p>
+ * Each listener instance can be registered at most once. Implementations of this interface have
+ * to guarantee that the listener's methods will not be invoked concurrently from multiple
+ * threads.
+ *
+ * @param listener {@link DataTreeListener} that is being registered
+ * @param subtrees Conceptual subtree identifier of subtrees which should be monitored for
+ * changes. May not be null or empty.
+ * @param allowRxMerges True if the backend may perform ingress state compression.
+ * @param producers {@link DataTreeProducer} instances to bind to the listener.
+ * @param <T> listener type
+ * @return A listener registration. Once closed, the listener will no longer be invoked and the
+ * producers will be unbound.
+ * @throws IllegalArgumentException if subtrees is empty or the listener is already bound
+ * @throws DataTreeLoopException if the registration of the listener to the specified subtrees
+ * with specified producers would form a feedback loop
+ */
+ @Nonnull
+ <T extends DataTreeListener> ListenerRegistration<T> registerListener(@Nonnull T listener,
+ @Nonnull Collection<DataTreeIdentifier<?>> subtrees, boolean allowRxMerges,
+ @Nonnull Collection<DataTreeProducer> producers) throws DataTreeLoopException;
+}
*
* @param child Child identifier
* @param data Data to be merged
+ * @param <T> data type
* @throws BackendFailedException when implementation-specific errors occurs while servicing the
* request.
*/
*
* @param child Child identifier
* @param data New node data
+ * @param <T> data type
* @throws BackendFailedException when implementation-specific errors occurs while servicing the
* request.
*/
<T extends TreeNode> void write(TreeArgument<T> child, T data);
-}
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import org.junit.Test;
+
+public class DataTreeListeningExceptionTest {
+
+ @Test(expected = DataTreeListeningException.class)
+ public void constructWithCauseTest() throws Exception {
+ throw new DataTreeListeningException("test", new Throwable());
+ }
+
+ @Test(expected = DataTreeListeningException.class)
+ public void constructTest() throws Exception {
+ throw new DataTreeListeningException("test");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import org.junit.Test;
+
+public class DataTreeLoopExceptionTest {
+
+ @Test(expected = DataTreeLoopException.class)
+ public void constructWithCauseTest() throws Exception {
+ throw new DataTreeLoopException("test", new Throwable());
+ }
+
+ @Test(expected = DataTreeLoopException.class)
+ public void constructTest() throws Exception {
+ throw new DataTreeLoopException("test");
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import org.junit.Test;
+
+public class DataTreeProducerBusyExceptionTest {
+
+ @Test(expected = DataTreeProducerBusyException.class)
+ public void constructWithCauseTest() throws Exception {
+ throw new DataTreeProducerBusyException("test", new Throwable());
+ }
+
+ @Test(expected = DataTreeProducerBusyException.class)
+ public void constructTest() throws Exception {
+ throw new DataTreeProducerBusyException("test");
+ }
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2017 Pantheon Technologies s.r.o. 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.mdsal.binding.javav2.api;
+
+import org.junit.Test;
+
+public class DataTreeProducerExceptionTest {
+
+ @Test(expected = DataTreeProducerException.class)
+ public void constructWithCauseTest() throws Exception {
+ throw new DataTreeProducerException("test", new Throwable());
+ }
+
+ @Test(expected = DataTreeProducerException.class)
+ public void constructTest() throws Exception {
+ throw new DataTreeProducerException("test");
+ }
+
+}
\ No newline at end of file