REOPENED - BATCH-778: MapJobRepositoryFactoryBean shouldn't require transactionManager
tx code moved from AbstractJobRepositoryFactoryBean to JobRepositoryFactoryBean
This commit is contained in:
@@ -1,19 +1,11 @@
|
||||
package org.springframework.batch.core.repository.support;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcut;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
|
||||
import org.springframework.batch.core.repository.dao.JobExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.JobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.StepExecutionDao;
|
||||
import org.springframework.batch.support.PropertiesConverter;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link FactoryBean} that automates the creation of a
|
||||
@@ -27,18 +19,7 @@ import org.springframework.util.Assert;
|
||||
* @author Lucas Ward
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
/**
|
||||
* Default value for isolation level in create* method.
|
||||
*/
|
||||
private static final String DEFAULT_ISOLATION_LEVEL = "ISOLATION_SERIALIZABLE";
|
||||
|
||||
private ProxyFactory proxyFactory;
|
||||
|
||||
private String isolationLevelForCreate = DEFAULT_ISOLATION_LEVEL;
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean {
|
||||
|
||||
/**
|
||||
* @return fully configured {@link JobInstanceDao} implementation.
|
||||
@@ -60,10 +41,6 @@ public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, I
|
||||
*/
|
||||
protected abstract ExecutionContextDao createExecutionContextDao() throws Exception;
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return proxyFactory.getProxy();
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of object to be returned from {@link #getObject()}.
|
||||
*
|
||||
@@ -78,53 +55,4 @@ public abstract class AbstractJobRepositoryFactoryBean implements FactoryBean, I
|
||||
return true;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
Assert.notNull(transactionManager, "TransactionManager must not be null.");
|
||||
|
||||
initializeProxy();
|
||||
}
|
||||
|
||||
protected void initializeProxy() throws Exception {
|
||||
proxyFactory = new ProxyFactory();
|
||||
TransactionInterceptor advice = new TransactionInterceptor(transactionManager, PropertiesConverter
|
||||
.stringToProperties("create*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate
|
||||
+ "\n*=PROPAGATION_REQUIRED"));
|
||||
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(advice);
|
||||
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
|
||||
pointcut.addMethodName("*");
|
||||
advisor.setPointcut(pointcut);
|
||||
proxyFactory.addAdvisor(advisor);
|
||||
proxyFactory.setProxyTargetClass(false);
|
||||
proxyFactory.addInterface(JobRepository.class);
|
||||
proxyFactory.setTarget(getTarget());
|
||||
}
|
||||
|
||||
private Object getTarget() throws Exception {
|
||||
return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(), createExecutionContextDao());
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link PlatformTransactionManager}.
|
||||
* @param transactionManager the transactionManager to set
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the isolation level to be used for the transaction when
|
||||
* job execution entities are initially created. The default is
|
||||
* ISOLATION_SERIALIZABLE, which prevents accidental concurrent execution of
|
||||
* the same job (ISOLATION_REPEATABLE_READ would work as well).
|
||||
*
|
||||
* @param isolationLevelForCreate the isolation level name to set
|
||||
*
|
||||
* @see SimpleJobRepository#createJobExecution(org.springframework.batch.core.Job,
|
||||
* org.springframework.batch.core.JobParameters)
|
||||
*/
|
||||
public void setIsolationLevelForCreate(String isolationLevelForCreate) {
|
||||
this.isolationLevelForCreate = isolationLevelForCreate;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,10 @@ package org.springframework.batch.core.repository.support;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcut;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
|
||||
import org.springframework.batch.core.repository.dao.ExecutionContextDao;
|
||||
import org.springframework.batch.core.repository.dao.JdbcExecutionContextDao;
|
||||
@@ -29,9 +33,13 @@ import org.springframework.batch.core.repository.dao.JobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.StepExecutionDao;
|
||||
import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
|
||||
import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
|
||||
import org.springframework.batch.support.PropertiesConverter;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcOperations;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -44,7 +52,16 @@ import org.springframework.util.StringUtils;
|
||||
* @author Ben Hale
|
||||
* @author Lucas Ward
|
||||
*/
|
||||
public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean implements InitializingBean {
|
||||
|
||||
/**
|
||||
* Default value for isolation level in create* method.
|
||||
*/
|
||||
private static final String DEFAULT_ISOLATION_LEVEL = "ISOLATION_SERIALIZABLE";
|
||||
|
||||
private ProxyFactory proxyFactory;
|
||||
|
||||
private String isolationLevelForCreate = DEFAULT_ISOLATION_LEVEL;
|
||||
|
||||
private DataSource dataSource;
|
||||
|
||||
@@ -55,7 +72,32 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
private String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
|
||||
|
||||
private DataFieldMaxValueIncrementerFactory incrementerFactory;
|
||||
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
/**
|
||||
* Public setter for the isolation level to be used for the transaction when
|
||||
* job execution entities are initially created. The default is
|
||||
* ISOLATION_SERIALIZABLE, which prevents accidental concurrent execution of
|
||||
* the same job (ISOLATION_REPEATABLE_READ would work as well).
|
||||
*
|
||||
* @param isolationLevelForCreate the isolation level name to set
|
||||
*
|
||||
* @see SimpleJobRepository#createJobExecution(org.springframework.batch.core.Job,
|
||||
* org.springframework.batch.core.JobParameters)
|
||||
*/
|
||||
public void setIsolationLevelForCreate(String isolationLevelForCreate) {
|
||||
this.isolationLevelForCreate = isolationLevelForCreate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link PlatformTransactionManager}.
|
||||
* @param transactionManager the transactionManager to set
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link DataSource}.
|
||||
* @param dataSource a {@link DataSource}
|
||||
@@ -86,7 +128,9 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
|
||||
Assert.notNull(transactionManager, "TransactionManager must not be null.");
|
||||
Assert.notNull(dataSource, "DataSource must not be null.");
|
||||
|
||||
jdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
|
||||
if (incrementerFactory == null) {
|
||||
@@ -96,10 +140,31 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
Assert.isTrue(incrementerFactory.isSupportedIncrementerType(databaseType), "'" + databaseType
|
||||
+ "' is an unsupported database type. The supported database types are "
|
||||
+ StringUtils.arrayToCommaDelimitedString(incrementerFactory.getSupportedIncrementerTypes()));
|
||||
|
||||
initializeProxy();
|
||||
|
||||
super.afterPropertiesSet();
|
||||
}
|
||||
|
||||
protected void initializeProxy() throws Exception {
|
||||
proxyFactory = new ProxyFactory();
|
||||
TransactionInterceptor advice = new TransactionInterceptor(transactionManager, PropertiesConverter
|
||||
.stringToProperties("create*=PROPAGATION_REQUIRES_NEW," + isolationLevelForCreate
|
||||
+ "\n*=PROPAGATION_REQUIRED"));
|
||||
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor(advice);
|
||||
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
|
||||
pointcut.addMethodName("*");
|
||||
advisor.setPointcut(pointcut);
|
||||
proxyFactory.addAdvisor(advisor);
|
||||
proxyFactory.setProxyTargetClass(false);
|
||||
proxyFactory.addInterface(JobRepository.class);
|
||||
proxyFactory.setTarget(getTarget());
|
||||
}
|
||||
|
||||
private Object getTarget() throws Exception {
|
||||
return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(), createExecutionContextDao());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobInstanceDao createJobInstanceDao() throws Exception {
|
||||
JdbcJobInstanceDao dao = new JdbcJobInstanceDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
@@ -109,6 +174,7 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobExecutionDao createJobExecutionDao() throws Exception {
|
||||
JdbcJobExecutionDao dao = new JdbcJobExecutionDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
@@ -121,6 +187,7 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
return dao;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StepExecutionDao createStepExecutionDao() throws Exception {
|
||||
JdbcStepExecutionDao dao = new JdbcStepExecutionDao();
|
||||
dao.setJdbcTemplate(jdbcTemplate);
|
||||
@@ -139,4 +206,8 @@ public class JobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
dao.afterPropertiesSet();
|
||||
return dao;
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return proxyFactory.getProxy();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,17 @@ import org.springframework.beans.factory.FactoryBean;
|
||||
*/
|
||||
public class MapJobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBean {
|
||||
|
||||
@Override
|
||||
protected JobExecutionDao createJobExecutionDao() throws Exception {
|
||||
return new MapJobExecutionDao();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JobInstanceDao createJobInstanceDao() throws Exception {
|
||||
return new MapJobInstanceDao();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StepExecutionDao createStepExecutionDao() throws Exception {
|
||||
return new MapStepExecutionDao();
|
||||
}
|
||||
@@ -36,4 +39,9 @@ public class MapJobRepositoryFactoryBean extends AbstractJobRepositoryFactoryBea
|
||||
return new MapExecutionContextDao();
|
||||
}
|
||||
|
||||
public Object getObject() throws Exception {
|
||||
return new SimpleJobRepository(createJobInstanceDao(), createJobExecutionDao(), createStepExecutionDao(),
|
||||
createExecutionContextDao());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,33 +1,24 @@
|
||||
package org.springframework.batch.core.repository.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
|
||||
/**
|
||||
* Tests for {@link MapJobRepositoryFactoryBean}.
|
||||
*/
|
||||
public class MapJobRepositoryFactoryBeanTests extends TestCase {
|
||||
public class MapJobRepositoryFactoryBeanTests {
|
||||
|
||||
private MapJobRepositoryFactoryBean tested = new MapJobRepositoryFactoryBean();
|
||||
|
||||
private PlatformTransactionManager transactionManager = new ResourcelessTransactionManager();
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
tested.setTransactionManager(transactionManager);
|
||||
tested.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the factory to create repository and check the repository remembers
|
||||
* created executions.
|
||||
*/
|
||||
@Test
|
||||
public void testCreateRepository() throws Exception {
|
||||
JobRepository repository = (JobRepository) tested.getObject();
|
||||
Job job = new JobSupport("jobName");
|
||||
|
||||
@@ -1,31 +1,29 @@
|
||||
<?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"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<import resource="data-source-context.xml" />
|
||||
<import resource="classpath:/org/springframework/batch/sample/config/common-context.xml" />
|
||||
|
||||
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<import
|
||||
resource="classpath:/org/springframework/batch/sample/config/common-context.xml" />
|
||||
<bean id="jobLauncher"
|
||||
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
|
||||
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
|
||||
p:databaseType="${environment}" p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager"/>
|
||||
|
||||
<bean id="mapJobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
|
||||
p:transactionManager-ref="transactionManager" lazy-init="true" autowire-candidate="false" />
|
||||
|
||||
<bean id="jobRepository"
|
||||
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
|
||||
p:databaseType="${environment}" p:dataSource-ref="dataSource"
|
||||
p:transactionManager-ref="transactionManager" />
|
||||
<bean id="mapJobRepository"
|
||||
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
|
||||
lazy-init="true" autowire-candidate="false" />
|
||||
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
|
||||
<property name="dataSource" ref="dataSource" />
|
||||
</bean>
|
||||
|
||||
<bean id="logAdvice" class="org.springframework.batch.sample.common.LogAdvice" />
|
||||
|
||||
<bean id="eventAdvice" class="org.springframework.batch.sample.jmx.StepExecutionApplicationEventAdvice" />
|
||||
|
||||
</beans>
|
||||
<bean id="eventAdvice"
|
||||
class="org.springframework.batch.sample.jmx.StepExecutionApplicationEventAdvice" />
|
||||
</beans>
|
||||
Reference in New Issue
Block a user