1. /*
  2. * Copyright 2002-2004 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. package org.springframework.orm.hibernate;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.sql.Connection;
  20. import java.sql.SQLException;
  21. import java.sql.Statement;
  22. import java.util.Properties;
  23. import javax.sql.DataSource;
  24. import javax.transaction.TransactionManager;
  25. import net.sf.hibernate.HibernateException;
  26. import net.sf.hibernate.Interceptor;
  27. import net.sf.hibernate.Session;
  28. import net.sf.hibernate.SessionFactory;
  29. import net.sf.hibernate.cfg.Configuration;
  30. import net.sf.hibernate.cfg.Environment;
  31. import net.sf.hibernate.cfg.NamingStrategy;
  32. import net.sf.hibernate.dialect.Dialect;
  33. import net.sf.hibernate.tool.hbm2ddl.DatabaseMetadata;
  34. import org.apache.commons.logging.Log;
  35. import org.apache.commons.logging.LogFactory;
  36. import org.springframework.beans.factory.DisposableBean;
  37. import org.springframework.beans.factory.FactoryBean;
  38. import org.springframework.beans.factory.InitializingBean;
  39. import org.springframework.core.io.ClassPathResource;
  40. import org.springframework.core.io.Resource;
  41. import org.springframework.dao.DataAccessException;
  42. import org.springframework.jdbc.support.JdbcUtils;
  43. import org.springframework.jdbc.support.lob.LobHandler;
  44. /**
  45. * FactoryBean that creates a local Hibernate SessionFactory instance.
  46. * Behaves like a SessionFactory instance when used as bean reference, e.g.
  47. * for HibernateTemplate's "sessionFactory" property. Note that switching
  48. * to JndiObjectFactoryBean is just a matter of configuration!
  49. *
  50. * <p>The typical usage will be to register this as singleton factory
  51. * (for a certain underlying JDBC DataSource) in an application context,
  52. * and give bean references to application services that need it.
  53. *
  54. * <p>Configuration settings can either be read from a Hibernate XML file,
  55. * specified as "configLocation", or completely via this class. A typical
  56. * local configuration consists of one or more "mappingResources", various
  57. * "hibernateProperties" (not strictly necessary), and a "dataSource" that the
  58. * SessionFactory should use. The latter can also be specified via Hibernate
  59. * properties, but "dataSource" supports any Spring-configured DataSource,
  60. * instead of relying on Hibernate's own connection providers.
  61. *
  62. * <p>This SessionFactory handling strategy is appropriate for most types of
  63. * applications, from Hibernate-only single database apps to ones that need
  64. * distributed transactions. Either HibernateTransactionManager or
  65. * JtaTransactionManager can be used for transaction demarcation, the latter
  66. * only being necessary for transactions that span multiple databases.
  67. *
  68. * <p>Registering a SessionFactory with JNDI is only advisable when using
  69. * Hibernate's JCA Connector, i.e. when the application server cares for
  70. * initialization. Else, portability is rather limited: Manual JNDI binding
  71. * isn't supported by some application servers (e.g. Tomcat). Unfortunately,
  72. * JCA has drawbacks too: Its setup is container-specific and can be tedious.
  73. *
  74. * <p>Note that the JCA Connector's sole major strength is its seamless
  75. * cooperation with EJB containers and JTA services. If you do not use EJB
  76. * and initiate your JTA transactions via Spring's JtaTransactionManager,
  77. * you can get all benefits including distributed transactions and proper
  78. * transactional JVM-level caching with local SessionFactory setup too -
  79. * without any configuration hassle like container-specific setup.
  80. *
  81. * <p>Note: Spring's Hibernate support requires Hibernate 2.1 (as of Spring 1.0).
  82. *
  83. * @author Juergen Hoeller
  84. * @since 05.05.2003
  85. * @see HibernateTemplate#setSessionFactory
  86. * @see HibernateTransactionManager#setSessionFactory
  87. * @see org.springframework.jndi.JndiObjectFactoryBean
  88. */
  89. public class LocalSessionFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
  90. private static ThreadLocal configTimeLobHandlerHolder = new ThreadLocal();
  91. /**
  92. * Return the LobHandler for the currently configured Hibernate SessionFactory,
  93. * to be used by Type implementations like ClobStringType.
  94. * <p>This instance will be set before initialization of the corresponding
  95. * SessionFactory, and reset immediately afterwards. It is thus only available
  96. * in constructors of UserType implementations.
  97. * @see #setLobHandler
  98. * @see org.springframework.orm.hibernate.support.ClobStringType
  99. * @see net.sf.hibernate.type.Type
  100. */
  101. public static LobHandler getConfigTimeLobHandler() {
  102. return (LobHandler) configTimeLobHandlerHolder.get();
  103. }
  104. protected final Log logger = LogFactory.getLog(getClass());
  105. private Resource configLocation;
  106. private Resource[] mappingLocations;
  107. private Resource[] mappingJarLocations;
  108. private Resource[] mappingDirectoryLocations;
  109. private Properties hibernateProperties;
  110. private DataSource dataSource;
  111. private TransactionManager jtaTransactionManager;
  112. private LobHandler lobHandler;
  113. private Interceptor entityInterceptor;
  114. private NamingStrategy namingStrategy;
  115. private boolean schemaUpdate = false;
  116. private Configuration configuration;
  117. private SessionFactory sessionFactory;
  118. /**
  119. * Set the location of the Hibernate XML config file, for example as
  120. * classpath resource "classpath:hibernate.cfg.xml".
  121. * <p>Note: Can be omitted when all necessary properties and mapping
  122. * resources are specified locally via this bean.
  123. * @see net.sf.hibernate.cfg.Configuration#configure(java.net.URL)
  124. */
  125. public void setConfigLocation(Resource configLocation) {
  126. this.configLocation = configLocation;
  127. }
  128. /**
  129. * Set Hibernate mapping resources to be found in the class path,
  130. * like "example.hbm.xml" or "mypackage/example.hbm.xml".
  131. * Analogous to mapping entries in a Hibernate XML config file.
  132. * Alternative to the more generic setMappingLocations method.
  133. * <p>Can be used to add to mappings from a Hibernate XML config file,
  134. * or to specify all mappings locally.
  135. * @see #setMappingLocations
  136. * @see net.sf.hibernate.cfg.Configuration#addResource
  137. */
  138. public void setMappingResources(String[] mappingResources) {
  139. this.mappingLocations = new Resource[mappingResources.length];
  140. for (int i = 0; i < mappingResources.length; i++) {
  141. this.mappingLocations[i] = new ClassPathResource(mappingResources[i]);
  142. }
  143. }
  144. /**
  145. * Set locations of Hibernate mapping files, for example as classpath
  146. * resource "classpath:example.hbm.xml". Supports any resource location
  147. * via Spring's resource abstraction, for example relative paths like
  148. * "WEB-INF/mappings/example.hbm.xml" when running in an application context.
  149. * <p>Can be used to add to mappings from a Hibernate XML config file,
  150. * or to specify all mappings locally.
  151. * @see net.sf.hibernate.cfg.Configuration#addInputStream
  152. */
  153. public void setMappingLocations(Resource[] mappingLocations) {
  154. this.mappingLocations = mappingLocations;
  155. }
  156. /**
  157. * Set locations of jar files that contain Hibernate mapping resources,
  158. * like "WEB-INF/lib/example.hbm.jar".
  159. * <p>Can be used to add to mappings from a Hibernate XML config file,
  160. * or to specify all mappings locally.
  161. * @see net.sf.hibernate.cfg.Configuration#addJar(java.io.File)
  162. */
  163. public void setMappingJarLocations(Resource[] mappingJarLocations) {
  164. this.mappingJarLocations = mappingJarLocations;
  165. }
  166. /**
  167. * Set locations of directories that contain Hibernate mapping resources,
  168. * like "WEB-INF/mappings".
  169. * <p>Can be used to add to mappings from a Hibernate XML config file,
  170. * or to specify all mappings locally.
  171. * @see net.sf.hibernate.cfg.Configuration#addDirectory(java.io.File)
  172. */
  173. public void setMappingDirectoryLocations(Resource[] mappingDirectoryLocations) {
  174. this.mappingDirectoryLocations = mappingDirectoryLocations;
  175. }
  176. /**
  177. * Set Hibernate properties, like "hibernate.dialect".
  178. * <p>Can be used to override values in a Hibernate XML config file,
  179. * or to specify all necessary properties locally.
  180. * <p>Note: Do not specify a transaction provider here when using
  181. * Spring-driven transactions. It is also advisable to omit connection
  182. * provider settings and use a Spring-set DataSource instead.
  183. * @see #setDataSource
  184. */
  185. public void setHibernateProperties(Properties hibernateProperties) {
  186. this.hibernateProperties = hibernateProperties;
  187. }
  188. /**
  189. * Set the DataSource to be used by the SessionFactory.
  190. * If set, this will override corresponding settings in Hibernate properties.
  191. * <p>Note: If this is set, the Hibernate settings should not define
  192. * a connection provider to avoid meaningless double configuration.
  193. * @see LocalDataSourceConnectionProvider
  194. */
  195. public void setDataSource(DataSource dataSource) {
  196. this.dataSource = dataSource;
  197. }
  198. /**
  199. * Set the JTA TransactionManager to be used for Hibernate's
  200. * TransactionManagerLookup. If set, this will override corresponding
  201. * settings in Hibernate properties. Allows to use a Spring-managed
  202. * JTA TransactionManager for Hibernate's cache synchronization.
  203. * <p>Note: If this is set, the Hibernate settings should not define a
  204. * transaction manager lookup to avoid meaningless double configuration.
  205. * @see LocalTransactionManagerLookup
  206. */
  207. public void setJtaTransactionManager(TransactionManager jtaTransactionManager) {
  208. this.jtaTransactionManager = jtaTransactionManager;
  209. }
  210. /**
  211. * Set the LobHandler to be used by the SessionFactory.
  212. * Will be exposed at config time for Type implementations.
  213. * @see #getConfigTimeLobHandler
  214. * @see org.springframework.orm.hibernate.support.ClobStringType
  215. * @see net.sf.hibernate.type.Type
  216. */
  217. public void setLobHandler(LobHandler lobHandler) {
  218. this.lobHandler = lobHandler;
  219. }
  220. /**
  221. * Set a Hibernate entity interceptor that allows to inspect and change
  222. * property values before writing to and reading from the database.
  223. * Will get applied to any new Session created by this factory.
  224. * <p>Such an interceptor can either be set at the SessionFactory level, i.e. on
  225. * LocalSessionFactoryBean, or at the Session level, i.e. on HibernateTemplate,
  226. * HibernateInterceptor, and HibernateTransactionManager. It's preferable to set
  227. * it on LocalSessionFactoryBean or HibernateTransactionManager to avoid repeated
  228. * configuration and guarantee consistent behavior in transactions.
  229. * @see HibernateTemplate#setEntityInterceptor
  230. * @see HibernateInterceptor#setEntityInterceptor
  231. * @see HibernateTransactionManager#setEntityInterceptor
  232. * @see net.sf.hibernate.cfg.Configuration#setInterceptor
  233. */
  234. public void setEntityInterceptor(Interceptor entityInterceptor) {
  235. this.entityInterceptor = entityInterceptor;
  236. }
  237. /**
  238. * Set a Hibernate NamingStrategy for the SessionFactory, determining the
  239. * physical column and table names given the info in the mapping document.
  240. * @see net.sf.hibernate.cfg.Configuration#setNamingStrategy
  241. */
  242. public void setNamingStrategy(NamingStrategy namingStrategy) {
  243. this.namingStrategy = namingStrategy;
  244. }
  245. /**
  246. * Set whether to execute a schema update after SessionFactory initialization.
  247. * <p>For details on how to make schema update scripts work, see the Hibernate
  248. * documentation, as this class leverages the same schema update script support
  249. * in net.sf.hibernate.cfg.Configuration as Hibernate's own SchemaUpdate tool.
  250. * @see net.sf.hibernate.cfg.Configuration#generateSchemaUpdateScript
  251. * @see net.sf.hibernate.tool.hbm2ddl.SchemaUpdate
  252. */
  253. public void setSchemaUpdate(boolean schemaUpdate) {
  254. this.schemaUpdate = schemaUpdate;
  255. }
  256. /**
  257. * Initialize the SessionFactory for the given or the default location.
  258. * @throws IllegalArgumentException in case of illegal property values
  259. * @throws HibernateException in case of Hibernate initialization errors
  260. */
  261. public void afterPropertiesSet() throws IllegalArgumentException, HibernateException, IOException {
  262. // create Configuration instance
  263. Configuration config = newConfiguration();
  264. if (this.lobHandler != null) {
  265. // make given LobHandler available for SessionFactory configuration
  266. // do early because because mapping resource might refer to custom types
  267. configTimeLobHandlerHolder.set(this.lobHandler);
  268. }
  269. if (this.namingStrategy != null) {
  270. // pass given naming strategy to Hibernate Configuration
  271. config.setNamingStrategy(this.namingStrategy);
  272. }
  273. if (this.configLocation != null) {
  274. // load Hibernate configuration from given location
  275. config.configure(this.configLocation.getURL());
  276. }
  277. if (this.mappingLocations != null) {
  278. // register given Hibernate mapping definitions, contained in resource files
  279. for (int i = 0; i < this.mappingLocations.length; i++) {
  280. config.addInputStream(this.mappingLocations[i].getInputStream());
  281. }
  282. }
  283. if (this.mappingJarLocations != null) {
  284. // register given Hibernate mapping definitions, contained in jar files
  285. for (int i = 0; i < this.mappingJarLocations.length; i++) {
  286. Resource resource = this.mappingJarLocations[i];
  287. config.addJar(resource.getFile());
  288. }
  289. }
  290. if (this.mappingDirectoryLocations != null) {
  291. // register all Hibernate mapping definitions in the given directories
  292. for (int i = 0; i < this.mappingDirectoryLocations.length; i++) {
  293. File file = this.mappingDirectoryLocations[i].getFile();
  294. if (!file.isDirectory()) {
  295. throw new IllegalArgumentException("Mapping directory location [" + this.mappingDirectoryLocations[i] +
  296. "] does not denote a directory");
  297. }
  298. config.addDirectory(file);
  299. }
  300. }
  301. if (this.hibernateProperties != null) {
  302. // add given Hibernate properties
  303. config.addProperties(this.hibernateProperties);
  304. }
  305. if (this.dataSource != null) {
  306. // make given DataSource available for SessionFactory configuration
  307. config.setProperty(Environment.CONNECTION_PROVIDER, LocalDataSourceConnectionProvider.class.getName());
  308. LocalDataSourceConnectionProvider.configTimeDataSourceHolder.set(this.dataSource);
  309. }
  310. if (this.jtaTransactionManager != null) {
  311. // set Spring-provided JTA TransactionManager for Hibernate cache callbacks
  312. config.setProperty(Environment.TRANSACTION_MANAGER_STRATEGY, LocalTransactionManagerLookup.class.getName());
  313. LocalTransactionManagerLookup.configTimeTransactionManagerHolder.set(this.jtaTransactionManager);
  314. }
  315. if (this.entityInterceptor != null) {
  316. // set given entity interceptor at SessionFactory level
  317. config.setInterceptor(this.entityInterceptor);
  318. }
  319. // perform custom post-processing in subclasses
  320. postProcessConfiguration(config);
  321. // build SessionFactory instance
  322. logger.info("Building new Hibernate SessionFactory");
  323. this.configuration = config;
  324. this.sessionFactory = newSessionFactory(config);
  325. if (this.jtaTransactionManager != null) {
  326. // reset TransactionManager holder
  327. LocalTransactionManagerLookup.configTimeTransactionManagerHolder.set(null);
  328. }
  329. if (this.dataSource != null) {
  330. // reset DataSource holder
  331. LocalDataSourceConnectionProvider.configTimeDataSourceHolder.set(null);
  332. }
  333. if (this.lobHandler != null) {
  334. // reset LobHandler holder
  335. configTimeLobHandlerHolder.set(null);
  336. }
  337. // execute schema update if requested
  338. if (this.schemaUpdate) {
  339. updateDatabaseSchema();
  340. }
  341. }
  342. /**
  343. * Subclasses can override this method to perform custom initialization
  344. * of the Configuration instance used for SessionFactory creation.
  345. * The properties of this LocalSessionFactoryBean will be applied to
  346. * the Configuration object that gets returned here.
  347. * <p>The default implementation creates a new Configuration instance.
  348. * A custom implementation could prepare the instance in a specific way,
  349. * or use a custom Configuration subclass.
  350. * @return the Configuration instance
  351. * @throws HibernateException in case of Hibernate initialization errors
  352. * @see net.sf.hibernate.cfg.Configuration#Configuration()
  353. */
  354. protected Configuration newConfiguration() throws HibernateException {
  355. return new Configuration();
  356. }
  357. /**
  358. * To be implemented by subclasses that want to to perform custom
  359. * post-processing of the Configuration object after this FactoryBean
  360. * performed its default initialization.
  361. * @param config the current Configuration object
  362. * @throws HibernateException in case of Hibernate initialization errors
  363. */
  364. protected void postProcessConfiguration(Configuration config) throws HibernateException {
  365. }
  366. /**
  367. * Subclasses can override this method to perform custom initialization
  368. * of the SessionFactory instance, creating it via the given Configuration
  369. * object that got prepared by this LocalSessionFactoryBean.
  370. * <p>The default implementation invokes Configuration's buildSessionFactory.
  371. * A custom implementation could prepare the instance in a specific way,
  372. * or use a custom SessionFactoryImpl subclass.
  373. * @param config Configuration prepared by this LocalSessionFactoryBean
  374. * @return the SessionFactory instance
  375. * @throws HibernateException in case of Hibernate initialization errors
  376. * @see net.sf.hibernate.cfg.Configuration#buildSessionFactory
  377. */
  378. protected SessionFactory newSessionFactory(Configuration config) throws HibernateException {
  379. return config.buildSessionFactory();
  380. }
  381. /**
  382. * Execute schema drop script, determined by the Configuration object
  383. * used for creating the SessionFactory. A replacement for Hibernate's
  384. * SchemaExport class, to be invoked on application setup.
  385. * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
  386. * SessionFactory to be able to invoke this method, e.g. via
  387. * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
  388. * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
  389. * connection to perform the script.
  390. * @throws DataAccessException in case of script execution errors
  391. * @see net.sf.hibernate.cfg.Configuration#generateDropSchemaScript
  392. * @see net.sf.hibernate.tool.hbm2ddl.SchemaExport#drop
  393. */
  394. public void dropDatabaseSchema() throws DataAccessException {
  395. logger.info("Dropping database schema for Hibernate SessionFactory");
  396. HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  397. hibernateTemplate.execute(
  398. new HibernateCallback() {
  399. public Object doInHibernate(Session session) throws HibernateException, SQLException {
  400. Connection con = session.connection();
  401. Dialect dialect = Dialect.getDialect(configuration.getProperties());
  402. String[] sql = configuration.generateDropSchemaScript(dialect);
  403. executeSchemaScript(con, sql);
  404. return null;
  405. }
  406. }
  407. );
  408. }
  409. /**
  410. * Execute schema creation script, determined by the Configuration object
  411. * used for creating the SessionFactory. A replacement for Hibernate's
  412. * SchemaExport class, to be invoked on application setup.
  413. * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
  414. * SessionFactory to be able to invoke this method, e.g. via
  415. * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
  416. * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
  417. * connection to perform the script.
  418. * @throws DataAccessException in case of script execution errors
  419. * @see net.sf.hibernate.cfg.Configuration#generateSchemaCreationScript
  420. * @see net.sf.hibernate.tool.hbm2ddl.SchemaExport#create
  421. */
  422. public void createDatabaseSchema() throws DataAccessException {
  423. logger.info("Creating database schema for Hibernate SessionFactory");
  424. HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  425. hibernateTemplate.execute(
  426. new HibernateCallback() {
  427. public Object doInHibernate(Session session) throws HibernateException, SQLException {
  428. Connection con = session.connection();
  429. final Dialect dialect = Dialect.getDialect(configuration.getProperties());
  430. String[] sql = configuration.generateSchemaCreationScript(dialect);
  431. executeSchemaScript(con, sql);
  432. return null;
  433. }
  434. }
  435. );
  436. }
  437. /**
  438. * Execute schema update script, determined by the Configuration object
  439. * used for creating the SessionFactory. A replacement for Hibernate's
  440. * SchemaUpdate class, for automatically executing schema update scripts
  441. * on application startup. Can also be invoked manually.
  442. * <p>Fetch the LocalSessionFactoryBean itself rather than the exposed
  443. * SessionFactory to be able to invoke this method, e.g. via
  444. * <code>LocalSessionFactoryBean lsfb = (LocalSessionFactoryBean) ctx.getBean("&mySessionFactory");</code>.
  445. * <p>Uses the SessionFactory that this bean generates for accessing a JDBC
  446. * connection to perform the script.
  447. * @throws HibernateException in case of Hibernate initialization errors
  448. * @see #setSchemaUpdate
  449. * @see net.sf.hibernate.cfg.Configuration#generateSchemaUpdateScript
  450. * @see net.sf.hibernate.tool.hbm2ddl.SchemaUpdate
  451. */
  452. public void updateDatabaseSchema() throws HibernateException {
  453. logger.info("Updating database schema for Hibernate SessionFactory");
  454. HibernateTemplate hibernateTemplate = new HibernateTemplate(this.sessionFactory);
  455. hibernateTemplate.setFlushMode(HibernateTemplate.FLUSH_NEVER);
  456. hibernateTemplate.execute(
  457. new HibernateCallback() {
  458. public Object doInHibernate(Session session) throws HibernateException, SQLException {
  459. Connection con = session.connection();
  460. final Dialect dialect = Dialect.getDialect(configuration.getProperties());
  461. DatabaseMetadata metadata = new DatabaseMetadata(con, dialect);
  462. String[] sql = configuration.generateSchemaUpdateScript(dialect, metadata);
  463. executeSchemaScript(con, sql);
  464. return null;
  465. }
  466. }
  467. );
  468. }
  469. /**
  470. * Execute the given schema script on the given JDBC Connection.
  471. * Will log unsuccessful statements and continue to execute.
  472. * @param con the JDBC Connection to execute the script on
  473. * @param sql the SQL statements to execute
  474. * @throws SQLException if thrown by JDBC methods
  475. */
  476. protected void executeSchemaScript(Connection con, String[] sql) throws SQLException {
  477. if (sql != null && sql.length > 0) {
  478. boolean oldAutoCommit = con.getAutoCommit();
  479. con.setAutoCommit(false);
  480. try {
  481. Statement stmt = con.createStatement();
  482. try {
  483. for (int i = 0; i < sql.length; i++) {
  484. logger.debug("Executing schema statement: " + sql[i]);
  485. try {
  486. stmt.executeUpdate(sql[i]);
  487. }
  488. catch (SQLException ex) {
  489. logger.warn("Unsuccessful schema statement: " + sql[i], ex);
  490. }
  491. }
  492. }
  493. finally {
  494. JdbcUtils.closeStatement(stmt);
  495. }
  496. con.commit();
  497. }
  498. finally {
  499. con.setAutoCommit(oldAutoCommit);
  500. }
  501. }
  502. }
  503. /**
  504. * Return the Configuration object used to build the SessionFactory.
  505. * Allows access to configuration metadata stored there (rarely needed).
  506. */
  507. public Configuration getConfiguration() {
  508. return configuration;
  509. }
  510. /**
  511. * Return the singleton SessionFactory.
  512. */
  513. public Object getObject() {
  514. return this.sessionFactory;
  515. }
  516. public Class getObjectType() {
  517. return (this.sessionFactory != null) ? this.sessionFactory.getClass() : SessionFactory.class;
  518. }
  519. public boolean isSingleton() {
  520. return true;
  521. }
  522. /**
  523. * Close the SessionFactory on bean factory shutdown.
  524. */
  525. public void destroy() throws HibernateException {
  526. logger.info("Closing Hibernate SessionFactory");
  527. this.sessionFactory.close();
  528. }
  529. }