KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > hibernate3 > HibernateTemplate


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.orm.hibernate3;
18
19 import java.io.Serializable JavaDoc;
20 import java.lang.reflect.InvocationHandler JavaDoc;
21 import java.lang.reflect.InvocationTargetException JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.lang.reflect.Proxy JavaDoc;
24 import java.sql.SQLException JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28
29 import org.hibernate.Criteria;
30 import org.hibernate.Filter;
31 import org.hibernate.FlushMode;
32 import org.hibernate.Hibernate;
33 import org.hibernate.HibernateException;
34 import org.hibernate.LockMode;
35 import org.hibernate.Query;
36 import org.hibernate.ReplicationMode;
37 import org.hibernate.Session;
38 import org.hibernate.SessionFactory;
39 import org.hibernate.criterion.DetachedCriteria;
40 import org.hibernate.criterion.Example;
41 import org.hibernate.engine.SessionImplementor;
42
43 import org.springframework.dao.DataAccessException;
44 import org.springframework.dao.InvalidDataAccessApiUsageException;
45 import org.springframework.util.Assert;
46
47 /**
48  * Helper class that simplifies Hibernate data access code. Automatically
49  * converts HibernateExceptions into DataAccessExceptions, following the
50  * <code>org.springframework.dao</code> exception hierarchy.
51  *
52  * <p><b>NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can
53  * also be coded in plain Hibernate style. Hence, for newly started projects,
54  * consider adopting the standard Hibernate3 style of coding data access objects
55  * instead, based on <code>SessionFactory.getCurrentSession()</code>.</b>
56  * (Spring's LocalSessionFactoryBean automatically supports Spring transaction
57  * management for the Hibernate3 <code>getCurrentSession()</code> method.)
58  *
59  * <p>The central method is <code>execute</code>, supporting Hibernate access code
60  * implementing the {@link HibernateCallback} interface. It provides Hibernate Session
61  * handling such that neither the HibernateCallback implementation nor the calling
62  * code needs to explicitly care about retrieving/closing Hibernate Sessions,
63  * or handling Session lifecycle exceptions. For typical single step actions,
64  * there are various convenience methods (find, load, saveOrUpdate, delete).
65  *
66  * <p>Can be used within a service implementation via direct instantiation
67  * with a SessionFactory reference, or get prepared in an application context
68  * and given to services as bean reference. Note: The SessionFactory should
69  * always be configured as bean in the application context, in the first case
70  * given to the service directly, in the second case to the prepared template.
71  *
72  * <p>This class can be considered as direct alternative to working with the raw
73  * Hibernate3 Session API (through <code>SessionFactory.getCurrentSession()</code>).
74  * The major advantage is its automatic conversion to DataAccessExceptions, the
75  * major disadvantage that no checked application exceptions can get thrown from
76  * within data access code. Corresponding checks and the actual throwing of such
77  * exceptions can often be deferred to after callback execution, though.
78  *
79  * <p>Note that even if {@link HibernateTransactionManager} is used for transaction
80  * demarcation in higher-level services, all those services above the data
81  * access layer don't need to be Hibernate-aware. Setting such a special
82  * PlatformTransactionManager is a configuration issue: For example,
83  * switching to JTA is just a matter of Spring configuration (use
84  * JtaTransactionManager instead) that does not affect application code.
85  *
86  * <p>{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
87  * to a specific Hibernate SessionFactory, at least in a non-EJB environment.
88  * The Spring application context will manage its lifecycle, initializing and
89  * shutting down the factory as part of the application.
90  *
91  * <p>Note that operations that return an Iterator (i.e. <code>iterate</code>)
92  * are supposed to be used within Spring-driven or JTA-driven transactions
93  * (with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
94  * Else, the Iterator won't be able to read results from its ResultSet anymore,
95  * as the underlying Hibernate Session will already have been closed.
96  *
97  * <p>Lazy loading will also just work with an open Hibernate Session,
98  * either within a transaction or within OpenSessionInViewFilter/Interceptor.
99  * Furthermore, some operations just make sense within transactions,
100  * for example: <code>contains</code>, <code>evict</code>, <code>lock</code>,
101  * <code>flush</code>, <code>clear</code>.
102  *
103  * @author Juergen Hoeller
104  * @since 1.2
105  * @see org.hibernate.SessionFactory#getCurrentSession()
106  * @see #setSessionFactory
107  * @see HibernateCallback
108  * @see org.hibernate.Session
109  * @see LocalSessionFactoryBean
110  * @see HibernateTransactionManager
111  * @see org.springframework.transaction.jta.JtaTransactionManager
112  * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
113  * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
114  */

