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:
dhgarrette
2009-05-18 23:54:18 +00:00
parent d7d3be4223
commit 9bdfdcbc43
19 changed files with 762 additions and 170 deletions

View File

@@ -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) {
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

@@ -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;
}
}