001/*
002 * Copyright 2002-2017 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.support;
018
019import java.sql.SQLDataException;
020import java.sql.SQLException;
021import java.sql.SQLFeatureNotSupportedException;
022import java.sql.SQLIntegrityConstraintViolationException;
023import java.sql.SQLInvalidAuthorizationSpecException;
024import java.sql.SQLNonTransientConnectionException;
025import java.sql.SQLNonTransientException;
026import java.sql.SQLRecoverableException;
027import java.sql.SQLSyntaxErrorException;
028import java.sql.SQLTimeoutException;
029import java.sql.SQLTransactionRollbackException;
030import java.sql.SQLTransientConnectionException;
031import java.sql.SQLTransientException;
032
033import org.springframework.dao.ConcurrencyFailureException;
034import org.springframework.dao.DataAccessException;
035import org.springframework.dao.DataAccessResourceFailureException;
036import org.springframework.dao.DataIntegrityViolationException;
037import org.springframework.dao.InvalidDataAccessApiUsageException;
038import org.springframework.dao.PermissionDeniedDataAccessException;
039import org.springframework.dao.QueryTimeoutException;
040import org.springframework.dao.RecoverableDataAccessException;
041import org.springframework.dao.TransientDataAccessResourceException;
042import org.springframework.jdbc.BadSqlGrammarException;
043import org.springframework.lang.Nullable;
044
045/**
046 * {@link SQLExceptionTranslator} implementation which analyzes the specific
047 * {@link java.sql.SQLException} subclass thrown by the JDBC driver.
048 *
049 * <p>Falls back to a standard {@link SQLStateSQLExceptionTranslator} if the JDBC
050 * driver does not actually expose JDBC 4 compliant {@code SQLException} subclasses.
051 *
052 * @author Thomas Risberg
053 * @author Juergen Hoeller
054 * @since 2.5
055 * @see java.sql.SQLTransientException
056 * @see java.sql.SQLTransientException
057 * @see java.sql.SQLRecoverableException
058 */
059public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLExceptionTranslator {
060
061        public SQLExceptionSubclassTranslator() {
062                setFallbackTranslator(new SQLStateSQLExceptionTranslator());
063        }
064
065        @Override
066        @Nullable
067        protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
068                if (ex instanceof SQLTransientException) {
069                        if (ex instanceof SQLTransientConnectionException) {
070                                return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
071                        }
072                        else if (ex instanceof SQLTransactionRollbackException) {
073                                return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex);
074                        }
075                        else if (ex instanceof SQLTimeoutException) {
076                                return new QueryTimeoutException(buildMessage(task, sql, ex), ex);
077                        }
078                }
079                else if (ex instanceof SQLNonTransientException) {
080                        if (ex instanceof SQLNonTransientConnectionException) {
081                                return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex);
082                        }
083                        else if (ex instanceof SQLDataException) {
084                                return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
085                        }
086                        else if (ex instanceof SQLIntegrityConstraintViolationException) {
087                                return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex);
088                        }
089                        else if (ex instanceof SQLInvalidAuthorizationSpecException) {
090                                return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex);
091                        }
092                        else if (ex instanceof SQLSyntaxErrorException) {
093                                return new BadSqlGrammarException(task, (sql != null ? sql : ""), ex);
094                        }
095                        else if (ex instanceof SQLFeatureNotSupportedException) {
096                                return new InvalidDataAccessApiUsageException(buildMessage(task, sql, ex), ex);
097                        }
098                }
099                else if (ex instanceof SQLRecoverableException) {
100                        return new RecoverableDataAccessException(buildMessage(task, sql, ex), ex);
101                }
102
103                // Fallback to Spring's own SQL state translation...
104                return null;
105        }
106
107}