Bump upstreams
[netconf.git] / plugins / netconf-client-mdsal / src / main / java / org / opendaylight / netconf / client / mdsal / spi / AbstractTxChain.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.netconf.client.mdsal.spi;
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.ListenableFuture;
14 import com.google.common.util.concurrent.SettableFuture;
15 import java.util.HashMap;
16 import java.util.Map;
17 import org.eclipse.jdt.annotation.NonNull;
18 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
19 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
20 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
21 import org.opendaylight.mdsal.dom.api.DOMTransactionChainClosedException;
22 import org.opendaylight.yangtools.concepts.Registration;
23 import org.opendaylight.yangtools.yang.common.Empty;
24
25 /**
26  * {@link DOMTransactionChain} implementation for Netconf connector.
27  */
28 abstract class AbstractTxChain implements DOMTransactionChain, TxListener {
29     // Submitted transactions that haven't completed yet.
30     private final Map<DOMDataTreeWriteTransaction, Registration> pendingTransactions = new HashMap<>();
31     private final @NonNull SettableFuture<Empty> future = SettableFuture.create();
32
33     final DOMDataBroker dataBroker;
34
35     /**
36      * Transaction created by this chain that hasn't been submitted or cancelled yet.
37      */
38     private AbstractWriteTx currentTransaction = null;
39     private boolean closed = false;
40     private boolean successful = true;
41
42     AbstractTxChain(final DOMDataBroker dataBroker) {
43         this.dataBroker = requireNonNull(dataBroker);
44     }
45
46     @Override
47     public final ListenableFuture<Empty> future() {
48         return future;
49     }
50
51     @Override
52     public final synchronized AbstractWriteTx newWriteOnlyTransaction() {
53         checkOperationPermitted();
54
55         final var writeTransaction = dataBroker.newWriteOnlyTransaction();
56         if (!(writeTransaction instanceof AbstractWriteTx pendingWriteTx)) {
57             throw new IllegalStateException("Unexpected transaction " + writeTransaction);
58         }
59         pendingTransactions.put(pendingWriteTx, pendingWriteTx.addListener(this));
60         currentTransaction = pendingWriteTx;
61         return pendingWriteTx;
62     }
63
64     @Override
65     public final synchronized void close() {
66         if (!closed) {
67             closed = true;
68             notifyChainListenerSuccess();
69         }
70     }
71
72     @Override
73     public final synchronized void onTransactionSuccessful(final AbstractWriteTx transaction) {
74         removePendingTx(transaction);
75         notifyChainListenerSuccess();
76     }
77
78     @Override
79     public final synchronized void onTransactionFailed(final AbstractWriteTx transaction, final Throwable cause) {
80         removePendingTx(transaction);
81         successful = false;
82         if (currentTransaction != null) {
83             currentTransaction.cancel();
84         }
85         future.setException(cause);
86     }
87
88     @Override
89     public final synchronized void onTransactionSubmitted(final AbstractWriteTx transaction) {
90         currentTransaction = null;
91     }
92
93     @Override
94     public final synchronized void onTransactionCancelled(final AbstractWriteTx transaction) {
95         removePendingTx(transaction);
96         currentTransaction = null;
97     }
98
99     /**
100      * Checks, if chain isn't closed and if there is no not submitted write transaction waiting.
101      */
102     final void checkOperationPermitted() {
103         if (closed) {
104             throw new DOMTransactionChainClosedException("Transaction chain was closed");
105         }
106         checkState(currentTransaction == null, "Last write transaction has not finished yet");
107     }
108
109     private void removePendingTx(final AbstractWriteTx transaction) {
110         pendingTransactions.remove(transaction).close();
111     }
112
113     private void notifyChainListenerSuccess() {
114         if (closed && pendingTransactions.isEmpty() && successful) {
115             future.set(Empty.value());
116         }
117     }
118 }