KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > hibernate > 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.hibernate;
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 net.sf.hibernate.Criteria;
30 import net.sf.hibernate.FlushMode;
31 import net.sf.hibernate.Hibernate;
32 import net.sf.hibernate.HibernateException;
33 import net.sf.hibernate.LockMode;
34 import net.sf.hibernate.Query;
35 import net.sf.hibernate.ReplicationMode;
36 import net.sf.hibernate.Session;
37 import net.sf.hibernate.SessionFactory;
38 import net.sf.hibernate.type.Type;
39
40 import org.springframework.dao.DataAccessException;
41 import org.springframework.dao.InvalidDataAccessApiUsageException;
42 import org.springframework.util.Assert;
43
44 /**
45  * Helper class that simplifies Hibernate data access code, and converts
46  * checked HibernateExceptions into unchecked DataAccessExceptions,
47  * following the <code>org.springframework.dao</code> exception hierarchy.
48  * Uses the same SQLExceptionTranslator mechanism as JdbcTemplate.
49  *
50  * <p>Typically used to implement data access or business logic services that
51  * use Hibernate within their implementation but are Hibernate-agnostic in their
52  * interface. The latter or code calling the latter only have to deal with
53  * domain objects, query objects, and <code>org.springframework.dao</code> exceptions.
54  *
55  * <p>The central method is <code>execute</code>, supporting Hibernate access code
56  * implementing the {@link HibernateCallback} interface. It provides Hibernate Session
57  * handling such that neither the HibernateCallback implementation nor the calling
58  * code needs to explicitly care about retrieving/closing Hibernate Sessions,
59  * or handling Session lifecycle exceptions. For typical single step actions,
60  * there are various convenience methods (find, load, saveOrUpdate, delete).
61  *
62  * <p>Can be used within a service implementation via direct instantiation
63  * with a SessionFactory reference, or get prepared in an application context
64  * and given to services as bean reference. Note: The SessionFactory should
65  * always be configured as bean in the application context, in the first case
66  * given to the service directly, in the second case to the prepared template.
67  *
68  * <p>This class can be considered as direct alternative to working with the raw
69  * Hibernate Session API (through <code>SessionFactoryUtils.getSession()</code>).
70  * The major advantage is its automatic conversion to DataAccessExceptions, the
71  * major disadvantage that no checked application exceptions can get thrown from
72  * within data access code. Corresponding checks and the actual throwing of such
73  * exceptions can often be deferred to after callback execution, though.
74  *
75  * <p>Note that even if {@link HibernateTransactionManager} is used for transaction
76  * demarcation in higher-level services, all those services above the data
77  * access layer don't need to be Hibernate-aware. Setting such a special
78  * PlatformTransactionManager is a configuration issue: For example,
79  * switching to JTA is just a matter of Spring configuration (use
80  * JtaTransactionManager instead) that does not affect application code.
81  *
82  * <p>{@link LocalSessionFactoryBean} is the preferred way of obtaining a reference
83  * to a specific Hibernate SessionFactory, at least in a non-EJB environment.
84  * The Spring application context will manage its lifecycle, initializing and
85  * shutting down the factory as part of the application.
86  *
87  * <p>Note that operations that return an Iterator (i.e. <code>iterate</code>)
88  * are supposed to be used within Spring-driven or JTA-driven transactions
89  * (with HibernateTransactionManager, JtaTransactionManager, or EJB CMT).
90  * Else, the Iterator won't be able to read results from its ResultSet anymore,
91  * as the underlying Hibernate Session will already have been closed.
92  *
93  * <p>Lazy loading will also just work with an open Hibernate Session,
94  * either within a transaction or within OpenSessionInViewFilter/Interceptor.
95  * Furthermore, some operations just make sense within transactions,
96  * for example: <code>contains</code>, <code>evict</code>, <code>lock</code>,
97  * <code>flush</code>, <code>clear</code>.
98  *
99  * <p>Note: Spring's Hibernate support in this package requires Hibernate 2.1.
100  * Dedicated Hibernate3 support can be found in a separate package:
101  * <code>org.springframework.orm.hibernate3</code>.
102  *
103  * @author Juergen Hoeller
104  * @since 02.05.2003
105  * @see #setSessionFactory
106  * @see #setJdbcExceptionTranslator
107  * @see HibernateCallback
108  * @see net.sf.hibernate.Session
109  * @see HibernateInterceptor
110  * @see LocalSessionFactoryBean
111  * @see org.springframework.jndi.JndiObjectFactoryBean
112  * @see org.springframework.jdbc.support.SQLExceptionTranslator
113  * @see HibernateTransactionManager
114  * @see org.springframework.transaction.jta.JtaTransactionManager
115  * @see org.springframework.orm.hibernate.support.OpenSessionInViewFilter
116  * @see org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor
117  */

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

