OPEN - issue BATCH-194: Incorrect exception handling when using Hibernate
http://opensource.atlassian.com/projects/spring/browse/BATCH-194
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -31,8 +31,7 @@ public abstract class AbstractValidatingBatchLauncherTests extends AbstractBatch
|
||||
|
||||
public void testLaunchJob() throws Exception {
|
||||
validatePreConditions();
|
||||
launcher.run(getJobName());
|
||||
launcher.stop();
|
||||
super.testLaunchJob();
|
||||
validatePostConditions();
|
||||
}
|
||||
|
||||
|
||||
@@ -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(){
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user