OPEN - issue BATCH-194: Incorrect exception handling when using Hibernate

http://opensource.atlassian.com/projects/spring/browse/BATCH-194
This commit is contained in:
dsyer
2007-11-13 19:03:56 +00:00
parent 645b882ff3
commit 3f340e2cf0
8 changed files with 178 additions and 76 deletions

View File

@@ -20,23 +20,47 @@ import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
/**
* @author Lucas Ward
*
*
*/
public class HibernateCreditWriter extends HibernateDaoSupport implements
CustomerCreditWriter {
/* (non-Javadoc)
private boolean failOnFlush = false;
/*
* (non-Javadoc)
*
* @see org.springframework.batch.sample.dao.CustomerCreditWriter#write(org.springframework.batch.sample.domain.CustomerCredit)
*/
public void write(CustomerCredit customerCredit) {
getHibernateTemplate().update(customerCredit);
if (!failOnFlush ) {
getHibernateTemplate().update(customerCredit);
} else {
// try to insert one with a duplicate ID
CustomerCredit newCredit = new CustomerCredit();
newCredit.setId(customerCredit.getId());
newCredit.setName(customerCredit.getName());
newCredit.setCredit(customerCredit.getCredit());
getHibernateTemplate().save(newCredit);
}
}
/* (non-Javadoc)
/*
* (non-Javadoc)
*
* @see org.springframework.batch.io.OutputSource#write(java.lang.Object)
*/
public void write(Object output) {
write((CustomerCredit)output);
write((CustomerCredit) output);
}
/**
* Public setter for the {@link boolean} property.
*
* @param failOnFlush true if you want to fail on flush (for testing)
*/
public void setFailOnFlush(boolean failOnFlush) {
this.failOnFlush = failOnFlush;
}
}

View File

@@ -4,13 +4,15 @@
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="org.springframework.batch.sample.domain.CustomerCredit" table="CUSTOMER">
<id name="id" column="ID">
<generator class="native"/>
</id>
<property name="id" />
<property name="name" />
<property name="credit" />
</class>
<class name="org.springframework.batch.sample.domain.CustomerCredit"
table="CUSTOMER">
<id name="id" column="ID">
<!-- To make the job fail on flush we need assigned IDs -->
<generator class="assigned" />
</id>
<property name="id" />
<property name="name" />
<property name="credit" />
</class>
</hibernate-mapping>

View File

@@ -1,18 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<description>
Example for Hibernate integration.
</description>
<description>Example for Hibernate integration.</description>
<bean parent="stepScope"/>
<bean parent="jobConfigurationRegistryBeanPostProcessor"/>
<bean parent="stepScope" />
<bean parent="jobConfigurationRegistryBeanPostProcessor" />
<bean id="jobConfiguration" parent="simpleJob">
<property name="steps">
@@ -21,19 +21,16 @@
<bean
class="org.springframework.batch.execution.tasklet.RestartableItemProviderTasklet">
<property name="itemProvider">
<bean class="org.springframework.batch.item.provider.InputSourceItemProvider">
<property name="inputSource" ref="hibernateInputSource" />
<bean
class="org.springframework.batch.item.provider.InputSourceItemProvider">
<property name="inputSource"
ref="hibernateInputSource" />
</bean>
</property>
<property name="itemProcessor">
<bean class="org.springframework.batch.sample.item.processor.CustomerCreditIncreaseProcessor">
<property name="outputSource">
<bean class="org.springframework.batch.sample.dao.HibernateCreditWriter"
scope="step">
<aop:scoped-proxy />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</property>
<bean
class="org.springframework.batch.sample.item.processor.CustomerCreditIncreaseProcessor">
<property name="outputSource" ref="hibernateOutputSource"/>
</bean>
</property>
</bean>
@@ -42,33 +39,34 @@
</property>
</bean>
<bean id="hibernateInputSource" class="org.springframework.batch.io.cursor.HibernateCursorInputSource"
scope="step" >
<bean id="hibernateOutputSource"
class="org.springframework.batch.sample.dao.HibernateCreditWriter">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="hibernateInputSource"
class="org.springframework.batch.io.cursor.HibernateCursorInputSource"
scope="step">
<aop:scoped-proxy />
<property name="queryString" value="from CustomerCredit" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mappingResources">
<list>
<value>CustomerCredit.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>CustomerCredit.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.HSQLDialect
</value>
</property>
</bean>
<bean parent="customEditorConfigurer"/>
<!-- register the step scope with the application context -->
<bean class="org.springframework.batch.execution.scope.StepScope" />
<bean parent="customEditorConfigurer" />
</beans>

View File

@@ -24,46 +24,60 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
/**
* Abstract unit test for running functional tests by getting context locations for
* both the container and configuration separately and having them auto wired in
* by type. This allows the two to be completely separated, and remove any
* 'configuration coupling' between the two. However, it is still purely
* theoretical until a decision is made as to how job configuration and container
* configuration files are pulled together.
* Abstract unit test for running functional tests by getting context locations
* for both the container and configuration separately and having them auto
* wired in by type. This allows the two to be completely separated, and remove
* any 'configuration coupling' between the two. However, it is still purely
* theoretical until a decision is made as to how job configuration and
* container configuration files are pulled together.
*
* @author Lucas Ward
*
*
*/
public abstract class AbstractBatchLauncherTests extends AbstractDependencyInjectionSpringContextTests {
public abstract class AbstractBatchLauncherTests extends
AbstractDependencyInjectionSpringContextTests {
private static final String CONTAINER_DEFINITION_LOCATION = "simple-container-definition.xml";
JobLauncher launcher;
JobConfiguration jobConfiguration;
/* (non-Javadoc)
private JobConfiguration jobConfiguration;
/*
* (non-Javadoc)
*
* @see org.springframework.test.AbstractSingleSpringContextTests#createApplicationContext(java.lang.String[])
*/
protected ConfigurableApplicationContext createApplicationContext(
String[] locations) {
ApplicationContext parent = new ClassPathXmlApplicationContext(CONTAINER_DEFINITION_LOCATION);
ApplicationContext parent = new ClassPathXmlApplicationContext(
CONTAINER_DEFINITION_LOCATION);
return new ClassPathXmlApplicationContext(locations, parent);
}
public void setLauncher(JobLauncher bootstrap){
public void setLauncher(JobLauncher bootstrap) {
this.launcher = bootstrap;
}
/**
* Public setter for the {@link JobConfiguration} property.
*
* @param jobConfiguration the jobConfiguration to set
*
* @param jobConfiguration
* the jobConfiguration to set
*/
public void setJobConfiguration(JobConfiguration jobConfiguration) {
this.jobConfiguration = jobConfiguration;
}
protected String getJobName() {
return jobConfiguration.getName();
}
/**
* @throws Exception
*
*/
public void testLaunchJob() throws Exception {
launcher.run(getJobName());
launcher.stop();
}
}

View File

@@ -24,8 +24,7 @@ public abstract class AbstractCustomerCreditIncreaseTests extends AbstractValida
private static final String CREDIT_COLUMN = "CREDIT";
private List creditsBeforeUpdate;
public void setJdbcTemplate(JdbcOperations jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}

View File

@@ -31,8 +31,7 @@ public abstract class AbstractValidatingBatchLauncherTests extends AbstractBatch
public void testLaunchJob() throws Exception {
validatePreConditions();
launcher.run(getJobName());
launcher.stop();
super.testLaunchJob();
validatePostConditions();
}

View File

@@ -34,7 +34,7 @@ public class GracefulShutdownFunctionalTest extends AbstractBatchLauncherTests {
return new String[] {"jobs/infiniteLoopJob.xml"};
}
public void testJob()throws Exception {
public void testLaunchJob() throws Exception {
final List errors = new ArrayList();
Thread jobThread = new Thread(){

View File

@@ -0,0 +1,66 @@
package org.springframework.batch.sample;
import org.springframework.batch.sample.dao.HibernateCreditWriter;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.orm.hibernate3.HibernateJdbcException;
/**
* Test for HibernateJob - checks that customer credit has been updated to
* expected value.
*
* @author Dave Syer
*/
public class HibernateFailureJobFunctionalTests extends
AbstractBatchLauncherTests {
private HibernateCreditWriter writer;
private JdbcOperations jdbcTemplate;
public void setJdbcTemplate(JdbcOperations jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
/**
* Public setter for the {@link HibernateCreditWriter} property.
*
* @param writer
* the writer to set
*/
public void setWriter(HibernateCreditWriter writer) {
this.writer = writer;
}
/*
* (non-Javadoc)
*
* @see org.springframework.test.AbstractSingleSpringContextTests#onTearDown()
*/
protected void onTearDown() throws Exception {
super.onTearDown();
writer.setFailOnFlush(false);
}
protected String[] getConfigLocations() {
return new String[] { "jobs/hibernateJob.xml" };
}
/*
* (non-Javadoc)
*
* @see org.springframework.batch.sample.AbstractValidatingBatchLauncherTests#testLaunchJob()
*/
public void testLaunchJob() throws Exception {
writer.setFailOnFlush(true);
int before = jdbcTemplate.queryForInt("SELECT COUNT(*) from CUSTOMER");
assertTrue(before>0);
try {
super.testLaunchJob();
} catch (HibernateJdbcException e) {
// Comment this out to see the test fail...
// fail("This exception is evil");
}
int after = jdbcTemplate.queryForInt("SELECT COUNT(*) from CUSTOMER");
assertEquals(before, after);
}
}