2 * Copyright (c) 2016 Red Hat, Inc. and others. All rights reserved.
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
8 package org.opendaylight.genius.datastoreutils;
10 import static java.util.Objects.requireNonNull;
11 import static org.opendaylight.genius.datastoreutils.TransactionCommitFailedExceptionMapper.SUBMIT_MAPPER;
13 import com.google.common.base.Optional;
14 import java.util.concurrent.ExecutionException;
15 import org.eclipse.jdt.annotation.NonNull;
16 import org.opendaylight.controller.md.sal.binding.api.DataBroker;
17 import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction;
18 import org.opendaylight.controller.md.sal.binding.api.ReadTransaction;
19 import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType;
20 import org.opendaylight.controller.md.sal.common.api.data.ReadFailedException;
21 import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
22 import org.opendaylight.genius.infra.ManagedNewTransactionRunner;
23 import org.opendaylight.genius.infra.RetryingManagedNewTransactionRunner;
24 import org.opendaylight.infrautils.utils.concurrent.ListenableFutures;
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;
31 * Utility methods for single transaction DataBroker usage.
33 * <p>Please consider using a {@link ManagedNewTransactionRunner} instead.
35 * @author Michael Vorburger
37 // do *NOT* make this a BP @Singleton; see https://wiki.opendaylight.org/view/BestPractices/DI_Guidelines#Nota_Bene for why
38 public class SingleTransactionDataBroker {
40 private static final Logger LOG = LoggerFactory.getLogger(SingleTransactionDataBroker.class);
42 private static final int DEFAULT_RETRIES = 3; // duplicated in RetryingManagedNewTransactionRunnerImpl
44 private final DataBroker broker;
46 // do *NOT* use BP @Inject here, see comment above
47 public SingleTransactionDataBroker(@NonNull DataBroker broker) {
48 this.broker = requireNonNull(broker, "dataBroker");
52 * Synchronously read; preferred & strongly recommended method variant
53 * over other ones offered by this class (because this is the most explicit
56 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
58 * @param datastoreType
59 * Logical data store from which read should occur.
61 * Path which uniquely identifies subtree which client want to read
65 * @return If the data at the supplied path exists, returns an Optional
66 * object containing the data; if the data at the supplied path does
67 * not exist, returns Optional#absent().
68 * @throws ReadFailedException in case of a technical (!) error while reading
70 public <T extends DataObject> Optional<T> syncReadOptional(
71 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
72 throws ReadFailedException {
73 return syncReadOptional(broker, datastoreType, path);
76 public static <T extends DataObject> Optional<T> syncReadOptional(
77 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
78 throws ReadFailedException {
80 try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
81 return tx.read(datastoreType, path).checkedGet();
86 * Synchronously read; method variant to use by code which expecting that data MUST exist at given path.
88 * <p>This variant is only recommended if the calling code would treat the Optional
89 * returned by the other method variant as a terminal failure anyway, and would itself throw
90 * an Exception for that.
92 * <p>If calling code can more sensibly handle non-present data, then use
93 * {@link #syncReadOptional(LogicalDatastoreType, InstanceIdentifier)} instead of this.
95 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
97 * @param datastoreType
98 * Logical data store from which read should occur.
100 * Path which uniquely identifies subtree which client want to read
102 * DataObject subclass
104 * @return If the data at the supplied path exists, returns the data.
105 * @throws ReadFailedException in case of a technical (!) error while reading
106 * @throws ExpectedDataObjectNotFoundException a ReadFailedException sub-type, if no data exists at path
108 public <T extends DataObject> T syncRead(
109 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
110 throws ReadFailedException {
111 return syncRead(broker, datastoreType, path);
114 public static <T extends DataObject> T syncRead(
115 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
116 throws ReadFailedException {
118 try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
119 Optional<T> optionalDataObject = tx.read(datastoreType, path).checkedGet();
120 if (optionalDataObject.isPresent()) {
121 return optionalDataObject.get();
123 throw new ExpectedDataObjectNotFoundException(datastoreType, path);
129 * Synchronously read; swallowing (!) ReadFailedException.
131 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
133 * @deprecated This variant is not recommended, and only exists for legacy
134 * purposes for code which does not yet correctly propagate
135 * technical exceptions. Prefer using
136 * {@link #syncReadOptional(LogicalDatastoreType, InstanceIdentifier)}.
138 * @param datastoreType
139 * Logical data store from which read should occur.
141 * Path which uniquely identifies subtree which client want to read
143 * DataObject subclass
145 * @return If the data at the supplied path exists, returns an Optional
146 * object containing the data; if the data at the supplied path does
147 * not exist, or a technical error occurred (logged), returns
151 public <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
152 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
153 return syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, datastoreType, path);
157 * Synchronously read; swallowing (!) ReadFailedException.
159 * @deprecated This variant is not recommended, and only exists for legacy
160 * purposes for code which does not yet correctly propagate
161 * technical exceptions. Prefer using
162 * {@link #syncReadOptional(DataBroker, LogicalDatastoreType, InstanceIdentifier)}.
165 public static <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
166 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
168 try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
169 return tx.read(datastoreType, path).checkedGet();
170 } catch (ReadFailedException e) {
171 LOG.error("ReadFailedException while reading data from {} store path {}; returning Optional.absent()",
172 datastoreType, path, e);
173 return Optional.absent();
177 public <T extends DataObject> void syncWrite(
178 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
179 throws TransactionCommitFailedException {
180 syncWrite(broker, datastoreType, path, data);
183 public <T extends DataObject> void syncWrite(
184 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
185 throws TransactionCommitFailedException {
186 syncWrite(broker, datastoreType, path, data, maxRetries);
189 public static <T extends DataObject> void syncWrite(
190 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
191 throws TransactionCommitFailedException {
192 syncWrite(broker, datastoreType, path, data, DEFAULT_RETRIES);
195 public static <T extends DataObject> void syncWrite(
196 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
197 throws TransactionCommitFailedException {
199 RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
200 ListenableFutures.checkedGet(
201 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.put(datastoreType, path, data, true)),
205 public <T extends DataObject> void syncUpdate(
206 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
207 throws TransactionCommitFailedException {
208 syncUpdate(broker, datastoreType, path, data);
211 public <T extends DataObject> void syncUpdate(
212 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
213 throws TransactionCommitFailedException {
214 syncUpdate(broker, datastoreType, path, data, maxRetries);
217 public static <T extends DataObject> void syncUpdate(
218 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
219 throws TransactionCommitFailedException {
220 syncUpdate(broker, datastoreType, path, data, DEFAULT_RETRIES);
223 public static <T extends DataObject> void syncUpdate(
224 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
225 throws TransactionCommitFailedException {
226 RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
227 ListenableFutures.checkedGet(
228 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.merge(datastoreType, path, data, true)),
232 public <T extends DataObject> void syncDelete(
233 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
234 throws TransactionCommitFailedException {
235 syncDelete(broker, datastoreType, path);
238 public <T extends DataObject> void syncDelete(
239 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
240 throws TransactionCommitFailedException {
241 syncDelete(broker, datastoreType, path, maxRetries);
244 public static <T extends DataObject> void syncDelete(
245 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
246 throws TransactionCommitFailedException {
247 syncDelete(broker, datastoreType, path, DEFAULT_RETRIES);
250 public static <T extends DataObject> void syncDelete(
251 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
252 throws TransactionCommitFailedException {
254 RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
255 ListenableFutures.checkedGet(
256 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(datastoreType, path)), SUBMIT_MAPPER);
259 public static <T extends DataObject> Boolean doesExists(
260 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
261 throws ReadFailedException {
262 try (ReadOnlyTransaction tx = broker.newReadOnlyTransaction()) {
263 return tx.exists(datastoreType, path).get();
264 } catch (InterruptedException | ExecutionException e) {
265 throw new ReadFailedException(e.getMessage(), e);