From d3428d4fdd9fb8142a1aa6780d8ff696c061ba66 Mon Sep 17 00:00:00 2001 From: dsyer Date: Mon, 4 Jan 2010 08:12:17 +0000 Subject: [PATCH] BATCH-1475: Moved job parameters validator to a nested element --- .../core/configuration/xml/JobParser.java | 34 ++- .../configuration/xml/spring-batch-2.1.xsd | 275 +++++++----------- ...ava => JobParserParentAttributeTests.java} | 121 ++++---- .../xml/JobParserValidatorTests.java | 95 ++++++ .../JobParserParentAttributeTests-context.xml | 11 - .../xml/JobParserValidatorTests-context.xml | 40 +++ 6 files changed, 339 insertions(+), 237 deletions(-) rename spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/{JobParserTests.java => JobParserParentAttributeTests.java} (60%) create mode 100644 spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserValidatorTests.java create mode 100644 spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserValidatorTests-context.xml diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java index 96dcba420..5fdb39cb3 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/JobParser.java @@ -18,7 +18,9 @@ package org.springframework.batch.core.configuration.xml; import java.util.Arrays; import java.util.List; +import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.ManagedList; @@ -39,6 +41,12 @@ public class JobParser extends AbstractSingleBeanDefinitionParser { private static final String MERGE_ATTR = "merge"; + private static final String REF_ATTR = "ref"; + + private static final String BEAN_ELE = "bean"; + + private static final String REF_ELE = "ref"; + private static final JobExecutionListenerParser jobListenerParser = new JobExecutionListenerParser(); @Override @@ -83,9 +91,9 @@ public class JobParser extends AbstractSingleBeanDefinitionParser { builder.addPropertyReference("jobRepository", repositoryAttribute); } - String parametersValidator = element.getAttribute("parameters-validator"); - if (StringUtils.hasText(parametersValidator)) { - builder.addPropertyReference("jobParametersValidator", parametersValidator); + Element validator = DomUtils.getChildElementByTagName(element, "validator"); + if (validator != null) { + builder.addPropertyValue("jobParametersValidator", parseBeanElement(validator, parserContext)); } String restartableAttribute = element.getAttribute("restartable"); @@ -141,4 +149,24 @@ public class JobParser extends AbstractSingleBeanDefinitionParser { } + public BeanMetadataElement parseBeanElement(Element element, ParserContext parserContext) { + String refAttribute = element.getAttribute(REF_ATTR); + Element beanElement = DomUtils.getChildElementByTagName(element, BEAN_ELE); + Element refElement = DomUtils.getChildElementByTagName(element, REF_ELE); + + if (StringUtils.hasText(refAttribute)) { + return new RuntimeBeanReference(refAttribute); + } + else if (beanElement != null) { + return parserContext.getDelegate().parseBeanDefinitionElement(beanElement); + } + else if (refElement != null) { + return (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElement, null); + } + + parserContext.getReaderContext().error( + "One of ref attribute or a nested bean definition or ref element must be specified", element); + return null; + } + } diff --git a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.1.xsd b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.1.xsd index da48e2dcb..a992fcec2 100644 --- a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.1.xsd +++ b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.1.xsd @@ -1,8 +1,7 @@ - - + - + + + + + + + + + + + + + + + + - - - - - - - - - - - + - + - + - + - + - - + - + - + @@ -267,7 +261,8 @@ Defines a stage in job processing backed by a Step. The id attribute must be specified. The - step requires either + step + requires either a chunk definition, a tasklet reference, or a reference to a (possibly abstract) parent step. @@ -300,17 +295,14 @@ - + - - + @@ -320,17 +312,14 @@ - + - - + @@ -350,15 +339,13 @@ - - + @@ -386,8 +373,7 @@ - + @@ -407,42 +393,36 @@ - - + - - + - - + @@ -453,14 +433,12 @@ - - + @@ -489,8 +467,7 @@ - + @@ -501,7 +478,7 @@ Grid size for the handler. Defaults to 6.]]> - + @@ -548,12 +525,9 @@ - - - + + + - + - + @@ -581,8 +553,7 @@ - + @@ -594,8 +565,7 @@ ]]> - + - - + - + - + - @@ -665,8 +630,7 @@ - @@ -707,8 +671,7 @@ - + @@ -720,8 +683,7 @@ - + @@ -733,8 +695,7 @@ - + @@ -746,13 +707,11 @@ - + - + - + @@ -786,8 +744,7 @@ - + @@ -797,8 +754,7 @@ - + - + - + - + - + - + - + - + - + - - + @@ -1007,7 +953,8 @@ A reference to a listener, a POJO with a listener-annotated method, or a POJO with - a method referenced by a + a method + referenced by a *-method attribute. @@ -1057,8 +1004,7 @@ - + @@ -1102,7 +1048,8 @@ Declares job should be stop at this point and - provides pointer where execution should continue when + provides pointer where execution should continue + when the job is restarted. @@ -1112,7 +1059,8 @@ A pattern to match against the exit status code. Use * and ? as wildcard characters. - When a step finishes + When a step + finishes the most specific match will be chosen to select the next step. @@ -1122,7 +1070,8 @@ The name of the step to start on when the stopped job is restarted. - Must resolve to one of the other steps + Must resolve to one of the + other steps in this job. @@ -1134,7 +1083,8 @@ Declares job should end at this point, without the possibility of restart. - BatchStatus will be COMPLETED. + BatchStatus will be + COMPLETED. ExitStatus is configurable. @@ -1143,14 +1093,14 @@ A pattern to match against the exit status code. Use * and ? as wildcard characters. - When a step finishes + When a step + finishes the most specific match will be chosen to select the next step. - + The exit code value to end on, defaults to COMPLETED. @@ -1170,14 +1120,14 @@ A pattern to match against the exit status code. Use * and ? as wildcard characters. - When a step finishes + When a step + finishes the most specific match will be chosen to select the next step. - + The exit code value to end on, defaults to FAILED. @@ -1191,16 +1141,14 @@ - - + @@ -1227,11 +1175,13 @@ Is this bean "abstract", that is, not meant to be instantiated itself - but rather just serving as parent for concrete + but rather just serving as + parent for concrete child bean definitions? The default is "false". Specify "true" to tell the bean factory to not - try to instantiate that particular bean + try + to instantiate that particular bean in any case. Note: This attribute will not be inherited by child @@ -1249,7 +1199,8 @@ Should this list be merged with the corresponding list provided - by the parent? If not, it will overwrite the parent + by the parent? If not, it will + overwrite the parent list. @@ -1257,13 +1208,13 @@ - + This attribute indicates the method from the class that should - be used to dynamically create a proxy. + be used to dynamically create a + proxy. diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests.java similarity index 60% rename from spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java rename to spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests.java index 6201818eb..e5bb8a960 100644 --- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserTests.java +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests.java @@ -19,41 +19,60 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import org.junit.BeforeClass; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.aop.framework.Advised; import org.springframework.batch.core.Job; import org.springframework.batch.core.JobExecutionListener; import org.springframework.batch.core.job.AbstractJob; -import org.springframework.batch.core.job.DefaultJobParametersValidator; 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; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.util.ReflectionTestUtils; /** * @author Dan Garrette + * @author Dave Syer * @since 2.0 */ -public class JobParserTests { +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class JobParserParentAttributeTests { - private static ConfigurableApplicationContext jobParserParentAttributeTestsCtx; - - @BeforeClass - public static void loadAppCtx() { - jobParserParentAttributeTestsCtx = new ClassPathXmlApplicationContext( - "org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml"); - } + @Autowired + @Qualifier("listenerClearingJob") + private Job listenerClearingJob; + @Autowired + @Qualifier("defaultRepoJob") + private Job defaultRepoJob; + @Autowired + @Qualifier("specifiedRepoJob") + private Job specifiedRepoJob; + @Autowired + @Qualifier("inheritSpecifiedRepoJob") + private Job inheritSpecifiedRepoJob; + @Autowired + @Qualifier("overrideInheritedRepoJob") + private Job overrideInheritedRepoJob; + @Autowired + @Qualifier("job3") + private Job job3; + @Autowired + @Qualifier("job2") + private Job job2; + @Autowired + @Qualifier("job1") + private Job job1; @Test public void testInheritListeners() throws Exception { - List job1Listeners = getListeners("job1", jobParserParentAttributeTestsCtx); + List job1Listeners = getListeners(job1); assertEquals(2, job1Listeners.size()); boolean a = false; boolean b = false; @@ -71,7 +90,7 @@ public class JobParserTests { @Test public void testInheritListeners_NoMerge() throws Exception { - List job2Listeners = getListeners("job2", jobParserParentAttributeTestsCtx); + List job2Listeners = getListeners(job2); assertEquals(1, job2Listeners.size()); boolean c = false; for (Object l : job2Listeners) { @@ -84,7 +103,7 @@ public class JobParserTests { @Test public void testStandaloneListener() throws Exception { - List jobListeners = getListeners("job3", jobParserParentAttributeTestsCtx); + List jobListeners = getListeners(job3); assertEquals(2, jobListeners.size()); boolean a = false; boolean b = false; @@ -100,10 +119,31 @@ public class JobParserTests { assertTrue(b); } + @Test + public void testJobRepositoryDefaults() throws Exception { + assertTrue(getJobRepository(defaultRepoJob) instanceof SimpleJobRepository); + assertTrue(getJobRepository(specifiedRepoJob) instanceof DummyJobRepository); + assertTrue(getJobRepository(inheritSpecifiedRepoJob) instanceof DummyJobRepository); + assertTrue(getJobRepository(overrideInheritedRepoJob) instanceof SimpleJobRepository); + } + + @Test + public void testListenerClearingJob() throws Exception { + assertEquals(0, getListeners(listenerClearingJob).size()); + } + + private JobRepository getJobRepository(Job job) throws Exception { + 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; + } + @SuppressWarnings("unchecked") - private List getListeners(String jobName, ApplicationContext ctx) throws Exception { - assertTrue(ctx.containsBean(jobName)); - Job job = (Job) ctx.getBean(jobName); + private List getListeners(Job job) throws Exception { assertTrue(job instanceof AbstractJob); Object compositeListener = ReflectionTestUtils.getField(job, "listener"); @@ -118,48 +158,7 @@ public class JobParserTests { listeners.add(listener); } 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; - } - - @Test - public void testParametersValidator() { - ApplicationContext ctx = jobParserParentAttributeTestsCtx; - Job job = (Job) ctx.getBean("jobWithParametersValidator"); - assertTrue(job instanceof AbstractJob); - Object validator = ReflectionTestUtils.getField(job, "jobParametersValidator"); - assertTrue(validator instanceof DefaultJobParametersValidator); - @SuppressWarnings("unchecked") - Collection keys = (Collection) ReflectionTestUtils.getField(validator, "requiredKeys"); - assertEquals(2, keys.size()); - } - - @Test - public void testListenerClearingJob() throws Exception { - assertEquals(0, getListeners("listenerClearingJob", jobParserParentAttributeTestsCtx).size()); } } diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserValidatorTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserValidatorTests.java new file mode 100644 index 000000000..0f5221f25 --- /dev/null +++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/xml/JobParserValidatorTests.java @@ -0,0 +1,95 @@ +/* + * Copyright 2006-2007 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 static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.batch.core.Job; +import org.springframework.batch.core.JobParameters; +import org.springframework.batch.core.JobParametersInvalidException; +import org.springframework.batch.core.job.AbstractJob; +import org.springframework.batch.core.job.DefaultJobParametersValidator; +import org.springframework.batch.core.job.JobParametersValidator; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import org.springframework.test.util.ReflectionTestUtils; + +/** + * @author Dave Syer + * + */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class JobParserValidatorTests { + + @Autowired + @Qualifier("job1") + private Job job1; + + @Autowired + @Qualifier("job2") + private Job job2; + + @Autowired + @Qualifier("job3") + private Job job3; + + @Test(expected=JobParametersInvalidException.class) + public void testValidatorAttribute() throws Exception { + assertNotNull(job1); + JobParametersValidator validator = (JobParametersValidator) ReflectionTestUtils.getField(job1, + "jobParametersValidator"); + assertNotNull(validator); + validator.validate(new JobParameters()); + } + + @Test(expected=JobParametersInvalidException.class) + public void testValidatorRef() throws Exception { + assertNotNull(job2); + JobParametersValidator validator = (JobParametersValidator) ReflectionTestUtils.getField(job2, + "jobParametersValidator"); + assertNotNull(validator); + validator.validate(new JobParameters()); + } + + @Test(expected=JobParametersInvalidException.class) + public void testValidatorBean() throws Exception { + assertNotNull(job3); + JobParametersValidator validator = (JobParametersValidator) ReflectionTestUtils.getField(job3, + "jobParametersValidator"); + assertNotNull(validator); + validator.validate(new JobParameters()); + } + + @Test + public void testParametersValidator() { + assertTrue(job1 instanceof AbstractJob); + Object validator = ReflectionTestUtils.getField(job1, "jobParametersValidator"); + assertTrue(validator instanceof DefaultJobParametersValidator); + @SuppressWarnings("unchecked") + Collection keys = (Collection) ReflectionTestUtils.getField(validator, "requiredKeys"); + assertEquals(2, keys.size()); + } + +} diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml index 99e347737..2b52ea131 100644 --- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml @@ -67,17 +67,6 @@ - - - - - - - - - - diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserValidatorTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserValidatorTests-context.xml new file mode 100644 index 000000000..a52b50a65 --- /dev/null +++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobParserValidatorTests-context.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +