Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » impl » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.impl;
   26   
   27   import java.io.IOException;
   28   import java.io.ObjectInputStream;
   29   import java.io.ObjectOutputStream;
   30   import java.io.Serializable;
   31   import java.sql.Connection;
   32   import java.sql.SQLException;
   33   import java.util.Collection;
   34   import java.util.Collections;
   35   import java.util.HashMap;
   36   import java.util.HashSet;
   37   import java.util.Iterator;
   38   import java.util.List;
   39   import java.util.Map;
   40   import java.util.Set;
   41   
   42   import org.slf4j.Logger;
   43   import org.slf4j.LoggerFactory;
   44   
   45   import org.hibernate.CacheMode;
   46   import org.hibernate.ConnectionReleaseMode;
   47   import org.hibernate.Criteria;
   48   import org.hibernate.EntityMode;
   49   import org.hibernate.Filter;
   50   import org.hibernate.FlushMode;
   51   import org.hibernate.HibernateException;
   52   import org.hibernate.Interceptor;
   53   import org.hibernate.LockMode;
   54   import org.hibernate.MappingException;
   55   import org.hibernate.ObjectDeletedException;
   56   import org.hibernate.Query;
   57   import org.hibernate.QueryException;
   58   import org.hibernate.ReplicationMode;
   59   import org.hibernate.SQLQuery;
   60   import org.hibernate.ScrollMode;
   61   import org.hibernate.ScrollableResults;
   62   import org.hibernate.Session;
   63   import org.hibernate.SessionException;
   64   import org.hibernate.SessionFactory;
   65   import org.hibernate.Transaction;
   66   import org.hibernate.TransientObjectException;
   67   import org.hibernate.UnresolvableObjectException;
   68   import org.hibernate.EntityNameResolver;
   69   import org.hibernate.collection.PersistentCollection;
   70   import org.hibernate.engine.ActionQueue;
   71   import org.hibernate.engine.CollectionEntry;
   72   import org.hibernate.engine.EntityEntry;
   73   import org.hibernate.engine.EntityKey;
   74   import org.hibernate.engine.FilterDefinition;
   75   import org.hibernate.engine.PersistenceContext;
   76   import org.hibernate.engine.QueryParameters;
   77   import org.hibernate.engine.StatefulPersistenceContext;
   78   import org.hibernate.engine.Status;
   79   import org.hibernate.engine.query.FilterQueryPlan;
   80   import org.hibernate.engine.query.HQLQueryPlan;
   81   import org.hibernate.engine.query.NativeSQLQueryPlan;
   82   import org.hibernate.engine.query.sql.NativeSQLQuerySpecification;
   83   import org.hibernate.event.AutoFlushEvent;
   84   import org.hibernate.event.AutoFlushEventListener;
   85   import org.hibernate.event.DeleteEvent;
   86   import org.hibernate.event.DeleteEventListener;
   87   import org.hibernate.event.DirtyCheckEvent;
   88   import org.hibernate.event.DirtyCheckEventListener;
   89   import org.hibernate.event.EventListeners;
   90   import org.hibernate.event.EventSource;
   91   import org.hibernate.event.EvictEvent;
   92   import org.hibernate.event.EvictEventListener;
   93   import org.hibernate.event.FlushEvent;
   94   import org.hibernate.event.FlushEventListener;
   95   import org.hibernate.event.InitializeCollectionEvent;
   96   import org.hibernate.event.InitializeCollectionEventListener;
   97   import org.hibernate.event.LoadEvent;
   98   import org.hibernate.event.LoadEventListener;
   99   import org.hibernate.event.LoadEventListener.LoadType;
  100   import org.hibernate.event.LockEvent;
  101   import org.hibernate.event.LockEventListener;
  102   import org.hibernate.event.MergeEvent;
  103   import org.hibernate.event.MergeEventListener;
  104   import org.hibernate.event.PersistEvent;
  105   import org.hibernate.event.PersistEventListener;
  106   import org.hibernate.event.RefreshEvent;
  107   import org.hibernate.event.RefreshEventListener;
  108   import org.hibernate.event.ReplicateEvent;
  109   import org.hibernate.event.ReplicateEventListener;
  110   import org.hibernate.event.SaveOrUpdateEvent;
  111   import org.hibernate.event.SaveOrUpdateEventListener;
  112   import org.hibernate.exception.JDBCExceptionHelper;
  113   import org.hibernate.jdbc.Batcher;
  114   import org.hibernate.jdbc.JDBCContext;
  115   import org.hibernate.jdbc.Work;
  116   import org.hibernate.loader.criteria.CriteriaLoader;
  117   import org.hibernate.loader.custom.CustomLoader;
  118   import org.hibernate.loader.custom.CustomQuery;
  119   import org.hibernate.persister.collection.CollectionPersister;
  120   import org.hibernate.persister.entity.EntityPersister;
  121   import org.hibernate.persister.entity.OuterJoinLoadable;
  122   import org.hibernate.pretty.MessageHelper;
  123   import org.hibernate.proxy.HibernateProxy;
  124   import org.hibernate.proxy.LazyInitializer;
  125   import org.hibernate.stat.SessionStatistics;
  126   import org.hibernate.stat.SessionStatisticsImpl;
  127   import org.hibernate.type.Type;
  128   import org.hibernate.util.ArrayHelper;
  129   import org.hibernate.util.CollectionHelper;
  130   import org.hibernate.util.StringHelper;
  131   
  132   
  133   /**
  134    * Concrete implementation of a Session, and also the central, organizing component
  135    * of Hibernate's internal implementation. As such, this class exposes two interfaces;
  136    * Session itself, to the application, and SessionImplementor, to other components
  137    * of Hibernate. This class is not threadsafe.
  138    *
  139    * @author Gavin King
  140    */
  141   public final class SessionImpl extends AbstractSessionImpl
  142   		implements EventSource, org.hibernate.classic.Session, JDBCContext.Context {
  143   
  144   	// todo : need to find a clean way to handle the "event source" role
  145   	// a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods...
  146   	// passing around seperate reto interceptor, factory, actionQueue, and persistentContext is not manageable...
  147   
  148   	private static final Logger log = LoggerFactory.getLogger(SessionImpl.class);
  149   
  150   	private transient EntityMode entityMode = EntityMode.POJO;
  151   	private transient boolean autoClear; //for EJB3
  152   	
  153   	private transient long timestamp;
  154   	private transient FlushMode flushMode = FlushMode.AUTO;
  155   	private transient CacheMode cacheMode = CacheMode.NORMAL;
  156   
  157   	private transient Interceptor interceptor;
  158   
  159   	private transient int dontFlushFromFind = 0;
  160   
  161   	private transient ActionQueue actionQueue;
  162   	private transient StatefulPersistenceContext persistenceContext;
  163   	private transient JDBCContext jdbcContext;
  164   	private transient EventListeners listeners;
  165   
  166   	private transient boolean flushBeforeCompletionEnabled;
  167   	private transient boolean autoCloseSessionEnabled;
  168   	private transient ConnectionReleaseMode connectionReleaseMode;
  169   	
  170   	private transient String fetchProfile;
  171   
  172   	private transient Map enabledFilters = new HashMap();
  173   
  174   	private transient Session rootSession;
  175   	private transient Map childSessionsByEntityMode;
  176   
  177   	private EntityNameResolver entityNameResolver = new CoordinatingEntityNameResolver();
  178   
  179   	/**
  180   	 * Constructor used in building "child sessions".
  181   	 *
  182   	 * @param parent The parent session
  183   	 * @param entityMode
  184   	 */
  185   	private SessionImpl(SessionImpl parent, EntityMode entityMode) {
  186   		super( parent.factory );
  187   		this.rootSession = parent;
  188   		this.timestamp = parent.timestamp;
  189   		this.jdbcContext = parent.jdbcContext;
  190   		this.interceptor = parent.interceptor;
  191   		this.listeners = parent.listeners;
  192   		this.actionQueue = new ActionQueue( this );
  193   		this.entityMode = entityMode;
  194   		this.persistenceContext = new StatefulPersistenceContext( this );
  195   		this.flushBeforeCompletionEnabled = false;
  196   		this.autoCloseSessionEnabled = false;
  197   		this.connectionReleaseMode = null;
  198   
  199   		if ( factory.getStatistics().isStatisticsEnabled() ) {
  200   			factory.getStatisticsImplementor().openSession();
  201   		}
  202   
  203   		log.debug( "opened session [" + entityMode + "]" );
  204   	}
  205   
  206   	/**
  207   	 * Constructor used for openSession(...) processing, as well as construction
  208   	 * of sessions for getCurrentSession().
  209   	 *
  210   	 * @param connection The user-supplied connection to use for this session.
  211   	 * @param factory The factory from which this session was obtained
  212   	 * @param autoclose NOT USED
  213   	 * @param timestamp The timestamp for this session
  214   	 * @param interceptor The interceptor to be applied to this session
  215   	 * @param entityMode The entity-mode for this session
  216   	 * @param flushBeforeCompletionEnabled Should we auto flush before completion of transaction
  217   	 * @param autoCloseSessionEnabled Should we auto close after completion of transaction
  218   	 * @param connectionReleaseMode The mode by which we should release JDBC connections.
  219   	 */
  220   	SessionImpl(
  221   			final Connection connection,
  222   			final SessionFactoryImpl factory,
  223   			final boolean autoclose,
  224   			final long timestamp,
  225   			final Interceptor interceptor,
  226   			final EntityMode entityMode,
  227   			final boolean flushBeforeCompletionEnabled,
  228   			final boolean autoCloseSessionEnabled,
  229   			final ConnectionReleaseMode connectionReleaseMode) {
  230   		super( factory );
  231   		this.rootSession = null;
  232   		this.timestamp = timestamp;
  233   		this.entityMode = entityMode;
  234   		this.interceptor = interceptor;
  235   		this.listeners = factory.getEventListeners();
  236   		this.actionQueue = new ActionQueue( this );
  237   		this.persistenceContext = new StatefulPersistenceContext( this );
  238   		this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
  239   		this.autoCloseSessionEnabled = autoCloseSessionEnabled;
  240   		this.connectionReleaseMode = connectionReleaseMode;
  241   		this.jdbcContext = new JDBCContext( this, connection, interceptor );
  242   
  243   		if ( factory.getStatistics().isStatisticsEnabled() ) {
  244   			factory.getStatisticsImplementor().openSession();
  245   		}
  246   
  247   		if ( log.isDebugEnabled() ) {
  248   			log.debug( "opened session at timestamp: " + timestamp );
  249   		}
  250   	}
  251   
  252   	public Session getSession(EntityMode entityMode) {
  253   		if ( this.entityMode == entityMode ) {
  254   			return this;
  255   		}
  256   
  257   		if ( rootSession != null ) {
  258   			rootSession.getSession( entityMode );
  259   		}
  260   
  261   		errorIfClosed();
  262   		checkTransactionSynchStatus();
  263   
  264   		SessionImpl rtn = null;
  265   		if ( childSessionsByEntityMode == null ) {
  266   			childSessionsByEntityMode = new HashMap();
  267   		}
  268   		else {
  269   			rtn = (SessionImpl) childSessionsByEntityMode.get( entityMode );
  270   		}
  271   
  272   		if ( rtn == null ) {
  273   			rtn = new SessionImpl( this, entityMode );
  274   			childSessionsByEntityMode.put( entityMode, rtn );
  275   		}
  276   
  277   		return rtn;
  278   	}
  279   
  280   	public void clear() {
  281   		errorIfClosed();
  282   		checkTransactionSynchStatus();
  283   		persistenceContext.clear();
  284   		actionQueue.clear();
  285   	}
  286   
  287   	public Batcher getBatcher() {
  288   		errorIfClosed();
  289   		checkTransactionSynchStatus();
  290   		// TODO : should remove this exposure
  291   		//  and have all references to the session's batcher use the ConnectionManager.
  292   		return jdbcContext.getConnectionManager().getBatcher();
  293   	}
  294   
  295   	public long getTimestamp() {
  296   		checkTransactionSynchStatus();
  297   		return timestamp;
  298   	}
  299   
  300   	public Connection close() throws HibernateException {
  301   		log.trace( "closing session" );
  302   		if ( isClosed() ) {
  303   			throw new SessionException( "Session was already closed" );
  304   		}
  305   		
  306   
  307   		if ( factory.getStatistics().isStatisticsEnabled() ) {
  308   			factory.getStatisticsImplementor().closeSession();
  309   		}
  310   
  311   		try {
  312   			try {
  313   				if ( childSessionsByEntityMode != null ) {
  314   					Iterator childSessions = childSessionsByEntityMode.values().iterator();
  315   					while ( childSessions.hasNext() ) {
  316   						final SessionImpl child = ( SessionImpl ) childSessions.next();
  317   						child.close();
  318   					}
  319   				}
  320   			}
  321   			catch( Throwable t ) {
  322   				// just ignore
  323   			}
  324   
  325   			if ( rootSession == null ) {
  326   				return jdbcContext.getConnectionManager().close();
  327   			}
  328   			else {
  329   				return null;
  330   			}
  331   		}
  332   		finally {
  333   			setClosed();
  334   			cleanup();
  335   		}
  336   	}
  337   
  338   	public ConnectionReleaseMode getConnectionReleaseMode() {
  339   		checkTransactionSynchStatus();
  340   		return connectionReleaseMode;
  341   	}
  342   
  343   	public boolean isAutoCloseSessionEnabled() {
  344   		return autoCloseSessionEnabled;
  345   	}
  346   
  347   	public boolean isOpen() {
  348   		checkTransactionSynchStatus();
  349   		return !isClosed();
  350   	}
  351   
  352   	public boolean isFlushModeNever() {
  353   		return FlushMode.isManualFlushMode( getFlushMode() );
  354   	}
  355   
  356   	public boolean isFlushBeforeCompletionEnabled() {
  357   		return flushBeforeCompletionEnabled;
  358   	}
  359   
  360   	public void managedFlush() {
  361   		if ( isClosed() ) {
  362   			log.trace( "skipping auto-flush due to session closed" );
  363   			return;
  364   		}
  365   		log.trace("automatically flushing session");
  366   		flush();
  367   		
  368   		if ( childSessionsByEntityMode != null ) {
  369   			Iterator iter = childSessionsByEntityMode.values().iterator();
  370   			while ( iter.hasNext() ) {
  371   				( (Session) iter.next() ).flush();
  372   			}
  373   		}
  374   	}
  375   
  376   	public boolean shouldAutoClose() {
  377   		return isAutoCloseSessionEnabled() && !isClosed();
  378   	}
  379   
  380   	public void managedClose() {
  381   		log.trace( "automatically closing session" );
  382   		close();
  383   	}
  384   
  385   	public Connection connection() throws HibernateException {
  386   		errorIfClosed();
  387   		return jdbcContext.borrowConnection();
  388   	}
  389   
  390   	public boolean isConnected() {
  391   		checkTransactionSynchStatus();
  392   		return !isClosed() && jdbcContext.getConnectionManager().isCurrentlyConnected();
  393   	}
  394   	
  395   	public boolean isTransactionInProgress() {
  396   		checkTransactionSynchStatus();
  397   		return !isClosed() && jdbcContext.isTransactionInProgress();
  398   	}
  399   
  400   	public Connection disconnect() throws HibernateException {
  401   		errorIfClosed();
  402   		log.debug( "disconnecting session" );
  403   		return jdbcContext.getConnectionManager().manualDisconnect();
  404   	}
  405   
  406   	public void reconnect() throws HibernateException {
  407   		errorIfClosed();
  408   		log.debug( "reconnecting session" );
  409   		checkTransactionSynchStatus();
  410   		jdbcContext.getConnectionManager().manualReconnect();
  411   	}
  412   
  413   	public void reconnect(Connection conn) throws HibernateException {
  414   		errorIfClosed();
  415   		log.debug( "reconnecting session" );
  416   		checkTransactionSynchStatus();
  417   		jdbcContext.getConnectionManager().manualReconnect( conn );
  418   	}
  419   
  420   	public void beforeTransactionCompletion(Transaction tx) {
  421   		log.trace( "before transaction completion" );
  422   		if ( rootSession == null ) {
  423   			try {
  424   				interceptor.beforeTransactionCompletion(tx);
  425   			}
  426   			catch (Throwable t) {
  427   				log.error("exception in interceptor beforeTransactionCompletion()", t);
  428   			}
  429   		}
  430   	}
  431   	
  432   	public void setAutoClear(boolean enabled) {
  433   		errorIfClosed();
  434   		autoClear = enabled;
  435   	}
  436   	
  437   	/**
  438   	 * Check if there is a Hibernate or JTA transaction in progress and, 
  439   	 * if there is not, flush if necessary, make sure the connection has 
  440   	 * been committed (if it is not in autocommit mode) and run the after 
  441   	 * completion processing
  442   	 */
  443   	public void afterOperation(boolean success) {
  444   		if ( !jdbcContext.isTransactionInProgress() ) {
  445   			jdbcContext.afterNontransactionalQuery( success );
  446   		}
  447   	}
  448   
  449   	public void afterTransactionCompletion(boolean success, Transaction tx) {
  450   		log.trace( "after transaction completion" );
  451   		persistenceContext.afterTransactionCompletion();
  452   		actionQueue.afterTransactionCompletion(success);
  453   		if ( rootSession == null && tx != null ) {
  454   			try {
  455   				interceptor.afterTransactionCompletion(tx);
  456   			}
  457   			catch (Throwable t) {
  458   				log.error("exception in interceptor afterTransactionCompletion()", t);
  459   			}
  460   		}
  461   		if ( autoClear ) {
  462   			clear();
  463   		}
  464   	}
  465   
  466   	/**
  467   	 * clear all the internal collections, just 
  468   	 * to help the garbage collector, does not
  469   	 * clear anything that is needed during the
  470   	 * afterTransactionCompletion() phase
  471   	 */
  472   	private void cleanup() {
  473   		persistenceContext.clear();
  474   	}
  475   
  476   	public LockMode getCurrentLockMode(Object object) throws HibernateException {
  477   		errorIfClosed();
  478   		checkTransactionSynchStatus();
  479   		if ( object == null ) {
  480   			throw new NullPointerException( "null object passed to getCurrentLockMode()" );
  481   		}
  482   		if ( object instanceof HibernateProxy ) {
  483   			object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(this);
  484   			if ( object == null ) {
  485   				return LockMode.NONE;
  486   			}
  487   		}
  488   		EntityEntry e = persistenceContext.getEntry(object);
  489   		if ( e == null ) {
  490   			throw new TransientObjectException( "Given object not associated with the session" );
  491   		}
  492   		if ( e.getStatus() != Status.MANAGED ) {
  493   			throw new ObjectDeletedException( 
  494   					"The given object was deleted", 
  495   					e.getId(), 
  496   					e.getPersister().getEntityName() 
  497   				);
  498   		}
  499   		return e.getLockMode();
  500   	}
  501   
  502   	public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
  503   		errorIfClosed();
  504   		// todo : should this get moved to PersistentContext?
  505   		// logically, is PersistentContext the "thing" to which an interceptor gets attached?
  506   		final Object result = persistenceContext.getEntity(key);
  507   		if ( result == null ) {
  508   			final Object newObject = interceptor.getEntity( key.getEntityName(), key.getIdentifier() );
  509   			if ( newObject != null ) {
  510   				lock( newObject, LockMode.NONE );
  511   			}
  512   			return newObject;
  513   		}
  514   		else {
  515   			return result;
  516   		}
  517   	}
  518   
  519   
  520   	// saveOrUpdate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  521   
  522   	public void saveOrUpdate(Object object) throws HibernateException {
  523   		saveOrUpdate(null, object);
  524   	}
  525   
  526   	public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
  527   		fireSaveOrUpdate( new SaveOrUpdateEvent(entityName, obj, this) );
  528   	}
  529   
  530   	private void fireSaveOrUpdate(SaveOrUpdateEvent event) {
  531   		errorIfClosed();
  532   		checkTransactionSynchStatus();
  533   		SaveOrUpdateEventListener[] saveOrUpdateEventListener = listeners.getSaveOrUpdateEventListeners();
  534   		for ( int i = 0; i < saveOrUpdateEventListener.length; i++ ) {
  535   			saveOrUpdateEventListener[i].onSaveOrUpdate(event);
  536   		}
  537   	}
  538   
  539   
  540   	// save() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  541   
  542   	public void save(Object obj, Serializable id) throws HibernateException {
  543   		save(null, obj, id);
  544   	}
  545   
  546   	public Serializable save(Object obj) throws HibernateException {
  547   		return save(null, obj);
  548   	}
  549   
  550   	public Serializable save(String entityName, Object object) throws HibernateException {
  551   		return fireSave( new SaveOrUpdateEvent(entityName, object, this) );
  552   	}
  553   
  554   	public void save(String entityName, Object object, Serializable id) throws HibernateException {
  555   		fireSave( new SaveOrUpdateEvent(entityName, object, id, this) );
  556   	}
  557   
  558   	private Serializable fireSave(SaveOrUpdateEvent event) {
  559   		errorIfClosed();
  560   		checkTransactionSynchStatus();
  561   		SaveOrUpdateEventListener[] saveEventListener = listeners.getSaveEventListeners();
  562   		for ( int i = 0; i < saveEventListener.length; i++ ) {
  563   			saveEventListener[i].onSaveOrUpdate(event);
  564   		}
  565   		return event.getResultId();
  566   	}
  567   
  568   
  569   	// update() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  570   
  571   	public void update(Object obj) throws HibernateException {
  572   		update(null, obj);
  573   	}
  574   
  575   	public void update(Object obj, Serializable id) throws HibernateException {
  576   		update(null, obj, id);
  577   	}
  578   
  579   	public void update(String entityName, Object object) throws HibernateException {
  580   		fireUpdate( new SaveOrUpdateEvent(entityName, object, this) );
  581   	}
  582   
  583   	public void update(String entityName, Object object, Serializable id) throws HibernateException {
  584   		fireUpdate(new SaveOrUpdateEvent(entityName, object, id, this));
  585   	}
  586   
  587   	private void fireUpdate(SaveOrUpdateEvent event) {
  588   		errorIfClosed();
  589   		checkTransactionSynchStatus();
  590   		SaveOrUpdateEventListener[] updateEventListener = listeners.getUpdateEventListeners();
  591   		for ( int i = 0; i < updateEventListener.length; i++ ) {
  592   			updateEventListener[i].onSaveOrUpdate(event);
  593   		}
  594   	}
  595   
  596   
  597   	// lock() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  598   
  599   	public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException {
  600   		fireLock( new LockEvent(entityName, object, lockMode, this) );
  601   	}
  602   
  603   	public void lock(Object object, LockMode lockMode) throws HibernateException {
  604   		fireLock( new LockEvent(object, lockMode, this) );
  605   	}
  606   
  607   	private void fireLock(LockEvent lockEvent) {
  608   		errorIfClosed();
  609   		checkTransactionSynchStatus();
  610   		LockEventListener[] lockEventListener = listeners.getLockEventListeners();
  611   		for ( int i = 0; i < lockEventListener.length; i++ ) {
  612   			lockEventListener[i].onLock( lockEvent );
  613   		}
  614   	}
  615   
  616   
  617   	// persist() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  618   
  619   	public void persist(String entityName, Object object) throws HibernateException {
  620   		firePersist( new PersistEvent(entityName, object, this) );
  621   	}
  622   
  623   	public void persist(Object object) throws HibernateException {
  624   		persist(null, object);
  625   	}
  626   
  627   	public void persist(String entityName, Object object, Map copiedAlready)
  628   	throws HibernateException {
  629   		firePersist( copiedAlready, new PersistEvent(entityName, object, this) );
  630   	}
  631   
  632   	private void firePersist(Map copiedAlready, PersistEvent event) {
  633   		errorIfClosed();
  634   		checkTransactionSynchStatus();
  635   		PersistEventListener[] persistEventListener = listeners.getPersistEventListeners();
  636   		for ( int i = 0; i < persistEventListener.length; i++ ) {
  637   			persistEventListener[i].onPersist(event, copiedAlready);
  638   		}
  639   	}
  640   
  641   	private void firePersist(PersistEvent event) {
  642   		errorIfClosed();
  643   		checkTransactionSynchStatus();
  644   		PersistEventListener[] createEventListener = listeners.getPersistEventListeners();
  645   		for ( int i = 0; i < createEventListener.length; i++ ) {
  646   			createEventListener[i].onPersist(event);
  647   		}
  648   	}
  649   
  650   
  651   	// persistOnFlush() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  652   
  653   	public void persistOnFlush(String entityName, Object object)
  654   			throws HibernateException {
  655   		firePersistOnFlush( new PersistEvent(entityName, object, this) );
  656   	}
  657   
  658   	public void persistOnFlush(Object object) throws HibernateException {
  659   		persist(null, object);
  660   	}
  661   
  662   	public void persistOnFlush(String entityName, Object object, Map copiedAlready)
  663   			throws HibernateException {
  664   		firePersistOnFlush( copiedAlready, new PersistEvent(entityName, object, this) );
  665   	}
  666   
  667   	private void firePersistOnFlush(Map copiedAlready, PersistEvent event) {
  668   		errorIfClosed();
  669   		checkTransactionSynchStatus();
  670   		PersistEventListener[] persistEventListener = listeners.getPersistOnFlushEventListeners();
  671   		for ( int i = 0; i < persistEventListener.length; i++ ) {
  672   			persistEventListener[i].onPersist(event, copiedAlready);
  673   		}
  674   	}
  675   
  676   	private void firePersistOnFlush(PersistEvent event) {
  677   		errorIfClosed();
  678   		checkTransactionSynchStatus();
  679   		PersistEventListener[] createEventListener = listeners.getPersistOnFlushEventListeners();
  680   		for ( int i = 0; i < createEventListener.length; i++ ) {
  681   			createEventListener[i].onPersist(event);
  682   		}
  683   	}
  684   
  685   
  686   	// merge() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  687   
  688   	public Object merge(String entityName, Object object) throws HibernateException {
  689   		return fireMerge( new MergeEvent(entityName, object, this) );
  690   	}
  691   
  692   	public Object merge(Object object) throws HibernateException {
  693   		return merge(null, object);
  694   	}
  695   
  696   	public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
  697   		fireMerge( copiedAlready, new MergeEvent(entityName, object, this) );
  698   	}
  699   
  700   	private Object fireMerge(MergeEvent event) {
  701   		errorIfClosed();
  702   		checkTransactionSynchStatus();
  703   		MergeEventListener[] mergeEventListener = listeners.getMergeEventListeners();
  704   		for ( int i = 0; i < mergeEventListener.length; i++ ) {
  705   			mergeEventListener[i].onMerge(event);
  706   		}
  707   		return event.getResult();
  708   	}
  709   
  710   	private void fireMerge(Map copiedAlready, MergeEvent event) {
  711   		errorIfClosed();
  712   		checkTransactionSynchStatus();
  713   		MergeEventListener[] mergeEventListener = listeners.getMergeEventListeners();
  714   		for ( int i = 0; i < mergeEventListener.length; i++ ) {
  715   			mergeEventListener[i].onMerge(event, copiedAlready);
  716   		}
  717   	}
  718   
  719   
  720   	// saveOrUpdateCopy() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  721   
  722   	public Object saveOrUpdateCopy(String entityName, Object object)
  723   			throws HibernateException {
  724   		return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, this) );
  725   	}
  726   
  727   	public Object saveOrUpdateCopy(Object object) throws HibernateException {
  728   		return saveOrUpdateCopy( null, object );
  729   	}
  730   
  731   	public Object saveOrUpdateCopy(String entityName, Object object, Serializable id)
  732   			throws HibernateException {
  733   		return fireSaveOrUpdateCopy( new MergeEvent(entityName, object, id, this) );
  734   	}
  735   
  736   	public Object saveOrUpdateCopy(Object object, Serializable id)
  737   			throws HibernateException {
  738   		return saveOrUpdateCopy( null, object, id );
  739   	}
  740   
  741   	public void saveOrUpdateCopy(String entityName, Object object, Map copiedAlready)
  742   			throws HibernateException {
  743   		fireSaveOrUpdateCopy( copiedAlready, new MergeEvent( entityName, object, this ) );
  744   	}
  745   
  746   	private void fireSaveOrUpdateCopy(Map copiedAlready, MergeEvent event) {
  747   		errorIfClosed();
  748   		checkTransactionSynchStatus();
  749   		MergeEventListener[] saveOrUpdateCopyEventListener = listeners.getSaveOrUpdateCopyEventListeners();
  750   		for ( int i = 0; i < saveOrUpdateCopyEventListener.length; i++ ) {
  751   			saveOrUpdateCopyEventListener[i].onMerge(event, copiedAlready);
  752   		}
  753   	}
  754   
  755   	private Object fireSaveOrUpdateCopy(MergeEvent event) {
  756   		errorIfClosed();
  757   		checkTransactionSynchStatus();
  758   		MergeEventListener[] saveOrUpdateCopyEventListener = listeners.getSaveOrUpdateCopyEventListeners();
  759   		for ( int i = 0; i < saveOrUpdateCopyEventListener.length; i++ ) {
  760   			saveOrUpdateCopyEventListener[i].onMerge(event);
  761   		}
  762   		return event.getResult();
  763   	}
  764   
  765   
  766   	// delete() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  767   
  768   	/**
  769   	 * Delete a persistent object
  770   	 */
  771   	public void delete(Object object) throws HibernateException {
  772   		fireDelete( new DeleteEvent(object, this) );
  773   	}
  774   
  775   	/**
  776   	 * Delete a persistent object (by explicit entity name)
  777   	 */
  778   	public void delete(String entityName, Object object) throws HibernateException {
  779   		fireDelete( new DeleteEvent( entityName, object, this ) );
  780   	}
  781   
  782   	/**
  783   	 * Delete a persistent object
  784   	 */
  785   	public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled, Set transientEntities) throws HibernateException {
  786   		fireDelete( new DeleteEvent( entityName, object, isCascadeDeleteEnabled, this ), transientEntities );
  787   	}
  788   
  789   	private void fireDelete(DeleteEvent event) {
  790   		errorIfClosed();
  791   		checkTransactionSynchStatus();
  792   		DeleteEventListener[] deleteEventListener = listeners.getDeleteEventListeners();
  793   		for ( int i = 0; i < deleteEventListener.length; i++ ) {
  794   			deleteEventListener[i].onDelete( event );
  795   		}
  796   	}
  797   
  798   	private void fireDelete(DeleteEvent event, Set transientEntities) {
  799   		errorIfClosed();
  800   		checkTransactionSynchStatus();
  801   		DeleteEventListener[] deleteEventListener = listeners.getDeleteEventListeners();
  802   		for ( int i = 0; i < deleteEventListener.length; i++ ) {
  803   			deleteEventListener[i].onDelete( event, transientEntities );
  804   		}
  805   	}
  806   
  807   
  808   	// load()/get() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  809   
  810   	public void load(Object object, Serializable id) throws HibernateException {
  811   		LoadEvent event = new LoadEvent(id, object, this);
  812   		fireLoad( event, LoadEventListener.RELOAD );
  813   	}
  814   
  815   	public Object load(Class entityClass, Serializable id) throws HibernateException {
  816   		return load( entityClass.getName(), id );
  817   	}
  818   
  819   	public Object load(String entityName, Serializable id) throws HibernateException {
  820   		LoadEvent event = new LoadEvent(id, entityName, false, this);
  821   		boolean success = false;
  822   		try {
  823   			fireLoad( event, LoadEventListener.LOAD );
  824   			if ( event.getResult() == null ) {
  825   				getFactory().getEntityNotFoundDelegate().handleEntityNotFound( entityName, id );
  826   			}
  827   			success = true;
  828   			return event.getResult();
  829   		}
  830   		finally {
  831   			afterOperation(success);
  832   		}
  833   	}
  834   
  835   	public Object get(Class entityClass, Serializable id) throws HibernateException {
  836   		return get( entityClass.getName(), id );
  837   	}
  838   
  839   	public Object get(String entityName, Serializable id) throws HibernateException {
  840   		LoadEvent event = new LoadEvent(id, entityName, false, this);
  841   		boolean success = false;
  842   		try {
  843   			fireLoad(event, LoadEventListener.GET);
  844   			success = true;
  845   			return event.getResult();
  846   		}
  847   		finally {
  848   			afterOperation(success);
  849   		}
  850   	}
  851   
  852   	/**
  853   	 * Load the data for the object with the specified id into a newly created object.
  854   	 * This is only called when lazily initializing a proxy.
  855   	 * Do NOT return a proxy.
  856   	 */
  857   	public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
  858   		if ( log.isDebugEnabled() ) {
  859   			EntityPersister persister = getFactory().getEntityPersister(entityName);
  860   			log.debug( "initializing proxy: " + MessageHelper.infoString( persister, id, getFactory() ) );
  861   		}
  862   		
  863   		LoadEvent event = new LoadEvent(id, entityName, true, this);
  864   		fireLoad(event, LoadEventListener.IMMEDIATE_LOAD);
  865   		return event.getResult();
  866   	}
  867   
  868   	public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) throws HibernateException {
  869   		// todo : remove
  870   		LoadEventListener.LoadType type = nullable ? 
  871   				LoadEventListener.INTERNAL_LOAD_NULLABLE : 
  872   				eager ? LoadEventListener.INTERNAL_LOAD_EAGER : LoadEventListener.INTERNAL_LOAD_LAZY;
  873   		LoadEvent event = new LoadEvent(id, entityName, true, this);
  874   		fireLoad(event, type);
  875   		if ( !nullable ) {
  876   			UnresolvableObjectException.throwIfNull( event.getResult(), id, entityName );
  877   		}
  878   		return event.getResult();
  879   	}
  880   
  881   	public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
  882   		return load( entityClass.getName(), id, lockMode );
  883   	}
  884   
  885   	public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
  886   		LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
  887   		fireLoad( event, LoadEventListener.LOAD );
  888   		return event.getResult();
  889   	}
  890   
  891   	public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
  892   		return get( entityClass.getName(), id, lockMode );
  893   	}
  894   
  895   	public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
  896   		LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
  897   	   	fireLoad(event, LoadEventListener.GET);
  898   		return event.getResult();
  899   	}
  900   
  901   	private void fireLoad(LoadEvent event, LoadType loadType) {
  902   		errorIfClosed();
  903   		checkTransactionSynchStatus();
  904   		LoadEventListener[] loadEventListener = listeners.getLoadEventListeners();
  905   		for ( int i = 0; i < loadEventListener.length; i++ ) {
  906   			loadEventListener[i].onLoad(event, loadType);
  907   		}
  908   	}
  909   
  910   
  911   	// refresh() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  912   
  913   	public void refresh(Object object) throws HibernateException {
  914   		fireRefresh( new RefreshEvent(object, this) );
  915   	}
  916   
  917   	public void refresh(Object object, LockMode lockMode) throws HibernateException {
  918   		fireRefresh( new RefreshEvent(object, lockMode, this) );
  919   	}
  920   
  921   	public void refresh(Object object, Map refreshedAlready) throws HibernateException {
  922   		fireRefresh( refreshedAlready, new RefreshEvent(object, this) );
  923   	}
  924   
  925   	private void fireRefresh(RefreshEvent refreshEvent) {
  926   		errorIfClosed();
  927   		checkTransactionSynchStatus();
  928   		RefreshEventListener[] refreshEventListener = listeners.getRefreshEventListeners();
  929   		for ( int i = 0; i < refreshEventListener.length; i++ ) {
  930   			refreshEventListener[i].onRefresh( refreshEvent );
  931   		}
  932   	}
  933   
  934   	private void fireRefresh(Map refreshedAlready, RefreshEvent refreshEvent) {
  935   		errorIfClosed();
  936   		checkTransactionSynchStatus();
  937   		RefreshEventListener[] refreshEventListener = listeners.getRefreshEventListeners();
  938   		for ( int i = 0; i < refreshEventListener.length; i++ ) {
  939   			refreshEventListener[i].onRefresh( refreshEvent, refreshedAlready );
  940   		}
  941   	}
  942   
  943   
  944   	// replicate() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  945   
  946   	public void replicate(Object obj, ReplicationMode replicationMode) throws HibernateException {
  947   		fireReplicate( new ReplicateEvent(obj, replicationMode, this) );
  948   	}
  949   
  950   	public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
  951   	throws HibernateException {
  952   		fireReplicate( new ReplicateEvent(entityName, obj, replicationMode, this) );
  953   	}
  954   
  955   	private void fireReplicate(ReplicateEvent event) {
  956   		errorIfClosed();
  957   		checkTransactionSynchStatus();
  958   		ReplicateEventListener[] replicateEventListener = listeners.getReplicateEventListeners();
  959   		for ( int i = 0; i < replicateEventListener.length; i++ ) {
  960   			replicateEventListener[i].onReplicate(event);
  961   		}
  962   	}
  963   
  964   
  965   	// evict() operations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  966   
  967   	/**
  968   	 * remove any hard references to the entity that are held by the infrastructure
  969   	 * (references held by application or other persistant instances are okay)
  970   	 */
  971   	public void evict(Object object) throws HibernateException {
  972   		fireEvict( new EvictEvent(object, this) );
  973   	}
  974   
  975   	private void fireEvict(EvictEvent evictEvent) {
  976   		errorIfClosed();
  977   		checkTransactionSynchStatus();
  978   		EvictEventListener[] evictEventListener = listeners.getEvictEventListeners();
  979   		for ( int i = 0; i < evictEventListener.length; i++ ) {
  980   			evictEventListener[i].onEvict( evictEvent );
  981   		}
  982   	}
  983   
  984   	/**
  985   	 * detect in-memory changes, determine if the changes are to tables
  986   	 * named in the query and, if so, complete execution the flush
  987   	 */
  988   	protected boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
  989   		errorIfClosed();
  990   		if ( ! isTransactionInProgress() ) {
  991   			// do not auto-flush while outside a transaction
  992   			return false;
  993   		}
  994   		AutoFlushEvent event = new AutoFlushEvent(querySpaces, this);
  995   		AutoFlushEventListener[] autoFlushEventListener = listeners.getAutoFlushEventListeners();
  996   		for ( int i = 0; i < autoFlushEventListener.length; i++ ) {
  997   			autoFlushEventListener[i].onAutoFlush(event);
  998   		}
  999   		return event.isFlushRequired();
 1000   	}
 1001   
 1002   	public boolean isDirty() throws HibernateException {
 1003   		errorIfClosed();
 1004   		checkTransactionSynchStatus();
 1005   		log.debug("checking session dirtiness");
 1006   		if ( actionQueue.areInsertionsOrDeletionsQueued() ) {
 1007   			log.debug("session dirty (scheduled updates and insertions)");
 1008   			return true;
 1009   		}
 1010   		else {
 1011   			DirtyCheckEvent event = new DirtyCheckEvent(this);
 1012   			DirtyCheckEventListener[] dirtyCheckEventListener = listeners.getDirtyCheckEventListeners();
 1013   			for ( int i = 0; i < dirtyCheckEventListener.length; i++ ) {
 1014   				dirtyCheckEventListener[i].onDirtyCheck(event);
 1015   			}
 1016   			return event.isDirty();
 1017   		}
 1018   	}
 1019   
 1020   	public void flush() throws HibernateException {
 1021   		errorIfClosed();
 1022   		checkTransactionSynchStatus();
 1023   		if ( persistenceContext.getCascadeLevel() > 0 ) {
 1024   			throw new HibernateException("Flush during cascade is dangerous");
 1025   		}
 1026   		FlushEventListener[] flushEventListener = listeners.getFlushEventListeners();
 1027   		for ( int i = 0; i < flushEventListener.length; i++ ) {
 1028   			flushEventListener[i].onFlush( new FlushEvent(this) );
 1029   		}
 1030   	}
 1031   
 1032   	public void forceFlush(EntityEntry entityEntry) throws HibernateException {
 1033   		errorIfClosed();
 1034   		if ( log.isDebugEnabled() ) {
 1035   			log.debug(
 1036   				"flushing to force deletion of re-saved object: " +
 1037   				MessageHelper.infoString( entityEntry.getPersister(), entityEntry.getId(), getFactory() )
 1038   			);
 1039   		}
 1040   
 1041   		if ( persistenceContext.getCascadeLevel() > 0 ) {
 1042   			throw new ObjectDeletedException(
 1043   				"deleted object would be re-saved by cascade (remove deleted object from associations)",
 1044   				entityEntry.getId(),
 1045   				entityEntry.getPersister().getEntityName()
 1046   			);
 1047   		}
 1048   
 1049   		flush();
 1050   	}
 1051   
 1052   	public Filter getEnabledFilter(String filterName) {
 1053   		checkTransactionSynchStatus();
 1054   		return (Filter) enabledFilters.get(filterName);
 1055   	}
 1056   
 1057   	public Filter enableFilter(String filterName) {
 1058   		errorIfClosed();
 1059   		checkTransactionSynchStatus();
 1060   		FilterImpl filter = new FilterImpl( factory.getFilterDefinition(filterName) );
 1061   		enabledFilters.put(filterName, filter);
 1062   		return filter;
 1063   	}
 1064   
 1065   	public void disableFilter(String filterName) {
 1066   		errorIfClosed();
 1067   		checkTransactionSynchStatus();
 1068   		enabledFilters.remove(filterName);
 1069   	}
 1070   
 1071   	public Object getFilterParameterValue(String filterParameterName) {
 1072   		errorIfClosed();
 1073   		checkTransactionSynchStatus();
 1074   		String[] parsed = parseFilterParameterName(filterParameterName);
 1075   		FilterImpl filter = (FilterImpl) enabledFilters.get( parsed[0] );
 1076   		if (filter == null) {
 1077   			throw new IllegalArgumentException("Filter [" + parsed[0] + "] currently not enabled");
 1078   		}
 1079   		return filter.getParameter( parsed[1] );
 1080   	}
 1081   
 1082   	public Type getFilterParameterType(String filterParameterName) {
 1083   		errorIfClosed();
 1084   		checkTransactionSynchStatus();
 1085   		String[] parsed = parseFilterParameterName(filterParameterName);
 1086   		FilterDefinition filterDef = factory.getFilterDefinition( parsed[0] );
 1087   		if (filterDef == null) {
 1088   			throw new IllegalArgumentException("Filter [" + parsed[0] + "] not defined");
 1089   		}
 1090   		Type type = filterDef.getParameterType( parsed[1] );
 1091   		if (type == null) {
 1092   			// this is an internal error of some sort...
 1093   			throw new InternalError("Unable to locate type for filter parameter");
 1094   		}
 1095   		return type;
 1096   	}
 1097   
 1098   	public Map getEnabledFilters() {
 1099   		errorIfClosed();
 1100   		checkTransactionSynchStatus();
 1101   		// First, validate all the enabled filters...
 1102   		//TODO: this implementation has bad performance
 1103   		Iterator itr = enabledFilters.values().iterator();
 1104   		while ( itr.hasNext() ) {
 1105   			final Filter filter = (Filter) itr.next();
 1106   			filter.validate();
 1107   		}
 1108   		return enabledFilters;
 1109   	}
 1110   
 1111   	private String[] parseFilterParameterName(String filterParameterName) {
 1112   		int dot = filterParameterName.indexOf('.');
 1113   		if (dot <= 0) {
 1114   			throw new IllegalArgumentException("Invalid filter-parameter name format"); // TODO: what type?
 1115   		}
 1116   		String filterName = filterParameterName.substring(0, dot);
 1117   		String parameterName = filterParameterName.substring(dot+1);
 1118   		return new String[] {filterName, parameterName};
 1119   	}
 1120   
 1121   
 1122   	/**
 1123   	 * Retrieve a list of persistent objects using a hibernate query
 1124   	 */
 1125   	public List find(String query) throws HibernateException {
 1126   		return list( query, new QueryParameters() );
 1127   	}
 1128   
 1129   	public List find(String query, Object value, Type type) throws HibernateException {
 1130   		return list( query, new QueryParameters(type, value) );
 1131   	}
 1132   
 1133   	public List find(String query, Object[] values, Type[] types) throws HibernateException {
 1134   		return list( query, new QueryParameters(types, values) );
 1135   	}
 1136   
 1137   	public List list(String query, QueryParameters queryParameters) throws HibernateException {
 1138   		errorIfClosed();
 1139   		checkTransactionSynchStatus();
 1140   		queryParameters.validateParameters();
 1141   		HQLQueryPlan plan = getHQLQueryPlan( query, false );
 1142   		autoFlushIfRequired( plan.getQuerySpaces() );
 1143   
 1144   		List results = CollectionHelper.EMPTY_LIST;
 1145   		boolean success = false;
 1146   
 1147   		dontFlushFromFind++;   //stops flush being called multiple times if this method is recursively called
 1148   		try {
 1149   			results = plan.performList( queryParameters, this );
 1150   			success = true;
 1151   		}
 1152   		finally {
 1153   			dontFlushFromFind--;
 1154   			afterOperation(success);
 1155   		}
 1156   		return results;
 1157   	}
 1158   
 1159   	public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
 1160   		errorIfClosed();
 1161   		checkTransactionSynchStatus();
 1162   		queryParameters.validateParameters();
 1163   		HQLQueryPlan plan = getHQLQueryPlan( query, false );
 1164   		autoFlushIfRequired( plan.getQuerySpaces() );
 1165   
 1166   		boolean success = false;
 1167   		int result = 0;
 1168   		try {
 1169   			result = plan.performExecuteUpdate( queryParameters, this );
 1170   			success = true;
 1171   		}
 1172   		finally {
 1173   			afterOperation(success);
 1174   		}
 1175   		return result;
 1176   	}
 1177   
 1178       public int executeNativeUpdate(NativeSQLQuerySpecification nativeQuerySpecification,
 1179               QueryParameters queryParameters) throws HibernateException {
 1180           errorIfClosed();
 1181           checkTransactionSynchStatus();
 1182           queryParameters.validateParameters();
 1183           NativeSQLQueryPlan plan = getNativeSQLQueryPlan(nativeQuerySpecification);
 1184   
 1185           
 1186           autoFlushIfRequired( plan.getCustomQuery().getQuerySpaces() );
 1187           
 1188           boolean success = false;
 1189           int result = 0;
 1190           try {
 1191               result = plan.performExecuteUpdate(queryParameters, this);
 1192               success = true;
 1193           } finally {
 1194               afterOperation(success);
 1195           }
 1196           return result;
 1197       }
 1198   
 1199   	public Iterator iterate(String query) throws HibernateException {
 1200   		return iterate( query, new QueryParameters() );
 1201   	}
 1202   
 1203   	public Iterator iterate(String query, Object value, Type type) throws HibernateException {
 1204   		return iterate( query, new QueryParameters(type, value) );
 1205   	}
 1206   
 1207   	public Iterator iterate(String query, Object[] values, Type[] types) throws HibernateException {
 1208   		return iterate( query, new QueryParameters(types, values) );
 1209   	}
 1210   
 1211   	public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
 1212   		errorIfClosed();
 1213   		checkTransactionSynchStatus();
 1214   		queryParameters.validateParameters();
 1215   		HQLQueryPlan plan = getHQLQueryPlan( query, true );
 1216   		autoFlushIfRequired( plan.getQuerySpaces() );
 1217   
 1218   		dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
 1219   		try {
 1220   			return plan.performIterate( queryParameters, this );
 1221   		}
 1222   		finally {
 1223   			dontFlushFromFind--;
 1224   		}
 1225   	}
 1226   
 1227   	public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
 1228   		errorIfClosed();
 1229   		checkTransactionSynchStatus();
 1230   		HQLQueryPlan plan = getHQLQueryPlan( query, false );
 1231   		autoFlushIfRequired( plan.getQuerySpaces() );
 1232   		dontFlushFromFind++;
 1233   		try {
 1234   			return plan.performScroll( queryParameters, this );
 1235   		}
 1236   		finally {
 1237   			dontFlushFromFind--;
 1238   		}
 1239   	}
 1240   
 1241   	public int delete(String query) throws HibernateException {
 1242   		return delete( query, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY );
 1243   	}
 1244   
 1245   	public int delete(String query, Object value, Type type) throws HibernateException {
 1246   		return delete( query, new Object[]{value}, new Type[]{type} );
 1247   	}
 1248   
 1249   	public int delete(String query, Object[] values, Type[] types) throws HibernateException {
 1250   		errorIfClosed();
 1251   		checkTransactionSynchStatus();
 1252   		if ( query == null ) {
 1253   			throw new IllegalArgumentException("attempt to perform delete-by-query with null query");
 1254   		}
 1255   
 1256   		if ( log.isTraceEnabled() ) {
 1257   			log.trace( "delete: " + query );
 1258   			if ( values.length != 0 ) {
 1259   				log.trace( "parameters: " + StringHelper.toString( values ) );
 1260   			}
 1261   		}
 1262   
 1263   		List list = find( query, values, types );
 1264   		int deletionCount = list.size();
 1265   		for ( int i = 0; i < deletionCount; i++ ) {
 1266   			delete( list.get( i ) );
 1267   		}
 1268   
 1269   		return deletionCount;
 1270   	}
 1271   
 1272   	public Query createFilter(Object collection, String queryString) {
 1273   		errorIfClosed();
 1274   		checkTransactionSynchStatus();
 1275   		CollectionFilterImpl filter = new CollectionFilterImpl(
 1276   				queryString,
 1277   		        collection,
 1278   		        this,
 1279   		        getFilterQueryPlan( collection, queryString, null, false ).getParameterMetadata()
 1280   		);
 1281   		filter.setComment( queryString );
 1282   		return filter;
 1283   	}
 1284   	
 1285   	public Query getNamedQuery(String queryName) throws MappingException {
 1286   		errorIfClosed();
 1287   		checkTransactionSynchStatus();
 1288   		return super.getNamedQuery(queryName);
 1289   	}
 1290   
 1291   	public Object instantiate(String entityName, Serializable id) throws HibernateException {
 1292   		return instantiate( factory.getEntityPersister(entityName), id );
 1293   	}
 1294   
 1295   	/**
 1296   	 * give the interceptor an opportunity to override the default instantiation
 1297   	 */
 1298   	public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException {
 1299   		errorIfClosed();
 1300   		checkTransactionSynchStatus();
 1301   		Object result = interceptor.instantiate( persister.getEntityName(), entityMode, id );
 1302   		if ( result == null ) {
 1303   			result = persister.instantiate( id, entityMode );
 1304   		}
 1305   		return result;
 1306   	}
 1307   
 1308   	public EntityMode getEntityMode() {
 1309   		checkTransactionSynchStatus();
 1310   		return entityMode;
 1311   	}
 1312   
 1313   	public void setFlushMode(FlushMode flushMode) {
 1314   		errorIfClosed();
 1315   		checkTransactionSynchStatus();
 1316   		if ( log.isTraceEnabled() ) {
 1317   			log.trace("setting flush mode to: " + flushMode);
 1318   		}
 1319   		this.flushMode = flushMode;
 1320   	}
 1321   	
 1322   	public FlushMode getFlushMode() {
 1323   		checkTransactionSynchStatus();
 1324   		return flushMode;
 1325   	}
 1326   
 1327   	public CacheMode getCacheMode() {
 1328   		checkTransactionSynchStatus();
 1329   		return cacheMode;
 1330   	}
 1331   	
 1332   	public void setCacheMode(CacheMode cacheMode) {
 1333   		errorIfClosed();
 1334   		checkTransactionSynchStatus();
 1335   		if ( log.isTraceEnabled() ) {
 1336   			log.trace("setting cache mode to: " + cacheMode);
 1337   		}
 1338   		this.cacheMode= cacheMode; 
 1339   	}
 1340   
 1341   	public Transaction getTransaction() throws HibernateException {
 1342   		errorIfClosed();
 1343   		return jdbcContext.getTransaction();
 1344   	}
 1345   	
 1346   	public Transaction beginTransaction() throws HibernateException {
 1347   		errorIfClosed();
 1348   		if ( rootSession != null ) {
 1349   			// todo : should seriously consider not allowing a txn to begin from a child session
 1350   			//      can always route the request to the root session...
 1351   			log.warn( "Transaction started on non-root session" );
 1352   		}
 1353   		Transaction result = getTransaction();
 1354   		result.begin();
 1355   		return result;
 1356   	}
 1357   	
 1358   	public void afterTransactionBegin(Transaction tx) {
 1359   		errorIfClosed();
 1360   		interceptor.afterTransactionBegin(tx);
 1361   	}
 1362   
 1363   	public EntityPersister getEntityPersister(final String entityName, final Object object) {
 1364   		errorIfClosed();
 1365   		if (entityName==null) {
 1366   			return factory.getEntityPersister( guessEntityName( object ) );
 1367   		}
 1368   		else {
 1369   			// try block is a hack around fact that currently tuplizers are not
 1370   			// given the opportunity to resolve a subclass entity name.  this
 1371   			// allows the (we assume custom) interceptor the ability to
 1372   			// influence this decision if we were not able to based on the
 1373   			// given entityName
 1374   			try {
 1375   				return factory.getEntityPersister( entityName )
 1376   						.getSubclassEntityPersister( object, getFactory(), entityMode );
 1377   			}
 1378   			catch( HibernateException e ) {
 1379   				try {
 1380   					return getEntityPersister( null, object );
 1381   				}
 1382   				catch( HibernateException e2 ) {
 1383   					throw e;
 1384   				}
 1385   			}
 1386   		}
 1387   	}
 1388   
 1389   	// not for internal use:
 1390   	public Serializable getIdentifier(Object object) throws HibernateException {
 1391   		errorIfClosed();
 1392   		checkTransactionSynchStatus();
 1393   		if ( object instanceof HibernateProxy ) {
 1394   			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
 1395   			if ( li.getSession() != this ) {
 1396   				throw new TransientObjectException( "The proxy was not associated with this session" );
 1397   			}
 1398   			return li.getIdentifier();
 1399   		}
 1400   		else {
 1401   			EntityEntry entry = persistenceContext.getEntry(object);
 1402   			if ( entry == null ) {
 1403   				throw new TransientObjectException( "The instance was not associated with this session" );
 1404   			}
 1405   			return entry.getId();
 1406   		}
 1407   	}
 1408   
 1409   	/**
 1410   	 * Get the id value for an object that is actually associated with the session. This
 1411   	 * is a bit stricter than getEntityIdentifierIfNotUnsaved().
 1412   	 */
 1413   	public Serializable getContextEntityIdentifier(Object object) {
 1414   		errorIfClosed();
 1415   		if ( object instanceof HibernateProxy ) {
 1416   			return getProxyIdentifier(object);
 1417   		}
 1418   		else {
 1419   			EntityEntry entry = persistenceContext.getEntry(object);
 1420   			return entry != null ? entry.getId() : null;
 1421   		}
 1422   	}
 1423   	
 1424   	private Serializable getProxyIdentifier(Object proxy) {
 1425   		return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getIdentifier();
 1426   	}
 1427   
 1428   	public Collection filter(Object collection, String filter) throws HibernateException {
 1429   		return listFilter( collection, filter, new QueryParameters( new Type[1], new Object[1] ) );
 1430   	}
 1431   
 1432   	public Collection filter(Object collection, String filter, Object value, Type type) throws HibernateException {
 1433   		return listFilter( collection, filter, new QueryParameters( new Type[]{null, type}, new Object[]{null, value} ) );
 1434   	}
 1435   
 1436   	public Collection filter(Object collection, String filter, Object[] values, Type[] types) 
 1437   	throws HibernateException {
 1438   		Object[] vals = new Object[values.length + 1];
 1439   		Type[] typs = new Type[types.length + 1];
 1440   		System.arraycopy( values, 0, vals, 1, values.length );
 1441   		System.arraycopy( types, 0, typs, 1, types.length );
 1442   		return listFilter( collection, filter, new QueryParameters( typs, vals ) );
 1443   	}
 1444   
 1445   	private FilterQueryPlan getFilterQueryPlan(
 1446   			Object collection,
 1447   			String filter,
 1448   			QueryParameters parameters,
 1449   			boolean shallow) throws HibernateException {
 1450   		if ( collection == null ) {
 1451   			throw new NullPointerException( "null collection passed to filter" );
 1452   		}
 1453   
 1454   		CollectionEntry entry = persistenceContext.getCollectionEntryOrNull( collection );
 1455   		final CollectionPersister roleBeforeFlush = (entry == null) ? null : entry.getLoadedPersister();
 1456   
 1457   		FilterQueryPlan plan = null;
 1458   		if ( roleBeforeFlush == null ) {
 1459   			// if it was previously unreferenced, we need to flush in order to
 1460   			// get its state into the database in order to execute query
 1461   			flush();
 1462   			entry = persistenceContext.getCollectionEntryOrNull( collection );
 1463   			CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister();
 1464   			if ( roleAfterFlush == null ) {
 1465   				throw new QueryException( "The collection was unreferenced" );
 1466   			}
 1467   			plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() );
 1468   		}
 1469   		else {
 1470   			// otherwise, we only need to flush if there are in-memory changes
 1471   			// to the queried tables
 1472   			plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleBeforeFlush.getRole(), shallow, getEnabledFilters() );
 1473   			if ( autoFlushIfRequired( plan.getQuerySpaces() ) ) {
 1474   				// might need to run a different filter entirely after the flush
 1475   				// because the collection role may have changed
 1476   				entry = persistenceContext.getCollectionEntryOrNull( collection );
 1477   				CollectionPersister roleAfterFlush = (entry == null) ? null : entry.getLoadedPersister();
 1478   				if ( roleBeforeFlush != roleAfterFlush ) {
 1479   					if ( roleAfterFlush == null ) {
 1480   						throw new QueryException( "The collection was dereferenced" );
 1481   					}
 1482   					plan = factory.getQueryPlanCache().getFilterQueryPlan( filter, roleAfterFlush.getRole(), shallow, getEnabledFilters() );
 1483   				}
 1484   			}
 1485   		}
 1486   
 1487   		if ( parameters != null ) {
 1488   			parameters.getPositionalParameterValues()[0] = entry.getLoadedKey();
 1489   			parameters.getPositionalParameterTypes()[0] = entry.getLoadedPersister().getKeyType();
 1490   		}
 1491   
 1492   		return plan;
 1493   	}
 1494   
 1495   	public List listFilter(Object collection, String filter, QueryParameters queryParameters) 
 1496   	throws HibernateException {
 1497   		errorIfClosed();
 1498   		checkTransactionSynchStatus();
 1499   		FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, false );
 1500   		List results = CollectionHelper.EMPTY_LIST;
 1501   
 1502   		boolean success = false;
 1503   		dontFlushFromFind++;   //stops flush being called multiple times if this method is recursively called
 1504   		try {
 1505   			results = plan.performList( queryParameters, this );
 1506   			success = true;
 1507   		}
 1508   		finally {
 1509   			dontFlushFromFind--;
 1510   			afterOperation(success);
 1511   		}
 1512   		return results;
 1513   	}
 1514   
 1515   	public Iterator iterateFilter(Object collection, String filter, QueryParameters queryParameters) 
 1516   	throws HibernateException {
 1517   		errorIfClosed();
 1518   		checkTransactionSynchStatus();
 1519   		FilterQueryPlan plan = getFilterQueryPlan( collection, filter, queryParameters, true );
 1520   		return plan.performIterate( queryParameters, this );
 1521   	}
 1522   
 1523   	public Criteria createCriteria(Class persistentClass, String alias) {
 1524   		errorIfClosed();
 1525   		checkTransactionSynchStatus();
 1526   		return new CriteriaImpl( persistentClass.getName(), alias, this );
 1527   	}
 1528   
 1529   	public Criteria createCriteria(String entityName, String alias) {
 1530   		errorIfClosed();
 1531   		checkTransactionSynchStatus();
 1532   		return new CriteriaImpl(entityName, alias, this);
 1533   	}
 1534   
 1535   	public Criteria createCriteria(Class persistentClass) {
 1536   		errorIfClosed();
 1537   		checkTransactionSynchStatus();
 1538   		return new CriteriaImpl( persistentClass.getName(), this );
 1539   	}
 1540   
 1541   	public Criteria createCriteria(String entityName) {
 1542   		errorIfClosed();
 1543   		checkTransactionSynchStatus();
 1544   		return new CriteriaImpl(entityName, this);
 1545   	}
 1546   
 1547   	public ScrollableResults scroll(CriteriaImpl criteria, ScrollMode scrollMode) {
 1548   		errorIfClosed();
 1549   		checkTransactionSynchStatus();
 1550   		String entityName = criteria.getEntityOrClassName();
 1551   		CriteriaLoader loader = new CriteriaLoader(
 1552   				getOuterJoinLoadable(entityName),
 1553   				factory,
 1554   				criteria,
 1555   				entityName,
 1556   				getEnabledFilters()
 1557   		);
 1558   		autoFlushIfRequired( loader.getQuerySpaces() );
 1559   		dontFlushFromFind++;
 1560   		try {
 1561   			return loader.scroll(this, scrollMode);
 1562   		}
 1563   		finally {
 1564   			dontFlushFromFind--;
 1565   		}
 1566   	}
 1567   
 1568   	public List list(CriteriaImpl criteria) throws HibernateException {
 1569   		errorIfClosed();
 1570   		checkTransactionSynchStatus();
 1571   		String[] implementors = factory.getImplementors( criteria.getEntityOrClassName() );
 1572   		int size = implementors.length;
 1573   
 1574   		CriteriaLoader[] loaders = new CriteriaLoader[size];
 1575   		Set spaces = new HashSet();
 1576   		for( int i=0; i <size; i++ ) {
 1577   
 1578   			loaders[i] = new CriteriaLoader(
 1579   					getOuterJoinLoadable( implementors[i] ),
 1580   					factory,
 1581   					criteria,
 1582   					implementors[i],
 1583   					getEnabledFilters()
 1584   				);
 1585   
 1586   			spaces.addAll( loaders[i].getQuerySpaces() );
 1587   
 1588   		}
 1589   
 1590   		autoFlushIfRequired(spaces);
 1591   
 1592   		List results = Collections.EMPTY_LIST;
 1593   		dontFlushFromFind++;
 1594   		boolean success = false;
 1595   		try {
 1596   			for( int i=0; i<size; i++ ) {
 1597   				final List currentResults = loaders[i].list(this);
 1598   				currentResults.addAll(results);
 1599   				results = currentResults;
 1600   			}
 1601   			success = true;
 1602   		}
 1603   		finally {
 1604   			dontFlushFromFind--;
 1605   			afterOperation(success);
 1606   		}
 1607   
 1608   		return results;
 1609   	}
 1610   
 1611   	private OuterJoinLoadable getOuterJoinLoadable(String entityName) throws MappingException {
 1612   		EntityPersister persister = factory.getEntityPersister(entityName);
 1613   		if ( !(persister instanceof OuterJoinLoadable) ) {
 1614   			throw new MappingException( "class persister is not OuterJoinLoadable: " + entityName );
 1615   		}
 1616   		return ( OuterJoinLoadable ) persister;
 1617   	}
 1618   
 1619   	public boolean contains(Object object) {
 1620   		errorIfClosed();
 1621   		checkTransactionSynchStatus();
 1622   		if ( object instanceof HibernateProxy ) {
 1623   			//do not use proxiesByKey, since not all
 1624   			//proxies that point to this session's
 1625   			//instances are in that collection!
 1626   			LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
 1627   			if ( li.isUninitialized() ) {
 1628   				//if it is an uninitialized proxy, pointing
 1629   				//with this session, then when it is accessed,
 1630   				//the underlying instance will be "contained"
 1631   				return li.getSession()==this;
 1632   			}
 1633   			else {
 1634   				//if it is initialized, see if the underlying
 1635   				//instance is contained, since we need to 
 1636   				//account for the fact that it might have been
 1637   				//evicted
 1638   				object = li.getImplementation();
 1639   			}
 1640   		}
 1641   		// A session is considered to contain an entity only if the entity has
 1642   		// an entry in the session's persistence context and the entry reports
 1643   		// that the entity has not been removed
 1644   		EntityEntry entry = persistenceContext.getEntry( object );
 1645   		return entry != null && entry.getStatus() != Status.DELETED && entry.getStatus() != Status.GONE;
 1646   	}
 1647   	
 1648   	public Query createQuery(String queryString) {
 1649   		errorIfClosed();
 1650   		checkTransactionSynchStatus();
 1651   		return super.createQuery(queryString);
 1652   	}
 1653   	
 1654   	public SQLQuery createSQLQuery(String sql) {
 1655   		errorIfClosed();
 1656   		checkTransactionSynchStatus();
 1657   		return super.createSQLQuery(sql);
 1658   	}
 1659   
 1660   	public Query createSQLQuery(String sql, String returnAlias, Class returnClass) {
 1661   		errorIfClosed();
 1662   		checkTransactionSynchStatus();
 1663   		return new SQLQueryImpl(
 1664   				sql,
 1665   		        new String[] { returnAlias },
 1666   		        new Class[] { returnClass },
 1667   		        this,
 1668   		        factory.getQueryPlanCache().getSQLParameterMetadata( sql )
 1669   		);
 1670   	}
 1671   
 1672   	public Query createSQLQuery(String sql, String returnAliases[], Class returnClasses[]) {
 1673   		errorIfClosed();
 1674   		checkTransactionSynchStatus();
 1675   		return new SQLQueryImpl(
 1676   				sql,
 1677   		        returnAliases,
 1678   		        returnClasses,
 1679   		        this,
 1680   		        factory.getQueryPlanCache().getSQLParameterMetadata( sql )
 1681   		);
 1682   	}
 1683   
 1684   	public ScrollableResults scrollCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
 1685   	throws HibernateException {
 1686   		errorIfClosed();
 1687   		checkTransactionSynchStatus();
 1688   
 1689   		if ( log.isTraceEnabled() ) {
 1690   			log.trace( "scroll SQL query: " + customQuery.getSQL() );
 1691   		}
 1692   
 1693   		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
 1694   
 1695   		autoFlushIfRequired( loader.getQuerySpaces() );
 1696   
 1697   		dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
 1698   		try {
 1699   			return loader.scroll(queryParameters, this);
 1700   		}
 1701   		finally {
 1702   			dontFlushFromFind--;
 1703   		}
 1704   	}
 1705   
 1706   	// basically just an adapted copy of find(CriteriaImpl)
 1707   	public List listCustomQuery(CustomQuery customQuery, QueryParameters queryParameters) 
 1708   	throws HibernateException {
 1709   		errorIfClosed();
 1710   		checkTransactionSynchStatus();
 1711   
 1712   		if ( log.isTraceEnabled() ) {
 1713   			log.trace( "SQL query: " + customQuery.getSQL() );
 1714   		}
 1715   		
 1716   		CustomLoader loader = new CustomLoader( customQuery, getFactory() );
 1717   
 1718   		autoFlushIfRequired( loader.getQuerySpaces() );
 1719   
 1720   		dontFlushFromFind++;
 1721   		boolean success = false;
 1722   		try {
 1723   			List results = loader.list(this, queryParameters);
 1724   			success = true;
 1725   			return results;
 1726   		}
 1727   		finally {
 1728   			dontFlushFromFind--;
 1729   			afterOperation(success);
 1730   		}
 1731   	}
 1732   
 1733   	public SessionFactory getSessionFactory() {
 1734   		checkTransactionSynchStatus();
 1735   		return factory;
 1736   	}
 1737   	
 1738   	public void initializeCollection(PersistentCollection collection, boolean writing) 
 1739   	throws HibernateException {
 1740   		errorIfClosed();
 1741   		checkTransactionSynchStatus();
 1742   		InitializeCollectionEventListener[] listener = listeners.getInitializeCollectionEventListeners();
 1743   		for ( int i = 0; i < listener.length; i++ ) {
 1744   			listener[i].onInitializeCollection( new InitializeCollectionEvent(collection, this) );
 1745   		}
 1746   	}
 1747   
 1748   	public String bestGuessEntityName(Object object) {
 1749   		if (object instanceof HibernateProxy) {
 1750   			LazyInitializer initializer = ( ( HibernateProxy ) object ).getHibernateLazyInitializer();
 1751   			// it is possible for this method to be called during flush processing,
 1752   			// so make certain that we do not accidently initialize an uninitialized proxy
 1753   			if ( initializer.isUninitialized() ) {
 1754   				return initializer.getEntityName();
 1755   			}
 1756   			object = initializer.getImplementation();
 1757   		}
 1758   		EntityEntry entry = persistenceContext.getEntry(object);
 1759   		if (entry==null) {
 1760   			return guessEntityName(object);
 1761   		}
 1762   		else {
 1763   			return entry.getPersister().getEntityName();
 1764   		}
 1765   	}
 1766   	
 1767   	public String getEntityName(Object object) {
 1768   		errorIfClosed();
 1769   		checkTransactionSynchStatus();
 1770   		if (object instanceof HibernateProxy) {
 1771   			if ( !persistenceContext.containsProxy( object ) ) {
 1772   				throw new TransientObjectException("proxy was not associated with the session");
 1773   			}
 1774   			object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation();
 1775   		}
 1776   
 1777   		EntityEntry entry = persistenceContext.getEntry(object);
 1778   		if ( entry == null ) {
 1779   			throwTransientObjectException( object );
 1780   		}
 1781   		return entry.getPersister().getEntityName();
 1782   	}
 1783   
 1784   	private void throwTransientObjectException(Object object) throws HibernateException {
 1785   		throw new TransientObjectException(
 1786   				"object references an unsaved transient instance - save the transient instance before flushing: " +
 1787   				guessEntityName(object)
 1788   			);
 1789   	}
 1790   
 1791   	public String guessEntityName(Object object) throws HibernateException {
 1792   		errorIfClosed();
 1793   		return entityNameResolver.resolveEntityName( object );
 1794   	}
 1795   
 1796   	public void cancelQuery() throws HibernateException {
 1797   		errorIfClosed();
 1798   		getBatcher().cancelLastQuery();
 1799   	}
 1800   
 1801   	public Interceptor getInterceptor() {
 1802   		checkTransactionSynchStatus();
 1803   		return interceptor;
 1804   	}
 1805   
 1806   	public int getDontFlushFromFind() {
 1807   		return dontFlushFromFind;
 1808   	}
 1809   
 1810   	public String toString() {
 1811   		StringBuffer buf = new StringBuffer(500)
 1812   			.append( "SessionImpl(" );
 1813   		if ( !isClosed() ) {
 1814   			buf.append(persistenceContext)
 1815   				.append(";")
 1816   				.append(actionQueue);
 1817   		}
 1818   		else {
 1819   			buf.append("<closed>");
 1820   		}
 1821   		return buf.append(')').toString();
 1822   	}
 1823   
 1824   	public EventListeners getListeners() {
 1825   		return listeners;
 1826   	}
 1827   
 1828   	public ActionQueue getActionQueue() {
 1829   		errorIfClosed();
 1830   		checkTransactionSynchStatus();
 1831   		return actionQueue;
 1832   	}
 1833   	
 1834   	public PersistenceContext getPersistenceContext() {
 1835   		errorIfClosed();
 1836   		checkTransactionSynchStatus();
 1837   		return persistenceContext;
 1838   	}
 1839   	
 1840   	public SessionStatistics getStatistics() {
 1841   		checkTransactionSynchStatus();
 1842   		return new SessionStatisticsImpl(this);
 1843   	}
 1844   
 1845   	public boolean isEventSource() {
 1846   		checkTransactionSynchStatus();
 1847   		return true;
 1848   	}
 1849   
 1850   	public void setReadOnly(Object entity, boolean readOnly) {
 1851   		errorIfClosed();
 1852   		checkTransactionSynchStatus();
 1853   		persistenceContext.setReadOnly(entity, readOnly);
 1854   	}
 1855   
 1856   	public void doWork(Work work) throws HibernateException {
 1857   		try {
 1858   			work.execute( jdbcContext.getConnectionManager().getConnection() );
 1859   			jdbcContext.getConnectionManager().afterStatement();
 1860   		}
 1861   		catch ( SQLException e ) {
 1862   			throw JDBCExceptionHelper.convert( factory.getSettings().getSQLExceptionConverter(), e, "error executing work" );
 1863   		}
 1864   	}
 1865   
 1866   	public void afterScrollOperation() {
 1867   		// nothing to do in a stateful session
 1868   	}
 1869   
 1870   	public String getFetchProfile() {
 1871   		checkTransactionSynchStatus();
 1872   		return fetchProfile;
 1873   	}
 1874   
 1875   	public JDBCContext getJDBCContext() {
 1876   		errorIfClosed();
 1877   		checkTransactionSynchStatus();
 1878   		return jdbcContext;
 1879   	}
 1880   
 1881   	public void setFetchProfile(String fetchProfile) {
 1882   		errorIfClosed();
 1883   		checkTransactionSynchStatus();
 1884   		this.fetchProfile = fetchProfile;
 1885   	}
 1886   
 1887   	private void checkTransactionSynchStatus() {
 1888   		if ( jdbcContext != null && !isClosed() ) {
 1889   			jdbcContext.registerSynchronizationIfPossible();
 1890   		}
 1891   	}
 1892   
 1893   	/**
 1894   	 * Used by JDK serialization...
 1895   	 *
 1896   	 * @param ois The input stream from which we are being read...
 1897   	 * @throws IOException Indicates a general IO stream exception
 1898   	 * @throws ClassNotFoundException Indicates a class resolution issue
 1899   	 */
 1900   	private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
 1901   		log.trace( "deserializing session" );
 1902   
 1903   		entityNameResolver = new CoordinatingEntityNameResolver();
 1904   
 1905   		boolean isRootSession = ois.readBoolean();
 1906   		connectionReleaseMode = ConnectionReleaseMode.parse( ( String ) ois.readObject() );
 1907   		entityMode = EntityMode.parse( ( String ) ois.readObject() );
 1908   		autoClear = ois.readBoolean();
 1909   		flushMode = FlushMode.parse( ( String ) ois.readObject() );
 1910   		cacheMode = CacheMode.parse( ( String ) ois.readObject() );
 1911   		flushBeforeCompletionEnabled = ois.readBoolean();
 1912   		autoCloseSessionEnabled = ois.readBoolean();
 1913   		fetchProfile = ( String ) ois.readObject();
 1914   		interceptor = ( Interceptor ) ois.readObject();
 1915   
 1916   		factory = SessionFactoryImpl.deserialize( ois );
 1917   		listeners = factory.getEventListeners();
 1918   
 1919   		if ( isRootSession ) {
 1920   			jdbcContext = JDBCContext.deserialize( ois, this, interceptor );
 1921   		}
 1922   
 1923   		persistenceContext = StatefulPersistenceContext.deserialize( ois, this );
 1924   		actionQueue = ActionQueue.deserialize( ois, this );
 1925   
 1926   		enabledFilters = ( Map ) ois.readObject();
 1927   		childSessionsByEntityMode = ( Map ) ois.readObject();
 1928   
 1929   		Iterator iter = enabledFilters.values().iterator();
 1930   		while ( iter.hasNext() ) {
 1931   			( ( FilterImpl ) iter.next() ).afterDeserialize(factory);
 1932   		}
 1933   
 1934   		if ( isRootSession && childSessionsByEntityMode != null ) {
 1935   			iter = childSessionsByEntityMode.values().iterator();
 1936   			while ( iter.hasNext() ) {
 1937   				final SessionImpl child = ( ( SessionImpl ) iter.next() );
 1938   				child.rootSession = this;
 1939   				child.jdbcContext = this.jdbcContext;
 1940   			}
 1941   		}
 1942   	}
 1943   
 1944   	/**
 1945   	 * Used by JDK serialization...
 1946   	 *
 1947   	 * @param oos The output stream to which we are being written...
 1948   	 * @throws IOException Indicates a general IO stream exception
 1949   	 */
 1950   	private void writeObject(ObjectOutputStream oos) throws IOException {
 1951   		if ( !jdbcContext.getConnectionManager().isReadyForSerialization() ) {
 1952   			throw new IllegalStateException( "Cannot serialize a session while connected" );
 1953   		}
 1954   
 1955   		log.trace( "serializing session" );
 1956   
 1957   		oos.writeBoolean( rootSession == null );
 1958   		oos.writeObject( connectionReleaseMode.toString() );
 1959   		oos.writeObject( entityMode.toString() );
 1960   		oos.writeBoolean( autoClear );
 1961   		oos.writeObject( flushMode.toString() );
 1962   		oos.writeObject( cacheMode.toString() );
 1963   		oos.writeBoolean( flushBeforeCompletionEnabled );
 1964   		oos.writeBoolean( autoCloseSessionEnabled );
 1965   		oos.writeObject( fetchProfile );
 1966   		// we need to writeObject() on this since interceptor is user defined
 1967   		oos.writeObject( interceptor );
 1968   
 1969   		factory.serialize( oos );
 1970   
 1971   		if ( rootSession == null ) {
 1972   			jdbcContext.serialize( oos );
 1973   		}
 1974   
 1975   		persistenceContext.serialize( oos );
 1976   		actionQueue.serialize( oos );
 1977   
 1978   		// todo : look at optimizing these...
 1979   		oos.writeObject( enabledFilters );
 1980   		oos.writeObject( childSessionsByEntityMode );
 1981   	}
 1982   
 1983   	private class CoordinatingEntityNameResolver implements EntityNameResolver {
 1984   		public String resolveEntityName(Object entity) {
 1985   			String entityName = interceptor.getEntityName( entity );
 1986   			if ( entityName != null ) {
 1987   				return entityName;
 1988   			}
 1989   
 1990   			Iterator itr = factory.iterateEntityNameResolvers( entityMode );
 1991   			while ( itr.hasNext() ) {
 1992   				final EntityNameResolver resolver = ( EntityNameResolver ) itr.next();
 1993   				entityName = resolver.resolveEntityName( entity );
 1994   				if ( entityName != null ) {
 1995   					break;
 1996   				}
 1997   			}
 1998   			if ( entityName != null ) {
 1999   				return entityName;
 2000   			}
 2001   
 2002   			// the old-time stand-by...
 2003   			return entity.getClass().getName();
 2004   		}
 2005   	}
 2006   }

Save This Page
Home » Hibernate-3.3.2.GA » org.hibernate » impl » [javadoc | source]