115 public class HibernateTemplate extends HibernateAccessor implements HibernateOperations {
116
117     private boolean allowCreate = true;
118
119     private boolean alwaysUseNewSession = false;
120
121     private boolean exposeNativeSession = false;
122
123     private boolean checkWriteOperations = true;
124
125     private boolean cacheQueries = false;
126
127     private String JavaDoc queryCacheRegion;
128
129     private int fetchSize = 0;
130
131     private int maxResults = 0;
132
133
134     /**
135      * Create a new HibernateTemplate instance.
136      */

137     public HibernateTemplate() {
138     }
139
140     /**
141      * Create a new HibernateTemplate instance.
142      * @param sessionFactory SessionFactory to create Sessions
143      */

144     public HibernateTemplate(SessionFactory sessionFactory) {
145         setSessionFactory(sessionFactory);
146         afterPropertiesSet();
147     }
148
149     /**
150      * Create a new HibernateTemplate instance.
151      * @param sessionFactory SessionFactory to create Sessions
152      * @param allowCreate if a non-transactional Session should be created when no
153      * transactional Session can be found for the current thread
154      */

155     public HibernateTemplate(SessionFactory sessionFactory, boolean allowCreate) {
156         setSessionFactory(sessionFactory);
157         setAllowCreate(allowCreate);
158         afterPropertiesSet();
159     }
160
161
162     /**
163      * Set if a new Session should be created when no transactional Session
164      * can be found for the current thread.
165      * <p>HibernateTemplate is aware of a corresponding Session bound to the
166      * current thread, for example when using HibernateTransactionManager.
167      * If allowCreate is true, a new non-transactional Session will be created
168      * if none found, which needs to be closed at the end of the operation.
169      * If false, an IllegalStateException will get thrown in this case.
170      * @see SessionFactoryUtils#getSession(SessionFactory, boolean)
171      */

172     public void setAllowCreate(boolean allowCreate) {
173         this.allowCreate = allowCreate;
174     }
175
176     /**
177      * Return if a new Session should be created if no thread-bound found.
178      */

179     public boolean isAllowCreate() {
180         return this.allowCreate;
181     }
182
183     /**
184      * Set whether to always use a new Hibernate Session for this template.
185      * Default is "false"; if activated, all operations on this template will
186      * work on a new Hibernate Session even in case of a pre-bound Session
187      * (for example, within a transaction or OpenSessionInViewFilter).
188      * <p>Within a transaction, a new Hibernate Session used by this template
189      * will participate in the transaction through using the same JDBC
190      * Connection. In such a scenario, multiple Sessions will participate
191      * in the same database transaction.
192      * <p>Turn this on for operations that are supposed to always execute
193      * independently, without side effects caused by a shared Hibernate Session.
194      */

195     public void setAlwaysUseNewSession(boolean alwaysUseNewSession) {
196         this.alwaysUseNewSession = alwaysUseNewSession;
197     }
198
199     /**
200      * Return whether to always use a new Hibernate Session for this template.
201      */

202     public boolean isAlwaysUseNewSession() {
203         return this.alwaysUseNewSession;
204     }
205
206     /**
207      * Set whether to expose the native Hibernate Session to
208      * HibernateCallback code.
209      * <p>Default is "false": a Session proxy will be returned, suppressing
210      * <code>close</code> calls and automatically applying query cache
211      * settings and transaction timeouts.
212      * @see HibernateCallback
213      * @see org.hibernate.Session
214      * @see #setCacheQueries
215      * @see #setQueryCacheRegion
216      * @see #prepareQuery
217      * @see #prepareCriteria
218      */

219     public void setExposeNativeSession(boolean exposeNativeSession) {
220         this.exposeNativeSession = exposeNativeSession;
221     }
222
223     /**
224      * Return whether to expose the native Hibernate Session to
225      * HibernateCallback code, or rather a Session proxy.
226      */

227     public boolean isExposeNativeSession() {
228         return this.exposeNativeSession;
229     }
230
231     /**
232      * Set whether to check that the Hibernate Session is not in read-only mode
233      * in case of write operations (save/update/delete).
234      * <p>Default is "true", for fail-fast behavior when attempting write operations
235      * within a read-only transaction. Turn this off to allow save/update/delete
236      * on a Session with flush mode NEVER.
237      * @see #setFlushMode
238      * @see #checkWriteOperationAllowed
239      * @see org.springframework.transaction.TransactionDefinition#isReadOnly
240      */

241     public void setCheckWriteOperations(boolean checkWriteOperations) {
242         this.checkWriteOperations = checkWriteOperations;
243     }
244
245     /**
246      * Return whether to check that the Hibernate Session is not in read-only
247      * mode in case of write operations (save/update/delete).
248      */

249     public boolean isCheckWriteOperations() {
250         return this.checkWriteOperations;
251     }
252
253     /**
254      * Set whether to cache all queries executed by this template.
255      * <p>If this is "true", all Query and Criteria objects created by
256      * this template will be marked as cacheable (including all
257      * queries through find methods).
258      * <p>To specify the query region to be used for queries cached
259      * by this template, set the "queryCacheRegion" property.
260      * @see #setQueryCacheRegion
261      * @see org.hibernate.Query#setCacheable
262      * @see org.hibernate.Criteria#setCacheable
263      */

264     public void setCacheQueries(boolean cacheQueries) {
265         this.cacheQueries = cacheQueries;
266     }
267
268     /**
269      * Return whether to cache all queries executed by this template.
270      */

271     public boolean isCacheQueries() {
272         return this.cacheQueries;
273     }
274
275     /**
276      * Set the name of the cache region for queries executed by this template.
277      * <p>If this is specified, it will be applied to all Query and Criteria objects
278      * created by this template (including all queries through find methods).
279      * <p>The cache region will not take effect unless queries created by this
280      * template are configured to be cached via the "cacheQueries" property.
281      * @see #setCacheQueries
282      * @see org.hibernate.Query#setCacheRegion
283      * @see org.hibernate.Criteria#setCacheRegion
284      */

285     public void setQueryCacheRegion(String JavaDoc queryCacheRegion) {
286         this.queryCacheRegion = queryCacheRegion;
287     }
288
289     /**
290      * Return the name of the cache region for queries executed by this template.
291      */

292     public String JavaDoc getQueryCacheRegion() {
293         return this.queryCacheRegion;
294     }
295
296     /**
297      * Set the fetch size for this HibernateTemplate. This is important for processing
298      * large result sets: Setting this higher than the default value will increase
299      * processing speed at the cost of memory consumption; setting this lower can
300      * avoid transferring row data that will never be read by the application.
301      * <p>Default is 0, indicating to use the JDBC driver's default.
302      */

303     public void setFetchSize(int fetchSize) {
304         this.fetchSize = fetchSize;
305     }
306
307     /**
308      * Return the fetch size specified for this HibernateTemplate.
309      */

310     public int getFetchSize() {
311         return this.fetchSize;
312     }
313
314     /**
315      * Set the maximum number of rows for this HibernateTemplate. This is important
316      * for processing subsets of large result sets, avoiding to read and hold
317      * the entire result set in the database or in the JDBC driver if we're
318      * never interested in the entire result in the first place (for example,
319      * when performing searches that might return a large number of matches).
320      * <p>Default is 0, indicating to use the JDBC driver's default.
321      */

322     public void setMaxResults(int maxResults) {
323         this.maxResults = maxResults;
324     }
325
326     /**
327      * Return the maximum number of rows specified for this HibernateTemplate.
328      */

329     public int getMaxResults() {
330         return this.maxResults;
331     }
332
333
334     public Object JavaDoc execute(HibernateCallback action) throws DataAccessException {
335         return execute(action, isExposeNativeSession());
336     }
337
338     public List JavaDoc executeFind(HibernateCallback action) throws DataAccessException {
339         Object JavaDoc result = execute(action, isExposeNativeSession());
340         if (result != null && !(result instanceof List JavaDoc)) {
341             throw new InvalidDataAccessApiUsageException(
342                     "Result object returned from HibernateCallback isn't a List: [" + result + "]");
343         }
344         return (List JavaDoc) result;
345     }
346
347     /**
348      * Execute the action specified by the given action object within a Session.
349      * @param action callback object that specifies the Hibernate action
350      * @param exposeNativeSession whether to expose the native Hibernate Session
351      * to callback code
352      * @return a result object returned by the action, or <code>null</code>
353      * @throws org.springframework.dao.DataAccessException in case of Hibernate errors
354      */

355     public Object JavaDoc execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
356         Assert.notNull(action, "Callback object must not be null");
357
358         Session session = getSession();
359         boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
360         if (existingTransaction) {
361             logger.debug("Found thread-bound Session for HibernateTemplate");
362         }
363
364         FlushMode previousFlushMode = null;
365         try {
366             previousFlushMode = applyFlushMode(session, existingTransaction);
367             enableFilters(session);
368             Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
369             Object JavaDoc result = action.doInHibernate(sessionToExpose);
370             flushIfNecessary(session, existingTransaction);
371             return result;
372         }
373         catch (HibernateException ex) {
374             throw convertHibernateAccessException(ex);
375         }
376         catch (SQLException JavaDoc ex) {
377             throw convertJdbcAccessException(ex);
378         }
379         catch (RuntimeException JavaDoc ex) {
380             // Callback code threw application exception...
381
throw ex;
382         }
383         finally {
384             if (existingTransaction) {
385                 logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
386                 disableFilters(session);
387                 if (previousFlushMode != null) {
388                     session.setFlushMode(previousFlushMode);
389                 }
390             }
391             else {
392                 // Never use deferred close for an explicitly new Session.
393
if (isAlwaysUseNewSession()) {
394                     SessionFactoryUtils.closeSession(session);
395                 }
396                 else {
397                     SessionFactoryUtils.closeSessionOrRegisterDeferredClose(session, getSessionFactory());
398                 }
399             }
400         }
401     }
402
403     /**
404      * Return a Session for use by this template.
405      * <p>Returns a new Session in case of "alwaysUseNewSession" (using the same
406      * JDBC Connection as a transactional Session, if applicable), a pre-bound
407      * Session in case of "allowCreate" turned off, and a pre-bound or new Session
408      * else (new only if no transactional or otherwise pre-bound Session exists).
409      * @see SessionFactoryUtils#getSession
410      * @see SessionFactoryUtils#getNewSession
411      * @see #setAlwaysUseNewSession
412      * @see #setAllowCreate
413      */

