KickJava   Java API By Example, From Geeks To Geeks.

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


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.File JavaDoc;
20 import java.lang.reflect.Array JavaDoc;
21 import java.sql.Connection JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.sql.Statement JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Enumeration JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.Map JavaDoc;
28 import java.util.Properties JavaDoc;
29
30 import javax.sql.DataSource JavaDoc;
31 import javax.transaction.TransactionManager JavaDoc;
32
33 import org.hibernate.ConnectionReleaseMode;
34 import org.hibernate.HibernateException;
35 import org.hibernate.Interceptor;
36 import org.hibernate.Session;
37 import org.hibernate.SessionFactory;
38 import org.hibernate.cfg.Configuration;
39 import org.hibernate.cfg.Environment;
40 import org.hibernate.cfg.Mappings;
41 import org.hibernate.cfg.NamingStrategy;
42 import org.hibernate.dialect.Dialect;
43 import org.hibernate.engine.FilterDefinition;
44 import org.hibernate.event.EventListeners;
45 import org.hibernate.tool.hbm2ddl.DatabaseMetadata;
46 import org.hibernate.transaction.JTATransactionFactory;
47
48 import org.springframework.beans.BeanUtils;
49 import org.springframework.core.io.ClassPathResource;
50 import org.springframework.core.io.Resource;
51 import org.springframework.dao.DataAccessException;
52 import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;
53 import org.springframework.jdbc.support.JdbcUtils;
54 import org.springframework.jdbc.support.lob.LobHandler;
55 import org.springframework.util.Assert;
56 import org.springframework.util.StringUtils;
57
58 /**
59  * {@link org.springframework.beans.factory.FactoryBean} that creates a
60  * Hibernate {@link org.hibernate.SessionFactory}. This is the usual way to
61  * set up a shared Hibernate SessionFactory in a Spring application context;
62  * the SessionFactory can then be passed to Hibernate-based DAOs via
63  * dependency injection.
64  *
65  * <p>Configuration settings can either be read from a Hibernate XML file,
66  * specified as "configLocation", or completely via this class. A typical
67  * local configuration consists of one or more "mappingResources", various
68  * "hibernateProperties" (not strictly necessary), and a "dataSource" that the
69  * SessionFactory should use. The latter can also be specified via Hibernate
70  * properties, but "dataSource" supports any Spring-configured DataSource,
71  * instead of relying on Hibernate's own connection providers.
72  *
73  * <p>This SessionFactory handling strategy is appropriate for most types of
74  * applications, from Hibernate-only single database apps to ones that need
75  * distributed transactions. Either {@link HibernateTransactionManager} or
76  * {@link org.springframework.transaction.jta.JtaTransactionManager} can be
77  * used for transaction demarcation, with the latter only necessary for
78  * transactions which span multiple databases.
79  *
80  * <p>This factory bean will by default expose a transaction-aware SessionFactory
81  * proxy, letting data access code work with the plain Hibernate SessionFactory
82  * and its <code>getCurrentSession()</code> method, while still being able to
83  * participate in current Spring-managed transactions: with any transaction
84  * management strategy, either local or JTA / EJB CMT, and any transaction
85  * synchronization mechanism, either Spring or JTA. Furthermore,
86  * <code>getCurrentSession()</code> will also seamlessly work with
87  * a request-scoped Session managed by
88  * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewFilter} /
89  * {@link org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor}.
90  *
91  * <p>Requires Hibernate 3.0.3 or later. Note that this factory will use
92  * "on_close" as default Hibernate connection release mode, unless in the
93  * case of a "jtaTransactionManager" specified, for the reason that
94  * this is appropriate for most Spring-based applications (in particular when
95  * using Spring's HibernateTransactionManager). Hibernate 3.0 used "on_close"
96  * as its own default too; however, Hibernate 3.1 changed this to "auto"
97  * (i.e. "after_statement" or "after_transaction").
98  *
99  * @author Juergen Hoeller
100  * @since 1.2
101  * @see HibernateTemplate#setSessionFactory
102  * @see HibernateTransactionManager#setSessionFactory
103  * @see #setExposeTransactionAwareSessionFactory
104  * @see #setJtaTransactionManager
105  * @see org.hibernate.SessionFactory#getCurrentSession()
106  * @see HibernateTransactionManager
107  */

