co.cask.cdap.data2.dataset2.tx.Transactional.java Source code

Java tutorial

Introduction

Here is the source code for co.cask.cdap.data2.dataset2.tx.Transactional.java

Source

/*
 * 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
 */
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();
                }
            }
        }
    }
}