RESOLVED - issue BATCH-680: Allow override of Transaction Definition in get transaction in Item Oriented Step

Added transactionAttribute to ItemOrientedStep and the factory bean
This commit is contained in:
dsyer
2008-06-21 09:44:40 +00:00
parent d3a7c90de9
commit a078199eae
10 changed files with 148 additions and 89 deletions

View File

@@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Map.Entry;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
@@ -30,6 +31,7 @@ import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.repository.NoSuchJobException;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.support.PropertiesConverter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
@@ -104,10 +106,10 @@ public class SimpleExportedJobLauncher implements ExportedJobLauncher, Initializ
int i = 0;
for (Iterator iterator = execution.getStepExecutions().iterator(); iterator.hasNext();) {
StepExecution stepExecution = (StepExecution) iterator.next();
Properties statistics = stepExecution.getExecutionContext().getProperties();
for (Iterator iter = statistics.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
result.setProperty(prefix + "step" + i + "." + key, statistics.getProperty(key));
ExecutionContext statistics = stepExecution.getExecutionContext();
for (Iterator iter = statistics.entrySet().iterator(); iter.hasNext();) {
Entry entry = (Entry) iter.next();
result.setProperty(prefix + "step" + i + "." + entry.getKey(), ""+entry.getValue());
}
}
}

View File

@@ -26,6 +26,7 @@ import org.springframework.batch.item.validator.Validator;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.TransactionAttribute;
import org.springframework.util.Assert;
/**
@@ -53,6 +54,8 @@ public abstract class AbstractStepFactoryBean implements FactoryBean, BeanNameAw
private ItemWriter itemWriter;
private PlatformTransactionManager transactionManager;
private TransactionAttribute transactionAttribute;
private JobRepository jobRepository;
@@ -185,6 +188,14 @@ public abstract class AbstractStepFactoryBean implements FactoryBean, BeanNameAw
this.transactionManager = transactionManager;
}
/**
* Public setter for the {@link TransactionAttribute}.
* @param transactionAttribute the {@link TransactionAttribute} to set
*/
public void setTransactionAttribute(TransactionAttribute transactionAttribute) {
this.transactionAttribute = transactionAttribute;
}
/**
* Create a {@link Step} from the configuration provided.
*
@@ -209,6 +220,9 @@ public abstract class AbstractStepFactoryBean implements FactoryBean, BeanNameAw
step.setItemHandler(new SimpleItemHandler(itemReader, itemWriter));
step.setTransactionManager(transactionManager);
if (transactionAttribute!=null) {
step.setTransactionAttribute(transactionAttribute);
}
step.setJobRepository(jobRepository);
step.setStartLimit(startLimit);
step.setAllowStartIfComplete(allowStartIfComplete);

View File

@@ -40,7 +40,8 @@ import org.springframework.batch.repeat.RepeatOperations;
import org.springframework.batch.repeat.support.RepeatTemplate;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAttribute;
/**
* Simple implementation of executing the step as a set of chunks, each chunk
@@ -78,6 +79,8 @@ public class ItemOrientedStep extends AbstractStep {
private PlatformTransactionManager transactionManager;
private TransactionAttribute transactionAttribute = new DefaultTransactionAttribute();
private ItemHandler itemHandler;
private StepExecutionSynchronizer synchronizer;
@@ -98,7 +101,15 @@ public class ItemOrientedStep extends AbstractStep {
public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
}
/**
* Public setter for the {@link TransactionAttribute}.
* @param transactionAttribute the {@link TransactionAttribute} to set
*/
public void setTransactionAttribute(TransactionAttribute transactionAttribute) {
this.transactionAttribute = transactionAttribute;
}
/**
* Public setter for the {@link ItemHandler}.
*
@@ -230,7 +241,7 @@ public class ItemOrientedStep extends AbstractStep {
ExitStatus exitStatus = ExitStatus.CONTINUABLE;
TransactionStatus transaction = transactionManager.getTransaction(new DefaultTransactionDefinition());
TransactionStatus transaction = transactionManager.getTransaction(transactionAttribute);
try {

View File

@@ -2,7 +2,6 @@ package org.springframework.batch.core.step;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import junit.framework.TestCase;
@@ -102,10 +101,10 @@ public class AbstractStepTests extends TestCase {
*/
private static class JobRepositoryStub extends JobRepositorySupport {
Properties saved = new Properties();
ExecutionContext saved = new ExecutionContext();
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
saved = stepExecution.getExecutionContext().getProperties();
saved = stepExecution.getExecutionContext();
}
}

