/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2010, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.engine.jdbc.spi;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import org.hibernate.JDBCException;
import org.hibernate.exception.internal.SQLStateConverter;
import org.hibernate.exception.spi.SQLExceptionConverter;
import org.hibernate.exception.spi.ViolatedConstraintNameExtracter;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.jboss.logging.Logger;
import org.jboss.logging.Logger.Level;
Helper for handling SQLExceptions in various manners.
Author: Steve Ebersole
/**
* Helper for handling SQLExceptions in various manners.
*
* @author Steve Ebersole
*/
public class SqlExceptionHelper {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
SqlExceptionHelper.class.getName()
);
private static final String DEFAULT_EXCEPTION_MSG = "SQL Exception";
private static final String DEFAULT_WARNING_MSG = "SQL Warning";
private static final SQLExceptionConverter DEFAULT_CONVERTER = new SQLStateConverter(
new ViolatedConstraintNameExtracter() {
public String extractConstraintName(SQLException e) {
return null;
}
}
);
private SQLExceptionConverter sqlExceptionConverter;
Create an exception helper with a default exception converter.
/**
* Create an exception helper with a default exception converter.
*/
public SqlExceptionHelper() {
sqlExceptionConverter = DEFAULT_CONVERTER;
}
Create an exception helper with a specific exception converter.
Params: - sqlExceptionConverter – The exception converter to use.
/**
* Create an exception helper with a specific exception converter.
*
* @param sqlExceptionConverter The exception converter to use.
*/
public SqlExceptionHelper(SQLExceptionConverter sqlExceptionConverter) {
this.sqlExceptionConverter = sqlExceptionConverter;
}
Access the current exception converter being used internally.
Returns: The current exception converter.
/**
* Access the current exception converter being used internally.
*
* @return The current exception converter.
*/
public SQLExceptionConverter getSqlExceptionConverter() {
return sqlExceptionConverter;
}
Inject the exception converter to use.
NOTE : null is allowed and signifies to use the default.
Params: - sqlExceptionConverter – The converter to use.
/**
* Inject the exception converter to use.
* <p/>
* NOTE : <tt>null</tt> is allowed and signifies to use the default.
*
* @param sqlExceptionConverter The converter to use.
*/
public void setSqlExceptionConverter(SQLExceptionConverter sqlExceptionConverter) {
this.sqlExceptionConverter = (sqlExceptionConverter == null ? DEFAULT_CONVERTER : sqlExceptionConverter);
}
// SQLException ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Convert an SQLException using the current converter, doing some logging first.
Params: - sqlException – The exception to convert
- message – An error message.
Returns: The converted exception
/**
* Convert an SQLException using the current converter, doing some logging first.
*
* @param sqlException The exception to convert
* @param message An error message.
*
* @return The converted exception
*/
public JDBCException convert(SQLException sqlException, String message) {
return convert( sqlException, message, "n/a" );
}
Convert an SQLException using the current converter, doing some logging first.
Params: - sqlException – The exception to convert
- message – An error message.
- sql – The SQL being executed when the exception occurred
Returns: The converted exception
/**
* Convert an SQLException using the current converter, doing some logging first.
*
* @param sqlException The exception to convert
* @param message An error message.
* @param sql The SQL being executed when the exception occurred
*
* @return The converted exception
*/
public JDBCException convert(SQLException sqlException, String message, String sql) {
logExceptions( sqlException, message + " [" + sql + "]" );
return sqlExceptionConverter.convert( sqlException, message, sql );
}
Log the given (and any nested) exception.
Params: - sqlException – The exception to log
- message – The message text to use as a preamble.
/**
* Log the given (and any nested) exception.
*
* @param sqlException The exception to log
* @param message The message text to use as a preamble.
*/
public void logExceptions(SQLException sqlException, String message) {
if ( LOG.isEnabled( Level.ERROR ) ) {
if ( LOG.isDebugEnabled() ) {
message = StringHelper.isNotEmpty( message ) ? message : DEFAULT_EXCEPTION_MSG;
LOG.debug( message, sqlException );
}
final boolean warnEnabled = LOG.isEnabled( Level.WARN );
while ( sqlException != null ) {
if ( warnEnabled ) {
LOG.warn( "SQL Error: " + sqlException.getErrorCode() + ", SQLState: " + sqlException.getSQLState() );
}
LOG.error( sqlException.getMessage() );
sqlException = sqlException.getNextException();
}
}
}
// SQLWarning ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contract for handling warnings
/**
* Contract for handling {@link SQLWarning warnings}
*/
public static interface WarningHandler {
Should processing be done? Allows short-circuiting if not.
Returns: True to process warnings, false otherwise.
/**
* Should processing be done? Allows short-circuiting if not.
*
* @return True to process warnings, false otherwise.
*/
public boolean doProcess();
Prepare for processing of a warning
stack. Note that the warning here is also the first passed to handleWarning
Params: - warning – The first warning in the stack.
/**
* Prepare for processing of a {@link SQLWarning warning} stack.
* <p/>
* Note that the warning here is also the first passed to {@link #handleWarning}
*
* @param warning The first warning in the stack.
*/
public void prepare(SQLWarning warning);
Handle an individual warning in the stack.
Params: - warning – The warning to handle.
/**
* Handle an individual warning in the stack.
*
* @param warning The warning to handle.
*/
public void handleWarning(SQLWarning warning);
}
Basic support for WarningHandler
implementations which handle warnings
/**
* Basic support for {@link WarningHandler} implementations which handle {@link SQLWarning warnings}
*/
public abstract static class WarningHandlerLoggingSupport implements WarningHandler {
@Override
public final void handleWarning(SQLWarning warning) {
logWarning(
"SQL Warning Code: " + warning.getErrorCode() + ", SQLState: " + warning.getSQLState(),
warning.getMessage()
);
}
Delegate to log common details of a warning
Params: - description – A description of the warning
- message – The warning message
/**
* Delegate to log common details of a {@link SQLWarning warning}
*
* @param description A description of the warning
* @param message The warning message
*/
protected abstract void logWarning(String description, String message);
}
Standard SQLWarning handler for logging warnings
/**
* Standard SQLWarning handler for logging warnings
*/
public static class StandardWarningHandler extends WarningHandlerLoggingSupport {
private final String introMessage;
Creates a StandardWarningHandler
Params: - introMessage – The introduction message for the hierarchy
/**
* Creates a StandardWarningHandler
*
* @param introMessage The introduction message for the hierarchy
*/
public StandardWarningHandler(String introMessage) {
this.introMessage = introMessage;
}
@Override
public boolean doProcess() {
return LOG.isEnabled( Level.WARN );
}
@Override
public void prepare(SQLWarning warning) {
LOG.debug( introMessage, warning );
}
@Override
protected void logWarning(
String description,
String message) {
LOG.warn( description );
LOG.warn( message );
}
}
Static access to the standard handler for logging warnings
/**
* Static access to the standard handler for logging warnings
*/
public static final StandardWarningHandler STANDARD_WARNING_HANDLER = new StandardWarningHandler( DEFAULT_WARNING_MSG );
Generic algorithm to walk the hierarchy of SQLWarnings
Params: - warning – The warning to walk
- handler – The handler
/**
* Generic algorithm to walk the hierarchy of SQLWarnings
*
* @param warning The warning to walk
* @param handler The handler
*/
public void walkWarnings(
SQLWarning warning,
WarningHandler handler) {
if ( warning == null || !handler.doProcess() ) {
return;
}
handler.prepare( warning );
while ( warning != null ) {
handler.handleWarning( warning );
warning = warning.getNextWarning();
}
}
Standard (legacy) behavior for logging warnings associated with a JDBC Connection
and clearing them. Calls handleAndClearWarnings(Connection, WarningHandler)
using STANDARD_WARNING_HANDLER
Params: - connection – The JDBC connection potentially containing warnings
/**
* Standard (legacy) behavior for logging warnings associated with a JDBC {@link Connection} and clearing them.
* <p/>
* Calls {@link #handleAndClearWarnings(Connection, WarningHandler)} using {@link #STANDARD_WARNING_HANDLER}
*
* @param connection The JDBC connection potentially containing warnings
*/
public void logAndClearWarnings(Connection connection) {
handleAndClearWarnings( connection, STANDARD_WARNING_HANDLER );
}
public void logAndClearWarnings(Statement statement) {
handleAndClearWarnings( statement, STANDARD_WARNING_HANDLER );
}
General purpose handling of warnings associated with a JDBC Connection
. Params: - connection – The JDBC connection potentially containing warnings
- handler – The handler for each individual warning in the stack.
See Also:
/**
* General purpose handling of warnings associated with a JDBC {@link Connection}.
*
* @param connection The JDBC connection potentially containing warnings
* @param handler The handler for each individual warning in the stack.
*
* @see #walkWarnings
*/
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
public void handleAndClearWarnings(
Connection connection,
WarningHandler handler) {
try {
walkWarnings( connection.getWarnings(), handler );
}
catch (SQLException sqle) {
// workaround for WebLogic
LOG.debug( "could not log warnings", sqle );
}
try {
// Sybase fail if we don't do that, sigh...
connection.clearWarnings();
}
catch (SQLException sqle) {
LOG.debug( "could not clear warnings", sqle );
}
}
General purpose handling of warnings associated with a JDBC Statement
. Params: - statement – The JDBC statement potentially containing warnings
- handler – The handler for each individual warning in the stack.
See Also:
/**
* General purpose handling of warnings associated with a JDBC {@link Statement}.
*
* @param statement The JDBC statement potentially containing warnings
* @param handler The handler for each individual warning in the stack.
*
* @see #walkWarnings
*/
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
public void handleAndClearWarnings(
Statement statement,
WarningHandler handler) {
// See HHH-9174. Statement#getWarnings can be an expensive call for many JDBC libs. Don't do it unless
// the log level would actually allow a warning to be logged.
if (LOG.isEnabled(Level.WARN)) {
try {
walkWarnings( statement.getWarnings(), handler );
}
catch (SQLException sqlException) {
// workaround for WebLogic
LOG.debug( "could not log warnings", sqlException );
}
}
try {
// Sybase fail if we don't do that, sigh...
statement.clearWarnings();
}
catch (SQLException sqle) {
LOG.debug( "could not clear warnings", sqle );
}
}
}