357     public Object JavaDoc execute(HibernateCallback action, boolean exposeNativeSession) throws DataAccessException {
358         Assert.notNull(action, "Callback object must not be null");
359
360         Session session = getSession();
361         boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());
362         if (existingTransaction) {
363             logger.debug("Found thread-bound Session for HibernateTemplate");
364         }
365
366         FlushMode previousFlushMode = null;
367         try {
368             previousFlushMode = applyFlushMode(session, existingTransaction);
369             Session sessionToExpose = (exposeNativeSession ? session : createSessionProxy(session));
370             Object JavaDoc result = action.doInHibernate(sessionToExpose);
371             flushIfNecessary(session, existingTransaction);
372             return result;
373         }
374         catch (HibernateException ex) {
375             throw convertHibernateAccessException(ex);
376         }
377         catch (SQLException JavaDoc ex) {
378             throw convertJdbcAccessException(ex);
379         }
380         catch (RuntimeException JavaDoc ex) {
381             // Callback code threw application exception...
382
throw ex;
383         }
384         finally {
385             if (existingTransaction) {
386                 logger.debug("Not closing pre-bound Hibernate Session after HibernateTemplate");
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 net.sf.hibernate.Session#close()
433      * @see #prepareQuery
434      * @see #prepareCriteria
435      */

436     protected Session createSessionProxy(Session session) {
437         return (Session) Proxy.newProxyInstance(
438                 getClass().getClassLoader(),
439                 new Class JavaDoc[] {Session.class},
440                 new CloseSuppressingInvocationHandler(session));
441     }
442
443
444     //-------------------------------------------------------------------------
445
// Convenience methods for loading individual objects
446
//-------------------------------------------------------------------------
447

448     public Object JavaDoc get(Class JavaDoc entityClass, Serializable JavaDoc id) throws DataAccessException {
449         return get(entityClass, id, null);
450     }
451
452     public Object JavaDoc get(final Class JavaDoc entityClass, final Serializable JavaDoc id, final LockMode lockMode)
453             throws DataAccessException {
454
455         return execute(new HibernateCallback() {
456             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
457                 if (lockMode != null) {
458                     return session.get(entityClass, id, lockMode);
459                 }
460                 else {
461                     return session.get(entityClass, id);
462                 }
463             }
464         }, true);
465     }
466
467     public Object JavaDoc load(Class JavaDoc entityClass, Serializable JavaDoc id) throws DataAccessException {
468         return load(entityClass, id, null);
469     }
470
471     public Object JavaDoc load(final Class JavaDoc entityClass, final Serializable JavaDoc id, final LockMode lockMode)
472             throws DataAccessException {
473
474         return execute(new HibernateCallback() {
475             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
476                 if (lockMode != null) {
477                     return session.load(entityClass, id, lockMode);
478                 }
479                 else {
480                     return session.load(entityClass, id);
481                 }
482             }
483         }, true);
484     }
485
486     public List JavaDoc loadAll(final Class JavaDoc entityClass) throws DataAccessException {
487         return (List JavaDoc) execute(new HibernateCallback() {
488             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
489                 Criteria criteria = session.createCriteria(entityClass);
490                 prepareCriteria(criteria);
491                 return criteria.list();
492             }
493         }, true);
494     }
495
496     public void load(final Object JavaDoc entity, final Serializable JavaDoc id) throws DataAccessException {
497         execute(new HibernateCallback() {
498             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
499                 session.load(entity, id);
500                 return null;
501             }
502         }, true);
503     }
504
505     public void refresh(final Object JavaDoc entity) throws DataAccessException {
506         refresh(entity, null);
507     }
508
509     public void refresh(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
510         execute(new HibernateCallback() {
511             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
512                 if (lockMode != null) {
513                     session.refresh(entity, lockMode);
514                 }
515                 else {
516                     session.refresh(entity);
517                 }
518                 return null;
519             }
520         }, true);
521     }
522
523     public boolean contains(final Object JavaDoc entity) throws DataAccessException {
524         Boolean JavaDoc result = (Boolean JavaDoc) execute(new HibernateCallback() {
525             public Object JavaDoc doInHibernate(Session session) {
526                 return (session.contains(entity) ? Boolean.TRUE : Boolean.FALSE);
527             }
528         }, true);
529         return result.booleanValue();
530     }
531
532     public void evict(final Object JavaDoc entity) throws DataAccessException {
533         execute(new HibernateCallback() {
534             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
535                 session.evict(entity);
536                 return null;
537             }
538         }, true);
539     }
540
541     public void initialize(Object JavaDoc proxy) throws DataAccessException {
542         try {
543             Hibernate.initialize(proxy);
544         }
545         catch (HibernateException ex) {
546             throw SessionFactoryUtils.convertHibernateAccessException(ex);
547         }
548     }
549
550
551     //-------------------------------------------------------------------------
552
// Convenience methods for storing individual objects
553
//-------------------------------------------------------------------------
554

555     public void lock(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
556         execute(new HibernateCallback() {
557             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
558                 session.lock(entity, lockMode);
559                 return null;
560             }
561         }, true);
562     }
563
564     public Serializable JavaDoc save(final Object JavaDoc entity) throws DataAccessException {
565         return (Serializable JavaDoc) execute(new HibernateCallback() {
566             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
567                 checkWriteOperationAllowed(session);
568                 return session.save(entity);
569             }
570         }, true);
571     }
572
573     public void save(final Object JavaDoc entity, final Serializable JavaDoc id) throws DataAccessException {
574         execute(new HibernateCallback() {
575             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
576                 checkWriteOperationAllowed(session);
577                 session.save(entity, id);
578                 return null;
579             }
580         }, true);
581     }
582
583     public void update(Object JavaDoc entity) throws DataAccessException {
584         update(entity, null);
585     }
586
587     public void update(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
588         execute(new HibernateCallback() {
589             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
590                 checkWriteOperationAllowed(session);
591                 session.update(entity);
592                 if (lockMode != null) {
593                     session.lock(entity, lockMode);
594                 }
595                 return null;
596             }
597         }, true);
598     }
599
600     public void saveOrUpdate(final Object JavaDoc entity) throws DataAccessException {
601         execute(new HibernateCallback() {
602             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
603                 checkWriteOperationAllowed(session);
604                 session.saveOrUpdate(entity);
605                 return null;
606             }
607         }, true);
608     }
609
610     public void saveOrUpdateAll(final Collection JavaDoc entities) throws DataAccessException {
611         execute(new HibernateCallback() {
612             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
613                 checkWriteOperationAllowed(session);
614                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
615                     session.saveOrUpdate(it.next());
616                 }
617                 return null;
618             }
619         }, true);
620     }
621
622     public Object JavaDoc saveOrUpdateCopy(final Object JavaDoc entity) throws DataAccessException {
623         return execute(new HibernateCallback() {
624             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
625                 checkWriteOperationAllowed(session);
626                 return session.saveOrUpdateCopy(entity);
627             }
628         }, true);
629     }
630
631     public void replicate(final Object JavaDoc entity, final ReplicationMode replicationMode)
632             throws DataAccessException {
633
634         execute(new HibernateCallback() {
635             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
636                 checkWriteOperationAllowed(session);
637                 session.replicate(entity, replicationMode);
638                 return null;
639             }
640         }, true);
641     }
642
643     public void delete(Object JavaDoc entity) throws DataAccessException {
644         delete(entity, null);
645     }
646
647     public void delete(final Object JavaDoc entity, final LockMode lockMode) throws DataAccessException {
648         execute(new HibernateCallback() {
649             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
650                 checkWriteOperationAllowed(session);
651                 if (lockMode != null) {
652                     session.lock(entity, lockMode);
653                 }
654                 session.delete(entity);
655                 return null;
656             }
657         }, true);
658     }
659
660     public void deleteAll(final Collection JavaDoc entities) throws DataAccessException {
661         execute(new HibernateCallback() {
662             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
663                 checkWriteOperationAllowed(session);
664                 for (Iterator JavaDoc it = entities.iterator(); it.hasNext();) {
665                     session.delete(it.next());
666                 }
667                 return null;
668             }
669         }, true);
670     }
671
672     public void flush() throws DataAccessException {
673         execute(new HibernateCallback() {
674             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
675                 session.flush();
676                 return null;
677             }
678         }, true);
679     }
680
681     public void clear() throws DataAccessException {
682         execute(new HibernateCallback() {
683             public Object JavaDoc doInHibernate(Session session) {
684                 session.clear();
685                 return null;
686             }
687         }, true);
688     }
689
690
691     //-------------------------------------------------------------------------
692
// Convenience finder methods for HQL strings
693
//-------------------------------------------------------------------------
694

695     public List JavaDoc find(String JavaDoc queryString) throws DataAccessException {
696         return find(queryString, (Object JavaDoc[]) null, (Type[]) null);
697     }
698
699     public List JavaDoc find(String JavaDoc queryString, Object JavaDoc value) throws DataAccessException {
700         return find(queryString, new Object JavaDoc[] {value}, (Type[]) null);
701     }
702
703     public List JavaDoc find(String JavaDoc queryString, Object JavaDoc value, Type type) throws DataAccessException {
704         return find(queryString, new Object JavaDoc[] {value}, new Type[] {type});
705     }
706
707     public List JavaDoc find(String JavaDoc queryString, Object JavaDoc[] values) throws DataAccessException {
708         return find(queryString, values, (Type[]) null);
709     }
710
711     public List JavaDoc find(final String JavaDoc queryString, final Object JavaDoc[] values, final Type[] types)
712             throws DataAccessException {
713
714         if (values != null && types != null && values.length != types.length) {
715             throw new IllegalArgumentException JavaDoc("Length of values array must match length of types array");
716         }
717         return (List JavaDoc) execute(new HibernateCallback() {
718             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
719                 Query queryObject = session.createQuery(queryString);
720                 prepareQuery(queryObject);
721                 if (values != null) {
722                     for (int i = 0; i < values.length; i++) {
723                         if (types != null && types[i] != null) {
724                             queryObject.setParameter(i, values[i], types[i]);
725                         }
726                         else {
727                             queryObject.setParameter(i, values[i]);
728                         }
729                     }
730                 }
731                 return queryObject.list();
732             }
733         }, true);
734     }
735
736     public List JavaDoc findByNamedParam(String JavaDoc queryString, String JavaDoc paramName, Object JavaDoc value)
737             throws DataAccessException {
738
739         return findByNamedParam(queryString, paramName, value, null);
740     }
741
742     public List JavaDoc findByNamedParam(String JavaDoc queryString, String JavaDoc paramName, Object JavaDoc value, Type type)
743             throws DataAccessException {
744
745         return findByNamedParam(queryString, new String JavaDoc[] {paramName}, new Object JavaDoc[] {value}, new Type[] {type});
746     }
747
748     public List JavaDoc findByNamedParam(String JavaDoc queryString, String JavaDoc[] paramNames, Object JavaDoc[] values)
749             throws DataAccessException {
750
751         return findByNamedParam(queryString, paramNames, values, null);
752     }
753
754     public List JavaDoc findByNamedParam(
755         final String JavaDoc queryString, final String JavaDoc[] paramNames, final Object JavaDoc[] values, final Type[] types)
756         throws DataAccessException {
757
758         if (paramNames.length != values.length) {
759             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of values array");
760         }
761         if (types != null && paramNames.length != types.length) {
762             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of types array");
763         }
764         return (List JavaDoc) execute(new HibernateCallback() {
765             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
766                 Query queryObject = session.createQuery(queryString);
767                 prepareQuery(queryObject);
768                 if (values != null) {
769                     for (int i = 0; i < values.length; i++) {
770                         applyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
771                     }
772                 }
773                 return queryObject.list();
774             }
775         }, true);
776     }
777
778     public List JavaDoc findByValueBean(final String JavaDoc queryString, final Object JavaDoc valueBean)
779             throws DataAccessException {
780
781         return (List JavaDoc) execute(new HibernateCallback() {
782             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
783                 Query queryObject = session.createQuery(queryString);
784                 prepareQuery(queryObject);
785                 queryObject.setProperties(valueBean);
786                 return queryObject.list();
787             }
788         }, true);
789     }
790
791
792     //-------------------------------------------------------------------------
793
// Convenience finder methods for named queries
794
//-------------------------------------------------------------------------
795

796     public List JavaDoc findByNamedQuery(String JavaDoc queryName) throws DataAccessException {
797         return findByNamedQuery(queryName, (Object JavaDoc[]) null, (Type[]) null);
798     }
799
800     public List JavaDoc findByNamedQuery(String JavaDoc queryName, Object JavaDoc value) throws DataAccessException {
801         return findByNamedQuery(queryName, new Object JavaDoc[] {value}, (Type[]) null);
802     }
803
804     public List JavaDoc findByNamedQuery(String JavaDoc queryName, Object JavaDoc value, Type type) throws DataAccessException {
805         return findByNamedQuery(queryName, new Object JavaDoc[] {value}, new Type[] {type});
806     }
807
808     public List JavaDoc findByNamedQuery(String JavaDoc queryName, Object JavaDoc[] values) throws DataAccessException {
809         return findByNamedQuery(queryName, values, (Type[]) null);
810     }
811
812     public List JavaDoc findByNamedQuery(final String JavaDoc queryName, final Object JavaDoc[] values, final Type[] types)
813             throws DataAccessException {
814
815         if (values != null && types != null && values.length != types.length) {
816             throw new IllegalArgumentException JavaDoc("Length of values array must match length of types array");
817         }
818         return (List JavaDoc) execute(new HibernateCallback() {
819             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
820                 Query queryObject = session.getNamedQuery(queryName);
821                 prepareQuery(queryObject);
822                 if (values != null) {
823                     for (int i = 0; i < values.length; i++) {
824                         if (types != null && types[i] != null) {
825                             queryObject.setParameter(i, values[i], types[i]);
826                         }
827                         else {
828                             queryObject.setParameter(i, values[i]);
829                         }
830                     }
831                 }
832                 return queryObject.list();
833             }
834         }, true);
835     }
836
837     public List JavaDoc findByNamedQueryAndNamedParam(String JavaDoc queryName, String JavaDoc paramName, Object JavaDoc value)
838             throws DataAccessException {
839
840         return findByNamedQueryAndNamedParam(queryName, paramName, value, null);
841     }
842
843     public List JavaDoc findByNamedQueryAndNamedParam(String JavaDoc queryName, String JavaDoc paramName, Object JavaDoc value, Type type)
844             throws DataAccessException {
845
846         return findByNamedQueryAndNamedParam(
847                 queryName, new String JavaDoc[] {paramName}, new Object JavaDoc[] {value}, new Type[] {type});
848     }
849
850     public List JavaDoc findByNamedQueryAndNamedParam(String JavaDoc queryName, String JavaDoc[] paramNames, Object JavaDoc[] values)
851             throws DataAccessException {
852
853         return findByNamedQueryAndNamedParam(queryName, paramNames, values, null);
854     }
855
856     public List JavaDoc findByNamedQueryAndNamedParam(
857         final String JavaDoc queryName, final String JavaDoc[] paramNames, final Object JavaDoc[] values, final Type[] types)
858         throws DataAccessException {
859
860         if (paramNames != null && values != null && paramNames.length != values.length) {
861             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of values array");
862         }
863         if (values != null && types != null && paramNames.length != types.length) {
864             throw new IllegalArgumentException JavaDoc("Length of paramNames array must match length of types array");
865         }
866         return (List JavaDoc) execute(new HibernateCallback() {
867             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
868                 Query queryObject = session.getNamedQuery(queryName);
869                 prepareQuery(queryObject);
870                 if (values != null) {
871                     for (int i = 0; i < values.length; i++) {
872                         applyNamedParameterToQuery(queryObject, paramNames[i], values[i], (types != null ? types[i] : null));
873                     }
874                 }
875                 return queryObject.list();
876             }
877         }, true);
878     }
879
880     public List JavaDoc findByNamedQueryAndValueBean(final String JavaDoc queryName, final Object JavaDoc valueBean)
881             throws DataAccessException {
882
883         return (List JavaDoc) execute(new HibernateCallback() {
884             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
885                 Query queryObject = session.getNamedQuery(queryName);
886                 prepareQuery(queryObject);
887                 queryObject.setProperties(valueBean);
888                 return queryObject.list();
889             }
890         }, true);
891     }
892
893
894     //-------------------------------------------------------------------------
895
// Convenience query methods for iterate and delete
896
//-------------------------------------------------------------------------
897

898     public Iterator JavaDoc iterate(String JavaDoc queryString) throws DataAccessException {
899         return iterate(queryString, (Object JavaDoc[]) null, (Type[]) null);
900     }
901
902     public Iterator JavaDoc iterate(String JavaDoc queryString, Object JavaDoc value) throws DataAccessException {
903         return iterate(queryString, new Object JavaDoc[] {value}, (Type[]) null);
904     }
905
906     public Iterator JavaDoc iterate(String JavaDoc queryString, Object JavaDoc value, Type type)
907             throws DataAccessException {
908
909         return iterate(queryString, new Object JavaDoc[] {value}, new Type[] {type});
910     }
911
912     public Iterator JavaDoc iterate(String JavaDoc queryString, Object JavaDoc[] values) throws DataAccessException {
913         return iterate(queryString, values, (Type[]) null);
914     }
915
916     public Iterator JavaDoc iterate(final String JavaDoc queryString, final Object JavaDoc[] values, final Type[] types)
917             throws DataAccessException {
918
919         if (values != null && types != null && values.length != types.length) {
920             throw new IllegalArgumentException JavaDoc("Length of values array must match length of types array");
921         }
922         return (Iterator JavaDoc) execute(new HibernateCallback() {
923             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
924                 Query queryObject = session.createQuery(queryString);
925                 prepareQuery(queryObject);
926                 if (values != null) {
927                     for (int i = 0; i < values.length; i++) {
928                         if (types != null && types[i] != null) {
929                             queryObject.setParameter(i, values[i], types[i]);
930                         }
931                         else {
932                             queryObject.setParameter(i, values[i]);
933                         }
934                     }
935                 }
936                 return queryObject.iterate();
937             }
938         }, true);
939     }
940
941     public void closeIterator(Iterator JavaDoc it) throws DataAccessException {
942         try {
943             Hibernate.close(it);
944         }
945         catch (HibernateException ex) {
946             throw SessionFactoryUtils.convertHibernateAccessException(ex);
947         }
948     }
949
950     public int delete(String JavaDoc queryString) throws DataAccessException {
951         return delete(queryString, (Object JavaDoc[]) null, (Type[]) null);
952     }
953
954     public int delete(String JavaDoc queryString, Object JavaDoc value, Type type)
955             throws DataAccessException {
956
957         return delete(queryString, new Object JavaDoc[] {value}, new Type[] {type});
958     }
959
960     public int delete(final String JavaDoc queryString, final Object JavaDoc[] values, final Type[] types)
961             throws DataAccessException {
962
963         if (values != null && types != null && values.length != types.length) {
964             throw new IllegalArgumentException JavaDoc("Length of values array must match length of types array");
965         }
966         Integer JavaDoc deleteCount = (Integer JavaDoc) execute(new HibernateCallback() {
967             public Object JavaDoc doInHibernate(Session session) throws HibernateException {
968                 checkWriteOperationAllowed(session);
969                 if (values != null) {
970                     return new Integer JavaDoc(session.delete(queryString, values, types));
971                 }
972                 else {
973                     return new Integer JavaDoc(session.delete(queryString));
974                 }
975             }
976         }, true);
977         return deleteCount.intValue();
978     }
979
980
981     //-------------------------------------------------------------------------
982
// Helper methods used by the operations above
983
//-------------------------------------------------------------------------
984

985     /**
986      * Check whether write operations are allowed on the given Session.
987      * <p>Default implementation throws an InvalidDataAccessApiUsageException
988      * in case of <code>FlushMode.NEVER</code>. Can be overridden in subclasses.
989      * @param session current Hibernate Session
990      * @throws InvalidDataAccessApiUsageException if write operations are not allowed
991      * @see #setCheckWriteOperations
992      * @see #getFlushMode()
993      * @see #FLUSH_EAGER
994      * @see net.sf.hibernate.Session#getFlushMode()
995      * @see net.sf.hibernate.FlushMode#NEVER
996      */

997     protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException {
998         if (isCheckWriteOperations() && getFlushMode() != FLUSH_EAGER &&
999                 FlushMode.NEVER.equals(session.getFlushMode())) {
1000            throw new InvalidDataAccessApiUsageException(
1001                    "Write operations are not allowed in read-only mode (FlushMode.NEVER): "+
1002                    "Turn your Session into FlushMode.AUTO or remove 'readOnly' marker from transaction definition.");
1003        }
1004    }
1005
1006    /**
1007     * Prepare the given Query object, applying cache settings and/or
1008     * a transaction timeout.
1009     * @param queryObject the Query object to prepare
1010     * @see #setCacheQueries
1011     * @see #setQueryCacheRegion
1012     * @see SessionFactoryUtils#applyTransactionTimeout
1013     */

1014    protected void prepareQuery(Query queryObject) {
1015        if (isCacheQueries()) {
1016            queryObject.setCacheable(true);
1017            if (getQueryCacheRegion() != null) {
1018                queryObject.setCacheRegion(getQueryCacheRegion());
1019            }
1020        }
1021        if (getFetchSize() > 0) {
1022            queryObject.setFetchSize(getFetchSize());
1023        }
1024        if (getMaxResults() > 0) {
1025            queryObject.setMaxResults(getMaxResults());
1026        }
1027        SessionFactoryUtils.applyTransactionTimeout(queryObject, getSessionFactory());
1028    }
1029
1030    /**
1031     * Prepare the given Criteria object, applying cache settings and/or
1032     * a transaction timeout.
1033     * @param criteria the Criteria object to prepare
1034     * @see #setCacheQueries
1035     * @see #setQueryCacheRegion
1036     * @see SessionFactoryUtils#applyTransactionTimeout
1037     */

1038    protected void prepareCriteria(Criteria criteria) {
1039        if (isCacheQueries()) {
1040            criteria.setCacheable(true);
1041            if (getQueryCacheRegion() != null) {
1042                criteria.setCacheRegion(getQueryCacheRegion());
1043            }
1044        }
1045        if (getFetchSize() > 0) {
1046            criteria.setFetchSize(getFetchSize());
1047        }
1048        if (getMaxResults() > 0) {
1049            criteria.setMaxResults(getMaxResults());
1050        }
1051        SessionFactoryUtils.applyTransactionTimeout(criteria, getSessionFactory());
1052    }
1053
1054    /**
1055     * Apply the given name parameter to the given Query object.
1056     * @param queryObject the Query object
1057     * @param paramName the name of the parameter
1058     * @param value the value of the parameter
1059     * @param type Hibernate type of the parameter (or <code>null</code> if none specified)
1060     * @throws HibernateException if thrown by the Query object
1061     */

1062    protected void applyNamedParameterToQuery(Query queryObject, String JavaDoc paramName, Object JavaDoc value, Type type)
1063            throws HibernateException {
1064
1065        if (value instanceof Collection JavaDoc) {
1066            if (type != null) {
1067                queryObject.setParameterList(paramName, (Collection JavaDoc) value, type);
1068            }
1069            else {
1070                queryObject.setParameterList(paramName, (Collection JavaDoc) value);
1071            }
1072        }
1073        else if (value instanceof Object JavaDoc[]) {
1074            if (type != null) {
1075                queryObject.setParameterList(paramName, (Object JavaDoc[]) value, type);
1076            }
1077            else {
1078                queryObject.setParameterList(paramName, (Object JavaDoc[]) value);
1079            }
1080        }
1081        else {
1082            if (type != null) {
1083                queryObject.setParameter(paramName, value, type);
1084            }
1085            else {
1086                queryObject.setParameter(paramName, value);
1087            }
1088        }
1089    }
1090
1091
1092    /**
1093     * Invocation handler that suppresses close calls on Hibernate Sessions.
1094     * Also prepares returned Query and Criteria objects.
1095     * @see net.sf.hibernate.Session#close
1096     */

1097    private class CloseSuppressingInvocationHandler implements InvocationHandler JavaDoc {
1098
1099        private final Session target;
1100
1101        public CloseSuppressingInvocationHandler(Session target) {
1102            this.target = target;
1103        }
1104
1105        public Object JavaDoc invoke(Object JavaDoc proxy, Method JavaDoc method, Object JavaDoc[] args) throws Throwable JavaDoc {
1106            // Invocation on Session interface coming in...
1107

1108            if (method.getName().equals("equals")) {
1109                // Only consider equal when proxies are identical.
1110
return (proxy == args[0] ? Boolean.TRUE : Boolean.FALSE);
1111            }
1112            else if (method.getName().equals("hashCode")) {
1113                // Use hashCode of Session proxy.
1114
return new Integer JavaDoc(hashCode());
1115            }
1116            else if (method.getName().equals("close")) {
1117                // Handle close method: suppress, not valid.
1118
return null;
1119            }
1120
1121            // Invoke method on target Session.
1122
try {
1123                Object JavaDoc retVal = method.invoke(this.target, args);
1124
1125                // If return value is a Query or Criteria, apply transaction timeout.
1126
// Applies to createQuery, getNamedQuery, createCriteria.
1127
if (retVal instanceof Query) {
1128                    prepareQuery(((Query) retVal));
1129                }
1130                if (retVal instanceof Criteria) {
1131                    prepareCriteria(((Criteria) retVal));
1132                }
1133
1134                return retVal;
1135            }
1136            catch (InvocationTargetException JavaDoc ex) {
1137                throw ex.getTargetException();
1138            }
1139        }
1140    }
1141
1142}
1143
Popular Tags