View File

@@ -36,20 +36,35 @@ import org.springframework.util.StringUtils;
public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
private Resource initScript;
private Resource[] initScripts;
private Resource destroyScript;
DataSource dataSource;
public void destroy() throws Exception {
super.destroy();
private static boolean initialized = false;
/**
* @throws Throwable
* @see java.lang.Object#finalize()
*/
protected void finalize() throws Throwable {
super.finalize();
initialized = false;
logger.debug("finalize called");
}
protected void destroyInstance(Object instance) throws Exception {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
logger.warn("Could not execute destroy script [" + destroyScript + "]", e);
if (logger.isDebugEnabled()) {
logger.warn("Could not execute destroy script [" + destroyScript + "]", e);
}
else {
logger.warn("Could not execute destroy script [" + destroyScript + "]");
}
}
}
@@ -60,13 +75,21 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
protected Object createInstance() throws Exception {
Assert.notNull(dataSource);
try {
doExecuteScript(destroyScript);
if (!initialized) {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
logger.debug("Could not execute destroy script [" + destroyScript + "]", e);
}
if (initScripts != null) {
for (int i = 0; i < initScripts.length; i++) {
Resource initScript = initScripts[i];
doExecuteScript(initScript);
}
}
initialized = true;
}
catch (Exception e) {
logger.debug("Could not execute destroy script [" + destroyScript + "]", e);
}
doExecuteScript(initScript);
return dataSource;
}
@@ -74,31 +97,29 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
if (scriptResource == null || !scriptResource.exists())
return;
TransactionTemplate transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
if (initScript != null) {
transactionTemplate.execute(new TransactionCallback() {
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] scripts;
try {
scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource
.getInputStream())), ";");
}
catch (IOException e) {
throw new BeanInitializationException("Cannot load script from [" + initScript + "]", e);
}
for (int i = 0; i < scripts.length; i++) {
String script = scripts[i].trim();
if (StringUtils.hasText(script)) {
jdbcTemplate.execute(scripts[i]);
}
}
return null;
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] scripts;
try {
scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource
.getInputStream())), ";");
}
catch (IOException e) {
throw new BeanInitializationException("Cannot load script from [" + scriptResource + "]", e);
}
for (int i = 0; i < scripts.length; i++) {
String script = scripts[i].trim();
if (StringUtils.hasText(script)) {
jdbcTemplate.execute(scripts[i]);
}
}
return null;
}
});
});
}
}
private String stripComments(List list) {
@@ -116,8 +137,8 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
return DataSource.class;
}
public void setInitScript(Resource initScript) {
this.initScript = initScript;
public void setInitScripts(Resource[] initScripts) {
this.initScripts = initScripts;
}
public void setDestroyScript(Resource destroyScript) {

View File

@@ -4,7 +4,7 @@
<bean id="dataSource" class="test.jdbc.datasource.InitializingDataSourceFactoryBean">
<property name="dataSource" ref="hsql" />
<property name="initScript" value="org/springframework/batch/jms/init.sql" />
<property name="initScripts" value="org/springframework/batch/jms/init.sql" />
<property name="destroyScript" value="org/springframework/batch/jms/destroy.sql" />
</bean>

View File

@@ -36,20 +36,35 @@ import org.springframework.util.StringUtils;
public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
private Resource initScript;
private Resource[] initScripts;
private Resource destroyScript;
DataSource dataSource;
public void destroy() throws Exception {
super.destroy();
private static boolean initialized = false;
/**
* @throws Throwable
* @see java.lang.Object#finalize()
*/
protected void finalize() throws Throwable {
super.finalize();
initialized = false;
logger.debug("finalize called");
}
protected void destroyInstance(Object instance) throws Exception {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
logger.warn("Could not execute destroy script [" + destroyScript + "]", e);
if (logger.isDebugEnabled()) {
logger.warn("Could not execute destroy script [" + destroyScript + "]", e);
}
else {
logger.warn("Could not execute destroy script [" + destroyScript + "]");
}
}
}
@@ -60,13 +75,21 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
protected Object createInstance() throws Exception {
Assert.notNull(dataSource);
try {
doExecuteScript(destroyScript);
if (!initialized) {
try {
doExecuteScript(destroyScript);
}
catch (Exception e) {
logger.debug("Could not execute destroy script [" + destroyScript + "]", e);
}
if (initScripts != null) {
for (int i = 0; i < initScripts.length; i++) {
Resource initScript = initScripts[i];
doExecuteScript(initScript);
}
}
initialized = true;
}
catch (Exception e) {
logger.debug("Could not execute destroy script [" + destroyScript + "]", e);
}
doExecuteScript(initScript);
return dataSource;
}
@@ -74,31 +97,29 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
if (scriptResource == null || !scriptResource.exists())
return;
TransactionTemplate transactionTemplate = new TransactionTemplate(new DataSourceTransactionManager(dataSource));
if (initScript != null) {
transactionTemplate.execute(new TransactionCallback() {
transactionTemplate.execute(new TransactionCallback() {
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] scripts;
try {
scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource
.getInputStream())), ";");
}
catch (IOException e) {
throw new BeanInitializationException("Cannot load script from [" + initScript + "]", e);
}
for (int i = 0; i < scripts.length; i++) {
String script = scripts[i].trim();
if (StringUtils.hasText(script)) {
jdbcTemplate.execute(scripts[i]);
}
}
return null;
public Object doInTransaction(TransactionStatus status) {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
String[] scripts;
try {
scripts = StringUtils.delimitedListToStringArray(stripComments(IOUtils.readLines(scriptResource
.getInputStream())), ";");
}
catch (IOException e) {
throw new BeanInitializationException("Cannot load script from [" + scriptResource + "]", e);
}
for (int i = 0; i < scripts.length; i++) {
String script = scripts[i].trim();
if (StringUtils.hasText(script)) {
jdbcTemplate.execute(scripts[i]);
}
}
return null;
}
});
});
}
}
private String stripComments(List list) {
@@ -116,8 +137,8 @@ public class InitializingDataSourceFactoryBean extends AbstractFactoryBean {
return DataSource.class;
}
public void setInitScript(Resource initScript) {
this.initScript = initScript;
public void setInitScripts(Resource[] initScripts) {
this.initScripts = initScripts;
}
public void setDestroyScript(Resource destroyScript) {

View File

@@ -9,7 +9,7 @@
<property name="url" value="jdbc:hsqldb:mem:testdb" />
</bean>
</property>
<property name="initScript" value="org/springframework/batch/item/database/init-foo-schema-hsqldb.sql" />
<property name="initScripts" value="org/springframework/batch/item/database/init-foo-schema-hsqldb.sql" />
<property name="destroyScript" value="org/springframework/batch/item/database/destroy-foo-schema-hsqldb.sql" />
</bean>

View File

@@ -13,7 +13,8 @@
<bean id="tradeJob" parent="simpleJob">
<property name="steps">
<list>
<bean id="step1" parent="simpleStep">
<bean id="step1" parent="simpleStep">
<property name="transactionAttribute" value="PROPAGATION_REQUIRED,ISOLATION_READ_UNCOMMITTED"/>
<property name="streams" ref="fileItemReader" />
<property name="itemReader">
<bean

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<import resource="classpath:/simple-job-launcher-context.xml" />
<import resource="classpath:/jobs/simpleJob.xml" />
</beans>