All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.tourniquet.tx.TransactionHelper Maven / Gradle / Ivy

There is a newer version: 0.4.8
Show newest version
/*
 * Copyright 2015-2016 DevCon5 GmbH, [email protected]
 *
 * 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 io.tourniquet.tx;

import java.lang.reflect.Method;
import java.util.Optional;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

/**
 * Utility class to enhance a Page instance with transaction support.
 */
public final class TransactionHelper {

    private TransactionHelper() {
    }

    /**
     * Adds transaction support to the page. The transaction support captures execution time of methods annotated with
     * {@link Transaction}
     *
     * @param 
     *
     * @param transactionSupport
     *         the transactionSupport element to be enhanced.
     * @return
     */
    @SuppressWarnings("unchecked")
    public static  T addTransactionSupport(TransactionSupport transactionSupport) {
        return (T) Enhancer.create(transactionSupport.getClass(), (MethodInterceptor) (obj, method, args, proxy) -> {
            final Optional txName = getTxName(transactionSupport, method);
            try {
                txName.ifPresent(transactionSupport::txBegin);
                Object result = method.invoke(transactionSupport, args);
                //dynamically enhance return values, if they are transactionSupport and not yet enhanced
                //this is required, i.e. if method return 'this' or create new objects which will
                //not be enhanced
                if (!isCGLibProxy(result) && result instanceof TransactionSupport) {
                    result = addTransactionSupport(transactionSupport);
                }
                return result;
            } finally {
                txName.ifPresent(transactionSupport::txEnd);
            }
        });
    }

    /**
     * Determines whether an instance is a CGLib Proxy.
     * @param object
     *  the object to check
     * @return
     *  true if the object is a CGLib proxy
     */
    private static boolean isCGLibProxy(Object object) {
        return object != null
                && object.getClass()
                         .getName()
                         .contains("$$EnhancerByCGLIB$$");
    }

    /**
     * Determines the transaction name of the method. The method must be annotated with {@link Transaction} otherwise
     * the empty optional is returned. The name is derived from the value of the {@link Transaction} annotation or from
     * the mehtod name. If the declaring class denotes a transaction itself, it's name prefixes the method transaction.
     *
     * @param method
     *         the method for which the transaction name should be determined
     *
     * @return the name of the transaction or the empty optional if the method denotes no transaction
     */
    public static Optional getTxName(Object object, final Method method) {

        return Optional.ofNullable(method.getAnnotation(Transaction.class))
                       .map(t -> getClassTxName(object.getClass())
                               .map(ctx -> ctx + '_')
                               .orElse("") + (isEmpty(t.value())
                                              ? method.getName()
                                              : t.value()));
    }

    /**
     * Determines the transaction name for the class. The class must be annoted with {@link Transaction} otherwise an
     * empty optional is returned. The name of the transaction is either the value of the annotation of the simple name
     * of the class itself
     *
     * @param type
     *         the type for which a transaction name should be determined
     *
     * @return the name of the transaction of the empty optional if the class is not transactional
     */
    public static Optional getClassTxName(final Class type) {

        return Optional.ofNullable(type.getAnnotation(Transaction.class))
                       .map(t -> isEmpty(t.value())
                                 ? type.getSimpleName()
                                 : t.value());
    }

    /**
     * Checks if a string is either null or empty
     * @param string
     *  the string to check
     * @return
     *  true if the string is null or empty
     */
    private static boolean isEmpty(String string){
        return string == null || string.isEmpty();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy