BATCH-1213: Defaults in xsd override parent attributes
*Introduced CoreNamespacePostProcessor to handle injection of JobRepository and TransactionManager onto jobs and steps defined using the namespace. *Introduced JobParserJobFactoryBean used to instantiate a FlowJob via the namespace. *Modified defaulting behavior of jobRepository attribute. Job's jobRepository now always overrides the Step's.
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2006-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class DummyJobRepository implements JobRepository, BeanNameAware {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void add(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public JobExecution createJobExecution(String jobName, JobParameters jobParameters)
|
||||
throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JobExecution getLastJobExecution(String jobName, JobParameters jobParameters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, String stepName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getStepExecutionCount(JobInstance jobInstance, String stepName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isJobInstanceExists(String jobName, JobParameters jobParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void update(JobExecution jobExecution) {
|
||||
}
|
||||
|
||||
public void update(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public void updateExecutionContext(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public void updateExecutionContext(JobExecution jobExecution) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2006-2009 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class DummyPlatformTransactionManager implements PlatformTransactionManager, BeanNameAware {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void commit(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
|
||||
public void rollback(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
|
||||
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
@@ -28,6 +27,8 @@ import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecutionListener;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -39,11 +40,12 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*/
|
||||
public class JobParserTests {
|
||||
|
||||
ConfigurableApplicationContext jobParserParentAttributeTestsCtx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
|
||||
@Test
|
||||
public void testInheritListeners() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> job1Listeners = getListeners("job1", ctx);
|
||||
List<?> job1Listeners = getListeners("job1", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(2, job1Listeners.size());
|
||||
boolean a = false;
|
||||
boolean b = false;
|
||||
@@ -61,9 +63,7 @@ public class JobParserTests {
|
||||
|
||||
@Test
|
||||
public void testInheritListeners_NoMerge() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> job2Listeners = getListeners("job2", ctx);
|
||||
List<?> job2Listeners = getListeners("job2", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(1, job2Listeners.size());
|
||||
boolean c = false;
|
||||
for (Object l : job2Listeners) {
|
||||
@@ -76,9 +76,7 @@ public class JobParserTests {
|
||||
|
||||
@Test
|
||||
public void testStandaloneListener() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> jobListeners = getListeners("job3", ctx);
|
||||
List<?> jobListeners = getListeners("job3", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(2, jobListeners.size());
|
||||
boolean a = false;
|
||||
boolean b = false;
|
||||
@@ -96,8 +94,7 @@ public class JobParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<?> getListeners(String jobName, ApplicationContext ctx) throws Exception {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Job.class);
|
||||
assertTrue(beans.containsKey(jobName));
|
||||
assertTrue(ctx.containsBean(jobName));
|
||||
Job job = (Job) ctx.getBean(jobName);
|
||||
|
||||
assertTrue(job instanceof AbstractJob);
|
||||
@@ -114,4 +111,29 @@ public class JobParserTests {
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobRepositoryDefaults() throws Exception {
|
||||
ApplicationContext ctx = jobParserParentAttributeTestsCtx;
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoJob", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("specifiedRepoJob", ctx) instanceof DummyJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("inheritSpecifiedRepoJob", ctx) instanceof DummyJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("overrideInheritedRepoJob", ctx) instanceof SimpleJobRepository);
|
||||
}
|
||||
|
||||
private JobRepository getJobRepository(String jobName, ApplicationContext ctx) throws Exception {
|
||||
assertTrue(ctx.containsBean(jobName));
|
||||
Job job = (Job) ctx.getBean(jobName);
|
||||
assertTrue(job instanceof AbstractJob);
|
||||
Object jobRepository = ReflectionTestUtils.getField(job, "jobRepository");
|
||||
while (jobRepository instanceof Advised) {
|
||||
jobRepository = ((Advised) jobRepository).getTargetSource().getTarget();
|
||||
}
|
||||
assertTrue(jobRepository instanceof JobRepository);
|
||||
return (JobRepository) jobRepository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,16 @@ import org.junit.Test;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -37,11 +42,13 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Dan Garrette
|
||||
*/
|
||||
public class StepParserTests {
|
||||
|
||||
@@ -182,8 +189,7 @@ public class StepParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private StepExecutionListener getListener(String stepName, ApplicationContext ctx) throws Exception {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object compositeListener = ReflectionTestUtils.getField(step, "stepExecutionListener");
|
||||
@@ -199,34 +205,107 @@ public class StepParserTests {
|
||||
return listener;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DefaultTransactionAttribute getTransactionAttribute(ApplicationContext ctx, String stepName) {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object transactionAttribute = ReflectionTestUtils.getField(step, "transactionAttribute");
|
||||
DefaultTransactionAttribute txa = (DefaultTransactionAttribute) transactionAttribute;
|
||||
return txa;
|
||||
return (DefaultTransactionAttribute) transactionAttribute;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritFromBean() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
|
||||
assertTrue(getTasklet("s9", ctx) instanceof DummyTasklet);
|
||||
assertTrue(getTasklet("s10", ctx) instanceof DummyTasklet);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Tasklet getTasklet(String stepName, ApplicationContext ctx) {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof Tasklet);
|
||||
return (Tasklet)tasklet;
|
||||
return (Tasklet) tasklet;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobRepositoryDefaults() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStepWithParent", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("overrideRepoStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertDummyJobRepository("injectedRepoStep", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoStepWithParent", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedOverrideRepoStep", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoFromParentStep", "dummyJobRepository2", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoFromParentStepWithParent", "dummyJobRepository2", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedOverrideRepoFromParentStep", "dummyJobRepository2", ctx);
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStandaloneStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertDummyJobRepository("specifiedRepoStandaloneStep", "dummyJobRepository2", ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionManagerDefaults() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
assertTrue(getTransactionManager("defaultTxMgrStep", ctx) instanceof ResourcelessTransactionManager);
|
||||
|
||||
assertDummyTransactionManager("specifiedTxMgrStep", "dummyTxMgr", ctx);
|
||||
|
||||
assertDummyTransactionManager("defaultTxMgrWithParentStep", "dummyTxMgr", ctx);
|
||||
|
||||
assertDummyTransactionManager("overrideTxMgrOnParentStep", "dummyTxMgr2", ctx);
|
||||
}
|
||||
|
||||
private void assertDummyJobRepository(String beanName, String jobRepoName, ApplicationContext ctx) throws Exception {
|
||||
JobRepository jobRepository = getJobRepository(beanName, ctx);
|
||||
assertTrue(jobRepository instanceof DummyJobRepository);
|
||||
assertEquals(jobRepoName, ((DummyJobRepository) jobRepository).getName());
|
||||
}
|
||||
|
||||
private void assertDummyTransactionManager(String beanName, String txMgrName, ApplicationContext ctx)
|
||||
throws Exception {
|
||||
PlatformTransactionManager txMgr = getTransactionManager(beanName, ctx);
|
||||
assertTrue(txMgr instanceof DummyPlatformTransactionManager);
|
||||
assertEquals(txMgrName, ((DummyPlatformTransactionManager) txMgr).getName());
|
||||
}
|
||||
|
||||
private JobRepository getJobRepository(String beanName, ApplicationContext ctx) throws Exception {
|
||||
Object jobRepository = getFieldFromBean(beanName, "jobRepository", ctx);
|
||||
assertTrue(jobRepository instanceof JobRepository);
|
||||
return (JobRepository) jobRepository;
|
||||
}
|
||||
|
||||
private PlatformTransactionManager getTransactionManager(String beanName, ApplicationContext ctx) throws Exception {
|
||||
Object jobRepository = getFieldFromBean(beanName, "transactionManager", ctx);
|
||||
assertTrue(jobRepository instanceof PlatformTransactionManager);
|
||||
return (PlatformTransactionManager) jobRepository;
|
||||
}
|
||||
|
||||
private Object getFieldFromBean(String beanName, String field, ApplicationContext ctx) throws Exception {
|
||||
assertTrue(ctx.containsBean(beanName));
|
||||
Object bean = ctx.getBean(beanName);
|
||||
assertTrue(bean instanceof AbstractStep || bean instanceof AbstractJob);
|
||||
Object property = ReflectionTestUtils.getField(bean, field);
|
||||
while (property instanceof Advised) {
|
||||
property = ((Advised) property).getTargetSource().getTarget();
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user