Merge "Bug 2806 - Immediate and infinite reconnect attempts during negotiation" into...
[netconf.git] / opendaylight / netconf / mdsal-netconf-connector / src / main / java / org / opendaylight / netconf / mdsal / connector / TransactionProvider.java
1 /*
2  * Copyright (c) 2015 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
9 package org.opendaylight.netconf.mdsal.connector;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.util.concurrent.CheckedFuture;
14 import java.util.ArrayList;
15 import java.util.List;
16 import org.opendaylight.controller.config.util.xml.DocumentedException;
17 import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorSeverity;
18 import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorTag;
19 import org.opendaylight.controller.config.util.xml.DocumentedException.ErrorType;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.controller.md.sal.dom.api.DOMDataBroker;
22 import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
25
26 //TODO make a global TransactionProvider for all Netconf sessions instead of each session having one.
27 public class TransactionProvider implements AutoCloseable{
28
29     private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
30
31     private final DOMDataBroker dataBroker;
32
33     private DOMDataReadWriteTransaction candidateTransaction = null;
34     private DOMDataReadWriteTransaction runningTransaction = null;
35     private final List<DOMDataReadWriteTransaction> allOpenReadWriteTransactions = new ArrayList<>();
36
37     private final String netconfSessionIdForReporting;
38
39     private static final String  NO_TRANSACTION_FOUND_FOR_SESSION = "No candidateTransaction found for session ";
40
41
42     public TransactionProvider(DOMDataBroker dataBroker, String netconfSessionIdForReporting) {
43         this.dataBroker = dataBroker;
44         this.netconfSessionIdForReporting = netconfSessionIdForReporting;
45     }
46
47     @Override
48     public synchronized void close() throws Exception {
49         for (DOMDataReadWriteTransaction rwt : allOpenReadWriteTransactions) {
50             rwt.cancel();
51         }
52
53         allOpenReadWriteTransactions.clear();
54     }
55
56     public synchronized Optional<DOMDataReadWriteTransaction> getCandidateTransaction() {
57         if (candidateTransaction == null) {
58             return Optional.absent();
59         }
60
61         return Optional.of(candidateTransaction);
62     }
63
64     public synchronized DOMDataReadWriteTransaction getOrCreateTransaction() {
65         if (getCandidateTransaction().isPresent()) {
66             return getCandidateTransaction().get();
67         }
68
69         candidateTransaction = dataBroker.newReadWriteTransaction();
70         allOpenReadWriteTransactions.add(candidateTransaction);
71         return candidateTransaction;
72     }
73
74     public synchronized boolean commitTransaction() throws DocumentedException {
75         if (!getCandidateTransaction().isPresent()) {
76             //making empty commit without prior opened transaction, just return true
77             LOG.debug("Making commit without open candidate transaction for session {}", netconfSessionIdForReporting);
78             return true;
79         }
80
81         CheckedFuture<Void, TransactionCommitFailedException> future = candidateTransaction.submit();
82         try {
83             future.checkedGet();
84         } catch (TransactionCommitFailedException e) {
85             LOG.debug("Transaction {} failed on", candidateTransaction, e);
86             final String cause = e.getCause() != null ? (" Cause: " + e.getCause().getMessage()) : "";
87             throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting +
88                     cause,
89                     ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
90         } finally {
91             allOpenReadWriteTransactions.remove(candidateTransaction);
92             candidateTransaction = null;
93         }
94
95         return true;
96     }
97
98     public synchronized void abortTransaction() {
99         LOG.debug("Aborting current candidateTransaction");
100         Optional<DOMDataReadWriteTransaction> otx = getCandidateTransaction();
101         if (!otx.isPresent()) {
102             LOG.warn("discard-changes triggerd on an empty transaction for session: {}", netconfSessionIdForReporting );
103             return;
104         }
105         candidateTransaction.cancel();
106         allOpenReadWriteTransactions.remove(candidateTransaction);
107         candidateTransaction = null;
108     }
109
110     public synchronized DOMDataReadWriteTransaction createRunningTransaction() {
111         runningTransaction = dataBroker.newReadWriteTransaction();
112         allOpenReadWriteTransactions.add(runningTransaction);
113         return runningTransaction;
114     }
115
116     public synchronized boolean commitRunningTransaction(DOMDataReadWriteTransaction tx) throws DocumentedException {
117         allOpenReadWriteTransactions.remove(tx);
118
119         CheckedFuture<Void, TransactionCommitFailedException> future = tx.submit();
120         try {
121             future.checkedGet();
122         } catch (TransactionCommitFailedException e) {
123             LOG.debug("Transaction {} failed on", tx, e);
124             throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " " + netconfSessionIdForReporting,
125                     ErrorType.application, ErrorTag.operation_failed, ErrorSeverity.error);
126         }
127
128         return true;
129     }
130
131     public synchronized void abortRunningTransaction(DOMDataReadWriteTransaction tx) {
132         LOG.debug("Aborting current running Transaction");
133         Preconditions.checkState(runningTransaction != null, NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
134         tx.cancel();
135         allOpenReadWriteTransactions.remove(tx);
136     }
137
138 }