/*
* JBoss, Home of Professional Open Source.
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership. Some portions may be licensed
* to Red Hat, Inc. under one or more contributor license agreements.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301 USA.
*/
package org.teiid.jdbc;
import java.io.IOException;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.NoRouteToHostException;
import java.net.UnknownHostException;
import java.sql.SQLException;
import org.teiid.client.ProcedureErrorInstructionException;
import org.teiid.client.security.InvalidSessionException;
import org.teiid.client.security.LogonException;
import org.teiid.client.util.ExceptionUtil;
import org.teiid.core.TeiidException;
import org.teiid.core.TeiidProcessingException;
import org.teiid.core.TeiidRuntimeException;
import org.teiid.net.CommunicationException;
import org.teiid.net.ConnectionException;
/**
* Teiid specific SQLException
*/
public class TeiidSQLException extends SQLException {
private static final long serialVersionUID = 3672305321346173922L;
private String teiidCode;
/**
* No-arg constructor required by Externalizable semantics.
*/
public TeiidSQLException() {
super();
}
public TeiidSQLException(String reason) {
super(reason, SQLStates.DEFAULT);
}
public TeiidSQLException(String reason, String state) {
super(reason, state);
}
public static TeiidSQLException create(Throwable exception) {
if (exception instanceof TeiidSQLException) {
return (TeiidSQLException)exception;
}
return create(exception, exception.getMessage());
}
public TeiidSQLException(Throwable ex, String reason, String sqlState, int errorCode) {
super(reason, sqlState, errorCode); // passing the message to the super class constructor.
initCause(ex);
}
private TeiidSQLException(SQLException ex, String message, boolean addChildren) {
super(message, ex.getSQLState() == null ? SQLStates.DEFAULT : ex.getSQLState(), ex.getErrorCode(), ex);
if (addChildren) {
SQLException childException = ex.getNextException(); // this a child to the SQLException constructed from reason
while (childException != null) {
if (childException instanceof TeiidSQLException) {
super.setNextException(ex);
break;
}
super.setNextException(new TeiidSQLException(childException, getMessage(childException, null),false));
childException = childException.getNextException();
}
}
}
public static TeiidSQLException create(Throwable exception, String message) {
message = getMessage(exception, message);
Throwable origException = exception;
if (exception instanceof TeiidSQLException
&& message.equals(exception.getMessage())) {
return (TeiidSQLException) exception;
}
if (exception instanceof SQLException) {
return new TeiidSQLException((SQLException) exception, message, true);
}
String sqlState = null;
int errorCode = 0;
SQLException se = ExceptionUtil.getExceptionOfType(exception, SQLException.class);
if (se != null && se.getSQLState() != null) {
sqlState = se.getSQLState();
errorCode = se.getErrorCode();
}
TeiidException te = ExceptionUtil.getExceptionOfType(exception, TeiidException.class);
String code = null;
if (te != null && te.getCode() != null) {
code = te.getCode();
if (errorCode == 0) {
String intPart = code;
if (code.startsWith("TEIID")) { //$NON-NLS-1$
intPart = code.substring(5);
}
try {
errorCode = Integer.valueOf(intPart);
} catch (NumberFormatException e) {
}
}
}
if (sqlState == null) {
exception = findRootException(exception);
sqlState = determineSQLState(exception, sqlState);
}
if (sqlState == null) {
sqlState = SQLStates.DEFAULT;
}
TeiidSQLException tse = new TeiidSQLException(origException, message, sqlState, errorCode);
tse.teiidCode = code;
return tse;
}
/**
* @param exception
* @param sqlState
* @return
*/
private static String determineSQLState(Throwable exception,
String sqlState) {
if (exception instanceof InvalidSessionException) {
sqlState = SQLStates.CONNECTION_EXCEPTION_STALE_CONNECTION;
} else if (exception instanceof LogonException) {
sqlState = SQLStates.INVALID_AUTHORIZATION_SPECIFICATION_NO_SUBCLASS;
} else if (exception instanceof ProcedureErrorInstructionException) {
sqlState = SQLStates.VIRTUAL_PROCEDURE_ERROR;
} else if (exception instanceof TeiidProcessingException) {
sqlState = SQLStates.USAGE_ERROR;
if (SQLStates.QUERY_CANCELED.equals(((TeiidException) exception).getCode())) {
sqlState = SQLStates.QUERY_CANCELED;
}
} else if (exception instanceof UnknownHostException
|| exception instanceof ConnectException
|| exception instanceof MalformedURLException
|| exception instanceof NoRouteToHostException
|| exception instanceof ConnectionException) {
sqlState = SQLStates.CONNECTION_EXCEPTION_SQLCLIENT_UNABLE_TO_ESTABLISH_SQLCONNECTION;
} else if (exception instanceof IOException) {
sqlState = SQLStates.CONNECTION_EXCEPTION_STALE_CONNECTION;
} else if (exception instanceof TeiidException) {
if (exception instanceof CommunicationException) {
sqlState = SQLStates.CONNECTION_EXCEPTION_STALE_CONNECTION;
}
Throwable originalException = exception;
exception = originalException.getCause();
exception = findRootException(exception);
if (exception != null && exception != originalException) {
sqlState = determineSQLState(exception, sqlState);
}
}
return sqlState;
}
/**
* @param exception
* @return
*/
private static Throwable findRootException(Throwable exception) {
if (exception instanceof TeiidRuntimeException) {
while (exception.getCause() != exception
&& exception.getCause() != null) {
exception = exception.getCause();
}
if (exception instanceof TeiidRuntimeException) {
TeiidRuntimeException runtimeException = (TeiidRuntimeException) exception;
while (runtimeException.getCause() != exception
&& runtimeException.getCause() != null) {
if (runtimeException.getCause() instanceof TeiidRuntimeException) {
runtimeException = (TeiidRuntimeException) runtimeException
.getCause();
} else {
exception = runtimeException.getCause();
break;
}
}
}
}
return exception;
}
/**
* @param exception
* @param message
* @return
* @since 4.1
*/
private static String getMessage(Throwable exception,
String message) {
if (message == null) {
message = exception.getMessage();
if (message == null) {
message = exception.getClass().getName();
}
}
return message;
}
/**
* @see org.teiid.jdbc.api.SQLException#isSystemErrorState()
* @since 4.3
*/
public boolean isSystemErrorState() {
return SQLStates.isSystemErrorState(getSQLState());
}
/**
* @see org.teiid.jdbc.api.SQLException#isUsageErrorState()
* @since 4.3
*/
public boolean isUsageErrorState() {
return SQLStates.isUsageErrorState(getSQLState());
}
public String getTeiidCode() {
return teiidCode;
}
}