414     protected Session getSession() {
415         if (isAlwaysUseNewSession()) {
416             return SessionFactoryUtils.getNewSession(getSessionFactory(), getEntityInterceptor());
417         }
418         else if (!isAllowCreate()) {
419             return SessionFactoryUtils.getSession(getSessionFactory(), false);
420         }
421         else {
422             return SessionFactoryUtils.getSession(
423                     getSessionFactory(), getEntityInterceptor(), getJdbcExceptionTranslator());
424         }
425     }
426
427     /**
428      * Create a close-suppressing proxy for the given Hibernate Session.
429      * The proxy also prepares returned Query and Criteria objects.
430      * @param session the Hibernate Session to create a proxy for
431      * @return the Session proxy
432      * @see org.hibernate.Session#close()
433      * @see #prepareQuery
434      * @see #prepareCriteria
435      */

436     protected Session createSessionProxy(Session session) {
437         Class JavaDoc[] sessionIfcs = null;
438         if (session instanceof SessionImplementor) {
439             sessionIfcs = new Class JavaDoc[] {Session.class, SessionImplementor.class};
440         }
441         else {
442             sessionIfcs = new Class JavaDoc[] {Session.class};
443         }
444         return (Session) Proxy.newProxyInstance(
445                 getClass().getClassLoader(), sessionIfcs,
446                 new CloseSuppressingInvocationHandler(session));
447     }
448
449
450     //-------------------------------------------------------------------------
451
// Convenience methods for loading individual objects
452
//-------------------------------------------------------------------------
453

454     public Object JavaDoc get(Class JavaDoc entityClass, Serializable JavaDoc id) throws DataAccessException {
455         return get(entityClass, id, null);
456     }
457
458     public Object JavaDoc get(final Class JavaDoc entityClass, final Serializable JavaDoc id, final LockMode lockMode)
459             throws DataAccessException {
460
461         return execute(new HibernateCallback() {
462             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
463                 if (lockMode != null) {
464                     return session.get(entityClass, id, lockMode);
465                 }
466                 else {
467                     return session.get(entityClass, id);
468                 }
469             }
470         }, true);
471     }
472
473     public Object JavaDoc get(String JavaDoc entityName, Serializable JavaDoc id) throws DataAccessException {
474         return get(entityName, id, null);
475     }
476
477     public Object JavaDoc get(final String JavaDoc entityName, final Serializable JavaDoc id, final LockMode lockMode)
478             throws DataAccessException {
479
480         return execute(new HibernateCallback() {
481             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
482                 if (lockMode != null) {
483                     return session.get(entityName, id, lockMode);
484                 }
485                 else {
486                     return session.get(entityName, id);
487                 }
488             }
489         }, true);
490     }
491
492     public Object JavaDoc load(Class JavaDoc entityClass, Serializable JavaDoc id) throws DataAccessException {
493         return load(entityClass, id, null);
494     }
495
496     public Object JavaDoc load(final Class JavaDoc entityClass, final Serializable JavaDoc id, final LockMode lockMode)
497             throws DataAccessException {
498
499         return execute(new HibernateCallback() {
500             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
501                 if (lockMode != null) {
502                     return session.load(entityClass, id, lockMode);
503                 }
504                 else {
505                     return session.load(entityClass, id);
506                 }
507             }
508         }, true);
509     }
510
511     public Object JavaDoc load(String JavaDoc entityName, Serializable JavaDoc id) throws DataAccessException {
512         return load(entityName, id, null);
513     }
514
515     public Object JavaDoc load(final String JavaDoc entityName, final Serializable JavaDoc id, final LockMode lockMode)
516             throws DataAccessException {
517
518         return execute(new HibernateCallback() {
519             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
520                 if (lockMode != null) {
521                     return session.load(entityName, id, lockMode);
522                 }
523                 else {
524                     return session.load(entityName, id);
525                 }
526             }
527         }, true);
528     }
529
530     public List JavaDoc loadAll(final Class JavaDoc entityClass) throws DataAccessException {
531         return (List JavaDoc) execute(new HibernateCallback() {
532             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
533                 Criteria criteria = session.createCriteria(entityClass);
534                 prepareCriteria(criteria);
535                 return criteria.list();
536             }
537         }, true);
538     }
539
540     public void load(final Object JavaDoc entity, final Serializable JavaDoc id) throws DataAccessException {
541         execute(new HibernateCallback() {
542             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
543                 session.load(entity, id);
544                 return null;
545             }
546         }, true);
547     }
548
549     public void refresh(final Object JavaDoc entity) throws DataAccessException {
550         refresh(entity, null);
551     }
552
553     public void refresh(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
554         execute(new HibernateCallback() {
555             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
556                 if (lockMode != null) {
557                     session.refresh(entity, lockMode);
558                 }
559                 else {
560                     session.refresh(entity);
561                 }
562                 return null;
563             }
564         }, true);
565     }
566
567     public boolean contains(final Object JavaDoc entity) throws DataAccessException {
568         Boolean JavaDoc result = (Boolean JavaDoc) execute(new HibernateCallback() {
569             public Object JavaDoc doInHibernate(Session session) {
570                 return (session.contains(entity) ? Boolean.TRUE : Boolean.FALSE);
571             }
572         }, true);
573         return result.booleanValue();
574     }
575
576     public void evict(final Object JavaDoc entity) throws DataAccessException {
577         execute(new HibernateCallback() {
578             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
579                 session.evict(entity);
580                 return null;
581             }
582         }, true);
583     }
584
585     public void initialize(Object JavaDoc proxy) throws DataAccessException {
586         try {
587             Hibernate.initialize(proxy);
588         }
589         catch (HibernateException ex) {
590             throw SessionFactoryUtils.convertHibernateAccessException(ex);
591         }
592     }
593
594     public Filter enableFilter(String JavaDoc filterName) throws IllegalStateException JavaDoc {
595         Session session = SessionFactoryUtils.getSession(getSessionFactory(), false);
596         Filter filter = session.getEnabledFilter(filterName);
597         if (filter == null) {
598             filter = session.enableFilter(filterName);
599         }
600         return filter;
601     }
602
603
604     //-------------------------------------------------------------------------
605
// Convenience methods for storing individual objects
606
//-------------------------------------------------------------------------
607

