import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
+import org.opendaylight.controller.config.api.ConflictingVersionException;
import org.opendaylight.controller.config.api.ValidationException;
import org.opendaylight.controller.config.api.jmx.CommitStatus;
import org.opendaylight.controller.config.util.ConfigRegistryClient;
import org.opendaylight.controller.config.util.ConfigTransactionClient;
import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
+import org.opendaylight.controller.netconf.confignetconfconnector.exception.NoTransactionFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private final String netconfSessionIdForReporting;
private ObjectName transaction;
private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
+ private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
public TransactionProvider(ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
this.configRegistryClient = configRegistryClient;
@Override
public synchronized void close() {
for (ObjectName tx : allOpenedTransactions) {
- if (isStillOpenTransaction(tx)) {
- try {
+ try {
+ if (isStillOpenTransaction(tx)) {
configRegistryClient.getConfigTransactionClient(tx).abortConfig();
- } catch (Exception e) {
- logger.debug("Ignoring {} while closing transaction {}", e.toString(), tx, e);
}
+ } catch (Exception e) {
+ logger.debug("Ignoring exception while closing transaction {}", tx, e);
}
}
allOpenedTransactions.clear();
public Optional<ObjectName> getTransaction() {
- if (transaction == null)
+ if (transaction == null){
return Optional.absent();
+ }
// Transaction was already closed somehow
- if (isStillOpenTransaction(transaction) == false) {
+ if (!isStillOpenTransaction(transaction)) {
logger.warn("Fixing illegal state: transaction {} was closed in {}", transaction,
netconfSessionIdForReporting);
transaction = null;
}
private boolean isStillOpenTransaction(ObjectName transaction) {
- boolean isStillOpenTransaction = configRegistryClient.getOpenConfigs().contains(transaction);
- return isStillOpenTransaction;
+ return configRegistryClient.getOpenConfigs().contains(transaction);
}
public synchronized ObjectName getOrCreateTransaction() {
/**
* Commit and notification send must be atomic
*/
- public synchronized CommitStatus commitTransaction() throws NetconfDocumentedException {
- final Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
- CommitStatus status = configRegistryClient.commitConfig(taON.get());
- allOpenedTransactions.remove(transaction);
- transaction = null;
- return status;
+ public synchronized CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException, NoTransactionFoundException {
+ if (!getTransaction().isPresent()){
+ throw new NoTransactionFoundException("No transaction found for session " + netconfSessionIdForReporting,
+ NetconfDocumentedException.ErrorType.application,
+ NetconfDocumentedException.ErrorTag.operation_failed,
+ NetconfDocumentedException.ErrorSeverity.error);
+ }
+ final Optional<ObjectName> maybeTaON = getTransaction();
+ ObjectName taON = maybeTaON.get();
+ try {
+ CommitStatus status = configRegistryClient.commitConfig(taON);
+ // clean up
+ allOpenedTransactions.remove(transaction);
+ transaction = null;
+ return status;
+ } catch (ValidationException validationException) {
+ // no clean up: user can reconfigure and recover this transaction
+ logger.warn("Transaction {} failed on {}", taON, validationException.toString());
+ throw validationException;
+ } catch (ConflictingVersionException e) {
+ logger.error("Exception while commit of {}, aborting transaction", taON, e);
+ // clean up
+ abortTransaction();
+ throw e;
+ }
}
public synchronized void abortTransaction() {
+ logger.debug("Aborting current transaction");
Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
+ Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
transactionClient.abortConfig();
}
public synchronized void abortTestTransaction(ObjectName testTx) {
+ logger.debug("Aborting transaction {}", testTx);
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(testTx);
allOpenedTransactions.remove(testTx);
transactionClient.abortConfig();
public void validateTransaction() throws ValidationException {
Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
+ Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
transactionClient.validateConfig();
}
- public void validateTestTransaction(ObjectName taON) {
+ public void validateTestTransaction(ObjectName taON) throws ValidationException {
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
transactionClient.validateConfig();
}
}
/**
- * Wiping means removing all module instances keeping the transaction open.
+ * Wiping means removing all module instances keeping the transaction open + service references.
*/
synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
: transactionClient.lookupConfigBeans(moduleName);
+ int i = lookupConfigBeans.size();
for (ObjectName instance : lookupConfigBeans) {
try {
transactionClient.destroyModule(instance);
} catch (InstanceNotFoundException e) {
- if (isTest)
+ if (isTest){
logger.debug("Unable to clean configuration in transactiom {}", taON, e);
- else
+ } else {
logger.warn("Unable to clean configuration in transactiom {}", taON, e);
+ }
throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
}
}
- logger.debug("Transaction {} wiped clean", taON);
+ logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
+
+ transactionClient.removeAllServiceReferences();
+ logger.debug("Transaction {} wiped clean of all service references", taON);
}
public void wipeTransaction() {
Optional<ObjectName> taON = getTransaction();
- Preconditions.checkState(taON.isPresent(), "No transaction found for session " + netconfSessionIdForReporting);
+ Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
wipeInternal(taON.get(), false, null);
}