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