001/*
002 * Copyright 2002-2020 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.orm.hibernate5;
018
019import java.io.File;
020import java.io.IOException;
021import java.util.Properties;
022
023import javax.sql.DataSource;
024
025import org.hibernate.Interceptor;
026import org.hibernate.SessionFactory;
027import org.hibernate.boot.MetadataSources;
028import org.hibernate.boot.model.naming.ImplicitNamingStrategy;
029import org.hibernate.boot.model.naming.PhysicalNamingStrategy;
030import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder;
031import org.hibernate.cache.spi.RegionFactory;
032import org.hibernate.cfg.Configuration;
033import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
034import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider;
035import org.hibernate.integrator.spi.Integrator;
036import org.hibernate.service.ServiceRegistry;
037
038import org.springframework.beans.factory.BeanFactory;
039import org.springframework.beans.factory.BeanFactoryAware;
040import org.springframework.beans.factory.DisposableBean;
041import org.springframework.beans.factory.FactoryBean;
042import org.springframework.beans.factory.InitializingBean;
043import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
044import org.springframework.context.ResourceLoaderAware;
045import org.springframework.core.io.ClassPathResource;
046import org.springframework.core.io.Resource;
047import org.springframework.core.io.ResourceLoader;
048import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
049import org.springframework.core.io.support.ResourcePatternResolver;
050import org.springframework.core.io.support.ResourcePatternUtils;
051import org.springframework.core.task.AsyncTaskExecutor;
052import org.springframework.core.type.filter.TypeFilter;
053import org.springframework.lang.Nullable;
054import org.springframework.util.ClassUtils;
055
056/**
057 * {@link FactoryBean} that creates a Hibernate {@link SessionFactory}. This is the usual
058 * way to set up a shared Hibernate SessionFactory in a Spring application context; the
059 * SessionFactory can then be passed to data access objects via dependency injection.
060 *
061 * <p>Compatible with Hibernate 5.0/5.1 as well as 5.2/5.3/5.4, as of Spring 5.2.
062 * Set up with Hibernate 5.2+, {@code LocalSessionFactoryBean} is an immediate alternative
063 * to {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean} for common
064 * JPA purposes: In particular with Hibernate 5.3/5.4, the Hibernate {@code SessionFactory}
065 * will natively expose the JPA {@code EntityManagerFactory} interface as well, and
066 * Hibernate {@code BeanContainer} integration will be registered out of the box.
067 * In combination with {@link HibernateTransactionManager}, this naturally allows for
068 * mixing JPA access code with native Hibernate access code within the same transaction.
069 *
070 * @author Juergen Hoeller
071 * @since 4.2
072 * @see #setDataSource
073 * @see #setPackagesToScan
074 * @see HibernateTransactionManager
075 * @see LocalSessionFactoryBuilder
076 * @see org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean
077 */
078public class LocalSessionFactoryBean extends HibernateExceptionTranslator
079                implements FactoryBean<SessionFactory>, ResourceLoaderAware, BeanFactoryAware, InitializingBean, DisposableBean {
080
081        @Nullable
082        private DataSource dataSource;
083
084        @Nullable
085        private Resource[] configLocations;
086
087        @Nullable
088        private String[] mappingResources;
089
090        @Nullable
091        private Resource[] mappingLocations;
092
093        @Nullable
094        private Resource[] cacheableMappingLocations;
095
096        @Nullable
097        private Resource[] mappingJarLocations;
098
099        @Nullable
100        private Resource[] mappingDirectoryLocations;
101
102        @Nullable
103        private Interceptor entityInterceptor;
104
105        @Nullable
106        private ImplicitNamingStrategy implicitNamingStrategy;
107
108        @Nullable
109        private PhysicalNamingStrategy physicalNamingStrategy;
110
111        @Nullable
112        private Object jtaTransactionManager;
113
114        @Nullable
115        private RegionFactory cacheRegionFactory;
116
117        @Nullable
118        private MultiTenantConnectionProvider multiTenantConnectionProvider;
119
120        @Nullable
121        private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
122
123        @Nullable
124        private Properties hibernateProperties;
125
126        @Nullable
127        private TypeFilter[] entityTypeFilters;
128
129        @Nullable
130        private Class<?>[] annotatedClasses;
131
132        @Nullable
133        private String[] annotatedPackages;
134
135        @Nullable
136        private String[] packagesToScan;
137
138        @Nullable
139        private AsyncTaskExecutor bootstrapExecutor;
140
141        @Nullable
142        private Integrator[] hibernateIntegrators;
143
144        private boolean metadataSourcesAccessed = false;
145
146        @Nullable
147        private MetadataSources metadataSources;
148
149        @Nullable
150        private ResourcePatternResolver resourcePatternResolver;
151
152        @Nullable
153        private ConfigurableListableBeanFactory beanFactory;
154
155        @Nullable
156        private Configuration configuration;
157
158        @Nullable
159        private SessionFactory sessionFactory;
160
161
162        /**
163         * Set the DataSource to be used by the SessionFactory.
164         * If set, this will override corresponding settings in Hibernate properties.
165         * <p>If this is set, the Hibernate settings should not define
166         * a connection provider to avoid meaningless double configuration.
167         */
168        public void setDataSource(DataSource dataSource) {
169                this.dataSource = dataSource;
170        }
171
172        /**
173         * Set the location of a single Hibernate XML config file, for example as
174         * classpath resource "classpath:hibernate.cfg.xml".
175         * <p>Note: Can be omitted when all necessary properties and mapping
176         * resources are specified locally via this bean.
177         * @see Configuration#configure(java.net.URL)
178         */
179        public void setConfigLocation(Resource configLocation) {
180                this.configLocations = new Resource[] {configLocation};
181        }
182
183        /**
184         * Set the locations of multiple Hibernate XML config files, for example as
185         * classpath resources "classpath:hibernate.cfg.xml,classpath:extension.cfg.xml".
186         * <p>Note: Can be omitted when all necessary properties and mapping
187         * resources are specified locally via this bean.
188         * @see Configuration#configure(java.net.URL)
189         */
190        public void setConfigLocations(Resource... configLocations) {
191                this.configLocations = configLocations;
192        }
193
194        /**
195         * Set Hibernate mapping resources to be found in the class path,
196         * like "example.hbm.xml" or "mypackage/example.hbm.xml".
197         * Analogous to mapping entries in a Hibernate XML config file.
198         * Alternative to the more generic setMappingLocations method.
199         * <p>Can be used to add to mappings from a Hibernate XML config file,
200         * or to specify all mappings locally.
201         * @see #setMappingLocations
202         * @see Configuration#addResource
203         */
204        public void setMappingResources(String... mappingResources) {
205                this.mappingResources = mappingResources;
206        }
207
208        /**
209         * Set locations of Hibernate mapping files, for example as classpath
210         * resource "classpath:example.hbm.xml". Supports any resource location
211         * via Spring's resource abstraction, for example relative paths like
212         * "WEB-INF/mappings/example.hbm.xml" when running in an application context.
213         * <p>Can be used to add to mappings from a Hibernate XML config file,
214         * or to specify all mappings locally.
215         * @see Configuration#addInputStream
216         */
217        public void setMappingLocations(Resource... mappingLocations) {
218                this.mappingLocations = mappingLocations;
219        }
220
221        /**
222         * Set locations of cacheable Hibernate mapping files, for example as web app
223         * resource "/WEB-INF/mapping/example.hbm.xml". Supports any resource location
224         * via Spring's resource abstraction, as long as the resource can be resolved
225         * in the file system.
226         * <p>Can be used to add to mappings from a Hibernate XML config file,
227         * or to specify all mappings locally.
228         * @see Configuration#addCacheableFile(File)
229         */
230        public void setCacheableMappingLocations(Resource... cacheableMappingLocations) {
231                this.cacheableMappingLocations = cacheableMappingLocations;
232        }
233
234        /**
235         * Set locations of jar files that contain Hibernate mapping resources,
236         * like "WEB-INF/lib/example.hbm.jar".
237         * <p>Can be used to add to mappings from a Hibernate XML config file,
238         * or to specify all mappings locally.
239         * @see Configuration#addJar(File)
240         */
241        public void setMappingJarLocations(Resource... mappingJarLocations) {
242                this.mappingJarLocations = mappingJarLocations;
243        }
244
245        /**
246         * Set locations of directories that contain Hibernate mapping resources,
247         * like "WEB-INF/mappings".
248         * <p>Can be used to add to mappings from a Hibernate XML config file,
249         * or to specify all mappings locally.
250         * @see Configuration#addDirectory(File)
251         */
252        public void setMappingDirectoryLocations(Resource... mappingDirectoryLocations) {
253                this.mappingDirectoryLocations = mappingDirectoryLocations;
254        }
255
256        /**
257         * Set a Hibernate entity interceptor that allows to inspect and change
258         * property values before writing to and reading from the database.
259         * Will get applied to any new Session created by this factory.
260         * @see Configuration#setInterceptor
261         */
262        public void setEntityInterceptor(Interceptor entityInterceptor) {
263                this.entityInterceptor = entityInterceptor;
264        }
265
266        /**
267         * Set a Hibernate 5 {@link ImplicitNamingStrategy} for the SessionFactory.
268         * @see Configuration#setImplicitNamingStrategy
269         */
270        public void setImplicitNamingStrategy(ImplicitNamingStrategy implicitNamingStrategy) {
271                this.implicitNamingStrategy = implicitNamingStrategy;
272        }
273
274        /**
275         * Set a Hibernate 5 {@link PhysicalNamingStrategy} for the SessionFactory.
276         * @see Configuration#setPhysicalNamingStrategy
277         */
278        public void setPhysicalNamingStrategy(PhysicalNamingStrategy physicalNamingStrategy) {
279                this.physicalNamingStrategy = physicalNamingStrategy;
280        }
281
282        /**
283         * Set the Spring {@link org.springframework.transaction.jta.JtaTransactionManager}
284         * or the JTA {@link javax.transaction.TransactionManager} to be used with Hibernate,
285         * if any. Implicitly sets up {@code JtaPlatform}.
286         * @see LocalSessionFactoryBuilder#setJtaTransactionManager
287         */
288        public void setJtaTransactionManager(Object jtaTransactionManager) {
289                this.jtaTransactionManager = jtaTransactionManager;
290        }
291
292        /**
293         * Set the Hibernate {@link RegionFactory} to use for the SessionFactory.
294         * Allows for using a Spring-managed {@code RegionFactory} instance.
295         * <p>Note: If this is set, the Hibernate settings should not define a
296         * cache provider to avoid meaningless double configuration.
297         * @since 5.1
298         * @see LocalSessionFactoryBuilder#setCacheRegionFactory
299         */
300        public void setCacheRegionFactory(RegionFactory cacheRegionFactory) {
301                this.cacheRegionFactory = cacheRegionFactory;
302        }
303
304        /**
305         * Set a {@link MultiTenantConnectionProvider} to be passed on to the SessionFactory.
306         * @since 4.3
307         * @see LocalSessionFactoryBuilder#setMultiTenantConnectionProvider
308         */
309        public void setMultiTenantConnectionProvider(MultiTenantConnectionProvider multiTenantConnectionProvider) {
310                this.multiTenantConnectionProvider = multiTenantConnectionProvider;
311        }
312
313        /**
314         * Set a {@link CurrentTenantIdentifierResolver} to be passed on to the SessionFactory.
315         * @see LocalSessionFactoryBuilder#setCurrentTenantIdentifierResolver
316         */
317        public void setCurrentTenantIdentifierResolver(CurrentTenantIdentifierResolver currentTenantIdentifierResolver) {
318                this.currentTenantIdentifierResolver = currentTenantIdentifierResolver;
319        }
320
321        /**
322         * Set Hibernate properties, such as "hibernate.dialect".
323         * <p>Note: Do not specify a transaction provider here when using
324         * Spring-driven transactions. It is also advisable to omit connection
325         * provider settings and use a Spring-set DataSource instead.
326         * @see #setDataSource
327         */
328        public void setHibernateProperties(Properties hibernateProperties) {
329                this.hibernateProperties = hibernateProperties;
330        }
331
332        /**
333         * Return the Hibernate properties, if any. Mainly available for
334         * configuration through property paths that specify individual keys.
335         */
336        public Properties getHibernateProperties() {
337                if (this.hibernateProperties == null) {
338                        this.hibernateProperties = new Properties();
339                }
340                return this.hibernateProperties;
341        }
342
343        /**
344         * Specify custom type filters for Spring-based scanning for entity classes.
345         * <p>Default is to search all specified packages for classes annotated with
346         * {@code @javax.persistence.Entity}, {@code @javax.persistence.Embeddable}
347         * or {@code @javax.persistence.MappedSuperclass}.
348         * @see #setPackagesToScan
349         */
350        public void setEntityTypeFilters(TypeFilter... entityTypeFilters) {
351                this.entityTypeFilters = entityTypeFilters;
352        }
353
354        /**
355         * Specify annotated entity classes to register with this Hibernate SessionFactory.
356         * @see Configuration#addAnnotatedClass(Class)
357         */
358        public void setAnnotatedClasses(Class<?>... annotatedClasses) {
359                this.annotatedClasses = annotatedClasses;
360        }
361
362        /**
363         * Specify the names of annotated packages, for which package-level
364         * annotation metadata will be read.
365         * @see Configuration#addPackage(String)
366         */
367        public void setAnnotatedPackages(String... annotatedPackages) {
368                this.annotatedPackages = annotatedPackages;
369        }
370
371        /**
372         * Specify packages to search for autodetection of your entity classes in the
373         * classpath. This is analogous to Spring's component-scan feature
374         * ({@link org.springframework.context.annotation.ClassPathBeanDefinitionScanner}).
375         */
376        public void setPackagesToScan(String... packagesToScan) {
377                this.packagesToScan = packagesToScan;
378        }
379
380        /**
381         * Specify an asynchronous executor for background bootstrapping,
382         * e.g. a {@link org.springframework.core.task.SimpleAsyncTaskExecutor}.
383         * <p>{@code SessionFactory} initialization will then switch into background
384         * bootstrap mode, with a {@code SessionFactory} proxy immediately returned for
385         * injection purposes instead of waiting for Hibernate's bootstrapping to complete.
386         * However, note that the first actual call to a {@code SessionFactory} method will
387         * then block until Hibernate's bootstrapping completed, if not ready by then.
388         * For maximum benefit, make sure to avoid early {@code SessionFactory} calls
389         * in init methods of related beans, even for metadata introspection purposes.
390         * @since 4.3
391         * @see LocalSessionFactoryBuilder#buildSessionFactory(AsyncTaskExecutor)
392         */
393        public void setBootstrapExecutor(AsyncTaskExecutor bootstrapExecutor) {
394                this.bootstrapExecutor = bootstrapExecutor;
395        }
396
397        /**
398         * Specify one or more Hibernate {@link Integrator} implementations to apply.
399         * <p>This will only be applied for an internally built {@link MetadataSources}
400         * instance. {@link #setMetadataSources} effectively overrides such settings,
401         * with integrators to be applied to the externally built {@link MetadataSources}.
402         * @since 5.1
403         * @see #setMetadataSources
404         * @see BootstrapServiceRegistryBuilder#applyIntegrator
405         */
406        public void setHibernateIntegrators(Integrator... hibernateIntegrators) {
407                this.hibernateIntegrators = hibernateIntegrators;
408        }
409
410        /**
411         * Specify a Hibernate {@link MetadataSources} service to use (e.g. reusing an
412         * existing one), potentially populated with a custom Hibernate bootstrap
413         * {@link org.hibernate.service.ServiceRegistry} as well.
414         * @since 4.3
415         * @see MetadataSources#MetadataSources(ServiceRegistry)
416         * @see BootstrapServiceRegistryBuilder#build()
417         */
418        public void setMetadataSources(MetadataSources metadataSources) {
419                this.metadataSourcesAccessed = true;
420                this.metadataSources = metadataSources;
421        }
422
423        /**
424         * Determine the Hibernate {@link MetadataSources} to use.
425         * <p>Can also be externally called to initialize and pre-populate a {@link MetadataSources}
426         * instance which is then going to be used for {@link SessionFactory} building.
427         * @return the MetadataSources to use (never {@code null})
428         * @since 4.3
429         * @see LocalSessionFactoryBuilder#LocalSessionFactoryBuilder(DataSource, ResourceLoader, MetadataSources)
430         */
431        public MetadataSources getMetadataSources() {
432                this.metadataSourcesAccessed = true;
433                if (this.metadataSources == null) {
434                        BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder();
435                        if (this.resourcePatternResolver != null) {
436                                builder = builder.applyClassLoader(this.resourcePatternResolver.getClassLoader());
437                        }
438                        if (this.hibernateIntegrators != null) {
439                                for (Integrator integrator : this.hibernateIntegrators) {
440                                        builder = builder.applyIntegrator(integrator);
441                                }
442                        }
443                        this.metadataSources = new MetadataSources(builder.build());
444                }
445                return this.metadataSources;
446        }
447
448        /**
449         * Specify a Spring {@link ResourceLoader} to use for Hibernate metadata.
450         * @param resourceLoader the ResourceLoader to use (never {@code null})
451         */
452        @Override
453        public void setResourceLoader(ResourceLoader resourceLoader) {
454                this.resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
455        }
456
457        /**
458         * Determine the Spring {@link ResourceLoader} to use for Hibernate metadata.
459         * @return the ResourceLoader to use (never {@code null})
460         * @since 4.3
461         */
462        public ResourceLoader getResourceLoader() {
463                if (this.resourcePatternResolver == null) {
464                        this.resourcePatternResolver = new PathMatchingResourcePatternResolver();
465                }
466                return this.resourcePatternResolver;
467        }
468
469        /**
470         * Accept the containing {@link BeanFactory}, registering corresponding Hibernate
471         * {@link org.hibernate.resource.beans.container.spi.BeanContainer} integration for
472         * it if possible. This requires a Spring {@link ConfigurableListableBeanFactory}
473         * and Hibernate 5.3 or higher on the classpath.
474         * @since 5.1
475         * @see SpringBeanContainer
476         * @see LocalSessionFactoryBuilder#setBeanContainer
477         */
478        @Override
479        public void setBeanFactory(BeanFactory beanFactory) {
480                if (beanFactory instanceof ConfigurableListableBeanFactory &&
481                                ClassUtils.isPresent("org.hibernate.resource.beans.container.spi.BeanContainer",
482                                                getClass().getClassLoader())) {
483                        this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
484                }
485        }
486
487
488        @Override
489        public void afterPropertiesSet() throws IOException {
490                if (this.metadataSources != null && !this.metadataSourcesAccessed) {
491                        // Repeated initialization with no user-customized MetadataSources -> clear it.
492                        this.metadataSources = null;
493                }
494
495                LocalSessionFactoryBuilder sfb = new LocalSessionFactoryBuilder(
496                                this.dataSource, getResourceLoader(), getMetadataSources());
497
498                if (this.configLocations != null) {
499                        for (Resource resource : this.configLocations) {
500                                // Load Hibernate configuration from given location.
501                                sfb.configure(resource.getURL());
502                        }
503                }
504
505                if (this.mappingResources != null) {
506                        // Register given Hibernate mapping definitions, contained in resource files.
507                        for (String mapping : this.mappingResources) {
508                                Resource mr = new ClassPathResource(mapping.trim(), getResourceLoader().getClassLoader());
509                                sfb.addInputStream(mr.getInputStream());
510                        }
511                }
512
513                if (this.mappingLocations != null) {
514                        // Register given Hibernate mapping definitions, contained in resource files.
515                        for (Resource resource : this.mappingLocations) {
516                                sfb.addInputStream(resource.getInputStream());
517                        }
518                }
519
520                if (this.cacheableMappingLocations != null) {
521                        // Register given cacheable Hibernate mapping definitions, read from the file system.
522                        for (Resource resource : this.cacheableMappingLocations) {
523                                sfb.addCacheableFile(resource.getFile());
524                        }
525                }
526
527                if (this.mappingJarLocations != null) {
528                        // Register given Hibernate mapping definitions, contained in jar files.
529                        for (Resource resource : this.mappingJarLocations) {
530                                sfb.addJar(resource.getFile());
531                        }
532                }
533
534                if (this.mappingDirectoryLocations != null) {
535                        // Register all Hibernate mapping definitions in the given directories.
536                        for (Resource resource : this.mappingDirectoryLocations) {
537                                File file = resource.getFile();
538                                if (!file.isDirectory()) {
539                                        throw new IllegalArgumentException(
540                                                        "Mapping directory location [" + resource + "] does not denote a directory");
541                                }
542                                sfb.addDirectory(file);
543                        }
544                }
545
546                if (this.entityInterceptor != null) {
547                        sfb.setInterceptor(this.entityInterceptor);
548                }
549
550                if (this.implicitNamingStrategy != null) {
551                        sfb.setImplicitNamingStrategy(this.implicitNamingStrategy);
552                }
553
554                if (this.physicalNamingStrategy != null) {
555                        sfb.setPhysicalNamingStrategy(this.physicalNamingStrategy);
556                }
557
558                if (this.jtaTransactionManager != null) {
559                        sfb.setJtaTransactionManager(this.jtaTransactionManager);
560                }
561
562                if (this.beanFactory != null) {
563                        sfb.setBeanContainer(this.beanFactory);
564                }
565
566                if (this.cacheRegionFactory != null) {
567                        sfb.setCacheRegionFactory(this.cacheRegionFactory);
568                }
569
570                if (this.multiTenantConnectionProvider != null) {
571                        sfb.setMultiTenantConnectionProvider(this.multiTenantConnectionProvider);
572                }
573
574                if (this.currentTenantIdentifierResolver != null) {
575                        sfb.setCurrentTenantIdentifierResolver(this.currentTenantIdentifierResolver);
576                }
577
578                if (this.hibernateProperties != null) {
579                        sfb.addProperties(this.hibernateProperties);
580                }
581
582                if (this.entityTypeFilters != null) {
583                        sfb.setEntityTypeFilters(this.entityTypeFilters);
584                }
585
586                if (this.annotatedClasses != null) {
587                        sfb.addAnnotatedClasses(this.annotatedClasses);
588                }
589
590                if (this.annotatedPackages != null) {
591                        sfb.addPackages(this.annotatedPackages);
592                }
593
594                if (this.packagesToScan != null) {
595                        sfb.scanPackages(this.packagesToScan);
596                }
597
598                // Build SessionFactory instance.
599                this.configuration = sfb;
600                this.sessionFactory = buildSessionFactory(sfb);
601        }
602
603        /**
604         * Subclasses can override this method to perform custom initialization
605         * of the SessionFactory instance, creating it via the given Configuration
606         * object that got prepared by this LocalSessionFactoryBean.
607         * <p>The default implementation invokes LocalSessionFactoryBuilder's buildSessionFactory.
608         * A custom implementation could prepare the instance in a specific way (e.g. applying
609         * a custom ServiceRegistry) or use a custom SessionFactoryImpl subclass.
610         * @param sfb a LocalSessionFactoryBuilder prepared by this LocalSessionFactoryBean
611         * @return the SessionFactory instance
612         * @see LocalSessionFactoryBuilder#buildSessionFactory
613         */
614        protected SessionFactory buildSessionFactory(LocalSessionFactoryBuilder sfb) {
615                return (this.bootstrapExecutor != null ? sfb.buildSessionFactory(this.bootstrapExecutor) :
616                                sfb.buildSessionFactory());
617        }
618
619        /**
620         * Return the Hibernate Configuration object used to build the SessionFactory.
621         * Allows for access to configuration metadata stored there (rarely needed).
622         * @throws IllegalStateException if the Configuration object has not been initialized yet
623         */
624        public final Configuration getConfiguration() {
625                if (this.configuration == null) {
626                        throw new IllegalStateException("Configuration not initialized yet");
627                }
628                return this.configuration;
629        }
630
631
632        @Override
633        @Nullable
634        public SessionFactory getObject() {
635                return this.sessionFactory;
636        }
637
638        @Override
639        public Class<?> getObjectType() {
640                return (this.sessionFactory != null ? this.sessionFactory.getClass() : SessionFactory.class);
641        }
642
643        @Override
644        public boolean isSingleton() {
645                return true;
646        }
647
648
649        @Override
650        public void destroy() {
651                if (this.sessionFactory != null) {
652                        this.sessionFactory.close();
653                }
654        }
655
656}