@Override protected DataAccessException doTranslate(String task, String sql, SQLException ex) { String sqlState = getSqlState(ex); if (sqlState != null && sqlState.length() >= 2) { String classCode = sqlState.substring(0, 2); if (logger.isDebugEnabled()) { logger.debug("Extracted SQL state class '" + classCode + "' from value '" + sqlState + "'"); } if (BAD_SQL_GRAMMAR_CODES.contains(classCode)) { return new BadSqlGrammarException(task, sql, ex); } else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) { return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); } else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) { return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); } else if (CONCURRENCY_FAILURE_CODES.contains(classCode)) { return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); } } return null; }
@Test @SuppressWarnings("resource") public void customErrorCodeTranslation() { new ClassPathXmlApplicationContext("test-custom-translators-context.xml", CustomSQLExceptionTranslatorRegistrarTests.class); SQLErrorCodes codes = SQLErrorCodesFactory.getInstance().getErrorCodes("H2"); SQLErrorCodeSQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(); sext.setSqlErrorCodes(codes); DataAccessException exFor4200 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 42000)); assertNotNull("Should have been translated", exFor4200); assertTrue("Should have been instance of BadSqlGrammarException", BadSqlGrammarException.class.isAssignableFrom(exFor4200.getClass())); DataAccessException exFor2 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 2)); assertNotNull("Should have been translated", exFor2); assertTrue("Should have been instance of TransientDataAccessResourceException", TransientDataAccessResourceException.class.isAssignableFrom(exFor2.getClass())); DataAccessException exFor3 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 3)); assertNull("Should not have been translated", exFor3); }
@Test(expected = TransientDataAccessResourceException.class) public void testNonSpringTxFactoryWithTx() throws Exception { Environment original = sqlSessionFactory.getConfiguration().getEnvironment(); Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource,null); sqlSessionFactory.getConfiguration().setEnvironment(nonSpring); TransactionStatus status = null; try { status = txManager.getTransaction(new DefaultTransactionDefinition()); session = SqlSessionUtils.getSqlSession(sqlSessionFactory); fail("should not be able to get an SqlSession using non-Spring tx manager when there is an active Spring tx"); } finally { // rollback required to close connection txManager.rollback(status); sqlSessionFactory.getConfiguration().setEnvironment(original); } }
@Test(expected = TransientDataAccessResourceException.class) public void testChangeExecutorTypeInTx() throws Exception { TransactionStatus status = null; try { status = txManager.getTransaction(new DefaultTransactionDefinition()); session = SqlSessionUtils.getSqlSession(sqlSessionFactory); session = SqlSessionUtils.getSqlSession(sqlSessionFactory, ExecutorType.BATCH, exceptionTranslator); fail("should not be able to change the Executor type during an existing transaction"); } finally { SqlSessionUtils.closeSqlSession(session, sqlSessionFactory); // rollback required to close connection txManager.rollback(status); } }
@Test(expected = TransientDataAccessResourceException.class) public void testNonSpringTxMgrWithTx() throws Exception { Environment original = sqlSessionFactory.getConfiguration().getEnvironment(); Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource,null); sqlSessionFactory.getConfiguration().setEnvironment(nonSpring); TransactionStatus status = null; try { status = txManager.getTransaction(new DefaultTransactionDefinition()); find(); fail("should not be able to get an SqlSession using non-Spring tx manager when there is an active Spring tx"); } finally { // rollback required to close connection txManager.rollback(status); sqlSessionFactory.getConfiguration().setEnvironment(original); } }
@Test public void testCustomErrorCodeTranslation() { SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 1); DataAccessException daeex = sext.translate("task", "SQL", dataIntegrityViolationEx); assertEquals(dataIntegrityViolationEx, daeex.getCause()); assertTrue(daeex instanceof BadSqlGrammarException); SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 2); DataAccessException darex = sext.translate("task", "SQL", dataAccessResourceEx); assertEquals(dataIntegrityViolationEx, daeex.getCause()); assertTrue(darex instanceof TransientDataAccessResourceException); }
@Test public void testCustomErrorCodeTranslation() { SQLErrorCodes codes = SQLErrorCodesFactory.getInstance().getErrorCodes("H2"); SQLErrorCodeSQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(); sext.setSqlErrorCodes(codes); DataAccessException exFor4200 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 42000)); assertNotNull("Should have been translated", exFor4200); assertTrue("Should have been instance of BadSqlGrammarException", BadSqlGrammarException.class.isAssignableFrom(exFor4200.getClass())); DataAccessException exFor2 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 2)); assertNotNull("Should have been translated", exFor2); assertTrue("Should have been instance of TransientDataAccessResourceException", TransientDataAccessResourceException.class.isAssignableFrom(exFor2.getClass())); DataAccessException exFor3 = sext.doTranslate("", "", new SQLException("Ouch", "42000", 3)); assertNull("Should not have been translated", exFor3); }
@Test(expected = TransientDataAccessResourceException.class) public void testNonSpringTxFactoryWithTx() throws Exception { Environment original = sqlSessionFactory.getConfiguration().getEnvironment(); Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource); sqlSessionFactory.getConfiguration().setEnvironment(nonSpring); TransactionStatus status = null; try { status = txManager.getTransaction(new DefaultTransactionDefinition()); session = SqlSessionUtils.getSqlSession(sqlSessionFactory); fail("should not be able to get an SqlSession using non-Spring tx manager when there is an active Spring tx"); } finally { // rollback required to close connection txManager.rollback(status); sqlSessionFactory.getConfiguration().setEnvironment(original); } }
@Test(expected = TransientDataAccessResourceException.class) public void testNonSpringTxMgrWithTx() throws Exception { Environment original = sqlSessionFactory.getConfiguration().getEnvironment(); Environment nonSpring = new Environment("non-spring", new JdbcTransactionFactory(), dataSource); sqlSessionFactory.getConfiguration().setEnvironment(nonSpring); TransactionStatus status = null; try { status = txManager.getTransaction(new DefaultTransactionDefinition()); find(); fail("should not be able to get an SqlSession using non-Spring tx manager when there is an active Spring tx"); } finally { // rollback required to close connection txManager.rollback(status); sqlSessionFactory.getConfiguration().setEnvironment(original); } }
public static RuntimeException doTranslate(final Exception ex) { if (ex instanceof JpoException) { throw (JpoException) ex; } if (ex instanceof BadSqlGrammarException) { return new JpoSqlBadGrammarException(ex); } else if (ex instanceof DataIntegrityViolationException) { return new JpoSqlDataIntegrityViolationException(ex); } else if (ex instanceof DataAccessResourceFailureException) { return new JpoSqlDataAccessResourceFailureException(ex); } else if (ex instanceof TransientDataAccessResourceException) { return new JpoSqlTransientDataAccessResourceException(ex); } else if (ex instanceof ConcurrencyFailureException) { return new JpoSqlConcurrencyFailureException(ex); } else if (ex instanceof TransactionTimedOutException) { return new JpoTransactionTimedOutException(ex); } return new JpoSqlException(ex); }
@Test public void canRetry_retryPossibleDueToAvailableDatabase_returnsTrue() throws Exception { //Arrange AmazonRDS amazonRDS = mock(AmazonRDS.class); DatabaseInstanceStatusRetryPolicy policy = new DatabaseInstanceStatusRetryPolicy(amazonRDS, "test"); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))). thenReturn(new DescribeDBInstancesResult().withDBInstances(new DBInstance().withDBInstanceStatus("available"))); RetryContext retryContext = policy.open(new RetryContextSupport(null)); //Act policy.registerThrowable(retryContext, new TransientDataAccessResourceException("not available")); //Assert assertTrue(policy.canRetry(retryContext)); policy.close(retryContext); }
@Test public void canRetry_withResourceIdResolver_returnsTrue() throws Exception { //Arrange AmazonRDS amazonRDS = mock(AmazonRDS.class); ResourceIdResolver resourceIdResolver = mock(ResourceIdResolver.class); DatabaseInstanceStatusRetryPolicy policy = new DatabaseInstanceStatusRetryPolicy(amazonRDS, "foo"); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))). thenReturn(new DescribeDBInstancesResult().withDBInstances(new DBInstance().withDBInstanceStatus("available"))); when(resourceIdResolver.resolveToPhysicalResourceId("foo")).thenReturn("test"); policy.setResourceIdResolver(resourceIdResolver); RetryContext retryContext = policy.open(new RetryContextSupport(null)); //Act policy.registerThrowable(retryContext, new TransientDataAccessResourceException("not available")); //Assert assertTrue(policy.canRetry(retryContext)); policy.close(retryContext); }
@Test public void canRetry_retryNotPossibleDueToNoDatabase_returnsFalse() throws Exception { //Arrange AmazonRDS amazonRDS = mock(AmazonRDS.class); DatabaseInstanceStatusRetryPolicy policy = new DatabaseInstanceStatusRetryPolicy(amazonRDS, "test"); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))). thenThrow(new DBInstanceNotFoundException("test")); RetryContext retryContext = policy.open(new RetryContextSupport(null)); //Act policy.registerThrowable(retryContext, new TransientDataAccessResourceException("not available")); //Assert assertFalse(policy.canRetry(retryContext)); policy.close(retryContext); }
@Test public void canRetry_multipleDatabasesFoundForInstanceIdentifier_reportsException() throws Exception { //Arrange this.expectedException.expect(IllegalStateException.class); this.expectedException.expectMessage("Multiple databases found for same identifier"); AmazonRDS amazonRDS = mock(AmazonRDS.class); DatabaseInstanceStatusRetryPolicy policy = new DatabaseInstanceStatusRetryPolicy(amazonRDS, "test"); DescribeDBInstancesResult describeDBInstancesResult = new DescribeDBInstancesResult().withDBInstances(new DBInstance(), new DBInstance()); when(amazonRDS.describeDBInstances(new DescribeDBInstancesRequest().withDBInstanceIdentifier("test"))). thenReturn(describeDBInstancesResult); RetryContext retryContext = policy.open(new RetryContextSupport(null)); //Act policy.registerThrowable(retryContext, new TransientDataAccessResourceException("not available")); //Assert policy.canRetry(retryContext); }
@Test public void discountTaskletWithRetryTemplateOk() throws Exception { DiscountsWithRetryTemplateTasklet tasklet = new DiscountsWithRetryTemplateTasklet(); DiscountService service = mock(DiscountService.class); DiscountsHolder holder = new DiscountsHolder(); tasklet.setDiscountService(service); tasklet.setDiscountsHolder(holder); List<Discount> discounts = new ArrayList<Discount>(); discounts.add(new Discount()); // HINT: Mockito를 이용하여, 두번의 실퍠 후 성공하는 가상 시나리오를 제작합니다. when(service.getDiscounts()) .thenThrow(new TransientDataAccessResourceException("")) .thenThrow(new TransientDataAccessResourceException("")) .thenReturn(discounts); RepeatStatus status = tasklet.execute(null, null); assertThat(status).isEqualTo(RepeatStatus.FINISHED); assertThat(holder.getDiscounts()).isEqualTo(discounts); }
@Test(expected = TransientDataAccessResourceException.class) public void discountTaskletWithRetryTemplateRetryExhausted() throws Exception { DiscountsWithRetryTemplateTasklet tasklet = new DiscountsWithRetryTemplateTasklet(); DiscountService service = mock(DiscountService.class); DiscountsHolder holder = new DiscountsHolder(); tasklet.setDiscountService(service); tasklet.setDiscountsHolder(holder); List<Discount> discounts = new ArrayList<Discount>(); discounts.add(new Discount()); when(service.getDiscounts()) .thenThrow(new TransientDataAccessResourceException("")) .thenThrow(new TransientDataAccessResourceException("")) .thenThrow(new TransientDataAccessResourceException("")) .thenReturn(discounts); tasklet.execute(null, null); }
@Test public void transparentRetry() throws Exception { List<Discount> discounts = new ArrayList<Discount>(); discounts.add(new Discount()); when(discountService.getDiscounts()) .thenThrow(new TransientDataAccessResourceException("")) .thenReturn(discounts) .thenThrow(new TransientDataAccessResourceException("")) .thenThrow(new TransientDataAccessResourceException("")) .thenReturn(discounts); RepeatStatus status = discountsTasklet.execute(null, null); assertThat(status).isEqualTo(RepeatStatus.FINISHED); assertThat(discountsHolder.getDiscounts()).isSameAs(discounts); try { discountsTasklet.execute(null, null); Assert.fail(); } catch (TransientDataAccessResourceException e) { // OK } }
@Override protected DataAccessException doTranslate(String task, String sql, SQLException ex) { if (ex instanceof SQLTransientException) { if (ex instanceof SQLTransientConnectionException) { return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLTransactionRollbackException) { return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLTimeoutException) { return new QueryTimeoutException(buildMessage(task, sql, ex), ex); } } else if (ex instanceof SQLNonTransientException) { if (ex instanceof SQLNonTransientConnectionException) { return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLDataException) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLIntegrityConstraintViolationException) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLInvalidAuthorizationSpecException) { return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLSyntaxErrorException) { return new BadSqlGrammarException(task, sql, ex); } else if (ex instanceof SQLFeatureNotSupportedException) { return new InvalidDataAccessApiUsageException(buildMessage(task, sql, ex), ex); } } else if (ex instanceof SQLRecoverableException) { return new RecoverableDataAccessException(buildMessage(task, sql, ex), ex); } // Fallback to Spring's own SQL state translation... return null; }
@DataProvider public Object[][] statuses() { TitanMigrationManager happyMigrationManager = new TitanMigrationManager(); TitanMigrationManager sadMigrationManager = new TitanMigrationManager(); Whitebox.setInternalState(happyMigrationManager, IS_MIGRATION_COMPLETE_FIELD_NAME, true); Whitebox.setInternalState(sadMigrationManager, IS_MIGRATION_COMPLETE_FIELD_NAME, false); return new Object[][] { new Object[] { mockDbWithUp(), Status.UP, AcsMonitoringUtilities.HealthCode.AVAILABLE, happyMigrationManager }, { mockDbWithException(new TransientDataAccessResourceException("")), Status.DOWN, AcsMonitoringUtilities.HealthCode.UNAVAILABLE, happyMigrationManager }, { mockDbWithException(new QueryTimeoutException("")), Status.DOWN, AcsMonitoringUtilities.HealthCode.UNAVAILABLE, happyMigrationManager }, { mockDbWithException(new DataSourceLookupFailureException("")), Status.DOWN, AcsMonitoringUtilities.HealthCode.UNREACHABLE, happyMigrationManager }, { mockDbWithException(new PermissionDeniedDataAccessException("", null)), Status.DOWN, AcsMonitoringUtilities.HealthCode.MISCONFIGURATION, happyMigrationManager }, { mockDbWithException(new ConcurrencyFailureException("")), Status.DOWN, AcsMonitoringUtilities.HealthCode.ERROR, happyMigrationManager }, { mockDbWithUp(), Status.DOWN, AcsMonitoringUtilities.HealthCode.MIGRATION_INCOMPLETE, sadMigrationManager }, }; }
@Override protected DataAccessException doTranslate(String task, String sql, SQLException ex) { // First, the getSQLState check... String sqlState = getSqlState(ex); if (sqlState != null && sqlState.length() >= 2) { String classCode = sqlState.substring(0, 2); if (logger.isDebugEnabled()) { logger.debug("Extracted SQL state class '" + classCode + "' from value '" + sqlState + "'"); } if (BAD_SQL_GRAMMAR_CODES.contains(classCode)) { return new BadSqlGrammarException(task, sql, ex); } else if (DATA_INTEGRITY_VIOLATION_CODES.contains(classCode)) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (DATA_ACCESS_RESOURCE_FAILURE_CODES.contains(classCode)) { return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); } else if (TRANSIENT_DATA_ACCESS_RESOURCE_CODES.contains(classCode)) { return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); } else if (CONCURRENCY_FAILURE_CODES.contains(classCode)) { return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); } } // For MySQL: exception class name indicating a timeout? // (since MySQL doesn't throw the JDBC 4 SQLTimeoutException) if (ex.getClass().getName().contains("Timeout")) { return new QueryTimeoutException(buildMessage(task, sql, ex), ex); } // Couldn't resolve anything proper - resort to UncategorizedSQLException. return null; }
@Test public void dataAccessResourceException() { SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 2); DataAccessException dae = sext.translate("task", "SQL", dataAccessResourceEx); assertEquals(dataAccessResourceEx, dae.getCause()); assertThat(dae, instanceOf(TransientDataAccessResourceException.class)); }
@Override public DataAccessException translate(String task, String sql, SQLException ex) { if (ex.getErrorCode() == 2) { return new TransientDataAccessResourceException("Custom", ex); } return null; }
@Override protected DataAccessException doTranslate(String task, String sql, SQLException ex) { if (ex instanceof SQLTransientException) { if (ex instanceof SQLTransactionRollbackException) { return new ConcurrencyFailureException(buildMessage(task, sql, ex), ex); } if (ex instanceof SQLTransientConnectionException) { return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex); } if (ex instanceof SQLTimeoutException) { return new QueryTimeoutException(buildMessage(task, sql, ex), ex); } } else if (ex instanceof SQLNonTransientException) { if (ex instanceof SQLDataException) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLFeatureNotSupportedException) { return new InvalidDataAccessApiUsageException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLIntegrityConstraintViolationException) { return new DataIntegrityViolationException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLInvalidAuthorizationSpecException) { return new PermissionDeniedDataAccessException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLNonTransientConnectionException) { return new DataAccessResourceFailureException(buildMessage(task, sql, ex), ex); } else if (ex instanceof SQLSyntaxErrorException) { return new BadSqlGrammarException(task, sql, ex); } } else if (ex instanceof SQLRecoverableException) { return new RecoverableDataAccessException(buildMessage(task, sql, ex), ex); } // Fallback to Spring's own SQL state translation... return null; }
@Test public void testRetryTransientExceptions() throws Exception { SqlRetryPolicy sqlRetryPolicy = new SqlRetryPolicy(); RetryContextSupport retryContext = new RetryContextSupport(null); retryContext.registerThrowable(new SQLTransientException("foo")); assertTrue(sqlRetryPolicy.canRetry(retryContext)); retryContext.registerThrowable(new TransientDataAccessResourceException("foo")); assertTrue(sqlRetryPolicy.canRetry(retryContext)); }
@Test public void testTranslateTransientDataAccessResourceFailure() throws Exception { doTest("S1", TransientDataAccessResourceException.class); }
@Test public void errorCodeTranslation() { SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 0); DataIntegrityViolationException divex = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx); assertEquals(dataIntegrityViolationEx, divex.getCause()); SQLException featureNotSupEx = SQLExceptionSubclassFactory.newSQLFeatureNotSupportedException("", "", 0); InvalidDataAccessApiUsageException idaex = (InvalidDataAccessApiUsageException) sext.translate("task", "SQL", featureNotSupEx); assertEquals(featureNotSupEx, idaex.getCause()); SQLException dataIntegrityViolationEx2 = SQLExceptionSubclassFactory.newSQLIntegrityConstraintViolationException("", "", 0); DataIntegrityViolationException divex2 = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx2); assertEquals(dataIntegrityViolationEx2, divex2.getCause()); SQLException permissionDeniedEx = SQLExceptionSubclassFactory.newSQLInvalidAuthorizationSpecException("", "", 0); PermissionDeniedDataAccessException pdaex = (PermissionDeniedDataAccessException) sext.translate("task", "SQL", permissionDeniedEx); assertEquals(permissionDeniedEx, pdaex.getCause()); SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLNonTransientConnectionException("", "", 0); DataAccessResourceFailureException darex = (DataAccessResourceFailureException) sext.translate("task", "SQL", dataAccessResourceEx); assertEquals(dataAccessResourceEx, darex.getCause()); SQLException badSqlEx2 = SQLExceptionSubclassFactory.newSQLSyntaxErrorException("", "", 0); BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", badSqlEx2); assertEquals("SQL2", bsgex2.getSql()); assertEquals(badSqlEx2, bsgex2.getSQLException()); SQLException tranRollbackEx = SQLExceptionSubclassFactory.newSQLTransactionRollbackException("", "", 0); ConcurrencyFailureException cfex = (ConcurrencyFailureException) sext.translate("task", "SQL", tranRollbackEx); assertEquals(tranRollbackEx, cfex.getCause()); SQLException transientConnEx = SQLExceptionSubclassFactory.newSQLTransientConnectionException("", "", 0); TransientDataAccessResourceException tdarex = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx); assertEquals(transientConnEx, tdarex.getCause()); SQLException transientConnEx2 = SQLExceptionSubclassFactory.newSQLTimeoutException("", "", 0); QueryTimeoutException tdarex2 = (QueryTimeoutException) sext.translate("task", "SQL", transientConnEx2); assertEquals(transientConnEx2, tdarex2.getCause()); SQLException recoverableEx = SQLExceptionSubclassFactory.newSQLRecoverableException("", "", 0); RecoverableDataAccessException rdaex2 = (RecoverableDataAccessException) sext.translate("task", "SQL", recoverableEx); assertEquals(recoverableEx, rdaex2.getCause()); // Test classic error code translation. We should move there next if the exception we pass in is not one // of the new sub-classes. SQLException sexEct = new SQLException("", "", 1); BadSqlGrammarException bsgEct = (BadSqlGrammarException) sext.translate("task", "SQL-ECT", sexEct); assertEquals("SQL-ECT", bsgEct.getSql()); assertEquals(sexEct, bsgEct.getSQLException()); // Test fallback. We assume that no database will ever return this error code, // but 07xxx will be bad grammar picked up by the fallback SQLState translator SQLException sexFbt = new SQLException("", "07xxx", 666666666); BadSqlGrammarException bsgFbt = (BadSqlGrammarException) sext.translate("task", "SQL-FBT", sexFbt); assertEquals("SQL-FBT", bsgFbt.getSql()); assertEquals(sexFbt, bsgFbt.getSQLException()); // and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator SQLException sexFbt2 = new SQLException("", "08xxx", 666666666); DataAccessResourceFailureException darfFbt = (DataAccessResourceFailureException) sext.translate("task", "SQL-FBT2", sexFbt2); assertEquals(sexFbt2, darfFbt.getCause()); }
/** * Gets an SqlSession from Spring Transaction Manager or creates a new one if needed. * Tries to get a SqlSession out of current transaction. If there is not any, it creates a new one. * Then, it synchronizes the SqlSession with the transaction if Spring TX is active and * <code>SpringManagedTransactionFactory</code> is configured as a transaction manager. * * @param sessionFactory a MyBatis {@code SqlSessionFactory} to create new sessions * @param executorType The executor type of the SqlSession to create * @param exceptionTranslator Optional. Translates SqlSession.commit() exceptions to Spring exceptions. * @throws TransientDataAccessResourceException if a transaction is active and the * {@code SqlSessionFactory} is not using a {@code SpringManagedTransactionFactory} * @see SpringManagedTransactionFactory */ public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sessionFactory, "No SqlSessionFactory specified"); notNull(executorType, "No ExecutorType specified"); SqlSessionHolder holder = (SqlSessionHolder) TransactionSynchronizationManager.getResource(sessionFactory); if (holder != null && holder.isSynchronizedWithTransaction()) { if (holder.getExecutorType() != executorType) { throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"); } holder.requested(); if (logger.isDebugEnabled()) { logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction"); } return holder.getSqlSession(); } if (logger.isDebugEnabled()) { logger.debug("Creating a new SqlSession"); } SqlSession session = sessionFactory.openSession(executorType); // Register session holder if synchronization is active (i.e. a Spring TX is active) // // Note: The DataSource used by the Environment should be synchronized with the // transaction either through DataSourceTxMgr or another tx synchronization. // Further assume that if an exception is thrown, whatever started the transaction will // handle closing / rolling back the Connection associated with the SqlSession. if (TransactionSynchronizationManager.isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if (logger.isDebugEnabled()) { logger.debug("Registering transaction synchronization for SqlSession [" + session + "]"); } holder = new SqlSessionHolder(session, executorType, exceptionTranslator); TransactionSynchronizationManager.bindResource(sessionFactory, holder); TransactionSynchronizationManager.registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(true); holder.requested(); } else { if (TransactionSynchronizationManager.getResource(environment.getDataSource()) == null) { if (logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional"); } } else { throw new TransientDataAccessResourceException( "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); } } } else { if (logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active"); } } return session; }
@Override public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException, DataAccessException { if ( name == null ) { throw new IllegalStateException("Username cannot be null"); } User user = userService.getDaemonAccountUser(); final String uriUser; final String password; final String salt; final Set<GrantedAuthority> grantedAuthorities; final boolean isEnabled = true; final boolean isCredentialNonExpired = true; try { if ( credentialType == CredentialType.Username ) { RegisteredUsersTable t; // first call from digest, basic or forms-based auth if ( name.startsWith(RegisteredUsersTable.UID_PREFIX) ) { t = RegisteredUsersTable.getUserByUri(name, datastore, user); if ( t == null ) { throw new UsernameNotFoundException("UID " + name + " is not recognized."); } } else { t = RegisteredUsersTable.getUniqueUserByUsername(name, datastore, user); if ( t == null ) { throw new UsernameNotFoundException("User " + name + " is not registered or the registered users table is corrupt."); } } uriUser = t.getUri(); switch ( passwordType ) { case BasicAuth: password = t.getBasicAuthPassword(); salt = t.getBasicAuthSalt(); break; case DigestAuth: password = t.getDigestAuthPassword(); salt = UUID.randomUUID().toString(); break; default: throw new AuthenticationCredentialsNotFoundException( "Password type " + passwordType.toString() + " cannot be interpretted"); } grantedAuthorities = getGrantedAuthorities(t.getUri()); if ( password == null ) { throw new AuthenticationCredentialsNotFoundException( "User " + name + " does not have a password configured. You must close and re-open your browser to clear this error."); } } else { // OAuth2 token... // there is no password for an OAuth2 credential if ( passwordType != PasswordType.Random ) { throw new AuthenticationCredentialsNotFoundException( "Password type " + passwordType.toString() + " cannot be interpretted"); } // set password and salt to unguessable strings... password = UUID.randomUUID().toString(); salt = UUID.randomUUID().toString(); // try to find user in registered users table... RegisteredUsersTable eUser = RegisteredUsersTable.getUniqueUserByEmail(name, datastore, user); if ( eUser != null ) { uriUser = eUser.getUri(); grantedAuthorities = getGrantedAuthorities(eUser.getUri()); } else { throw new UsernameNotFoundException("User " + name + " is not registered"); } } } catch (ODKDatastoreException e) { throw new TransientDataAccessResourceException("persistence layer problem", e); } return new AggregateUser(uriUser, password, salt, "-undefined-", isEnabled, true, isCredentialNonExpired, true, grantedAuthorities ); }
public void testErrorCodeTranslation() { if (JdkVersion.getMajorJavaVersion() < JdkVersion.JAVA_16) { return; } SQLExceptionTranslator sext = new SQLErrorCodeSQLExceptionTranslator(ERROR_CODES); SQLException dataIntegrityViolationEx = SQLExceptionSubclassFactory.newSQLDataException("", "", 0); DataIntegrityViolationException divex = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx); assertEquals(dataIntegrityViolationEx, divex.getCause()); SQLException featureNotSupEx = SQLExceptionSubclassFactory.newSQLFeatureNotSupportedException("", "", 0); InvalidDataAccessApiUsageException idaex = (InvalidDataAccessApiUsageException) sext.translate("task", "SQL", featureNotSupEx); assertEquals(featureNotSupEx, idaex.getCause()); SQLException dataIntegrityViolationEx2 = SQLExceptionSubclassFactory.newSQLIntegrityConstraintViolationException("", "", 0); DataIntegrityViolationException divex2 = (DataIntegrityViolationException) sext.translate("task", "SQL", dataIntegrityViolationEx2); assertEquals(dataIntegrityViolationEx2, divex2.getCause()); SQLException permissionDeniedEx = SQLExceptionSubclassFactory.newSQLInvalidAuthorizationSpecException("", "", 0); PermissionDeniedDataAccessException pdaex = (PermissionDeniedDataAccessException) sext.translate("task", "SQL", permissionDeniedEx); assertEquals(permissionDeniedEx, pdaex.getCause()); SQLException dataAccessResourceEx = SQLExceptionSubclassFactory.newSQLNonTransientConnectionException("", "", 0); DataAccessResourceFailureException darex = (DataAccessResourceFailureException) sext.translate("task", "SQL", dataAccessResourceEx); assertEquals(dataAccessResourceEx, darex.getCause()); SQLException badSqlEx2 = SQLExceptionSubclassFactory.newSQLSyntaxErrorException("", "", 0); BadSqlGrammarException bsgex2 = (BadSqlGrammarException) sext.translate("task", "SQL2", badSqlEx2); assertEquals("SQL2", bsgex2.getSql()); assertEquals(badSqlEx2, bsgex2.getSQLException()); SQLException tranRollbackEx = SQLExceptionSubclassFactory.newSQLTransactionRollbackException("", "", 0); ConcurrencyFailureException cfex = (ConcurrencyFailureException) sext.translate("task", "SQL", tranRollbackEx); assertEquals(tranRollbackEx, cfex.getCause()); SQLException transientConnEx = SQLExceptionSubclassFactory.newSQLTransientConnectionException("", "", 0); TransientDataAccessResourceException tdarex = (TransientDataAccessResourceException) sext.translate("task", "SQL", transientConnEx); assertEquals(transientConnEx, tdarex.getCause()); SQLException transientConnEx2 = SQLExceptionSubclassFactory.newSQLTimeoutException("", "", 0); QueryTimeoutException tdarex2 = (QueryTimeoutException) sext.translate("task", "SQL", transientConnEx2); assertEquals(transientConnEx2, tdarex2.getCause()); SQLException recoverableEx = SQLExceptionSubclassFactory.newSQLRecoverableException("", "", 0); RecoverableDataAccessException rdaex2 = (RecoverableDataAccessException) sext.translate("task", "SQL", recoverableEx); assertEquals(recoverableEx, rdaex2.getCause()); // Test classic error code translation. We should move there next if the exception we pass in is not one // of the new sub-classes. SQLException sexEct = new SQLException("", "", 1); BadSqlGrammarException bsgEct = (BadSqlGrammarException) sext.translate("task", "SQL-ECT", sexEct); assertEquals("SQL-ECT", bsgEct.getSql()); assertEquals(sexEct, bsgEct.getSQLException()); // Test fallback. We assume that no database will ever return this error code, // but 07xxx will be bad grammar picked up by the fallback SQLState translator SQLException sexFbt = new SQLException("", "07xxx", 666666666); BadSqlGrammarException bsgFbt = (BadSqlGrammarException) sext.translate("task", "SQL-FBT", sexFbt); assertEquals("SQL-FBT", bsgFbt.getSql()); assertEquals(sexFbt, bsgFbt.getSQLException()); // and 08xxx will be data resource failure (non-transient) picked up by the fallback SQLState translator SQLException sexFbt2 = new SQLException("", "08xxx", 666666666); DataAccessResourceFailureException darfFbt = (DataAccessResourceFailureException) sext.translate("task", "SQL-FBT2", sexFbt2); assertEquals(sexFbt2, darfFbt.getCause()); }
/** * Gets an SqlSession from Spring Transaction Manager or creates a new one if needed. * Tries to get a SqlSession out of current transaction. If there is not any, it creates a new one. * Then, it synchronizes the SqlSession with the transaction if Spring TX is active and * <code>SpringManagedTransactionFactory</code> is configured as a transaction manager. * * @param sessionFactory a MyBatis {@code SqlSessionFactory} to create new sessions * @param executorType The executor type of the SqlSession to create * @param exceptionTranslator Optional. Translates SqlSession.commit() exceptions to Spring exceptions. * @throws TransientDataAccessResourceException if a transaction is active and the * {@code SqlSessionFactory} is not using a {@code SpringManagedTransactionFactory} * @see SpringManagedTransactionFactory */ public static SqlSession getSqlSession(SqlSessionFactory sessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sessionFactory, "No SqlSessionFactory specified"); notNull(executorType, "No ExecutorType specified"); SqlSessionHolder holder = (SqlSessionHolder) getResource(sessionFactory); if (holder != null && holder.isSynchronizedWithTransaction()) { if (holder.getExecutorType() != executorType) { throw new TransientDataAccessResourceException("Cannot change the ExecutorType when there is an existing transaction"); } holder.requested(); if (logger.isDebugEnabled()) { logger.debug("Fetched SqlSession [" + holder.getSqlSession() + "] from current transaction"); } return holder.getSqlSession(); } if (logger.isDebugEnabled()) { logger.debug("Creating a new SqlSession"); } SqlSession session = sessionFactory.openSession(executorType); // Register session holder if synchronization is active (i.e. a Spring TX is active) // // Note: The DataSource used by the Environment should be synchronized with the // transaction either through DataSourceTxMgr or another tx synchronization. // Further assume that if an exception is thrown, whatever started the transaction will // handle closing / rolling back the Connection associated with the SqlSession. if (isSynchronizationActive()) { Environment environment = sessionFactory.getConfiguration().getEnvironment(); if (environment.getTransactionFactory() instanceof SpringManagedTransactionFactory) { if (logger.isDebugEnabled()) { logger.debug("Registering transaction synchronization for SqlSession [" + session + "]"); } holder = new SqlSessionHolder(session, executorType, exceptionTranslator); bindResource(sessionFactory, holder); registerSynchronization(new SqlSessionSynchronization(holder, sessionFactory)); holder.setSynchronizedWithTransaction(true); holder.requested(); } else { if (getResource(environment.getDataSource()) == null) { if (logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because DataSource is not transactional"); } } else { throw new TransientDataAccessResourceException( "SqlSessionFactory must be using a SpringManagedTransactionFactory in order to use Spring transaction synchronization"); } } } else { if (logger.isDebugEnabled()) { logger.debug("SqlSession [" + session + "] was not registered for synchronization because synchronization is not active"); } } return session; }