2 * Copyright (c) 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.netconf.mdsal.connector;
10 import static com.google.common.base.Preconditions.checkState;
12 import com.google.common.util.concurrent.FluentFuture;
13 import java.util.ArrayList;
14 import java.util.List;
15 import java.util.Optional;
16 import java.util.concurrent.ExecutionException;
17 import org.opendaylight.mdsal.common.api.CommitInfo;
18 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
19 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
20 import org.opendaylight.netconf.api.DocumentedException;
21 import org.opendaylight.netconf.api.DocumentedException.ErrorSeverity;
22 import org.opendaylight.netconf.api.DocumentedException.ErrorTag;
23 import org.opendaylight.netconf.api.DocumentedException.ErrorType;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
27 public class TransactionProvider implements AutoCloseable {
28 private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
30 private final DOMDataBroker dataBroker;
32 private DOMDataTreeReadWriteTransaction candidateTransaction = null;
33 private DOMDataTreeReadWriteTransaction runningTransaction = null;
34 private final List<DOMDataTreeReadWriteTransaction> allOpenReadWriteTransactions = new ArrayList<>();
35 private final DOMDataTransactionValidator transactionValidator;
37 private final String netconfSessionIdForReporting;
39 private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No candidateTransaction found for session ";
41 public TransactionProvider(final DOMDataBroker dataBroker, final String netconfSessionIdForReporting) {
42 this.dataBroker = dataBroker;
43 this.netconfSessionIdForReporting = netconfSessionIdForReporting;
44 this.transactionValidator = dataBroker.getExtensions().getInstance(DOMDataTransactionValidator.class);
48 public synchronized void close() {
49 for (final DOMDataTreeReadWriteTransaction rwt : allOpenReadWriteTransactions) {
53 allOpenReadWriteTransactions.clear();
56 public synchronized Optional<DOMDataTreeReadWriteTransaction> getCandidateTransaction() {
57 return Optional.ofNullable(candidateTransaction);
60 public synchronized DOMDataTreeReadWriteTransaction getOrCreateTransaction() {
61 if (getCandidateTransaction().isPresent()) {
62 return getCandidateTransaction().get();
65 candidateTransaction = dataBroker.newReadWriteTransaction();
66 allOpenReadWriteTransactions.add(candidateTransaction);
67 return candidateTransaction;
70 public synchronized void validateTransaction() throws DocumentedException {
71 if (transactionValidator == null) {
72 LOG.error("Validate capability is not supported");
73 throw new DocumentedException("Validate capability is not supported",
74 ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
77 if (getCandidateTransaction().isEmpty()) {
78 // Validating empty transaction, just return true
79 LOG.debug("Validating empty candidate transaction for session {}", netconfSessionIdForReporting);
84 transactionValidator.validate(candidateTransaction).get();
85 } catch (final InterruptedException | ExecutionException e) {
86 LOG.debug("Candidate transaction validation {} failed on session {}", candidateTransaction,
87 netconfSessionIdForReporting, e);
88 final String cause = e.getCause() != null ? " Cause: " + e.getCause().getMessage() : "";
89 throw new DocumentedException("Candidate transaction validate failed [sessionId="
90 + netconfSessionIdForReporting + "]: " + e.getMessage() + cause, e, ErrorType.APPLICATION,
91 ErrorTag.OPERATION_FAILED, ErrorSeverity.ERROR);
95 public synchronized boolean commitTransaction() throws DocumentedException {
96 if (getCandidateTransaction().isEmpty()) {
97 //making empty commit without prior opened transaction, just return true
98 LOG.debug("Making commit without open candidate transaction for session {}", netconfSessionIdForReporting);
102 final FluentFuture<? extends CommitInfo> future = candidateTransaction.commit();
105 } catch (final InterruptedException | ExecutionException e) {
106 LOG.debug("Transaction {} failed on", candidateTransaction, e);
107 final String cause = e.getCause() != null ? " Cause: " + e.getCause().getMessage() : "";
108 throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " "
109 + netconfSessionIdForReporting + cause, e, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
110 ErrorSeverity.ERROR);
112 allOpenReadWriteTransactions.remove(candidateTransaction);
113 candidateTransaction = null;
119 public synchronized void abortTransaction() {
120 LOG.debug("Aborting current candidateTransaction");
121 final Optional<DOMDataTreeReadWriteTransaction> otx = getCandidateTransaction();
123 LOG.warn("discard-changes triggerd on an empty transaction for session: {}", netconfSessionIdForReporting);
126 candidateTransaction.cancel();
127 allOpenReadWriteTransactions.remove(candidateTransaction);
128 candidateTransaction = null;
131 public synchronized DOMDataTreeReadWriteTransaction createRunningTransaction() {
132 runningTransaction = dataBroker.newReadWriteTransaction();
133 allOpenReadWriteTransactions.add(runningTransaction);
134 return runningTransaction;
137 public synchronized void abortRunningTransaction(final DOMDataTreeReadWriteTransaction tx) {
138 LOG.debug("Aborting current running Transaction");
139 checkState(runningTransaction != null, NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
141 allOpenReadWriteTransactions.remove(tx);