Skip to content

Commit

Permalink
DERBY-6253: Collapse SQLException factories
Browse files Browse the repository at this point in the history
- Move functionality from SQLExceptionFactory40 to SQLExceptionFactory

- Move logic for retrieving the exception factory from Util to
  ExceptionFactory in order to reduce compile-time dependencies on
  impl classes from iapi classes

- Use varargs in Util's helper methods in order to reduce the number
  of methods

git-svn-id: https://svn.apache.org/repos/asf/db/derby/code/trunk@1493701 13f79535-47bb-0310-9956-ffa450edef68
  • Loading branch information
kahatlen committed Jun 17, 2013
1 parent 91405af commit aa5c5de
Show file tree
Hide file tree
Showing 15 changed files with 136 additions and 285 deletions.
5 changes: 2 additions & 3 deletions java/drda/org/apache/derby/impl/drda/DRDAConnThread.java
Expand Up @@ -1380,8 +1380,7 @@ private boolean isAuthenticationException (SQLException sqlException) {
boolean authFail = false;

// get exception which carries Derby messageID and args
SQLException se = Util.getExceptionFactory().
getArgumentFerry(sqlException);
SQLException se = StandardException.getArgumentFerry(sqlException);

if (se instanceof EmbedSQLException) {
// DERBY-3060: if this is an EmbedSQLException, we can
Expand Down Expand Up @@ -6446,7 +6445,7 @@ private String buildSqlerrmc (SQLException se)
String sqlerrmc;

// get exception which carries Derby messageID and args, per DERBY-1178
se = Util.getExceptionFactory().getArgumentFerry( se );
se = StandardException.getArgumentFerry( se );

if (se instanceof EmbedSQLException && ! severe) {
sqlerrmc = buildTokenizedSqlerrmc(se);
Expand Down
14 changes: 1 addition & 13 deletions java/engine/org/apache/derby/iapi/jdbc/BrokeredConnection.java
Expand Up @@ -47,9 +47,6 @@ public abstract class BrokeredConnection implements EngineConnection
protected boolean isClosed;
private String connString;

/** Exception factory for the underlying connection. */
private final ExceptionFactory exceptionFactory;

/**
Maintain state as seen by this Connection handle, not the state
of the underlying Connection it is attached to.
Expand All @@ -68,8 +65,6 @@ public BrokeredConnection(BrokeredConnectionControl control)
throws SQLException
{
this.control = control;
this.exceptionFactory =
control.getRealConnection().getExceptionFactory();
}

// JDBC 2.0 methods
Expand Down Expand Up @@ -505,7 +500,7 @@ public final PreparedStatement prepareStatement(
* @return a no-current-connection exception
*/
final SQLException noCurrentConnection() {
return exceptionFactory.getSQLException(
return ExceptionFactory.getInstance().getSQLException(
SQLState.NO_CURRENT_CONNECTION, null, null, null);
}

Expand Down Expand Up @@ -773,13 +768,6 @@ public void resetFromPool()
getRealConnection().resetFromPool();
}

/**
* Return the exception factory for the underlying connection.
*/
public final ExceptionFactory getExceptionFactory() {
return exceptionFactory;
}

////////////////////////////////////////////////////////////////////
//
// INTRODUCED BY JDBC 4.1 IN JAVA 7
Expand Down
Expand Up @@ -320,7 +320,7 @@ public final <T> T unwrap(java.lang.Class<T> interfaces)
try {
return interfaces.cast(this);
} catch (ClassCastException cce) {
throw getExceptionFactory().getSQLException(
throw ExceptionFactory.getInstance().getSQLException(
SQLState.UNABLE_TO_UNWRAP, null, null,
new Object[]{ interfaces });
}
Expand Down
4 changes: 2 additions & 2 deletions java/engine/org/apache/derby/iapi/jdbc/BrokeredStatement.java
Expand Up @@ -582,7 +582,7 @@ protected final void checkIfClosed()
throws SQLException
{
if (isClosed()) {
throw control.getExceptionFactory().getSQLException(
throw ExceptionFactory.getInstance().getSQLException(
SQLState.ALREADY_CLOSED, null, null,
new Object[]{ "Statement" });
}
Expand All @@ -596,7 +596,7 @@ protected final void checkIfClosed()
* @return an exception indicating that unwrap failed
*/
final SQLException unableToUnwrap(Class iface) {
return control.getExceptionFactory().getSQLException(
return ExceptionFactory.getInstance().getSQLException(
SQLState.UNABLE_TO_UNWRAP, null, null,
new Object[]{ iface });
}
Expand Down
Expand Up @@ -80,10 +80,4 @@ public interface BrokeredStatementControl
@param s Statement that created the ResultSet.
*/
public ResultSet wrapResultSet(Statement s, ResultSet rs);

/**
* Return the exception factory for the underlying connection.
* @return an exception factory instance
*/
public ExceptionFactory getExceptionFactory();
}
9 changes: 0 additions & 9 deletions java/engine/org/apache/derby/iapi/jdbc/EngineConnection.java
Expand Up @@ -21,7 +21,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more
package org.apache.derby.iapi.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.SQLWarning;

Expand Down Expand Up @@ -110,14 +109,6 @@ public void addWarning(SQLWarning newWarning)
*/
public void resetFromPool() throws SQLException;

/**
* Return an exception factory that could be used to generate
* {@code SQLException}s raised by this connection.
*
* @return an exception factory instance
*/
public ExceptionFactory getExceptionFactory();

////////////////////////////////////////////////////////////////////
//
// INTRODUCED BY JDBC 4.1 IN JAVA 7
Expand Down
46 changes: 30 additions & 16 deletions java/engine/org/apache/derby/iapi/jdbc/ExceptionFactory.java
Expand Up @@ -26,20 +26,35 @@ Licensed to the Apache Software Foundation (ASF) under one or more
/**
* An exception factory is used to create SQLExceptions of the correct type.
*/
public interface ExceptionFactory {
public abstract class ExceptionFactory {

/** The singleton ExceptionFactory instance. */
private static final ExceptionFactory INSTANCE;
static {
// Initialize the singleton instance. Use reflection so that there
// is no compile-time dependency on implementation classes from iapi.
// Currently, there is only one implementation. There used to be two;
// one for JDBC 3.0 and lower, and one for JDBC 4.0 and higher. If
// the need for more than one implementation ever arises again, the
// code below should be changed to load the correct factory for the
// run-time platform.
String impl = "org.apache.derby.impl.jdbc.SQLExceptionFactory";
ExceptionFactory factory = null;
try {
factory = (ExceptionFactory) Class.forName(impl).newInstance();
} catch (Exception e) {
throw new ExceptionInInitializerError(e);
}
INSTANCE = factory;
}

/**
* Unpack a SQL exception, looking for an EmbedSQLException which carries
* the Derby messageID and args which we will serialize across DRDA so
* that the client can reconstitute a SQLException with appropriate text.
* If we are running JDBC 3, then we hope that the passed-in
* exception is already an EmbedSQLException, which carries all the
* information we need.
*
* @param se the exception to unpack
* @return the argument ferry for the exception
* Get the singleton exception factory instance.
* @return an {@code ExceptionFactory} instance
*/
SQLException getArgumentFerry(SQLException se);
public static ExceptionFactory getInstance() {
return INSTANCE;
}

/**
* Construct an SQLException whose message and severity are specified
Expand All @@ -53,8 +68,8 @@ public interface ExceptionFactory {
* @param args the message arguments
* @return an SQLException
*/
SQLException getSQLException(String message, String messageId,
SQLException next, int severity, Throwable cause, Object[] args);
public abstract SQLException getSQLException(String message, String messageId,
SQLException next, int severity, Throwable cause, Object... args);

/**
* Construct an SQLException whose message and severity are derived from
Expand All @@ -66,7 +81,6 @@ SQLException getSQLException(String message, String messageId,
* @param args the message arguments
* @return an SQLException
*/
SQLException getSQLException(String messageId, SQLException next,
Throwable cause, Object[] args);

public abstract SQLException getSQLException(String messageId,
SQLException next, Throwable cause, Object... args);
}
6 changes: 0 additions & 6 deletions java/engine/org/apache/derby/impl/jdbc/EmbedConnection.java
Expand Up @@ -88,7 +88,6 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import java.util.concurrent.Executor;

import org.apache.derby.iapi.jdbc.EngineLOB;
import org.apache.derby.iapi.jdbc.ExceptionFactory;
import org.apache.derby.iapi.jdbc.FailedProperties40;
import org.apache.derby.iapi.reference.Limits;
import org.apache.derby.iapi.sql.conn.StatementContext;
Expand Down Expand Up @@ -3184,11 +3183,6 @@ final int getResultSetOrderId() {
}
}

/** Get the exception factory for this connection. */
public ExceptionFactory getExceptionFactory() {
return Util.getExceptionFactory();
}

protected static SQLException newSQLException(String messageId) {
return Util.generateCsSQLException(messageId);
}
Expand Down
110 changes: 92 additions & 18 deletions java/engine/org/apache/derby/impl/jdbc/SQLExceptionFactory.java
Expand Up @@ -21,50 +21,124 @@ Licensed to the Apache Software Foundation (ASF) under one or more

package org.apache.derby.impl.jdbc;

import java.sql.SQLDataException;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLIntegrityConstraintViolationException;
import java.sql.SQLInvalidAuthorizationSpecException;
import java.sql.SQLNonTransientConnectionException;
import java.sql.SQLSyntaxErrorException;
import java.sql.SQLTimeoutException;
import java.sql.SQLTransactionRollbackException;
import org.apache.derby.iapi.error.StandardException;
import org.apache.derby.iapi.jdbc.ExceptionFactory;
import org.apache.derby.iapi.services.i18n.MessageService;

import java.sql.SQLException;
import org.apache.derby.shared.common.reference.SQLState;

/**
*Class to create SQLException
*
*/
public class SQLExceptionFactory implements ExceptionFactory {
public class SQLExceptionFactory extends ExceptionFactory {
/**
* <p>
* method to construct SQLException
* version specific drivers can overload this method to create
* version specific exceptions
* </p>
*
* <p>
* This implementation creates JDBC 4 exceptions.
* </p>
*
* <pre>
* SQLSTATE CLASS (prefix) Exception
* 0A java.sql.SQLFeatureNotSupportedException
* 08 java.sql.SQLNonTransientConnectionException
* 22 java.sql.SQLDataException
* 28 java.sql.SQLInvalidAuthorizationSpecException
* 40 java.sql.SQLTransactionRollbackException
* 42 java.sql.SQLSyntaxErrorException
* </pre>
*/
@Override
public SQLException getSQLException(String message, String messageId,
SQLException next, int severity, Throwable t, Object[] args) {
return new EmbedSQLException(message, messageId, next, severity,
t, args);
SQLException next, int severity, Throwable t, Object... args) {
String sqlState = StandardException.getSQLStateFromIdentifier(messageId);

//
// Create dummy exception which ferries arguments needed to serialize
// SQLExceptions across the DRDA network layer.
//
t = wrapArgsForTransportAcrossDRDA( message, messageId, next, severity, t, args );

final SQLException ex;
if (sqlState.startsWith(SQLState.CONNECTIVITY_PREFIX)) {
//no derby sqlstate belongs to
//TransientConnectionException DERBY-3074
ex = new SQLNonTransientConnectionException(message, sqlState, severity, t);
} else if (sqlState.startsWith(SQLState.SQL_DATA_PREFIX)) {
ex = new SQLDataException(message, sqlState, severity, t);
} else if (sqlState.startsWith(SQLState.INTEGRITY_VIOLATION_PREFIX)) {
ex = new SQLIntegrityConstraintViolationException(message, sqlState,
severity, t);
} else if (sqlState.startsWith(SQLState.AUTHORIZATION_SPEC_PREFIX)) {
ex = new SQLInvalidAuthorizationSpecException(message, sqlState,
severity, t);
}
else if (sqlState.startsWith(SQLState.TRANSACTION_PREFIX)) {
ex = new SQLTransactionRollbackException(message, sqlState,
severity, t);
} else if (sqlState.startsWith(SQLState.LSE_COMPILATION_PREFIX)) {
ex = new SQLSyntaxErrorException(message, sqlState, severity, t);
} else if (sqlState.startsWith(SQLState.UNSUPPORTED_PREFIX)) {
ex = new SQLFeatureNotSupportedException(message, sqlState, severity, t);
} else if
(
sqlState.equals(SQLState.LANG_STATEMENT_CANCELLED_OR_TIMED_OUT.substring(0, 5)) ||
sqlState.equals(SQLState.LOGIN_TIMEOUT.substring(0, 5))
) {
ex = new SQLTimeoutException(message, sqlState, severity, t);
} else {
ex = new SQLException(message, sqlState, severity, t);
}

if (next != null) {
ex.setNextException(next);
}
return ex;
}

/**
* Construct an SQLException whose message and severity are derived from
* the message id.
*/
@Override
public final SQLException getSQLException(String messageId,
SQLException next, Throwable cause, Object[] args) {
SQLException next, Throwable cause, Object... args) {
String message = MessageService.getCompleteMessage(messageId, args);
int severity = StandardException.getSeverityFromIdentifier(messageId);
return getSQLException(message, messageId, next, severity, cause, args);
}

/**
* Unpack a SQL exception, looking for an EmbedSQLException which carries
* the Derby messageID and args which we will serialize across DRDA so
* that the client can reconstitute a SQLException with appropriate text.
* If we are running JDBC3 or JDBC2, then we hope that the passed-in
* exception is already an EmbedSQLException, which carries all the
* information we need.
* <p>
* The following method helps handle DERBY-1178. The problem is that we may
* need to serialize our final SQLException across the DRDA network layer.
* That serialization involves some clever encoding of the Derby messageID and
* arguments. Unfortunately, once we create one of the
* JDBC4-specific subclasses of SQLException, we lose the messageID and
* args. This method creates a dummy EmbedSQLException which preserves that
* information. We return the dummy exception.
* </p>
*/
public SQLException getArgumentFerry(SQLException se)
{
return StandardException.getArgumentFerry(se);
}

private SQLException wrapArgsForTransportAcrossDRDA(
String message, String messageId, SQLException next,
int severity, Throwable t, Object[] args) {
return new EmbedSQLException(
message, messageId,
(next == null ?
null : StandardException.getArgumentFerry(next)),
severity, t, args);
}
}

0 comments on commit aa5c5de

Please sign in to comment.