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 java.util.ArrayList;
14 import java.util.List;
16 import javax.management.InstanceNotFoundException;
17 import javax.management.ObjectName;
18 import org.opendaylight.controller.config.api.ConflictingVersionException;
19 import org.opendaylight.controller.config.api.ValidationException;
20 import org.opendaylight.controller.config.api.jmx.CommitStatus;
21 import org.opendaylight.controller.config.util.ConfigRegistryClient;
22 import org.opendaylight.controller.config.util.ConfigTransactionClient;
23 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
24 import org.opendaylight.controller.netconf.confignetconfconnector.exception.NoTransactionFoundException;
25 import org.slf4j.Logger;
26 import org.slf4j.LoggerFactory;
28 public class TransactionProvider implements AutoCloseable {
29 private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
31 private final ConfigRegistryClient configRegistryClient;
33 private final String netconfSessionIdForReporting;
34 private ObjectName transaction;
35 private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
36 private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
38 public TransactionProvider(ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
39 this.configRegistryClient = configRegistryClient;
40 this.netconfSessionIdForReporting = netconfSessionIdForReporting;
44 public synchronized void close() {
45 for (ObjectName tx : allOpenedTransactions) {
47 if (isStillOpenTransaction(tx)) {
48 configRegistryClient.getConfigTransactionClient(tx).abortConfig();
50 } catch (Exception e) {
51 LOG.debug("Ignoring exception while closing transaction {}", tx, e);
54 allOpenedTransactions.clear();
57 public synchronized Optional<ObjectName> getTransaction() {
59 if (transaction == null){
60 return Optional.absent();
63 // Transaction was already closed somehow
64 if (!isStillOpenTransaction(transaction)) {
65 LOG.warn("Fixing illegal state: transaction {} was closed in {}", transaction,
66 netconfSessionIdForReporting);
68 return Optional.absent();
70 return Optional.of(transaction);
73 private boolean isStillOpenTransaction(ObjectName transaction) {
74 return configRegistryClient.getOpenConfigs().contains(transaction);
77 public synchronized ObjectName getOrCreateTransaction() {
78 Optional<ObjectName> ta = getTransaction();
82 transaction = configRegistryClient.beginConfig();
83 allOpenedTransactions.add(transaction);
88 * Used for editConfig test option
90 public synchronized ObjectName getTestTransaction() {
91 ObjectName testTx = configRegistryClient.beginConfig();
92 allOpenedTransactions.add(testTx);
97 * Commit and notification send must be atomic
99 public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException, NoTransactionFoundException {
100 if (!getTransaction().isPresent()){
101 throw new NoTransactionFoundException("No transaction found for session " + netconfSessionIdForReporting,
102 NetconfDocumentedException.ErrorType.application,
103 NetconfDocumentedException.ErrorTag.operation_failed,
104 NetconfDocumentedException.ErrorSeverity.error);
106 final Optional<ObjectName> maybeTaON = getTransaction();
107 ObjectName taON = maybeTaON.get();
109 CommitStatus status = configRegistryClient.commitConfig(taON);
111 allOpenedTransactions.remove(transaction);
114 } catch (ValidationException validationException) {
115 // no clean up: user can reconfigure and recover this transaction
116 LOG.warn("Transaction {} failed on {}", taON, validationException.toString());
117 throw validationException;
118 } catch (ConflictingVersionException e) {
119 LOG.error("Exception while commit of {}, aborting transaction", taON, e);
126 public synchronized void abortTransaction() {
127 LOG.debug("Aborting current transaction");
128 Optional<ObjectName> taON = getTransaction();
129 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
131 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
132 transactionClient.abortConfig();
133 allOpenedTransactions.remove(transaction);
137 public synchronized void abortTestTransaction(ObjectName testTx) {
138 LOG.debug("Aborting transaction {}", testTx);
139 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(testTx);
140 allOpenedTransactions.remove(testTx);
141 transactionClient.abortConfig();
144 public void validateTransaction() throws ValidationException {
145 Optional<ObjectName> taON = getTransaction();
146 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
148 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
149 transactionClient.validateConfig();
152 public void validateTestTransaction(ObjectName taON) throws ValidationException {
153 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
154 transactionClient.validateConfig();
157 public void wipeTestTransaction(ObjectName taON) {
158 wipeInternal(taON, true);
162 * Wiping means removing all module instances keeping the transaction open + service references.
164 synchronized void wipeInternal(ObjectName taON, boolean isTest) {
165 ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
167 Set<ObjectName> lookupConfigBeans = transactionClient.lookupConfigBeans();
168 int i = lookupConfigBeans.size();
169 for (ObjectName instance : lookupConfigBeans) {
171 transactionClient.destroyModule(instance);
172 } catch (InstanceNotFoundException e) {
174 LOG.debug("Unable to clean configuration in transactiom {}", taON, e);
176 LOG.warn("Unable to clean configuration in transactiom {}", taON, e);
179 throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
182 LOG.debug("Transaction {} wiped clean of {} config beans", taON, i);
184 transactionClient.removeAllServiceReferences();
185 LOG.debug("Transaction {} wiped clean of all service references", taON);
188 public void wipeTransaction() {
189 Optional<ObjectName> taON = getTransaction();
190 Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
191 wipeInternal(taON.get(), false);