f19a3f85ed7ee5bd45adc31b563bfee085be01f7
[genius.git] / mdsalutil / mdsalutil-api / src / main / java / org / opendaylight / genius / datastoreutils / SingleTransactionDataBroker.java
1 /*
2  * Copyright (c) 2016 Red Hat, 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 package org.opendaylight.genius.datastoreutils;
9
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.genius.datastoreutils.TransactionCommitFailedExceptionMapper.SUBMIT_MAPPER;
12
13 import com.google.common.base.Optional;
14 import org.eclipse.jdt.annotation.NonNull;
15 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
16 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
17 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
18 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
19 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
20 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
21 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
22 import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
23 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
24 import org.opendaylight.yangtools.yang.binding.DataObject;
25 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 /**
30  * Utility methods for single transaction DataBroker usage.
31  *
32  * <p>Please consider using a {@link ManagedNewTransactionRunner} instead.
33  *
34  * @author Michael Vorburger
35  */
36 // do *NOT* make this a BP @Singleton; see https://wiki.opendaylight.org/view/BestPractices/DI_Guidelines#Nota_Bene for why
37 public class SingleTransactionDataBroker {
38
39     private static final Logger LOG = LoggerFactory.getLogger(SingleTransactionDataBroker.class);
40
41     private static final int DEFAULT_RETRIES = 3; // duplicated in RetryingManagedNewTransactionRunnerImpl
42
43     private final DataBroker broker;
44
45     // do *NOT* use BP @Inject here, see comment above
46     public SingleTransactionDataBroker(@NonNull DataBroker broker) {
47         this.broker = requireNonNull(broker, "dataBroker");
48     }
49
50     /**
51      * Synchronously read; preferred &amp; strongly recommended method variant
52      * over other ones offered by this class (because this is the most explicit
53      * variant).
54      *
55      * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
56      *
57      * @param datastoreType
58      *            Logical data store from which read should occur.
59      * @param path
60      *            Path which uniquely identifies subtree which client want to read
61      * @param <T>
62      *            DataObject subclass
63      *
64      * @return If the data at the supplied path exists, returns an Optional
65      *         object containing the data; if the data at the supplied path does
66      *         not exist, returns Optional#absent().
67      * @throws ReadFailedException in case of a technical (!) error while reading
68      */
69     public <T extends DataObject> Optional<T> syncReadOptional(
70             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
71             throws ReadFailedException {
72         return syncReadOptional(broker, datastoreType, path);
73     }
74
75     public static <T extends DataObject> Optional<T> syncReadOptional(
76             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
77             throws ReadFailedException {
78
79         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
80             return tx.read(datastoreType, path).checkedGet();
81         }
82     }
83
84     /**
85      * Synchronously read; method variant to use by code which expecting that data MUST exist at given path.
86      *
87      * <p>This variant is only recommended if the calling code would treat the Optional
88      * returned by the other method variant as a terminal failure anyway, and would itself throw
89      * an Exception for that.
90      *
91      * <p>If calling code can more sensibly handle non-present data, then use
92      * {@link #syncReadOptional(LogicalDatastoreType, InstanceIdentifier)} instead of this.
93      *
94      * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
95      *
96      * @param datastoreType
97      *            Logical data store from which read should occur.
98      * @param path
99      *            Path which uniquely identifies subtree which client want to read
100      * @param <T>
101      *            DataObject subclass
102      *
103      * @return If the data at the supplied path exists, returns the data.
104      * @throws ReadFailedException in case of a technical (!) error while reading
105      * @throws ExpectedDataObjectNotFoundException a ReadFailedException sub-type, if no data exists at path
106      */
107     public <T extends DataObject> T syncRead(
108             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
109             throws ReadFailedException {
110         return syncRead(broker, datastoreType, path);
111     }
112
113     public static <T extends DataObject> T syncRead(
114             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
115             throws ReadFailedException {
116
117         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
118             Optional<T> optionalDataObject = tx.read(datastoreType, path).checkedGet();
119             if (optionalDataObject.isPresent()) {
120                 return optionalDataObject.get();
121             } else {
122                 throw new ExpectedDataObjectNotFoundException(datastoreType, path);
123             }
124         }
125     }
126
127     /**
128      * Synchronously read; swallowing (!) ReadFailedException.
129      *
130      * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
131      *
132      * @deprecated This variant is not recommended, and only exists for legacy
133      *             purposes for code which does not yet correctly propagate
134      *             technical exceptions. Prefer using
135      *             {@link #syncReadOptional(LogicalDatastoreType, InstanceIdentifier)}.
136      *
137      * @param datastoreType
138      *            Logical data store from which read should occur.
139      * @param path
140      *            Path which uniquely identifies subtree which client want to read
141      * @param <T>
142      *            DataObject subclass
143      *
144      * @return If the data at the supplied path exists, returns an Optional
145      *         object containing the data; if the data at the supplied path does
146      *         not exist, or a technical error occurred (logged), returns
147      *         Optional#absent().
148      */
149     @Deprecated
150     public <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
151             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
152         return syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, datastoreType, path);
153     }
154
155     /**
156      * Synchronously read; swallowing (!) ReadFailedException.
157      *
158      * @deprecated This variant is not recommended, and only exists for legacy
159      *             purposes for code which does not yet correctly propagate
160      *             technical exceptions. Prefer using
161      *             {@link #syncReadOptional(DataBroker, LogicalDatastoreType, InstanceIdentifier)}.
162      */
163     @Deprecated
164     public static <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
165             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
166
167         try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
168             return tx.read(datastoreType, path).checkedGet();
169         } catch (ReadFailedException e) {
170             LOG.error("ReadFailedException while reading data from {} store path {}; returning Optional.absent()",
171                     datastoreType, path, e);
172             return Optional.absent();
173         }
174     }
175
176     public <T extends DataObject> void syncWrite(
177             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
178             throws TransactionCommitFailedException {
179         syncWrite(broker, datastoreType, path, data);
180     }
181
182     public <T extends DataObject> void syncWrite(
183             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
184             throws TransactionCommitFailedException {
185         syncWrite(broker, datastoreType, path, data, maxRetries);
186     }
187
188     public static <T extends DataObject> void syncWrite(
189             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
190             throws TransactionCommitFailedException {
191         syncWrite(broker, datastoreType, path, data, DEFAULT_RETRIES);
192     }
193
194     public static <T extends DataObject> void syncWrite(
195             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
196             throws TransactionCommitFailedException {
197
198         RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
199         ListenableFutures.checkedGet(
200                 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.put(datastoreType, path, data, true)),
201                 SUBMIT_MAPPER);
202     }
203
204     public <T extends DataObject> void syncUpdate(
205             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
206             throws TransactionCommitFailedException {
207         syncUpdate(broker, datastoreType, path, data);
208     }
209
210     public <T extends DataObject> void syncUpdate(
211             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
212             throws TransactionCommitFailedException {
213         syncUpdate(broker, datastoreType, path, data, maxRetries);
214     }
215
216     public static <T extends DataObject> void syncUpdate(
217             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
218             throws TransactionCommitFailedException {
219         syncUpdate(broker, datastoreType, path, data, DEFAULT_RETRIES);
220     }
221
222     public static <T extends DataObject> void syncUpdate(
223             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
224             throws TransactionCommitFailedException {
225         RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
226         ListenableFutures.checkedGet(
227                 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.merge(datastoreType, path, data, true)),
228                 SUBMIT_MAPPER);
229     }
230
231     public <T extends DataObject> void syncDelete(
232             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
233             throws TransactionCommitFailedException {
234         syncDelete(broker, datastoreType, path);
235     }
236
237     public <T extends DataObject> void syncDelete(
238             LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
239             throws TransactionCommitFailedException {
240         syncDelete(broker, datastoreType, path, maxRetries);
241     }
242
243     public static <T extends DataObject> void syncDelete(
244             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
245             throws TransactionCommitFailedException {
246         syncDelete(broker, datastoreType, path, DEFAULT_RETRIES);
247     }
248
249     public static <T extends DataObject> void syncDelete(
250             DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
251             throws TransactionCommitFailedException {
252
253         RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
254         ListenableFutures.checkedGet(
255                 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(datastoreType, path)), SUBMIT_MAPPER);
256     }
257
258 }