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.support; 018 019import java.sql.SQLException; 020 021import org.apache.commons.logging.Log; 022import org.apache.commons.logging.LogFactory; 023 024import org.springframework.dao.DataAccessException; 025import org.springframework.jdbc.UncategorizedSQLException; 026import org.springframework.util.Assert; 027 028/** 029 * Base class for {@link SQLExceptionTranslator} implementations that allow for 030 * fallback to some other {@link SQLExceptionTranslator}. 031 * 032 * @author Juergen Hoeller 033 * @since 2.5.6 034 */ 035public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExceptionTranslator { 036 037 /** Logger available to subclasses */ 038 protected final Log logger = LogFactory.getLog(getClass()); 039 040 private SQLExceptionTranslator fallbackTranslator; 041 042 043 /** 044 * Override the default SQL state fallback translator 045 * (typically a {@link SQLStateSQLExceptionTranslator}). 046 */ 047 public void setFallbackTranslator(SQLExceptionTranslator fallback) { 048 this.fallbackTranslator = fallback; 049 } 050 051 /** 052 * Return the fallback exception translator, if any. 053 */ 054 public SQLExceptionTranslator getFallbackTranslator() { 055 return this.fallbackTranslator; 056 } 057 058 059 /** 060 * Pre-checks the arguments, calls {@link #doTranslate}, and invokes the 061 * {@link #getFallbackTranslator() fallback translator} if necessary. 062 */ 063 @Override 064 public DataAccessException translate(String task, String sql, SQLException ex) { 065 Assert.notNull(ex, "Cannot translate a null SQLException"); 066 if (task == null) { 067 task = ""; 068 } 069 if (sql == null) { 070 sql = ""; 071 } 072 073 DataAccessException dae = doTranslate(task, sql, ex); 074 if (dae != null) { 075 // Specific exception match found. 076 return dae; 077 } 078 079 // Looking for a fallback... 080 SQLExceptionTranslator fallback = getFallbackTranslator(); 081 if (fallback != null) { 082 dae = fallback.translate(task, sql, ex); 083 if (dae != null) { 084 // Fallback exception match found. 085 return dae; 086 } 087 } 088 089 // We couldn't identify it more precisely. 090 return new UncategorizedSQLException(task, sql, ex); 091 } 092 093 /** 094 * Template method for actually translating the given exception. 095 * <p>The passed-in arguments will have been pre-checked. Furthermore, this method 096 * is allowed to return {@code null} to indicate that no exception match has 097 * been found and that fallback translation should kick in. 098 * @param task readable text describing the task being attempted 099 * @param sql the SQL query or update that caused the problem (if known) 100 * @param ex the offending {@code SQLException} 101 * @return the DataAccessException, wrapping the {@code SQLException}; 102 * or {@code null} if no exception match found 103 */ 104 protected abstract DataAccessException doTranslate(String task, String sql, SQLException ex); 105 106 107 /** 108 * Build a message {@code String} for the given {@link java.sql.SQLException}. 109 * <p>To be called by translator subclasses when creating an instance of a generic 110 * {@link org.springframework.dao.DataAccessException} class. 111 * @param task readable text describing the task being attempted 112 * @param sql the SQL statement that caused the problem 113 * @param ex the offending {@code SQLException} 114 * @return the message {@code String} to use 115 */ 116 protected String buildMessage(String task, String sql, SQLException ex) { 117 return task + "; SQL [" + sql + "]; " + ex.getMessage(); 118 } 119 120}