2 * Copyright (c) 2013 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
9 package org.opendaylight.controller.netconf.confignetconfconnector.transactions;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import org.opendaylight.controller.config.api.ConflictingVersionException;
14 import org.opendaylight.controller.config.api.ValidationException;
15 import org.opendaylight.controller.config.api.jmx.CommitStatus;
16 import org.opendaylight.controller.config.util.ConfigRegistryClient;
17 import org.opendaylight.controller.config.util.ConfigTransactionClient;
18 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
19 import org.opendaylight.controller.netconf.confignetconfconnector.exception.NoTransactionFoundException;
20 import org.slf4j.Logger;
21 import org.slf4j.LoggerFactory;
23 import javax.management.InstanceNotFoundException;
24 import javax.management.ObjectName;
25 import java.util.ArrayList;
26 import java.util.List;
29 public class TransactionProvider implements AutoCloseable {
30 private static final Logger logger = LoggerFactory.getLogger(TransactionProvider.class);
32 private final ConfigRegistryClient configRegistryClient;
34 private final String netconfSessionIdForReporting;
35 private ObjectName transaction;
36 private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
37 private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
39 public TransactionProvider(ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
40 this.configRegistryClient = configRegistryClient;
41 this.netconfSessionIdForReporting = netconfSessionIdForReporting;
45 public synchronized void close() {
46 for (ObjectName tx : allOpenedTransactions) {
48 if (isStillOpenTransaction(tx)) {
49 configRegistryClient.getConfigTransactionClient(tx).abortConfig();
51 } catch (Exception e) {
52 logger.debug("Ignoring exception while closing transaction {}", tx, e);
55 allOpenedTransactions.clear();
58 public Optional<ObjectName> getTransaction() {
60 if (transaction == null){
61 return Optional.absent();
64 // Transaction was already closed somehow
65 if (!isStillOpenTransaction(transaction)) {
66 logger.warn("Fixing illegal state: transaction {} was closed in {}", transaction,
67 netconfSessionIdForReporting);
69 return Optional.absent();
71 return Optional.of(transaction);
74 private boolean isStillOpenTransaction(ObjectName transaction) {
75 return configRegistryClient.getOpenConfigs().contains(transaction);
78 public synchronized ObjectName getOrCreateTransaction() {
79 Optional<ObjectName> ta = getTransaction();
83 transaction = configRegistryClient.beginConfig();
84 allOpenedTransactions.add(transaction);
89 * Used for editConfig test option
91 public synchronized ObjectName getTestTransaction() {
92 ObjectName testTx = configRegistryClient.beginConfig();
93 allOpenedTransactions.add(testTx);
98 * Commit and notification send must be atomic
100 public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException, NoTransactionFoundException {
101 if (!getTransaction().isPresent()){
102 throw new NoTransactionFoundException("No transaction found for session " + netconfSessionIdForReporting,
103 NetconfDocumentedException.ErrorType.application,
104 NetconfDocumentedException.ErrorTag.operation_failed,
105 NetconfDocumentedException.ErrorSeverity.error);
107 final Optional<ObjectName> maybeTaON = getTransaction();
108 ObjectName taON = maybeTaON.get();
110 CommitStatus status = configRegistryClient.commitConfig(taON);
112 allOpenedTransactions.remove(transaction);
115 } catch (ValidationException validationException) {
116 // no clean up: user can reconfigure and recover this transaction
117 logger.warn("Transaction {} failed on {}", taON, validationException.toString());
118 throw validationException;
119 } catch (ConflictingVersionException e) {
120 logger.error("Exception while commit of {}, aborting transaction", taON, e);
127 public synchronized void abortTransaction() {
128 logger.debug("Aborting current transaction");
129 Optional<ObjectName> taON = getTransaction();
130 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
132 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
133 transactionClient.abortConfig();
134 allOpenedTransactions.remove(transaction);
138 public synchronized void abortTestTransaction(ObjectName testTx) {
139 logger.debug("Aborting transaction {}", testTx);
140 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(testTx);
141 allOpenedTransactions.remove(testTx);
142 transactionClient.abortConfig();
145 public void validateTransaction() throws ValidationException {
146 Optional<ObjectName> taON = getTransaction();
147 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
149 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
150 transactionClient.validateConfig();
153 public void validateTestTransaction(ObjectName taON) throws ValidationException {
154 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
155 transactionClient.validateConfig();
158 public void wipeTestTransaction(ObjectName taON) {
159 wipeInternal(taON, true, null);
163 * Wiping means removing all module instances keeping the transaction open + service references.
165 synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
166 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
168 Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
169 : transactionClient.lookupConfigBeans(moduleName);
170 int i = lookupConfigBeans.size();
171 for (ObjectName instance : lookupConfigBeans) {
173 transactionClient.destroyModule(instance);
174 } catch (InstanceNotFoundException e) {
176 logger.debug("Unable to clean configuration in transactiom {}", taON, e);
178 logger.warn("Unable to clean configuration in transactiom {}", taON, e);
181 throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
184 logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
186 transactionClient.removeAllServiceReferences();
187 logger.debug("Transaction {} wiped clean of all service references", taON);
190 public void wipeTransaction() {
191 Optional<ObjectName> taON = getTransaction();
192 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
193 wipeInternal(taON.get(), false, null);