608     public void lock(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
609         execute(new HibernateCallback() {
610             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
611                 session.lock(entity, lockMode);
612                 return null;
613             }
614         }, true);
615     }
616
617     public void lock(final String JavaDoc entityName, final Object JavaDoc entity, final LockMode lockMode)
618             throws DataAccessException {
619
620         execute(new HibernateCallback() {
621             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
622                 session.lock(entityName, entity, lockMode);
623                 return null;
624             }
625         }, true);
626     }
627
628     public Serializable JavaDoc save(final Object JavaDoc entity) throws DataAccessException {
629         return (Serializable JavaDoc) execute(new HibernateCallback() {
630             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
631                 checkWriteOperationAllowed(session);
632                 return session.save(entity);
633             }
634         }, true);
635     }
636
637     public Serializable JavaDoc save(final String JavaDoc entityName, final Object JavaDoc entity) throws DataAccessException {
638         return (Serializable JavaDoc) execute(new HibernateCallback() {
639             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
640                 checkWriteOperationAllowed(session);
641                 return session.save(entityName, entity);
642             }
643         }, true);
644     }
645
646     public void update(Object JavaDoc entity) throws DataAccessException {
647         update(entity, null);
648     }
649
650     public void update(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
651         execute(new HibernateCallback() {
652             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
653                 checkWriteOperationAllowed(session);
654                 session.update(entity);
655                 if (lockMode != null) {
656                     session.lock(entity, lockMode);
657                 }
658                 return null;
659             }
660         }, true);
661     }
662
663     public void update(String JavaDoc entityName, Object JavaDoc entity) throws DataAccessException {
664         update(entityName, entity, null);
665     }
666
667     public void update(final String JavaDoc entityName, final Object JavaDoc entity, final LockMode lockMode)
668             throws DataAccessException {
669
670         execute(new HibernateCallback() {
671             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
672                 checkWriteOperationAllowed(session);
673                 session.update(entityName, entity);
674                 if (lockMode != null) {
675                     session.lock(entity, lockMode);
676                 }
677                 return null;
678             }
679         }, true);
680     }
681
682     public void saveOrUpdate(final Object JavaDoc entity) throws DataAccessException {
683         execute(new HibernateCallback() {
684             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
685                 checkWriteOperationAllowed(session);
686                 session.saveOrUpdate(entity);
687                 return null;
688             }
689         }, true);
690     }
691
692     public void saveOrUpdate(final String JavaDoc entityName, final Object JavaDoc entity) throws DataAccessException {
693         execute(new HibernateCallback() {
694             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
695                 checkWriteOperationAllowed(session);
696                 session.saveOrUpdate(entityName, entity);
697                 return null;
698             }
699         }, true);
700     }
701
702     public void saveOrUpdateAll(final Collection JavaDoc entities) throws DataAccessException {
703         execute(new HibernateCallback() {
704             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
705                 checkWriteOperationAllowed(session);
706                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
707                     session.saveOrUpdate(it.next());
708                 }
709                 return null;
710             }
711         }, true);
712     }
713
714     public void replicate(final Object JavaDoc entity, final ReplicationMode replicationMode)
715             throws DataAccessException {
716
717         execute(new HibernateCallback() {
718             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
719                 checkWriteOperationAllowed(session);
720                 session.replicate(entity, replicationMode);
721                 return null;
722             }
723         }, true);
724     }
725
726     public void replicate(final String JavaDoc entityName, final Object JavaDoc entity, final ReplicationMode replicationMode)
727             throws DataAccessException {
728
729         execute(new HibernateCallback() {
730             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
731                 checkWriteOperationAllowed(session);
732                 session.replicate(entityName, entity, replicationMode);
733                 return null;
734             }
735         }, true);
736     }
737
738     public void persist(final Object JavaDoc entity) throws DataAccessException {
739         execute(new HibernateCallback() {
740             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
741                 checkWriteOperationAllowed(session);
742                 session.persist(entity);
743                 return null;
744             }
745         }, true);
746     }
747
748     public void persist(final String JavaDoc entityName, final Object JavaDoc entity) throws DataAccessException {
749         execute(new HibernateCallback() {
750             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
751                 checkWriteOperationAllowed(session);
752                 session.persist(entityName, entity);
753                 return null;
754             }
755         }, true);
756     }
757
758     public Object JavaDoc merge(final Object JavaDoc entity) throws DataAccessException {
759         return execute(new HibernateCallback() {
760             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
761                 checkWriteOperationAllowed(session);
762                 return session.merge(entity);
763             }
764         }, true);
765     }
766
767     public Object JavaDoc merge(final String JavaDoc entityName, final Object JavaDoc entity) throws DataAccessException {
768         return execute(new HibernateCallback() {
769             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
770                 checkWriteOperationAllowed(session);
771                 return session.merge(entityName, entity);
772             }
773         }, true);
774     }
775
776     public void delete(Object JavaDoc entity) throws DataAccessException {
777         delete(entity, null);
778     }
779
780     public void delete(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
781         execute(new HibernateCallback() {
782             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
783                 checkWriteOperationAllowed(session);
784                 if (lockMode != null) {
785                     session.lock(entity, lockMode);
786                 }
787                 session.delete(entity);
788                 return null;
789             }
790         }, true);
791     }
792
793     public void deleteAll(final Collection JavaDoc entities) throws DataAccessException {
794         execute(new HibernateCallback() {
795             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
796                 checkWriteOperationAllowed(session);
797                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
798                     session.delete(it.next());
799                 }
800                 return null;
801             }
802         }, true);
803     }
804
805     public void flush() throws DataAccessException {
806         execute(new HibernateCallback() {
807             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
808                 session.flush();
809                 return null;
810             }
811         }, true);
812     }
813
814     public void clear() throws DataAccessException {
815         execute(new HibernateCallback() {
816             public Object JavaDoc doInHibernate(Session session) {
817                 session.clear();
818                 return null;
819             }
820         }, true);
821     }
822
823
824     //-------------------------------------------------------------------------
825
// Convenience finder methods for HQL strings
826
//-------------------------------------------------------------------------
827

