Refactor DOM{Action,Rpc}Implementation
[mdsal.git] / dom / mdsal-dom-api / src / main / java / org / opendaylight / mdsal / dom / api / DOMTransactionChain.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.mdsal.dom.api;
9
10 import com.google.common.util.concurrent.FutureCallback;
11 import com.google.common.util.concurrent.Futures;
12 import com.google.common.util.concurrent.ListenableFuture;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import java.util.concurrent.Executor;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.yangtools.concepts.Registration;
17 import org.opendaylight.yangtools.yang.common.Empty;
18
19 /**
20  * A chain of transactions. Transactions in a chain need to be committed in sequence and each transaction should see
21  * the effects of previous committed transactions as they occurred. A chain makes no guarantees of atomicity across
22  * the chained transactions - the transactions are committed as soon as possible in the order that they were committed.
23  * This behaviour is different from the default AsyncDataBroker, where a transaction is always created from the current
24  * global state, not taking into account any transactions previously committed by the calling thread. Due to
25  * the asynchronous nature of transaction submission this can lead to surprising results. If a thread executes
26  * the following sequence sufficiently quickly:
27  *
28  * <code>
29  * DOMWriteTransaction t1 = broker.newWriteOnlyTransaction();
30  * t1.put(id, data);
31  * t1.commit();
32  *
33  * DOMReadTransaction t2 = broker.newReadOnlyTransaction();
34  * Optional&lt;?&gt; maybeData = t2.read(id).get();
35  * </code>
36  * it may happen, that it sees maybeData.isPresent() == false, simply because t1 has not completed the processes
37  * of being applied and t2 is actually allocated from the previous state. This is obviously bad for users who create
38  * incremental state in the datastore and actually read what they write in subsequent transactions.
39  * Using a TransactionChain instead of a broker solves this particular problem, and leads to expected behavior: t2 will
40  * always see the data written in t1
41  * present.
42  */
43 public interface DOMTransactionChain extends Registration, DOMTransactionFactory {
44     /**
45      * Create a new read only transaction which will continue the chain.
46      *
47      * <p>
48      * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
49      * invoked) or CANCELLED ({@link #close close} was invoked).
50      *
51      * <p>
52      * The returned read-only transaction presents an isolated view of the data if the previous write transaction was
53      * successful - in other words, this read-only transaction will see the state changes made by the previous write
54      * transaction in the chain. However, state which was introduced by other transactions outside this transaction
55      * chain after creation of the previous transaction is not visible.
56      *
57      * @return New transaction in the chain.
58      * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
59      * @throws DOMTransactionChainClosedException if the chain has been closed.
60      */
61     @Override
62     DOMDataTreeReadTransaction newReadOnlyTransaction();
63
64     /**
65      * Create a new write-only transaction which will continue the chain.
66      *
67      * <p>
68      * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
69      * invoked) or CANCELLED ({@link #close close} was invoked)
70      *
71      * <p>
72      * The returned write-only transaction presents an isolated view of the data if the previous write transaction was
73      * successful - in other words, this write-only transaction will see the state changes made by the previous write
74      * transaction in the chain. However, state which was introduced by other transactions outside this transaction
75      * chain after creation of the previous transaction is not visible
76      *
77      * <p>
78      * Committing this write-only transaction using {@link DOMDataTreeWriteTransaction#commit commit} will commit
79      * the state changes in this transaction to be visible to any subsequent transaction in this chain and also to any
80      * transaction outside this chain.
81      *
82      * @return New transaction in the chain.
83      * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
84      * @throws DOMTransactionChainClosedException if the chain has been closed.
85      */
86     @Override
87     DOMDataTreeWriteTransaction newWriteOnlyTransaction();
88
89     /**
90      * Create a new read-write transaction which will continue the chain.
91      *
92      * <p>
93      * The previous write transaction has to be either SUBMITTED ({@link DOMDataTreeWriteTransaction#commit commit} was
94      * invoked) or CANCELLED ({@link #close close} was invoked).
95      *
96      * <p>
97      * The returned read-write transaction presents an isolated view of the data if the previous write transaction was
98      * successful - in other words, this read-write transaction will see the state changes made by the previous write
99      * transaction in the chain. However, state which was introduced by other transactions outside this transaction
100      * chain after creation of the previous transaction is not visible.
101      *
102      * <p>
103      * Committing this read-write transaction using {@link DOMDataTreeReadWriteTransaction#commit commit} will commit
104      * the state changes in this transaction to be visible to any subsequent transaction in this chain and also to any
105      * transaction outside this chain.
106      *
107      * @return New transaction in the chain.
108      * @throws IllegalStateException if the previous transaction was not SUBMITTED or CANCELLED.
109      * @throws DOMTransactionChainClosedException if the chain has been closed.
110      */
111     @Override
112     DOMDataTreeReadWriteTransaction newReadWriteTransaction();
113
114     /**
115      * Add a completion callback to execute when {@link #future()} completes. This is a shorthand for
116      * {@code Futures.addCallback(future(), callback, MoreExecutors.directExecutor())}.
117      *
118      * @param callback completion callback
119      */
120     default void addCallback(final FutureCallback<Empty> callback) {
121         addCallback(callback, MoreExecutors.directExecutor());
122     }
123
124     /**
125      * Add a completion callback to execute on specified executor when {@link #future()} completes. This is a shorthand
126      * for {@code Futures.addCallback(future(), callback, executor)}.
127      *
128      * @param callback completion callback
129      * @param executor executor on which to execute the callback
130      */
131     default void addCallback(final FutureCallback<Empty> callback, final Executor executor) {
132         Futures.addCallback(future(), callback, executor);
133     }
134
135     /**
136      * Return a {@link ListenableFuture} which completes when this chain completes.
137      *
138      * @return A {@link ListenableFuture}
139      */
140     @NonNull ListenableFuture<Empty> future();
141 }