/* * Copyright © 2014 Cask Data, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package co.cask.cdap.data2.dataset2.tx; import co.cask.tephra.TransactionAware; import co.cask.tephra.TransactionExecutor; import co.cask.tephra.TransactionExecutorFactory; import co.cask.tephra.TransactionFailureException; import com.google.common.base.Function; import com.google.common.base.Predicates; import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.Iterables; import java.io.Closeable; import java.io.IOException; /** * Handy utility for performing transactional operations that delegates execution to {@link TransactionExecutor} * and manages resources in transaction context. Transaction context is supplied using given {@link Supplier} and * provides list of resources by implementing {@link Iterable}. This applies transaction logic to those resources * that implement {@link TransactionAware}. Additionally, if resource implements {@link Closeable} its * {@link java.io.Closeable#close()} is invoked at the end of transaction. * * @param <T> type of the transactional context * @param <V> type of objects contained inside the transaction context * * @deprecated Don't use this class anymore. Use {@link TransactionExecutor} instead. */ @Deprecated public class Transactional<T extends Iterable<V>, V> { private final TransactionExecutorFactory txFactory; private final Supplier<T> supplier; public static <T extends Iterable<V>, V> Transactional<T, V> of(TransactionExecutorFactory txFactory, Supplier<T> supplier) { return new Transactional<>(txFactory, supplier); } /** * Creates instance of {@link Transactional}. * @param txFactory factory for {@link TransactionExecutor}s * @param supplier supplies transaction context. Transaction logic will be applied to the items returned by the * context's getIterator() method for those that implement {@link TransactionAware} */ private Transactional(TransactionExecutorFactory txFactory, Supplier<T> supplier) { this.txFactory = txFactory; this.supplier = supplier; } /** * Executes given function within new transaction. */ public <R> R execute(final TransactionExecutor.Function<T, R> func) throws TransactionFailureException, InterruptedException, IOException { return execute(txFactory, supplier, func); } /** * Executes given function within new transaction and rethrows all exceptions with * {@link Throwables#propagate(Throwable)} */ public <R> R executeUnchecked(final TransactionExecutor.Function<T, R> func) { try { return execute(txFactory, supplier, func); } catch (IOException | TransactionFailureException e) { throw Throwables.propagate(e); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw Throwables.propagate(e); } } /** * Executes function within new transaction. See {@link Transactional} for more details. * @param txFactory transaction factory to create new transaction * @param supplier supplier of transaction context * @param func function to execute * @param <V> type of object contained inside the transaction context * @param <T> type of the transaction context * @param <R> type of the function result * @return function result */ public static <V, T extends Iterable<V>, R> R execute(TransactionExecutorFactory txFactory, Supplier<T> supplier, TransactionExecutor.Function<T, R> func) throws TransactionFailureException, IOException, InterruptedException { T it = supplier.get(); Iterable<TransactionAware> txAwares = Iterables.transform( Iterables.filter(it, Predicates.instanceOf(TransactionAware.class)), new Function<V, TransactionAware>() { @Override public TransactionAware apply(V input) { return (TransactionAware) input; } }); TransactionExecutor executor = txFactory.createExecutor(txAwares); try { return executor.execute(func, it); } finally { for (V t : it) { if (t instanceof Closeable) { ((Closeable) t).close(); } } } } }