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 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;
32 * Utility methods for single transaction DataBroker usage.
34 * <p>Please consider using a {@link ManagedNewTransactionRunner} instead.
36 * @author Michael Vorburger
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 {
41 private static final Logger LOG = LoggerFactory.getLogger(SingleTransactionDataBroker.class);
43 private static final int DEFAULT_RETRIES = 3; // duplicated in RetryingManagedNewTransactionRunnerImpl
45 private final DataBroker broker;
47 // do *NOT* use BP @Inject here, see comment above
48 public SingleTransactionDataBroker(@NonNull DataBroker broker) {
49 this.broker = requireNonNull(broker, "dataBroker");
53 * Synchronously read; preferred & strongly recommended method variant
54 * over other ones offered by this class (because this is the most explicit
57 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
59 * @param datastoreType
60 * Logical data store from which read should occur.
62 * Path which uniquely identifies subtree which client want to read
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().
70 * @throws ExecutionException in case of a technical (!) error while reading
72 * @throws InterruptedException in case of a technical (!) error while reading
74 public <T extends DataObject> Optional<T> syncReadOptional(LogicalDatastoreType datastoreType,
75 InstanceIdentifier<T> path) throws ExecutionException, InterruptedException {
76 return syncReadOptional(broker, datastoreType, path);
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();
88 * Synchronously read; method variant to use by code which expecting that data MUST exist at given path.
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.
94 * <p>If calling code can more sensibly handle non-present data, then use
95 * {@link #syncReadOptional(LogicalDatastoreType, InstanceIdentifier)} instead of this.
97 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
99 * @param datastoreType
100 * Logical data store from which read should occur.
102 * Path which uniquely identifies subtree which client want to read
104 * DataObject subclass
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
110 public <T extends DataObject> T syncRead(
111 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
112 throws ReadFailedException {
113 return syncRead(broker, datastoreType, path);
116 public static <T extends DataObject> T syncRead(
117 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
118 throws ExpectedDataObjectNotFoundException {
120 try (ReadTransaction tx = broker.newReadOnlyTransaction()) {
121 Optional<T> optionalDataObject = tx.read(datastoreType, path).get();
122 if (optionalDataObject.isPresent()) {
123 return optionalDataObject.get();
125 throw new ExpectedDataObjectNotFoundException(datastoreType, path);
127 } catch (InterruptedException | ExecutionException e) {
128 LOG.error("failed", e);
134 * Synchronously read; swallowing (!) ReadFailedException.
136 * <p>See {@link ReadTransaction#read(LogicalDatastoreType, InstanceIdentifier)}.
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)}.
143 * @param datastoreType
144 * Logical data store from which read should occur.
146 * Path which uniquely identifies subtree which client want to read
148 * DataObject subclass
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
156 public <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
157 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
158 return syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(broker, datastoreType, path);
162 * Synchronously read; swallowing (!) ReadFailedException.
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)}.
170 * DataObject subclass
173 * @param datastoreType
174 * the {@link Datastore} type that will be accessed
176 * Path which uniquely identifies subtree which client want to read
177 * @return If the data at the supplied path exists, returns the data.
181 public static <T extends DataObject> Optional<T> syncReadOptionalAndTreatReadFailedExceptionAsAbsentOptional(
182 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path) {
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();
192 public <T extends DataObject> void syncWrite(
193 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
194 throws TransactionCommitFailedException {
195 syncWrite(broker, datastoreType, path, data);
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);
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);
210 public static <T extends DataObject> void syncWrite(
211 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data, int maxRetries)
212 throws TransactionCommitFailedException {
214 RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
215 ListenableFutures.checkedGet(runner.callWithNewWriteOnlyTransactionAndSubmit(tx ->
216 tx.mergeParentStructurePut(datastoreType,path,data)), SUBMIT_MAPPER);
219 public <T extends DataObject> void syncUpdate(
220 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, T data)
221 throws TransactionCommitFailedException {
222 syncUpdate(broker, datastoreType, path, data);
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);
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);
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);
245 public <T extends DataObject> void syncDelete(
246 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path)
247 throws TransactionCommitFailedException {
248 syncDelete(broker, datastoreType, path);
251 public <T extends DataObject> void syncDelete(
252 LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
253 throws TransactionCommitFailedException {
254 syncDelete(broker, datastoreType, path, maxRetries);
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);
263 public static <T extends DataObject> void syncDelete(
264 DataBroker broker, LogicalDatastoreType datastoreType, InstanceIdentifier<T> path, int maxRetries)
265 throws TransactionCommitFailedException {
267 RetryingManagedNewTransactionRunner runner = new RetryingManagedNewTransactionRunner(broker, maxRetries);
268 ListenableFutures.checkedGet(
269 runner.callWithNewWriteOnlyTransactionAndSubmit(tx -> tx.delete(datastoreType, path)), SUBMIT_MAPPER);