108 public class LocalSessionFactoryBean extends AbstractSessionFactoryBean {
109
110     private static final ThreadLocal JavaDoc configTimeDataSourceHolder = new ThreadLocal JavaDoc();
111
112     private static final ThreadLocal JavaDoc configTimeTransactionManagerHolder = new ThreadLocal JavaDoc();
113
114     private static final ThreadLocal JavaDoc configTimeLobHandlerHolder = new ThreadLocal JavaDoc();
115
116     /**
117      * Return the DataSource for the currently configured Hibernate SessionFactory,
118      * to be used by LocalDataSourceConnectionProvoder.
119      * <p>This instance will be set before initialization of the corresponding
120      * SessionFactory, and reset immediately afterwards. It is thus only available
121      * during configuration.
122      * @see #setDataSource
123      * @see LocalDataSourceConnectionProvider
124      */

125     public static DataSource JavaDoc getConfigTimeDataSource() {
126         return (DataSource JavaDoc) configTimeDataSourceHolder.get();
127     }
128
129     /**
130      * Return the JTA TransactionManager for the currently configured Hibernate
131      * SessionFactory, to be used by LocalTransactionManagerLookup.
132      * <p>This instance will be set before initialization of the corresponding
133      * SessionFactory, and reset immediately afterwards. It is thus only available
134      * during configuration.
135      * @see #setJtaTransactionManager
136      * @see LocalTransactionManagerLookup
137      */

138     public static TransactionManager JavaDoc getConfigTimeTransactionManager() {
139         return (TransactionManager JavaDoc) configTimeTransactionManagerHolder.get();
140     }
141
142     /**
143      * Return the LobHandler for the currently configured Hibernate SessionFactory,
144      * to be used by UserType implementations like ClobStringType.
145      * <p>This instance will be set before initialization of the corresponding
146      * SessionFactory, and reset immediately afterwards. It is thus only available
147      * during configuration.
148      * @see #setLobHandler
149      * @see org.springframework.orm.hibernate3.support.ClobStringType
150      * @see org.springframework.orm.hibernate3.support.BlobByteArrayType
151      * @see org.springframework.orm.hibernate3.support.BlobSerializableType
152      */

153     public static LobHandler getConfigTimeLobHandler() {
154         return (LobHandler) configTimeLobHandlerHolder.get();
155     }
156
157
158     private Class JavaDoc configurationClass = Configuration.class;
159
160     private Resource[] configLocations;
161
162     private Resource[] mappingLocations;
163
164     private Resource[] cacheableMappingLocations;
165
166     private Resource[] mappingJarLocations;
167
168     private Resource[] mappingDirectoryLocations;
169
170     private Properties JavaDoc hibernateProperties;
171
172     private DataSource JavaDoc dataSource;
173
174     private boolean useTransactionAwareDataSource = false;
175
176     private TransactionManager JavaDoc jtaTransactionManager;
177
178     private LobHandler lobHandler;
179
180     private Interceptor entityInterceptor;
181
182     private NamingStrategy namingStrategy;
183
184     private TypeDefinitionBean[] typeDefinitions;
185
186     private FilterDefinition[] filterDefinitions;
187
188     private Properties JavaDoc entityCacheStrategies;
189
190     private Properties JavaDoc collectionCacheStrategies;
191
192     private Map JavaDoc eventListeners;
193
194     private boolean schemaUpdate = false;
195
196     private Configuration configuration;
197
198
199     /**
200      * Specify the Hibernate Configuration class to use.
201      * Default is "org.hibernate.cfg.Configuration"; any subclass of
202      * this default Hibernate Configuration class can be specified.
203      * <p>Can be set to "org.hibernate.cfg.AnnotationConfiguration" for
204      * using Hibernate3 annotation support (initially only available as
205      * alpha download separate from the main Hibernate3 distribution).
206      * <p>Annotated packages and annotated classes can be specified via the
207      * corresponding tags in "hibernate.cfg.xml" then, so this will usually
208      * be combined with a "configLocation" property that points at such a
209      * standard Hibernate configuration file.
210      * @see #setConfigLocation
211      * @see org.hibernate.cfg.Configuration
212      * @see org.hibernate.cfg.AnnotationConfiguration
213      */

214     public void setConfigurationClass(Class JavaDoc configurationClass) {
215         if (configurationClass == null || !Configuration.class.isAssignableFrom(configurationClass)) {
216             throw new IllegalArgumentException JavaDoc(
217                     "configurationClass must be assignable to [org.hibernate.cfg.Configuration]");
218         }
219         this.configurationClass = configurationClass;
220     }
221
222     /**
223      * Set the location of a single Hibernate XML config file, for example as
224      * classpath resource "classpath:hibernate.cfg.xml".
225      * <p>Note: Can be omitted when all necessary properties and mapping
226      * resources are specified locally via this bean.
227      * @see org.hibernate.cfg.Configuration#configure(java.net.URL)
228      */

229     public void setConfigLocation(Resource configLocation) {
230         this.configLocations = new Resource[] {configLocation};
231     }
232
233     /**
234      * Set the locations of multiple Hibernate XML config files, for example as
235      * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
236      * <p>Note: Can be omitted when all necessary properties and mapping
237      * resources are specified locally via this bean.
238      * @see org.hibernate.cfg.Configuration#configure(java.net.URL)
239      */

240     public void setConfigLocations(Resource[] configLocations) {
241         this.configLocations = configLocations;
242     }
243
244     /**
245      * Set Hibernate mapping resources to be found in the class path,
246      * like "example.hbm.xml" or "mypackage/example.hbm.xml".
247      * Analogous to mapping entries in a Hibernate XML config file.
248      * Alternative to the more generic setMappingLocations method.
249      * <p>Can be used to add to mappings from a Hibernate XML config file,
250      * or to specify all mappings locally.
251      * @see #setMappingLocations
252      * @see org.hibernate.cfg.Configuration#addResource
253      */

254     public void setMappingResources(String JavaDoc[] mappingResources) {
255         this.mappingLocations = new Resource[mappingResources.length];
256         for (int i = 0; i < mappingResources.length; i++) {
257             this.mappingLocations[i] = new ClassPathResource(mappingResources[i].trim());
258         }
259     }
260
261     /**
262      * Set locations of Hibernate mapping files, for example as classpath
263      * resource "classpath:example.hbm.xml". Supports any resource location
264      * via Spring's resource abstraction, for example relative paths like
265      * "WEB-INF/mappings/example.hbm.xml" when running in an application context.
266      * <p>Can be used to add to mappings from a Hibernate XML config file,
267      * or to specify all mappings locally.
268      * @see org.hibernate.cfg.Configuration#addInputStream
269      */

270     public void setMappingLocations(Resource[] mappingLocations) {
271         this.mappingLocations = mappingLocations;
272     }
273
274     /**
275      * Set locations of cacheable Hibernate mapping files, for example as web app
276      * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
277      * via Spring's resource abstraction, as long as the resource can be resolved
278      * in the file system.
279      * <p>Can be used to add to mappings from a Hibernate XML config file,
280      * or to specify all mappings locally.
281      * @see org.hibernate.cfg.Configuration#addCacheableFile(java.io.File)
282      */

283     public void setCacheableMappingLocations(Resource[] cacheableMappingLocations) {
284         this.cacheableMappingLocations = cacheableMappingLocations;
285     }
286
287     /**
288      * Set locations of jar files that contain Hibernate mapping resources,
289      * like "WEB-INF/lib/example.hbm.jar".
290      * <p>Can be used to add to mappings from a Hibernate XML config file,
291      * or to specify all mappings locally.
292      * @see org.hibernate.cfg.Configuration#addJar(java.io.File)
293      */

294     public void setMappingJarLocations(Resource[] mappingJarLocations) {
295         this.mappingJarLocations = mappingJarLocations;
296     }
297
298     /**
299      * Set locations of directories that contain Hibernate mapping resources,
300      * like "WEB-INF/mappings".
301      * <p>Can be used to add to mappings from a Hibernate XML config file,
302      * or to specify all mappings locally.
303      * @see org.hibernate.cfg.Configuration#addDirectory(java.io.File)
304      */

305     public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
306         this.mappingDirectoryLocations = mappingDirectoryLocations;
307     }
308
309     /**
310      * Set Hibernate properties, such as "hibernate.dialect".
311      * <p>Can be used to override values in a Hibernate XML config file,
312      * or to specify all necessary properties locally.
313      * <p>Note: Do not specify a transaction provider here when using
314      * Spring-driven transactions. It is also advisable to omit connection
315      * provider settings and use a Spring-set DataSource instead.
316      * @see #setDataSource
317      */

