Migrate netconf to MD-SAL APIs
[netconf.git] / netconf / sal-netconf-connector / src / main / java / org / opendaylight / netconf / sal / connect / netconf / sal / tx / TxChain.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.sal.connect.netconf.sal.tx;
9
10 import com.google.common.base.Preconditions;
11 import java.util.HashMap;
12 import java.util.Map;
13 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
14 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadTransaction;
15 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
16 import org.opendaylight.mdsal.dom.api.DOMDataTreeWriteTransaction;
17 import org.opendaylight.mdsal.dom.api.DOMTransactionChain;
18 import org.opendaylight.mdsal.dom.api.DOMTransactionChainClosedException;
19 import org.opendaylight.mdsal.dom.api.DOMTransactionChainListener;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
22
23 /**
24  * {@link DOMTransactionChain} implementation for Netconf connector.
25  */
26 public class TxChain implements DOMTransactionChain, TxListener {
27
28     private static final Logger LOG = LoggerFactory.getLogger(TxChain.class);
29
30     private final DOMDataBroker dataBroker;
31     private final DOMTransactionChainListener listener;
32     /**
33      * Submitted transactions that haven't completed yet.
34      */
35     private final Map<DOMDataTreeWriteTransaction, AutoCloseable> pendingTransactions = new HashMap<>();
36
37     /**
38      * Transaction created by this chain that hasn't been submitted or cancelled yet.
39      */
40     private AbstractWriteTx currentTransaction = null;
41     private boolean closed = false;
42     private boolean successful = true;
43
44     public TxChain(final DOMDataBroker dataBroker, final DOMTransactionChainListener listener) {
45         this.dataBroker = dataBroker;
46         this.listener = listener;
47     }
48
49     @Override
50     public synchronized DOMDataTreeReadTransaction newReadOnlyTransaction() {
51         checkOperationPermitted();
52         return dataBroker.newReadOnlyTransaction();
53     }
54
55     @Override
56     public synchronized AbstractWriteTx newWriteOnlyTransaction() {
57         checkOperationPermitted();
58         final DOMDataTreeWriteTransaction writeTransaction = dataBroker.newWriteOnlyTransaction();
59         Preconditions.checkState(writeTransaction instanceof AbstractWriteTx);
60         final AbstractWriteTx pendingWriteTx = (AbstractWriteTx) writeTransaction;
61         pendingTransactions.put(pendingWriteTx, pendingWriteTx.addListener(this));
62         currentTransaction = pendingWriteTx;
63         return pendingWriteTx;
64     }
65
66     @Override
67     public synchronized DOMDataTreeReadWriteTransaction newReadWriteTransaction() {
68         return new ReadWriteTx(dataBroker.newReadOnlyTransaction(), newWriteOnlyTransaction());
69     }
70
71     @Override
72     public synchronized void close() {
73         if (!closed) {
74             closed = true;
75             notifyChainListenerSuccess();
76         }
77     }
78
79     @Override
80     public synchronized void onTransactionSuccessful(final AbstractWriteTx transaction) {
81         removePendingTx(transaction);
82         notifyChainListenerSuccess();
83     }
84
85     @Override
86     public synchronized void onTransactionFailed(final AbstractWriteTx transaction, final Throwable cause) {
87         removePendingTx(transaction);
88         successful = false;
89         if (currentTransaction != null) {
90             currentTransaction.cancel();
91         }
92         listener.onTransactionChainFailed(this, transaction, cause);
93     }
94
95     @Override
96     public synchronized void onTransactionSubmitted(final AbstractWriteTx transaction) {
97         currentTransaction = null;
98     }
99
100     @Override
101     public synchronized void onTransactionCancelled(final AbstractWriteTx transaction) {
102         removePendingTx(transaction);
103         currentTransaction = null;
104     }
105
106     @SuppressWarnings("checkstyle:IllegalCatch")
107     private void removePendingTx(final AbstractWriteTx transaction) {
108         try {
109             pendingTransactions.remove(transaction).close();
110         } catch (final Exception e) {
111             LOG.error("Can't remove transaction listener registration", e);
112         }
113     }
114
115     /**
116      * Checks, if chain isn't closed and if there is no not submitted write transaction waiting.
117      */
118     private void checkOperationPermitted() {
119         if (closed) {
120             throw new DOMTransactionChainClosedException("Transaction chain was closed");
121         }
122         Preconditions.checkState(currentTransaction == null, "Last write transaction has not finished yet");
123     }
124
125     private void notifyChainListenerSuccess() {
126         if (closed && pendingTransactions.isEmpty() && successful) {
127             listener.onTransactionChainSuccessful(this);
128         }
129     }
130
131 }