/*
* ============================================================================
* GNU Lesser General Public License
* ============================================================================
*
* Beanlet - JSE Application Container.
* Copyright (C) 2006 Leon van Zantvoort
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* Leon van Zantvoort
* 243 Acalanes Drive #11
* Sunnyvale, CA 94086
* USA
*
* zantvoort@users.sourceforge.net
* http://beanlet.org
*/
package org.beanlet.persistence.impl;
import javax.persistence.*;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.metamodel.Metamodel;
import java.util.Map;
/**
* <ul>
* <li>The application may obtain a container-managed entity manager with
* transaction-scoped persistence context bound to the JTA transaction by
* injection or direct lookup in the JNDI namespace. The persistence context
* type for the entity manager is defaulted or defined as PersistenceContext-
* Type.TRANSACTION. (5.6.1 p121)
* <li>A new persistence context begins when the container-managed entity
* manager is invoked in the scope of an active JTA transaction, and there is no
* current persistence context already associated with the JTA transaction. The
* persistence context is created and then associated with the JTA transaction.
* (5.6.1 p121)
* <li>The persistence context ends when the associated JTA transaction commits
* or rolls back, and all entities that were managed by the EntityManager become
* detached. (5.6.1 p121)
* <li>If the entity manager is invoked outside the scope of a transaction,
* any entities loaded from the database will immediately become detached at the
* end of the method call. (5.6.1 p121)
* <li>The container must throw the {@code TransactionRequiredException} if
* a transaction-scoped persistence context is used, and the
* {@code EntityManager} {@code persist}, {@code remove}, {@code merge}, or
* {@code refresh} is invoked when no transaction is active. (5.9.1 p130)
* </ul>
*
* @author Leon van Zantvoort
*/
public final class TransactionScopedEntityManager extends
ContainerManagedEntityManager {
private final InternalJTAEntityManagerFactory jta;
private final InternalNonJTAEntityManagerFactory nonJTA;
public TransactionScopedEntityManager(BeanletEntityManagerFactory emf) {
this.nonJTA = new InternalNonJTAEntityManagerFactory(emf);
this.jta = new InternalJTAEntityManagerFactory(emf);
}
public EntityManager getEntityManager() {
final EntityManager em;
if (jta.isTransactionActive()) {
em = jta.createEntityManager();
} else {
em = nonJTA.createEntityManager();
}
return em;
}
/**
* This method has package private visibility.
*/
@Override
void preInvoke() {
nonJTA.preInvoke();
jta.preInvoke();
}
/**
* This method has package private visibility.
*/
@Override
void postInvoke(boolean commit) {
jta.postInvoke();
nonJTA.postInvoke();
}
@Override
public void persist(Object object) {
verifyTransactionActive();
super.persist(object);
}
@Override
public void remove(Object object) {
verifyTransactionActive();
super.remove(object);
}
@Override
public <T> T merge(T entity) {
verifyTransactionActive();
return super.merge(entity);
}
@Override
public void refresh(Object object) {
verifyTransactionActive();
super.refresh(object);
}
@Override
public boolean isOpen() {
throw new IllegalStateException("Container managed transaction-scoped" +
" entity manager does not allow this function.");
}
@Override
public EntityTransaction getTransaction() {
throw new IllegalStateException("Container managed transaction-scoped" +
" entity manager does not allow this function.");
}
private void verifyTransactionActive() throws TransactionRequiredException {
// PENDING: check if transaction is active?
if (!jta.isTransactionActive()) {
throw new TransactionRequiredException();
}
}
public <T> T find(Class<T> cls, Object object) {
verifyTransactionActive();
return super.find(cls, object);
}
public <T> T getReference(Class<T> cls, Object object) {
verifyTransactionActive();
return super.getReference(cls, object);
}
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
verifyTransactionActive();
return super.createNamedQuery(name, resultClass);
}
public <T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties) {
verifyTransactionActive();
return super.find(entityClass, primaryKey, properties);
}
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode) {
verifyTransactionActive();
return super.find(entityClass, primaryKey, lockMode);
}
public <T> T find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String, Object> properties) {
verifyTransactionActive();
return super.find(entityClass, primaryKey, lockMode, properties);
}
public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) {
verifyTransactionActive();
super.lock(entity, lockMode, properties);
}
public void refresh(Object entity, Map<String, Object> properties) {
verifyTransactionActive();
super.refresh(entity, properties);
}
public void refresh(Object entity, LockModeType lockMode) {
verifyTransactionActive();
super.refresh(entity, lockMode);
}
public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) {
verifyTransactionActive();
super.refresh(entity, lockMode, properties);
}
public void detach(Object entity) {
verifyTransactionActive();
super.detach(entity);
}
public LockModeType getLockMode(Object entity) {
verifyTransactionActive();
return super.getLockMode(entity);
}
public void setProperty(String propertyName, Object value) {
verifyTransactionActive();
super.setProperty(propertyName, value);
}
public Map<String, Object> getProperties() {
verifyTransactionActive();
return super.getProperties();
}
public <T> TypedQuery<T> createQuery(CriteriaQuery<T> criteriaQuery) {
verifyTransactionActive();
return super.createQuery(criteriaQuery);
}
public <T> TypedQuery<T> createQuery(String qlString, Class<T> resultClass) {
verifyTransactionActive();
return super.createQuery(qlString, resultClass);
}
public <T> T unwrap(Class<T> cls) {
verifyTransactionActive();
return super.unwrap(cls);
}
public EntityManagerFactory getEntityManagerFactory() {
verifyTransactionActive();
return super.getEntityManagerFactory();
}
public CriteriaBuilder getCriteriaBuilder() {
verifyTransactionActive();
return super.getCriteriaBuilder();
}
public Metamodel getMetamodel() {
verifyTransactionActive();
return super.getMetamodel();
}
}