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

com.jwebmp.guicedpersistence.injectors.CustomJpaLocalTxnInterceptor Maven / Gradle / Ivy

/*
 * Copyright (C) 2010 Google, 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 com.jwebmp.guicedpersistence.injectors;

import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.persist.Transactional;
import com.google.inject.persist.UnitOfWork;
import com.jwebmp.guicedinjection.GuiceContext;
import com.jwebmp.guicedpersistence.services.ITransactionHandler;
import com.oracle.jaxb21.PersistenceUnit;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import javax.persistence.EntityManager;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

import static com.jwebmp.guicedpersistence.scanners.PersistenceServiceLoadersBinder.*;

/**
 * @author Dhanji R. Prasanna ([email protected])
 */
public class CustomJpaLocalTxnInterceptor
		implements MethodInterceptor
{
	/**
	 * Is this the starting @Transactional?
	 */
	private final ThreadLocal didWeStartWork = new ThreadLocal<>();
	/**
	 * Injected provider for em
	 */
	@Inject
	private CustomJpaPersistService emProvider = null;
	/**
	 * The unit of work we are referencing
	 */
	@Inject
	private UnitOfWork unitOfWork = null;

	@Override
	@SuppressWarnings("Duplicates")
	public Object invoke(MethodInvocation methodInvocation) throws Throwable
	{
		if (!emProvider.isWorking())
		{
			emProvider.begin();
			didWeStartWork.set(true);
		}

		Transactional transactional = readTransactionMetadata(methodInvocation);
		EntityManager em = emProvider.get();
		Class providedAnnotation = emProvider.getAnnotation();
		PersistenceUnit unit = GuiceContext.get(Key.get(PersistenceUnit.class, providedAnnotation));
		Boolean startedWork = didWeStartWork.get() == null ? false : didWeStartWork.get();

		boolean transactionIsActive = false;
		for (ITransactionHandler handler : GuiceContext.get(ITransactionHandlerReader))
		{
			if (handler.active(unit) && handler.transactionExists(em, unit))
			{
				transactionIsActive = true;
				break;
			}
		}

		if (!startedWork && transactionIsActive)
		{
			return methodInvocation.proceed();
		}

		for (ITransactionHandler handler : GuiceContext.get(ITransactionHandlerReader))
		{
			if (handler.active(unit))
			{
				handler.beginTransacation(false, em, unit);
			}
		}

		Object result;
		try
		{
			result = methodInvocation.proceed();

		}
		catch (Exception e)
		{
			if (rollbackIfNecessary(transactional, e, unit, em))
			{
				for (ITransactionHandler handler : GuiceContext.get(ITransactionHandlerReader))
				{
					if (handler.active(unit))
					{
						handler.commitTransacation(false, em, unit);
					}
				}
			}

			if (startedWork)
			{
				didWeStartWork.remove();
				unitOfWork.end();
			}

			throw e;

		}

		try
		{
			for (ITransactionHandler handler : GuiceContext.get(ITransactionHandlerReader))
			{
				if (handler.active(unit))
				{
					handler.commitTransacation(false, em, unit);
				}
			}
		}
		finally
		{
			if (startedWork)
			{
				em.clear();
				em.close();
				didWeStartWork.remove();
				unitOfWork.end();
			}
		}

		return result;
	}

	/**
	 * Method readTransactionMetadata ...
	 *
	 * @param methodInvocation
	 * 		of type MethodInvocation
	 *
	 * @return Transactional
	 */
	private Transactional readTransactionMetadata(MethodInvocation methodInvocation)
	{
		Transactional transactional;
		Method method = methodInvocation.getMethod();
		Class targetClass = methodInvocation.getThis()
		                                       .getClass();

		transactional = method.getAnnotation(Transactional.class);
		if (null == transactional)
		{
			transactional = targetClass.getAnnotation(Transactional.class);
		}
		if (null == transactional)
		{
			transactional = Internal.class.getAnnotation(Transactional.class);
		}

		return transactional;
	}

	/**
	 * Returns True if rollback DID NOT HAPPEN (i.e. if commit should continue).
	 *
	 * @param transactional
	 * 		The metadata annotation of the method
	 * @param e
	 * 		The exception to test for rollback
	 * @param em
	 * 		Entity Manager
	 * @param unit
	 * 		The associated persistence unit
	 */
	@SuppressWarnings("Duplicates")
	private boolean rollbackIfNecessary(Transactional transactional, Exception e, PersistenceUnit unit, EntityManager em)
	{
		boolean commit = true;
		for (Class rollBackOn : transactional.rollbackOn())
		{
			if (rollBackOn.isInstance(e))
			{
				commit = false;
				for (Class exceptOn : transactional.ignore())
				{
					if (exceptOn.isInstance(e))
					{
						commit = true;
						break;
					}
				}

				if (!commit)
				{
					for (ITransactionHandler handler : GuiceContext.get(ITransactionHandlerReader))
					{
						if (handler.active(unit))
						{
							handler.rollbackTransacation(false, em, unit);
						}
					}
				}
				break;
			}
		}

		return commit;
	}

	@Transactional
	private static class Internal {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy