KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > orm > hibernate > 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.hibernate;
18
19 import java.io.File JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.sql.Connection JavaDoc;
22 import java.sql.SQLException JavaDoc;
23 import java.sql.Statement JavaDoc;
24 import java.util.Properties JavaDoc;
25
26 import javax.sql.DataSource JavaDoc;
27 import javax.transaction.TransactionManager JavaDoc;
28
29 import net.sf.hibernate.HibernateException;
30 import net.sf.hibernate.Interceptor;
31 import net.sf.hibernate.Session;
32 import net.sf.hibernate.SessionFactory;
33 import net.sf.hibernate.cfg.Configuration;
34 import net.sf.hibernate.cfg.Environment;
35 import net.sf.hibernate.cfg.NamingStrategy;
36 import net.sf.hibernate.dialect.Dialect;
37 import net.sf.hibernate.tool.hbm2ddl.DatabaseMetadata;
38 import org.apache.commons.logging.Log;
39 import org.apache.commons.logging.LogFactory;
40
41 import org.springframework.beans.factory.DisposableBean;
42 import org.springframework.beans.factory.FactoryBean;
43 import org.springframework.beans.factory.InitializingBean;
44 import org.springframework.core.io.ClassPathResource;
45 import org.springframework.core.io.Resource;
46 import org.springframework.dao.DataAccessException;
47 import org.springframework.jdbc.support.JdbcUtils;
48 import org.springframework.jdbc.support.lob.LobHandler;
49
50 /**
51  * {@link org.springframework.beans.factory.FactoryBean} that creates a
52  * Hibernate {@link net.sf.hibernate.SessionFactory}. This is the usual way to
53  * set up a shared Hibernate SessionFactory in a Spring application context;
54  * the SessionFactory can then be passed to Hibernate-based DAOs via
55  * dependency injection.
56  *
57  * <p>Configuration settings can either be read from a Hibernate XML file,
58  * specified as "configLocation", or completely via this class. A typical
59  * local configuration consists of one or more "mappingResources", various
60  * "hibernateProperties" (not strictly necessary), and a "dataSource" that the
61  * SessionFactory should use. The latter can also be specified via Hibernate
62  * properties, but "dataSource" supports any Spring-configured DataSource,
63  * instead of relying on Hibernate's own connection providers.
64  *
65  * <p>This SessionFactory handling strategy is appropriate for most types of
66  * applications, from Hibernate-only single database apps to ones that need
67  * distributed transactions. Either {@link HibernateTransactionManager} or
68  * {@link org.springframework.transaction.jta.JtaTransactionManager} can be
69  * used for transaction demarcation, with the latter only necessary for
70  * transactions which span multiple databases.
71  *
72  * <p>Note: Spring's Hibernate support in this package requires Hibernate 2.1.
73  * Dedicated Hibernate3 support can be found in a separate package:
74  * <code>org.springframework.orm.hibernate3</code>.
75  *
76  * @author Juergen Hoeller
77  * @since 05.05.2003
78  * @see HibernateTemplate#setSessionFactory
79  * @see HibernateTransactionManager#setSessionFactory
80  */

81 public class LocalSessionFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
82
83     private static final ThreadLocal JavaDoc configTimeDataSourceHolder = new ThreadLocal JavaDoc();
84
85     private static final ThreadLocal JavaDoc configTimeTransactionManagerHolder = new ThreadLocal JavaDoc();
86
87     private static final ThreadLocal JavaDoc configTimeLobHandlerHolder = new ThreadLocal JavaDoc();
88
89     /**
90      * Return the DataSource for the currently configured Hibernate SessionFactory,
91      * to be used by LocalDataSourceConnectionProvoder.
92      * <p>This instance will be set before initialization of the corresponding
93      * SessionFactory, and reset immediately afterwards. It is thus only available
94      * during configuration.
95      * @see #setDataSource
96      * @see LocalDataSourceConnectionProvider
97      */

98     public static DataSource JavaDoc getConfigTimeDataSource() {
99         return (DataSource JavaDoc) configTimeDataSourceHolder.get();
100     }
101
102     /**
103      * Return the JTA TransactionManager for the currently configured Hibernate
104      * SessionFactory, to be used by LocalTransactionManagerLookup.
105      * <p>This instance will be set before initialization of the corresponding
106      * SessionFactory, and reset immediately afterwards. It is thus only available
107      * during configuration.
108      * @see #setJtaTransactionManager
109      * @see LocalTransactionManagerLookup
110      */

111     public static TransactionManager JavaDoc getConfigTimeTransactionManager() {
112         return (TransactionManager JavaDoc) configTimeTransactionManagerHolder.get();
113     }
114
115     /**
116      * Return the LobHandler for the currently configured Hibernate SessionFactory,
117      * to be used by UserType implementations like ClobStringType.
118      * <p>This instance will be set before initialization of the corresponding
119      * SessionFactory, and reset immediately afterwards. It is thus only available
120      * during configuration.
121      * @see #setLobHandler
122      * @see org.springframework.orm.hibernate.support.ClobStringType
123      * @see org.springframework.orm.hibernate.support.BlobByteArrayType
124      * @see org.springframework.orm.hibernate.support.BlobSerializableType
125      */

126     public static LobHandler getConfigTimeLobHandler() {
127         return (LobHandler) configTimeLobHandlerHolder.get();
128     }
129
130
131     protected final Log logger = LogFactory.getLog(getClass());
132
133     private Resource configLocation;
134
135     private Resource[] mappingLocations;
136
137     private Resource[] mappingJarLocations;
138
139     private Resource[] mappingDirectoryLocations;
140
141     private Properties JavaDoc hibernateProperties;
142
143     private DataSource JavaDoc dataSource;
144
145     private boolean useTransactionAwareDataSource = false;
146
147     private TransactionManager JavaDoc jtaTransactionManager;
148
149     private LobHandler lobHandler;
150
151     private Interceptor entityInterceptor;
152
153     private NamingStrategy namingStrategy;
154
155     private boolean schemaUpdate = false;
156
157     private Configuration configuration;
158
159     private SessionFactory sessionFactory;
160
161
162     /**
163      * Set the location of the Hibernate XML config file, for example as
164      * classpath resource "classpath:hibernate.cfg.xml".
165      * <p>Note: Can be omitted when all necessary properties and mapping
166      * resources are specified locally via this bean.
167      * @see net.sf.hibernate.cfg.Configuration#configure(java.net.URL)
168      */

169     public void setConfigLocation(Resource configLocation) {
170         this.configLocation = configLocation;
171     }
172
173     /**
174      * Set Hibernate mapping resources to be found in the class path,
175      * like "example.hbm.xml" or "mypackage/example.hbm.xml".
176      * Analogous to mapping entries in a Hibernate XML config file.
177      * Alternative to the more generic setMappingLocations method.
178      * <p>Can be used to add to mappings from a Hibernate XML config file,
179      * or to specify all mappings locally.
180      * @see #setMappingLocations
181      * @see net.sf.hibernate.cfg.Configuration#addResource
182      */

183     public void setMappingResources(String JavaDoc[] mappingResources) {
184         this.mappingLocations = new Resource[mappingResources.length];
185         for (int i = 0; i < mappingResources.length; i++) {
186             this.mappingLocations[i] = new ClassPathResource(mappingResources[i].trim());
187         }
188     }
189
190     /**
191      * Set locations of Hibernate mapping files, for example as classpath
192      * resource "classpath:example.hbm.xml". Supports any resource location
193      * via Spring's resource abstraction, for example relative paths like
194      * "WEB-INF/mappings/example.hbm.xml" when running in an application context.
195      * <p>Can be used to add to mappings from a Hibernate XML config file,
196      * or to specify all mappings locally.
197      * @see net.sf.hibernate.cfg.Configuration#addInputStream
198      */

199     public void setMappingLocations(Resource[] mappingLocations) {
200         this.mappingLocations = mappingLocations;
201     }
202
203     /**
204      * Set locations of jar files that contain Hibernate mapping resources,
205      * like "WEB-INF/lib/example.hbm.jar".
206      * <p>Can be used to add to mappings from a Hibernate XML config file,
207      * or to specify all mappings locally.
208      * @see net.sf.hibernate.cfg.Configuration#addJar(java.io.File)
209      */

210     public void setMappingJarLocations(Resource[] mappingJarLocations) {
211         this.mappingJarLocations = mappingJarLocations;
212     }
213
214     /**
215      * Set locations of directories that contain Hibernate mapping resources,
216      * like "WEB-INF/mappings".
217      * <p>Can be used to add to mappings from a Hibernate XML config file,
218      * or to specify all mappings locally.
219      * @see net.sf.hibernate.cfg.Configuration#addDirectory(java.io.File)
220      */

221     public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
222         this.mappingDirectoryLocations = mappingDirectoryLocations;
223     }
224
225     /**
226      * Set Hibernate properties, such as "hibernate.dialect".
227      * <p>Can be used to override values in a Hibernate XML config file,
228      * or to specify all necessary properties locally.
229      * <p>Note: Do not specify a transaction provider here when using
230      * Spring-driven transactions. It is also advisable to omit connection
231      * provider settings and use a Spring-set DataSource instead.
232      * @see #setDataSource
233      */

234     public void setHibernateProperties(Properties JavaDoc hibernateProperties) {
235         this.hibernateProperties = hibernateProperties;
236     }
237
238     /**
239      * Return the Hibernate properties, if any. Mainly available for
240      * configuration through property paths that specify individual keys.
241      */

242     public Properties JavaDoc getHibernateProperties() {
243         if (this.hibernateProperties == null) {
244             this.hibernateProperties = new Properties JavaDoc();
245         }
246         return this.hibernateProperties;
247     }
248
249     /**
250      * Set the DataSource to be used by the SessionFactory.
251      * If set, this will override corresponding settings in Hibernate properties.
252      * <p>Note: If this is set, the Hibernate settings should not define
253      * a connection provider to avoid meaningless double configuration.
254      * <p>If using HibernateTransactionManager as transaction strategy, consider
255      * proxying your target DataSource with a LazyConnectionDataSourceProxy.
256      * This defers fetching of an actual JDBC Connection until the first JDBC
257      * Statement gets executed, even within JDBC transactions (as performed by
258      * HibernateTransactionManager). Such lazy fetching is particularly beneficial
259      * for read-only operations, in particular if the chances of resolving the
260      * result in the second-level cache are high.
261      * <p>As JTA and transactional JNDI DataSources already provide lazy enlistment
262      * of JDBC Connections, LazyConnectionDataSourceProxy does not add value with
263      * JTA (i.e. Spring's JtaTransactionManager) as transaction strategy.
264      * @see #setUseTransactionAwareDataSource
265      * @see LocalDataSourceConnectionProvider
266      * @see HibernateTransactionManager
267      * @see org.springframework.transaction.jta.JtaTransactionManager
268      * @see org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy
269      */

270     public void setDataSource(DataSource JavaDoc dataSource) {
271         this.dataSource = dataSource;
272     }
273
274     /**
275      * Set whether to use a transaction-aware DataSource for the SessionFactory,
276      * i.e. whether to automatically wrap the passed-in DataSource with Spring's
277      * TransactionAwareDataSourceProxy.
278      * <p>Default is "false": LocalSessionFactoryBean is usually used with Spring's
279      * HibernateTransactionManager or JtaTransactionManager, both of which work nicely
280      * on a plain JDBC DataSource. Hibernate Sessions and their JDBC Connections are
281      * fully managed by the Hibernate/JTA transaction infrastructure in such a scenario.
282      * <p>If you switch this flag to "true", Spring's Hibernate access will be able to
283      * <i>participate in JDBC-based transactions managed outside of Hibernate</i>
284      * (for example, by Spring's DataSourceTransactionManager). This can be convenient
285      * if you need a different local transaction strategy for another O/R mapping tool,
286      * for example, but still want Hibernate access to join into those transactions.
287      * <p>A further benefit of this option is that <i>plain Sessions opened directly
288      * via the SessionFactory</i>, outside of Spring's Hibernate support, will still
289      * participate in active Spring-managed transactions.
290      * <p>As a further effect, using a transaction-aware DataSource will <i>apply
291      * remaining transaction timeouts to all created JDBC Statements</i>. This means
292      * that all operations performed by the SessionFactory will automatically
293      * participate in Spring-managed transaction timeouts, not just queries.
294      * This adds value even for HibernateTransactionManager.
295      * <p><b>WARNING: Be aware of side effects when using a transaction-aware
296      * DataSource in combination with OpenSessionInViewFilter/Interceptor.</b>
297      * This combination is only properly supported with HibernateTransactionManager
298      * transactions. PROPAGATION_SUPPORTS with HibernateTransactionManager and
299      * JtaTransactionManager in general are only supported on Hibernate3, which
300      * introduces (optional) aggressive release of Connections.
301      * @see #setDataSource
302      * @see org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
303      * @see org.springframework.jdbc.datasource.DataSourceTransactionManager
304      * @see org.springframework.orm.hibernate.support.OpenSessionInViewFilter
305      * @see org.springframework.orm.hibernate.support.OpenSessionInViewInterceptor
306      * @see HibernateTransactionManager
307      * @see org.springframework.transaction.jta.JtaTransactionManager
308      * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setUseTransactionAwareDataSource
309      */

310     public void setUseTransactionAwareDataSource(boolean useTransactionAwareDataSource) {
311         this.useTransactionAwareDataSource = useTransactionAwareDataSource;
312     }
313
314     /**
315      * Set the JTA TransactionManager to be used for Hibernate's
316      * TransactionManagerLookup. If set, this will override corresponding
317      * settings in Hibernate properties. Allows to use a Spring-managed
318      * JTA TransactionManager for Hibernate's cache synchronization.
319      * <p>Note: If this is set, the Hibernate settings should not define a
320      * transaction manager lookup to avoid meaningless double configuration.
321      * @see LocalTransactionManagerLookup
322      */

323     public void setJtaTransactionManager(TransactionManager JavaDoc jtaTransactionManager) {
324         this.jtaTransactionManager = jtaTransactionManager;
325     }
326
327     /**
328      * Set the LobHandler to be used by the SessionFactory.
329      * Will be exposed at config time for UserType implementations.
330      * @see #getConfigTimeLobHandler
331      * @see net.sf.hibernate.UserType
332      * @see org.springframework.orm.hibernate.support.ClobStringType
333      * @see org.springframework.orm.hibernate.support.BlobByteArrayType
334      * @see org.springframework.orm.hibernate.support.BlobSerializableType
335      */

336     public void setLobHandler(LobHandler lobHandler) {
337         this.lobHandler = lobHandler;
338     }
339
340     /**
341      * Set a Hibernate entity interceptor that allows to inspect and change
342      * property values before writing to and reading from the database.
343      * Will get applied to any new Session created by this factory.
344      * <p>Such an interceptor can either be set at the SessionFactory level, i.e. on
345      * LocalSessionFactoryBean, or at the Session level, i.e. on HibernateTemplate,
346      * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set
347      * it on LocalSessionFactoryBean or HibernateTransactionManager to avoid repeated
348      * configuration and guarantee consistent behavior in transactions.
349      * @see HibernateTemplate#setEntityInterceptor
350      * @see HibernateInterceptor#setEntityInterceptor
351      * @see HibernateTransactionManager#setEntityInterceptor
352      * @see net.sf.hibernate.cfg.Configuration#setInterceptor
353      */

354     public void setEntityInterceptor(Interceptor entityInterceptor) {
355         this.entityInterceptor = entityInterceptor;
356     }
357
358     /**
359      * Set a Hibernate NamingStrategy for the SessionFactory, determining the
360      * physical column and table names given the info in the mapping document.
361      * @see net.sf.hibernate.cfg.Configuration#setNamingStrategy
362      */

363     public void setNamingStrategy(NamingStrategy namingStrategy) {
364         this.namingStrategy = namingStrategy;
365     }
366
367     /**
368      * Set whether to execute a schema update after SessionFactory initialization.
369      * <p>For details on how to make schema update scripts work, see the Hibernate
370      * documentation, as this class leverages the same schema update script support
371      * in net.sf.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
372      * @see net.sf.hibernate.cfg.Configuration#generateSchemaUpdateScript
373      * @see net.sf.hibernate.tool.hbm2ddl.SchemaUpdate
374      */

375     public void setSchemaUpdate(boolean schemaUpdate) {
376         this.schemaUpdate = schemaUpdate;
377     }
378
379
380     /**
381      * Initialize the SessionFactory for the given or the default location.
382      * @throws IllegalArgumentException in case of illegal property values
383      * @throws HibernateException in case of Hibernate initialization errors
384      */

385     public void afterPropertiesSet() throws IllegalArgumentException JavaDoc, HibernateException, IOException JavaDoc {
386         // Create Configuration instance.
387
Configuration config = newConfiguration();
388
389         if (this.dataSource != null) {
390             // Make given DataSource available for SessionFactory configuration.
391
configTimeDataSourceHolder.set(this.dataSource);
392         }
393
394         if (this.jtaTransactionManager != null) {
395             // Make Spring-provided JTA TransactionManager available.
396
configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
397         }
398
399         if (this.lobHandler != null) {
400             // Make given LobHandler available for SessionFactory configuration.
401
// Do early because because mapping resource might refer to custom types.
402
configTimeLobHandlerHolder.set(this.lobHandler);
403         }
404
405         try {
406
407             if (this.entityInterceptor != null) {
408                 // Set given entity interceptor at SessionFactory level.
409
config.setInterceptor(this.entityInterceptor);
410             }
411
412             if (this.namingStrategy != null) {
413                 // Pass given naming strategy to Hibernate Configuration.
414
config.setNamingStrategy(this.namingStrategy);
415             }
416
417             if (this.configLocation != null) {
418                 // Load Hibernate configuration from given location.
419
config.configure(this.configLocation.getURL());
420             }
421
422             if (this.hibernateProperties != null) {
423                 // Add given Hibernate properties to Configuration.
424
config.addProperties(this.hibernateProperties);
425             }
426
427             if (this.dataSource != null) {
428                 // Set Spring-provided DataSource as Hibernate property.
429
config.setProperty(Environment.CONNECTION_PROVIDER,
430                         this.useTransactionAwareDataSource ?
431                         TransactionAwareDataSourceConnectionProvider.class.getName() :
432                         LocalDataSourceConnectionProvider.class.getName());
433             }
434
435             if (this.jtaTransactionManager != null) {
436                 // Set Spring-provided JTA TransactionManager as Hibernate property.
437
config.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
438             }
439
440             if (this.mappingLocations != null) {
441                 // Register given Hibernate mapping definitions, contained in resource files.
442
for (int i = 0; i < this.mappingLocations.length; i++) {
443                     config.addInputStream(this.mappingLocations[i].getInputStream());
444                 }
445             }
446
447             if (this.mappingJarLocations != null) {
448                 // Register given Hibernate mapping definitions, contained in jar files.
449
for (int i = 0; i < this.mappingJarLocations.length; i++) {
450                     Resource resource = this.mappingJarLocations[i];
451                     config.addJar(resource.getFile());
452                 }
453             }
454
455             if (this.mappingDirectoryLocations != null) {
456                 // Register all Hibernate mapping definitions in the given directories.
457
for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
458                     File JavaDoc file = this.mappingDirectoryLocations[i].getFile();
459                     if (!file.isDirectory()) {
460                         throw new IllegalArgumentException JavaDoc(
461                                 "Mapping directory location [" + this.mappingDirectoryLocations[i] +
462                                 "] does not denote a directory");
463                     }
464                     config.addDirectory(file);
465                 }
466             }
467
468             // Perform custom post-processing in subclasses.
469
postProcessConfiguration(config);
470
471             // Build SessionFactory instance.
472
logger.info("Building new Hibernate SessionFactory");
473             this.configuration = config;
474             this.sessionFactory = newSessionFactory(config);
475         }
476
477         finally {
478             if (this.dataSource != null) {
479                 // Reset DataSource holder.
480
configTimeDataSourceHolder.set(null);
481             }
482
483             if (this.jtaTransactionManager != null) {
484                 // Reset TransactionManager holder.
485
configTimeTransactionManagerHolder.set(null);
486             }
487
488             if (this.lobHandler != null) {
489                 // Reset LobHandler holder.
490
configTimeLobHandlerHolder.set(null);
491             }
492         }
493
494         // Execute schema update if requested.
495
if (this.schemaUpdate) {
496             updateDatabaseSchema();
497         }
498     }
499     
500
501     /**
502      * Subclasses can override this method to perform custom initialization
503      * of the Configuration instance used for SessionFactory creation.
504      * The properties of this LocalSessionFactoryBean will be applied to
505      * the Configuration object that gets returned here.
506      * <p>The default implementation creates a new Configuration instance.
507      * A custom implementation could prepare the instance in a specific way,
508      * or use a custom Configuration subclass.
509      * @return the Configuration instance
510      * @throws HibernateException in case of Hibernate initialization errors
511      * @see net.sf.hibernate.cfg.Configuration#Configuration()
512      */

513     protected Configuration newConfiguration() throws HibernateException {
514         return new Configuration();
515     }
516
517     /**
518      * To be implemented by subclasses that want to to perform custom
519      * post-processing of the Configuration object after this FactoryBean
520      * performed its default initialization.
521      * @param config the current Configuration object
522      * @throws HibernateException in case of Hibernate initialization errors
523      */

524     protected void postProcessConfiguration(Configuration config) throws HibernateException {
525     }
526
527     /**
528      * Subclasses can override this method to perform custom initialization
529      * of the SessionFactory instance, creating it via the given Configuration
530      * object that got prepared by this LocalSessionFactoryBean.
531      * <p>The default implementation invokes Configuration's buildSessionFactory.
532      * A custom implementation could prepare the instance in a specific way,
533      * or use a custom SessionFactoryImpl subclass.
534      * @param config Configuration prepared by this LocalSessionFactoryBean
535      * @return the SessionFactory instance
536      * @throws HibernateException in case of Hibernate initialization errors
537      * @see net.sf.hibernate.cfg.Configuration#buildSessionFactory
538      */

539     protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
540         return config.buildSessionFactory();
541     }
542
543
544     /**
545      * Execute schema drop script, determined by the Configuration object
546      * used for creating the SessionFactory. A replacement for Hibernate's
547      * SchemaExport class, to be invoked on application setup.
548      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
549      * SessionFactory to be able to invoke this method, e.g. via
550      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
551      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
552      * connection to perform the script.
553      * @throws DataAccessException in case of script execution errors
554      * @see net.sf.hibernate.cfg.Configuration#generateDropSchemaScript
555      * @see net.sf.hibernate.tool.hbm2ddl.SchemaExport#drop
556      */

557     public void dropDatabaseSchema() throws DataAccessException {
558         logger.info("Dropping database schema for Hibernate SessionFactory");
559         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
560         hibernateTemplate.execute(
561             new HibernateCallback() {
562                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
563                     Connection JavaDoc con = session.connection();
564                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
565                     String JavaDoc[] sql = configuration.generateDropSchemaScript(dialect);
566                     executeSchemaScript(con, sql);
567                     return null;
568                 }
569             }
570         );
571     }
572
573     /**
574      * Execute schema creation script, determined by the Configuration object
575      * used for creating the SessionFactory. A replacement for Hibernate's
576      * SchemaExport class, to be invoked on application setup.
577      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
578      * SessionFactory to be able to invoke this method, e.g. via
579      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
580      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
581      * connection to perform the script.
582      * @throws DataAccessException in case of script execution errors
583      * @see net.sf.hibernate.cfg.Configuration#generateSchemaCreationScript
584      * @see net.sf.hibernate.tool.hbm2ddl.SchemaExport#create
585      */

586     public void createDatabaseSchema() throws DataAccessException {
587         logger.info("Creating database schema for Hibernate SessionFactory");
588         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
589         hibernateTemplate.execute(
590             new HibernateCallback() {
591                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
592                     Connection JavaDoc con = session.connection();
593                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
594                     String JavaDoc[] sql = configuration.generateSchemaCreationScript(dialect);
595                     executeSchemaScript(con, sql);
596                     return null;
597                 }
598             }
599         );
600     }
601
602     /**
603      * Execute schema update script, determined by the Configuration object
604      * used for creating the SessionFactory. A replacement for Hibernate's
605      * SchemaUpdate class, for automatically executing schema update scripts
606      * on application startup. Can also be invoked manually.
607      * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
608      * SessionFactory to be able to invoke this method, e.g. via
609      * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
610      * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
611      * connection to perform the script.
612      * @throws DataAccessException in case of script execution errors
613      * @see #setSchemaUpdate
614      * @see net.sf.hibernate.cfg.Configuration#generateSchemaUpdateScript
615      * @see net.sf.hibernate.tool.hbm2ddl.SchemaUpdate
616      */

617     public void updateDatabaseSchema() throws DataAccessException {
618         logger.info("Updating database schema for Hibernate SessionFactory");
619         HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
620         hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
621         hibernateTemplate.execute(
622             new HibernateCallback() {
623                 public Object JavaDoc doInHibernate(Session session) throws HibernateException, SQLException JavaDoc {
624                     Connection JavaDoc con = session.connection();
625                     Dialect dialect = Dialect.getDialect(configuration.getProperties());
626                     DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
627                     String JavaDoc[] sql = configuration.generateSchemaUpdateScript(dialect, metadata);
628                     executeSchemaScript(con, sql);
629                     return null;
630                 }
631             }
632         );
633     }
634
635     /**
636      * Execute the given schema script on the given JDBC Connection.
637      * <p>Note that the default implementation will log unsuccessful statements
638      * and continue to execute. Override the <code>executeSchemaStatement</code>
639      * method to treat failures differently.
640      * @param con the JDBC Connection to execute the script on
641      * @param sql the SQL statements to execute
642      * @throws SQLException if thrown by JDBC methods
643      * @see #executeSchemaStatement
644      */

645     protected void executeSchemaScript(Connection JavaDoc con, String JavaDoc[] sql) throws SQLException JavaDoc {
646         if (sql != null && sql.length > 0) {
647             boolean oldAutoCommit = con.getAutoCommit();
648             if (!oldAutoCommit) {
649                 con.setAutoCommit(true);
650             }
651             try {
652                 Statement JavaDoc stmt = con.createStatement();
653                 try {
654                     for (int i = 0; i < sql.length; i++) {
655                         executeSchemaStatement(stmt, sql[i]);
656                     }
657                 }
658                 finally {
659                     JdbcUtils.closeStatement(stmt);
660                 }
661             }
662             finally {
663                 if (!oldAutoCommit) {
664                     con.setAutoCommit(false);
665                 }
666             }
667         }
668     }
669
670     /**
671      * Execute the given schema SQL on the given JDBC Statement.
672      * <p>Note that the default implementation will log unsuccessful statements
673      * and continue to execute. Override this method to treat failures differently.
674      * @param stmt the JDBC Statement to execute the SQL on
675      * @param sql the SQL statement to execute
676      * @throws SQLException if thrown by JDBC methods (and considered fatal)
677      */

678     protected void executeSchemaStatement(Statement JavaDoc stmt, String JavaDoc sql) throws SQLException JavaDoc {
679         if (logger.isDebugEnabled()) {
680             logger.debug("Executing schema statement: " + sql);
681         }
682         try {
683             stmt.executeUpdate(sql);
684         }
685         catch (SQLException JavaDoc ex) {
686             if (logger.isWarnEnabled()) {
687                 logger.warn("Unsuccessful schema statement: " + sql, ex);
688             }
689         }
690     }
691
692
693     /**
694      * Return the Configuration object used to build the SessionFactory.
695      * Allows access to configuration metadata stored there (rarely needed).
696      */

697     public Configuration getConfiguration() {
698         return configuration;
699     }
700
701
702     /**
703      * Return the singleton SessionFactory.
704      */

705     public Object JavaDoc getObject() {
706         return this.sessionFactory;
707     }
708
709     public Class JavaDoc getObjectType() {
710         return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
711     }
712
713     public boolean isSingleton() {
714         return true;
715     }
716
717
718     /**
719      * Close the SessionFactory on bean factory shutdown.
720      */

721     public void destroy() throws HibernateException {
722         logger.info("Closing Hibernate SessionFactory");
723         if (this.dataSource != null) {
724             // Make given DataSource available for potential SchemaExport,
725
// which unfortunately reinstantiates a ConnectionProvider.
726
configTimeDataSourceHolder.set(this.dataSource);
727         }
728         try {
729             this.sessionFactory.close();
730         }
731         finally {
732             if (this.dataSource != null) {
733                 // Reset DataSource holder.
734
configTimeDataSourceHolder.set(null);
735             }
736         }
737     }
738
739 }
740
Popular Tags