@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2012 the original author or authors .
* Copyright 2002 - 2013 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 .
@ -71,7 +71,7 @@ public abstract class ExtendedEntityManagerCreator {
@@ -71,7 +71,7 @@ public abstract class ExtendedEntityManagerCreator {
public static EntityManager createApplicationManagedEntityManager (
EntityManager rawEntityManager , EntityManagerPlusOperations plusOperations ) {
return createProxy ( rawEntityManager , null , null , plusOperations , null , null , false ) ;
return createProxy ( rawEntityManager , null , null , plusOperations , null , null , false , false ) ;
}
/ * *
@ -91,7 +91,7 @@ public abstract class ExtendedEntityManagerCreator {
@@ -91,7 +91,7 @@ public abstract class ExtendedEntityManagerCreator {
EntityManager rawEntityManager , EntityManagerPlusOperations plusOperations ,
PersistenceExceptionTranslator exceptionTranslator ) {
return createProxy ( rawEntityManager , null , null , plusOperations , exceptionTranslator , null , false ) ;
return createProxy ( rawEntityManager , null , null , plusOperations , exceptionTranslator , null , false , false ) ;
}
/ * *
@ -107,13 +107,31 @@ public abstract class ExtendedEntityManagerCreator {
@@ -107,13 +107,31 @@ public abstract class ExtendedEntityManagerCreator {
public static EntityManager createApplicationManagedEntityManager (
EntityManager rawEntityManager , EntityManagerFactoryInfo emfInfo ) {
return createProxy ( rawEntityManager , emfInfo , false ) ;
return createProxy ( rawEntityManager , emfInfo , false , false ) ;
}
/ * *
* Create an EntityManager that can join transactions with the
* { @code joinTransaction ( ) } method , but is not automatically
* managed by the container .
* @param rawEntityManager raw EntityManager
* @param emfInfo the EntityManagerFactoryInfo to obtain the
* EntityManagerPlusOperations and PersistenceUnitInfo from
* @param synchronizedWithTransaction whether to automatically join ongoing
* transactions ( according to the JPA 2 . 1 SynchronizationType rules )
* @return an application - managed EntityManager that can join transactions
* but does not participate in them automatically
* /
public static EntityManager createApplicationManagedEntityManager (
EntityManager rawEntityManager , EntityManagerFactoryInfo emfInfo , boolean synchronizedWithTransaction ) {
return createProxy ( rawEntityManager , emfInfo , false , synchronizedWithTransaction ) ;
}
/ * *
* Create an EntityManager that automatically joins transactions on each
* operation in a transaction .
* Create an EntityManager whose lifecycle is managed by the container and whi ch
* automatically joins a transaction when being invoked within its scope .
* @param rawEntityManager raw EntityManager
* @param plusOperations an implementation of the EntityManagerPlusOperations
* interface , if those operations should be exposed ( may be { @code null } )
@ -123,12 +141,12 @@ public abstract class ExtendedEntityManagerCreator {
@@ -123,12 +141,12 @@ public abstract class ExtendedEntityManagerCreator {
public static EntityManager createContainerManagedEntityManager (
EntityManager rawEntityManager , EntityManagerPlusOperations plusOperations ) {
return createProxy ( rawEntityManager , null , null , plusOperations , null , null , true ) ;
return createProxy ( rawEntityManager , null , null , plusOperations , null , null , true , true ) ;
}
/ * *
* Create an EntityManager that automatically joins transactions on ea ch
* operation in a transaction .
* Create an EntityManager whose lifecycle is managed by the container and whi ch
* automatically joins a transaction when being invoked within its scope .
* @param rawEntityManager raw EntityManager
* @param plusOperations an implementation of the EntityManagerPlusOperations
* interface , if those operations should be exposed ( may be { @code null } )
@ -142,12 +160,12 @@ public abstract class ExtendedEntityManagerCreator {
@@ -142,12 +160,12 @@ public abstract class ExtendedEntityManagerCreator {
EntityManager rawEntityManager , EntityManagerPlusOperations plusOperations ,
PersistenceExceptionTranslator exceptionTranslator ) {
return createProxy ( rawEntityManager , null , null , plusOperations , exceptionTranslator , null , true ) ;
return createProxy ( rawEntityManager , null , null , plusOperations , exceptionTranslator , null , true , true ) ;
}
/ * *
* Create an EntityManager that automatically joins transactions on ea ch
* operation in a transaction .
* Create an EntityManager whose lifecycle is managed by the container and whi ch
* automatically joins a transaction when being invoked within its scope .
* @param rawEntityManager raw EntityManager
* @param emfInfo the EntityManagerFactoryInfo to obtain the
* EntityManagerPlusOperations and PersistenceUnitInfo from
@ -157,13 +175,12 @@ public abstract class ExtendedEntityManagerCreator {
@@ -157,13 +175,12 @@ public abstract class ExtendedEntityManagerCreator {
public static EntityManager createContainerManagedEntityManager (
EntityManager rawEntityManager , EntityManagerFactoryInfo emfInfo ) {
return createProxy ( rawEntityManager , emfInfo , true ) ;
return createProxy ( rawEntityManager , emfInfo , true , true ) ;
}
/ * *
* Create an EntityManager that automatically joins transactions on ea ch
* operation in a transaction .
* Create an EntityManager whose lifecycle is managed by the container and whi ch
* automatically joins a transaction when being invoked within its scope .
* @param emf the EntityManagerFactory to create the EntityManager with .
* If this implements the EntityManagerFactoryInfo interface , appropriate handling
* of the native EntityManagerFactory and available EntityManagerPlusOperations
@ -173,12 +190,12 @@ public abstract class ExtendedEntityManagerCreator {
@@ -173,12 +190,12 @@ public abstract class ExtendedEntityManagerCreator {
* @see javax . persistence . EntityManagerFactory # createEntityManager ( )
* /
public static EntityManager createContainerManagedEntityManager ( EntityManagerFactory emf ) {
return createContainerManagedEntityManager ( emf , null ) ;
return createContainerManagedEntityManager ( emf , null , true ) ;
}
/ * *
* Create an EntityManager that automatically joins transactions on ea ch
* operation in a transaction .
* Create an EntityManager whose lifecycle is managed by the container and whi ch
* automatically joins a transaction when being invoked within its scope .
* @param emf the EntityManagerFactory to create the EntityManager with .
* If this implements the EntityManagerFactoryInfo interface , appropriate handling
* of the native EntityManagerFactory and available EntityManagerPlusOperations
@ -190,18 +207,39 @@ public abstract class ExtendedEntityManagerCreator {
@@ -190,18 +207,39 @@ public abstract class ExtendedEntityManagerCreator {
* @see javax . persistence . EntityManagerFactory # createEntityManager ( java . util . Map )
* /
public static EntityManager createContainerManagedEntityManager ( EntityManagerFactory emf , Map properties ) {
return createContainerManagedEntityManager ( emf , properties , true ) ;
}
/ * *
* Create an EntityManager whose lifecycle is managed by the container and which
* may automatically join a transaction when being invoked within its scope .
* @param emf the EntityManagerFactory to create the EntityManager with .
* If this implements the EntityManagerFactoryInfo interface , appropriate handling
* of the native EntityManagerFactory and available EntityManagerPlusOperations
* will automatically apply .
* @param properties the properties to be passed into the { @code createEntityManager }
* call ( may be { @code null } )
* @param synchronizedWithTransaction whether to automatically join ongoing
* transactions ( according to the JPA 2 . 1 SynchronizationType rules )
* @return a container - managed EntityManager that expects container - driven lifecycle
* management but may opt out of automatic transaction synchronization
* @see javax . persistence . EntityManagerFactory # createEntityManager ( java . util . Map )
* /
public static EntityManager createContainerManagedEntityManager (
EntityManagerFactory emf , Map properties , boolean synchronizedWithTransaction ) {
Assert . notNull ( emf , "EntityManagerFactory must not be null" ) ;
if ( emf instanceof EntityManagerFactoryInfo ) {
EntityManagerFactoryInfo emfInfo = ( EntityManagerFactoryInfo ) emf ;
EntityManagerFactory nativeEmf = emfInfo . getNativeEntityManagerFactory ( ) ;
EntityManager rawEntityManager = ( ! CollectionUtils . isEmpty ( properties ) ?
nativeEmf . createEntityManager ( properties ) : nativeEmf . createEntityManager ( ) ) ;
return createProxy ( rawEntityManager , emfInfo , true ) ;
return createProxy ( rawEntityManager , emfInfo , true , synchronizedWithTransaction ) ;
}
else {
EntityManager rawEntityManager = ( ! CollectionUtils . isEmpty ( properties ) ?
emf . createEntityManager ( properties ) : emf . createEntityManager ( ) ) ;
return createProxy ( rawEntityManager , null , null , null , null , null , true ) ;
return createProxy ( rawEntityManager , null , null , null , null , null , true , synchronizedWithTransaction ) ;
}
}
@ -213,10 +251,12 @@ public abstract class ExtendedEntityManagerCreator {
@@ -213,10 +251,12 @@ public abstract class ExtendedEntityManagerCreator {
* EntityManagerPlusOperations and PersistenceUnitInfo from
* @param containerManaged whether to follow container - managed EntityManager
* or application - managed EntityManager semantics
* @param synchronizedWithTransaction whether to automatically join ongoing
* transactions ( according to the JPA 2 . 1 SynchronizationType rules )
* @return the EntityManager proxy
* /
private static EntityManager createProxy (
EntityManager rawEntityManager , EntityManager FactoryInfo emfInfo , boolean containerManaged ) {
private static EntityManager createProxy ( EntityManager rawEntityManager ,
EntityManagerFactoryInfo emfInfo , boolean containerManaged , boolean synchronizedWithTransaction ) {
Assert . notNull ( emfInfo , "EntityManagerFactoryInfo must not be null" ) ;
JpaDialect jpaDialect = emfInfo . getJpaDialect ( ) ;
@ -227,7 +267,7 @@ public abstract class ExtendedEntityManagerCreator {
@@ -227,7 +267,7 @@ public abstract class ExtendedEntityManagerCreator {
PersistenceUnitInfo pui = emfInfo . getPersistenceUnitInfo ( ) ;
Boolean jta = ( pui ! = null ? pui . getTransactionType ( ) = = PersistenceUnitTransactionType . JTA : null ) ;
return createProxy ( rawEntityManager , emfInfo . getEntityManagerInterface ( ) ,
emfInfo . getBeanClassLoader ( ) , plusOperations , jpaDialect , jta , containerManaged ) ;
emfInfo . getBeanClassLoader ( ) , plusOperations , jpaDialect , jta , containerManaged , synchronizedWithTransaction ) ;
}
/ * *
@ -242,12 +282,14 @@ public abstract class ExtendedEntityManagerCreator {
@@ -242,12 +282,14 @@ public abstract class ExtendedEntityManagerCreator {
* ( or { @code null } if not known in advance )
* @param containerManaged whether to follow container - managed EntityManager
* or application - managed EntityManager semantics
* @param synchronizedWithTransaction whether to automatically join ongoing
* transactions ( according to the JPA 2 . 1 SynchronizationType rules )
* @return the EntityManager proxy
* /
private static EntityManager createProxy (
EntityManager rawEm , Class < ? extends EntityManager > emIfc , ClassLoader cl ,
EntityManagerPlusOperations plusOperations , PersistenceExceptionTranslator exceptionTranslator ,
Boolean jta , boolean containerManaged ) {
Boolean jta , boolean containerManaged , boolean synchronizedWithTransaction ) {
Assert . notNull ( rawEm , "EntityManager must not be null" ) ;
Set < Class > ifcs = new LinkedHashSet < Class > ( ) ;
@ -265,7 +307,7 @@ public abstract class ExtendedEntityManagerCreator {
@@ -265,7 +307,7 @@ public abstract class ExtendedEntityManagerCreator {
( cl ! = null ? cl : ExtendedEntityManagerCreator . class . getClassLoader ( ) ) ,
ifcs . toArray ( new Class [ ifcs . size ( ) ] ) ,
new ExtendedEntityManagerInvocationHandler (
rawEm , plusOperations , exceptionTranslator , jta , containerManaged ) ) ;
rawEm , plusOperations , exceptionTranslator , jta , containerManaged , synchronizedWithTransaction ) ) ;
}
@ -283,19 +325,23 @@ public abstract class ExtendedEntityManagerCreator {
@@ -283,19 +325,23 @@ public abstract class ExtendedEntityManagerCreator {
private final PersistenceExceptionTranslator exceptionTranslator ;
private final boolean jta ;
private final boolean containerManaged ;
private boolean jta ;
private final boolean synchronizedWithTransaction ;
private ExtendedEntityManagerInvocationHandler (
EntityManager target , EntityManagerPlusOperations plusOperations ,
PersistenceExceptionTranslator exceptionTranslator , Boolean jta , boolean containerManaged ) {
PersistenceExceptionTranslator exceptionTranslator , Boolean jta ,
boolean containerManaged , boolean synchronizedWithTransaction ) {
this . target = target ;
this . plusOperations = plusOperations ;
this . exceptionTranslator = exceptionTranslator ;
this . jta = ( jta ! = null ? jta : isJtaEntityManager ( ) ) ;
this . containerManaged = containerManaged ;
this . synchronizedWithTransaction = synchronizedWithTransaction ;
}
private boolean isJtaEntityManager ( ) {
@ -340,20 +386,33 @@ public abstract class ExtendedEntityManagerCreator {
@@ -340,20 +386,33 @@ public abstract class ExtendedEntityManagerCreator {
if ( this . containerManaged ) {
throw new IllegalStateException ( "Invalid usage: Cannot close a container-managed EntityManager" ) ;
}
ExtendedEntityManagerSynchronization synch = ( ExtendedEntityManagerSynchronization )
TransactionSynchronizationManager . getResource ( this . target ) ;
if ( synch ! = null ) {
// Local transaction joined - don't actually call close() before transaction completion
synch . closeOnCompletion = true ;
return null ;
}
}
else if ( method . getName ( ) . equals ( "getTransaction" ) ) {
if ( this . containerManaged ) {
if ( this . synchronizedWithTransaction ) {
throw new IllegalStateException (
"Cannot execute getTransaction() on a container-managed EntityManager" ) ;
"Cannot obtain local EntityTransaction from a transaction-synchroniz ed EntityManager" ) ;
}
}
else if ( method . getName ( ) . equals ( "joinTransaction" ) ) {
doJoinTransaction ( true ) ;
return null ;
}
else if ( method . getName ( ) . equals ( "isJoinedToTransaction" ) ) {
// Handle JPA 2.1 isJoinedToTransaction method for the non-JTA case.
if ( ! this . jta ) {
return TransactionSynchronizationManager . hasResource ( this . target ) ;
}
}
// Do automatic joining if required.
if ( this . containerManaged & & method . getDeclaringClass ( ) . isInterface ( ) ) {
// Do automatic joining if required. Excludes toString, equals, hashCode calls.
if ( this . synchronizedWithTransaction & & method . getDeclaringClass ( ) . isInterface ( ) ) {
doJoinTransaction ( false ) ;
}
@ -416,18 +475,16 @@ public abstract class ExtendedEntityManagerCreator {
@@ -416,18 +475,16 @@ public abstract class ExtendedEntityManagerCreator {
* /
private void enlistInCurrentTransaction ( ) {
// Resource local transaction, need to acquire the EntityTransaction,
// start a transaction now and enlist a synchronization for
// commit or rollback later.
// start a transaction now and enlist a synchronization for commit or rollback later.
EntityTransaction et = this . target . getTransaction ( ) ;
et . begin ( ) ;
if ( logger . isDebugEnabled ( ) ) {
logger . debug ( "Starting resource local transaction on application-managed " +
logger . debug ( "Starting resource- local transaction on application-managed " +
"EntityManager [" + this . target + "]" ) ;
}
ExtendedEntityManagerSynchronization extendedEntityManagerSynchronization =
new ExtendedEntityManagerSynchronization ( this . target , this . exceptionTranslator ) ;
TransactionSynchronizationManager . bindResource ( this . target ,
extendedEntityManagerSynchronization ) ;
TransactionSynchronizationManager . bindResource ( this . target , extendedEntityManagerSynchronization ) ;
TransactionSynchronizationManager . registerSynchronization ( extendedEntityManagerSynchronization ) ;
}
}
@ -445,6 +502,8 @@ public abstract class ExtendedEntityManagerCreator {
@@ -445,6 +502,8 @@ public abstract class ExtendedEntityManagerCreator {
private final PersistenceExceptionTranslator exceptionTranslator ;
public volatile boolean closeOnCompletion = false ;
public ExtendedEntityManagerSynchronization (
EntityManager em , PersistenceExceptionTranslator exceptionTranslator ) {
super ( new EntityManagerHolder ( em ) , em ) ;
@ -453,7 +512,7 @@ public abstract class ExtendedEntityManagerCreator {
@@ -453,7 +512,7 @@ public abstract class ExtendedEntityManagerCreator {
}
public int getOrder ( ) {
return EntityManagerFactoryUtils . ENTITY_MANAGER_SYNCHRONIZATION_ORDER + 1 ;
return EntityManagerFactoryUtils . ENTITY_MANAGER_SYNCHRONIZATION_ORDER - 1 ;
}
@Override
@ -485,14 +544,21 @@ public abstract class ExtendedEntityManagerCreator {
@@ -485,14 +544,21 @@ public abstract class ExtendedEntityManagerCreator {
@Override
public void afterCompletion ( int status ) {
super . afterCompletion ( status ) ;
if ( status ! = STATUS_COMMITTED ) {
// Haven't had an afterCommit call: trigger a rollback.
try {
this . entityManager . getTransaction ( ) . rollback ( ) ;
try {
super . afterCompletion ( status ) ;
if ( status ! = STATUS_COMMITTED ) {
// Haven't had an afterCommit call: trigger a rollback.
try {
this . entityManager . getTransaction ( ) . rollback ( ) ;
}
catch ( RuntimeException ex ) {
throw convertException ( ex ) ;
}
}
catch ( RuntimeException ex ) {
throw convertException ( ex ) ;
}
finally {
if ( this . closeOnCompletion ) {
EntityManagerFactoryUtils . closeEntityManager ( this . entityManager ) ;
}
}
}