alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (AbstractEntityManagerImpl.java)

This example Hibernate source code file (AbstractEntityManagerImpl.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

a, class, hibernateexception, hibernateexception, illegalargumentexception, illegalargumentexception, io, object, object, override, persistenceexception, string, t, transaction, util, x, x

The Hibernate AbstractEntityManagerImpl.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Inc.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program 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 distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 */
package org.hibernate.ejb;

import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import javax.persistence.EntityTransaction;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.LockTimeoutException;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceContextType;
import javax.persistence.PersistenceException;
import javax.persistence.PessimisticLockException;
import javax.persistence.PessimisticLockScope;
import javax.persistence.Query;
import javax.persistence.QueryTimeoutException;
import javax.persistence.TransactionRequiredException;
import javax.persistence.Tuple;
import javax.persistence.TupleElement;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Selection;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.spi.PersistenceUnitTransactionType;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionManager;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jboss.logging.Logger;

import org.hibernate.AssertionFailure;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.MappingException;
import org.hibernate.ObjectDeletedException;
import org.hibernate.ObjectNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.StaleStateException;
import org.hibernate.TransientObjectException;
import org.hibernate.TypeMismatchException;
import org.hibernate.UnresolvableObjectException;
import org.hibernate.cfg.Environment;
import org.hibernate.ejb.criteria.CriteriaQueryCompiler;
import org.hibernate.ejb.criteria.ValueHandlerFactory;
import org.hibernate.ejb.criteria.expression.CompoundSelectionImpl;
import org.hibernate.ejb.internal.EntityManagerMessageLogger;
import org.hibernate.ejb.util.CacheModeHelper;
import org.hibernate.ejb.util.ConfigurationHelper;
import org.hibernate.ejb.util.LockModeTypeHelper;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.HQLQueryPlan;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.spi.JoinStatus;
import org.hibernate.engine.transaction.spi.TransactionCoordinator;
import org.hibernate.engine.transaction.spi.TransactionImplementor;
import org.hibernate.engine.transaction.synchronization.spi.AfterCompletionAction;
import org.hibernate.engine.transaction.synchronization.spi.ExceptionMapper;
import org.hibernate.engine.transaction.synchronization.spi.ManagedFlushChecker;
import org.hibernate.engine.transaction.synchronization.spi.SynchronizationCallbackCoordinator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.service.jta.platform.spi.JtaPlatform;
import org.hibernate.transform.BasicTransformerAdapter;
import org.hibernate.type.Type;

/**
 * @author <a href="mailto:gavin@hibernate.org">Gavin King
 * @author Emmanuel Bernard
 * @author Steve Ebersole
 * @author Hardy Ferentschik
 */
@SuppressWarnings("unchecked")
public abstract class AbstractEntityManagerImpl implements HibernateEntityManagerImplementor, Serializable {

    private static final EntityManagerMessageLogger LOG = Logger.getMessageLogger(EntityManagerMessageLogger.class,
                                                                           AbstractEntityManagerImpl.class.getName());

	private static final List<String> entityManagerSpecificProperties = new ArrayList();

	static {
		entityManagerSpecificProperties.add( AvailableSettings.LOCK_SCOPE );
		entityManagerSpecificProperties.add( AvailableSettings.LOCK_TIMEOUT );
		entityManagerSpecificProperties.add( AvailableSettings.FLUSH_MODE );
		entityManagerSpecificProperties.add( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
		entityManagerSpecificProperties.add( AvailableSettings.SHARED_CACHE_STORE_MODE );
		entityManagerSpecificProperties.add( QueryHints.SPEC_HINT_TIMEOUT );
	}

	private EntityManagerFactoryImpl entityManagerFactory;
	protected transient TransactionImpl tx = new TransactionImpl( this );
	protected PersistenceContextType persistenceContextType;
	private PersistenceUnitTransactionType transactionType;
	private Map<String, Object> properties;
	private LockOptions lockOptions;

	protected AbstractEntityManagerImpl(
			EntityManagerFactoryImpl entityManagerFactory,
			PersistenceContextType type,
			PersistenceUnitTransactionType transactionType,
			Map properties) {
		this.entityManagerFactory = entityManagerFactory;
		this.persistenceContextType = type;
		this.transactionType = transactionType;

		this.lockOptions = new LockOptions();
		this.properties = new HashMap<String, Object>();
		if ( properties != null ) {
			for ( String key : entityManagerSpecificProperties ) {
				if ( properties.containsKey( key ) ) {
					this.properties.put( key, properties.get( key ) );
				}
			}
		}
	}

	public PersistenceUnitTransactionType getTransactionType() {
		return transactionType;
	}

	protected void postInit() {
		//register in Sync if needed
		if ( PersistenceUnitTransactionType.JTA.equals( transactionType ) ) {
			joinTransaction( false );
		}

		setDefaultProperties();
		applyProperties();
	}

	private void applyProperties() {
		getSession().setFlushMode( ConfigurationHelper.getFlushMode( properties.get( AvailableSettings.FLUSH_MODE ) ) );
		setLockOptions( this.properties, this.lockOptions );
		getSession().setCacheMode(
				CacheModeHelper.interpretCacheMode(
						currentCacheStoreMode(),
						currentCacheRetrieveMode()
				)
		);
	}

	private Query applyProperties(Query query) {
		if ( lockOptions.getLockMode() != LockMode.NONE ) {
			query.setLockMode( getLockMode(lockOptions.getLockMode()));
		}
		Object queryTimeout;
		if ( (queryTimeout = getProperties().get(QueryHints.SPEC_HINT_TIMEOUT)) != null ) {
			query.setHint ( QueryHints.SPEC_HINT_TIMEOUT, queryTimeout );
		}
		return query;
	}

	private CacheRetrieveMode currentCacheRetrieveMode() {
		return determineCacheRetrieveMode( properties );
	}

	private CacheRetrieveMode determineCacheRetrieveMode(Map<String, Object> settings) {
		return ( CacheRetrieveMode ) settings.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE );
	}

	private CacheStoreMode currentCacheStoreMode() {
		return determineCacheStoreMode( properties );
	}

	private CacheStoreMode determineCacheStoreMode(Map<String, Object> settings) {
		return ( CacheStoreMode ) properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE );
	}

	private void setLockOptions(Map<String, Object> props, LockOptions options) {
		Object lockScope = props.get( AvailableSettings.LOCK_SCOPE );
		if ( lockScope instanceof String && PessimisticLockScope.valueOf( ( String ) lockScope ) == PessimisticLockScope.EXTENDED ) {
			options.setScope( true );
		}
		else if ( lockScope instanceof PessimisticLockScope ) {
			boolean extended = PessimisticLockScope.EXTENDED.equals( lockScope );
			options.setScope( extended );
		}
		else if ( lockScope != null ) {
			throw new PersistenceException( "Unable to parse " + AvailableSettings.LOCK_SCOPE + ": " + lockScope );
		}

		Object lockTimeout = props.get( AvailableSettings.LOCK_TIMEOUT );
		int timeout = 0;
		boolean timeoutSet = false;
		if ( lockTimeout instanceof String ) {
			timeout = Integer.parseInt( ( String ) lockTimeout );
			timeoutSet = true;
		}
		else if ( lockTimeout instanceof Number ) {
			timeout = ( (Number) lockTimeout ).intValue();
			timeoutSet = true;
		}
		else if ( lockTimeout != null ) {
			throw new PersistenceException( "Unable to parse " + AvailableSettings.LOCK_TIMEOUT + ": " + lockTimeout );
		}
		if ( timeoutSet ) {
			if ( timeout < 0 ) {
				options.setTimeOut( LockOptions.WAIT_FOREVER );
			}
			else if ( timeout == 0 ) {
				options.setTimeOut( LockOptions.NO_WAIT );
			}
			else {
				options.setTimeOut( timeout );
			}
		}
	}

	/**
	 * Sets the default property values for the properties the entity manager supports and which are not already explicitly
	 * set.
	 */
	private void setDefaultProperties() {
		if ( properties.get( AvailableSettings.FLUSH_MODE ) == null ) {
			properties.put( AvailableSettings.FLUSH_MODE, getSession().getFlushMode().toString() );
		}
		if ( properties.get( AvailableSettings.LOCK_SCOPE ) == null ) {
			this.properties.put( AvailableSettings.LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() );
		}
		if ( properties.get( AvailableSettings.LOCK_TIMEOUT ) == null ) {
			properties.put( AvailableSettings.LOCK_TIMEOUT, LockOptions.WAIT_FOREVER );
		}
		if ( properties.get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) == null ) {
			properties.put( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE );
		}
		if ( properties.get( AvailableSettings.SHARED_CACHE_STORE_MODE ) == null ) {
			properties.put( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE );
		}
	}

	public Query createQuery(String jpaqlString) {
		try {
			return applyProperties( new QueryImpl<Object>( getSession().createQuery( jpaqlString ), this ) );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public <T> TypedQuery createQuery(String jpaqlString, Class resultClass) {
		try {
			// do the translation
			org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );

			// do some validation checking
			if ( Object[].class.equals( resultClass ) ) {
				// no validation needed
			}
			else if ( Tuple.class.equals( resultClass ) ) {
				TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( hqlQuery );
				hqlQuery.setResultTransformer( tupleTransformer  );
			}
			else {
				final HQLQueryPlan queryPlan = unwrap( SessionImplementor.class )
						.getFactory()
						.getQueryPlanCache()
						.getHQLQueryPlan( jpaqlString, false, null );
				final Class dynamicInstantiationClass = queryPlan.getDynamicInstantiationResultType();
				if ( dynamicInstantiationClass != null ) {
					if ( ! resultClass.isAssignableFrom( dynamicInstantiationClass ) ) {
						throw new IllegalArgumentException(
								"Mismatch in requested result type [" + resultClass.getName() +
										"] and actual result type [" + dynamicInstantiationClass.getName() + "]"
						);
					}
				}
				else if ( hqlQuery.getReturnTypes().length == 1 ) {
					// if we have only a single return expression, its java type should match with the requested type
					if ( !resultClass.isAssignableFrom( hqlQuery.getReturnTypes()[0].getReturnedClass() ) ) {
						throw new IllegalArgumentException(
								"Type specified for TypedQuery [" +
										resultClass.getName() +
										"] is incompatible with query return type [" +
										hqlQuery.getReturnTypes()[0].getReturnedClass() + "]"
						);
					}
				}
				else {
					throw new IllegalArgumentException(
							"Cannot create TypedQuery for query with more than one return using requested result type [" +
									resultClass.getName() + "]"
					);
				}
			}

			// finally, build/return the query instance
			return new QueryImpl<T>( hqlQuery, this );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public static class TupleBuilderTransformer extends BasicTransformerAdapter {
		private List<TupleElement tupleElements;
		private Map<String,HqlTupleElementImpl> tupleElementsByAlias;

		public TupleBuilderTransformer(org.hibernate.Query hqlQuery) {
			final Type[] resultTypes = hqlQuery.getReturnTypes();
			final int tupleSize = resultTypes.length;

			this.tupleElements = CollectionHelper.arrayList( tupleSize );

			final String[] aliases = hqlQuery.getReturnAliases();
			final boolean hasAliases = aliases != null && aliases.length > 0;
			this.tupleElementsByAlias = hasAliases
					? CollectionHelper.<String, HqlTupleElementImpl>mapOfSize( tupleSize )
					: Collections.<String, HqlTupleElementImpl>emptyMap();

			for ( int i = 0; i < tupleSize; i++ ) {
				final HqlTupleElementImpl tupleElement = new HqlTupleElementImpl(
						i,
						aliases == null ? null : aliases[i],
						resultTypes[i]
				);
				tupleElements.add( tupleElement );
				if ( hasAliases ) {
					final String alias = aliases[i];
					if ( alias != null ) {
						tupleElementsByAlias.put( alias, tupleElement );
					}
				}
			}
		}

		@Override
		public Object transformTuple(Object[] tuple, String[] aliases) {
			if ( tuple.length != tupleElements.size() ) {
				throw new IllegalArgumentException(
						"Size mismatch between tuple result [" + tuple.length + "] and expected tuple elements [" +
								tupleElements.size() + "]"
				);
			}
			return new HqlTupleImpl( tuple );
		}

		public static class HqlTupleElementImpl<X> implements TupleElement {
			private final int position;
			private final String alias;
			private final Type hibernateType;

			public HqlTupleElementImpl(int position, String alias, Type hibernateType) {
				this.position = position;
				this.alias = alias;
				this.hibernateType = hibernateType;
			}

			@Override
			public Class getJavaType() {
				return hibernateType.getReturnedClass();
			}

			@Override
			public String getAlias() {
				return alias;
			}

			public int getPosition() {
				return position;
			}

			public Type getHibernateType() {
				return hibernateType;
			}
		}

		public class HqlTupleImpl implements Tuple {
			private Object[] tuple;

			public HqlTupleImpl(Object[] tuple) {
				this.tuple = tuple;
			}

			@Override
			public <X> X get(String alias, Class type) {
				return (X) get( alias );
			}

			@Override
			public Object get(String alias) {
				HqlTupleElementImpl tupleElement = tupleElementsByAlias.get( alias );
				if ( tupleElement == null ) {
					throw new IllegalArgumentException( "Unknown alias [" + alias + "]" );
				}
				return tuple[ tupleElement.getPosition() ];
			}

			@Override
			public <X> X get(int i, Class type) {
				return (X) get( i );
			}

			@Override
			public Object get(int i) {
				if ( i < 0 ) {
					throw new IllegalArgumentException( "requested tuple index must be greater than zero" );
				}
				if ( i > tuple.length ) {
					throw new IllegalArgumentException( "requested tuple index exceeds actual tuple size" );
				}
				return tuple[i];
			}

			@Override
			public Object[] toArray() {
				// todo : make a copy?
				return tuple;
			}

			@Override
			public List<TupleElement getElements() {
				return tupleElements;
			}

			@Override
			public <X> X get(TupleElement tupleElement) {
				if ( HqlTupleElementImpl.class.isInstance( tupleElement ) ) {
					return get( ( (HqlTupleElementImpl) tupleElement ).getPosition(), tupleElement.getJavaType() );
				}
				else {
					return get( tupleElement.getAlias(), tupleElement.getJavaType() );
				}
			}
		}
	}

	public <T> TypedQuery createQuery(
			String jpaqlString,
			Class<T> resultClass,
			Selection selection,
			Options options) {
		try {
			org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );

			if ( options.getValueHandlers() == null ) {
				options.getResultMetadataValidator().validate( hqlQuery.getReturnTypes() );
			}

			// determine if we need a result transformer
			List tupleElements = Tuple.class.equals( resultClass )
					? ( ( CompoundSelectionImpl<Tuple> ) selection ).getCompoundSelectionItems()
					: null;
			if ( options.getValueHandlers() != null || tupleElements != null ) {
				hqlQuery.setResultTransformer(
						new CriteriaQueryTransformer( options.getValueHandlers(), tupleElements )
				);
			}
			return new QueryImpl<T>( hqlQuery, this, options.getNamedParameterExplicitTypes() );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	private static class CriteriaQueryTransformer extends BasicTransformerAdapter {
		private final List<ValueHandlerFactory.ValueHandler> valueHandlers;
		private final List tupleElements;

		private CriteriaQueryTransformer(List<ValueHandlerFactory.ValueHandler> valueHandlers, List tupleElements) {
			// todo : should these 2 sizes match *always*?
			this.valueHandlers = valueHandlers;
			this.tupleElements = tupleElements;
		}

		@Override
		public Object transformTuple(Object[] tuple, String[] aliases) {
			final Object[] valueHandlerResult;
			if ( valueHandlers == null ) {
				valueHandlerResult = tuple;
			}
			else {
				valueHandlerResult = new Object[tuple.length];
				for ( int i = 0; i < tuple.length; i++ ) {
					ValueHandlerFactory.ValueHandler valueHandler = valueHandlers.get( i );
					valueHandlerResult[i] = valueHandler == null
							? tuple[i]
							: valueHandler.convert( tuple[i] );
				}
			}

			return tupleElements == null
					? valueHandlerResult.length == 1 ? valueHandlerResult[0] : valueHandlerResult
					: new TupleImpl( tuple );

		}

		private class TupleImpl implements Tuple {
			private final Object[] tuples;

			private TupleImpl(Object[] tuples) {
				if ( tuples.length != tupleElements.size() ) {
					throw new IllegalArgumentException(
							"Size mismatch between tuple result [" + tuples.length
									+ "] and expected tuple elements [" + tupleElements.size() + "]"
					);
				}
				this.tuples = tuples;
			}

			public <X> X get(TupleElement tupleElement) {
				int index = tupleElements.indexOf( tupleElement );
				if ( index < 0 ) {
					throw new IllegalArgumentException(
							"Requested tuple element did not correspond to element in the result tuple"
					);
				}
				// index should be "in range" by nature of size check in ctor
				return ( X ) tuples[index];
			}

			public Object get(String alias) {
				int index = -1;
				if ( alias != null ) {
					alias = alias.trim();
					if ( alias.length() > 0 ) {
						int i = 0;
						for ( TupleElement selection : ( List<TupleElement> ) tupleElements ) {
							if ( alias.equals( selection.getAlias() ) ) {
								index = i;
								break;
							}
							i++;
						}
					}
				}
				if ( index < 0 ) {
					throw new IllegalArgumentException(
							"Given alias [" + alias + "] did not correspond to an element in the result tuple"
					);
				}
				// index should be "in range" by nature of size check in ctor
				return tuples[index];
			}

			public <X> X get(String alias, Class type) {
				return ( X ) get( alias );
			}

			public Object get(int i) {
				if ( i >= tuples.length ) {
					throw new IllegalArgumentException(
							"Given index [" + i + "] was outside the range of result tuple size [" + tuples.length + "] "
					);
				}
				return tuples[i];
			}

			public <X> X get(int i, Class type) {
				return ( X ) get( i );
			}

			public Object[] toArray() {
				return tuples;
			}

			public List<TupleElement getElements() {
				return tupleElements;
			}
		}
	}

	private CriteriaQueryCompiler criteriaQueryCompiler;

	public <T> TypedQuery createQuery(CriteriaQuery criteriaQuery) {
		if ( criteriaQueryCompiler == null ) {
			criteriaQueryCompiler = new CriteriaQueryCompiler( this );
		}
		return criteriaQueryCompiler.compile( criteriaQuery );
	}

	public Query createNamedQuery(String name) {
		try {
			org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
			try {
				return new QueryImpl( namedQuery, this );
			}
			catch ( HibernateException he ) {
				throw convert( he );
			}
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( "Named query not found: " + name );
		}
	}

	public <T> TypedQuery createNamedQuery(String name, Class resultClass) {
		try {
			/*
			 * Get the named query.
			 * If the named query is a SQL query, get the expected returned type from the query definition
			 * or its associated result set mapping
			 * If the named query is a HQL query, use getReturnType()
			 */
			org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
			//TODO clean this up to avoid downcasting
			final SessionFactoryImplementor factoryImplementor = ( SessionFactoryImplementor ) entityManagerFactory.getSessionFactory();
			final NamedSQLQueryDefinition queryDefinition = factoryImplementor.getNamedSQLQuery( name );
			try {
				if ( queryDefinition != null ) {
					Class<?> actualReturnedClass;

					final NativeSQLQueryReturn[] queryReturns;
					if ( queryDefinition.getQueryReturns() != null ) {
						queryReturns = queryDefinition.getQueryReturns();
					}
					else if ( queryDefinition.getResultSetRef() != null ) {
						final ResultSetMappingDefinition rsMapping = factoryImplementor.getResultSetMapping(
								queryDefinition.getResultSetRef()
						);
						queryReturns = rsMapping.getQueryReturns();
					}
					else {
						throw new AssertionFailure( "Unsupported named query model. Please report the bug in Hibernate EntityManager");
					}
					if ( queryReturns.length > 1 ) {
						throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
					}
					final NativeSQLQueryReturn nativeSQLQueryReturn = queryReturns[0];
					if ( nativeSQLQueryReturn instanceof NativeSQLQueryRootReturn ) {
						final String entityClassName = ( ( NativeSQLQueryRootReturn ) nativeSQLQueryReturn ).getReturnEntityName();
						try {
							actualReturnedClass = ReflectHelper.classForName( entityClassName, AbstractEntityManagerImpl.class );
						}
						catch ( ClassNotFoundException e ) {
							throw new AssertionFailure( "Unable to instantiate class declared on named native query: " + name + " " + entityClassName );
						}
						if ( !resultClass.isAssignableFrom( actualReturnedClass ) ) {
							throw buildIncompatibleException( resultClass, actualReturnedClass );
						}
					}
					else {
						//TODO support other NativeSQLQueryReturn type. For now let it go.
					}
				}
				else {
					if ( namedQuery.getReturnTypes().length != 1 ) {
						throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
					}
					if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
						throw buildIncompatibleException( resultClass, namedQuery.getReturnTypes()[0].getReturnedClass() );
					}
				}
				return new QueryImpl<T>( namedQuery, this );
			}
			catch ( HibernateException he ) {
				throw convert( he );
			}
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( "Named query not found: " + name );
		}
	}

	private IllegalArgumentException buildIncompatibleException(Class<?> resultClass, Class actualResultClass) {
		return new IllegalArgumentException(
							"Type specified for TypedQuery [" +
									resultClass.getName() +
									"] is incompatible with query return type [" +
									actualResultClass + "]"
					);
	}

	public Query createNativeQuery(String sqlString) {
		try {
			SQLQuery q = getSession().createSQLQuery( sqlString );
			return new QueryImpl( q, this );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public Query createNativeQuery(String sqlString, Class resultClass) {
		try {
			SQLQuery q = getSession().createSQLQuery( sqlString );
			q.addEntity( "alias1", resultClass.getName(), LockMode.READ );
			return new QueryImpl( q, this );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public Query createNativeQuery(String sqlString, String resultSetMapping) {
		try {
			SQLQuery q = getSession().createSQLQuery( sqlString );
			q.setResultSetMapping( resultSetMapping );
			return new QueryImpl( q, this );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	@SuppressWarnings("unchecked")
	public <T> T getReference(Class entityClass, Object primaryKey) {
		try {
			return ( T ) getSession().load( entityClass, ( Serializable ) primaryKey );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( TypeMismatchException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( ClassCastException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	@SuppressWarnings("unchecked")
	public <A> A find(Class entityClass, Object primaryKey) {
		return find( entityClass, primaryKey, null, null );
	}

	public <T> T find(Class entityClass, Object primaryKey, Map properties) {
		return find( entityClass, primaryKey, null, properties );
	}

	@SuppressWarnings("unchecked")
	public <A> A find(Class entityClass, Object primaryKey, LockModeType lockModeType) {
		return find( entityClass, primaryKey, lockModeType, null );
	}

	public <A> A find(Class entityClass, Object primaryKey, LockModeType lockModeType, Map properties) {
		CacheMode previousCacheMode = getSession().getCacheMode();
		CacheMode cacheMode = determineAppropriateLocalCacheMode( properties );
		LockOptions lockOptions = null;
		try {
			getSession().setCacheMode( cacheMode );
			if ( lockModeType != null ) {
				return ( A ) getSession().get(
						entityClass, ( Serializable ) primaryKey,
						getLockRequest( lockModeType, properties )
				);
			}
			else {
				return ( A ) getSession().get( entityClass, ( Serializable ) primaryKey );
			}
		}
		catch ( ObjectDeletedException e ) {
			//the spec is silent about people doing remove() find() on the same PC
			return null;
		}
		catch ( ObjectNotFoundException e ) {
			//should not happen on the entity itself with get
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( TypeMismatchException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( ClassCastException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( HibernateException he ) {
			throw convert( he, lockOptions );
		}
		finally {
			getSession().setCacheMode( previousCacheMode );
		}
	}

	public CacheMode determineAppropriateLocalCacheMode(Map<String, Object> localProperties) {
		CacheRetrieveMode retrieveMode = null;
		CacheStoreMode storeMode = null;
		if ( localProperties != null ) {
			retrieveMode = determineCacheRetrieveMode( localProperties );
			storeMode = determineCacheStoreMode( localProperties );
		}
		if ( retrieveMode == null ) {
			// use the EM setting
			retrieveMode = determineCacheRetrieveMode( this.properties );
		}
		if ( storeMode == null ) {
			// use the EM setting
			storeMode = determineCacheStoreMode( this.properties );
		}
		return CacheModeHelper.interpretCacheMode( storeMode, retrieveMode );
	}

	private void checkTransactionNeeded() {
		if ( persistenceContextType == PersistenceContextType.TRANSACTION && !isTransactionInProgress() ) {
			//no need to mark as rollback, no tx in progress
			throw new TransactionRequiredException(
					"no transaction is in progress for a TRANSACTION type persistence context"
			);
		}
	}

	public void persist(Object entity) {
		checkTransactionNeeded();
		try {
			getSession().persist( entity );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage() );
		}
		catch ( RuntimeException e ) {
			throw convert( e );
		}
	}

	@SuppressWarnings("unchecked")
	public <A> A merge(A entity) {
		checkTransactionNeeded();
		try {
			return ( A ) getSession().merge( entity );
		}
		catch ( ObjectDeletedException sse ) {
			throw new IllegalArgumentException( sse );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( RuntimeException e ) { //including HibernateException
			throw convert( e );
		}
	}

	public void remove(Object entity) {
		checkTransactionNeeded();
		try {
			getSession().delete( entity );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( RuntimeException e ) { //including HibernateException
			throw convert( e );
		}
	}

	public void refresh(Object entity) {
		refresh( entity, null, null );
	}

	public void refresh(Object entity, Map<String, Object> properties) {
		refresh( entity, null, properties );
	}

	public void refresh(Object entity, LockModeType lockModeType) {
		refresh( entity, lockModeType, null );
	}

	public void refresh(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
		checkTransactionNeeded();
		CacheMode previousCacheMode = getSession().getCacheMode();
		CacheMode localCacheMode = determineAppropriateLocalCacheMode( properties );
		LockOptions lockOptions = null;
		try {
			getSession().setCacheMode( localCacheMode );
			if ( !getSession().contains( entity ) ) {
				throw new IllegalArgumentException( "Entity not managed" );
			}
			if ( lockModeType != null ) {
				getSession().refresh( entity, ( lockOptions = getLockRequest( lockModeType, properties ) ) );
			}
			else {
				getSession().refresh( entity );
			}
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( HibernateException he ) {
			throw convert( he, lockOptions );
		}
		finally {
			getSession().setCacheMode( previousCacheMode );
		}
	}

	public boolean contains(Object entity) {
		try {
			if ( entity != null
					&& !( entity instanceof HibernateProxy )
					&& getSession().getSessionFactory().getClassMetadata( entity.getClass() ) == null ) {
				throw new IllegalArgumentException( "Not an entity:" + entity.getClass() );
			}
			return getSession().contains( entity );
		}
		catch ( MappingException e ) {
			throw new IllegalArgumentException( e.getMessage(), e );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public LockModeType getLockMode(Object entity) {
		if ( !contains( entity ) ) {
			throw new IllegalArgumentException( "entity not in the persistence context" );
		}
		return getLockModeType( getSession().getCurrentLockMode( entity ) );
	}

	public void setProperty(String s, Object o) {
		if ( entityManagerSpecificProperties.contains( s ) ) {
			properties.put( s, o );
			applyProperties();
        } else LOG.debugf("Trying to set a property which is not supported on entity manager level");
	}

	public Map<String, Object> getProperties() {
		return Collections.unmodifiableMap( properties );
	}

	public void flush() {
		if ( !isTransactionInProgress() ) {
			throw new TransactionRequiredException( "no transaction is in progress" );
		}
		try {
			getSession().flush();
		}
		catch ( RuntimeException e ) {
			throw convert( e );
		}
	}

	/**
	 * return a Session
	 *
	 * @throws IllegalStateException if the entity manager is closed
	 */
	public abstract Session getSession();

	/**
	 * Return a Session (even if the entity manager is closed).
	 *
	 * @return A session.
	 */
	protected abstract Session getRawSession();

	public EntityTransaction getTransaction() {
		if ( transactionType == PersistenceUnitTransactionType.JTA ) {
			throw new IllegalStateException( "A JTA EntityManager cannot use getTransaction()" );
		}
		return tx;
	}

	/**
	 * {@inheritDoc}
	 */
	public EntityManagerFactoryImpl getEntityManagerFactory() {
		return entityManagerFactory;
	}

	/**
	 * {@inheritDoc}
	 */
	public HibernateEntityManagerFactory getFactory() {
		return entityManagerFactory;
	}

	/**
	 * {@inheritDoc}
	 */
	public CriteriaBuilder getCriteriaBuilder() {
		return getEntityManagerFactory().getCriteriaBuilder();
	}

	/**
	 * {@inheritDoc}
	 */
	public Metamodel getMetamodel() {
		return getEntityManagerFactory().getMetamodel();
	}

	public void setFlushMode(FlushModeType flushModeType) {
		if ( flushModeType == FlushModeType.AUTO ) {
			getSession().setFlushMode( FlushMode.AUTO );
		}
		else if ( flushModeType == FlushModeType.COMMIT ) {
			getSession().setFlushMode( FlushMode.COMMIT );
		}
		else {
			throw new AssertionFailure( "Unknown FlushModeType: " + flushModeType );
		}
	}

	public void clear() {
		try {
			getSession().clear();
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	public void detach(Object entity) {
		try {
			getSession().evict( entity );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	/**
	 * Hibernate can be set in various flush modes that are unknown to
	 * JPA 2.0. This method can then return null.
	 * If it returns null, do em.unwrap(Session.class).getFlushMode() to get the
	 * Hibernate flush mode
	 */
	public FlushModeType getFlushMode() {
		FlushMode mode = getSession().getFlushMode();
		if ( mode == FlushMode.AUTO ) {
			return FlushModeType.AUTO;
		}
		else if ( mode == FlushMode.COMMIT ) {
			return FlushModeType.COMMIT;
		}
		else {
			// otherwise this is an unknown mode for EJB3
			return null;
		}
	}

	public void lock(Object entity, LockModeType lockMode) {
		lock( entity, lockMode, null );
	}

	public void lock(Object entity, LockModeType lockModeType, Map<String, Object> properties) {
		LockOptions lockOptions = null;
		if ( !isTransactionInProgress() ) {
			throw new TransactionRequiredException( "no transaction is in progress" );
		}

		try {
			if ( !contains( entity ) ) {
				throw new IllegalArgumentException( "entity not in the persistence context" );
			}
			getSession().buildLockRequest( ( lockOptions = getLockRequest( lockModeType, properties ) ) )
					.lock( entity );
		}
		catch ( HibernateException he ) {
			throw convert( he, lockOptions );
		}
	}

	public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties) {
		LockOptions lockOptions = new LockOptions();
		LockOptions.copy( this.lockOptions, lockOptions );
		lockOptions.setLockMode( getLockMode( lockModeType ) );
		if ( properties != null ) {
			setLockOptions( properties, lockOptions );
		}
		return lockOptions;
	}

	@SuppressWarnings("deprecation")
	private static LockModeType getLockModeType(LockMode lockMode) {
		//TODO check that if we have UPGRADE_NOWAIT we have a timeout of zero?
		return LockModeTypeHelper.getLockModeType( lockMode );
	}


	private static LockMode getLockMode(LockModeType lockMode) {
		return LockModeTypeHelper.getLockMode( lockMode );
	}

	public boolean isTransactionInProgress() {
		return ( ( SessionImplementor ) getRawSession() ).isTransactionInProgress();
	}

	private SessionFactoryImplementor sfi() {
		return (SessionFactoryImplementor) getRawSession().getSessionFactory();
	}

	protected void markAsRollback() {
        LOG.debugf("Mark transaction for rollback");
		if ( tx.isActive() ) {
			tx.setRollbackOnly();
		}
		else {
			//no explicit use of the tx. boundaries methods
			if ( PersistenceUnitTransactionType.JTA == transactionType ) {
				TransactionManager transactionManager = sfi().getServiceRegistry().getService( JtaPlatform.class ).retrieveTransactionManager();
				if ( transactionManager == null ) {
					throw new PersistenceException(
							"Using a JTA persistence context wo setting hibernate.transaction.manager_lookup_class"
					);
				}
				try {
                    if ( transactionManager.getStatus() != Status.STATUS_NO_TRANSACTION ) {
                        transactionManager.setRollbackOnly();
                    }
				}
				catch ( SystemException e ) {
					throw new PersistenceException( "Unable to set the JTA transaction as RollbackOnly", e );
				}
			}
		}
	}

	public void joinTransaction() {
		if( !isOpen() ){
			throw new IllegalStateException( "EntityManager is closed" );
		}
		joinTransaction( true );
	}

	public <T> T unwrap(Class clazz) {
		if ( Session.class.isAssignableFrom( clazz ) ) {
			return ( T ) getSession();
		}
		if ( SessionImplementor.class.isAssignableFrom( clazz ) ) {
			return ( T ) getSession();
		}
		if ( EntityManager.class.isAssignableFrom( clazz ) ) {
			return ( T ) this;
		}
		throw new PersistenceException( "Hibernate cannot unwrap " + clazz );
	}

	private void joinTransaction(boolean explicitRequest) {
		if ( transactionType != PersistenceUnitTransactionType.JTA ) {
			if ( explicitRequest ) {
			    LOG.callingJoinTransactionOnNonJtaEntityManager();
			}
			return;
		}

		final SessionImplementor session = (SessionImplementor) getSession();
		final TransactionCoordinator transactionCoordinator = session.getTransactionCoordinator();
		final TransactionImplementor transaction = transactionCoordinator.getTransaction();

		transaction.markForJoin();
		transactionCoordinator.pulse();

		LOG.debug( "Looking for a JTA transaction to join" );
		if ( ! transactionCoordinator.isTransactionJoinable() ) {
			if ( explicitRequest ) {
				// if this is an explicit join request, log a warning so user can track underlying cause
				// of subsequent exceptions/messages
				LOG.unableToJoinTransaction(Environment.TRANSACTION_STRATEGY);
			}
		}

		try {
			if ( transaction.getJoinStatus() == JoinStatus.JOINED ) {
				LOG.debug( "Transaction already joined" );
				return; // noop
			}

			// join the transaction and then recheck the status
			transaction.join();
			if ( transaction.getJoinStatus() == JoinStatus.NOT_JOINED ) {
				if ( explicitRequest ) {
					throw new TransactionRequiredException( "No active JTA transaction on joinTransaction call" );
				}
				else {
					LOG.debug( "Unable to join JTA transaction" );
					return;
				}
			}
			else if ( transaction.getJoinStatus() == JoinStatus.MARKED_FOR_JOINED ) {
				throw new AssertionFailure( "Transaction MARKED_FOR_JOINED after isOpen() call" );
			}

			// register behavior changes
			SynchronizationCallbackCoordinator callbackCoordinator = transactionCoordinator.getSynchronizationCallbackCoordinator();
			callbackCoordinator.setManagedFlushChecker( new ManagedFlushCheckerImpl() );
			callbackCoordinator.setExceptionMapper( new CallbackExceptionMapperImpl() );
			callbackCoordinator.setAfterCompletionAction( new AfterCompletionActionImpl( session, transactionType ) );
		}
		catch ( HibernateException he ) {
			throw convert( he );
		}
	}

	/**
	 * returns the underlying session
	 */
	public Object getDelegate() {
		return getSession();
	}

	private void writeObject(ObjectOutputStream oos) throws IOException {
		oos.defaultWriteObject();
	}

	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
		ois.defaultReadObject();
		tx = new TransactionImpl( this );
	}

	/**
	 * {@inheritDoc}
	 */
	public void handlePersistenceException(PersistenceException e) {
		if ( e instanceof NoResultException ) {
			return;
		}
		if ( e instanceof NonUniqueResultException ) {
			return;
		}
		if ( e instanceof LockTimeoutException ) {
			return;
		}
		if ( e instanceof QueryTimeoutException ) {
			return;
		}

		try {
			markAsRollback();
		}
		catch ( Exception ne ) {
			//we do not want the subsequent exception to swallow the original one
            LOG.unableToMarkForRollbackOnPersistenceException(ne);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void throwPersistenceException(PersistenceException e) {
		handlePersistenceException( e );
		throw e;
	}

	/**
	 * {@inheritDoc}
	 */
	//FIXME should we remove all calls to this method and use convert(RuntimeException) ?
	public RuntimeException convert(HibernateException e) {
		return convert( e, null );
	}

	public RuntimeException convert(RuntimeException e) {
		RuntimeException result = e;
		if ( e instanceof HibernateException ) {
			result = convert( ( HibernateException ) e );
		}
		else {
			markAsRollback();
		}
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public RuntimeException convert(HibernateException e, LockOptions lockOptions) {
		if ( e instanceof StaleStateException ) {
			PersistenceException converted = wrapStaleStateException( ( StaleStateException ) e );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof org.hibernate.OptimisticLockException ) {
			PersistenceException converted = wrapLockException( e, lockOptions );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof org.hibernate.PessimisticLockException ) {
			PersistenceException converted = wrapLockException( e, lockOptions );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof org.hibernate.QueryTimeoutException ) {
			QueryTimeoutException converted = new QueryTimeoutException(e.getMessage(), e);
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof ObjectNotFoundException ) {
			EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof org.hibernate.NonUniqueResultException ) {
			NonUniqueResultException converted = new NonUniqueResultException( e.getMessage() );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof UnresolvableObjectException ) {
			EntityNotFoundException converted = new EntityNotFoundException( e.getMessage() );
			handlePersistenceException( converted );
			return converted;
		}
		else if ( e instanceof QueryException ) {
			return new IllegalArgumentException( e );
		}
		else if ( e instanceof TransientObjectException ) {
			try {
				markAsRollback();
			}
			catch ( Exception ne ) {
				//we do not want the subsequent exception to swallow the original one
                LOG.unableToMarkForRollbackOnTransientObjectException(ne);
			}
			return new IllegalStateException( e ); //Spec 3.2.3 Synchronization rules
		}
		else {
			PersistenceException converted = new PersistenceException( e );
			handlePersistenceException( converted );
			return converted;
		}
	}

	/**
	 * {@inheritDoc}
	 */
	public void throwPersistenceException(HibernateException e) {
		throw convert( e );
	}

	/**
	 * {@inheritDoc}
	 */
	public PersistenceException wrapStaleStateException(StaleStateException e) {
		PersistenceException pe;
		if ( e instanceof StaleObjectStateException ) {
			StaleObjectStateException sose = ( StaleObjectStateException ) e;
			Serializable identifier = sose.getIdentifier();
			if ( identifier != null ) {
				try {
					Object entity = getRawSession().load( sose.getEntityName(), identifier );
					if ( entity instanceof Serializable ) {
						//avoid some user errors regarding boundary crossing
						pe = new OptimisticLockException( null, e, entity );
					}
					else {
						pe = new OptimisticLockException( e );
					}
				}
				catch ( EntityNotFoundException enfe ) {
					pe = new OptimisticLockException( e );
				}
			}
			else {
				pe = new OptimisticLockException( e );
			}
		}
		else {
			pe = new OptimisticLockException( e );
		}
		return pe;
	}

	public PersistenceException wrapLockException(HibernateException e, LockOptions lockOptions) {
		PersistenceException pe;
		if ( e instanceof org.hibernate.OptimisticLockException ) {
			org.hibernate.OptimisticLockException ole = ( org.hibernate.OptimisticLockException ) e;
			pe = new OptimisticLockException( ole.getMessage(), ole, ole.getEntity() );
		}
		else if ( e instanceof org.hibernate.PessimisticLockException ) {
			org.hibernate.PessimisticLockException ple = ( org.hibernate.PessimisticLockException ) e;
			if ( lockOptions != null && lockOptions.getTimeOut() > -1 ) {
				// assume lock timeout occurred if a timeout or NO WAIT was specified
				pe = new LockTimeoutException( ple.getMessage(), ple, ple.getEntity() );
			}
			else {
				pe = new PessimisticLockException( ple.getMessage(), ple, ple.getEntity() );
			}
		}
		else {
			pe = new OptimisticLockException( e );
		}
		return pe;
	}

	private static class AfterCompletionActionImpl implements AfterCompletionAction {
		private final SessionImplementor session;
		private final PersistenceUnitTransactionType transactionType;

		private AfterCompletionActionImpl(SessionImplementor session, PersistenceUnitTransactionType transactionType) {
			this.session = session;
			this.transactionType = transactionType;
		}

		@Override
		public void doAction(TransactionCoordinator transactionCoordinator, int status) {
			if ( session.isClosed() ) {
                LOG.trace("Session was closed; nothing to do");
				return;
			}

			final boolean successful = JtaStatusHelper.isCommitted( status );
			if ( !successful && transactionType == PersistenceUnitTransactionType.JTA ) {
				( (Session) session ).clear();
			}
			session.getTransactionCoordinator().resetJoinStatus();
		}
	}

	private static class ManagedFlushCheckerImpl implements ManagedFlushChecker {
		@Override
		public boolean shouldDoManagedFlush(TransactionCoordinator coordinator, int jtaStatus) {
			return ! coordinator.getTransactionContext().isClosed() &&
					! coordinator.getTransactionContext().isFlushModeNever() &&
					! JtaStatusHelper.isRollback( jtaStatus );
		}
	}

	private class CallbackExceptionMapperImpl implements ExceptionMapper {
		@Override
		public RuntimeException mapStatusCheckFailure(String message, SystemException systemException) {
			throw new PersistenceException( message, systemException );
		}

		@Override
		public RuntimeException mapManagedFlushFailure(String message, RuntimeException failure) {
			if ( HibernateException.class.isInstance( failure ) ) {
				throw convert( failure );
			}
			if ( PersistenceException.class.isInstance( failure ) ) {
				throw failure;
			}
			throw new PersistenceException( message, failure );
		}
	}
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.