Merge "Bug 1362: New AsyncWriteTransaction#submit method"
authorTony Tkacik <ttkacik@cisco.com>
Mon, 21 Jul 2014 09:11:50 +0000 (09:11 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Mon, 21 Jul 2014 09:11:50 +0000 (09:11 +0000)
26 files changed:
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java
opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/Bug1125RegressionTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/ListInsertionDataChangeListenerTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/test/AbstractDataBrokerTest.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/AsyncWriteTransaction.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataValidationFailedException.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/OptimisticLockFailedException.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/TransactionCommitFailedException.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataTransaction.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/AbstractDOMForwardedTransactionFactory.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataBrokerTransactionChainImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitCoordinatorImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitErrorInvoker.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitExecutor.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMDataCommitImplementation.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedReadWriteTransaction.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMForwardedWriteTransaction.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/compat/BackwardsCompatibleTransaction.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerPerformanceTest.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMBrokerTest.java
opendaylight/md-sal/sal-dom-broker/src/test/java/org/opendaylight/controller/md/sal/dom/broker/impl/DOMTransactionChainTest.java
opendaylight/md-sal/samples/toaster-provider/src/main/java/org/opendaylight/controller/sample/toaster/provider/OpendaylightToaster.java

index 9eceeb1e436b96fd1e063e8b79e3a96bcaf54c94..a8eef5a3cae2687f6cc552454407e0bb8bf9eb97 100644 (file)
@@ -10,13 +10,12 @@ package org.opendaylight.controller.md.sal.binding.impl;
 import java.util.Collections;
 import java.util.Map.Entry;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.Identifiable;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.slf4j.Logger;
@@ -24,7 +23,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.Iterables;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 
 /**
  *
@@ -122,8 +121,8 @@ public class AbstractWriteTransaction<T extends DOMDataWriteTransaction> extends
         getDelegate().delete(store, normalized);
     }
 
-    protected final ListenableFuture<RpcResult<TransactionStatus>> doCommit() {
-        return getDelegate().commit();
+    protected final CheckedFuture<Void,TransactionCommitFailedException> doSubmit() {
+        return getDelegate().submit();
     }
 
     protected final boolean doCancel() {
index a62319be22cc881612922a18f7de2e149d3713c0..7e622baac3d07e0168173f9f551ed83215c90d79 100644 (file)
@@ -10,11 +10,13 @@ package org.opendaylight.controller.md.sal.binding.impl;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.yangtools.yang.binding.DataObject;
 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
 import org.opendaylight.yangtools.yang.common.RpcResult;
-
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.ListenableFuture;
 
 class BindingDataWriteTransactionImpl<T extends DOMDataWriteTransaction> extends
@@ -24,8 +26,6 @@ class BindingDataWriteTransactionImpl<T extends DOMDataWriteTransaction> extends
         super(delegateTx, codec);
     }
 
-
-
     @Override
     public void put(final LogicalDatastoreType store, final InstanceIdentifier<?> path, final DataObject data) {
         doPut(store, path, data);
@@ -43,7 +43,12 @@ class BindingDataWriteTransactionImpl<T extends DOMDataWriteTransaction> extends
 
     @Override
     public ListenableFuture<RpcResult<TransactionStatus>> commit() {
-        return doCommit();
+        return AbstractDataTransaction.convertToLegacyCommitFuture(submit());
+    }
+
+    @Override
+    public CheckedFuture<Void,TransactionCommitFailedException> submit() {
+        return doSubmit();
     }
 
     @Override
index b45450ae3a54554243fe6a3c5097f362fb82779b..12f26b09bb2cf1645d645438302e705c3c0489ce 100644 (file)
@@ -28,6 +28,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.Data
 import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegistration;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
 import org.opendaylight.controller.sal.binding.api.data.DataChangeListener;
@@ -160,7 +161,7 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat
             @Override
             public ListenableFuture<RpcResult<TransactionStatus>> apply(final Boolean requestCommitSuccess) throws Exception {
                 if(requestCommitSuccess) {
-                    return tx.getDelegate().commit();
+                    return AbstractDataTransaction.convertToLegacyCommitFuture(tx.getDelegate().submit());
                 }
                 return Futures.immediateFuture(RpcResultBuilder.<TransactionStatus>failed().withResult(TransactionStatus.FAILED).build());
             }
index 9f1ae3845749e13e2adeb216d516a182379f4494..fb115350612cfe894e2cf85a29c6af2f0c53741c 100644 (file)
@@ -49,13 +49,13 @@ public class Bug1125RegressionTest extends AbstractDataChangeListenerTest {
                                 "foo").build()).build();
         initialTx.put(LogicalDatastoreType.OPERATIONAL, path(TOP_FOO_KEY),
                 topLevelList(TOP_FOO_KEY, fooAugment));
-        assertCommit(initialTx.commit());
+        assertCommit(initialTx.submit());
     }
 
     private void delete(final InstanceIdentifier<?> path) {
         WriteTransaction tx = getDataBroker().newWriteOnlyTransaction();
         tx.delete(LogicalDatastoreType.OPERATIONAL, path);
-        assertCommit(tx.commit());
+        assertCommit(tx.submit());
     }
 
     private void verifyRemoved(
index 05bc857969005bfab5a35f9627970a1434eb1bc6..54493300e342df6d2f3f2428a53f597677089948 100644 (file)
@@ -48,7 +48,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe
     protected void setupWithDataBroker(final DataBroker dataBroker) {
         WriteTransaction initialTx = dataBroker.newWriteOnlyTransaction();
         initialTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_FOO_KEY)));
-        assertCommit(initialTx.commit());
+        assertCommit(initialTx.submit());
     }
 
     @Test
@@ -60,7 +60,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe
 
         ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
         writeTx.put(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
-        assertCommit(writeTx.commit());
+        assertCommit(writeTx.submit());
         AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> top = topListener.event();
         AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> all = allListener.event();
         AsyncDataChangeEvent<InstanceIdentifier<?>, DataObject> foo = fooListener.event();
@@ -115,7 +115,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe
 
         ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
         writeTx.merge(CONFIGURATION, TOP, top(topLevelList(TOP_BAR_KEY)));
-        assertCommit(writeTx.commit());
+        assertCommit(writeTx.submit());
 
         verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
     }
@@ -129,7 +129,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe
 
         ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
         writeTx.put(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
-        assertCommit(writeTx.commit());
+        assertCommit(writeTx.submit());
 
         verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
     }
@@ -143,7 +143,7 @@ public class ListInsertionDataChangeListenerTest extends AbstractDataChangeListe
 
         ReadWriteTransaction writeTx = getDataBroker().newReadWriteTransaction();
         writeTx.merge(CONFIGURATION, TOP_BAR, topLevelList(TOP_BAR_KEY));
-        assertCommit(writeTx.commit());
+        assertCommit(writeTx.submit());
 
         verifyBarOnlyAdded(topListener,allListener,fooListener,barListener);
     }
index 43e951423c0a2bfdecef87969abd01c51816d28e..b577e2af1f2c845586615985fa77ec1169abd291 100644 (file)
@@ -7,14 +7,11 @@
  */
 package org.opendaylight.controller.md.sal.binding.impl.test;
 
-import static org.junit.Assert.assertEquals;
-
 import java.util.concurrent.ExecutionException;
 
 import org.junit.Test;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
 import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder;
@@ -35,7 +32,7 @@ public class WriteTransactionTest extends AbstractDataBrokerTest {
         WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction();
         writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build());
         writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build());
-        assertEquals(TransactionStatus.COMMITED, writeTx.commit().get().getResult());
+        writeTx.submit().get();
     }
 
 }
index 7f23ac26b6edc521557a412e25c2bca1a500ff71..5789270dee4e60953e5d7e4805bacffcbb96b6e4 100644 (file)
@@ -7,16 +7,12 @@
  */
 package org.opendaylight.controller.md.sal.binding.test;
 
-import static org.junit.Assert.assertEquals;
-
 import java.util.concurrent.ExecutionException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 
 import com.google.common.util.concurrent.ListenableFuture;
@@ -53,9 +49,9 @@ public class AbstractDataBrokerTest extends AbstractSchemaAwareTest {
         return domBroker;
     }
 
-    protected static final void assertCommit(final ListenableFuture<RpcResult<TransactionStatus>> commit) {
+    protected static final void assertCommit(final ListenableFuture<Void> commit) {
         try {
-            assertEquals(TransactionStatus.COMMITED,commit.get(500, TimeUnit.MILLISECONDS).getResult());
+            commit.get(500, TimeUnit.MILLISECONDS);
         } catch (InterruptedException | ExecutionException | TimeoutException e) {
             throw new IllegalStateException(e);
         }
index f7eae27320107ef6a90696ff73f2cf40b3c99fde..9aaa77ca61f1c5f16df1650a696899d90c96e5f5 100644 (file)
@@ -11,6 +11,7 @@ import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.yangtools.concepts.Path;
 import org.opendaylight.yangtools.yang.common.RpcResult;
 
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -65,7 +66,7 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * <tt>true</tt> otherwise
      *
      */
-    public boolean cancel();
+    boolean cancel();
 
     /**
      * Store a piece of data at specified path. This acts as an add / replace
@@ -97,7 +98,7 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * @throws IllegalStateException
      *             if the transaction is no longer {@link TransactionStatus#NEW}
      */
-    public void put(LogicalDatastoreType store, P path, D data);
+    void put(LogicalDatastoreType store, P path, D data);
 
     /**
      * Store a piece of data at the specified path. This acts as a merge operation,
@@ -132,7 +133,7 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * @throws IllegalStateException
      *             if the transaction is no longer {@link TransactionStatus#NEW}
      */
-    public void merge(LogicalDatastoreType store, P path, D data);
+    void merge(LogicalDatastoreType store, P path, D data);
 
     /**
      * Remove a piece of data from specified path. This operation does not fail
@@ -145,10 +146,14 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * @throws IllegalStateException
      *             if the transaction is no longer {@link TransactionStatus#NEW}
      */
-    public void delete(LogicalDatastoreType store, P path);
+    void delete(LogicalDatastoreType store, P path);
 
     /**
-     * Submits transaction to be applied to update logical data tree.
+     * Submits this transaction to be asynchronously applied to update the logical data tree.
+     * The returned CheckedFuture conveys the result of applying the data changes.
+     * <p>
+     * <b>Note:</b> It is strongly recommended to process the CheckedFuture result in an asynchronous
+     * manner rather than using the blocking get() method. See example usage below.
      * <p>
      * This call logically seals the transaction, which prevents the client from
      * further changing data tree using this transaction. Any subsequent calls to
@@ -158,31 +163,65 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * {@link IllegalStateException}.
      *
      * The transaction is marked as {@link TransactionStatus#SUBMITED} and
-     * enqueued into the data store backed for processing.
+     * enqueued into the data store back-end for processing.
      *
      * <p>
      * Whether or not the commit is successful is determined by versioning
-     * of data tree and validation of registered commit participants
-     * {@link AsyncConfigurationCommitHandler}
-     * if transaction changes {@link LogicalDatastoreType#CONFIGURATION} data tree.
-     *<p>
-     * The effects of successful commit of data depends on
-     * other data change listeners {@link AsyncDataChangeListener} and
-     * {@link AsyncConfigurationCommitHandler}, which was registered to the
-     * same {@link AsyncDataBroker}, to which this transaction belongs.
-     *
+     * of the data tree and validation of registered commit participants
+     * ({@link AsyncConfigurationCommitHandler})
+     * if the transaction changes the data tree.
+     * <p>
+     * The effects of a successful commit of data depends on data change listeners
+     * ({@link AsyncDataChangeListener}) and commit participants
+     * ({@link AsyncConfigurationCommitHandler}) that are registered with the data broker.
+     * <p>
+     * <h3>Example usage:</h3>
+     * <pre>
+     *  private void doWrite( final int tries ) {
+     *      WriteTransaction writeTx = dataBroker.newWriteOnlyTransaction();
+     *
+     *      MyDataObject data = ...;
+     *      InstanceIdentifier<MyDataObject> path = ...;
+     *      writeTx.put( LogicalDatastoreType.OPERATIONAL, path, data );
+     *
+     *      Futures.addCallback( writeTx.commit(), new FutureCallback<Void>() {
+     *          public void onSuccess( Void result ) {
+     *              // succeeded
+     *          }
+     *
+     *          public void onFailure( Throwable t ) {
+     *              if( t instanceof OptimisticLockFailedException ) {
+     *                  if( ( tries - 1 ) > 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
-     * non-compatible way (see below). In this case the returned future will fail with
+     * <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 submit the same modification again in
-     * order to update data tree.</li>
+     * 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 {@link DataValidationFailedException}. User should not retry to
+     * fail with {@link DataValidationFailedException}. User should not retry to
      * create new transaction with same data, since it probably will fail again.
      * </li>
      * </ul>
@@ -288,19 +327,21 @@ public interface AsyncWriteTransaction<P extends Path<P>, D> extends AsyncTransa
      * with {@link OptimisticLockFailedException} exception, which indicates to
      * client that concurrent transaction prevented the submitted transaction from being
      * applied.
-     *
-     * @return Result of the Commit, containing success information or list of
-     *         encountered errors, if commit was not successful. The Future
-     *         blocks until {@link TransactionStatus#COMMITED} is reached.
-     *         Future will fail with {@link TransactionCommitFailedException} if
-     *         Commit of this transaction failed. TODO: Usability: Consider
-     *         change from ListenableFuture to
-     *         {@link com.google.common.util.concurrent.CheckedFuture} which
-     *         will throw {@link TransactionCommitFailedException}.
+     * <br>
+     * @return a CheckFuture containing the result of the commit. 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 not {@link TransactionStatus#NEW}
      */
-    public ListenableFuture<RpcResult<TransactionStatus>> commit();
+    CheckedFuture<Void,TransactionCommitFailedException> submit();
+
+    /**
+     * @deprecated Use {@link #submit()} instead.
+     */
+    @Deprecated
+    ListenableFuture<RpcResult<TransactionStatus>> commit();
 
 }
index c59c12ec5c3c59314d94094d421ab45c96deb4cb..d48bfc79fe8941935bbfa2b762d254d93f1da2d0 100644 (file)
@@ -8,6 +8,8 @@
 package org.opendaylight.controller.md.sal.common.api.data;
 
 import org.opendaylight.yangtools.concepts.Path;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 
 import com.google.common.base.Preconditions;
 
@@ -31,14 +33,17 @@ public class DataValidationFailedException extends TransactionCommitFailedExcept
 
     private Class<? extends Path<?>> pathType;
 
-    public <P extends Path<P>> DataValidationFailedException(final Class<P> pathType,final P path, final String message, final Throwable cause) {
-        super(message, cause);
+    public <P extends Path<P>> DataValidationFailedException(final Class<P> pathType,final P path,
+                                                             final String message, final Throwable cause) {
+        super(message, cause, RpcResultBuilder.newError(ErrorType.APPLICATION, "invalid-value", message, null,
+                                                        path != null ? path.toString() : null, cause));
         this.pathType = Preconditions.checkNotNull(pathType, "path type must not be null");
         this.path = Preconditions.checkNotNull(path,"path must not be null.");
     }
 
-    public  <P extends Path<P>> DataValidationFailedException(final Class<P> pathType,final P path,final String message) {
-        this(pathType,path,message,null);
+    public  <P extends Path<P>> DataValidationFailedException(final Class<P> pathType,final P path,
+                                                              final String message) {
+        this(pathType, path, message, null);
     }
 
     public final Path<?> getPath() {
index 222289ab6cb967396478a67869dbb11cf6689903..5ddec6b1edfcec9c76425d8587bc989abf3d897f 100644 (file)
@@ -1,5 +1,8 @@
 package org.opendaylight.controller.md.sal.common.api.data;
 
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+
 /**
 *
 * Failure of asynchronous transaction commit caused by failure
@@ -18,17 +21,13 @@ public class OptimisticLockFailedException extends TransactionCommitFailedExcept
 
     private static final long serialVersionUID = 1L;
 
-    protected OptimisticLockFailedException(final String message, final Throwable cause, final boolean enableSuppression,
-            final boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
-    }
-
     public OptimisticLockFailedException(final String message, final Throwable cause) {
-        super(message, cause);
+        super(message, cause, RpcResultBuilder.newError(ErrorType.APPLICATION, "resource-denied",
+                                                        message, null, null, cause));
     }
 
     public OptimisticLockFailedException(final String message) {
-        super(message);
+        this(message, null);
     }
 
 }
index f3c2e1093cfbdacea1b2019f5df64f64ac54aeb9..18a857e1d5c4bd0816674a6af99070c2a9dc1e76 100644 (file)
@@ -7,6 +7,15 @@
  */
 package org.opendaylight.controller.md.sal.common.api.data;
 
+import java.util.Arrays;
+import java.util.List;
+
+import org.opendaylight.yangtools.yang.common.RpcError;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
+import org.opendaylight.yangtools.yang.common.RpcError.ErrorType;
+
+import com.google.common.collect.ImmutableList;
+
 /**
  *
  * Failed commit of asynchronous transaction
@@ -17,18 +26,39 @@ package org.opendaylight.controller.md.sal.common.api.data;
  */
 public class TransactionCommitFailedException extends Exception {
 
-    private static final long serialVersionUID = -6138306275373237068L;
+    private static final long serialVersionUID = 1L;
 
-    protected TransactionCommitFailedException(final String message, final Throwable cause, final boolean enableSuppression, final boolean writableStackTrace) {
-        super(message, cause, enableSuppression, writableStackTrace);
+    private final List<RpcError> errorList;
+
+    public TransactionCommitFailedException(final String message, final RpcError... errors) {
+        this(message, null, errors);
     }
 
-    public TransactionCommitFailedException(final String message, final Throwable cause) {
+    public TransactionCommitFailedException(final String message, final Throwable cause,
+                                            final RpcError... errors) {
         super(message, cause);
+
+        if( errors != null && errors.length > 0 ) {
+            errorList = ImmutableList.<RpcError>builder().addAll( Arrays.asList( errors ) ).build();
+        }
+        else {
+            // Add a default RpcError.
+            errorList = ImmutableList.of(RpcResultBuilder.newError(ErrorType.APPLICATION, null,
+                    getMessage(), null, null, getCause()));
+        }
     }
 
-    public TransactionCommitFailedException(final String message) {
-        super(message);
+    /**
+     * Returns additional error information about this exception.
+     *
+     * @return a List of RpcErrors. There is always at least one RpcError.
+     */
+    public List<RpcError> getErrorList() {
+        return errorList;
     }
 
+    @Override
+    public String getMessage() {
+        return new StringBuilder( super.getMessage() ).append(", errors: ").append( errorList ).toString();
+    }
 }
index b030e6cb5f84b8da49d1780ab51ec2e7ab425ede..d544c4b3710b06a12dac1bba3b11b5e13ced4f89 100644 (file)
@@ -11,13 +11,19 @@ import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.common.impl.AbstractDataModification;
 import org.opendaylight.yangtools.concepts.Path;
 import org.opendaylight.yangtools.yang.common.RpcResult;
+import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Preconditions;
+import com.google.common.util.concurrent.AsyncFunction;
+import com.google.common.util.concurrent.CheckedFuture;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
 
 public abstract class AbstractDataTransaction<P extends Path<P>, D extends Object> extends
         AbstractDataModification<P, D> {
@@ -83,18 +89,23 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D extends Objec
 
     @Override
     public boolean equals(Object obj) {
-        if (this == obj)
+        if (this == obj) {
             return true;
-        if (obj == null)
+        }
+        if (obj == null) {
             return false;
-        if (getClass() != obj.getClass())
+        }
+        if (getClass() != obj.getClass()) {
             return false;
+        }
         AbstractDataTransaction<?, ?> other = (AbstractDataTransaction<?, ?>) obj;
         if (identifier == null) {
-            if (other.identifier != null)
+            if (other.identifier != null) {
                 return false;
-        } else if (!identifier.equals(other.identifier))
+            }
+        } else if (!identifier.equals(other.identifier)) {
             return false;
+        }
         return true;
     }
 
@@ -122,4 +133,15 @@ public abstract class AbstractDataTransaction<P extends Path<P>, D extends Objec
         this.status = status;
         this.onStatusChange(status);
     }
+
+    public static ListenableFuture<RpcResult<TransactionStatus>> convertToLegacyCommitFuture(
+                                        CheckedFuture<Void,TransactionCommitFailedException> from ) {
+        return Futures.transform(from, new AsyncFunction<Void, RpcResult<TransactionStatus>>() {
+            @Override
+            public ListenableFuture<RpcResult<TransactionStatus>> apply(Void input) throws Exception {
+                return Futures.immediateFuture(RpcResultBuilder.<TransactionStatus>
+                                                              success(TransactionStatus.COMMITED).build());
+            }
+        } );
+    }
 }
index 5694d0bca9a68fccd5f31557418a8824b35d7a5a..d354cca005974c332c2814c76e696f774b772bc4 100644 (file)
@@ -114,7 +114,7 @@ public abstract class AbstractDOMForwardedTransactionFactory<T extends DOMStoreT
      * <li> {@link DOMDataWriteTransaction#commit()} - results in invoking
      * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts
      * and then invoking finalized implementation callback
-     * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which
+     * {@link #submit(DOMDataWriteTransaction, Iterable)} with transaction which
      * was commited and gathered results.
      * </ul>
      *
@@ -167,7 +167,7 @@ public abstract class AbstractDOMForwardedTransactionFactory<T extends DOMStoreT
      * <li> {@link DOMDataWriteTransaction#commit()} - results in invoking
      * {@link DOMStoreWriteTransaction#ready()}, gathering all resulting cohorts
      * and then invoking finalized implementation callback
-     * {@link #commit(DOMDataWriteTransaction, Iterable)} with transaction which
+     * {@link #submit(DOMDataWriteTransaction, Iterable)} with transaction which
      * was commited and gathered results.
      * <li>
      * </ul>
index 7e37a1e3a3467837b16963a8026236738535f599..7731646a57d874348f0192be357a16f8de040212 100644 (file)
@@ -12,9 +12,9 @@ import static com.google.common.base.Preconditions.checkState;
 import java.util.Map.Entry;
 import java.util.concurrent.atomic.AtomicLong;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataChangeListener;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
@@ -23,14 +23,13 @@ import org.opendaylight.controller.sal.core.spi.data.DOMStore;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
 import org.opendaylight.yangtools.concepts.ListenerRegistration;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.ListeningExecutorService;
 
 public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DOMStore> implements DOMDataBroker,
@@ -78,7 +77,7 @@ public class DOMDataBrokerImpl extends AbstractDOMForwardedTransactionFactory<DO
     }
 
     @Override
-    public ListenableFuture<RpcResult<TransactionStatus>> commit(final DOMDataWriteTransaction transaction,
+    public CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
             final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
         LOG.debug("Transaction: {} submitted with cohorts {}.", transaction.getIdentifier(), cohorts);
         return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> absent());
index b9f096aafc251400b01ee6b7319395cc8ec739fd..227693ca4df5015f79d8f88cf02e666be7f25e39 100644 (file)
@@ -10,21 +10,20 @@ import java.util.concurrent.atomic.AtomicLong;
 
 import javax.annotation.concurrent.GuardedBy;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreTransactionChain;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Optional;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 
 /**
  * NormalizedNode implementation of {@link org.opendaylight.controller.md.sal.common.api.data.TransactionChain} which is backed
@@ -73,7 +72,7 @@ public class DOMDataBrokerTransactionChainImpl extends AbstractDOMForwardedTrans
     }
 
     @Override
-    public synchronized ListenableFuture<RpcResult<TransactionStatus>> commit(
+    public synchronized CheckedFuture<Void,TransactionCommitFailedException> submit(
             final DOMDataWriteTransaction transaction, final Iterable<DOMStoreThreePhaseCommitCohort> cohorts) {
         return coordinator.submit(transaction, cohorts, Optional.<DOMDataCommitErrorListener> of(this));
     }
index 13a0093d340b7ef3bc496cf6950d1118ad309ab5..8b9eb445fd45b4d19f5a3f6523a7ce2a711ef310 100644 (file)
@@ -12,12 +12,9 @@ import java.util.concurrent.ExecutionException;
 
 import javax.annotation.concurrent.GuardedBy;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-import org.opendaylight.yangtools.yang.common.RpcResultBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -82,18 +79,19 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
     }
 
     @Override
-    public ListenableFuture<RpcResult<TransactionStatus>> submit(final DOMDataWriteTransaction transaction,
+    public CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
             final Iterable<DOMStoreThreePhaseCommitCohort> cohorts, final Optional<DOMDataCommitErrorListener> listener) {
         Preconditions.checkArgument(transaction != null, "Transaction must not be null.");
         Preconditions.checkArgument(cohorts != null, "Cohorts must not be null.");
         Preconditions.checkArgument(listener != null, "Listener must not be null");
         LOG.debug("Tx: {} is submitted for execution.", transaction.getIdentifier());
-        ListenableFuture<RpcResult<TransactionStatus>> commitFuture = executor.submit(new CommitCoordinationTask(
+        ListenableFuture<Void> commitFuture = executor.submit(new CommitCoordinationTask(
                 transaction, cohorts, listener));
         if (listener.isPresent()) {
             Futures.addCallback(commitFuture, new DOMDataCommitErrorInvoker(transaction, listener.get()));
         }
-        return commitFuture;
+
+        return Futures.makeChecked(commitFuture, TransactionCommitFailedExceptionMapper.COMMIT_ERROR_MAPPER);
     }
 
     /**
@@ -139,7 +137,7 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
      * support of cancelation.
      *
      */
-    private static class CommitCoordinationTask implements Callable<RpcResult<TransactionStatus>> {
+    private static class CommitCoordinationTask implements Callable<Void> {
 
         private final DOMDataWriteTransaction tx;
         private final Iterable<DOMStoreThreePhaseCommitCohort> cohorts;
@@ -156,12 +154,13 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
         }
 
         @Override
-        public RpcResult<TransactionStatus> call() throws TransactionCommitFailedException {
+        public Void call() throws TransactionCommitFailedException {
 
             try {
                 canCommitBlocking();
                 preCommitBlocking();
-                return commitBlocking();
+                commitBlocking();
+                return null;
             } catch (TransactionCommitFailedException e) {
                 LOG.warn("Tx: {} Error during phase {}, starting Abort", tx.getIdentifier(), currentPhase, e);
                 abortBlocking(e);
@@ -217,9 +216,8 @@ public class DOMDataCommitCoordinatorImpl implements DOMDataCommitExecutor {
          *             If one of cohorts failed preCommit
          *
          */
-        private RpcResult<TransactionStatus> commitBlocking() throws TransactionCommitFailedException {
+        private void commitBlocking() throws TransactionCommitFailedException {
             commitAll().checkedGet();
-            return RpcResultBuilder.<TransactionStatus>success(TransactionStatus.COMMITED).build();
         }
 
         /**
index 811d4d88394fa3a51da6facbd1fc00dff6e61cfe..5ce9241dd2943399ddac9a9d3d9cb7d9bb2c6c1d 100644 (file)
@@ -6,10 +6,7 @@
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
 import com.google.common.base.Preconditions;
 import com.google.common.util.concurrent.FutureCallback;
 
@@ -22,7 +19,7 @@ import com.google.common.util.concurrent.FutureCallback;
  * callback is invoked with associated transaction and throwable is invoked on listener.
  *
  */
-class DOMDataCommitErrorInvoker implements FutureCallback<RpcResult<TransactionStatus>> {
+class DOMDataCommitErrorInvoker implements FutureCallback<Void> {
 
     private final DOMDataWriteTransaction tx;
     private final DOMDataCommitErrorListener listener;
@@ -46,7 +43,7 @@ class DOMDataCommitErrorInvoker implements FutureCallback<RpcResult<TransactionS
     }
 
     @Override
-    public void onSuccess(RpcResult<TransactionStatus> result) {
+    public void onSuccess(Void result) {
         // NOOP
     }
 }
\ No newline at end of file
index 2050d148a8a9638bd562b81d1b2f2a5374f8f4c9..234758ca75413e3381cf5b71fd67c2e2f41e815a 100644 (file)
@@ -7,13 +7,11 @@
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
 import com.google.common.base.Optional;
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 
 /**
  * Executor of Three Phase Commit coordination for
@@ -40,12 +38,12 @@ interface DOMDataCommitExecutor {
      *            subtransactoins.
      * @param listener
      *            Error listener which should be notified if transaction failed.
-     * @return ListenableFuture which contains RpcResult with
-     *         {@link TransactionStatus#COMMITED} if commit coordination on
-     *         cohorts finished successfully.
+     * @return a CheckedFuture. if commit coordination on cohorts finished successfully,
+     *         nothing is returned from the Future, On failure,
+     *         the Future fails with a {@link TransactionCommitFailedException}.
      *
      */
-    ListenableFuture<RpcResult<TransactionStatus>> submit(DOMDataWriteTransaction tx,
+    CheckedFuture<Void,TransactionCommitFailedException> submit(DOMDataWriteTransaction tx,
             Iterable<DOMStoreThreePhaseCommitCohort> cohort, Optional<DOMDataCommitErrorListener> listener);
 
 }
index 4906b6e84df9c9b84516c9e958d146f15d9766af..2f2b6e508a198f013f94892ce2c446cc1bb27955 100644 (file)
@@ -7,12 +7,10 @@
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
-import org.opendaylight.yangtools.yang.common.RpcResult;
-
-import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.CheckedFuture;
 
 /**
  *
@@ -23,10 +21,10 @@ import com.google.common.util.concurrent.ListenableFuture;
 public interface DOMDataCommitImplementation {
 
     /**
-     * User-supplied implementation of {@link DOMDataWriteTransaction#commit()}
+     * User-supplied implementation of {@link DOMDataWriteTransaction#submit()}
      * for transaction.
      *
-     * Callback invoked when {@link DOMDataWriteTransaction#commit()} is invoked
+     * Callback invoked when {@link DOMDataWriteTransaction#submit()} is invoked
      * on transaction created by this factory.
      *
      * @param transaction
@@ -37,7 +35,7 @@ public interface DOMDataCommitImplementation {
      *            commited transaction.
      *
      */
-    ListenableFuture<RpcResult<TransactionStatus>> commit(final DOMDataWriteTransaction transaction,
+    CheckedFuture<Void,TransactionCommitFailedException> submit(final DOMDataWriteTransaction transaction,
             final Iterable<DOMStoreThreePhaseCommitCohort> cohorts);
 }
 
index f5b96e27f5724be29a7bf844b508cbe6d51117cb..e1d27e453bd5a2e0652ec5ab70161eded553025b 100644 (file)
@@ -29,7 +29,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  * <li>{@link #merge(LogicalDatastoreType, InstanceIdentifier, NormalizedNode)}
  * </ul>
  * {@link #commit()} will result in invocation of
- * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
+ * {@link DOMDataCommitImplementation#submit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
  * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying
  * transactions.
  *
index f791522a2a77214e9a233f966801fac096948618..5bddd763fb396506702ec834f912245e2ec2177a 100644 (file)
@@ -13,6 +13,8 @@ import javax.annotation.concurrent.GuardedBy;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort;
 import org.opendaylight.controller.sal.core.spi.data.DOMStoreWriteTransaction;
@@ -23,6 +25,7 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.util.concurrent.CheckedFuture;
 import com.google.common.util.concurrent.ListenableFuture;
 
 /**
@@ -39,7 +42,7 @@ import com.google.common.util.concurrent.ListenableFuture;
  * </ul>
  * <p>
  * {@link #commit()} will result in invocation of
- * {@link DOMDataCommitImplementation#commit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
+ * {@link DOMDataCommitImplementation#submit(org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction, Iterable)}
  * invocation with all {@link org.opendaylight.controller.sal.core.spi.data.DOMStoreThreePhaseCommitCohort} for underlying
  * transactions.
  *
@@ -74,7 +77,7 @@ class DOMForwardedWriteTransaction<T extends DOMStoreWriteTransaction> extends
      *
      */
     @GuardedBy("this")
-    private volatile ListenableFuture<RpcResult<TransactionStatus>> commitFuture;
+    private volatile CheckedFuture<Void, TransactionCommitFailedException> commitFuture;
 
     protected DOMForwardedWriteTransaction(final Object identifier,
             final ImmutableMap<LogicalDatastoreType, T> backingTxs, final DOMDataCommitImplementation commitImpl) {
@@ -119,6 +122,11 @@ class DOMForwardedWriteTransaction<T extends DOMStoreWriteTransaction> extends
 
     @Override
     public synchronized ListenableFuture<RpcResult<TransactionStatus>> commit() {
+        return AbstractDataTransaction.convertToLegacyCommitFuture(submit());
+    }
+
+    @Override
+    public CheckedFuture<Void,TransactionCommitFailedException> submit() {
         checkNotReady();
 
         ImmutableList.Builder<DOMStoreThreePhaseCommitCohort> cohortsBuilder = ImmutableList.builder();
@@ -126,7 +134,7 @@ class DOMForwardedWriteTransaction<T extends DOMStoreWriteTransaction> extends
             cohortsBuilder.add(subTx.ready());
         }
         ImmutableList<DOMStoreThreePhaseCommitCohort> cohorts = cohortsBuilder.build();
-        commitFuture = commitImpl.commit(this, cohorts);
+        commitFuture = commitImpl.submit(this, cohorts);
 
         /*
          *We remove reference to Commit Implementation in order
@@ -148,5 +156,4 @@ class DOMForwardedWriteTransaction<T extends DOMStoreWriteTransaction> extends
     private void checkNotCommited() {
         checkState(commitFuture == null, "Transaction was already submited.");
     }
-
 }
\ No newline at end of file
index 27e322f23baf265a046d04317f2bfbf78ab2f74c..f57579858cf559404510c897a9f2fe76b6cfed36 100644 (file)
@@ -21,6 +21,7 @@ import java.util.concurrent.Future;
 
 import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
+import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation;
 import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizer;
@@ -204,7 +205,7 @@ DataModificationTransaction, Delegator<T> {
         public Future<RpcResult<TransactionStatus>> commit() {
             Preconditions.checkState(status == TransactionStatus.NEW);
             status = TransactionStatus.SUBMITED;
-            return getDelegate().commit();
+            return AbstractDataTransaction.convertToLegacyCommitFuture(getDelegate().submit());
         }
 
         @Override
index 29e078918e65eeae080f62c61d6ce5bae4fc3a9f..2dec6f2e4d1bdf773001c66343c8cf1ad4549160 100644 (file)
@@ -169,7 +169,7 @@ public class DOMBrokerPerformanceTest {
                             public List<ListenableFuture<?>> call() throws Exception {
                                 List<ListenableFuture<?>> builder = new ArrayList<>(txNum);
                                 for (DOMDataReadWriteTransaction tx :transactions) {
-                                    builder.add(tx.commit());
+                                    builder.add(tx.submit());
                                 }
                                 return builder;
                             }
@@ -267,7 +267,7 @@ public class DOMBrokerPerformanceTest {
                 measure("Txs:1 Submit", new Callable<ListenableFuture<?>>() {
                     @Override
                     public ListenableFuture<?> call() throws Exception {
-                        return writeTx.commit();
+                        return writeTx.submit();
                     }
                 }).get();
                 return null;
index fec73d665b90763a30ac7cc400d2bf364ffdd358..b006ca94e5d1387bfd84e7a76eccba3700756905 100644 (file)
@@ -107,7 +107,7 @@ public class DOMBrokerTest {
                 TestModel.TEST_PATH);
         assertTrue(writeTxContainer.get().isPresent());
 
-        writeTx.commit().get();
+        writeTx.submit().get();
 
         Optional<NormalizedNode<?, ?>> afterCommitRead = domBroker.newReadOnlyTransaction()
                 .read(OPERATIONAL, TestModel.TEST_PATH).get();
index 38f08b30f94ea37d4e73e3537c5c7bd798eb12ed..3ea0bcefa5bab97ea12a9ead64e40cce49b78277 100644 (file)
@@ -7,7 +7,6 @@
  */
 package org.opendaylight.controller.md.sal.dom.broker.impl;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -21,7 +20,6 @@ import java.util.concurrent.TimeoutException;
 
 import org.junit.Before;
 import org.junit.Test;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadTransaction;
 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
@@ -29,7 +27,6 @@ import org.opendaylight.controller.md.sal.dom.api.DOMTransactionChain;
 import org.opendaylight.controller.md.sal.dom.store.impl.InMemoryDOMDataStore;
 import org.opendaylight.controller.md.sal.dom.store.impl.TestModel;
 import org.opendaylight.controller.sal.core.spi.data.DOMStore;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
 import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
@@ -80,7 +77,7 @@ public class DOMTransactionChainTest {
          * First transaction is marked as ready, we are able to allocate chained
          * transactions
          */
-        ListenableFuture<RpcResult<TransactionStatus>> firstWriteTxFuture = firstTx.commit();
+        ListenableFuture<Void> firstWriteTxFuture = firstTx.submit();
 
         /**
          * We alocate chained transaction - read transaction.
@@ -126,7 +123,7 @@ public class DOMTransactionChainTest {
         /**
          * third transaction is sealed and commited
          */
-        ListenableFuture<RpcResult<TransactionStatus>> thirdDeleteTxFuture = thirdDeleteTx.commit();
+        ListenableFuture<Void> thirdDeleteTxFuture = thirdDeleteTx.submit();
         assertCommitSuccessful(thirdDeleteTxFuture);
 
         /**
@@ -188,11 +185,9 @@ public class DOMTransactionChainTest {
         return tx;
     }
 
-    private static void assertCommitSuccessful(final ListenableFuture<RpcResult<TransactionStatus>> future)
+    private static void assertCommitSuccessful(final ListenableFuture<Void> future)
             throws InterruptedException, ExecutionException {
-        RpcResult<TransactionStatus> rpcResult = future.get();
-        assertTrue(rpcResult.isSuccessful());
-        assertEquals(TransactionStatus.COMMITED, rpcResult.getResult());
+        future.get();
     }
 
     private static void assertTestContainerExists(final DOMDataReadTransaction readTx) throws InterruptedException,
index ea2ddc9b6558248f25ea7ae2bc7aec43f2f166f7..b7518e094d0e61594a391c2fc4a78b181294e00a 100644 (file)
@@ -20,10 +20,10 @@ import org.opendaylight.controller.md.sal.binding.api.DataBroker;
 import org.opendaylight.controller.md.sal.binding.api.DataChangeListener;
 import org.opendaylight.controller.md.sal.binding.api.ReadWriteTransaction;
 import org.opendaylight.controller.md.sal.binding.api.WriteTransaction;
-import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
 import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
 import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
+import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
 import org.opendaylight.controller.sal.binding.api.NotificationProviderService;
 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.DisplayString;
 import org.opendaylight.yang.gen.v1.http.netconfcentral.org.ns.toaster.rev091120.MakeToastInput;
@@ -100,12 +100,11 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         executor.shutdown();
 
         if (dataProvider != null) {
-            WriteTransaction t = dataProvider.newWriteOnlyTransaction();
-            t.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID);
-            ListenableFuture<RpcResult<TransactionStatus>> future = t.commit();
-            Futures.addCallback( future, new FutureCallback<RpcResult<TransactionStatus>>() {
+            WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
+            tx.delete(LogicalDatastoreType.OPERATIONAL,TOASTER_IID);
+            Futures.addCallback( tx.submit(), new FutureCallback<Void>() {
                 @Override
-                public void onSuccess( final RpcResult<TransactionStatus> result ) {
+                public void onSuccess( final Void result ) {
                     LOG.debug( "Delete Toaster commit result: " + result );
                 }
 
@@ -170,7 +169,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
 
         final SettableFuture<RpcResult<Void>> futureResult = SettableFuture.create();
 
-        checkStatusAndMakeToast( input, futureResult );
+        checkStatusAndMakeToast( input, futureResult, 2 );
 
         return futureResult;
     }
@@ -186,7 +185,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
     }
 
     private void checkStatusAndMakeToast( final MakeToastInput input,
-                                          final SettableFuture<RpcResult<Void>> futureResult ) {
+                                          final SettableFuture<RpcResult<Void>> futureResult,
+                                          final int tries ) {
 
         // Read the ToasterStatus and, if currently Up, try to write the status to Down.
         // If that succeeds, then we essentially have an exclusive lock and can proceed
@@ -196,12 +196,11 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         ListenableFuture<Optional<Toaster>> readFuture =
                                           tx.read( LogicalDatastoreType.OPERATIONAL, TOASTER_IID );
 
-        final ListenableFuture<RpcResult<TransactionStatus>> commitFuture =
-            Futures.transform( readFuture, new AsyncFunction<Optional<Toaster>,
-                                                                   RpcResult<TransactionStatus>>() {
+        final ListenableFuture<Void> commitFuture =
+            Futures.transform( readFuture, new AsyncFunction<Optional<Toaster>,Void>() {
 
                 @Override
-                public ListenableFuture<RpcResult<TransactionStatus>> apply(
+                public ListenableFuture<Void> apply(
                         final Optional<Toaster> toasterData ) throws Exception {
 
                     ToasterStatus toasterStatus = ToasterStatus.Up;
@@ -216,8 +215,8 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                         if( outOfBread() ) {
                             LOG.debug( "Toaster is out of bread" );
 
-                            return Futures.immediateFuture( RpcResultBuilder.<TransactionStatus>failed()
-                                    .withRpcError( makeToasterOutOfBreadError() ).build() );
+                            return Futures.immediateFailedCheckedFuture(
+                                    new TransactionCommitFailedException( "", makeToasterOutOfBreadError() ) );
                         }
 
                         LOG.debug( "Setting Toaster status to Down" );
@@ -227,7 +226,7 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                         // concurrent toasting.
                         tx.put( LogicalDatastoreType.OPERATIONAL, TOASTER_IID,
                                 buildToaster( ToasterStatus.Down ) );
-                        return tx.commit();
+                        return tx.submit();
                     }
 
                     LOG.debug( "Oops - already making toast!" );
@@ -235,30 +234,16 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                     // Return an error since we are already making toast. This will get
                     // propagated to the commitFuture below which will interpret the null
                     // TransactionStatus in the RpcResult as an error condition.
-                    return Futures.immediateFuture( RpcResultBuilder.<TransactionStatus>failed()
-                            .withRpcError( makeToasterInUseError() ).build() );
+                    return Futures.immediateFailedCheckedFuture(
+                            new TransactionCommitFailedException( "", makeToasterInUseError() ) );
                 }
         } );
 
-        Futures.addCallback( commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() {
+        Futures.addCallback( commitFuture, new FutureCallback<Void>() {
             @Override
-            public void onSuccess( final RpcResult<TransactionStatus> result ) {
-                if( result.getResult() == TransactionStatus.COMMITED  ) {
-
-                    // OK to make toast
-                    currentMakeToastTask.set( executor.submit(
-                                                    new MakeToastTask( input, futureResult ) ) );
-                } else {
-
-                    LOG.debug( "Setting error result" );
-
-                    // Either the transaction failed to commit for some reason or, more likely,
-                    // the read above returned ToasterStatus.Down. Either way, fail the
-                    // futureResult and copy the errors.
-
-                    futureResult.set( RpcResultBuilder.<Void>failed().withRpcErrors(
-                                                                     result.getErrors() ).build() );
-                }
+            public void onSuccess( final Void result ) {
+                // OK to make toast
+                currentMakeToastTask.set( executor.submit( new MakeToastTask( input, futureResult ) ) );
             }
 
             @Override
@@ -269,17 +254,24 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
                     // status before us. Try reading the status again - if another make toast is
                     // now in progress, we should get ToasterStatus.Down and fail.
 
-                    LOG.debug( "Got OptimisticLockFailedException - trying again" );
+                    if( ( tries - 1 ) > 0 ) {
+                        LOG.debug( "Got OptimisticLockFailedException - trying again" );
 
-                    checkStatusAndMakeToast( input, futureResult );
+                        checkStatusAndMakeToast( input, futureResult, tries - 1 );
+                    }
+                    else {
+                        futureResult.set( RpcResultBuilder.<Void> failed()
+                                .withError( ErrorType.APPLICATION, ex.getMessage() ).build() );
+                    }
 
                 } else {
 
-                    LOG.error( "Failed to commit Toaster status", ex );
+                    LOG.debug( "Failed to commit Toaster status", ex );
 
-                    // Got some unexpected error so fail.
+                    // Probably already making toast.
                     futureResult.set( RpcResultBuilder.<Void> failed()
-                                        .withError( ErrorType.APPLICATION, ex.getMessage() ).build() );
+                            .withRpcErrors( ((TransactionCommitFailedException)ex).getErrorList() )
+                            .build() );
                 }
             }
         } );
@@ -327,16 +319,10 @@ public class OpendaylightToaster implements ToasterService, ToasterProviderRunti
         WriteTransaction tx = dataProvider.newWriteOnlyTransaction();
         tx.put( LogicalDatastoreType.OPERATIONAL,TOASTER_IID, buildToaster( ToasterStatus.Up ) );
 
-        ListenableFuture<RpcResult<TransactionStatus>> commitFuture = tx.commit();
-
-        Futures.addCallback( commitFuture, new FutureCallback<RpcResult<TransactionStatus>>() {
+        Futures.addCallback( tx.submit(), new FutureCallback<Void>() {
             @Override
-            public void onSuccess( final RpcResult<TransactionStatus> result ) {
-                if( result.getResult() != TransactionStatus.COMMITED ) {
-                    LOG.error( "Failed to update toaster status: " + result.getErrors() );
-                }
-
-                notifyCallback( result.getResult() == TransactionStatus.COMMITED );
+            public void onSuccess( final Void result ) {
+                notifyCallback( true );
             }
 
             @Override