Remove yang-test
[controller.git] / opendaylight / config / config-manager-facade-xml / src / main / java / org / opendaylight / controller / config / facade / xml / transactions / TransactionProvider.java
1 /*
2  * Copyright (c) 2015, 2017 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.config.facade.xml.transactions;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13
14 import java.util.ArrayList;
15 import java.util.Collections;
16 import java.util.List;
17 import java.util.Set;
18
19 import javax.management.InstanceNotFoundException;
20 import javax.management.ObjectName;
21
22 import org.opendaylight.controller.config.api.ConflictingVersionException;
23 import org.opendaylight.controller.config.api.ValidationException;
24 import org.opendaylight.controller.config.api.jmx.CommitStatus;
25 import org.opendaylight.controller.config.util.ConfigRegistryClient;
26 import org.opendaylight.controller.config.util.ConfigTransactionClient;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 public class TransactionProvider implements AutoCloseable {
31     private static final Logger LOG = LoggerFactory.getLogger(TransactionProvider.class);
32
33     private final ConfigRegistryClient configRegistryClient;
34
35     private final String sessionIdForReporting;
36     private ObjectName candidateTx;
37     private ObjectName readTx;
38     private final List<ObjectName> allOpenedTransactions = new ArrayList<>();
39     private static final String NO_TRANSACTION_FOUND_FOR_SESSION = "No transaction found for session ";
40
41     public TransactionProvider(final ConfigRegistryClient configRegistryClient, final String sessionIdForReporting) {
42         this.configRegistryClient = configRegistryClient;
43         this.sessionIdForReporting = sessionIdForReporting;
44     }
45
46     @Override
47     @SuppressWarnings("IllegalCatch")
48     public synchronized void close() {
49         for (ObjectName tx : allOpenedTransactions) {
50             try {
51                 if (isStillOpenTransaction(tx)) {
52                     configRegistryClient.getConfigTransactionClient(tx).abortConfig();
53                 }
54             } catch (final RuntimeException e) {
55                 LOG.debug("Ignoring exception while closing transaction {}", tx, e);
56             }
57         }
58         allOpenedTransactions.clear();
59     }
60
61     public synchronized Optional<ObjectName> getTransaction() {
62
63         if (candidateTx == null) {
64             return Optional.absent();
65         }
66
67         // Transaction was already closed somehow
68         if (!isStillOpenTransaction(candidateTx)) {
69             LOG.warn("Fixing illegal state: transaction {} was closed in {}", candidateTx, sessionIdForReporting);
70             candidateTx = null;
71             return Optional.absent();
72         }
73         return Optional.of(candidateTx);
74     }
75
76     public synchronized Optional<ObjectName> getReadTransaction() {
77
78         if (readTx == null) {
79             return Optional.absent();
80         }
81
82         // Transaction was already closed somehow
83         if (!isStillOpenTransaction(readTx)) {
84             LOG.warn("Fixing illegal state: transaction {} was closed in {}", readTx, sessionIdForReporting);
85             readTx = null;
86             return Optional.absent();
87         }
88         return Optional.of(readTx);
89     }
90
91     private boolean isStillOpenTransaction(final ObjectName transaction) {
92         return configRegistryClient.getOpenConfigs().contains(transaction);
93     }
94
95     public synchronized ObjectName getOrCreateTransaction() {
96         Optional<ObjectName> ta = getTransaction();
97
98         if (ta.isPresent()) {
99             return ta.get();
100         }
101         candidateTx = configRegistryClient.beginConfig();
102         allOpenedTransactions.add(candidateTx);
103         return candidateTx;
104     }
105
106     public synchronized ObjectName getOrCreateReadTransaction() {
107         Optional<ObjectName> ta = getReadTransaction();
108
109         if (ta.isPresent()) {
110             return ta.get();
111         }
112         readTx = configRegistryClient.beginConfig();
113         allOpenedTransactions.add(readTx);
114         return readTx;
115     }
116
117     /**
118      * Used for editConfig test option.
119      */
120     public synchronized ObjectName getTestTransaction() {
121         ObjectName testTx = configRegistryClient.beginConfig();
122         allOpenedTransactions.add(testTx);
123         return testTx;
124     }
125
126     /**
127      * Commit and notification send must be atomic.
128      */
129     public CommitStatus commitTransaction() throws ValidationException, ConflictingVersionException {
130         return commitTransaction(configRegistryClient);
131     }
132
133     /**
134      * Commit and notification send must be atomic.
135      */
136     public synchronized CommitStatus commitTransaction(final ConfigRegistryClient client)
137             throws ValidationException, ConflictingVersionException {
138         if (!getTransaction().isPresent()) {
139             // making empty commit without prior opened transaction, just return commit
140             // status with empty lists
141             LOG.debug("Making commit without open candidate transaction for session {}", sessionIdForReporting);
142             return new CommitStatus(Collections.emptyList(), Collections.emptyList(), Collections.emptyList());
143         }
144         final Optional<ObjectName> maybeTaON = getTransaction();
145         ObjectName taON = maybeTaON.get();
146         try {
147             CommitStatus status = client.commitConfig(taON);
148             // clean up
149             allOpenedTransactions.remove(candidateTx);
150             candidateTx = null;
151             return status;
152         } catch (final ValidationException validationException) {
153             // no clean up: user can reconfigure and recover this transaction
154             LOG.warn("Transaction {} failed on {}", taON, validationException.toString());
155             throw validationException;
156         } catch (final ConflictingVersionException e) {
157             LOG.debug("Exception while commit of {}, aborting transaction", taON, e);
158             // clean up
159             abortTransaction();
160             throw e;
161         }
162     }
163
164     public synchronized void abortTransaction() {
165         LOG.debug("Aborting current transaction");
166         Optional<ObjectName> taON = getTransaction();
167         Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + sessionIdForReporting);
168
169         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
170         transactionClient.abortConfig();
171         allOpenedTransactions.remove(candidateTx);
172         candidateTx = null;
173     }
174
175     public synchronized void closeReadTransaction() {
176         LOG.debug("Closing read transaction");
177         Optional<ObjectName> taON = getReadTransaction();
178         Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + sessionIdForReporting);
179
180         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
181         transactionClient.abortConfig();
182         allOpenedTransactions.remove(readTx);
183         readTx = null;
184     }
185
186     public synchronized void abortTestTransaction(final ObjectName testTx) {
187         LOG.debug("Aborting transaction {}", testTx);
188         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(testTx);
189         allOpenedTransactions.remove(testTx);
190         transactionClient.abortConfig();
191     }
192
193     public void validateTransaction() throws ValidationException {
194         Optional<ObjectName> taON = getTransaction();
195         Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + sessionIdForReporting);
196
197         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON.get());
198         transactionClient.validateConfig();
199     }
200
201     public void validateTestTransaction(final ObjectName taON) throws ValidationException {
202         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
203         transactionClient.validateConfig();
204     }
205
206     public void wipeTestTransaction(final ObjectName taON) {
207         wipeInternal(taON, true);
208     }
209
210     /**
211      * Wiping means removing all module instances keeping the transaction open +
212      * service references.
213      */
214     synchronized void wipeInternal(final ObjectName taON, final boolean isTest) {
215         ConfigTransactionClient transactionClient = configRegistryClient.getConfigTransactionClient(taON);
216
217         Set<ObjectName> lookupConfigBeans = transactionClient.lookupConfigBeans();
218         int index = lookupConfigBeans.size();
219         for (ObjectName instance : lookupConfigBeans) {
220             try {
221                 transactionClient.destroyModule(instance);
222             } catch (final InstanceNotFoundException e) {
223                 if (isTest) {
224                     LOG.debug("Unable to clean configuration in transactiom {}", taON, e);
225                 } else {
226                     LOG.warn("Unable to clean configuration in transactiom {}", taON, e);
227                 }
228
229                 throw new IllegalStateException("Unable to clean configuration in transactiom " + taON, e);
230             }
231         }
232         LOG.debug("Transaction {} wiped clean of {} config beans", taON, index);
233
234         transactionClient.removeAllServiceReferences();
235         LOG.debug("Transaction {} wiped clean of all service references", taON);
236     }
237
238     public void wipeTransaction() {
239         Optional<ObjectName> taON = getTransaction();
240         Preconditions.checkState(taON.isPresent(), NO_TRANSACTION_FOUND_FOR_SESSION + sessionIdForReporting);
241         wipeInternal(taON.get(), false);
242     }
243 }