org.broadleafcommerce.openadmin.server.service.persistence.entitymanager.BroadleafEntityManagerInvocationHandler.java Source code

Java tutorial

Introduction

Here is the source code for org.broadleafcommerce.openadmin.server.service.persistence.entitymanager.BroadleafEntityManagerInvocationHandler.java

Source

/*
 * Copyright 2008-2009 the original author or authors.
 *
 * 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 org.broadleafcommerce.openadmin.server.service.persistence.entitymanager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.broadleafcommerce.openadmin.server.service.SandBoxContext;
import org.broadleafcommerce.openadmin.server.service.SandBoxMode;
import org.broadleafcommerce.openadmin.server.service.exception.SandBoxException;
import org.broadleafcommerce.openadmin.server.service.persistence.datasource.SandBoxDataSource;
import org.hibernate.ejb.HibernateEntityManager;
import org.springframework.orm.jpa.EntityManagerFactoryInfo;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * Created by IntelliJ IDEA.
 * User: jfischer
 * Date: 8/2/11
 * Time: 2:26 PM
 * To change this template use File | Settings | File Templates.
 */
public class BroadleafEntityManagerInvocationHandler implements InvocationHandler {

    private static final Log LOG = LogFactory.getLog(BroadleafEntityManagerInvocationHandler.class);

    protected final HibernateEntityManager standardManager;
    protected final HibernateEntityManager sandboxManager;
    protected final PlatformTransactionManager standardTransactionManager;
    protected final PlatformTransactionManager sandboxTransactionManager;
    protected final HibernateCleaner cleaner;

    public BroadleafEntityManagerInvocationHandler(HibernateEntityManager standardManager,
            HibernateEntityManager sandboxManager, HibernateCleaner cleaner) {
        this.standardManager = standardManager;
        this.sandboxManager = sandboxManager;
        standardTransactionManager = new org.springframework.orm.jpa.JpaTransactionManager(
                standardManager.getEntityManagerFactory());
        sandboxTransactionManager = new org.springframework.orm.jpa.JpaTransactionManager(
                sandboxManager.getEntityManagerFactory());
        this.cleaner = cleaner;
    }

    protected Object executeInTransaction(Executable executable, PlatformTransactionManager txManager)
            throws Throwable {
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setName("SandBoxTx");
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        Object response;
        TransactionStatus status = txManager.getTransaction(def);
        try {
            response = executable.execute();
        } catch (Throwable ex) {
            txManager.rollback(status);
            throw ex;
        }
        txManager.commit(status);

        return response;
    }

    protected void logInvocation(String prefix, HibernateEntityManager em, String methodName) {
        StringBuffer sb = new StringBuffer();
        sb.append(prefix);
        sb.append(" \"");
        sb.append(methodName);
        sb.append("\" on sandbox destination: ");
        sb.append(((SandBoxDataSource) ((EntityManagerFactoryInfo) sandboxManager.getEntityManagerFactory())
                .getDataSource()).getJDBCUrl());

        LOG.info(sb.toString());
    }

    @Override
    public Object invoke(Object o, final Method method, final Object[] objects) throws Throwable {
        SandBoxContext context = SandBoxContext.getSandBoxContext();
        boolean isSandBox = context != null && context.getSandBoxMode() == SandBoxMode.SANDBOX_COMMIT;
        if (method.getName().equals("merge") || method.getName().equals("persist")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    Object[] converted = new Object[] {
                            cleaner.convertBean(objects[0], method, sandboxManager, sandboxTransactionManager) };
                    return converted[0];
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            } else {
                return executeInTransaction(new Executable() {
                    @Override
                    public Object execute() throws Throwable {
                        return method.invoke(standardManager, objects);
                    }
                }, standardTransactionManager);
            }
        }
        if (method.getName().equals("remove") || method.getName().equals("flush")
                || method.getName().equals("lock")) {
            if (isSandBox) {
                return executeInTransaction(new Executable() {
                    @Override
                    public Object execute() throws Throwable {
                        logInvocation("Executing", sandboxManager, method.getName());
                        try {
                            return method.invoke(sandboxManager, objects);
                        } finally {
                            logInvocation("Completed", sandboxManager, method.getName());
                        }
                    }
                }, sandboxTransactionManager);
            } else {
                return executeInTransaction(new Executable() {
                    @Override
                    public Object execute() throws Throwable {
                        return method.invoke(standardManager, objects);
                    }
                }, standardTransactionManager);
            }
        }
        if (method.getName().equals("setFlushMode") || method.getName().equals("getFlushMode")
                || method.getName().equals("getLockMode") || method.getName().equals("joinTransaction")
                || method.getName().equals("getTransaction")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    return method.invoke(sandboxManager, objects);
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            } else {
                return method.invoke(standardManager, objects);
            }
        }
        if (method.getName().equals("find") || method.getName().equals("getReference")
                || method.getName().equals("unwrap")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    Object response = method.invoke(sandboxManager, objects);
                    if (response != null) {
                        return response;
                    }
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            }
            LOG.info(method.getName() + " not successful on sandbox, trying standard entity manager instead");
            return method.invoke(standardManager, objects);
        }
        if (method.getName().equals("refresh")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    return method.invoke(sandboxManager, objects);
                } catch (Exception e) {
                    //TODO remove this stack trace later
                    e.printStackTrace();
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            }
            LOG.info(method.getName() + " not successful on sandbox, trying standard entity manager instead");
            return method.invoke(standardManager, objects);
        }
        if (method.getName().equals("clear") || method.getName().equals("getProperties")
                || method.getName().equals("setProperty") || method.getName().equals("close")) {
            logInvocation("Executing", sandboxManager, method.getName());
            try {
                method.invoke(sandboxManager, objects);
            } finally {
                logInvocation("Completed", sandboxManager, method.getName());
            }
            return method.invoke(standardManager, objects);
        }
        if (method.getName().equals("detach")) {
            if (sandboxManager.contains(objects[0])) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    sandboxManager.detach(objects[0]);
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            }
            if (standardManager.contains(objects[0])) {
                standardManager.detach(objects[0]);
            }
            return null;
        }
        if (method.getName().equals("contains")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    boolean contains = sandboxManager.contains(objects[0]);
                    if (contains) {
                        return true;
                    }
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            }
            return standardManager.contains(objects[0]);
        }
        if (method.getName().equals("isOpen")) {
            if (isSandBox) {
                logInvocation("Executing", sandboxManager, method.getName());
                try {
                    boolean isOpen = sandboxManager.isOpen();
                    if (!isOpen) {
                        return false;
                    }
                } finally {
                    logInvocation("Completed", sandboxManager, method.getName());
                }
            }
            return standardManager.isOpen();
        }
        if (method.getName().equals("getDelegate") || method.getName().equals("getEntityManagerFactory")
                || method.getName().equals("getMetamodel") || method.getName().equals("getSession")) {
            return method.invoke(standardManager, objects);
        }
        if (method.getName().equals("createQuery") || method.getName().equals("createNamedQuery")
                || method.getName().equals("createNativeQuery") || method.getName().equals("getCriteriaBuilder")) {
            //TODO need to return a proxied version of query that is intelligent enough to return a mixed list
            return method.invoke(standardManager, objects);
        }
        if (method.getName().equals("getStandardManager")) {
            return standardManager;
        }
        if (method.getName().equals("getSandboxManager")) {
            return sandboxManager;
        }
        throw new SandBoxException("Unrecognized EntityManager method sent to proxy: " + method.getName());
    }

    public interface Executable {

        public Object execute() throws Throwable;

    }
}