001/*
002 * Copyright 2002-2018 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.support;
018
019import org.hibernate.Session;
020import org.hibernate.SessionFactory;
021
022import org.springframework.dao.DataAccessResourceFailureException;
023import org.springframework.dao.support.DaoSupport;
024import org.springframework.lang.Nullable;
025import org.springframework.orm.hibernate5.HibernateTemplate;
026import org.springframework.util.Assert;
027
028/**
029 * Convenient super class for Hibernate-based data access objects.
030 *
031 * <p>Requires a {@link SessionFactory} to be set, providing a
032 * {@link org.springframework.orm.hibernate5.HibernateTemplate} based on it to
033 * subclasses through the {@link #getHibernateTemplate()} method.
034 * Can alternatively be initialized directly with a HibernateTemplate,
035 * in order to reuse the latter's settings such as the SessionFactory,
036 * exception translator, flush mode, etc.
037 *
038 * <p>This class will create its own HibernateTemplate instance if a SessionFactory
039 * is passed in. The "allowCreate" flag on that HibernateTemplate will be "true"
040 * by default. A custom HibernateTemplate instance can be used through overriding
041 * {@link #createHibernateTemplate}.
042 *
043 * <p><b>NOTE: Hibernate access code can also be coded in plain Hibernate style.
044 * Hence, for newly started projects, consider adopting the standard Hibernate
045 * style of coding data access objects instead, based on
046 * {@link SessionFactory#getCurrentSession()}.
047 * This HibernateTemplate primarily exists as a migration helper for Hibernate 3
048 * based data access code, to benefit from bug fixes in Hibernate 5.x.</b>
049 *
050 * @author Juergen Hoeller
051 * @since 4.2
052 * @see #setSessionFactory
053 * @see #getHibernateTemplate
054 * @see org.springframework.orm.hibernate5.HibernateTemplate
055 */
056public abstract class HibernateDaoSupport extends DaoSupport {
057
058        @Nullable
059        private HibernateTemplate hibernateTemplate;
060
061
062        /**
063         * Set the Hibernate SessionFactory to be used by this DAO.
064         * Will automatically create a HibernateTemplate for the given SessionFactory.
065         * @see #createHibernateTemplate
066         * @see #setHibernateTemplate
067         */
068        public final void setSessionFactory(SessionFactory sessionFactory) {
069                if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) {
070                        this.hibernateTemplate = createHibernateTemplate(sessionFactory);
071                }
072        }
073
074        /**
075         * Create a HibernateTemplate for the given SessionFactory.
076         * Only invoked if populating the DAO with a SessionFactory reference!
077         * <p>Can be overridden in subclasses to provide a HibernateTemplate instance
078         * with different configuration, or a custom HibernateTemplate subclass.
079         * @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for
080         * @return the new HibernateTemplate instance
081         * @see #setSessionFactory
082         */
083        protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) {
084                return new HibernateTemplate(sessionFactory);
085        }
086
087        /**
088         * Return the Hibernate SessionFactory used by this DAO.
089         */
090        @Nullable
091        public final SessionFactory getSessionFactory() {
092                return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null);
093        }
094
095        /**
096         * Set the HibernateTemplate for this DAO explicitly,
097         * as an alternative to specifying a SessionFactory.
098         * @see #setSessionFactory
099         */
100        public final void setHibernateTemplate(@Nullable HibernateTemplate hibernateTemplate) {
101                this.hibernateTemplate = hibernateTemplate;
102        }
103
104        /**
105         * Return the HibernateTemplate for this DAO,
106         * pre-initialized with the SessionFactory or set explicitly.
107         * <p><b>Note: The returned HibernateTemplate is a shared instance.</b>
108         * You may introspect its configuration, but not modify the configuration
109         * (other than from within an {@link #initDao} implementation).
110         * Consider creating a custom HibernateTemplate instance via
111         * {@code new HibernateTemplate(getSessionFactory())}, in which case
112         * you're allowed to customize the settings on the resulting instance.
113         */
114        @Nullable
115        public final HibernateTemplate getHibernateTemplate() {
116                return this.hibernateTemplate;
117        }
118
119        @Override
120        protected final void checkDaoConfig() {
121                if (this.hibernateTemplate == null) {
122                        throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required");
123                }
124        }
125
126
127        /**
128         * Conveniently obtain the current Hibernate Session.
129         * @return the Hibernate Session
130         * @throws DataAccessResourceFailureException if the Session couldn't be created
131         * @see SessionFactory#getCurrentSession()
132         */
133        protected final Session currentSession() throws DataAccessResourceFailureException {
134                SessionFactory sessionFactory = getSessionFactory();
135                Assert.state(sessionFactory != null, "No SessionFactory set");
136                return sessionFactory.getCurrentSession();
137        }
138
139}