828     public List JavaDoc find(String JavaDoc queryString) throws DataAccessException {
829         return find(queryString, (Object JavaDoc[]) null);
830     }
831
832     public List JavaDoc find(String JavaDoc queryString, Object JavaDoc value) throws DataAccessException {
833         return find(queryString, new Object JavaDoc[] {value});
834     }
835
836     public List JavaDoc find(final String JavaDoc queryString, final Object JavaDoc[] values) throws DataAccessException {
837         return (List JavaDoc) execute(new HibernateCallback() {
838             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
839                 Query queryObject = session.createQuery(queryString);
840                 prepareQuery(queryObject);
841                 if (values != null) {
842                     for (int i = 0; i < values.length; i++) {
843                         queryObject.setParameter(i, values[i]);
844                     }
845                 }
846                 return queryObject.list();
847             }
848         }, true);
849     }
850
851     public List JavaDoc findByNamedParam(String JavaDoc queryString, String JavaDoc paramName, Object JavaDoc value)
852             throws DataAccessException {
853
854         return findByNamedParam(queryString, new String JavaDoc[] {paramName}, new Object JavaDoc[] {value});
855     }
856
857     public List JavaDoc findByNamedParam(final String JavaDoc queryString, final String JavaDoc[] paramNames, final Object JavaDoc[] values)
858             throws DataAccessException {
859
860         if (paramNames.length != values.length) {
861             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of values array");
862         }
863         return (List JavaDoc) execute(new HibernateCallback() {
864             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
865                 Query queryObject = session.createQuery(queryString);
866                 prepareQuery(queryObject);
867                 if (values != null) {
868                     for (int i = 0; i < values.length; i++) {
869                         applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
870                     }
871                 }
872                 return queryObject.list();
873             }
874         }, true);
875     }
876
877     public List JavaDoc findByValueBean(final String JavaDoc queryString, final Object JavaDoc valueBean)
878             throws DataAccessException {
879
880         return (List JavaDoc) execute(new HibernateCallback() {
881             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
882                 Query queryObject = session.createQuery(queryString);
883                 prepareQuery(queryObject);
884                 queryObject.setProperties(valueBean);
885                 return queryObject.list();
886             }
887         }, true);
888     }
889
890
891     //-------------------------------------------------------------------------
892
// Convenience finder methods for named queries
893
//-------------------------------------------------------------------------
894

895     public List JavaDoc findByNamedQuery(String JavaDoc queryName) throws DataAccessException {
896         return findByNamedQuery(queryName, (Object JavaDoc[]) null);
897     }
898
899     public List JavaDoc findByNamedQuery(String JavaDoc queryName, Object JavaDoc value) throws DataAccessException {
900         return findByNamedQuery(queryName, new Object JavaDoc[] {value});
901     }
902
903     public List JavaDoc findByNamedQuery(final String JavaDoc queryName, final Object JavaDoc[] values) throws DataAccessException {
904         return (List JavaDoc) execute(new HibernateCallback() {
905             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
906                 Query queryObject = session.getNamedQuery(queryName);
907                 prepareQuery(queryObject);
908                 if (values != null) {
909                     for (int i = 0; i < values.length; i++) {
910                         queryObject.setParameter(i, values[i]);
911                     }
912                 }
913                 return queryObject.list();
914             }
915         }, true);
916     }
917
918     public List JavaDoc findByNamedQueryAndNamedParam(String JavaDoc queryName, String JavaDoc paramName, Object JavaDoc value)
919             throws DataAccessException {
920
921         return findByNamedQueryAndNamedParam(queryName, new String JavaDoc[] {paramName}, new Object JavaDoc[] {value});
922     }
923
924     public List JavaDoc findByNamedQueryAndNamedParam(
925             final String JavaDoc queryName, final String JavaDoc[] paramNames, final Object JavaDoc[] values)
926             throws DataAccessException {
927
928         if (paramNames != null && values != null && paramNames.length != values.length) {
929             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of values array");
930         }
931         return (List JavaDoc) execute(new HibernateCallback() {
932             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
933                 Query queryObject = session.getNamedQuery(queryName);
934                 prepareQuery(queryObject);
935                 if (values != null) {
936                     for (int i = 0; i < values.length; i++) {
937                         applyNamedParameterToQuery(queryObject, paramNames[i], values[i]);
938                     }
939                 }
940                 return queryObject.list();
941             }
942         }, true);
943     }
944
945     public List JavaDoc findByNamedQueryAndValueBean(final String JavaDoc queryName, final Object JavaDoc valueBean)
946             throws DataAccessException {
947
948         return (List JavaDoc) execute(new HibernateCallback() {
949             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
950                 Query queryObject = session.getNamedQuery(queryName);
951                 prepareQuery(queryObject);
952                 queryObject.setProperties(valueBean);
953                 return queryObject.list();
954             }
955         }, true);
956     }
957
958
959     //-------------------------------------------------------------------------
960
// Convenience finder methods for detached criteria
961
//-------------------------------------------------------------------------
962

