Cuando una implementación de plug-in de usuario genera una excepción, eXtreme Scale comprueba determinadas excepciones definidas en el contrato throws. Sin embargo, a veces una excepción no comprobada contiene una excepción de contrato o la excepción no observa el contrato adecuadamente. Por lo tanto se necesita un mecanismo para correlacionar la excepción con la excepción de contrato si es posible, por ejemplo ExceptionMapper.
Tenga en cuenta que un JPALoader debe generar una LoaderNotAvailableException cuando el servidor de base de datos o la red no está funcional o la base de datos se queda sin recursos. Sin embargo, normalmente la implementación de proveedor JPA sólo genera una PersistenceException genérica con una SQLException, cuyo estado de SQL o código de error puede indicar el problema de servidor de base de datos o el problema de red. Para complicar adicionalmente la situación, diferentes bases de datos tienen códigos de error y de estado de SQL diferentes para esos problemas. Por lo tanto, el mecanismo de correlación de excepciones debe ser específico de la base de datos.
Se utiliza la Interfaz ExceptionMapper para solucionar el problema. Tiene un método Throwable map(Throwable original) para correlacionar la excepción original con una excepción consumible.
Por ejemplo, para resolver el problema indicado, la clase de implementación puede inspeccionar el estado de SQL y el código de error de java.sql.SQLException encadenados en la excepción JPA. A continuación, puede generar una LoaderNotAvailableException si el estado de SQL y el código de error indican que el servidor de base de datos o la red no está funcional o si la base de datos se queda sin recursos.
Actualmente, el bean ExceptionMapper sólo se puede configurar en los beans JPATxCallback ObjectGrid. Se utiliza para correlacionar todas las excepciones recibidas desde los beans JPATxCallback y JPALoader o JPAEntityLoader.
Para configurar un ExceptionMapper, debe utilizar una configuración de estilo Spring para el bean ExceptionMapper dentro del bean JPATxCallback.
Consulte Configuración de cargadores JPA para obtener información sobre cómo utilizar la configuración de estilo Spring para un JPALoader.
A continuación se proporciona un ejemplo en el que se correlacionan las excepciones JPA con una LoaderNotAvailableException si ésta indica un problema de servidor de base de datos o un problema de red. Esta implementación ExceptionMapper es para utilizar un proveedor JPA con una base de datos MSSQL. En primer lugar, defina un conjunto de códigos de error de SQL y estados de SQL que indiquen el problema de red o el problema de servidor de base de datos en concreto. En el método de correlación, en primer lugar compruebe el código de error de SQL con una lista de códigos de error conocidos, a continuación los estados de SQL y finalmente el mensaje. Si uno de ellos coincide, genere una LoaderNotAvaliableException.
public class JPAMSSQLExceptionMapper implements ExceptionMapper {
static Set<Integer> loaderNotAvailableSQLErrorSet = new HashSet<Integer>();
static Set<String> loaderNotAvailableSQLStateSet = new HashSet<String>();
static {
addInitialMaps();
}
public C3P0MSSQLExceptionMapper() {
System.out.println("C3P0MSSQLExceptionMapper is constructed");
}
/**
* @internal
* Este método se utiliza para añadir correlaciones iniciales al hash, se utiliza
* internamente y no es para la vista pública
*/
private static void addInitialMaps() {
// http://msdn.microsoft.com/en-us/library/cc645603.aspx
loaderNotAvailableSQLErrorSet.add(new Integer(230));
loaderNotAvailableSQLErrorSet.add(new Integer(6002));
// http://white-box.us/2009/03/08/sql-92-sqlstate-codes/
/*
* 08001 el cliente SQL no puede establecer la conexión SQL
* 08002 nombre de conexión en uso
* 08003 la conexión no existe
* 08004 el servidor SQL ha rechazado la conexión SQL
* 08006 anomalía de conexión
* 08007 resolución de transacción desconocida
*/
loaderNotAvailableSQLStateSet.add("08000");
loaderNotAvailableSQLStateSet.add("08001");
loaderNotAvailableSQLStateSet.add("08002");
loaderNotAvailableSQLStateSet.add("08003");
loaderNotAvailableSQLStateSet.add("08004");
loaderNotAvailableSQLStateSet.add("08006");
loaderNotAvailableSQLStateSet.add("08007");
// http://msdn.microsoft.com/en-us/library/ms714687.aspx
loaderNotAvailableSQLStateSet.add("08S01");
loaderNotAvailableSQLStateSet.add("HY000");
}
private static Pattern[] sqlServerMessagePatterns = new Pattern[] {
Pattern.compile("La conexión TCP/IP con el host .* ha fallado.*"), Pattern.compile(".*Restablecimiento de conexión.*") };
private static Pattern[] sqlExceptionMessagePatterns = new Pattern[] { Pattern
.compile(".*No se han podido adquirir conexiones de la base de datos subyacente.*") };
private static String connection_reset = "Restablecimiento de conexión";
public Throwable map(Throwable originalEx) {
Throwable cause = originalEx;
while (cause != null) {
// mantener el bucle para comprobar la siguiente excepción encadenada
if (cause instanceof SQLException) {
// Sólo comprobar si la excepción es SQLException
SQLException sqle = (SQLException) cause;
// Si el conjunto de estados de SQL no disponible del cargador contiene este estado SQL, entonces
// devolvemos una LoaderNotAvailableException con la excepción original encadenada en ella.
if (loaderNotAvailableSQLStateSet.contains(sqle.getSQLState())) {
return new LoaderNotAvailableException(originalEx);
}
// Si el conjunto de códigos de error de SQL no disponible del cargador contiene este código de error, entonces
// devolvemos un LoaderNotAvailableException con la excepción original encadenada en ella
if (loaderNotAvailableSQLErrorSet.contains(new Integer(sqle.getErrorCode()))) {
return new LoaderNotAvailableException(originalEx);
}
String msg = sqle.getMessage();
for (int i=0; i<sqlExceptionMessagePatterns.length; i++) {
if (sqlExceptionMessagePatterns[i].matcher(msg).matches()) {
return new LoaderNotAvailableException(originalEx);
}
}
} else if (cause.getClass().getName().equals("com.microsoft.sqlserver.jdbc.SQLServerException")) {
String msg = cause.getMessage();
for (int i=0; i<sqlServerMessagePatterns.length; i++) {
if (sqlServerMessagePatterns[i].matcher(msg).matches()) {
return new LoaderNotAvailableException(originalEx);
}
}
System.out.println("msg " + msg + " does not match");
}
// Obtener la siguiente excepción encadenada
Throwable newCause = cause.getCause();
// Comprobar de forma segura para evitar un bucle indefinido si la excepción se encadena a sí misma
if (newCause == cause) {
// Devolver siempre la excepción original si no se puede correlacionar.
return originalEx;
} else {
cause = newCause;
}
}
// Devolver siempre la excepción original si no se puede correlacionar.
return originalEx;
}