318     public void setHibernateProperties(Properties JavaDoc hibernateProperties) {
319         this.hibernateProperties = hibernateProperties;
320     }
321
322     /**
323      * Return the Hibernate properties, if any. Mainly available for
324      * configuration through property paths that specify individual keys.
325      */

326     public Properties JavaDoc getHibernateProperties() {
327         if (this.hibernateProperties == null) {
328             this.hibernateProperties = new Properties JavaDoc();
329         }
330         return this.hibernateProperties;
331     }
332
333     /**
334      * Set the DataSource to be used by the SessionFactory.
335      * If set, this will override corresponding settings in Hibernate properties.
336      * <p>If this is set, the Hibernate settings should not define
337      * a connection provider to avoid meaningless double configuration.
338      * <p>If using HibernateTransactionManager as transaction strategy, consider
339      * proxying your target DataSource with a LazyConnectionDataSourceProxy.
340      * This defers fetching of an actual JDBC Connection until the first JDBC
341      * Statement gets executed, even within JDBC transactions (as performed by
342      * HibernateTransactionManager). Such lazy fetching is particularly beneficial
343      * for read-only operations, in particular if the chances of resolving the
344      * result in the second-level cache are high.
345      * <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
346      * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
347      * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
348      * @see #setUseTransactionAwareDataSource
349      * @see LocalDataSourceConnectionProvider
350      * @see HibernateTransactionManager
351      * @see org.springframework.transaction.jta.JtaTransactionManager
352      * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
353      */

354     public void setDataSource(DataSource JavaDoc dataSource) {
355         this.dataSource = dataSource;
356     }
357
358     /**
359      * Set whether to use a transaction-aware DataSource for the SessionFactory,
360      * i.e. whether to automatically wrap the passed-in DataSource with Spring's
361      * TransactionAwareDataSourceProxy.
362      * <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
363      * HibernateTransactionManager or JtaTransactionManager, both of which work nicely
364      * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
365      * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
366      * <p>If you switch this flag to "true", Spring's Hibernate access will be able to
367      * <i>participate in JDBC-based transactions managed outside of Hibernate</i>
368      * (for example, by Spring's DataSourceTransactionManager). This can be convenient
369      * if you need a different local transaction strategy for another O/R mapping tool,
370      * for example, but still want Hibernate access to join into those transactions.
371      * <p>A further benefit of this option is that <i>plain Sessions opened directly
372      * via the SessionFactory</i>, outside of Spring's Hibernate support, will still
373      * participate in active Spring-managed transactions. However, consider using
374      * Hibernate's <code>getCurrentSession()</code> method instead (see javadoc of
375      * "exposeTransactionAwareSessionFactory" property).
376      * <p>As a further effect, using a transaction-aware DataSource will <i>apply
377      * remaining transaction timeouts to all created JDBC Statements</i>. This means
378      * that all operations performed by the SessionFactory will automatically
379      * participate in Spring-managed transaction timeouts, not just queries.
380      * This adds value even for HibernateTransactionManager, but only on Hibernate 3.0,
381      * as there is a direct transaction timeout facility in Hibernate 3.1.
382      * <p><b>WARNING:</b> When using a transaction-aware JDBC DataSource in combination
383      * with OpenSessionInViewFilter/Interceptor, whether participating in JTA or
384      * external JDBC-based transactions, it is strongly recommended to set Hibernate's
385      * Connection release mode to "after_transaction" or "after_statement", which
386      * guarantees proper Connection handling in such a scenario. In contrast to that,
387      * HibernateTransactionManager generally requires release mode "on_close".
388      * <p>Note: If you want to use Hibernate's Connection release mode "after_statement"
389      * with a DataSource specified on this LocalSessionFactoryBean (for example, a
390      * JTA-aware DataSource fetched from JNDI), switch this setting to "true".
391      * Else, the ConnectionProvider used underneath will vote against aggressive
392      * release and thus silently switch to release mode "after_transaction".
393      * @see #setDataSource
394      * @see #setExposeTransactionAwareSessionFactory
395      * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
396      * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
397      * @see org.springframework.orm.hibernate3.support.OpenSessionInViewFilter
398      * @see org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor
399      * @see HibernateTransactionManager
400      * @see org.springframework.transaction.jta.JtaTransactionManager
401      */

