/* * Copyright © 2018 Red Hat, Inc. and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 which accompanies this distribution, * and is available at http://www.eclipse.org/legal/epl-v10.html */ package org.opendaylight.mdsal.binding.util; import static java.util.Objects.requireNonNull; import com.google.common.util.concurrent.FluentFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.function.BiFunction; import java.util.function.Supplier; import javax.annotation.CheckReturnValue; import org.opendaylight.mdsal.binding.api.ReadTransaction; import org.opendaylight.mdsal.binding.api.TransactionFactory; import org.opendaylight.mdsal.binding.api.WriteTransaction; import org.opendaylight.yangtools.util.concurrent.FluentFutures; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Basic implementation of a {@link ManagedTransactionFactory}. */ class ManagedTransactionFactoryImpl implements ManagedTransactionFactory { private static final Logger LOG = LoggerFactory.getLogger(ManagedTransactionFactoryImpl.class); private final T transactionFactory; ManagedTransactionFactoryImpl(final T transactionFactory) { this.transactionFactory = requireNonNull(transactionFactory, "transactionFactory must not be null"); } @Override public R applyInterruptiblyWithNewReadOnlyTransactionAndClose( final Class datastoreType, final InterruptibleCheckedFunction, R, E> txFunction) throws E, InterruptedException { try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) { TypedReadTransaction wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx); return txFunction.apply(wrappedTx); } } @Override public R applyWithNewReadOnlyTransactionAndClose( final Class datastoreType, final CheckedFunction, R, E> txFunction) throws E { try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) { TypedReadTransaction wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx); return txFunction.apply(wrappedTx); } } @Override @CheckReturnValue public FluentFuture applyWithNewReadWriteTransactionAndSubmit(final Class datastoreType, final InterruptibleCheckedFunction, R, E> txFunction) { return applyWithNewTransactionAndSubmit(datastoreType, transactionFactory::newReadWriteTransaction, TypedReadWriteTransactionImpl::new, txFunction, (realTx, wrappedTx) -> realTx.commit()); } @Override public void callInterruptiblyWithNewReadOnlyTransactionAndClose( final Class datastoreType, final InterruptibleCheckedConsumer, E> txConsumer) throws E, InterruptedException { try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) { TypedReadTransaction wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx); txConsumer.accept(wrappedTx); } } @Override public void callWithNewReadOnlyTransactionAndClose( final Class datastoreType, final CheckedConsumer, E> txConsumer) throws E { try (ReadTransaction realTx = transactionFactory.newReadOnlyTransaction()) { TypedReadTransaction wrappedTx = new TypedReadTransactionImpl<>(datastoreType, realTx); txConsumer.accept(wrappedTx); } } @Override @CheckReturnValue public FluentFuture callWithNewReadWriteTransactionAndSubmit(final Class datastoreType, final InterruptibleCheckedConsumer, E> txConsumer) { return callWithNewTransactionAndSubmit(datastoreType, transactionFactory::newReadWriteTransaction, TypedReadWriteTransactionImpl::new, txConsumer, (realTx, wrappedTx) -> realTx.commit()); } @Override @CheckReturnValue public FluentFuture callWithNewWriteOnlyTransactionAndSubmit(final Class datastoreType, final InterruptibleCheckedConsumer, E> txConsumer) { return callWithNewTransactionAndSubmit(datastoreType, transactionFactory::newWriteOnlyTransaction, TypedWriteTransactionImpl::new, txConsumer, (realTx, wrappedTx) -> realTx.commit()); } @CheckReturnValue protected FluentFuture callWithNewTransactionAndSubmit( final Class datastoreType, final Supplier txSupplier, final BiFunction, T, W> txWrapper, final InterruptibleCheckedConsumer txConsumer, final BiFunction> txSubmitter) { return applyWithNewTransactionAndSubmit(datastoreType, txSupplier, txWrapper, tx -> { txConsumer.accept(tx); return null; }, txSubmitter); } @CheckReturnValue @SuppressWarnings("checkstyle:IllegalCatch") protected FluentFuture applyWithNewTransactionAndSubmit( final Class datastoreType, final Supplier txSupplier, final BiFunction, T, W> txWrapper, final InterruptibleCheckedFunction txFunction, final BiFunction> txSubmitter) { T realTx = txSupplier.get(); W wrappedTx = txWrapper.apply(datastoreType, realTx); R result; try { // We must store the result before submitting the transaction; if we inline the next line in the // transform lambda, that's not guaranteed result = txFunction.apply(wrappedTx); } catch (Exception e) { // catch Exception for both the thrown by accept() as well as any RuntimeException if (!realTx.cancel()) { LOG.error("Transaction.cancel() returned false - this should never happen (here)"); } return FluentFutures.immediateFailedFluentFuture(e); } return txSubmitter.apply(realTx, wrappedTx).transform(v -> result, MoreExecutors.directExecutor()); } protected T getTransactionFactory() { return transactionFactory; } }