963     public List JavaDoc findByCriteria(DetachedCriteria criteria) throws DataAccessException {
964         return findByCriteria(criteria, -1, -1);
965     }
966
967     public List JavaDoc findByCriteria(final DetachedCriteria criteria, final int firstResult, final int maxResults)
968             throws DataAccessException {
969
970         Assert.notNull(criteria, "DetachedCriteria must not be null");
971         return (List JavaDoc) execute(new HibernateCallback() {
972             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
973                 Criteria executableCriteria = criteria.getExecutableCriteria(session);
974                 prepareCriteria(executableCriteria);
975                 if (firstResult >= 0) {
976                     executableCriteria.setFirstResult(firstResult);
977                 }
978                 if (maxResults > 0) {
979                     executableCriteria.setMaxResults(maxResults);
980                 }
981                 return executableCriteria.list();
982             }
983         }, true);
984     }
985
986     public List JavaDoc findByExample(Object JavaDoc exampleEntity) throws DataAccessException {
987         return findByExample(exampleEntity, -1, -1);
988     }
989
990     public List JavaDoc findByExample(final Object JavaDoc exampleEntity, final int firstResult, final int maxResults)
991             throws DataAccessException {
992
993         Assert.notNull(exampleEntity, "Example entity must not be null");
994         return (List JavaDoc) execute(new HibernateCallback() {
995             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
996                 Criteria executableCriteria = session.createCriteria(exampleEntity.getClass());
997                 executableCriteria.add(Example.create(exampleEntity));
998                 prepareCriteria(executableCriteria);
999                 if (firstResult >= 0) {
1000                    executableCriteria.setFirstResult(firstResult);
1001                }
1002                if (maxResults > 0) {
1003                    executableCriteria.setMaxResults(maxResults);
1004                }
1005                return executableCriteria.list();
1006            }
1007        }, true);
1008    }
1009
1010
1011    //-------------------------------------------------------------------------
1012
// Convenience query methods for iteration and bulk updates/deletes
1013
//-------------------------------------------------------------------------
1014

1015    public Iterator JavaDoc iterate(String JavaDoc queryString) throws DataAccessException {
1016        return iterate(queryString, (Object JavaDoc[]) null);
1017    }
1018
1019    public Iterator JavaDoc iterate(String JavaDoc queryString, Object JavaDoc value) throws DataAccessException {
1020        return iterate(queryString, new Object JavaDoc[] {value});
1021    }
1022
1023    public Iterator JavaDoc iterate(final String JavaDoc queryString, final Object JavaDoc[] values) throws DataAccessException {
1024        return (Iterator JavaDoc) execute(new HibernateCallback() {
1025            public Object JavaDoc doInHibernate(Session session) throws HibernateException {
1026                Query queryObject = session.createQuery(queryString);
1027                prepareQuery(queryObject);
1028                if (values != null) {
1029                    for (int i = 0; i < values.length; i++) {
1030                        queryObject.setParameter(i, values[i]);
1031                    }
1032                }
1033                return queryObject.iterate();
1034            }
1035        }, true);
1036    }
1037
1038    public void closeIterator(Iterator JavaDoc it) throws DataAccessException {
1039        try {
1040            Hibernate.close(it);
1041        }
1042        catch (HibernateException ex) {
1043            throw SessionFactoryUtils.convertHibernateAccessException(ex);
1044        }
1045    }
1046
1047    public int bulkUpdate(String JavaDoc queryString) throws DataAccessException {
1048        return bulkUpdate(queryString, (Object JavaDoc[]) null);
1049    }
1050
1051    public int bulkUpdate(String JavaDoc queryString, Object JavaDoc value) throws DataAccessException {
1052        return bulkUpdate(queryString, new Object JavaDoc[] {value});
1053    }
1054
1055    public int bulkUpdate(final String JavaDoc queryString, final Object JavaDoc[] values) throws DataAccessException {
1056        Integer JavaDoc updateCount = (Integer JavaDoc) execute(new HibernateCallback() {
1057            public Object JavaDoc doInHibernate(Session session) throws HibernateException {
1058                Query queryObject = session.createQuery(queryString);
1059                prepareQuery(queryObject);
1060                if (values != null) {
1061                    for (int i = 0; i < values.length; i++) {
1062                        queryObject.setParameter(i, values[i]);
1063                    }
1064                }
1065                return new Integer JavaDoc(queryObject.executeUpdate());
1066            }
1067        }, true);
1068        return updateCount.intValue();
1069    }
1070
1071
1072    //-------------------------------------------------------------------------
1073
// Helper methods used by the operations above
1074
//-------------------------------------------------------------------------
1075

1076    /**
1077     * Check whether write operations are allowed on the given Session.
1078     * <p>Default implementation throws an InvalidDataAccessApiUsageException in
1079     * case of <code>FlushMode.NEVER/MANUAL</code>. Can be overridden in subclasses.
1080     * @param session current Hibernate Session
1081     * @throws InvalidDataAccessApiUsageException if write operations are not allowed
1082     * @see #setCheckWriteOperations
1083     * @see #getFlushMode()
1084     * @see #FLUSH_EAGER
1085     * @see org.hibernate.Session#getFlushMode()
1086     * @see org.hibernate.FlushMode#NEVER
1087     * @see org.hibernate.FlushMode#MANUAL
1088     */

1089    protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
1090        if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
1091                session.getFlushMode().lessThan(FlushMode.COMMIT)) {
1092            throw new InvalidDataAccessApiUsageException(
1093                    "Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): "+
1094                    "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.");
1095        }
1096    }
1097
1098    /**
1099     * Prepare the given Query object, applying cache settings and/or
1100     * a transaction timeout.
1101     * @param queryObject the Query object to prepare
1102     * @see #setCacheQueries
1103     * @see #setQueryCacheRegion
1104     * @see SessionFactoryUtils#applyTransactionTimeout
1105     */

1106    protected void prepareQuery(Query queryObject) {
1107        if (isCacheQueries()) {
1108            queryObject.setCacheable(true);
1109            if (getQueryCacheRegion() != null) {
1110                queryObject.setCacheRegion(getQueryCacheRegion());
1111            }
1112        }
1113        if (getFetchSize() > 0) {
1114            queryObject.setFetchSize(getFetchSize());
1115        }
1116        if (getMaxResults() > 0) {
1117            queryObject.setMaxResults(getMaxResults());
1118        }
1119        SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
1120    }
1121
1122    /**
1123     * Prepare the given Criteria object, applying cache settings and/or
1124     * a transaction timeout.
1125     * @param criteria the Criteria object to prepare
1126     * @see #setCacheQueries
1127     * @see #setQueryCacheRegion
1128     * @see SessionFactoryUtils#applyTransactionTimeout
1129     */

1130    protected void prepareCriteria(Criteria criteria) {
1131        if (isCacheQueries()) {
1132            criteria.setCacheable(true);
1133            if (getQueryCacheRegion() != null) {
1134                criteria.setCacheRegion(getQueryCacheRegion());
1135            }
1136        }
1137        if (getFetchSize() > 0) {
1138            criteria.setFetchSize(getFetchSize());
1139        }
1140        if (getMaxResults() > 0) {
1141            criteria.setMaxResults(getMaxResults());
1142        }
1143        SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
1144    }
1145
1146    /**
1147     * Apply the given name parameter to the given Query object.
1148     * @param queryObject the Query object
1149     * @param paramName the name of the parameter
1150     * @param value the value of the parameter
1151     * @throws HibernateException if thrown by the Query object
1152     */

1153    protected void applyNamedParameterToQuery(Query queryObject, String JavaDoc paramName, Object JavaDoc value)
1154            throws HibernateException {
1155
1156        if (value instanceof Collection JavaDoc) {
1157            queryObject.setParameterList(paramName, (Collection JavaDoc) value);
1158        }
1159        else if (value instanceof Object JavaDoc[]) {
1160            queryObject.setParameterList(paramName, (Object JavaDoc[]) value);
1161        }
1162        else {
1163            queryObject.setParameter(paramName, value);
1164        }
1165    }
1166
1167
1168    /**
1169     * Invocation handler that suppresses close calls on Hibernate Sessions.
1170     * Also prepares returned Query and Criteria objects.
1171     * @see org.hibernate.Session#close
1172     */

1173    private class CloseSuppressingInvocationHandler implements InvocationHandler JavaDoc {
1174
1175        private final Session target;
1176
1177        public CloseSuppressingInvocationHandler(Session target) {
1178            this.target = target;
1179        }
1180
1181        public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
1182            // Invocation on Session interface coming in...
1183

1184            if (method.getName().equals("equals")) {
1185                // Only consider equal when proxies are identical.
1186
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
1187            }
1188            else if (method.getName().equals("hashCode")) {
1189                // Use hashCode of Session proxy.
1190
return new Integer JavaDoc(hashCode());
1191            }
1192            else if (method.getName().equals("close")) {
1193                // Handle close method: suppress, not valid.
1194
return null;
1195            }
1196
1197            // Invoke method on target Session.
1198
try {
1199                Object JavaDoc retVal = method.invoke(this.target, args);
1200
1201                // If return value is a Query or Criteria, apply transaction timeout.
1202
// Applies to createQuery, getNamedQuery, createCriteria.
1203
if (retVal instanceof Query) {
1204                    prepareQuery(((Query) retVal));
1205                }
1206                if (retVal instanceof Criteria) {
1207                    prepareCriteria(((Criteria) retVal));
1208                }
1209
1210                return retVal;
1211            }
1212            catch (InvocationTargetException JavaDoc ex) {
1213                throw ex.getTargetException();
1214            }
1215        }
1216    }
1217
1218}
1219
Popular Tags