Merge "Fixed typo in test name. Temporary ignore test."
[controller.git] / opendaylight / netconf / config-netconf-connector / src / main / java / org / opendaylight / controller / netconf / confignetconfconnector / transactions / TransactionProvider.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.controller.netconf.confignetconfconnector.transactions;
10
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;
22
23 import javax.management.InstanceNotFoundException;
24 import javax.management.ObjectName;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Set;
28
29 public class TransactionProvider implements AutoCloseable {
30     private static final Logger logger = LoggerFactory.getLogger(TransactionProvider.class);
31
32     private final ConfigRegistryClient configRegistryClient;
33
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 ";
38
39     public TransactionProvider(ConfigRegistryClient configRegistryClient, String netconfSessionIdForReporting) {
40         this.configRegistryClient = configRegistryClient;
41         this.netconfSessionIdForReporting = netconfSessionIdForReporting;
42     }
43
44     @Override
45     public synchronized void close() {
46         for (ObjectName tx : allOpenedTransactions) {
47             try {
48                 if (isStillOpenTransaction(tx)) {
49                     configRegistryClient.getConfigTransactionClient(tx).abortConfig();
50                 }
51             } catch (Exception e) {
52                 logger.debug("Ignoring exception while closing transaction {}", tx, e);
53             }
54         }
55         allOpenedTransactions.clear();
56     }
57
58     public Optional<ObjectName> getTransaction() {
59
60         if (transaction == null){
61             return Optional.absent();
62         }
63
64         // Transaction was already closed somehow
65         if (!isStillOpenTransaction(transaction)) {
66             logger.warn("Fixing illegal state: transaction {} was closed in {}", transaction,
67                     netconfSessionIdForReporting);
68             transaction = null;
69             return Optional.absent();
70         }
71         return Optional.of(transaction);
72     }
73
74     private boolean isStillOpenTransaction(ObjectName transaction) {
75         return configRegistryClient.getOpenConfigs().contains(transaction);
76     }
77
78     public synchronized ObjectName getOrCreateTransaction() {
79         Optional<ObjectName> ta = getTransaction();
80
81         if (ta.isPresent())
82             return ta.get();
83         transaction = configRegistryClient.beginConfig();
84         allOpenedTransactions.add(transaction);
85         return transaction;
86     }
87
88     /**
89      * Used for editConfig test option
90      */
91     public synchronized ObjectName getTestTransaction() {
92         ObjectName testTx = configRegistryClient.beginConfig();
93         allOpenedTransactions.add(testTx);
94         return testTx;
95     }
96
97     /**
98      * Commit and notification send must be atomic
99      */
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);
106         }
107         final Optional<ObjectName> maybeTaON = getTransaction();
108         ObjectName taON = maybeTaON.get();
109         try {
110             CommitStatus status = configRegistryClient.commitConfig(taON);
111             // clean up
112             allOpenedTransactions.remove(transaction);
113             transaction = null;
114             return status;
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);
121             // clean up
122             abortTransaction();
123             throw e;
124         }
125     }
126
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);
131
132         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
133         transactionClient.abortConfig();
134         allOpenedTransactions.remove(transaction);
135         transaction = null;
136     }
137
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();
143     }
144
145     public void validateTransaction() throws ValidationException {
146         Optional<ObjectName> taON = getTransaction();
147         Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + netconfSessionIdForReporting);
148
149         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
150         transactionClient.validateConfig();
151     }
152
153     public void validateTestTransaction(ObjectName taON) throws ValidationException {
154         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
155         transactionClient.validateConfig();
156     }
157
158     public void wipeTestTransaction(ObjectName taON) {
159         wipeInternal(taON, true, null);
160     }
161
162     /**
163      * Wiping means removing all module instances keeping the transaction open + service references.
164      */
165     synchronized void wipeInternal(ObjectName taON, boolean isTest, String moduleName) {
166         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
167
168         Set<ObjectName> lookupConfigBeans = moduleName == null ? transactionClient.lookupConfigBeans()
169                 : transactionClient.lookupConfigBeans(moduleName);
170         int i = lookupConfigBeans.size();
171         for (ObjectName instance : lookupConfigBeans) {
172             try {
173                 transactionClient.destroyModule(instance);
174             } catch (InstanceNotFoundException e) {
175                 if (isTest){
176                     logger.debug("Unable to clean configuration in transactiom {}", taON, e);
177                 } else {
178                     logger.warn("Unable to clean configuration in transactiom {}", taON, e);
179                 }
180
181                 throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
182             }
183         }
184         logger.debug("Transaction {} wiped clean of {} config beans", taON, i);
185
186         transactionClient.removeAllServiceReferences();
187         logger.debug("Transaction {} wiped clean of all service references", taON);
188     }
189
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);
194     }
195
196 }