402     public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
403         this.useTransactionAwareDataSource = useTransactionAwareDataSource;
404     }
405
406     /**
407      * Set the JTA TransactionManager to be used for Hibernate's
408      * TransactionManagerLookup. If set, this will override corresponding
409      * settings in Hibernate properties. Allows to use a Spring-managed
410      * JTA TransactionManager for Hibernate's cache synchronization.
411      * <p>Note: If this is set, the Hibernate settings should not define a
412      * transaction manager lookup to avoid meaningless double configuration.
413      * @see LocalTransactionManagerLookup
414      */

415     public void setJtaTransactionManager(TransactionManager JavaDoc jtaTransactionManager) {
416         this.jtaTransactionManager = jtaTransactionManager;
417     }
418
419     /**
420      * Set the LobHandler to be used by the SessionFactory.
421      * Will be exposed at config time for UserType implementations.
422      * @see #getConfigTimeLobHandler
423      * @see org.hibernate.usertype.UserType
424      * @see org.springframework.orm.hibernate3.support.ClobStringType
425      * @see org.springframework.orm.hibernate3.support.BlobByteArrayType
426      * @see org.springframework.orm.hibernate3.support.BlobSerializableType
427      */

428     public void setLobHandler(LobHandler lobHandler) {
429         this.lobHandler = lobHandler;
430     }
431
432     /**
433      * Set a Hibernate entity interceptor that allows to inspect and change
434      * property values before writing to and reading from the database.
435      * Will get applied to any new Session created by this factory.
436      * <p>Such an interceptor can either be set at the SessionFactory level, i.e. on
437      * LocalSessionFactoryBean, or at the Session level, i.e. on HibernateTemplate,
438      * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set
439      * it on LocalSessionFactoryBean or HibernateTransactionManager to avoid repeated
440      * configuration and guarantee consistent behavior in transactions.
441      * @see HibernateTemplate#setEntityInterceptor
442      * @see HibernateInterceptor#setEntityInterceptor
443      * @see HibernateTransactionManager#setEntityInterceptor
444      * @see org.hibernate.cfg.Configuration#setInterceptor
445      */

446     public void setEntityInterceptor(Interceptor entityInterceptor) {
447         this.entityInterceptor = entityInterceptor;
448     }
449
450     /**
451      * Set a Hibernate NamingStrategy for the SessionFactory, determining the
452      * physical column and table names given the info in the mapping document.
453      * @see org.hibernate.cfg.Configuration#setNamingStrategy
454      */

455     public void setNamingStrategy(NamingStrategy namingStrategy) {
456         this.namingStrategy = namingStrategy;
457     }
458
459     /**
460      * Specify the Hibernate type definitions to register with the SessionFactory,
461      * as Spring TypeDefinitionBean instances. This is an alternative to specifying
462      * <&lt;typedef&gt; elements in Hibernate mapping files.
463      * <p>Unfortunately, Hibernate itself does not define a complete object that
464      * represents a type definition, hence the need for Spring's TypeDefinitionBean.
465      * @see TypeDefinitionBean
466      * @see org.hibernate.cfg.Mappings#addTypeDef(String, String, java.util.Properties)
467      */

468     public void setTypeDefinitions(TypeDefinitionBean[] typeDefinitions) {
469         this.typeDefinitions = typeDefinitions;
470     }
471
472     /**
473      * Specify the Hibernate FilterDefinitions to register with the SessionFactory.
474      * This is an alternative to specifying <&lt;filter-def&gt; elements in
475      * Hibernate mapping files.
476      * <p>Typically, the passed-in FilterDefinition objects will have been defined
477      * as Spring FilterDefinitionFactoryBeans, probably as inner beans within the
478      * LocalSessionFactoryBean definition.
479      * @see FilterDefinitionFactoryBean
480      * @see org.hibernate.cfg.Configuration#addFilterDefinition
481      */

482     public void setFilterDefinitions(FilterDefinition[] filterDefinitions) {
483         this.filterDefinitions = filterDefinitions;
484     }
485
486     /**
487      * Specify the cache strategies for entities (persistent classes or named entities).
488      * This configuration setting corresponds to the &lt;class-cache&gt; entry
489      * in the "hibernate.cfg.xml" configuration format.
490      * <p>For example:
491      * <pre>
492      * &lt;property name="entityCacheStrategies"&gt;
493      * &lt;props&gt;
494      * &lt;prop key="com.mycompany.Customer"&gt;read-write&lt;/prop&gt;
495      * &lt;prop key="com.mycompany.Product"&gt;read-only,myRegion&lt;/prop&gt;
496      * &lt;/props&gt;
497      * &lt;/property&gt;</pre>
498      * Note that appending a cache region name (with a comma separator) is only
499      * supported on Hibernate 3.1, where this functionality is publically available.
500      * @param entityCacheStrategies properties that define entity cache strategies,
501      * with class names as keys and cache concurrency strategies as values
502      * @see org.hibernate.cfg.Configuration#setCacheConcurrencyStrategy(String, String)
503      */

504     public void setEntityCacheStrategies(Properties JavaDoc entityCacheStrategies) {
505         this.entityCacheStrategies = entityCacheStrategies;
506     }
507
508     /**
509      * Specify the cache strategies for persistent collections (with specific roles).
510      * This configuration setting corresponds to the &lt;collection-cache&gt; entry
511      * in the "hibernate.cfg.xml" configuration format.
512      * <p>For example:
513      * <pre>
514      * &lt;property name="collectionCacheStrategies"&gt;
515      * &lt;props&gt;
516      * &lt;prop key="com.mycompany.Order.items">read-write&lt;/prop&gt;
517      * &lt;prop key="com.mycompany.Product.categories"&gt;read-only,myRegion&lt;/prop&gt;
518      * &lt;/props&gt;
519      * &lt;/property&gt;</pre>
520      * Note that appending a cache region name (with a comma separator) is only
521      * supported on Hibernate 3.1, where this functionality is publically available.
522      * @param collectionCacheStrategies properties that define collection cache strategies,
523      * with collection roles as keys and cache concurrency strategies as values
524      * @see org.hibernate.cfg.Configuration#setCollectionCacheConcurrencyStrategy(String, String)
525      */

526     public void setCollectionCacheStrategies(Properties JavaDoc collectionCacheStrategies) {
527         this.collectionCacheStrategies = collectionCacheStrategies;
528     }
529
530     /**
531      * Specify the Hibernate event listeners to register, with listener types
532      * as keys and listener objects as values.
533      * <p>Instead of a single listener object, you can also pass in a list
534      * or set of listeners objects as value. However, this is only supported
535      * on Hibernate 3.1.
536      * <p>See the Hibernate documentation for further details on listener types
537      * and associated listener interfaces.
538      * @param eventListeners Map with listener type Strings as keys and
539      * listener objects as values
540      * @see org.hibernate.cfg.Configuration#setListener(String, Object)
541      */

542     public void setEventListeners(Map JavaDoc eventListeners) {
543         this.eventListeners = eventListeners;
544     }
545
546     /**
547      * Set whether to execute a schema update after SessionFactory initialization.
548      * <p>For details on how to make schema update scripts work, see the Hibernate
549      * documentation, as this class leverages the same schema update script support
550      * in org.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
551      * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
552      * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
553      */

554     public void setSchemaUpdate(boolean schemaUpdate) {
555         this.schemaUpdate = schemaUpdate;
556     }
557
558
559     protected SessionFactory buildSessionFactory() throws Exception JavaDoc {
560         // Create Configuration instance.
561
Configuration config = newConfiguration();
562
563         if (this.dataSource != null) {
564             // Make given DataSource available for SessionFactory configuration.
565
configTimeDataSourceHolder.set(this.dataSource);
566         }
567
568         if (this.jtaTransactionManager != null) {
569             // Make Spring-provided JTA TransactionManager available.
570
configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
571         }
572
573         if (this.lobHandler != null) {
574             // Make given LobHandler available for SessionFactory configuration.
575
// Do early because because mapping resource might refer to custom types.
576
configTimeLobHandlerHolder.set(this.lobHandler);
577         }
578
579         try {
580             if (this.jtaTransactionManager != null) {
581                 // Set Spring-provided JTA TransactionManager as Hibernate property.
582
config.setProperty(
583                         Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
584                 config.setProperty(
585                         Environment.TRANSACTION_STRATEGY, JTATransactionFactory.class.getName());
586             }
587             else {
588                 // Set connection release mode "on_close" as default.
589
// This was the case for Hibernate 3.0; Hibernate 3.1 changed
590
// it to "auto" (i.e. "after_statement" or "after_transaction").
591
// However, for Spring's resource management (in particular for
592
// HibernateTransactionManager), "on_close" is the better default.
593
config.setProperty(Environment.RELEASE_CONNECTIONS, ConnectionReleaseMode.ON_CLOSE.toString());
594             }
595
596             if (!isExposeTransactionAwareSessionFactory()) {
597                 // Not exposing a SessionFactory proxy with transaction-aware
598
// getCurrentSession() method -> set Hibernate 3.1 CurrentSessionContext
599
// implementation instead, providing the Spring-managed Session that way.
600
// Can be overridden by a custom value for the corresponding Hibernate property.
601
config.setProperty(Environment.CURRENT_SESSION_CONTEXT_CLASS,
602                         "org.springframework.orm.hibernate3.SpringSessionContext");
603             }
604
605             if (this.entityInterceptor != null) {
606                 // Set given entity interceptor at SessionFactory level.
607
config.setInterceptor(this.entityInterceptor);
608             }
609
610             if (this.namingStrategy != null) {
611                 // Pass given naming strategy to Hibernate Configuration.
612
config.setNamingStrategy(this.namingStrategy);
613             }
614
615             if (this.typeDefinitions != null) {
616                 // Register specified Hibernate type definitions.
617
Mappings mappings = config.createMappings();
618                 for (int i = 0; i < this.typeDefinitions.length; i++) {
619                     TypeDefinitionBean typeDef = this.typeDefinitions[i];
620                     mappings.addTypeDef(typeDef.getTypeName(), typeDef.getTypeClass(), typeDef.getParameters());
621                 }
622             }
623
624             if (this.filterDefinitions != null) {
625                 // Register specified Hibernate FilterDefinitions.
626
for (int i = 0; i < this.filterDefinitions.length; i++) {
627                     config.addFilterDefinition(this.filterDefinitions[i]);
628                 }
629             }
630
631             if (this.configLocations != null) {
632                 for (int i = 0; i < this.configLocations.length; i++) {
633                     // Load Hibernate configuration from given location.
634
config.configure(this.configLocations[i].getURL());
635                 }
636             }
637
638             if (this.hibernateProperties != null) {
639                 // Add given Hibernate properties to Configuration.
640
config.addProperties(this.hibernateProperties);
641             }
642
643             if (this.dataSource != null) {
644                 boolean actuallyTransactionAware =
645                         (this.useTransactionAwareDataSource || this.dataSource instanceof TransactionAwareDataSourceProxy);
646                 // Set Spring-provided DataSource as Hibernate ConnectionProvider.
647
config.setProperty(Environment.CONNECTION_PROVIDER,
648                         actuallyTransactionAware ?
649                         TransactionAwareDataSourceConnectionProvider.class.getName() :
650                         LocalDataSourceConnectionProvider.class.getName());
651             }
652
653             if (this.mappingLocations != null) {
654                 // Register given Hibernate mapping definitions, contained in resource files.
655
for (int i = 0; i < this.mappingLocations.length; i++) {
656                     config.addInputStream(this.mappingLocations[i].getInputStream());
657                 }
658             }
659
660             if (this.cacheableMappingLocations != null) {
661                 // Register given cacheable Hibernate mapping definitions, read from the file system.
662
for (int i = 0; i < this.cacheableMappingLocations.length; i++) {
663                     config.addCacheableFile(this.cacheableMappingLocations[i].getFile());
664                 }
665             }
666
667             if (this.mappingJarLocations != null) {
668                 // Register given Hibernate mapping definitions, contained in jar files.
669
for (int i = 0; i < this.mappingJarLocations.length; i++) {
670                     Resource resource = this.mappingJarLocations[i];
671                     config.addJar(resource.getFile());
672                 }
673             }
674
675             if (this.mappingDirectoryLocations != null) {
676                 // Register all Hibernate mapping definitions in the given directories.
677
for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
678                     File JavaDoc file = this.mappingDirectoryLocations[i].getFile();
679                     if (!file.isDirectory()) {
680                         throw new IllegalArgumentException JavaDoc(
681                                 "Mapping directory location [" + this.mappingDirectoryLocations[i] +
682                                 "] does not denote a directory");
683                     }
684                     config.addDirectory(file);
685                 }
686             }
687
688             if (this.entityCacheStrategies != null) {
689                 // Register cache strategies for mapped entities.
690
for (Enumeration JavaDoc classNames = this.entityCacheStrategies.propertyNames(); classNames.hasMoreElements();) {
691                     String JavaDoc className = (String JavaDoc) classNames.nextElement();
692                     String JavaDoc[] strategyAndRegion =
693                             StringUtils.commaDelimitedListToStringArray(this.entityCacheStrategies.getProperty(className));
694                     if (strategyAndRegion.length > 1) {
695                         config.setCacheConcurrencyStrategy(className, strategyAndRegion[0], strategyAndRegion[1]);
696                     }
697                     else if (strategyAndRegion.length > 0) {
698                         config.setCacheConcurrencyStrategy(className, strategyAndRegion[0]);
699                     }
700                 }
701             }
702
703             if (this.collectionCacheStrategies != null) {
704                 // Register cache strategies for mapped collections.
705
for (Enumeration JavaDoc collRoles = this.collectionCacheStrategies.propertyNames(); collRoles.hasMoreElements();) {
706                     String JavaDoc collRole = (String JavaDoc) collRoles.nextElement();
707                     String JavaDoc[] strategyAndRegion =
708                             StringUtils.commaDelimitedListToStringArray(this.collectionCacheStrategies.getProperty(collRole));
709                     if (strategyAndRegion.length > 1) {
710                         config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0], strategyAndRegion[1]);
711                     }
712                     else if (strategyAndRegion.length > 0) {
713                         config.setCollectionCacheConcurrencyStrategy(collRole, strategyAndRegion[0]);
714                     }
715                 }
716             }
717
718             if (this.eventListeners != null) {
719                 // Register specified Hibernate event listeners.
720
for (Iterator JavaDoc it = this.eventListeners.entrySet().iterator(); it.hasNext();) {
721                     Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
722                     Assert.isTrue(entry.getKey() instanceof String JavaDoc, "Event listener key needs to be of type String");
723                     String JavaDoc listenerType = (String JavaDoc) entry.getKey();
724                     Object JavaDoc listenerObject = entry.getValue();
725                     if (listenerObject instanceof Collection JavaDoc) {
726                         Collection JavaDoc listeners = (Collection JavaDoc) listenerObject;
727                         EventListeners listenerRegistry = config.getEventListeners();
728                         Object JavaDoc[] listenerArray =
729                                 (Object JavaDoc[]) Array.newInstance(listenerRegistry.getListenerClassFor(listenerType), listeners.size());
730                         listenerArray = listeners.toArray(listenerArray);
731                         config.setListeners(listenerType, listenerArray);
732                     }
733                     else {
734                         config.setListener(listenerType, listenerObject);
735                     }
736                 }
737             }
738
739             // Perform custom post-processing in subclasses.
740
postProcessConfiguration(config);
741
742             // Build SessionFactory instance.
743
logger.info("Building new Hibernate SessionFactory");
744             this.configuration = config;
745             return newSessionFactory(config);
746         }
747
748         finally {
749             if (this.dataSource != null) {
750                 // Reset DataSource holder.
751
configTimeDataSourceHolder.set(null);
752             }
753
754             if (this.jtaTransactionManager != null) {
755                 // Reset TransactionManager holder.
756
configTimeTransactionManagerHolder.set(null);
757             }
758
759             if (this.lobHandler != null) {
760                 // Reset LobHandler holder.
761
configTimeLobHandlerHolder.set(null);
762             }
763         }
764     }
765
766     /**
767      * Subclasses can override this method to perform custom initialization
768      * of the Configuration instance used for SessionFactory creation.
769      * The properties of this LocalSessionFactoryBean will be applied to
770      * the Configuration object that gets returned here.
771      * <p>The default implementation creates a new Configuration instance.
772      * A custom implementation could prepare the instance in a specific way,
773      * or use a custom Configuration subclass.
774      * @return the Configuration instance
775      * @throws HibernateException in case of Hibernate initialization errors
776      * @see org.hibernate.cfg.Configuration#Configuration()
777      */

778     protected Configuration newConfiguration() throws HibernateException {
779         return (Configuration) BeanUtils.instantiateClass(this.configurationClass);
780     }
781
782     /**
783      * To be implemented by subclasses that want to to perform custom
784      * post-processing of the Configuration object after this FactoryBean
785      * performed its default initialization.
786      * @param config the current Configuration object
787      * @throws HibernateException in case of Hibernate initialization errors
788      */

789     protected void postProcessConfiguration(Configuration config) throws HibernateException {
790     }
791
792     /**
793      * Subclasses can override this method to perform custom initialization
794      * of the SessionFactory instance, creating it via the given Configuration
795      * object that got prepared by this LocalSessionFactoryBean.
796      * <p>The default implementation invokes Configuration's buildSessionFactory.
797      * A custom implementation could prepare the instance in a specific way,
798      * or use a custom SessionFactoryImpl subclass.
799      * @param config Configuration prepared by this LocalSessionFactoryBean
800      * @return the SessionFactory instance
801      * @throws HibernateException in case of Hibernate initialization errors
802      * @see org.hibernate.cfg.Configuration#buildSessionFactory
803      */

804     protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
805         return config.buildSessionFactory();
806     }
807
808     /**
809      * Return the Configuration object used to build the SessionFactory.
810      * Allows access to configuration metadata stored there (rarely needed).
811      * @throws IllegalStateException if the Configuration object has not been initialized yet
812      */

813     public final Configuration getConfiguration() {
814         if (this.configuration == null) {
815             throw new IllegalStateException JavaDoc("Configuration not initialized yet");
816         }
817         return this.configuration;
818     }
819
820     /**
821      * Executes schema update if requested.
822      * @see #setSchemaUpdate
823      * @see #updateDatabaseSchema()
824      */

825     protected void afterSessionFactoryCreation() throws Exception JavaDoc {
826         if (this.schemaUpdate) {
827             if (this.dataSource != null) {
828                 // Make given DataSource available for the schema update,
829
// which unfortunately reinstantiates a ConnectionProvider.
830
configTimeDataSourceHolder.set(this.dataSource);
831             }
832             try {
833                 updateDatabaseSchema();
834             }
835             finally {
836                 if (this.dataSource != null) {
837                     // Reset DataSource holder.
838
configTimeDataSourceHolder.set(null);
839                 }
840             }
841         }
842     }
843
844     /**
845      * Allows for schema export on shutdown.
846      */

847     public void destroy() throws HibernateException {
848         if (this.dataSource != null) {
849             // Make given DataSource available for potential SchemaExport,
850
// which unfortunately reinstantiates a ConnectionProvider.
851
configTimeDataSourceHolder.set(this.dataSource);
852         }
853         try {
854             super.destroy();
855         }
856         finally {
857             if (this.dataSource != null) {
858                 // Reset DataSource holder.
859
configTimeDataSourceHolder.set(null);
860             }
861         }
862     }
863
864
865     /**
866      * Execute schema drop script, determined by the Configuration object
867      * used for creating the SessionFactory. A replacement for Hibernate's
868      * SchemaExport class, to be invoked on application setup.
869      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
870      * SessionFactory to be able to invoke this method, e.g. via
871      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
872      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
873      * connection to perform the script.
874      * @throws org.springframework.dao.DataAccessException in case of script execution errors
875      * @see org.hibernate.cfg.Configuration#generateDropSchemaScript
876      * @see org.hibernate.tool.hbm2ddl.SchemaExport#drop
877      */

