org.hibernate.bytecode.enhance.spi.interceptor.Helper Maven / Gradle / Ivy
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or .
*/
package org.hibernate.bytecode.enhance.spi.interceptor;
import java.util.Locale;
import org.hibernate.FlushMode;
import org.hibernate.LazyInitializationException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.SessionFactoryRegistry;
import org.jboss.logging.Logger;
/**
* @author Steve Ebersole
*/
public class Helper {
private static final Logger log = Logger.getLogger( Helper.class );
interface Consumer {
SharedSessionContractImplementor getLinkedSession();
boolean allowLoadOutsideTransaction();
String getSessionFactoryUuid();
}
interface LazyInitializationWork {
T doWork(SharedSessionContractImplementor session, boolean isTemporarySession);
// informational details
String getEntityName();
String getAttributeName();
}
private final Consumer consumer;
public Helper(Consumer consumer) {
this.consumer = consumer;
}
public T performWork(LazyInitializationWork lazyInitializationWork) {
SharedSessionContractImplementor session = consumer.getLinkedSession();
boolean isTempSession = false;
boolean isJta = false;
// first figure out which Session to use
if ( session == null ) {
if ( consumer.allowLoadOutsideTransaction() ) {
session = openTemporarySessionForLoading( lazyInitializationWork );
isTempSession = true;
}
else {
throwLazyInitializationException( Cause.NO_SESSION, lazyInitializationWork );
}
}
else if ( !session.isOpen() ) {
if ( consumer.allowLoadOutsideTransaction() ) {
session = openTemporarySessionForLoading( lazyInitializationWork );
isTempSession = true;
}
else {
throwLazyInitializationException( Cause.CLOSED_SESSION, lazyInitializationWork );
}
}
else if ( !session.isConnected() ) {
if ( consumer.allowLoadOutsideTransaction() ) {
session = openTemporarySessionForLoading( lazyInitializationWork );
isTempSession = true;
}
else {
throwLazyInitializationException( Cause.DISCONNECTED_SESSION, lazyInitializationWork );
}
}
// If we are using a temporary Session, begin a transaction if necessary
if ( isTempSession ) {
isJta = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta();
if ( !isJta ) {
// Explicitly handle the transactions only if we're not in
// a JTA environment. A lazy loading temporary session can
// be created even if a current session and transaction are
// open (ex: session.clear() was used). We must prevent
// multiple transactions.
session.beginTransaction();
}
}
try {
// do the actual work
return lazyInitializationWork.doWork( session, isTempSession );
}
finally {
if ( isTempSession ) {
try {
// Commit the JDBC transaction is we started one.
if ( !isJta ) {
session.getTransaction().commit();
}
}
catch (Exception e) {
log.warn(
"Unable to commit JDBC transaction on temporary session used to load lazy " +
"collection associated to no session"
);
}
// Close the just opened temp Session
try {
session.close();
}
catch (Exception e) {
log.warn( "Unable to close temporary session used to load lazy collection associated to no session" );
}
}
}
}
enum Cause {
NO_SESSION,
CLOSED_SESSION,
DISCONNECTED_SESSION,
NO_SF_UUID
}
private void throwLazyInitializationException(Cause cause, LazyInitializationWork work) {
final String reason;
switch ( cause ) {
case NO_SESSION: {
reason = "no session and settings disallow loading outside the Session";
break;
}
case CLOSED_SESSION: {
reason = "session is closed and settings disallow loading outside the Session";
break;
}
case DISCONNECTED_SESSION: {
reason = "session is disconnected and settings disallow loading outside the Session";
break;
}
case NO_SF_UUID: {
reason = "could not determine SessionFactory UUId to create temporary Session for loading";
break;
}
default: {
reason = "";
}
}
final String message = String.format(
Locale.ROOT,
"Unable to perform requested lazy initialization [%s.%s] - %s",
work.getEntityName(),
work.getAttributeName(),
reason
);
throw new LazyInitializationException( message );
}
private SharedSessionContractImplementor openTemporarySessionForLoading(LazyInitializationWork lazyInitializationWork) {
if ( consumer.getSessionFactoryUuid() == null ) {
throwLazyInitializationException( Cause.NO_SF_UUID, lazyInitializationWork );
}
final SessionFactoryImplementor sf = (SessionFactoryImplementor)
SessionFactoryRegistry.INSTANCE.getSessionFactory( consumer.getSessionFactoryUuid() );
final SharedSessionContractImplementor session = (SharedSessionContractImplementor) sf.openSession();
session.getPersistenceContext().setDefaultReadOnly( true );
session.setHibernateFlushMode( FlushMode.MANUAL );
return session;
}
}