Remove AsyncDataBroker and related classes 16/76516/4
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 1 Oct 2018 07:33:39 +0000 (09:33 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Wed, 3 Oct 2018 08:18:06 +0000 (10:18 +0200)
DOM and Binding APIs need to evolve separately, remove the common
straightjacket they were using.

Change-Id: I91f49284c61020fff4b4e262aa03c0a7eca70a06
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
30 files changed:
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/DataBroker.java
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ReadTransaction.java
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/ReadWriteTransaction.java
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/Transaction.java
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/TransactionFactory.java
binding/mdsal-binding-api/src/main/java/org/opendaylight/mdsal/binding/api/WriteTransaction.java
binding/mdsal-binding-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/dom/adapter/AbstractForwardedTransaction.java
binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/DataBroker.java
binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/ReadTransaction.java
binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/Transaction.java
binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/TransactionFactory.java
binding2/mdsal-binding2-api/src/main/java/org/opendaylight/mdsal/binding/javav2/api/WriteTransaction.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/data/BindingDOMDataBrokerAdapter.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/impl/transaction/BindingDOMTransactionChainAdapter.java
binding2/mdsal-binding2-dom-adapter/src/main/java/org/opendaylight/mdsal/binding/javav2/dom/adapter/spi/AbstractForwardedTransaction.java
binding2/mdsal-binding2-spi/src/main/java/org/opendaylight/mdsal/binding/javav2/spi/ForwardingDataBroker.java
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataBroker.java [deleted file]
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataTransactionFactory.java [deleted file]
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadTransaction.java [deleted file]
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadWriteTransaction.java [deleted file]
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncTransaction.java [deleted file]
common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncWriteTransaction.java [deleted file]
common/mdsal-common-util/src/main/java/org/opendaylight/mdsal/common/util/ForwardingAsyncReadWriteTransaction.java [deleted file]
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataBroker.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeReadTransaction.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeReadWriteTransaction.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeTransaction.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMDataTreeWriteTransaction.java
dom/mdsal-dom-api/src/main/java/org/opendaylight/mdsal/dom/api/DOMTransactionFactory.java
dom/mdsal-dom-broker/src/main/java/org/opendaylight/mdsal/dom/broker/AbstractDOMForwardedCompositeTransaction.java

index 5bcfbea7c831c202c49b6c50ab484c0577fc2544..16e271712328e95a1dfd15244ee1a55c8152b9fd 100644 (file)
@@ -7,10 +7,6 @@
  */
 package org.opendaylight.mdsal.binding.api;
 
-import org.opendaylight.mdsal.common.api.AsyncDataBroker;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
 /**
  * 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.
@@ -42,8 +38,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL,
  * but only to be consumed by them.
  */
-public interface DataBroker extends AsyncDataBroker<InstanceIdentifier<?>, DataObject>, TransactionFactory,
-        BindingService, DataTreeChangeService {
+public interface DataBroker extends BindingService, TransactionFactory, DataTreeChangeService {
     /**
      * Create a new transaction chain. The chain will be initialized to read from its backing datastore, with
      * no outstanding transaction. Listener will be registered to handle chain-level events.
index 69fcba2ca0cbc7bc19c35a21f801985f6b9ca517..35c97389cb55cd0ce128d0da87113820c4fd3d5a 100644 (file)
@@ -9,9 +9,9 @@ package org.opendaylight.mdsal.binding.api;
 
 import com.google.common.util.concurrent.FluentFuture;
 import java.util.Optional;
-import org.opendaylight.mdsal.common.api.AsyncReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -50,7 +50,7 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * java.util.concurrent.Executor)} or other functions from {@link com.google.common.util.concurrent.Futures} to register
  * more specific listeners.
  */
-public interface ReadTransaction extends Transaction, AsyncReadTransaction<InstanceIdentifier<?>, DataObject> {
+public interface ReadTransaction extends Transaction, Registration {
     /**
      * Reads data from the provided logical data store located at the provided path.
      *
index 70299ec8a1f9181d3317f916775673722ebfe3b4..5ce5f4972a120c0f08aff4597ab5dfbe4d8ee999 100644 (file)
@@ -8,17 +8,15 @@
 package org.opendaylight.mdsal.binding.api;
 
 import com.google.common.annotations.Beta;
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
 /**
  * A transaction that enables combined read/write capabilities.
  *
  * <p>
- * For more information on usage and examples, please see the documentation in {@link AsyncReadWriteTransaction}.
+ * For more information on usage and examples, please see the documentation in {@link ReadTransaction} and
+ * {@link WriteTransaction}
  */
 @Beta
-public interface ReadWriteTransaction extends ReadTransaction, WriteTransaction,
-        AsyncReadWriteTransaction<InstanceIdentifier<?>, DataObject> {
+public interface ReadWriteTransaction extends ReadTransaction, WriteTransaction {
+
 }
index c5c1b42ae31fd17c189489476cc2c8ed70ebf47a..61e3a75d825ae2f9fa71e03d03c4be6750fbbece 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.api;
 
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.concepts.Identifiable;
 
 /**
  * A common parent for all transactions which operate on a conceptual data tree.
@@ -21,7 +19,6 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  *
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL.
  */
-public interface Transaction extends AsyncTransaction<InstanceIdentifier<?>, DataObject> {
-    @Override
-    Object getIdentifier();
+public interface Transaction extends Identifiable<Object> {
+
 }
index b41e7be9e68319490cdf2f153e73e57bd93ee4be..f7314bbd26f601c39b48f17701f7275447fb078c 100644 (file)
@@ -7,17 +7,86 @@
  */
 package org.opendaylight.mdsal.binding.api;
 
-import org.opendaylight.mdsal.common.api.AsyncDataTransactionFactory;
-import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public interface TransactionFactory extends AsyncDataTransactionFactory<InstanceIdentifier<?>, DataObject> {
-    @Override
+/**
+ * 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 DataBroker}
+ * <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()}
+ * </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 ReadTransaction}, {@link WriteTransaction}
+ * and {@link WriteTransaction#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 DataBroker
+*/
+public interface TransactionFactory {
+    /**
+     * Allocates a new read-only transaction which provides an immutable snapshot of the data tree. The view of data
+     * tree is an immutable snapshot of current data tree state when transaction was allocated.
+     *
+     * @return A new read-only transaction
+     */
     ReadTransaction newReadOnlyTransaction();
 
-    @Override
+    /**
+     * 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 ReadWriteTransaction#commit()} for more details about conflicting and non-conflicting
+     * changes and failure scenarios.
+     *
+     * @return new read-write transaction
+     */
     ReadWriteTransaction newReadWriteTransaction();
 
-    @Override
+    /**
+     * 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 WriteTransaction#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 who are exclusive
+     * writers (exporters of data) to the subtree they modify. This prevents optimistic lock failures as described in
+     * {@link WriteTransaction#commit()}.
+     *
+     * <p>
+     * Exclusivity of writers to particular subtree SHOULD BE enforced by external locking mechanism.
+     *
+     * @return new write-only transaction
+     */
     WriteTransaction newWriteOnlyTransaction();
 }
index c9c0d022f1eac61c892d922b0fdb9ef9984a2a2f..a94c989fd42bafa10af414b79117ba065283ae93 100644 (file)
@@ -10,9 +10,11 @@ package org.opendaylight.mdsal.binding.api;
 import com.google.common.util.concurrent.FluentFuture;
 import javax.annotation.CheckReturnValue;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.common.api.AsyncWriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.DataValidationFailedException;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 
@@ -83,11 +85,366 @@ import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL, but only to be
  * consumed by them.
  */
-public interface WriteTransaction extends Transaction, AsyncWriteTransaction<InstanceIdentifier<?>, DataObject> {
-    @Override
+public interface WriteTransaction extends Transaction {
+    /**
+     * Cancels the transaction. Transactions can only be cancelled if it was not yet committed.
+     * Invoking cancel() on failed or already canceled will have no effect, and transaction is considered cancelled.
+     * Invoking cancel() on finished transaction (future returned by {@link #commit()} 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();
 
-    @Override
+    /**
+     * Commits this transaction to be asynchronously applied to update the logical data tree. The returned
+     * {@link FluentFuture} conveys the result of applying the data changes.
+     *
+     * <p>
+     * This call logically seals the transaction, which prevents the client from further changing the data tree using
+     * this transaction. Any subsequent calls to <code>put(LogicalDatastoreType, Path, Object)</code>,
+     * <code>merge(LogicalDatastoreType, Path, Object)</code>, <code>delete(LogicalDatastoreType, Path)</code> will fail
+     * with {@link IllegalStateException}. The transaction is marked as committed and enqueued into the data store
+     * back-end for processing.
+     *
+     * <p>
+     * Whether or not the commit is successful is determined by versioning of the data tree and validation of registered
+     * commit participants if the transaction changes the data tree.
+     *
+     * <p>
+     * The effects of a successful commit of data depends on listeners and commit participants that are registered with
+     * the data broker.
+     *
+     * <h3>Example usage:</h3>
+     * <pre>
+     *  private void doWrite(final int tries) {
+     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+     *      MyDataObject data = ...;
+     *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
+     *      writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
+     *      Futures.addCallback(writeTx.commit(), new FutureCallback&lt;CommitInfo&gt;() {
+     *          public void onSuccess(CommitInfo result) {
+     *              // succeeded
+     *          }
+     *          public void onFailure(Throwable t) {
+     *              if (t instanceof OptimisticLockFailedException) {
+     *                  if(( tries - 1) &gt; 0 ) {
+     *                      // do retry
+     *                      doWrite(tries - 1);
+     *                  } else {
+     *                      // out of retries
+     *                  }
+     *              } else {
+     *                  // failed due to another type of TransactionCommitFailedException.
+     *              }
+     *          });
+     * }
+     * ...
+     * doWrite(2);
+     * </pre>
+     *
+     * <h2>Failure scenarios</h2>
+     *
+     * <p>
+     * Transaction may fail because of multiple reasons, such as
+     * <ul>
+     *   <li>
+     *     Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
+     *     case the returned future will fail with an {@link OptimisticLockFailedException}. It is the responsibility
+     *     of the caller to create a new transaction and commit the same modification again in order to update data
+     *     tree.
+     *     <i>
+     *       <b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result in a high
+     *       probability of success. However, there are scenarios, albeit unusual, where any number of retries will
+     *       not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid
+     *       an endless loop.
+     *     </i>
+     *   </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 a {@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 committed.
+     *
+     * <table summary="Change compatibility of leaf values">
+     * <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 committed.
+     *
+     * <table summary="Change compatibility of containers">
+     * <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 FluentFuture} 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 FluentFuture} object will fail with {@link OptimisticLockFailedException}
+     * exception, which indicates to client that concurrent transaction prevented the committed
+     * transaction from being applied. <br>
+     *
+     * <p>
+     * A successful commit produces implementation-specific {@link CommitInfo} structure, which is used to communicate
+     * post-condition information to the caller. Such information can contain commit-id, timing information or any
+     * other information the implementation wishes to share.
+     *
+     * @return a FluentFuture containing the result of the commit information. The Future blocks until the commit
+     *         operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
+     *         {@link TransactionCommitFailedException} or an exception derived from TransactionCommitFailedException.
+     * @throws IllegalStateException if the transaction is already committed or was canceled.
+     */
     @CheckReturnValue
     @NonNull FluentFuture<? extends @NonNull CommitInfo> commit();
 
@@ -101,8 +458,6 @@ public interface WriteTransaction extends Transaction, AsyncWriteTransaction<Ins
      * with <code>createMissingParents</code> set to false.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
-     * <p>
      * If you need to make sure that a parent object exists but you do not want modify
      * its pre-existing state by using put, consider using {@link #merge} instead.
      *
@@ -115,23 +470,16 @@ public interface WriteTransaction extends Transaction, AsyncWriteTransaction<Ins
     <T extends DataObject> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data);
 
     /**
-     * Stores a piece of data at the specified path. This acts as an add /
-     * replace operation, which is to say that whole subtree will be replaced by
-     * the specified data.
-     *
-     * <p>
-     * For more information on usage and examples, please see the documentation
-     * in {@link AsyncWriteTransaction}.
+     * Stores a piece of data at the specified path. This acts as an add / replace operation, which is to say that whole
+     * subtree will be replaced by the specified data.
      *
      * <p>
-     * If you need to make sure that a parent object exists but you do not want
-     * modify its pre-existing state by using put, consider using {@link #merge}
-     * instead.
+     * If you need to make sure that a parent object exists but you do not want modify its pre-existing state by using
+     * put, consider using {@link #merge} instead.
      *
      * <p>
-     * Note: Using <code>createMissingParents</code> with value true, may
-     * introduce garbage in data store, or recreate nodes, which were deleted by
-     * previous transaction.
+     * Note: Using <code>createMissingParents</code> with value true, may introduce garbage in data store, or recreate
+     * nodes, which were deleted by previous transaction.
      *
      * @param store the logical data store which should be modified
      * @param path the data object path
@@ -154,9 +502,6 @@ public interface WriteTransaction extends Transaction, AsyncWriteTransaction<Ins
      * with <code>createMissingParents</code> set to false.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
-     *
-     * <p>
      * If you require an explicit replace operation, use {@link #put} instead.
      * @param store the logical data store which should be modified
      * @param path the data object path
@@ -171,9 +516,6 @@ public interface WriteTransaction extends Transaction, AsyncWriteTransaction<Ins
      * overwritten will be preserved. This means that if you store a container, its child lists will be merged.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
-     *
-     * <p>
      * If you require an explicit replace operation, use {@link #put} instead.
      *
      * @param store the logical data store which should be modified
@@ -187,7 +529,13 @@ public interface WriteTransaction extends Transaction, AsyncWriteTransaction<Ins
     <T extends DataObject> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
             boolean createMissingParents);
 
-    @Override
+    /**
+     * Removes 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 was committed or canceled.
+     */
     void delete(LogicalDatastoreType store, InstanceIdentifier<?> path);
 
     /**
index cf2b24e2333459f0e316a50e2bdee985e5e7420b..276521ca8ce13e1ad5e74bfbaab68657c78348d0 100644 (file)
@@ -7,46 +7,46 @@
  */
 package org.opendaylight.mdsal.binding.dom.adapter;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Optional;
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.concepts.Identifiable;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
-abstract class AbstractForwardedTransaction<T extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>>
-        implements Delegator<T>, Identifiable<Object> {
+abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction> implements Delegator<T>,
+        Identifiable<Object> {
 
     private final T delegate;
     private final BindingToNormalizedNodeCodec codec;
 
     AbstractForwardedTransaction(final T delegateTx, final BindingToNormalizedNodeCodec codec) {
-        this.delegate = Preconditions.checkNotNull(delegateTx, "Delegate must not be null");
-        this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
+        this.delegate = requireNonNull(delegateTx, "Delegate must not be null");
+        this.codec = requireNonNull(codec, "Codec must not be null");
     }
 
 
     @Override
-    public final  Object getIdentifier() {
+    public final Object getIdentifier() {
         return delegate.getIdentifier();
     }
 
     @Override
-    public final  T getDelegate() {
+    public final T getDelegate() {
         return delegate;
     }
 
     @SuppressWarnings("unchecked")
-    protected final <S extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>> S getDelegateChecked(
-            final Class<S> txType) {
-        Preconditions.checkState(txType.isInstance(delegate));
+    protected final <S extends DOMDataTreeTransaction> S getDelegateChecked(final Class<S> txType) {
+        checkState(txType.isInstance(delegate));
         return (S) delegate;
     }
 
@@ -57,7 +57,7 @@ abstract class AbstractForwardedTransaction<T extends AsyncTransaction<YangInsta
     protected final <D extends DataObject> FluentFuture<Optional<D>> doRead(
             final DOMDataTreeReadTransaction readTx, final LogicalDatastoreType store,
             final InstanceIdentifier<D> path) {
-        Preconditions.checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
+        checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
 
         return readTx.read(store, codec.toYangInstanceIdentifierBlocking(path))
                 .transform(codec.getCodecRegistry().deserializeFunction(path)::apply, MoreExecutors.directExecutor());
index 713d13099189c73d63cee6d3191b31134a2ea5ef..536de55ecab552e096be46cf07336118be112da7 100644 (file)
@@ -8,9 +8,6 @@
 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;
 
 /**
  * Provides access to a conceptual data tree store and also provides the ability to
@@ -44,8 +41,7 @@ import org.opendaylight.mdsal.common.api.AsyncDataBroker;
  * but only to be consumed by them.
  */
 @Beta
-public interface DataBroker extends AsyncDataBroker<InstanceIdentifier<?>, TreeNode>, BindingService,
-        TransactionFactory, DataTreeService {
+public interface DataBroker extends BindingService, TransactionFactory, DataTreeService {
     /**
      * Create a new transaction chain. The chain will be initialized to read from its backing datastore, with
      * no outstanding transaction. Listener will be registered to handle chain-level events.
index 34c786c7ac0dc94708b580132fb55ef2f923db23..21dc6850e947901560d07421554b341aea24b564 100644 (file)
@@ -5,27 +5,53 @@
  * 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 org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.yangtools.concepts.Registration;
 
 /**
- * A transaction that provides a stateful read-only view of the data tree.
+ * A transaction that provides read access to a logical data store.
+ *
+ * <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>
- * For more information on usage and examples, please see the documentation in
- *  {@link org.opendaylight.mdsal.common.api.AsyncReadTransaction}.
+ * <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>
+ * Lets assume initial state of data tree for <code>PATH</code> is <code>A</code>.
+ *
+ * <code>
+ * 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.submit().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;
+ * </code>
+ *
+ * <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 com.google.common.util.concurrent.FluentFuture#get()} is
+ * discouraged for most uses and you should use
+ * {@link com.google.common.util.concurrent.FluentFuture#addCallback(com.google.common.util.concurrent.FutureCallback,
+ * java.util.concurrent.Executor)} or other functions from {@link com.google.common.util.concurrent.Futures} to register
+ * more specific listeners.
  */
 @Beta
-public interface ReadTransaction extends Transaction, AsyncReadTransaction<InstanceIdentifier<?>, TreeNode> {
-
+public interface ReadTransaction extends Transaction, Registration {
     /**
      * Reads data from the provided logical data store located at the provided path.
      *
@@ -43,4 +69,10 @@ public interface ReadTransaction extends Transaction, AsyncReadTransaction<Insta
      */
     <T extends TreeNode> void read(LogicalDatastoreType store, InstanceIdentifier<T> path,
         BiConsumer<ReadFailedException, T> callback);
+
+    /**
+     * Closes this transaction and releases all resources associated with it.
+     */
+    @Override
+    void close();
 }
index 99b2000cd3fb1930ea4dba8dfdcdf87ca5842c61..0cbd97581aa7cf7bd3fa2ded31476a806e7659bb 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.mdsal.binding.javav2.api;
 
-import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
-import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
+import org.opendaylight.yangtools.concepts.Identifiable;
 
 /**
  * A common parent for all transactions which operate on a conceptual data tree.
@@ -21,7 +19,6 @@ import org.opendaylight.mdsal.common.api.AsyncTransaction;
  *
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL.
  */
-public interface Transaction extends AsyncTransaction<InstanceIdentifier<?>, TreeNode> {
-    @Override
-    Object getIdentifier();
+public interface Transaction extends Identifiable<Object> {
+
 }
index aa9f5708d2150bb0775a71c3445504e597070865..32eaa393d4aeee29bea6d159fd3563400b8fc59c 100644 (file)
@@ -8,23 +8,75 @@
 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.AsyncDataTransactionFactory;
 
 /**
  * A factory which allocates new transactions to operate on the data tree.
  *
  * <p>
- * For more information on usage, please see the documentation in {@link AsyncDataTransactionFactory}.
+ * <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 DataBroker}
+ * <li> {@link TransactionChain}
+ * </ul>
  *
- * @see AsyncDataTransactionFactory
- */
+ * <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()}
+ * </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 ReadTransaction}, {@link WriteTransaction}
+ * and {@link WriteTransaction#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 DataBroker
+*/
 @Beta
-public interface TransactionFactory extends AsyncDataTransactionFactory<InstanceIdentifier<?>, TreeNode> {
-    @Override
+public interface TransactionFactory {
+    /**
+     * Allocates a new read-only transaction which provides an immutable snapshot of the data tree. The view of data
+     * tree is an immutable snapshot of current data tree state when transaction was allocated.
+     *
+     * @return A new read-only transaction
+     */
     ReadTransaction newReadOnlyTransaction();
 
-    @Override
+    /**
+     * 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 WriteTransaction#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 who are exclusive
+     * writers (exporters of data) to the subtree they modify. This prevents optimistic lock failures as described in
+     * {@link WriteTransaction#commit()}.
+     *
+     * <p>
+     * Exclusivity of writers to particular subtree SHOULD BE enforced by external locking mechanism.
+     *
+     * @return new write-only transaction
+     */
     WriteTransaction newWriteOnlyTransaction();
 }
index 10e582ad3da2b0320cc282108c588c8b4ef5bec1..cad3ab22c1a4e60ab9a5e7aa0eb3c27566995e6f 100644 (file)
@@ -13,9 +13,11 @@ import javax.annotation.CheckReturnValue;
 import org.eclipse.jdt.annotation.NonNull;
 import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncWriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.DataValidationFailedException;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 
 /**
  * A transaction that provides mutation capabilities on a data tree.
@@ -85,11 +87,366 @@ import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
  * consumed by them.
  */
 @Beta
-public interface WriteTransaction extends AsyncWriteTransaction<InstanceIdentifier<?>, TreeNode>, Transaction {
-    @Override
+public interface WriteTransaction extends Transaction {
+    /**
+     * Cancels the transaction. Transactions can only be cancelled if it was not yet committed.
+     * Invoking cancel() on failed or already canceled will have no effect, and transaction is considered cancelled.
+     * Invoking cancel() on finished transaction (future returned by {@link #commit()} 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();
 
-    @Override
+    /**
+     * Commits this transaction to be asynchronously applied to update the logical data tree. The returned
+     * {@link FluentFuture} conveys the result of applying the data changes.
+     *
+     * <p>
+     * This call logically seals the transaction, which prevents the client from further changing the data tree using
+     * this transaction. Any subsequent calls to <code>put(LogicalDatastoreType, Path, Object)</code>,
+     * <code>merge(LogicalDatastoreType, Path, Object)</code>, <code>delete(LogicalDatastoreType, Path)</code> will fail
+     * with {@link IllegalStateException}. The transaction is marked as committed and enqueued into the data store
+     * back-end for processing.
+     *
+     * <p>
+     * Whether or not the commit is successful is determined by versioning of the data tree and validation of registered
+     * commit participants if the transaction changes the data tree.
+     *
+     * <p>
+     * The effects of a successful commit of data depends on listeners and commit participants that are registered with
+     * the data broker.
+     *
+     * <h3>Example usage:</h3>
+     * <pre>
+     *  private void doWrite(final int tries) {
+     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+     *      MyDataObject data = ...;
+     *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
+     *      writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
+     *      Futures.addCallback(writeTx.commit(), new FutureCallback&lt;CommitInfo&gt;() {
+     *          public void onSuccess(CommitInfo result) {
+     *              // succeeded
+     *          }
+     *          public void onFailure(Throwable t) {
+     *              if (t instanceof OptimisticLockFailedException) {
+     *                  if(( tries - 1) &gt; 0 ) {
+     *                      // do retry
+     *                      doWrite(tries - 1);
+     *                  } else {
+     *                      // out of retries
+     *                  }
+     *              } else {
+     *                  // failed due to another type of TransactionCommitFailedException.
+     *              }
+     *          });
+     * }
+     * ...
+     * doWrite(2);
+     * </pre>
+     *
+     * <h2>Failure scenarios</h2>
+     *
+     * <p>
+     * Transaction may fail because of multiple reasons, such as
+     * <ul>
+     *   <li>
+     *     Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
+     *     case the returned future will fail with an {@link OptimisticLockFailedException}. It is the responsibility
+     *     of the caller to create a new transaction and commit the same modification again in order to update data
+     *     tree.
+     *     <i>
+     *       <b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result in a high
+     *       probability of success. However, there are scenarios, albeit unusual, where any number of retries will
+     *       not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid
+     *       an endless loop.
+     *     </i>
+     *   </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 a {@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 committed.
+     *
+     * <table summary="Change compatibility of leaf values">
+     * <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 committed.
+     *
+     * <table summary="Change compatibility of containers">
+     * <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 FluentFuture} 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 FluentFuture} object will fail with {@link OptimisticLockFailedException}
+     * exception, which indicates to client that concurrent transaction prevented the committed
+     * transaction from being applied. <br>
+     *
+     * <p>
+     * A successful commit produces implementation-specific {@link CommitInfo} structure, which is used to communicate
+     * post-condition information to the caller. Such information can contain commit-id, timing information or any
+     * other information the implementation wishes to share.
+     *
+     * @return a FluentFuture containing the result of the commit information. The Future blocks until the commit
+     *         operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
+     *         {@link TransactionCommitFailedException} or an exception derived from TransactionCommitFailedException.
+     * @throws IllegalStateException if the transaction is already committed or was canceled.
+     */
     @CheckReturnValue
     @NonNull FluentFuture<? extends @NonNull CommitInfo> commit();
 
@@ -103,8 +460,6 @@ public interface WriteTransaction extends AsyncWriteTransaction<InstanceIdentifi
      * with <code>createMissingParents</code> set to false.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
-     * <p>
      * If you need to make sure that a parent object exists but you do not want modify
      * its pre-existing state by using put, consider using {@link #merge} instead.
      *
@@ -121,18 +476,12 @@ public interface WriteTransaction extends AsyncWriteTransaction<InstanceIdentifi
     <T extends TreeNode> void put(LogicalDatastoreType store, InstanceIdentifier<T> path, T data);
 
     /**
-     * Stores a piece of data at the specified path. This acts as an add /
-     * replace operation, which is to say that whole subtree will be replaced by
-     * the specified data.
-     *
-     * <p>
-     * For more information on usage and examples, please see the documentation
-     * in {@link AsyncWriteTransaction}.
+     * Stores a piece of data at the specified path. This acts as an add / replace operation, which is to say that whole
+     * subtree will be replaced by the specified data.
      *
      * <p>
-     * If you need to make sure that a parent object exists but you do not want
-     * modify its pre-existing state by using put, consider using {@link #merge}
-     * instead.
+     * If you need to make sure that a parent object exists but you do not want modify its pre-existing state by using
+     * put, consider using {@link #merge} instead.
      *
      * <p>
      * Note: Using <code>createMissingParents</code> with value true, may
@@ -156,9 +505,8 @@ public interface WriteTransaction extends AsyncWriteTransaction<InstanceIdentifi
         boolean createMissingParents);
 
     /**
-     * Merges a piece of data with the existing data at a specified path. 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.
+     * Merges a piece of data with the existing data at a specified path. 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.
      *
      * <p>
      * This method does not automatically create missing parent nodes. It is equivalent to invoking
@@ -166,51 +514,42 @@ public interface WriteTransaction extends AsyncWriteTransaction<InstanceIdentifi
      * with <code>createMissingParents</code> set to false.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in
-     * {@link AsyncWriteTransaction}.
-     *
-     *<p>
      * If you require an explicit replace operation, use {@link #put} instead.
-     * @param store
-     *            the logical data store which should be modified
-     * @param path
-     *            the data object path
-     * @param data
-     *            the data object to be merged to the specified path
+     * @param store the logical data store which should be modified
+     * @param path the data object path
+     * @param data the data object to be merged to the specified path
      * @param <T> data tree type
-     * @throws IllegalStateException
-     *             if the transaction has already been submitted
+     * @throws IllegalStateException if the transaction has already been submitted
      */
     <T extends TreeNode> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data);
 
     /**
-     * Merges a piece of data with the existing data at a specified path. 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.
-     *
-     * <p>
-     * For more information on usage and examples, please see the documentation
-     * in {@link AsyncWriteTransaction}.
+     * Merges a piece of data with the existing data at a specified path. 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.
      *
      * <p>
      * If you require an explicit replace operation, use {@link #put} instead.
      *
-     * @param store
-     *            the logical data store which should be modified
-     * @param path
-     *            the data object path
-     * @param data
-     *            the data object to be merged to the specified path
-     * @param createMissingParents
-     *            if {@link #CREATE_MISSING_PARENTS}, any missing parent nodes will be automatically created
-     *            using a merge operation.
+     * @param store the logical data store which should be modified
+     * @param path the data object path
+     * @param data the data object to be merged to the specified path
+     * @param createMissingParents if {@link #CREATE_MISSING_PARENTS}, any missing parent nodes will be automatically
+     *                             created using a merge operation.
      * @param <T> data tree type
-     * @throws IllegalStateException
-     *             if the transaction has already been submitted
+     * @throws IllegalStateException if the transaction has already been submitted
      */
     <T extends TreeNode> void merge(LogicalDatastoreType store, InstanceIdentifier<T> path, T data,
         boolean createMissingParents);
 
+    /**
+     * Removes 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 was committed or canceled.
+     */
+    void delete(LogicalDatastoreType store, InstanceIdentifier<?> path);
+
     /**
      * Flag value indicating that missing parents should be created.
      */
index ba5c28b2e0438614f37a94c85dd92303005f9afa..523642cccde1782eaedae0acca7e98ff2d5e7072 100644 (file)
@@ -31,9 +31,6 @@ import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.AbstractForwardedDa
 import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.BindingDOMAdapterBuilder;
 import org.opendaylight.mdsal.binding.javav2.dom.adapter.spi.builder.BindingDOMAdapterBuilder.Factory;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
-import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
 import org.opendaylight.mdsal.dom.api.DOMService;
@@ -78,12 +75,6 @@ public class BindingDOMDataBrokerAdapter extends AbstractForwardedDataBroker imp
         return new BindingDOMWriteTransactionAdapter<>(getDelegate().newWriteOnlyTransaction(), getCodec());
     }
 
-    @Override
-    public AsyncReadWriteTransaction<InstanceIdentifier<?>, TreeNode> newReadWriteTransaction() {
-        // TODO - placeholder for now
-        throw new UnsupportedOperationException();
-    }
-
     @Override
     public TransactionChain createTransactionChain(final TransactionChainListener listener) {
         return new BindingDOMTransactionChainAdapter(getDelegate(), getCodec(), listener);
index e02d2f2624440a86377a01ec52fcff13e36fef4c..3dcfe8278e815c4a8ba65bbcda17226cb5f87b26 100644 (file)
@@ -22,9 +22,6 @@ import org.opendaylight.mdsal.binding.javav2.api.TransactionChainClosedException
 import org.opendaylight.mdsal.binding.javav2.api.TransactionChainListener;
 import org.opendaylight.mdsal.binding.javav2.api.WriteTransaction;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
-import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
-import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
@@ -79,12 +76,6 @@ public final class BindingDOMTransactionChainAdapter implements TransactionChain
         };
     }
 
-    @Override
-    public AsyncReadWriteTransaction<InstanceIdentifier<?>, TreeNode> newReadWriteTransaction() {
-        // TODO - placeholder for now
-        throw new UnsupportedOperationException();
-    }
-
     private <T, F extends FluentFuture<T>> F listenForFailure(final WriteTransaction tx, final F future) {
         future.addCallback(new FutureCallback<T>() {
             @Override
index 7fbb2e94bf66cae75061fc0c17376476e80c64bf..ce0c955bb9603095d144e7e673228082c5233f4f 100644 (file)
@@ -7,8 +7,11 @@
  */
 package org.opendaylight.mdsal.binding.javav2.dom.adapter.spi;
 
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkState;
+import static java.util.Objects.requireNonNull;
+
 import com.google.common.annotations.Beta;
-import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FluentFuture;
 import com.google.common.util.concurrent.MoreExecutors;
 import java.util.Optional;
@@ -16,31 +19,27 @@ import javax.annotation.Nonnull;
 import org.opendaylight.mdsal.binding.javav2.dom.codec.impl.BindingToNormalizedNodeCodec;
 import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
 import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
 import org.opendaylight.yangtools.concepts.Delegator;
 import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 /**
  * Abstract class for forwards transaction and codec for serialize/deserialize DOM and Binding data.
  *
- * @param <T>
- *            - type of asynchronous transaction
+ * @param <T> type of asynchronous transaction
  */
 @Beta
-public abstract class AbstractForwardedTransaction<
-        T extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>>
+public abstract class AbstractForwardedTransaction<T extends DOMDataTreeTransaction>
         implements Delegator<T>, Identifiable<Object> {
 
     private final T delegate;
     private final BindingToNormalizedNodeCodec codec;
 
     public AbstractForwardedTransaction(final T delegateTx, final BindingToNormalizedNodeCodec codec) {
-        this.delegate = Preconditions.checkNotNull(delegateTx, "Delegate must not be null");
-        this.codec = Preconditions.checkNotNull(codec, "Codec must not be null");
+        this.delegate = requireNonNull(delegateTx, "Delegate must not be null");
+        this.codec = requireNonNull(codec, "Codec must not be null");
     }
 
     @Nonnull
@@ -55,9 +54,8 @@ public abstract class AbstractForwardedTransaction<
     }
 
     @SuppressWarnings("unchecked")
-    protected final <S extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>>> S
-            getDelegateChecked(final Class<S> txType) {
-        Preconditions.checkState(txType.isInstance(delegate));
+    protected final <S extends DOMDataTreeTransaction> S getDelegateChecked(final Class<S> txType) {
+        checkState(txType.isInstance(delegate));
         return (S) delegate;
     }
 
@@ -68,7 +66,7 @@ public abstract class AbstractForwardedTransaction<
     protected final <D extends TreeNode> FluentFuture<Optional<D>> doRead(
             final DOMDataTreeReadTransaction readTx, final LogicalDatastoreType store,
             final InstanceIdentifier<D> path) {
-        Preconditions.checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
+        checkArgument(!path.isWildcarded(), "Invalid read of wildcarded path %s", path);
 
         return readTx.read(store, codec.toYangInstanceIdentifierBlocking(path))
             .transform(codec.deserializeFunction(path)::apply, MoreExecutors.directExecutor());
index 77622fd9fc2cc27aeef7fa0d7d73ad94ad012ebf..fd66e0eec74c8a7b487db80e7e14a09988217cbf 100644 (file)
@@ -19,9 +19,6 @@ import org.opendaylight.mdsal.binding.javav2.api.ReadTransaction;
 import org.opendaylight.mdsal.binding.javav2.api.TransactionChain;
 import org.opendaylight.mdsal.binding.javav2.api.TransactionChainListener;
 import org.opendaylight.mdsal.binding.javav2.api.WriteTransaction;
-import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
-import org.opendaylight.mdsal.binding.javav2.spec.base.TreeNode;
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
 
 /**
@@ -38,11 +35,6 @@ public abstract class ForwardingDataBroker extends ForwardingObject implements D
         return delegate().newReadOnlyTransaction();
     }
 
-    @Override
-    public AsyncReadWriteTransaction<InstanceIdentifier<?>, TreeNode> newReadWriteTransaction() {
-        return delegate().newReadWriteTransaction();
-    }
-
     @Override
     public WriteTransaction newWriteOnlyTransaction() {
         return delegate().newWriteOnlyTransaction();
@@ -65,5 +57,4 @@ public abstract class ForwardingDataBroker extends ForwardingObject implements D
     public TransactionChain createTransactionChain(final TransactionChainListener listener) {
         return delegate().createTransactionChain(listener);
     }
-
 }
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataBroker.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataBroker.java
deleted file mode 100644 (file)
index 33afe6d..0000000
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.common.api;
-
-import org.opendaylight.yangtools.concepts.Path;
-
-
-/**
- * Base interface that 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>
- * 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()}
- * </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}
- * 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
- * @deprecated This interface is being removed. Use either {@code org.opendaylight.mdsal.binding.api.DataBroker}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMDataBroker} instead.
- */
-@Deprecated
-public interface AsyncDataBroker<P extends Path<P>, D> extends
-        AsyncDataTransactionFactory<P, D> {
-
-
-    @Override
-    AsyncReadTransaction<P, D> newReadOnlyTransaction();
-
-
-    @Override
-    AsyncWriteTransaction<P, D> newWriteOnlyTransaction();
-
-    @Override
-    AsyncReadWriteTransaction<P, D> newReadWriteTransaction();
-}
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataTransactionFactory.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncDataTransactionFactory.java
deleted file mode 100644 (file)
index b6d1693..0000000
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.common.api;
-
-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}
- * </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()}
- * </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}
- * 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
- *
- * @param <P> Type of path (subtree identifier), which represents location in tree
- * @param <D> Type of data (payload), which represents data payload
- * @deprecated This interface is being removed. Use either {@code org.opendaylight.mdsal.binding.api.TransactionFactory}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMTransactionFactory} instead.
- */
-@Deprecated
-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 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();
-
-    /**
-     * 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();
-}
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadTransaction.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadTransaction.java
deleted file mode 100644 (file)
index 00d9792..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.common.api;
-
-import org.opendaylight.yangtools.concepts.Path;
-
-/**
- * Marker interface for stateful read 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>
- * Lets 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 = broker.put(OPERATIONAL, PATH, B); // writes B to PATH
- * txRead.read(OPERATIONAL, PATH).get(); // still returns Optional containing A
- * txWrite.submit().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 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
- * @deprecated This interface is being removed. Use either {@code org.opendaylight.mdsal.binding.api.ReadTransaction}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction} instead.
- */
-@Deprecated
-public interface AsyncReadTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D>, AutoCloseable {
-
-    /**
-     * Closes this transaction and releases all resources associated with it.
-     */
-    @Override
-    void close();
-}
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadWriteTransaction.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncReadWriteTransaction.java
deleted file mode 100644 (file)
index 5d63b97..0000000
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright (c) 2017 Brocade Communications 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.mdsal.common.api;
-
-import org.opendaylight.yangtools.concepts.Path;
-
-/**
- * Transaction enabling a client to have 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.
- *
- * <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 commits 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>
- *
- * <p>
- * Let's 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>
- *
- * <p>
- * 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.
- *
- * @see AsyncReadTransaction
- * @see AsyncWriteTransaction
- *
- * @param <P> Type of path (subtree identifier), which represents location in tree
- * @param <D> Type of data (payload), which represents data payload
- * @deprecated This interface is being removed. Use either
- *             {@code org.opendaylight.mdsal.binding.api.ReadWriteTransaction}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction} instead.
- */
-@Deprecated
-public interface AsyncReadWriteTransaction<P extends Path<P>, D> extends AsyncReadTransaction<P, D>,
-        AsyncWriteTransaction<P, D> {
-
-}
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncTransaction.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncTransaction.java
deleted file mode 100644 (file)
index 644a319..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.common.api;
-
-import org.opendaylight.yangtools.concepts.Identifiable;
-import org.opendaylight.yangtools.concepts.Path;
-
-/**
- * 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>
- * </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
- * @deprecated This interface is being removed.  Use either {@code org.opendaylight.mdsal.binding.api.Transaction}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction} instead.
- */
-@Deprecated
-public interface AsyncTransaction<P extends Path<P>,D> extends Identifiable<Object> {
-    @Override
-    Object getIdentifier();
-}
diff --git a/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncWriteTransaction.java b/common/mdsal-common-api/src/main/java/org/opendaylight/mdsal/common/api/AsyncWriteTransaction.java
deleted file mode 100644 (file)
index 2da17bd..0000000
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
- *
- * This program and the accompanying materials are made available under the
- * terms of the Eclipse Public License v1.0 which accompanies this distribution,
- * and is available at http://www.eclipse.org/legal/epl-v10.html
- */
-package org.opendaylight.mdsal.common.api;
-
-import com.google.common.util.concurrent.FluentFuture;
-import com.google.common.util.concurrent.ListenableFuture;
-import javax.annotation.CheckReturnValue;
-import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.yangtools.concepts.Path;
-
-/**
- * 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 make changes to the local data tree in the transaction by via the
- * <b>put</b>, <b>merge</b>, and <b>delete</b> operations.
- *
- * <h2>Put operation</h2>
- * Stores a piece of data at a specified path. This acts as an add / replace
- * operation, which is to say that whole subtree will be replaced by the
- * specified data.
- *
- * <p>
- * 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>
- * <h2>Merge operation</h2>
- * Merges a piece of data with the existing data at a specified path. 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.
- *
- * <p>
- * 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.
- *
- * <h2>Delete operation</h2>
- * Removes a piece of data from a specified path.
- *
- * <p>
- * After applying changes to the local data tree, 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 commits 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
- * @deprecated This interface is being removed. Use either {@code org.opendaylight.mdsal.binding.api.WriteTransaction}
- *             or {@code org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction} instead.
- */
-@Deprecated
-public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransaction<P, D> {
-    /**
-     * Cancels the transaction.
-     * Transactions can only be cancelled if it was not yet committed.
-     * Invoking cancel() on failed or already canceled will have no effect, and transaction is
-     * considered cancelled.
-     * Invoking cancel() on finished transaction (future returned by {@link #commit()} 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();
-
-    /**
-     * Removes 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 was committed or canceled.
-     */
-    void delete(LogicalDatastoreType store, P path);
-
-    /**
-     * Commits this transaction to be asynchronously applied to update the logical data tree. The returned
-     * {@link FluentFuture} conveys the result of applying the data changes.
-     *
-     * <p>
-     * This call logically seals the transaction, which prevents the client from further changing the data tree using
-     * this transaction. Any subsequent calls to <code>put(LogicalDatastoreType, Path, Object)</code>,
-     * <code>merge(LogicalDatastoreType, Path, Object)</code>, <code>delete(LogicalDatastoreType, Path)</code> will fail
-     * with {@link IllegalStateException}. The transaction is marked as committed and enqueued into the data store
-     * back-end for processing.
-     *
-     * <p>
-     * Whether or not the commit is successful is determined by versioning of the data tree and validation of registered
-     * commit participants if the transaction changes the data tree.
-     *
-     * <p>
-     * The effects of a successful commit of data depends on listeners and commit participants that are registered with
-     * the data broker.
-     *
-     * <h3>Example usage:</h3>
-     * <pre>
-     *  private void doWrite(final int tries) {
-     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
-     *      MyDataObject data = ...;
-     *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
-     *      writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
-     *      Futures.addCallback(writeTx.commit(), new FutureCallback&lt;CommitInfo&gt;() {
-     *          public void onSuccess(CommitInfo result) {
-     *              // succeeded
-     *          }
-     *          public void onFailure(Throwable t) {
-     *              if(t instanceof OptimisticLockFailedException) {
-     *                  if(( tries - 1) &gt; 0 ) {
-     *                      // do retry
-     *                      doWrite(tries - 1);
-     *                  } else {
-     *                      // out of retries
-     *                  }
-     *              } else {
-     *                  // failed due to another type of TransactionCommitFailedException.
-     *              }
-     *          });
-     * }
-     * ...
-     * doWrite(2);
-     * </pre>
-     *
-     * <h2>Failure scenarios</h2>
-     *
-     * <p>
-     * Transaction may fail because of multiple reasons, such as
-     * <ul>
-     *   <li>
-     *     Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
-     *     case the returned future will fail with an {@link OptimisticLockFailedException}. It is the responsibility
-     *     of the caller to create a new transaction and commit the same modification again in order to update data
-     *     tree.
-     *     <i>
-     *       <b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result in a high
-     *       probability of success. However, there are scenarios, albeit unusual, where any number of retries will
-     *       not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid
-     *       an endless loop.
-     *     </i>
-     *   </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 a {@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 committed.
-     *
-     * <table summary="Change compatibility of leaf values">
-     * <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 committed.
-     *
-     * <table summary="Change compatibility of containers">
-     * <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 committed
-     * transaction from being applied. <br>
-     *
-     * <p>
-     * A successful commit produces implementation-specific {@link CommitInfo} structure, which is used to communicate
-     * post-condition information to the caller. Such information can contain commit-id, timing information or any
-     * other information the implementation wishes to share.
-     *
-     * @return a FluentFuture containing the result of the commit information. The Future blocks until the commit
-     *         operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
-     *         {@link TransactionCommitFailedException} or an exception derived from TransactionCommitFailedException.
-     * @throws IllegalStateException if the transaction is already committed or was canceled.
-     */
-    @CheckReturnValue
-    @NonNull FluentFuture<? extends @NonNull CommitInfo> commit();
-}
diff --git a/common/mdsal-common-util/src/main/java/org/opendaylight/mdsal/common/util/ForwardingAsyncReadWriteTransaction.java b/common/mdsal-common-util/src/main/java/org/opendaylight/mdsal/common/util/ForwardingAsyncReadWriteTransaction.java
deleted file mode 100644 (file)
index c39aa0c..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright Â© 2017, 2018 Red Hat, Inc. and others.
- *
- * 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.common.util;
-
-import com.google.common.collect.ForwardingObject;
-import com.google.common.util.concurrent.FluentFuture;
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
-import org.opendaylight.mdsal.common.api.CommitInfo;
-import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
-import org.opendaylight.yangtools.concepts.Path;
-
-/**
- * Utility {@link AsyncReadWriteTransaction} implementation which forwards all interface method
- * invocation to a delegate instance.
- */
-public class ForwardingAsyncReadWriteTransaction<P extends Path<P>, D> extends ForwardingObject
-        implements AsyncReadWriteTransaction<P, D> {
-
-    private final AsyncReadWriteTransaction<P, D> delegate;
-
-    protected ForwardingAsyncReadWriteTransaction(AsyncReadWriteTransaction<P, D> delegate) {
-        this.delegate = delegate;
-    }
-
-    @Override
-    protected AsyncReadWriteTransaction<P, D> delegate() {
-        return delegate;
-    }
-
-    @Override
-    public Object getIdentifier() {
-        return delegate.getIdentifier();
-    }
-
-    @Override
-    public boolean cancel() {
-        return delegate.cancel();
-    }
-
-    @Override
-    public FluentFuture<? extends CommitInfo> commit() {
-        return delegate.commit();
-    }
-
-    @Override
-    public void delete(LogicalDatastoreType store, P path) {
-        delegate.delete(store, path);
-    }
-
-    @Override
-    public void close() {
-        delegate.close();
-    }
-}
index 34b4c517bd3ce8fe287f185e4f0d64b442a6d230..dab3c13988eae1829b7241627df99a6254d0c025 100644 (file)
@@ -7,8 +7,6 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import org.opendaylight.mdsal.common.api.AsyncDataBroker;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 /**
@@ -42,8 +40,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL,
  * but only to be consumed by them.
  */
-public interface DOMDataBroker extends
-        AsyncDataBroker<YangInstanceIdentifier, NormalizedNode<?, ?>>, DOMTransactionFactory,
+public interface DOMDataBroker extends DOMTransactionFactory,
         DOMExtensibleService<DOMDataBroker, DOMDataBrokerExtension> {
     /**
      * Create a new transaction chain. The chain will be initialized to read from its backing datastore, with
index 578b48e371a281f3a71c775694ceda501810a922..d36f72f51246a03232bf9684ab16d97e2ec83310 100644 (file)
@@ -9,9 +9,9 @@ package org.opendaylight.mdsal.dom.api;
 
 import com.google.common.util.concurrent.FluentFuture;
 import java.util.Optional;
-import org.opendaylight.mdsal.common.api.AsyncReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
 import org.opendaylight.mdsal.common.api.ReadFailedException;
+import org.opendaylight.yangtools.concepts.Registration;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
@@ -50,8 +50,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * java.util.concurrent.Executor)} or other functions from {@link com.google.common.util.concurrent.Futures} to register
  * more specific listeners.
  */
-public interface DOMDataTreeReadTransaction extends DOMDataTreeTransaction,
-        AsyncReadTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> {
+public interface DOMDataTreeReadTransaction extends DOMDataTreeTransaction, Registration {
     /**
      * Reads data from provided logical data store located at the provided path.
      *
index 7b481c794e567829015099994f46426ed38b3552..941eab2dcf0fac9f55f89e2e3acba9ed52e317e6 100644 (file)
@@ -7,16 +7,12 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import org.opendaylight.mdsal.common.api.AsyncReadWriteTransaction;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
 /**
  * A transaction that provides read/write access to a logical data store.
  *
  * <p>
- * For more information on usage and examples, please see the documentation in {@link AsyncReadWriteTransaction}.
+ * For more information on usage and examples, please see the documentation in {@link DOMDataTreeReadTransaction}
+ * and {@link DOMDataTreeWriteTransaction}.
  */
-public interface DOMDataTreeReadWriteTransaction extends DOMDataTreeReadTransaction, DOMDataTreeWriteTransaction,
-        AsyncReadWriteTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> {
+public interface DOMDataTreeReadWriteTransaction extends DOMDataTreeReadTransaction, DOMDataTreeWriteTransaction {
 }
index 6cabe0266dbefbe5795283fa73a25aa1d4b4a35a..09d4298f6cb63d220720b4474ef1544c48c6bdd0 100644 (file)
@@ -7,9 +7,7 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.concepts.Identifiable;
 
 /**
  * A common parent for all transactions which operate on a conceptual data tree.
@@ -21,7 +19,6 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  *
  * <b>Implementation Note:</b> This interface is not intended to be implemented by users of MD-SAL.
  */
-public interface DOMDataTreeTransaction extends AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> {
-    @Override
-    Object getIdentifier();
+public interface DOMDataTreeTransaction extends Identifiable<Object> {
+
 }
index 24f57dfeae4fdbd98fa8da7408952d2dafce73a5..252c9829ffc38226dbe7a32e8b03aef44909732e 100644 (file)
@@ -10,71 +10,484 @@ package org.opendaylight.mdsal.dom.api;
 import com.google.common.util.concurrent.FluentFuture;
 import javax.annotation.CheckReturnValue;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.common.api.AsyncWriteTransaction;
 import org.opendaylight.mdsal.common.api.CommitInfo;
+import org.opendaylight.mdsal.common.api.DataValidationFailedException;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.mdsal.common.api.OptimisticLockFailedException;
+import org.opendaylight.mdsal.common.api.TransactionCommitFailedException;
 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 /**
- * A transaction that provides mutation capabilities on a data tree.
+ * Write transaction provides mutation capabilities for a data tree.
  *
  * <p>
- * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
+ * 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 make changes to the local data tree in the transaction by via the
+ * <b>put</b>, <b>merge</b>, and <b>delete</b> operations.
+ *
+ * <h2>Put operation</h2>
+ * Stores a piece of data at a specified path. This acts as an add / replace
+ * operation, which is to say that whole subtree will be replaced by the
+ * specified data.
+ *
+ * <p>
+ * 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>
+ * <h2>Merge operation</h2>
+ * Merges a piece of data with the existing data at a specified path. 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.
+ *
+ * <p>
+ * 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.
+ *
+ * <h2>Delete operation</h2>
+ * Removes a piece of data from a specified path.
+ *
+ * <p>
+ * After applying changes to the local data tree, 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 commits 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.
  */
-public interface DOMDataTreeWriteTransaction extends DOMDataTreeTransaction,
-        AsyncWriteTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> {
+public interface DOMDataTreeWriteTransaction extends DOMDataTreeTransaction {
     /**
-     * Stores a piece of data at the specified path. This acts as an add / replace
-     * operation, which is to say that whole subtree will be replaced by the specified data.
+     * Stores a piece of data at the specified path. This acts as an add / replace operation, which is to say that whole
+     * subtree will be replaced by the specified data.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
+     * If you need to make sure that a parent object exists but you do not want modify its pre-existing state by using
+     * put, consider using {@link #merge} instead.
      *
-     * <p>
-     * If you need to make sure that a parent object exists but you do not want modify
-     * its pre-existing state by using put, consider using {@link #merge} instead.
-     *
-     * @param store
-     *            the logical data store which should be modified
-     * @param path
-     *            the data object path
-     * @param data
-     *            the data object to be written to the specified path
-     * @throws IllegalStateException
-     *             if the transaction has already been submitted
+     * @param store the logical data store which should be modified
+     * @param path the data object path
+     * @param data the data object to be written to the specified path
+     * @throws IllegalStateException if the transaction has already been submitted
      */
     void put(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
 
     /**
-     * Merges a piece of data with the existing data at a specified path. 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.
+     * Merges a piece of data with the existing data at a specified path. 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.
      *
      * <p>
-     * For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}.
-     *
-     *<p>
      * If you require an explicit replace operation, use {@link #put} instead.
      *
-     * @param store
-     *            the logical data store which should be modified
-     * @param path
-     *            the data object path
-     * @param data
-     *            the data object to be merged to the specified path
-     * @throws IllegalStateException
-     *             if the transaction has already been submitted
+     * @param store the logical data store which should be modified
+     * @param path the data object path
+     * @param data the data object to be merged to the specified path
+     * @throws IllegalStateException if the transaction has already been submitted
      */
     void merge(LogicalDatastoreType store, YangInstanceIdentifier path, NormalizedNode<?, ?> data);
 
-    @Override
+    /**
+     * Removes 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 was committed or canceled.
+     */
     void delete(LogicalDatastoreType store, YangInstanceIdentifier path);
 
-    @Override
+    /**
+     * Commits this transaction to be asynchronously applied to update the logical data tree. The returned
+     * {@link FluentFuture} conveys the result of applying the data changes.
+     *
+     * <p>
+     * This call logically seals the transaction, which prevents the client from further changing the data tree using
+     * this transaction. Any subsequent calls to <code>put(LogicalDatastoreType, Path, Object)</code>,
+     * <code>merge(LogicalDatastoreType, Path, Object)</code>, <code>delete(LogicalDatastoreType, Path)</code> will fail
+     * with {@link IllegalStateException}. The transaction is marked as committed and enqueued into the data store
+     * back-end for processing.
+     *
+     * <p>
+     * Whether or not the commit is successful is determined by versioning of the data tree and validation of registered
+     * commit participants if the transaction changes the data tree.
+     *
+     * <p>
+     * The effects of a successful commit of data depends on listeners and commit participants that are registered with
+     * the data broker.
+     *
+     * <h3>Example usage:</h3>
+     * <pre>
+     *  private void doWrite(final int tries) {
+     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+     *      MyDataObject data = ...;
+     *      InstanceIdentifier&lt;MyDataObject&gt; path = ...;
+     *      writeTx.put(LogicalDatastoreType.OPERATIONAL, path, data);
+     *      Futures.addCallback(writeTx.commit(), new FutureCallback&lt;CommitInfo&gt;() {
+     *          public void onSuccess(CommitInfo result) {
+     *              // succeeded
+     *          }
+     *          public void onFailure(Throwable t) {
+     *              if (t instanceof OptimisticLockFailedException) {
+     *                  if(( tries - 1) &gt; 0 ) {
+     *                      // do retry
+     *                      doWrite(tries - 1);
+     *                  } else {
+     *                      // out of retries
+     *                  }
+     *              } else {
+     *                  // failed due to another type of TransactionCommitFailedException.
+     *              }
+     *          });
+     * }
+     * ...
+     * doWrite(2);
+     * </pre>
+     *
+     * <h2>Failure scenarios</h2>
+     *
+     * <p>
+     * Transaction may fail because of multiple reasons, such as
+     * <ul>
+     *   <li>
+     *     Another transaction finished earlier and modified the same node in a non-compatible way (see below). In this
+     *     case the returned future will fail with an {@link OptimisticLockFailedException}. It is the responsibility
+     *     of the caller to create a new transaction and commit the same modification again in order to update data
+     *     tree.
+     *     <i>
+     *       <b>Warning</b>: In most cases, retrying after an OptimisticLockFailedException will result in a high
+     *       probability of success. However, there are scenarios, albeit unusual, where any number of retries will
+     *       not succeed. Therefore it is strongly recommended to limit the number of retries (2 or 3) to avoid
+     *       an endless loop.
+     *     </i>
+     *   </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 a {@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 committed.
+     *
+     * <table summary="Change compatibility of leaf values">
+     * <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 committed.
+     *
+     * <table summary="Change compatibility of containers">
+     * <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 FluentFuture} 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 FluentFuture} object will fail with {@link OptimisticLockFailedException}
+     * exception, which indicates to client that concurrent transaction prevented the committed
+     * transaction from being applied. <br>
+     *
+     * <p>
+     * A successful commit produces implementation-specific {@link CommitInfo} structure, which is used to communicate
+     * post-condition information to the caller. Such information can contain commit-id, timing information or any
+     * other information the implementation wishes to share.
+     *
+     * @return a FluentFuture containing the result of the commit information. The Future blocks until the commit
+     *         operation is complete. A successful commit returns nothing. On failure, the Future will fail with a
+     *         {@link TransactionCommitFailedException} or an exception derived from TransactionCommitFailedException.
+     * @throws IllegalStateException if the transaction is already committed or was canceled.
+     */
     @CheckReturnValue
     @NonNull FluentFuture<? extends @NonNull CommitInfo> commit();
 
-    @Override
+    /**
+     * Cancels the transaction. Transactions can only be cancelled if it was not yet committed.
+     * Invoking cancel() on failed or already canceled will have no effect, and transaction is considered cancelled.
+     * Invoking cancel() on finished transaction (future returned by {@link #commit()} 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();
 }
index 586702605ab61bb42018d184838d80939b18f797..d12ec4d9eaf7c190f6a7aa8ca8f3046ed1dedab7 100644 (file)
@@ -7,10 +7,6 @@
  */
 package org.opendaylight.mdsal.dom.api;
 
-import org.opendaylight.mdsal.common.api.AsyncDataTransactionFactory;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-
 /**
  * A factory which allocates new transactions to operate on the data tree.
  *
@@ -52,15 +48,46 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  * @see DOMDataBroker
  * @see DOMTransactionChain
  */
-public interface DOMTransactionFactory
-        extends AsyncDataTransactionFactory<YangInstanceIdentifier, NormalizedNode<?, ?>> {
-
-    @Override
+public interface DOMTransactionFactory {
+    /**
+     * Allocates a new read-only transaction which provides an immutable snapshot of the data tree. The view of data
+     * tree is an immutable snapshot of current data tree state when transaction was allocated.
+     *
+     * @return A new read-only transaction
+     */
     DOMDataTreeReadTransaction newReadOnlyTransaction();
 
-    @Override
+    /**
+     * 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 DOMDataTreeWriteTransaction#commit()} for more details about conflicting and
+     * non-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 DOMDataTreeWriteTransaction#commit()}.
+     *
+     * <p>
+     * Exclusivity of writers to particular subtree SHOULD BE enforced by external locking mechanism.
+     *
+     * @return new write-only transaction
+     */
     DOMDataTreeWriteTransaction newWriteOnlyTransaction();
 
-    @Override
+    /**
+     * 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 DOMDataTreeReadWriteTransaction#commit()} for more details about conflicting and
+     * non-conflicting changes and failure scenarios.
+     *
+     * @return new read-write transaction
+     */
     DOMDataTreeReadWriteTransaction newReadWriteTransaction();
 }
index 747ef3f4bfe4f0a9d2d71e8206fd9fc88f053dfd..0a0b8c91a3645080e1f2f8f91cd751026306095b 100644 (file)
@@ -5,16 +5,15 @@
  * 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.dom.broker;
 
-import com.google.common.base.Preconditions;
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
 import java.util.Collection;
 import java.util.Map;
-import org.opendaylight.mdsal.common.api.AsyncTransaction;
+import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
 import org.opendaylight.mdsal.dom.spi.store.DOMStoreTransaction;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 
 /**
  * Composite DOM Transaction backed by {@link DOMStoreTransaction}.
@@ -30,7 +29,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
  *            Subtransaction type
  */
 abstract class AbstractDOMForwardedCompositeTransaction<K, T extends DOMStoreTransaction> implements
-        AsyncTransaction<YangInstanceIdentifier, NormalizedNode<?, ?>> {
+        DOMDataTreeTransaction {
 
     private final Map<K, T> backingTxs;
     private final Object identifier;
@@ -44,8 +43,8 @@ abstract class AbstractDOMForwardedCompositeTransaction<K, T extends DOMStoreTra
      *            Key,value map of backing transactions.
      */
     protected AbstractDOMForwardedCompositeTransaction(final Object identifier, final Map<K, T> backingTxs) {
-        this.identifier = Preconditions.checkNotNull(identifier, "Identifier should not be null");
-        this.backingTxs = Preconditions.checkNotNull(backingTxs, "Backing transactions should not be null");
+        this.identifier = requireNonNull(identifier, "Identifier should not be null");
+        this.backingTxs = requireNonNull(backingTxs, "Backing transactions should not be null");
     }
 
     /**
@@ -59,10 +58,10 @@ abstract class AbstractDOMForwardedCompositeTransaction<K, T extends DOMStoreTra
      *             if no subtransaction is associated with key.
      */
     protected final T getSubtransaction(final K key) {
-        Preconditions.checkNotNull(key, "key must not be null.");
+        requireNonNull(key, "key must not be null.");
 
         final T ret = backingTxs.get(key);
-        Preconditions.checkArgument(ret != null, "No subtransaction associated with %s", key);
+        checkArgument(ret != null, "No subtransaction associated with %s", key);
         return ret;
     }