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