f061976f01ca128be7b35bbaf569f061b3d3bad1
[mdsal.git] / binding / mdsal-binding-util / src / main / java / org / opendaylight / mdsal / binding / util / ManagedNewTransactionRunnerImpl.java
1 /*
2  * Copyright (c) 2017 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.mdsal.binding.util;
9
10 import static java.util.Objects.requireNonNull;
11
12 import com.google.common.annotations.Beta;
13 import com.google.common.util.concurrent.FluentFuture;
14 import edu.umd.cs.findbugs.annotations.CheckReturnValue;
15 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
16 import java.util.function.Function;
17 import javax.inject.Inject;
18 import org.opendaylight.mdsal.binding.api.DataBroker;
19 import org.opendaylight.mdsal.binding.api.Transaction;
20 import org.opendaylight.mdsal.binding.api.TransactionChain;
21 import org.opendaylight.mdsal.binding.api.TransactionChainListener;
22 import org.opendaylight.mdsal.binding.api.WriteTransaction;
23 import org.opendaylight.mdsal.common.api.CommitInfo;
24 import org.slf4j.Logger;
25 import org.slf4j.LoggerFactory;
26
27 /**
28  * Implementation of {@link ManagedNewTransactionRunner}. This is based on {@link ManagedTransactionFactoryImpl} but
29  * re-implements operations based on read-write transactions to cancel transactions which don't end up making any
30  * changes to the datastore.
31  */
32 @Beta
33 // Do *NOT* mark this as @Singleton, because users choose their implementation
34 public class ManagedNewTransactionRunnerImpl extends ManagedTransactionFactoryImpl<DataBroker>
35         implements ManagedNewTransactionRunner {
36
37     private static final Logger LOG = LoggerFactory.getLogger(ManagedNewTransactionRunnerImpl.class);
38
39     @Inject
40     public ManagedNewTransactionRunnerImpl(final DataBroker broker) {
41         // Early check to ensure the error message is understandable for the caller
42         super(requireNonNull(broker, "broker must not be null"));
43     }
44
45     // This is overridden to use this class’s commit method
46     @Override
47     @CheckReturnValue
48     public <D extends Datastore, E extends Exception, R> FluentFuture<R> applyWithNewReadWriteTransactionAndSubmit(
49             final Class<D> datastoreType,
50             final InterruptibleCheckedFunction<TypedReadWriteTransaction<D>, R, E> txFunction) {
51         return super.applyWithNewTransactionAndSubmit(datastoreType, getTransactionFactory()::newReadWriteTransaction,
52             WriteTrackingTypedReadWriteTransactionImpl::new, txFunction::apply, this::commit);
53     }
54
55     @Override
56     @SuppressFBWarnings("RCN_REDUNDANT_NULLCHECK_WOULD_HAVE_BEEN_A_NPE")
57     public <R> R applyWithNewTransactionChainAndClose(final Function<ManagedTransactionChain, R> chainConsumer) {
58         try (TransactionChain realTxChain = getTransactionFactory().createTransactionChain(
59             new TransactionChainListener() {
60                 @Override
61                 public void onTransactionChainFailed(TransactionChain chain, Transaction transaction, Throwable cause) {
62                     LOG.error("Error handling a transaction chain", cause);
63                 }
64
65                 @Override
66                 public void onTransactionChainSuccessful(TransactionChain chain) {
67                     // Nothing to do
68                 }
69             })) {
70             return chainConsumer.apply(new ManagedTransactionChainImpl(realTxChain));
71         }
72     }
73
74     // This is overridden to use this class’s commit method
75     @Override
76     @CheckReturnValue
77     public <D extends Datastore, E extends Exception> FluentFuture<? extends Object>
78         callWithNewReadWriteTransactionAndSubmit(final Class<D> datastoreType,
79             final InterruptibleCheckedConsumer<TypedReadWriteTransaction<D>, E> txConsumer) {
80         return callWithNewTransactionAndSubmit(datastoreType, getTransactionFactory()::newReadWriteTransaction,
81             WriteTrackingTypedReadWriteTransactionImpl::new, txConsumer::accept, this::commit);
82     }
83
84     // This is overridden to use this class’s commit method
85     @Override
86     @CheckReturnValue
87     public <D extends Datastore, E extends Exception> FluentFuture<? extends Object>
88             callWithNewWriteOnlyTransactionAndSubmit(final Class<D> datastoreType,
89                     final InterruptibleCheckedConsumer<TypedWriteTransaction<D>, E> txConsumer) {
90         return super.callWithNewTransactionAndSubmit(datastoreType, getTransactionFactory()::newWriteOnlyTransaction,
91             WriteTrackingTypedWriteTransactionImpl::new, txConsumer::accept, this::commit);
92     }
93
94     @CheckReturnValue
95     private FluentFuture<? extends CommitInfo> commit(final WriteTransaction realTx,
96             final WriteTrackingTransaction wrappedTx) {
97         if (wrappedTx.isWritten()) {
98             // The transaction contains changes, commit it
99             return realTx.commit();
100         }
101
102         // The transaction only handled reads, cancel it
103         realTx.cancel();
104         return CommitInfo.emptyFluentFuture();
105     }
106 }