BATCH-2002: JSR Property Substitution Language
This commit is contained in:
@@ -49,9 +49,16 @@ import javax.batch.api.partition.PartitionReducer;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.scope.StepScope;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanExpressionResolver;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
@@ -64,10 +71,12 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Michael Minella
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BatchPropertyBeanPostProcessor implements BeanPostProcessor {
|
||||
@Autowired
|
||||
public class BatchPropertyBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {
|
||||
private BatchPropertyContext batchPropertyContext;
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
private ConfigurableListableBeanFactory beanFactory;
|
||||
private BeanExpressionContext beanExpressionContext;
|
||||
private BeanExpressionResolver expressionResolver = new StandardBeanExpressionResolver();
|
||||
private Set<Class<? extends Annotation>> requiredAnnotations = new HashSet<Class<? extends Annotation>>();
|
||||
|
||||
public BatchPropertyBeanPostProcessor() {
|
||||
@@ -96,12 +105,12 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor {
|
||||
ClassLoader cl = BatchPropertyBeanPostProcessor.class.getClassLoader();
|
||||
|
||||
try {
|
||||
this.requiredAnnotations.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
|
||||
requiredAnnotations.add((Class<? extends Annotation>) cl.loadClass("javax.inject.Inject"));
|
||||
} catch (ClassNotFoundException ex) {
|
||||
logger.warn("javax.inject.Inject not found - @BatchProperty marked fields will not be processed.");
|
||||
}
|
||||
|
||||
this.requiredAnnotations.add(BatchProperty.class);
|
||||
requiredAnnotations.add(BatchProperty.class);
|
||||
}
|
||||
|
||||
private boolean isBatchArtifact(Object bean) {
|
||||
@@ -162,7 +171,9 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private String getBatchProperty(String propertyKey, Properties batchArtifactProperties) {
|
||||
if (batchArtifactProperties.containsKey(propertyKey)) {
|
||||
return (String) batchArtifactProperties.get(propertyKey);
|
||||
String propertyValue = (String) batchArtifactProperties.get(propertyKey);
|
||||
|
||||
return (String) expressionResolver.evaluate(propertyValue, beanExpressionContext);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -170,7 +181,7 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
private boolean isAnnotated(Field field) {
|
||||
for (Class<? extends Annotation> annotation : requiredAnnotations) {
|
||||
if(!field.isAnnotationPresent(annotation)) {
|
||||
if (!field.isAnnotationPresent(annotation)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -186,4 +197,20 @@ public class BatchPropertyBeanPostProcessor implements BeanPostProcessor {
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (!(beanFactory instanceof ConfigurableListableBeanFactory)) {
|
||||
throw new IllegalArgumentException(
|
||||
"BatchPropertyBeanPostProcessor requires a ConfigurableListableBeanFactory");
|
||||
}
|
||||
|
||||
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
|
||||
this.beanExpressionContext = new BeanExpressionContext(this.beanFactory, this.beanFactory.getBean(StepScope.class));
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setBatchPropertyContext(BatchPropertyContext batchPropertyContext) {
|
||||
this.batchPropertyContext = batchPropertyContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,11 +31,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BatchPropertyContext {
|
||||
private static final String JOB_ARTIFACT_PROPERTY_PREFIX = "job-";
|
||||
|
||||
private ConcurrentHashMap<String, Properties> batchProperties = new ConcurrentHashMap<String, Properties>();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Adds each of the provided {@link BatchPropertyContext} objects to the existing propery
|
||||
* Adds each of the provided {@link BatchPropertyContext} objects to the existing property
|
||||
* context.
|
||||
* </p>
|
||||
*
|
||||
@@ -61,19 +63,21 @@ public class BatchPropertyContext {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtains all properties for the specific batch artifact / bean name without any job level
|
||||
* properties.
|
||||
* </p>
|
||||
*
|
||||
* @param beanName the batch artifact / bean name to obtain {@link Properties} for
|
||||
* @return the step level {@link Properties}
|
||||
*/
|
||||
public Properties getStepLevelProperties(String beanName) {
|
||||
Properties properties = new Properties();
|
||||
String originalBeanName = getOriginalBeanName(beanName);
|
||||
|
||||
if (batchProperties.containsKey(beanName)) {
|
||||
properties.putAll(batchProperties.get(beanName));
|
||||
} else {
|
||||
if(beanName.startsWith("scopedTarget")) {
|
||||
beanName = beanName.substring(13);
|
||||
}
|
||||
|
||||
if(batchProperties.containsKey(beanName)) {
|
||||
properties.putAll(batchProperties.get(beanName));
|
||||
}
|
||||
if (batchProperties.containsKey(originalBeanName)) {
|
||||
properties.putAll(batchProperties.get(originalBeanName));
|
||||
}
|
||||
|
||||
return properties;
|
||||
@@ -82,7 +86,8 @@ public class BatchPropertyContext {
|
||||
/**
|
||||
* <p>
|
||||
* Obtains the batch {@link Properties} for the provided bean name / batch artifact. The returned
|
||||
* {@link Properties} will also contain any job level properties that have been set.
|
||||
* {@link Properties} will also contain any job level properties that have been set. Job level
|
||||
* properties will not override existing lower level artifact properties.
|
||||
* </p>
|
||||
*
|
||||
* @param beanName the bean name representing the batch artifact to obtain properties for
|
||||
@@ -90,32 +95,53 @@ public class BatchPropertyContext {
|
||||
*/
|
||||
public Properties getBatchProperties(String beanName) {
|
||||
Properties properties = new Properties();
|
||||
String originalBeanName = getOriginalBeanName(beanName);
|
||||
|
||||
if (batchProperties.containsKey(beanName)) {
|
||||
properties.putAll(batchProperties.get(beanName));
|
||||
} else {
|
||||
if(beanName.startsWith("scopedTarget")) {
|
||||
beanName = beanName.substring(13);
|
||||
}
|
||||
|
||||
if(batchProperties.containsKey(beanName)) {
|
||||
properties.putAll(batchProperties.get(beanName));
|
||||
}
|
||||
if (batchProperties.containsKey(originalBeanName)) {
|
||||
properties.putAll(batchProperties.get(originalBeanName));
|
||||
}
|
||||
|
||||
for (String jobLevelProperty : batchProperties.keySet()) {
|
||||
if (jobLevelProperty.startsWith("job-")) {
|
||||
if (batchProperties.containsKey(jobLevelProperty)) {
|
||||
properties.putAll(batchProperties.get(jobLevelProperty));
|
||||
}
|
||||
Properties jobLevelProperties = getJobProperties();
|
||||
|
||||
break;
|
||||
for (String jobLevelProperty : jobLevelProperties.stringPropertyNames()) {
|
||||
if (!properties.containsKey(jobLevelProperty)) {
|
||||
properties.put(jobLevelProperty, jobLevelProperties.getProperty(jobLevelProperty));
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Obtains all {@link Properties} that reside at the Job level configuration.
|
||||
* </p>
|
||||
*
|
||||
* @return the job level {@link Properties}
|
||||
*/
|
||||
public Properties getJobProperties() {
|
||||
Properties jobProperties = new Properties();
|
||||
|
||||
for (String jobLevelProperty : batchProperties.keySet()) {
|
||||
if (jobLevelProperty.startsWith(JOB_ARTIFACT_PROPERTY_PREFIX)) {
|
||||
if (batchProperties.containsKey(jobLevelProperty)) {
|
||||
jobProperties.putAll(batchProperties.get(jobLevelProperty));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return jobProperties;
|
||||
}
|
||||
|
||||
protected String getOriginalBeanName(String beanName) {
|
||||
if (beanName.startsWith("scopedTarget")) {
|
||||
return beanName.substring(13);
|
||||
}
|
||||
|
||||
return beanName;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Simple object to encapsulate batch properties of a given bean / batch artifact.
|
||||
|
||||
@@ -66,7 +66,6 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
|
||||
parserContext.getRegistry().registerBeanDefinition("stepContextFactory", stepContextBeanDefinition);
|
||||
|
||||
new ListnerParser(JobListenerFactoryBean.class, "jobExecutionListeners").parseListeners(element, parserContext, builder);
|
||||
new PropertyParser("job-" + jobName, parserContext).parseProperties(element);
|
||||
new PropertyParser(PropertyParser.JOB_ARTIFACT_PROPERTY_PREFIX + jobName, parserContext).parseProperties(element);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@
|
||||
*/
|
||||
package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
@@ -28,30 +30,35 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Parser for the <properties /> element defined by JSR-352.
|
||||
* Parser for the <properties /> element defined by JSR-352. Parsed job level properties are
|
||||
* also registered as a Map similar to systemProperties. Job level properties can be obtained for
|
||||
* example through SPeL by referencing #{jobProperties['key']}.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
public class PropertyParser {
|
||||
private static final String PROPERTY_ELEMENT = "property";
|
||||
private static final String PROPERTIES_ELEMENT = "properties";
|
||||
private static final String PROPERTY_NAME_ATTRIBUTE = "name";
|
||||
private static final String PROPERTY_VALUE_ATTRIBUTE = "value";
|
||||
private static final String BATCH_CONTEXT_ENTRIES_PROPERTY_NAME = "batchContextEntries";
|
||||
private static final String BATCH_PROPERTY_CONTEXT_BEAN_CLASS_NAME = "org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext";
|
||||
private static final String BATCH_PROPERTY_CONTEXT_BEAN_NAME = "batchPropertyContext";
|
||||
static final String JOB_ARTIFACT_PROPERTY_PREFIX = "job-";
|
||||
private static final String PROPERTY_ELEMENT = "property";
|
||||
private static final String PROPERTIES_ELEMENT = "properties";
|
||||
private static final String PROPERTY_NAME_ATTRIBUTE = "name";
|
||||
private static final String PROPERTY_VALUE_ATTRIBUTE = "value";
|
||||
private static final String JOB_PROPERTIES_BEAN_NAME = "jobProperties";
|
||||
private static final String BATCH_CONTEXT_ENTRIES_PROPERTY_NAME = "batchContextEntries";
|
||||
private static final String BATCH_PROPERTY_CONTEXT_BEAN_CLASS_NAME = "org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext";
|
||||
private static final String BATCH_PROPERTY_CONTEXT_BEAN_NAME = "batchPropertyContext";
|
||||
|
||||
private String beanName;
|
||||
private ParserContext parserContext;
|
||||
private String beanName;
|
||||
private ParserContext parserContext;
|
||||
|
||||
public PropertyParser(String beanName, ParserContext parserContext) {
|
||||
this.beanName = beanName;
|
||||
this.parserContext = parserContext;
|
||||
public PropertyParser(String beanName, ParserContext parserContext) {
|
||||
this.beanName = beanName;
|
||||
this.parserContext = parserContext;
|
||||
|
||||
registerBatchPropertyContext();
|
||||
}
|
||||
registerBatchPropertyContext();
|
||||
registerJobProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -60,27 +67,29 @@ public class PropertyParser {
|
||||
* which represent the property entries key and value.
|
||||
* </p>
|
||||
*
|
||||
* @param element
|
||||
* @param element the element to parse looking for <properties />
|
||||
*/
|
||||
public void parseProperties(Element element) {
|
||||
List<Element> propertiesElements = DomUtils.getChildElementsByTagName(element, PROPERTIES_ELEMENT);
|
||||
public void parseProperties(Element element) {
|
||||
List<Element> propertiesElements = DomUtils.getChildElementsByTagName(element, PROPERTIES_ELEMENT);
|
||||
|
||||
Properties properties = new Properties();
|
||||
Properties properties = new Properties();
|
||||
|
||||
if (propertiesElements.size() == 1) {
|
||||
List<Element> propertyElements = DomUtils.getChildElementsByTagName(propertiesElements.get(0), PROPERTY_ELEMENT);
|
||||
if (propertiesElements.size() == 1) {
|
||||
List<Element> propertyElements = DomUtils.getChildElementsByTagName(propertiesElements.get(0), PROPERTY_ELEMENT);
|
||||
|
||||
for (Element propertyElement : propertyElements) {
|
||||
properties.put(propertyElement.getAttribute(PROPERTY_NAME_ATTRIBUTE), propertyElement.getAttribute(PROPERTY_VALUE_ATTRIBUTE));
|
||||
}
|
||||
for (Element propertyElement : propertyElements) {
|
||||
properties.put(propertyElement.getAttribute(PROPERTY_NAME_ATTRIBUTE), propertyElement.getAttribute(PROPERTY_VALUE_ATTRIBUTE));
|
||||
}
|
||||
|
||||
addProperties(properties);
|
||||
} else if (propertiesElements.size() > 1) {
|
||||
parserContext.getReaderContext().error("The <properties> element may not appear more than once in a single <listener>.", element);
|
||||
}
|
||||
}
|
||||
addProperties(properties);
|
||||
} else if (propertiesElements.size() > 1) {
|
||||
parserContext.getReaderContext().error("The <properties> element may not appear more than once in a single <listener>.", element);
|
||||
}
|
||||
|
||||
private void addProperties(Properties properties) {
|
||||
setJobProperties(properties);
|
||||
}
|
||||
|
||||
private void addProperties(Properties properties) {
|
||||
BeanDefinition beanDefinition = parserContext.getRegistry().getBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME);
|
||||
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
@@ -92,17 +101,41 @@ public class PropertyParser {
|
||||
managedList.add(batchPropertyContextEntry);
|
||||
|
||||
beanDefinition.getPropertyValues().addPropertyValue(BATCH_CONTEXT_ENTRIES_PROPERTY_NAME, managedList);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerBatchPropertyContext() {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder batchPropertyContextBeanDefinitionBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_CLASS_NAME);
|
||||
private void registerBatchPropertyContext() {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME)) {
|
||||
BeanDefinitionBuilder batchPropertyContextBeanDefinitionBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_CLASS_NAME);
|
||||
|
||||
AbstractBeanDefinition batchPropertyContextBeanDefinition = batchPropertyContextBeanDefinitionBuilder.getBeanDefinition();
|
||||
batchPropertyContextBeanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
AbstractBeanDefinition batchPropertyContextBeanDefinition = batchPropertyContextBeanDefinitionBuilder.getBeanDefinition();
|
||||
batchPropertyContextBeanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME, batchPropertyContextBeanDefinition);
|
||||
}
|
||||
}
|
||||
parserContext.getRegistry().registerBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME, batchPropertyContextBeanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerJobProperties() {
|
||||
if (!parserContext.getRegistry().containsBeanDefinition(JOB_PROPERTIES_BEAN_NAME)) {
|
||||
AbstractBeanDefinition jobPropertiesBeanDefinition = BeanDefinitionBuilder.genericBeanDefinition(HashMap.class).getBeanDefinition();
|
||||
jobPropertiesBeanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
|
||||
parserContext.getRegistry().registerBeanDefinition(JOB_PROPERTIES_BEAN_NAME, jobPropertiesBeanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
private void setJobProperties(Properties properties) {
|
||||
if (beanName.startsWith(JOB_ARTIFACT_PROPERTY_PREFIX)) {
|
||||
Map<String, String> jobProperties = new HashMap<String, String>();
|
||||
|
||||
if (properties != null) {
|
||||
for (String param : properties.stringPropertyNames()) {
|
||||
jobProperties.put(param, properties.getProperty(param));
|
||||
}
|
||||
}
|
||||
|
||||
BeanDefinition jobPropertiesBeanDefinition = parserContext.getRegistry().getBeanDefinition(JOB_PROPERTIES_BEAN_NAME);
|
||||
jobPropertiesBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(jobProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -502,6 +502,7 @@ public class JsrJobOperator implements JobOperator {
|
||||
|
||||
batchContext.setParent(baseContext);
|
||||
batchContext.refresh();
|
||||
|
||||
final Job job = batchContext.getBean(Job.class);
|
||||
|
||||
Assert.notNull(jobName, "The job name must not be null.");
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* Copyright 2013 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.jsr.configuration.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test cases around {@link BatchPropertyContext}.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
*/
|
||||
public class BatchPropertyContextTests {
|
||||
private List<BatchPropertyContext.BatchPropertyContextEntry> entries = new ArrayList<BatchPropertyContext.BatchPropertyContextEntry>();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
|
||||
Properties bean1Properties = new Properties();
|
||||
bean1Properties.setProperty("readerName", "bean1readerName");
|
||||
bean1Properties.setProperty("readerWriter", "bean1writerName");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("bean1", bean1Properties));
|
||||
|
||||
Properties bean2Properties = new Properties();
|
||||
bean2Properties.setProperty("readerName", "bean2readerName");
|
||||
bean2Properties.setProperty("readerWriter", "bean2writerName");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("bean2", bean2Properties));
|
||||
|
||||
Properties jobProperties = new Properties();
|
||||
jobProperties.setProperty("jobProperty1", "jobProperty1value");
|
||||
jobProperties.setProperty("jobProperty2", "jobProperty2value");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("job-testJob", jobProperties));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddBatchContextEntries() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean1 = batchPropertyContext.getBatchProperties("bean1");
|
||||
assertEquals(4, bean1.size());
|
||||
assertEquals("bean1readerName", bean1.getProperty("readerName"));
|
||||
assertEquals("bean1writerName", bean1.getProperty("readerWriter"));
|
||||
assertEquals("jobProperty1value", bean1.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean1.getProperty("jobProperty2"));
|
||||
|
||||
Properties bean2 = batchPropertyContext.getBatchProperties("bean2");
|
||||
assertEquals(4, bean2.size());
|
||||
assertEquals("bean2readerName", bean2.getProperty("readerName"));
|
||||
assertEquals("bean2writerName", bean2.getProperty("readerWriter"));
|
||||
assertEquals("jobProperty1value", bean2.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean2.getProperty("jobProperty2"));
|
||||
|
||||
Properties jobProperties = batchPropertyContext.getBatchProperties("job-testJob");
|
||||
assertEquals(2, jobProperties.size());
|
||||
assertEquals("jobProperty1value", jobProperties.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", jobProperties.getProperty("jobProperty2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddBatchContextEntriesToExistingArtifact() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
|
||||
Properties bean2Properties = new Properties();
|
||||
bean2Properties.setProperty("processorName", "bean2processorName");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("bean2", bean2Properties));
|
||||
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean2 = batchPropertyContext.getBatchProperties("bean2");
|
||||
assertEquals(5, bean2.size());
|
||||
assertEquals("bean2readerName", bean2.getProperty("readerName"));
|
||||
assertEquals("bean2writerName", bean2.getProperty("readerWriter"));
|
||||
assertEquals("bean2processorName", bean2.getProperty("processorName"));
|
||||
assertEquals("jobProperty1value", bean2.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean2.getProperty("jobProperty2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStepLevelProperties() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean1 = batchPropertyContext.getStepLevelProperties("bean1");
|
||||
assertEquals(2, bean1.size());
|
||||
assertEquals("bean1readerName", bean1.getProperty("readerName"));
|
||||
assertEquals("bean1writerName", bean1.getProperty("readerWriter"));
|
||||
|
||||
Properties bean2 = batchPropertyContext.getStepLevelProperties("bean2");
|
||||
assertEquals(2, bean2.size());
|
||||
assertEquals("bean2readerName", bean2.getProperty("readerName"));
|
||||
assertEquals("bean2writerName", bean2.getProperty("readerWriter"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetScopedStepLevelProperties() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
|
||||
Properties scopedBeanProperties = new Properties();
|
||||
scopedBeanProperties.setProperty("scopedBeanName", "scopedBeanValue");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("scopedBean", scopedBeanProperties));
|
||||
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean1 = batchPropertyContext.getStepLevelProperties("bean1");
|
||||
assertEquals(2, bean1.size());
|
||||
assertEquals("bean1readerName", bean1.getProperty("readerName"));
|
||||
assertEquals("bean1writerName", bean1.getProperty("readerWriter"));
|
||||
|
||||
Properties bean2 = batchPropertyContext.getStepLevelProperties("bean2");
|
||||
assertEquals(2, bean2.size());
|
||||
assertEquals("bean2readerName", bean2.getProperty("readerName"));
|
||||
assertEquals("bean2writerName", bean2.getProperty("readerWriter"));
|
||||
|
||||
Properties scopedBean = batchPropertyContext.getStepLevelProperties("scopedTarget.scopedBean");
|
||||
assertEquals(1, scopedBean.size());
|
||||
assertEquals("scopedBeanValue", scopedBean.getProperty("scopedBeanName"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetScopedBatchProperties() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
|
||||
Properties scopedBeanProperties = new Properties();
|
||||
scopedBeanProperties.setProperty("scopedBeanName", "scopedBeanValue");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("scopedBean", scopedBeanProperties));
|
||||
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean1 = batchPropertyContext.getBatchProperties("bean1");
|
||||
assertEquals(4, bean1.size());
|
||||
assertEquals("bean1readerName", bean1.getProperty("readerName"));
|
||||
assertEquals("bean1writerName", bean1.getProperty("readerWriter"));
|
||||
assertEquals("jobProperty1value", bean1.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean1.getProperty("jobProperty2"));
|
||||
|
||||
Properties bean2 = batchPropertyContext.getBatchProperties("bean2");
|
||||
assertEquals(4, bean2.size());
|
||||
assertEquals("bean2readerName", bean2.getProperty("readerName"));
|
||||
assertEquals("bean2writerName", bean2.getProperty("readerWriter"));
|
||||
assertEquals("jobProperty1value", bean2.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean2.getProperty("jobProperty2"));
|
||||
|
||||
Properties scopedBean = batchPropertyContext.getBatchProperties("scopedTarget.scopedBean");
|
||||
assertEquals(3, scopedBean.size());
|
||||
assertEquals("scopedBeanValue", scopedBean.getProperty("scopedBeanName"));
|
||||
assertEquals("jobProperty1value", scopedBean.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", scopedBean.getProperty("jobProperty2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOriginalBeanName() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
String originalName = batchPropertyContext.getOriginalBeanName("scopedTarget.myBean");
|
||||
assertTrue(originalName.equals("myBean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobProperties() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties jobProperties = batchPropertyContext.getJobProperties();
|
||||
assertEquals(2, jobProperties.size());
|
||||
assertEquals("jobProperty1value", jobProperties.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", jobProperties.getProperty("jobProperty2"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobNonOverridingJobProperties() {
|
||||
BatchPropertyContext batchPropertyContext = new BatchPropertyContext();
|
||||
|
||||
Properties jobProperties = new Properties();
|
||||
jobProperties.setProperty("readerName", "testJobreaderName");
|
||||
entries.add(batchPropertyContext.new BatchPropertyContextEntry("job-testJob", jobProperties));
|
||||
|
||||
batchPropertyContext.setBatchContextEntries(entries);
|
||||
|
||||
Properties bean1 = batchPropertyContext.getBatchProperties("bean1");
|
||||
assertEquals(4, bean1.size());
|
||||
assertEquals("bean1readerName", bean1.getProperty("readerName"));
|
||||
assertEquals("bean1writerName", bean1.getProperty("readerWriter"));
|
||||
assertEquals("jobProperty1value", bean1.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", bean1.getProperty("jobProperty2"));
|
||||
|
||||
Properties testJobBean = batchPropertyContext.getBatchProperties("job-testJob");
|
||||
assertEquals(3, testJobBean.size());
|
||||
assertEquals("testJobreaderName", testJobBean.getProperty("readerName"));
|
||||
assertEquals("jobProperty1value", testJobBean.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty2value", testJobBean.getProperty("jobProperty2"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright 2013 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.jsr.configuration.xml;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import javax.batch.api.BatchProperty;
|
||||
import javax.batch.api.chunk.ItemProcessor;
|
||||
import javax.batch.api.chunk.ItemReader;
|
||||
import javax.batch.api.chunk.ItemWriter;
|
||||
import javax.inject.Inject;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.ExitStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test cases for JSR-352 job property substitution.
|
||||
* </p>
|
||||
*
|
||||
* TODO: enhance test cases with more complex substitutions
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JobPropertySubstitutionTests {
|
||||
@Autowired
|
||||
private Job job;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private TestItemWriter testItemWriter;
|
||||
|
||||
@Autowired
|
||||
private TestItemReader testItemReader;
|
||||
|
||||
@Test
|
||||
public void testSystemPropertySubstitution() throws Exception {
|
||||
assertEquals(System.getProperty("file.separator"), testItemReader.readerPropertyName1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobPropertySubstitution() throws Exception {
|
||||
assertEquals("jobPropertyValue1", testItemWriter.writerPropertyName1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobParameterSubstitution() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job,
|
||||
new JobParametersBuilder().addString("testParam", "testParamValue").toJobParameters());
|
||||
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
|
||||
}
|
||||
|
||||
public static final class TestItemReader implements ItemReader {
|
||||
private int cnt;
|
||||
|
||||
@Inject
|
||||
@BatchProperty
|
||||
String readerPropertyName1;
|
||||
|
||||
@Override
|
||||
public void open(Serializable serializable) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object readItem() throws Exception {
|
||||
if (cnt == 0) {
|
||||
cnt++;
|
||||
return "blah";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable checkpointInfo() throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestItemWriter implements ItemWriter {
|
||||
@Inject
|
||||
@BatchProperty
|
||||
String writerPropertyName1;
|
||||
|
||||
@Override
|
||||
public void open(Serializable serializable) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeItems(List<Object> objects) throws Exception {
|
||||
System.out.println(objects);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable checkpointInfo() throws Exception {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class TestItemProcessor implements ItemProcessor {
|
||||
@Inject
|
||||
@BatchProperty
|
||||
String processorProperty1;
|
||||
|
||||
@Override
|
||||
public Object processItem(Object item) throws Exception {
|
||||
assertEquals("testParamValue", processorProperty1);
|
||||
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,6 @@ import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@@ -82,9 +81,6 @@ public class JobPropertyTests {
|
||||
@Autowired
|
||||
private TestBatchlet testBatchlet;
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Test
|
||||
public void testJobLevelPropertiesInItemReader() throws Exception {
|
||||
assertEquals("jobPropertyValue1", testItemReader.getJobPropertyName1());
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
<?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.xsd
|
||||
http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd">
|
||||
|
||||
<!-- Not implemented (partition relatated): JSR 8.2.6.2, 8.2.6.3.1, 8.2.6.4.1, 8.2.6.5.1, 8.2.6.6.1 -->
|
||||
|
||||
<job id="job1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
|
||||
<properties>
|
||||
<property name="jobPropertyName1" value="jobPropertyValue1"/>
|
||||
</properties>
|
||||
|
||||
<step id="step1">
|
||||
<chunk>
|
||||
<reader ref="testReader">
|
||||
<properties>
|
||||
<property name="readerPropertyName1" value="#{systemProperties['file.separator']}"/>
|
||||
</properties>
|
||||
</reader>
|
||||
<processor ref="testProcessor">
|
||||
<properties>
|
||||
<property name="processorProperty1" value="#{jobParameters['testParam']}"/>
|
||||
</properties>
|
||||
</processor>
|
||||
<writer ref="testWriter">
|
||||
<properties>
|
||||
<property name="writerPropertyName1" value="#{jobProperties['jobPropertyName1']}"/>
|
||||
</properties>
|
||||
</writer>
|
||||
</chunk>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
|
||||
|
||||
<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.MapJobRepositoryFactoryBean"/>
|
||||
|
||||
<bean id="testReader" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertySubstitutionTests$TestItemReader"/>
|
||||
|
||||
<bean id="testWriter" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertySubstitutionTests$TestItemWriter"/>
|
||||
|
||||
<bean id="testProcessor" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertySubstitutionTests$TestItemProcessor"
|
||||
scope="step"/>
|
||||
</beans>
|
||||
@@ -106,20 +106,20 @@
|
||||
|
||||
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"/>
|
||||
|
||||
<bean id="testReader" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestItemReader"/>
|
||||
<bean id="testReader" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemReader"/>
|
||||
|
||||
<bean id="testProcessor" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestItemProcessor"/>
|
||||
<bean id="testProcessor" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemProcessor"/>
|
||||
|
||||
<bean id="testWriter" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestItemWriter"/>
|
||||
<bean id="testWriter" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemWriter"/>
|
||||
|
||||
<bean id="testCheckpointAlgorithm" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestCheckpointAlgorithm"/>
|
||||
<bean id="testCheckpointAlgorithm" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestCheckpointAlgorithm"/>
|
||||
|
||||
<bean id="testBatchlet" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestBatchlet"/>
|
||||
<bean id="testBatchlet" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestBatchlet"/>
|
||||
|
||||
<bean id="testStepListener" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestStepListener"/>
|
||||
<bean id="testStepListener" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestStepListener"/>
|
||||
|
||||
<bean id="testDecider" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.TestDecider"/>
|
||||
<bean id="testDecider" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestDecider"/>
|
||||
|
||||
<bean id="injectTestObj" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests.InjectTestObj"
|
||||
<bean id="injectTestObj" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$InjectTestObj"
|
||||
c:name="Chris"/>
|
||||
</beans>
|
||||
|
||||
Reference in New Issue
Block a user