Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/hibernate/impl/SessionImpl.java


1   //$Id: SessionImpl.java,v 1.126 2005/04/24 00:11:46 oneovthafew Exp $
2   package org.hibernate.impl;
3   
4   import java.io.IOException;
5   import java.io.ObjectInputStream;
6   import java.io.ObjectOutputStream;
7   import java.io.Serializable;
8   import java.sql.Connection;
9   import java.util.Collection;
10  import java.util.Collections;
11  import java.util.HashMap;
12  import java.util.HashSet;
13  import java.util.Iterator;
14  import java.util.List;
15  import java.util.Map;
16  import java.util.Set;
17  
18  import org.apache.commons.logging.Log;
19  import org.apache.commons.logging.LogFactory;
20  import org.dom4j.Element;
21  import org.hibernate.CacheMode;
22  import org.hibernate.Criteria;
23  import org.hibernate.EntityMode;
24  import org.hibernate.Filter;
25  import org.hibernate.FlushMode;
26  import org.hibernate.HibernateException;
27  import org.hibernate.Interceptor;
28  import org.hibernate.LockMode;
29  import org.hibernate.MappingException;
30  import org.hibernate.ObjectDeletedException;
31  import org.hibernate.ObjectNotFoundException;
32  import org.hibernate.Query;
33  import org.hibernate.QueryException;
34  import org.hibernate.ReplicationMode;
35  import org.hibernate.SQLQuery;
36  import org.hibernate.ScrollMode;
37  import org.hibernate.ScrollableResults;
38  import org.hibernate.Session;
39  import org.hibernate.SessionFactory;
40  import org.hibernate.Transaction;
41  import org.hibernate.TransientObjectException;
42  import org.hibernate.UnresolvableObjectException;
43  import org.hibernate.collection.PersistentCollection;
44  import org.hibernate.engine.ActionQueue;
45  import org.hibernate.engine.CollectionEntry;
46  import org.hibernate.engine.EntityEntry;
47  import org.hibernate.engine.EntityKey;
48  import org.hibernate.engine.FilterDefinition;
49  import org.hibernate.engine.NamedQueryDefinition;
50  import org.hibernate.engine.NamedSQLQueryDefinition;
51  import org.hibernate.engine.PersistenceContext;
52  import org.hibernate.engine.QueryParameters;
53  import org.hibernate.engine.SessionFactoryImplementor;
54  import org.hibernate.engine.SessionImplementor;
55  import org.hibernate.engine.Status;
56  import org.hibernate.event.AutoFlushEvent;
57  import org.hibernate.event.PersistEvent;
58  import org.hibernate.event.DeleteEvent;
59  import org.hibernate.event.DirtyCheckEvent;
60  import org.hibernate.event.EvictEvent;
61  import org.hibernate.event.FlushEvent;
62  import org.hibernate.event.InitializeCollectionEvent;
63  import org.hibernate.event.LoadEvent;
64  import org.hibernate.event.LoadEventListener;
65  import org.hibernate.event.LockEvent;
66  import org.hibernate.event.MergeEvent;
67  import org.hibernate.event.RefreshEvent;
68  import org.hibernate.event.ReplicateEvent;
69  import org.hibernate.event.SaveOrUpdateEvent;
70  import org.hibernate.event.SessionEventListenerConfig;
71  import org.hibernate.hql.FilterTranslator;
72  import org.hibernate.hql.QuerySplitter;
73  import org.hibernate.hql.QueryTranslator;
74  import org.hibernate.jdbc.Batcher;
75  import org.hibernate.jdbc.JDBCContext;
76  import org.hibernate.loader.criteria.CriteriaLoader;
77  import org.hibernate.loader.custom.CustomLoader;
78  import org.hibernate.loader.custom.CustomQuery;
79  import org.hibernate.persister.collection.CollectionPersister;
80  import org.hibernate.persister.entity.EntityPersister;
81  import org.hibernate.persister.entity.OuterJoinLoadable;
82  import org.hibernate.pretty.MessageHelper;
83  import org.hibernate.proxy.HibernateProxy;
84  import org.hibernate.proxy.LazyInitializer;
85  import org.hibernate.type.Type;
86  import org.hibernate.util.ArrayHelper;
87  import org.hibernate.util.CollectionHelper;
88  import org.hibernate.util.EmptyIterator;
89  import org.hibernate.util.JoinedIterator;
90  import org.hibernate.util.StringHelper;
91  
92  
93  /**
94   * Concrete implementation of a Session, and also the central, organizing component
95   * of Hibernate's internal implementation. As such, this class exposes two interfaces;
96   * Session itself, to the application, and SessionImplementor, to other components
97   * of Hibernate. This class is not threadsafe.
98   *
99   * @author Gavin King
100  */
101 public final class SessionImpl implements SessionImplementor, JDBCContext.Context {
102 
103   // todo : need to find a clean way to handle the "event source" role
104   // a seperate classs responsible for generating/dispatching events just duplicates most of the Session methods...
105   // passing around seperate references to interceptor, factory, actionQueue, and persistentContext is not manageable...
106 
107   private static final Log log = LogFactory.getLog(SessionImpl.class);
108 
109   private transient SessionFactoryImpl factory;
110   private EntityMode entityMode = EntityMode.POJO;
111 
112   private final long timestamp;
113   private boolean closed = false;
114   private FlushMode flushMode = FlushMode.AUTO;
115   private CacheMode cacheMode = CacheMode.NORMAL;
116 
117   private Interceptor interceptor;
118 
119   private transient int dontFlushFromFind = 0;
120 
121   private ActionQueue actionQueue;
122   private PersistenceContext persistenceContext;
123   private transient JDBCContext jdbcContext;
124   private SessionEventListenerConfig listeners;
125 
126   private boolean flushBeforeCompletionEnabled;
127   private boolean autoCloseSessionEnabled;
128 
129   private Map enabledFilters = new HashMap();
130 
131   private boolean isRootSession = true;
132   private Map childSessionsByEntityMode;
133 
134 
135   public Session getSession(EntityMode entityMode) {
136     if ( this.entityMode == entityMode ) {
137       return this;
138     }
139 
140     if ( childSessionsByEntityMode == null ) {
141       childSessionsByEntityMode = new HashMap();
142     }
143 
144     SessionImpl rtn = (SessionImpl) childSessionsByEntityMode.get( entityMode );
145     if ( rtn == null ) {
146       rtn = new SessionImpl( this, entityMode );
147       childSessionsByEntityMode.put( entityMode, rtn );
148     }
149 
150     return rtn;
151   }
152 
153 
154   private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
155     log.trace("deserializing session");
156 
157     interceptor = (Interceptor) ois.readObject();
158     factory = (SessionFactoryImpl) ois.readObject();
159     jdbcContext = (JDBCContext) ois.readObject();
160     ois.defaultReadObject();
161   }
162 
163   private void writeObject(ObjectOutputStream oos) throws IOException {
164     if ( isConnected() ) throw new IllegalStateException( "Cannot serialize a Session while connected" );
165 
166     log.trace( "serializing session" );
167 
168     oos.writeObject(interceptor);
169     oos.writeObject(factory);
170     oos.writeObject(jdbcContext);
171     oos.defaultWriteObject();
172 
173   }
174 
175   public void clear() {
176     persistenceContext.clear();
177     actionQueue.clear();
178   }
179 
180   private SessionImpl(SessionImpl parent, EntityMode entityMode) {
181     this.factory = parent.factory;
182 
183     this.timestamp = parent.timestamp;
184 
185     this.jdbcContext = parent.jdbcContext;
186 
187     this.interceptor = parent.interceptor;
188     this.listeners = parent.listeners;
189 
190     this.actionQueue = new ActionQueue(this);
191 
192     this.entityMode = entityMode;
193     this.persistenceContext = new PersistenceContext(this);
194 
195     this.isRootSession = false;
196 
197     if ( factory.getStatistics().isStatisticsEnabled() ) {
198       factory.getStatisticsImplementor().openSession();
199     }
200     
201     log.debug( "opened session [" + entityMode + "]" );
202   }
203 
204   SessionImpl(
205       final Connection connection,
206       final SessionFactoryImpl factory,
207       final boolean autoclose,
208       final long timestamp,
209       final Interceptor interceptor,
210       final SessionEventListenerConfig listeners,
211       final EntityMode entityMode,
212       final boolean flushBeforeCompletionEnabled,
213       final boolean autoCloseSessionEnabled) {
214     this.factory = factory;
215 
216     this.timestamp = timestamp;
217 
218     this.entityMode = entityMode;
219 
220     this.interceptor = interceptor;
221     this.listeners = listeners;
222 
223     this.actionQueue = new ActionQueue( this );
224     this.persistenceContext = new PersistenceContext( this );
225 
226     this.isRootSession = true;
227 
228     this.flushBeforeCompletionEnabled = flushBeforeCompletionEnabled;
229     this.autoCloseSessionEnabled = autoCloseSessionEnabled;
230 
231     this.jdbcContext = new JDBCContext( this, connection, autoclose );
232 
233     if ( factory.getStatistics().isStatisticsEnabled() ) {
234       factory.getStatisticsImplementor().openSession();
235     }
236     
237     if ( log.isDebugEnabled() ) log.debug( "opened session at timestamp: " + timestamp );
238   }
239 
240   public Batcher getBatcher() {
241     return jdbcContext.getBatcher();
242   }
243 
244   public SessionFactoryImplementor getFactory() {
245     return factory;
246   }
247 
248   public long getTimestamp() {
249     return timestamp;
250   }
251 
252   public Connection close() throws HibernateException {
253 
254     log.trace( "closing session" );
255 
256     if ( factory.getStatistics().isStatisticsEnabled() ) 
257       factory.getStatisticsImplementor().closeSession();
258 
259     try {
260       try {
261         if ( childSessionsByEntityMode != null ) {
262           Iterator childSessions = childSessionsByEntityMode.values().iterator();
263           while ( childSessions.hasNext() ) {
264             final SessionImpl child = ( SessionImpl ) childSessions.next();
265             child.close();
266           }
267         }
268       }
269       catch( Throwable t ) {
270         // just ignore
271       }
272 
273       if ( isRootSession ) {
274         return jdbcContext.release();
275       }
276       else {
277         return null;
278       }
279     }
280     finally {
281       closed = true;
282       cleanup();
283     }
284   }
285 
286   public boolean isAggressiveReleaseEnabled() {
287     return factory.getSettings().isAggressiveReleaseEnabled();
288   }
289 
290   public boolean isAutoCloseSessionEnabled() {
291     return autoCloseSessionEnabled;
292   }
293 
294   public boolean isOpen() {
295     return !closed;
296   }
297 
298   public boolean isFlushModeNever() {
299     return getFlushMode() == FlushMode.NEVER;
300   }
301 
302   public boolean isFlushBeforeCompletionEnabled() {
303     return flushBeforeCompletionEnabled;
304   }
305 
306   public void managedFlush() {
307 
308     log.trace("automatically flushing session");
309     flush();
310     
311     if ( childSessionsByEntityMode != null ) {
312       Iterator iter = childSessionsByEntityMode.values().iterator();
313       while ( iter.hasNext() ) {
314         ( (Session) iter.next() ).flush();
315       }
316     }
317     
318   }
319 
320   public boolean shouldAutoClose() {
321     return isAutoCloseSessionEnabled() && isOpen();
322   }
323 
324   public void managedClose() {
325     log.trace("automatically closing session");
326     close();
327   }
328 
329   public Connection connection() throws HibernateException {
330     return jdbcContext.connection();
331   }
332 
333   public boolean isConnected() {
334     return jdbcContext.isConnected();
335   }
336 
337   public Connection disconnect() throws HibernateException {
338     log.debug( "disconnecting session" );
339         return jdbcContext.disconnect();
340   }
341 
342   public void reconnect() throws HibernateException {
343     log.debug( "reconnecting session" );
344     jdbcContext.reconnect();
345   }
346 
347   public void reconnect(Connection conn) throws HibernateException {
348     log.debug( "reconnecting session" );
349     jdbcContext.reconnect( conn );
350   }
351 
352   public void beforeTransactionCompletion(Transaction tx) {
353     log.trace( "before transaction completion" );
354 
355     if ( !isRootSession ) {
356       log.trace( "skipping beforeTransactionCompletion processing as this is not root session" );
357       return;
358     }
359 
360     try {
361       interceptor.beforeTransactionCompletion(tx);
362     }
363     catch (Throwable t) {
364       log.error("exception in interceptor beforeTransactionCompletion()", t);
365     }
366   }
367 
368   public void afterTransactionCompletion(boolean success, Transaction tx) {
369     log.trace( "after transaction completion" );
370 
371     persistenceContext.afterTransactionCompletion();
372     actionQueue.afterTransactionCompletion(success);
373 
374     if ( isRootSession ) {
375 
376       try {
377         interceptor.afterTransactionCompletion(tx);
378       }
379       catch (Throwable t) {
380         log.error("exception in interceptor beforeTransactionCompletion()", t);
381       }
382       
383     }
384     
385   }
386 
387   /**
388    * clear all the internal collections, just 
389    * to help the garbage collector, does not
390    * clear anything that is needed during the
391    * afterTransactionCompletion() phase
392    */
393   private void cleanup() {
394     persistenceContext.clear();
395   }
396 
397   public LockMode getCurrentLockMode(Object object) throws HibernateException {
398     if ( object == null ) throw new NullPointerException( "null object passed to getCurrentLockMode()" );
399     if ( object instanceof HibernateProxy ) {
400       object = ( (HibernateProxy) object ).getHibernateLazyInitializer().getImplementation(this);
401       if ( object == null ) return LockMode.NONE;
402     }
403     EntityEntry e = persistenceContext.getEntry(object);
404     if ( e == null ) throw new TransientObjectException( "Given object not associated with the session" );
405     if ( e.getStatus() != Status.MANAGED ) throw new ObjectDeletedException( 
406         "The given object was deleted", 
407         e.getId(), e.getPersister().getEntityName() 
408     );
409     return e.getLockMode();
410   }
411 
412   public Object getEntityUsingInterceptor(EntityKey key) throws HibernateException {
413     // todo : should this get moved to PersistentContext?
414     // logically, is PersistentContext the "thing" to which an interceptor gets attached?
415     final Object result = persistenceContext.getEntity(key);
416     if ( result == null ) {
417       final Object newObject = interceptor.getEntity( key.getEntityName(), key.getIdentifier() );
418       if ( newObject != null ) lock(newObject, LockMode.NONE);
419       return newObject;
420     }
421     else {
422       return result;
423     }
424   }
425 
426   public void saveOrUpdate(Object object) throws HibernateException {
427     saveOrUpdate(null, object);
428   }
429 
430   public void saveOrUpdate(String entityName, Object obj) throws HibernateException {
431     SaveOrUpdateEvent event = new SaveOrUpdateEvent(entityName, obj, this);
432     listeners.getSaveOrUpdateEventListener().onSaveOrUpdate(event);
433   }
434 
435   public void save(Object obj, Serializable id) throws HibernateException {
436     save(null, obj, id);
437   }
438 
439   public Serializable save(Object obj) throws HibernateException {
440     return save(null, obj);
441   }
442 
443   public Serializable save(String entityName, Object object) throws HibernateException {
444     SaveOrUpdateEvent event = new SaveOrUpdateEvent(entityName, object, this);
445     return listeners.getSaveEventListener().onSaveOrUpdate(event);
446   }
447 
448   public void save(String entityName, Object object, Serializable id) throws HibernateException {
449     SaveOrUpdateEvent event = new SaveOrUpdateEvent(entityName, object, id, this);
450     listeners.getSaveEventListener().onSaveOrUpdate(event);
451   }
452 
453   public void update(Object obj) throws HibernateException {
454     update(null, obj);
455   }
456 
457   public void update(Object obj, Serializable id) throws HibernateException {
458     update(null, obj, id);
459   }
460 
461   public void update(String entityName, Object object) throws HibernateException {
462     SaveOrUpdateEvent event = new SaveOrUpdateEvent(entityName, object, this);
463     listeners.getUpdateEventListener().onSaveOrUpdate(event);
464   }
465 
466   public void update(String entityName, Object object, Serializable id) throws HibernateException {
467     SaveOrUpdateEvent event = new SaveOrUpdateEvent(entityName, object, id, this);
468     listeners.getUpdateEventListener().onSaveOrUpdate(event);
469   }
470 
471   public void lock(Object object, LockMode lockMode) throws HibernateException {
472         listeners.getLockEventListener().onLock( new LockEvent(object, lockMode, this) );
473   }
474 
475   public void lock(String entityName, Object object, LockMode lockMode) throws HibernateException {
476     LockEvent event = new LockEvent(entityName, object, lockMode, this);
477     listeners.getLockEventListener().onLock(event);
478   }
479 
480   public void persist(String entityName, Object object, Map copiedAlready)
481   throws HibernateException {
482     PersistEvent event = new PersistEvent(entityName, object, this);
483     listeners.getCreateEventListener().onPersist(event, copiedAlready);
484   }
485 
486   public void persist(String entityName, Object object)
487   throws HibernateException {
488     PersistEvent event = new PersistEvent(entityName, object, this);
489     listeners.getCreateEventListener().onPersist(event);
490   }
491 
492   public void persist(Object object) throws HibernateException {
493     persist(null, object);
494   }
495 
496   public Object merge(String entityName, Object object)
497   throws HibernateException {
498     MergeEvent event = new MergeEvent(entityName, object, this);
499     return listeners.getMergeEventListener().onMerge(event);
500   }
501 
502   public Object merge(Object object) throws HibernateException {
503     return merge(null, object);
504   }
505 
506   public void merge(String entityName, Object object, Map copiedAlready) throws HibernateException {
507     MergeEvent event = new MergeEvent(entityName, object, this);
508     listeners.getMergeEventListener().onMerge(event, copiedAlready);
509   }
510 
511   public Object saveOrUpdateCopy(String entityName, Object object)
512   throws HibernateException {
513     MergeEvent event = new MergeEvent(entityName, object, this);
514     return listeners.getSaveOrUpdateCopyEventListener().onMerge(event);
515   }
516 
517   public Object saveOrUpdateCopy(Object object) throws HibernateException {
518     return saveOrUpdateCopy(null, object);
519   }
520 
521   public Object saveOrUpdateCopy(String entityName, Object object, Serializable id) 
522   throws HibernateException {
523     MergeEvent event = new MergeEvent(entityName, object, id, this);
524     return listeners.getSaveOrUpdateCopyEventListener().onMerge(event);
525   }
526 
527   public Object saveOrUpdateCopy(Object object, Serializable id) 
528   throws HibernateException {
529     return saveOrUpdateCopy(null, object, id);
530   }
531 
532   public void saveOrUpdateCopy(String entityName, Object object, Map copiedAlready) 
533   throws HibernateException {
534     MergeEvent event = new MergeEvent(entityName, object, this);
535     listeners.getSaveOrUpdateCopyEventListener().onMerge(event, copiedAlready);
536   }
537 
538   /**
539    * Delete a persistent object
540    */
541   public void delete(Object object) throws HibernateException {
542     DeleteEvent event = new DeleteEvent(object, this);
543         listeners.getDeleteEventListener().onDelete(event);
544   }
545 
546   /**
547    * Delete a persistent object
548    */
549   public void delete(String entityName, Object object, boolean isCascadeDeleteEnabled) throws HibernateException {
550     DeleteEvent event = new DeleteEvent(entityName, object, isCascadeDeleteEnabled, this);
551         listeners.getDeleteEventListener().onDelete(event);
552   }
553 
554   public void load(Object object, Serializable id) throws HibernateException {
555         LoadEvent event = new LoadEvent(id, object, this);
556         listeners.getLoadEventListener().onLoad(event, null);
557   }
558 
559   public Object load(Class entityClass, Serializable id) throws HibernateException {
560     return load( entityClass.getName(), id );
561   }
562 
563   public Object load(String entityName, Serializable id) throws HibernateException {
564         LoadEvent event = new LoadEvent(id, entityName, false, this);
565         Object result = listeners.getLoadEventListener().onLoad(event, LoadEventListener.LOAD);
566 
567     ObjectNotFoundException.throwIfNull(result, id, entityName);
568     return result;
569   }
570 
571   public Object get(Class entityClass, Serializable id) throws HibernateException {
572     return get( entityClass.getName(), id );
573   }
574 
575   public Object get(String entityName, Serializable id) throws HibernateException {
576         LoadEvent event = new LoadEvent(id, entityName, false, this);
577         return listeners.getLoadEventListener().onLoad(event, LoadEventListener.GET);
578   }
579 
580   /**
581    * Load the data for the object with the specified id into a newly created object.
582    * This is only called when lazily initializing a proxy.
583    * Do NOT return a proxy.
584    */
585   public Object immediateLoad(String entityName, Serializable id) throws HibernateException {
586     
587     if ( log.isDebugEnabled() ) {
588       EntityPersister persister = getFactory().getEntityPersister(entityName);
589       log.debug( "initializing proxy: " + MessageHelper.infoString( persister, id, getFactory() ) );
590     }
591     
592         LoadEvent event = new LoadEvent(id, entityName, true, this);
593         Object result = listeners.getLoadEventListener().onLoad(event, LoadEventListener.IMMEDIATE_LOAD);
594 
595     ObjectNotFoundException.throwIfNull(result, id, entityName); //should it be UnresolvableObject?
596     return result;
597   }
598 
599   public Object internalLoad(String entityName, Serializable id, boolean nullable) throws HibernateException {
600     // todo : remove
601         LoadEvent event = new LoadEvent(id, entityName, true, this);
602         Object result = listeners.getLoadEventListener()
603           .onLoad(event, nullable ? LoadEventListener.INTERNAL_LOAD_NULLABLE : LoadEventListener.INTERNAL_LOAD);
604     if (!nullable) UnresolvableObjectException.throwIfNull(result, id, entityName);
605     return result;
606   }
607 
608   public Object load(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
609     return load( entityClass.getName(), id, lockMode );
610   }
611 
612   public Object load(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
613         LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
614         return listeners.getLoadEventListener().onLoad(event, LoadEventListener.LOAD);
615   }
616 
617   public Object get(Class entityClass, Serializable id, LockMode lockMode) throws HibernateException {
618     return get( entityClass.getName(), id, lockMode );
619   }
620 
621   public Object get(String entityName, Serializable id, LockMode lockMode) throws HibernateException {
622         LoadEvent event = new LoadEvent(id, entityName, lockMode, this);
623         return listeners.getLoadEventListener().onLoad(event, LoadEventListener.GET);
624   }
625 
626   public void refresh(Object object) throws HibernateException {
627     listeners.getRefreshEventListener().onRefresh( new RefreshEvent(object, this) );
628   }
629 
630   public void refresh(Object object, LockMode lockMode) throws HibernateException {
631     listeners.getRefreshEventListener().onRefresh( new RefreshEvent(object, lockMode, this) );
632   }
633 
634   public void replicate(Object obj, ReplicationMode replicationMode) throws HibernateException {
635     ReplicateEvent event = new ReplicateEvent(obj, replicationMode, this);
636     listeners.getReplicateEventListener().onReplicate(event);
637   }
638 
639   public void replicate(String entityName, Object obj, ReplicationMode replicationMode)
640   throws HibernateException {
641     ReplicateEvent event = new ReplicateEvent(entityName, obj, replicationMode, this);
642     listeners.getReplicateEventListener().onReplicate(event);
643   }
644 
645   /**
646    * remove any hard references to the entity that are held by the infrastructure
647    * (references held by application or other persistant instances are okay)
648    */
649   public void evict(Object object) throws HibernateException {
650         listeners.getEvictEventListener().onEvict( new EvictEvent(object, this) );
651   }
652 
653   /**
654    * detect in-memory changes, determine if the changes are to tables
655    * named in the query and, if so, complete execution the flush
656    */
657   private boolean autoFlushIfRequired(Set querySpaces) throws HibernateException {
658     AutoFlushEvent event = new AutoFlushEvent(querySpaces, this);
659     return listeners.getAutoFlushEventListener().onAutoFlush(event);
660   }
661 
662   public boolean isDirty() throws HibernateException {
663     log.debug("checking session dirtiness");
664     if ( actionQueue.areInsertionsOrDeletionsQueued() ) {
665       log.debug("session dirty (scheduled updates and insertions)");
666       return true;
667     }
668     else {
669       DirtyCheckEvent event = new DirtyCheckEvent(this);
670       return listeners.getDirtyCheckEventListener().onDirtyCheck(event);
671     }
672   }
673 
674   public void flush() throws HibernateException {
675     if ( persistenceContext.getCascadeLevel() > 0 ) {
676       throw new HibernateException("Flush during cascade is dangerous");
677     }
678     listeners.getFlushEventListener().onFlush( new FlushEvent(this) );
679   }
680 
681   public void forceFlush(EntityEntry e) throws HibernateException {
682     if ( log.isDebugEnabled() ) {
683       log.debug(
684         "flushing to force deletion of re-saved object: " +
685         MessageHelper.infoString( e.getPersister(), e.getId(), getFactory() )
686       );
687     }
688 
689     if ( persistenceContext.getCascadeLevel() > 0 ) {
690       throw new ObjectDeletedException(
691         "deleted object would be re-saved by cascade (remove deleted object from associations)",
692         e.getId(),
693         e.getPersister().getEntityName()
694       );
695     }
696 
697     flush();
698   }
699 
700   public Filter enableFilter(String filterName) {
701         FilterImpl filter = new FilterImpl( factory.getFilterDefinition(filterName) );
702     enabledFilters.put(filterName, filter);
703     return filter;
704   }
705 
706   public Filter getEnabledFilter(String filterName) {
707     return (Filter) enabledFilters.get(filterName);
708   }
709 
710   public void disableFilter(String filterName) {
711     enabledFilters.remove(filterName);
712   }
713 
714   public Object getFilterParameterValue(String filterParameterName) {
715         String[] parsed = parseFilterParameterName(filterParameterName);
716     FilterImpl filter = (FilterImpl) enabledFilters.get( parsed[0] );
717     if (filter == null) {
718       throw new IllegalArgumentException("Filter [" + parsed[0] + "] currently not enabled");
719     }
720     return filter.getParameter( parsed[1] );
721   }
722 
723   public Type getFilterParameterType(String filterParameterName) {
724     String[] parsed = parseFilterParameterName(filterParameterName);
725     FilterDefinition filterDef = factory.getFilterDefinition( parsed[0] );
726     if (filterDef == null) {
727       throw new IllegalArgumentException("Filter [" + parsed[0] + "] not defined");
728     }
729     Type type = filterDef.getParameterType( parsed[1] );
730     if (type == null) {
731       // this is an internal error of some sort...
732       throw new InternalError("Unable to locate type for filter parameter");
733     }
734     return type;
735   }
736 
737   public Map getEnabledFilters() {
738     // First, validate all the enabled filters...
739     //TODO: this implementation has bad performance
740     Iterator itr = enabledFilters.values().iterator();
741     while ( itr.hasNext() ) {
742       final Filter filter = (Filter) itr.next();
743       filter.validate();
744     }
745     return enabledFilters;
746   }
747 
748   private String[] parseFilterParameterName(String filterParameterName) {
749     int dot = filterParameterName.indexOf('.');
750     if (dot <= 0) {
751       throw new IllegalArgumentException("Invalid filter-parameter name format"); // TODO: what type?
752     }
753     String filterName = filterParameterName.substring(0, dot);
754     String parameterName = filterParameterName.substring(dot+1);
755     return new String[] {filterName, parameterName};
756   }
757 
758 
759   /**
760    * Retrieve a list of persistent objects using a hibernate query
761    */
762   public List find(String query) throws HibernateException {
763     return list( query, new QueryParameters() );
764   }
765 
766   public List find(String query, Object value, Type type) throws HibernateException {
767     return list( query, new QueryParameters(type, value) );
768   }
769 
770   public List find(String query, Object[] values, Type[] types) throws HibernateException {
771     return list( query, new QueryParameters(types, values) );
772   }
773 
774   public List list(String query, QueryParameters queryParameters) throws HibernateException {
775 
776     if ( log.isTraceEnabled() ) {
777       log.trace( "find: " + query );
778       queryParameters.traceParameters(factory);
779     }
780 
781     queryParameters.validateParameters();
782     QueryTranslator[] q = getQueries(query, false);
783 
784     List results = CollectionHelper.EMPTY_LIST;
785 
786     dontFlushFromFind++;   //stops flush being called multiple times if this method is recursively called
787 
788     //execute the queries and return all result lists as a single list
789     try {
790       for ( int i = 0; i < q.length; i++ ) {
791         List currentResults = q[i].list(this, queryParameters);
792         currentResults.addAll(results);
793         results = currentResults;
794       }
795     }
796     finally {
797       dontFlushFromFind--;
798     }
799     return results;
800   }
801 
802   public int executeUpdate(String query, QueryParameters queryParameters) throws HibernateException {
803 
804     if ( log.isTraceEnabled() ) {
805       log.trace( "executeUpdate: " + query );
806       queryParameters.traceParameters(factory);
807     }
808 
809     queryParameters.validateParameters();
810     QueryTranslator[] queryTranslators = getQueries(query, false);
811     
812     int result = 0;
813     for (int i=0; i<queryTranslators.length; i++) {
814       result += queryTranslators[i].executeUpdate( queryParameters, this );
815     }
816     return result;
817   }
818 
819   private QueryTranslator[] getQueries(String query, boolean scalar) throws HibernateException {
820 
821     // take the union of the query spaces (ie. the queried tables)
822     QueryTranslator[] q = factory.getQuery( query, scalar, getEnabledFilters() );
823     return prepareQueries(q);
824 
825   }
826 
827   private QueryTranslator[] prepareQueries(QueryTranslator[] q) {
828     HashSet qs = new HashSet();
829     for ( int i = 0; i < q.length; i++ ) {
830       qs.addAll( q[i].getQuerySpaces() );
831     }
832 
833     autoFlushIfRequired(qs);
834 
835     return q;
836   }
837 
838   public Iterator iterate(String query) throws HibernateException {
839     return iterate( query, new QueryParameters() );
840   }
841 
842   public Iterator iterate(String query, Object value, Type type) throws HibernateException {
843     return iterate( query, new QueryParameters(type, value) );
844   }
845 
846   public Iterator iterate(String query, Object[] values, Type[] types) throws HibernateException {
847     return iterate( query, new QueryParameters(types, values) );
848   }
849 
850   public Iterator iterate(String query, QueryParameters queryParameters) throws HibernateException {
851 
852     if ( log.isTraceEnabled() ) {
853       log.trace( "iterate: " + query );
854       queryParameters.traceParameters(factory);
855     }
856 
857     queryParameters.validateParameters();
858     QueryTranslator[] q = getQueries(query, true);
859 
860     if ( q.length == 0 ) return EmptyIterator.INSTANCE;
861 
862     Iterator result = null;
863     Iterator[] results = null;
864     boolean many = q.length > 1;
865     if (many) results = new Iterator[q.length];
866 
867     dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
868 
869     try {
870 
871       //execute the queries and return all results as a single iterator
872       for ( int i = 0; i < q.length; i++ ) {
873         result = q[i].iterate(queryParameters, this);
874         if (many) results[i] = result;
875       }
876 
877       return many ? new JoinedIterator(results) : result;
878 
879     }
880     finally {
881       dontFlushFromFind--;
882     }
883   }
884 
885   public ScrollableResults scroll(String query, QueryParameters queryParameters) throws HibernateException {
886 
887     if ( log.isTraceEnabled() ) {
888       log.trace( "scroll: " + query );
889       queryParameters.traceParameters( factory );
890     }
891 
892     QueryTranslator[] q = factory.getQuery( query, false, getEnabledFilters() );
893     if ( q.length != 1 ) throw new QueryException( "implicit polymorphism not supported for scroll() queries" );
894     autoFlushIfRequired( q[0].getQuerySpaces() );
895 
896     dontFlushFromFind++; //stops flush being called multiple times if this method is recursively called
897     try {
898       return q[0].scroll(queryParameters, this);
899     }
900     finally {
901       dontFlushFromFind--;
902     }
903   }
904 
905   public int delete(String query) throws HibernateException {
906     return delete( query, ArrayHelper.EMPTY_OBJECT_ARRAY, ArrayHelper.EMPTY_TYPE_ARRAY );
907   }
908 
909   public int delete(String query, Object value, Type type) throws HibernateException {
910     return delete( query, new Object[]{value}, new Type[]{type} );
911   }
912 
913   public int delete(String query, Object[] values, Type[] types) throws HibernateException {
914     if ( query == null ) {
915       throw new IllegalArgumentException("attempt to perform delete-by-query with null query");
916     }
917 
918     if ( log.isTraceEnabled() ) {
919       log.trace( "delete: " + query );
920       if ( values.length != 0 ) {
921         log.trace( "parameters: " + StringHelper.toString( values ) );
922       }
923     }
924 
925     List list = find( query, values, types );
926     int deletionCount = list.size();
927     for ( int i = 0; i < deletionCount; i++ ) {
928       delete( list.get( i ) );
929     }
930 
931     return deletionCount;
932   }
933 
934   public Query createFilter(Object collection, String queryString) {
935     return new CollectionFilterImpl(queryString, collection, this);
936   }
937   
938   public Query createQuery(String queryString) {
939     return new QueryImpl(queryString, this);
940   }
941 
942   private Query createQuery(String queryString, FlushMode queryFlushMode) {
943     return new QueryImpl(queryString, queryFlushMode, this);
944   }
945   
946   public Query getNamedQuery(String queryName) throws MappingException {
947     NamedQueryDefinition nqd = factory.getNamedQuery(queryName);
948     final Query query;
949     if ( nqd != null ) {
950       query = createQuery( 
951           nqd.getQueryString(), 
952           nqd.getFlushMode()
953       );
954       if ( factory.getSettings().isCommentsEnabled() ) {
955         query.setComment("named query " + queryName);
956       }
957     }
958     else {
959       NamedSQLQueryDefinition nsqlqd = factory.getNamedSQLQuery( queryName );
960       if (nsqlqd==null) {
961         throw new MappingException("Named query not known: " + queryName);
962       }
963       query = new SQLQueryImpl(nsqlqd, this);
964       nqd = nsqlqd;
965       if ( factory.getSettings().isCommentsEnabled() ) {
966         query.setComment("named SQL query " + queryName);
967       }
968     }
969     query.setCacheable( nqd.isCacheable() );
970     query.setCacheRegion( nqd.getCacheRegion() );
971     if ( nqd.getTimeout()!=null ) query.setTimeout( nqd.getTimeout().intValue() );
972     if ( nqd.getFetchSize()!=null ) query.setFetchSize( nqd.getFetchSize().intValue() );
973     return query;
974   }
975 
976   public Object instantiate(String entityName, Serializable id) throws HibernateException {
977     return instantiate( factory.getEntityPersister(entityName), id );
978   }
979 
980   /**
981    * give the interceptor an opportunity to override the default instantiation
982    */
983   public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException {
984     Object result = interceptor.instantiate( persister.getEntityName(), entityMode, id );
985     if ( result == null ) result = persister.instantiate( id, entityMode );
986     return result;
987   }
988 
989   public EntityMode getEntityMode() {
990     return entityMode;
991   }
992 
993   public void setFlushMode(FlushMode flushMode) {
994     if ( log.isTraceEnabled() ) log.trace("setting flush mode to: " + flushMode);
995     this.flushMode = flushMode;
996   }
997   
998   public FlushMode getFlushMode() {
999     return flushMode;
1000  }
1001
1002  public CacheMode getCacheMode() {
1003    return cacheMode;
1004  }
1005  
1006  public void setCacheMode(CacheMode cacheMode) {
1007    if ( log.isTraceEnabled() ) log.trace("setting cache mode to: " + cacheMode);
1008    this.cacheMode= cacheMode; 
1009  }
1010
1011  public Transaction beginTransaction() throws HibernateException {
1012    if ( !isRootSession ) {
1013      log.warn("Transaction started on non-root session");
1014    }
1015    Transaction tx = jdbcContext.beginTransaction();
1016    interceptor.afterTransactionBegin(tx);
1017    return tx;
1018  }
1019
1020  public EntityPersister getEntityPersister(final String entityName, final Object object) {
1021    if (entityName==null) {
1022      return factory.getEntityPersister( guessEntityName(object) );
1023    }
1024    else {
1025      return factory.getEntityPersister( entityName ).getSubclassEntityPersister( object, getFactory(), entityMode );
1026    }
1027  }
1028
1029  // not for internal use:
1030  public Serializable getIdentifier(Object object) throws HibernateException {
1031    if ( object instanceof HibernateProxy ) {
1032      LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer();
1033      if ( li.getSession() != this ) {
1034        throw new TransientObjectException( "The proxy was not associated with this session" );
1035      }
1036      return li.getIdentifier();
1037    }
1038    else {
1039      EntityEntry entry = persistenceContext.getEntry(object);
1040      if ( entry == null ) {
1041        throw new TransientObjectException( "The instance was not associated with this session" );
1042      }
1043      return entry.getId();
1044    }
1045  }
1046
1047  /**
1048   * Get the id value for an object that is actually associated with the session. This
1049   * is a bit stricter than getEntityIdentifierIfNotUnsaved().
1050   */
1051  public Serializable getEntityIdentifier(Object object) {
1052    if ( object instanceof HibernateProxy ) {
1053      return getProxyIdentifier(object);
1054    }
1055    else {
1056      EntityEntry entry = persistenceContext.getEntry(object);
1057      return entry != null ? entry.getId() : null;
1058    }
1059  }
1060  
1061  private Serializable getProxyIdentifier(Object proxy) {
1062    return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getIdentifier();
1063  }
1064
1065  public Collection filter(Object collection, String filter) throws HibernateException {
1066    return listFilter( collection, filter, new QueryParameters( new Type[1], new Object[1] ) );
1067  }
1068
1069  public Collection filter(Object collection, String filter, Object value, Type type) throws HibernateException {
1070    return listFilter( collection, filter, new QueryParameters( new Type[]{null, type}, new Object[]{null, value} ) );
1071  }
1072
1073  public Collection filter(Object collection, String filter, Object[] values, Type[] types) 
1074  throws HibernateException {
1075    Object[] vals = new Object[values.length + 1];
1076    Type[] typs = new Type[types.length + 1];
1077    System.arraycopy( values, 0, vals, 1, values.length );
1078    System.arraycopy( types, 0, typs, 1, types.length );
1079    return listFilter( collection, filter, new QueryParameters( typs, vals ) );
1080  }
1081
1082  /**
1083   * 1. determine the collection role of the given collection (this may require a flush, if the