Do not generate 'isFoo()' methods
[mdsal.git] / dom / mdsal-dom-broker / src / main / java / org / opendaylight / mdsal / dom / broker / ShardedDOMTransactionChainAdapter.java
1 /*
2  * Copyright (c) 2016 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.broker;
9
10 import static com.google.common.base.Preconditions.checkState;
11 import static java.util.Objects.requireNonNull;
12
13 import com.google.common.util.concurrent.FluentFuture;
14 import com.google.common.util.concurrent.FutureCallback;
15 import com.google.common.util.concurrent.MoreExecutors;
16 import java.util.Collection;
17 import java.util.Collections;
18 import java.util.EnumMap;
19 import java.util.Map;
20 import java.util.concurrent.atomic.AtomicLong;
21 import org.opendaylight.mdsal.common.api.CommitInfo;
22 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
23 import org.opendaylight.mdsal.dom.api.DOMDataTreeCursorAwareTransaction;
24 import org.opendaylight.mdsal.dom.api.DOMDataTreeIdentifier;
25 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducer;
26 import org.opendaylight.mdsal.dom.api.DOMDataTreeProducerException;
27 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
28 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
29 import org.opendaylight.mdsal.dom.api.DOMDataTreeService;
30 import org.opendaylight.mdsal.dom.api.DOMDataTreeTransaction;
31 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
32 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
33 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
34 import org.opendaylight.mdsal.dom.spi.ForwardingDOMDataTreeService;
35
36 public class ShardedDOMTransactionChainAdapter implements DOMTransactionChain {
37
38     private final DOMDataTreeService dataTreeService;
39     private final Object txChainIdentifier;
40     private final AtomicLong txNum = new AtomicLong();
41     private final DOMTransactionChainListener txChainListener;
42     private final CachedDataTreeService cachedDataTreeService;
43     private TransactionChainWriteTransaction writeTx;
44     private TransactionChainReadTransaction readTx;
45     private FluentFuture<? extends CommitInfo> writeTxCommitFuture;
46     private boolean finished = false;
47
48     public ShardedDOMTransactionChainAdapter(final Object txChainIdentifier,
49             final DOMDataTreeService dataTreeService, final DOMTransactionChainListener txChainListener) {
50         this.dataTreeService = requireNonNull(dataTreeService);
51         this.txChainIdentifier = requireNonNull(txChainIdentifier);
52         this.txChainListener = txChainListener;
53         this.cachedDataTreeService = new CachedDataTreeService(dataTreeService);
54     }
55
56     @Override
57     public DOMDataTreeReadTransaction newReadOnlyTransaction() {
58         checkRunning();
59         checkReadTxClosed();
60         checkWriteTxClosed();
61         readTx = new TransactionChainReadTransaction(newTransactionIdentifier(),
62                 new ShardedDOMReadTransactionAdapter(newTransactionIdentifier(), dataTreeService),
63                 writeTxCommitFuture, this);
64
65         return readTx;
66     }
67
68     @Override
69     public DOMDataTreeWriteTransaction newWriteOnlyTransaction() {
70         checkRunning();
71         checkWriteTxClosed();
72         checkReadTxClosed();
73         writeTx = new TransactionChainWriteTransaction(newTransactionIdentifier(),
74                 new ShardedDOMWriteTransactionAdapter(newTransactionIdentifier(),
75                         cachedDataTreeService), this);
76
77         return writeTx;
78     }
79
80     @Override
81     public DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
82         checkRunning();
83         checkWriteTxClosed();
84         checkReadTxClosed();
85         ShardedDOMReadWriteTransactionAdapter adapter = new ShardedDOMReadWriteTransactionAdapter(
86                 newTransactionIdentifier(), cachedDataTreeService);
87         TransactionChainReadWriteTransaction readWriteTx = new TransactionChainReadWriteTransaction(
88                 newTransactionIdentifier(), adapter, adapter.getReadAdapter(), writeTxCommitFuture, this);
89
90         writeTx = readWriteTx;
91         return readWriteTx;
92     }
93
94     @Override
95     public void close() {
96         if (finished) {
97             // already closed, do nothing
98             return;
99         }
100
101         checkReadTxClosed();
102         checkWriteTxClosed();
103         writeTxCommitFuture.addCallback(new FutureCallback<CommitInfo>() {
104             @Override
105             public void onSuccess(final CommitInfo result) {
106                 txChainListener.onTransactionChainSuccessful(ShardedDOMTransactionChainAdapter.this);
107             }
108
109             @Override
110             public void onFailure(final Throwable throwable) {
111                 // We don't have to do nothing here,
112                 // tx should take car of it
113             }
114         }, MoreExecutors.directExecutor());
115
116         cachedDataTreeService.closeProducers();
117         finished = true;
118     }
119
120     public void closeReadTransaction() {
121         readTx = null;
122     }
123
124     public void closeWriteTransaction(final FluentFuture<? extends CommitInfo> commitFuture) {
125         writeTxCommitFuture = commitFuture;
126         writeTx = null;
127     }
128
129     private Object newTransactionIdentifier() {
130         return "DOM-CHAIN-" + txChainIdentifier + "-" + txNum.getAndIncrement();
131     }
132
133     private void checkWriteTxClosed() {
134         checkState(writeTx == null);
135     }
136
137     private void checkReadTxClosed() {
138         checkState(readTx == null);
139     }
140
141     private void checkRunning() {
142         checkState(!finished);
143     }
144
145     public void transactionFailed(final DOMDataTreeTransaction tx, final Throwable cause) {
146         txChainListener.onTransactionChainFailed(this, tx, cause);
147         if (writeTx != null) {
148             writeTx.cancel();
149         }
150         if (readTx != null) {
151             readTx.close();
152         }
153         cachedDataTreeService.closeProducers();
154         finished = true;
155     }
156
157     private static final class CachedDataTreeService extends ForwardingDOMDataTreeService {
158         private final Map<LogicalDatastoreType, NoopCloseDataProducer> producersMap =
159             new EnumMap<>(LogicalDatastoreType.class);
160         private final DOMDataTreeService delegate;
161
162         CachedDataTreeService(final DOMDataTreeService delegate) {
163             this.delegate = requireNonNull(delegate);
164         }
165
166         @Override
167         public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
168             checkState(subtrees.size() == 1);
169             DOMDataTreeIdentifier treeId = subtrees.iterator().next();
170             NoopCloseDataProducer producer = new NoopCloseDataProducer(delegate.createProducer(
171                 Collections.singleton(treeId)));
172             producersMap.putIfAbsent(treeId.getDatastoreType(), producer);
173             return producer;
174         }
175
176         @Override
177         protected DOMDataTreeService delegate() {
178             return delegate;
179         }
180
181         void closeProducers() {
182             producersMap.values().forEach(NoopCloseDataProducer::closeDelegate);
183         }
184     }
185
186     private static final class NoopCloseDataProducer implements DOMDataTreeProducer {
187         private final DOMDataTreeProducer delegateTreeProducer;
188
189         NoopCloseDataProducer(final DOMDataTreeProducer delegateTreeProducer) {
190             this.delegateTreeProducer = delegateTreeProducer;
191         }
192
193         @Override
194         public DOMDataTreeCursorAwareTransaction createTransaction(final boolean isolated) {
195             return delegateTreeProducer.createTransaction(isolated);
196         }
197
198         @Override
199         public DOMDataTreeProducer createProducer(final Collection<DOMDataTreeIdentifier> subtrees) {
200             return delegateTreeProducer.createProducer(subtrees);
201         }
202
203         @Override
204         public void close() {
205             // noop
206         }
207
208         public void closeDelegate() {
209             try {
210                 delegateTreeProducer.close();
211             } catch (final DOMDataTreeProducerException e) {
212                 throw new IllegalStateException("Trying to close DOMDataTreeProducer with open transaction", e);
213             }
214         }
215     }
216 }