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.jdbc.core.support;
018
019import java.sql.Connection;
020
021import javax.sql.DataSource;
022
023import org.springframework.dao.support.DaoSupport;
024import org.springframework.jdbc.CannotGetJdbcConnectionException;
025import org.springframework.jdbc.core.JdbcTemplate;
026import org.springframework.jdbc.datasource.DataSourceUtils;
027import org.springframework.jdbc.support.SQLExceptionTranslator;
028import org.springframework.lang.Nullable;
029import org.springframework.util.Assert;
030
031/**
032 * Convenient super class for JDBC-based data access objects.
033 *
034 * <p>Requires a {@link javax.sql.DataSource} to be set, providing a
035 * {@link org.springframework.jdbc.core.JdbcTemplate} based on it to
036 * subclasses through the {@link #getJdbcTemplate()} method.
037 *
038 * <p>This base class is mainly intended for JdbcTemplate usage but can
039 * also be used when working with a Connection directly or when using
040 * {@code org.springframework.jdbc.object} operation objects.
041 *
042 * @author Juergen Hoeller
043 * @since 28.07.2003
044 * @see #setDataSource
045 * @see #getJdbcTemplate
046 * @see org.springframework.jdbc.core.JdbcTemplate
047 */
048public abstract class JdbcDaoSupport extends DaoSupport {
049
050        @Nullable
051        private JdbcTemplate jdbcTemplate;
052
053
054        /**
055         * Set the JDBC DataSource to be used by this DAO.
056         */
057        public final void setDataSource(DataSource dataSource) {
058                if (this.jdbcTemplate == null || dataSource != this.jdbcTemplate.getDataSource()) {
059                        this.jdbcTemplate = createJdbcTemplate(dataSource);
060                        initTemplateConfig();
061                }
062        }
063
064        /**
065         * Create a JdbcTemplate for the given DataSource.
066         * Only invoked if populating the DAO with a DataSource reference!
067         * <p>Can be overridden in subclasses to provide a JdbcTemplate instance
068         * with different configuration, or a custom JdbcTemplate subclass.
069         * @param dataSource the JDBC DataSource to create a JdbcTemplate for
070         * @return the new JdbcTemplate instance
071         * @see #setDataSource
072         */
073        protected JdbcTemplate createJdbcTemplate(DataSource dataSource) {
074                return new JdbcTemplate(dataSource);
075        }
076
077        /**
078         * Return the JDBC DataSource used by this DAO.
079         */
080        @Nullable
081        public final DataSource getDataSource() {
082                return (this.jdbcTemplate != null ? this.jdbcTemplate.getDataSource() : null);
083        }
084
085        /**
086         * Set the JdbcTemplate for this DAO explicitly,
087         * as an alternative to specifying a DataSource.
088         */
089        public final void setJdbcTemplate(@Nullable JdbcTemplate jdbcTemplate) {
090                this.jdbcTemplate = jdbcTemplate;
091                initTemplateConfig();
092        }
093
094        /**
095         * Return the JdbcTemplate for this DAO,
096         * pre-initialized with the DataSource or set explicitly.
097         */
098        @Nullable
099        public final JdbcTemplate getJdbcTemplate() {
100                return this.jdbcTemplate;
101        }
102
103        /**
104         * Initialize the template-based configuration of this DAO.
105         * Called after a new JdbcTemplate has been set, either directly
106         * or through a DataSource.
107         * <p>This implementation is empty. Subclasses may override this
108         * to configure further objects based on the JdbcTemplate.
109         * @see #getJdbcTemplate()
110         */
111        protected void initTemplateConfig() {
112        }
113
114        @Override
115        protected void checkDaoConfig() {
116                if (this.jdbcTemplate == null) {
117                        throw new IllegalArgumentException("'dataSource' or 'jdbcTemplate' is required");
118                }
119        }
120
121
122        /**
123         * Return the SQLExceptionTranslator of this DAO's JdbcTemplate,
124         * for translating SQLExceptions in custom JDBC access code.
125         * @see org.springframework.jdbc.core.JdbcTemplate#getExceptionTranslator()
126         */
127        protected final SQLExceptionTranslator getExceptionTranslator() {
128                JdbcTemplate jdbcTemplate = getJdbcTemplate();
129                Assert.state(jdbcTemplate != null, "No JdbcTemplate set");
130                return jdbcTemplate.getExceptionTranslator();
131        }
132
133        /**
134         * Get a JDBC Connection, either from the current transaction or a new one.
135         * @return the JDBC Connection
136         * @throws CannotGetJdbcConnectionException if the attempt to get a Connection failed
137         * @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection(javax.sql.DataSource)
138         */
139        protected final Connection getConnection() throws CannotGetJdbcConnectionException {
140                DataSource dataSource = getDataSource();
141                Assert.state(dataSource != null, "No DataSource set");
142                return DataSourceUtils.getConnection(dataSource);
143        }
144
145        /**
146         * Close the given JDBC Connection, created via this DAO's DataSource,
147         * if it isn't bound to the thread.
148         * @param con the Connection to close
149         * @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
150         */
151        protected final void releaseConnection(Connection con) {
152                DataSourceUtils.releaseConnection(con, getDataSource());
153        }
154
155}