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.server.mdsal;
10 import com.google.common.util.concurrent.FluentFuture;
11 import java.util.ArrayList;
12 import java.util.List;
13 import java.util.Optional;
14 import java.util.concurrent.ExecutionException;
15 import org.opendaylight.mdsal.common.api.CommitInfo;
16 import org.opendaylight.mdsal.dom.api.DOMDataBroker;
17 import org.opendaylight.mdsal.dom.api.DOMDataTreeReadWriteTransaction;
18 import org.opendaylight.netconf.api.DocumentedException;
19 import org.opendaylight.yang.gen.v1.urn.ietf.params.xml.ns.netconf.base._1._0.rev110601.SessionIdType;
20 import org.opendaylight.yangtools.yang.common.ErrorSeverity;
21 import org.opendaylight.yangtools.yang.common.ErrorTag;
22 import org.opendaylight.yangtools.yang.common.ErrorType;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 public final class TransactionProvider implements AutoCloseable {
27 private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
29 private final List<DOMDataTreeReadWriteTransaction> allOpenReadWriteTransactions = new ArrayList<>();
30 private final DOMDataTransactionValidator transactionValidator;
31 private final DOMDataBroker dataBroker;
32 private final SessionIdType sessionId;
34 private DOMDataTreeReadWriteTransaction candidateTransaction = null;
35 private DOMDataTreeReadWriteTransaction runningTransaction = null;
37 public TransactionProvider(final DOMDataBroker dataBroker, final SessionIdType sessionId) {
38 this.dataBroker = dataBroker;
39 this.sessionId = sessionId;
40 transactionValidator = dataBroker.extension(DOMDataTransactionValidator.class);
44 public synchronized void close() {
45 for (var rwt : allOpenReadWriteTransactions) {
49 allOpenReadWriteTransactions.clear();
52 public synchronized Optional<DOMDataTreeReadWriteTransaction> getCandidateTransaction() {
53 return Optional.ofNullable(candidateTransaction);
56 public synchronized DOMDataTreeReadWriteTransaction getOrCreateTransaction() {
57 if (candidateTransaction == null) {
58 candidateTransaction = dataBroker.newReadWriteTransaction();
59 allOpenReadWriteTransactions.add(candidateTransaction);
61 return candidateTransaction;
64 public synchronized void validateTransaction() throws DocumentedException {
65 if (transactionValidator == null) {
66 LOG.error("Validate capability is not supported");
67 throw new DocumentedException("Validate capability is not supported",
68 ErrorType.PROTOCOL, ErrorTag.OPERATION_NOT_SUPPORTED, ErrorSeverity.ERROR);
71 if (candidateTransaction == null) {
72 // Validating empty transaction, just return true
73 LOG.debug("Validating empty candidate transaction for session {}", sessionId.getValue());
78 transactionValidator.validate(candidateTransaction).get();
79 } catch (final InterruptedException | ExecutionException e) {
80 LOG.debug("Candidate transaction validation {} failed on session {}", candidateTransaction,
81 sessionId.getValue(), e);
82 final String cause = e.getCause() != null ? " Cause: " + e.getCause().getMessage() : "";
83 throw new DocumentedException("Candidate transaction validate failed [sessionId="
84 + sessionId.getValue() + "]: " + e.getMessage() + cause, e, ErrorType.APPLICATION,
85 ErrorTag.OPERATION_FAILED, ErrorSeverity.ERROR);
89 public synchronized boolean commitTransaction() throws DocumentedException {
90 if (candidateTransaction == null) {
91 //making empty commit without prior opened transaction, just return true
92 LOG.debug("Making commit without open candidate transaction for session {}", sessionId.getValue());
96 final FluentFuture<? extends CommitInfo> future = candidateTransaction.commit();
99 } catch (final InterruptedException | ExecutionException e) {
100 LOG.debug("Transaction {} failed on", candidateTransaction, e);
101 final String cause = e.getCause() != null ? " Cause: " + e.getCause().getMessage() : "";
102 throw new DocumentedException("Transaction commit failed on " + e.getMessage() + " "
103 + sessionId.getValue() + cause, e, ErrorType.APPLICATION, ErrorTag.OPERATION_FAILED,
104 ErrorSeverity.ERROR);
106 allOpenReadWriteTransactions.remove(candidateTransaction);
107 candidateTransaction = null;
113 public synchronized void abortTransaction() {
114 LOG.debug("Aborting current candidateTransaction");
115 if (candidateTransaction == null) {
116 LOG.warn("discard-changes triggerd on an empty transaction for session: {}", sessionId.getValue());
120 candidateTransaction.cancel();
121 allOpenReadWriteTransactions.remove(candidateTransaction);
122 candidateTransaction = null;
125 public synchronized DOMDataTreeReadWriteTransaction createRunningTransaction() {
126 runningTransaction = dataBroker.newReadWriteTransaction();
127 allOpenReadWriteTransactions.add(runningTransaction);
128 return runningTransaction;
131 public synchronized void abortRunningTransaction(final DOMDataTreeReadWriteTransaction tx) {
132 LOG.debug("Aborting current running Transaction");
133 if (runningTransaction == null) {
134 throw new IllegalStateException("No candidateTransaction found for session " + sessionId.getValue());
137 allOpenReadWriteTransactions.remove(tx);