878     public void dropDatabaseSchema() throws DataAccessException {
879         logger.info("Dropping database schema for Hibernate SessionFactory");
880         HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
881         hibernateTemplate.execute(
882             new HibernateCallback() {
883                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
884                     Connection JavaDoc con = session.connection();
885                     Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
886                     String JavaDoc[] sql = getConfiguration().generateDropSchemaScript(dialect);
887                     executeSchemaScript(con, sql);
888                     return null;
889                 }
890             }
891         );
892     }
893
894     /**
895      * Execute schema creation script, determined by the Configuration object
896      * used for creating the SessionFactory. A replacement for Hibernate's
897      * SchemaExport class, to be invoked on application setup.
898      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
899      * SessionFactory to be able to invoke this method, e.g. via
900      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
901      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
902      * connection to perform the script.
903      * @throws DataAccessException in case of script execution errors
904      * @see org.hibernate.cfg.Configuration#generateSchemaCreationScript
905      * @see org.hibernate.tool.hbm2ddl.SchemaExport#create
906      */

907     public void createDatabaseSchema() throws DataAccessException {
908         logger.info("Creating database schema for Hibernate SessionFactory");
909         HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
910         hibernateTemplate.execute(
911             new HibernateCallback() {
912                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
913                     Connection JavaDoc con = session.connection();
914                     Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
915                     String JavaDoc[] sql = getConfiguration().generateSchemaCreationScript(dialect);
916                     executeSchemaScript(con, sql);
917                     return null;
918                 }
919             }
920         );
921     }
922
923     /**
924      * Execute schema update script, determined by the Configuration object
925      * used for creating the SessionFactory. A replacement for Hibernate's
926      * SchemaUpdate class, for automatically executing schema update scripts
927      * on application startup. Can also be invoked manually.
928      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
929      * SessionFactory to be able to invoke this method, e.g. via
930      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
931      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
932      * connection to perform the script.
933      * @throws DataAccessException in case of script execution errors
934      * @see #setSchemaUpdate
935      * @see org.hibernate.cfg.Configuration#generateSchemaUpdateScript
936      * @see org.hibernate.tool.hbm2ddl.SchemaUpdate
937      */

938     public void updateDatabaseSchema() throws DataAccessException {
939         logger.info("Updating database schema for Hibernate SessionFactory");
940         HibernateTemplate hibernateTemplate = new HibernateTemplate(getSessionFactory());
941         hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
942         hibernateTemplate.execute(
943             new HibernateCallback() {
944                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
945                     Connection JavaDoc con = session.connection();
946                     Dialect dialect = Dialect.getDialect(getConfiguration().getProperties());
947                     DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
948                     String JavaDoc[] sql = getConfiguration().generateSchemaUpdateScript(dialect, metadata);
949                     executeSchemaScript(con, sql);
950                     return null;
951                 }
952             }
953         );
954     }
955
956     /**
957      * Execute the given schema script on the given JDBC Connection.
958      * <p>Note that the default implementation will log unsuccessful statements
959      * and continue to execute. Override the <code>executeSchemaStatement</code>
960      * method to treat failures differently.
961      * @param con the JDBC Connection to execute the script on
962      * @param sql the SQL statements to execute
963      * @throws SQLException if thrown by JDBC methods
964      * @see #executeSchemaStatement
965      */

966     protected void executeSchemaScript(Connection JavaDoc con, String JavaDoc[] sql) throws SQLException JavaDoc {
967         if (sql != null && sql.length > 0) {
968             boolean oldAutoCommit = con.getAutoCommit();
969             if (!oldAutoCommit) {
970                 con.setAutoCommit(true);
971             }
972             try {
973                 Statement JavaDoc stmt = con.createStatement();
974                 try {
975                     for (int i = 0; i < sql.length; i++) {
976                         executeSchemaStatement(stmt, sql[i]);
977                     }
978                 }
979                 finally {
980                     JdbcUtils.closeStatement(stmt);
981                 }
982             }
983             finally {
984                 if (!oldAutoCommit) {
985                     con.setAutoCommit(false);
986                 }
987             }
988         }
989     }
990
991     /**
992      * Execute the given schema SQL on the given JDBC Statement.
993      * <p>Note that the default implementation will log unsuccessful statements
994      * and continue to execute. Override this method to treat failures differently.
995      * @param stmt the JDBC Statement to execute the SQL on
996      * @param sql the SQL statement to execute
997      * @throws SQLException if thrown by JDBC methods (and considered fatal)
998      */

999     protected void executeSchemaStatement(Statement JavaDoc stmt, String JavaDoc sql) throws SQLException JavaDoc {
1000        if (logger.isDebugEnabled()) {
1001            logger.debug("Executing schema statement: " + sql);
1002        }
1003        try {
1004            stmt.executeUpdate(sql);
1005        }
1006        catch (SQLException JavaDoc ex) {
1007            if (logger.isWarnEnabled()) {
1008                logger.warn("Unsuccessful schema statement: " + sql, ex);
1009            }
1010        }
1011    }
1012
1013}
1014
Popular Tags