db610bd0eab5cffef84322f8d812c6f8ef439e9a
[mdsal.git] / binding / mdsal-binding-util / src / main / java / org / opendaylight / mdsal / binding / util / ManagedTransactionFactoryImpl.java
1 /*
2  * Copyright © 2018 Red Hat, Inc. and others.
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.mdsal.binding.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.util.concurrent.FluentFuture;
13 import com.google.common.util.concurrent.MoreExecutors;
14 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
15 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
16 import java.util.function.BiFunction;
17 import java.util.function.Supplier;
18 import org.opendaylight.mdsal.binding.api.ReadTransaction;
19 import org.opendaylight.mdsal.binding.api.TransactionFactory;
20 import org.opendaylight.mdsal.binding.api.WriteTransaction;
21 import org.opendaylight.yangtools.util.concurrent.FluentFutures;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24
25 /**
26  * Basic implementation of a {@link ManagedTransactionFactory}.
27  */
28 class ManagedTransactionFactoryImpl<T extends TransactionFactory> implements ManagedTransactionFactory {
29     private static final Logger LOG = LoggerFactory.getLogger(ManagedTransactionFactoryImpl.class);
30
31     private final T transactionFactory;
32
33     ManagedTransactionFactoryImpl(final T transactionFactory) {
34         this.transactionFactory = requireNonNull(transactionFactory, "transactionFactory must not be null");
35     }
36
37     @Override
38     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
39     public <D extends Datastore, E extends Exception, R> R applyInterruptiblyWithNewReadOnlyTransactionAndClose(
40             final Class<D> datastoreType, final InterruptibleCheckedFunction<TypedReadTransaction<D>, R, E> txFunction)
41             throws E, InterruptedException {
42         try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) {
43             TypedReadTransaction<D>
44                 wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx);
45             return txFunction.apply(wrappedTx);
46         }
47     }
48
49     @Override
50     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
51     public <D extends Datastore, E extends Exception, R> R applyWithNewReadOnlyTransactionAndClose(
52             final Class<D> datastoreType, final CheckedFunction<TypedReadTransaction<D>, R, E> txFunction) throws E {
53         try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) {
54             TypedReadTransaction<D>
55                 wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx);
56             return txFunction.apply(wrappedTx);
57         }
58     }
59
60     @Override
61     @CheckReturnValue
62     public <D extends Datastore, E extends Exception, R>
63         FluentFuture<R> applyWithNewReadWriteTransactionAndSubmit(final Class<D> datastoreType,
64             final InterruptibleCheckedFunction<TypedReadWriteTransaction<D>, R, E> txFunction) {
65         return applyWithNewTransactionAndSubmit(datastoreType, transactionFactory::newReadWriteTransaction,
66             TypedReadWriteTransactionImpl::new, txFunction, (realTx, wrappedTx) -> realTx.commit());
67     }
68
69     @Override
70     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
71     public <D extends Datastore, E extends Exception> void callInterruptiblyWithNewReadOnlyTransactionAndClose(
72             final Class<D> datastoreType, final InterruptibleCheckedConsumer<TypedReadTransaction<D>, E> txConsumer)
73             throws E, InterruptedException {
74         try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) {
75             TypedReadTransaction<D> wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx);
76             txConsumer.accept(wrappedTx);
77         }
78     }
79
80     @Override
81     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
82     public <D extends Datastore, E extends Exception> void callWithNewReadOnlyTransactionAndClose(
83             final Class<D> datastoreType, final CheckedConsumer<TypedReadTransaction<D>, E> txConsumer) throws E {
84         try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) {
85             TypedReadTransaction<D> wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx);
86             txConsumer.accept(wrappedTx);
87         }
88     }
89
90     @Override
91     @CheckReturnValue
92     public <D extends Datastore, E extends Exception>
93         FluentFuture<? extends Object> callWithNewReadWriteTransactionAndSubmit(final Class<D> datastoreType,
94             final InterruptibleCheckedConsumer<TypedReadWriteTransaction<D>, E> txConsumer) {
95         return callWithNewTransactionAndSubmit(datastoreType, transactionFactory::newReadWriteTransaction,
96             TypedReadWriteTransactionImpl::new, txConsumer, (realTx, wrappedTx) -> realTx.commit());
97     }
98
99     @Override
100     @CheckReturnValue
101     public <D extends Datastore, E extends Exception> FluentFuture<? extends Object>
102             callWithNewWriteOnlyTransactionAndSubmit(final Class<D> datastoreType,
103                     final InterruptibleCheckedConsumer<TypedWriteTransaction<D>, E> txConsumer) {
104         return callWithNewTransactionAndSubmit(datastoreType, transactionFactory::newWriteOnlyTransaction,
105             TypedWriteTransactionImpl::new, txConsumer, (realTx, wrappedTx) -> realTx.commit());
106     }
107
108     @CheckReturnValue
109     protected <D extends Datastore, X extends WriteTransaction, W, E extends Exception> FluentFuture<? extends Object>
110         callWithNewTransactionAndSubmit(
111             final Class<D> datastoreType, final Supplier<X> txSupplier, final BiFunction<Class<D>, X, W> txWrapper,
112             final InterruptibleCheckedConsumer<W, E> txConsumer, final BiFunction<X, W, FluentFuture<?>> txSubmitter) {
113         return applyWithNewTransactionAndSubmit(datastoreType, txSupplier, txWrapper, tx -> {
114             txConsumer.accept(tx);
115             return null;
116         }, txSubmitter);
117     }
118
119     @CheckReturnValue
120     @SuppressWarnings("checkstyle:IllegalCatch")
121     protected <D extends Datastore, X extends WriteTransaction, W, R, E extends Exception> FluentFuture<R>
122         applyWithNewTransactionAndSubmit(
123             final Class<D> datastoreType, final Supplier<X> txSupplier, final BiFunction<Class<D>, X, W> txWrapper,
124             final InterruptibleCheckedFunction<W, R, E> txFunction,
125             final BiFunction<X, W, FluentFuture<?>> txSubmitter) {
126         X realTx = txSupplier.get();
127         W wrappedTx = txWrapper.apply(datastoreType, realTx);
128         R result;
129         try {
130             // We must store the result before submitting the transaction; if we inline the next line in the
131             // transform lambda, that's not guaranteed
132             result = txFunction.apply(wrappedTx);
133         } catch (Exception e) {
134             // catch Exception for both the <E extends Exception> thrown by accept() as well as any RuntimeException
135             if (!realTx.cancel()) {
136                 LOG.error("Transaction.cancel() returned false - this should never happen (here)");
137             }
138             return FluentFutures.immediateFailedFluentFuture(e);
139         }
140         return txSubmitter.apply(realTx, wrappedTx).transform(v -> result, MoreExecutors.directExecutor());
141     }
142
143     protected T getTransactionFactory() {
144         return transactionFactory;
145     }
146 }