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

org.hibernate.bytecode.enhance.spi.interceptor.Helper Maven / Gradle / Ivy

There is a newer version: 7.0.0.Alpha1
Show newest version
/*
 * 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;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy