Remove property resolution through the original bean factory post processor and move resolution to
occur during XML pre-processing. JSR-352 allows for property replacement and expressions to be present on any element and the preprocessing provides the ability to load a well formed XML document into the context with the intended values already present.
This commit is contained in:
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* 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.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionVisitor;
|
||||
import org.springframework.beans.factory.config.BeanExpressionContext;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.context.expression.StandardBeanExpressionResolver;
|
||||
import org.springframework.core.PriorityOrdered;
|
||||
import org.springframework.util.StringValueResolver;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* This post processor will resolve values in bean definitions that represent #{jobParameter['key']}
|
||||
* expressions prior to the standard SPeL resolution if they correspond with an entry in the user
|
||||
* provided {@link java.util.Properties} to the start or restart methods of the
|
||||
* {@link org.springframework.batch.core.jsr.launch.JsrJobOperator}. This allows jobProperty replacements
|
||||
* to occur for elements that require resolution prior to context initialization and are not step scoped.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JobParameterResolvingBeanFactoryPostProcessor implements BeanFactoryPostProcessor, PriorityOrdered {
|
||||
private Properties properties;
|
||||
private JobParameterResolver jobParameterResolver;
|
||||
private static final Pattern JOB_PARAMETERS_KEY_PATTERN = Pattern.compile("'([^']*?)'");
|
||||
private static final Pattern JOB_PARAMETERS_PATTERN = Pattern.compile("(#\\{jobParameters[^}]+\\})");
|
||||
|
||||
public JobParameterResolvingBeanFactoryPostProcessor(Properties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
|
||||
*/
|
||||
@Override
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
if (jobParameterResolver == null) {
|
||||
this.jobParameterResolver = new JobParameterResolver(beanFactory, properties);
|
||||
}
|
||||
|
||||
String[] beanNames = beanFactory.getBeanDefinitionNames();
|
||||
|
||||
for (String curName : beanNames) {
|
||||
jobParameterResolver.visitBeanDefinition(beanFactory.getBeanDefinition(curName));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets this {@link BeanFactoryPostProcessor} to the highest precedence so that
|
||||
* it is executed as early as possible in the chain of {@link BeanFactoryPostProcessor}s
|
||||
*/
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return PriorityOrdered.HIGHEST_PRECEDENCE;
|
||||
}
|
||||
|
||||
protected class JobParameterResolver {
|
||||
private Properties properties;
|
||||
private JsrExpressionParser jsrExpressionParser;
|
||||
private BeanDefinitionVisitor beanDefinitionVisitor;
|
||||
|
||||
public JobParameterResolver(ConfigurableListableBeanFactory beanFactory, Properties properties) {
|
||||
this.properties = properties;
|
||||
this.jsrExpressionParser = new JsrExpressionParser(new StandardBeanExpressionResolver(), new BeanExpressionContext(beanFactory, null));
|
||||
this.beanDefinitionVisitor = new BeanDefinitionVisitor(new JobParameterStringValueResolver());
|
||||
}
|
||||
|
||||
public void visitBeanDefinition(BeanDefinition beanDefinition) {
|
||||
if (properties != null && ! properties.isEmpty() && ! "step".equals(beanDefinition.getScope())) {
|
||||
beanDefinitionVisitor.visitBeanDefinition(beanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
protected class JobParameterStringValueResolver implements StringValueResolver {
|
||||
private static final String NULL = "null";
|
||||
|
||||
@Override
|
||||
public String resolveStringValue(String value) {
|
||||
if (value != null && ! "".equals(value)) {
|
||||
String resolvedString = resolveJobParameters(value);
|
||||
|
||||
if (!"".equals(resolvedString)) {
|
||||
return jsrExpressionParser.parseExpression(resolvedString);
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
private String resolveJobParameters(String value) {
|
||||
StringBuffer valueBuffer = new StringBuffer();
|
||||
Matcher jobParameterMatcher = JOB_PARAMETERS_PATTERN.matcher(value);
|
||||
|
||||
while (jobParameterMatcher.find()) {
|
||||
Matcher jobParameterKeyMatcher = JOB_PARAMETERS_KEY_PATTERN.matcher(jobParameterMatcher.group(1));
|
||||
|
||||
if (jobParameterKeyMatcher.find()) {
|
||||
String extractedProperty = jobParameterKeyMatcher.group(1);
|
||||
|
||||
if (properties.containsKey(extractedProperty)) {
|
||||
String resolvedProperty = properties.getProperty(extractedProperty);
|
||||
jobParameterMatcher.appendReplacement(valueBuffer, resolvedProperty);
|
||||
} else {
|
||||
jobParameterMatcher.appendReplacement(valueBuffer, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
jobParameterMatcher.appendTail(valueBuffer);
|
||||
|
||||
return valueBuffer.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,8 @@ import org.springframework.util.StringUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsrExpressionParser {
|
||||
public static final String QUOTE = "'";
|
||||
private static final String QUOTE = "'";
|
||||
private static final String NULL = "null";
|
||||
private static final String ELVIS_RHS = ":";
|
||||
private static final String ELVIS_LHS = "\\?";
|
||||
private static final String ELVIS_OPERATOR = "?:";
|
||||
@@ -43,6 +44,15 @@ public class JsrExpressionParser {
|
||||
private BeanExpressionContext beanExpressionContext;
|
||||
private BeanExpressionResolver beanExpressionResolver;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a new instance of this expression parser without and expression resolver. Creating
|
||||
* an instance via this constructor will still parse expressions but no resolution of operators
|
||||
* will occur as its expected the caller will.
|
||||
* </p>
|
||||
*/
|
||||
public JsrExpressionParser() { }
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a new instances of this expression parser with the provided expression resolver and context to evaluate
|
||||
@@ -66,11 +76,13 @@ public class JsrExpressionParser {
|
||||
* @return a JSR-352 transformed expression that can be evaluated by a SPeL parser
|
||||
*/
|
||||
public String parseExpression(String expression) {
|
||||
if (StringUtils.countOccurrencesOf(expression, ELVIS_OPERATOR) > 0) {
|
||||
return parseConditionalExpressions(expression);
|
||||
String expressionToParse = expression;
|
||||
|
||||
if (StringUtils.countOccurrencesOf(expressionToParse, ELVIS_OPERATOR) > 0) {
|
||||
expressionToParse = parseConditionalExpressions(expressionToParse);
|
||||
}
|
||||
|
||||
return (String) beanExpressionResolver.evaluate(expression, beanExpressionContext);
|
||||
return evaluateExpression(expressionToParse);
|
||||
}
|
||||
|
||||
private String parseConditionalExpressions(String expression) {
|
||||
@@ -84,20 +96,35 @@ public class JsrExpressionParser {
|
||||
String value = conditionalExpression.split(ELVIS_LHS)[0];
|
||||
String defaultValue = conditionalExpression.split(ELVIS_RHS)[1];
|
||||
|
||||
StringBuilder parsedExpression = new StringBuilder()
|
||||
.append(EXPRESSION_PREFIX)
|
||||
.append((String) beanExpressionResolver.evaluate(value, beanExpressionContext))
|
||||
.append(ELVIS_OPERATOR)
|
||||
.append(QUOTE)
|
||||
.append((String) beanExpressionResolver.evaluate(defaultValue, beanExpressionContext))
|
||||
.append(QUOTE)
|
||||
.append(EXPRESSION_SUFFIX);
|
||||
StringBuilder parsedExpression = new StringBuilder();
|
||||
|
||||
if(beanExpressionResolver != null) {
|
||||
parsedExpression.append(EXPRESSION_PREFIX)
|
||||
.append(evaluateExpression(value))
|
||||
.append(ELVIS_OPERATOR)
|
||||
.append(QUOTE)
|
||||
.append(evaluateExpression(defaultValue))
|
||||
.append(QUOTE)
|
||||
.append(EXPRESSION_SUFFIX);
|
||||
} else {
|
||||
if(NULL.equals(value)) {
|
||||
parsedExpression.append(defaultValue);
|
||||
} else {
|
||||
parsedExpression.append(value);
|
||||
}
|
||||
}
|
||||
|
||||
expressionToParse = expressionToParse.replace(conditionalExpression, parsedExpression);
|
||||
}
|
||||
|
||||
expressionToParse = expressionToParse.replace(DEFAULT_VALUE_SEPARATOR, "");
|
||||
return expressionToParse.replace(DEFAULT_VALUE_SEPARATOR, "");
|
||||
}
|
||||
|
||||
return (String) beanExpressionResolver.evaluate(expressionToParse, beanExpressionContext);
|
||||
private String evaluateExpression(String expression) {
|
||||
if(beanExpressionResolver != null) {
|
||||
return (String) beanExpressionResolver.evaluate(expression, beanExpressionContext);
|
||||
}
|
||||
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.jsr.configuration.support.JsrExpressionParser;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
|
||||
import org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.ls.DOMImplementationLS;
|
||||
import org.w3c.dom.traversal.DocumentTraversal;
|
||||
import org.w3c.dom.traversal.NodeFilter;
|
||||
import org.w3c.dom.traversal.NodeIterator;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link DefaultBeanDefinitionDocumentReader} extension to hook into the pre/post processing of the provided
|
||||
* XML document, ensuring any references to property operators such as jobParameters and jobProperties are
|
||||
* resolved prior to loading the context. Since we know these initial values upfront, doing this transformation
|
||||
* allows us to ensure values are retrieved in their resolved form prior to loading the context and property
|
||||
* operators can be used on any element.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsrBeanDefinitionDocumentReader extends DefaultBeanDefinitionDocumentReader {
|
||||
private static final String NULL = "null";
|
||||
private static final String ROOT_JOB_ELEMENT_NAME = "job";
|
||||
private static final String JOB_PROPERTY_ELEMENT_NAME = "property";
|
||||
private static final String JOB_PROPERTIES_ELEMENT_NAME = "properties";
|
||||
private static final String JOB_PROPERTY_ELEMENT_NAME_ATTRIBUTE = "name";
|
||||
private static final String JOB_PROPERTY_ELEMENT_VALUE_ATTRIBUTE = "value";
|
||||
private static final String JOB_PROPERTIES_KEY_NAME = "jobProperties";
|
||||
private static final String JOB_PARAMETERS_KEY_NAME = "jobParameters";
|
||||
private static final String JOB_PARAMETERS_BEAN_DEFINITION_NAME = "jsr_jobParameters";
|
||||
private static final Log LOG = LogFactory.getLog(JsrBeanDefinitionDocumentReader.class);
|
||||
private static final Pattern PROPERTY_KEY_SEPERATOR = Pattern.compile("'([^']*?)'");
|
||||
private static final Pattern OPERATOR_PATTERN = Pattern.compile("(#\\{(job(Properties|Parameters))[^}]+\\})");
|
||||
|
||||
private BeanDefinitionRegistry beanDefinitionRegistry;
|
||||
private JsrExpressionParser expressionParser = new JsrExpressionParser();
|
||||
private Map<String, Properties> propertyMap = new HashMap<String, Properties>();
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Creates a new {@link JsrBeanDefinitionDocumentReader} instance.
|
||||
* </p>
|
||||
*/
|
||||
public JsrBeanDefinitionDocumentReader() { }
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new {@link JsrBeanDefinitionDocumentReader} instance with the provided
|
||||
* {@link BeanDefinitionRegistry}.
|
||||
* </p>
|
||||
*
|
||||
* @param beanDefinitionRegistry the {@link BeanDefinitionRegistry} to use
|
||||
*/
|
||||
public JsrBeanDefinitionDocumentReader(BeanDefinitionRegistry beanDefinitionRegistry) {
|
||||
this.beanDefinitionRegistry = beanDefinitionRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preProcessXml(Element root) {
|
||||
if (ROOT_JOB_ELEMENT_NAME.equals(root.getLocalName())) {
|
||||
initProperties(root);
|
||||
transformDocument(root);
|
||||
|
||||
if (LOG.isDebugEnabled()) {
|
||||
LOG.debug("Transformed XML from preProcessXml: " + elementToString(root));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void initProperties(Element root) {
|
||||
propertyMap.put(JOB_PARAMETERS_KEY_NAME, initJobParameters());
|
||||
propertyMap.put(JOB_PROPERTIES_KEY_NAME, initJobProperties(root));
|
||||
|
||||
resolvePropertyValues(propertyMap.get(JOB_PARAMETERS_KEY_NAME));
|
||||
resolvePropertyValues(propertyMap.get(JOB_PROPERTIES_KEY_NAME));
|
||||
}
|
||||
|
||||
private Properties initJobParameters() {
|
||||
Properties jobParameters = new Properties();
|
||||
|
||||
if (getBeanDefinitionRegistry().containsBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME)) {
|
||||
BeanDefinition beanDefintion = getBeanDefinitionRegistry().getBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME);
|
||||
|
||||
Properties properties = (Properties) beanDefintion.getConstructorArgumentValues()
|
||||
.getGenericArgumentValue(Properties.class)
|
||||
.getValue();
|
||||
|
||||
if (properties == null) {
|
||||
return new Properties();
|
||||
}
|
||||
|
||||
jobParameters.putAll(properties);
|
||||
}
|
||||
|
||||
return jobParameters;
|
||||
}
|
||||
|
||||
private Properties initJobProperties(Element root) {
|
||||
Properties properties = new Properties();
|
||||
Node propertiesNode = root.getElementsByTagName(JOB_PROPERTIES_ELEMENT_NAME).item(0);
|
||||
|
||||
if(propertiesNode != null) {
|
||||
NodeList children = propertiesNode.getChildNodes();
|
||||
|
||||
for(int i=0; i < children.getLength(); i++) {
|
||||
Node child = children.item(i);
|
||||
|
||||
if(JOB_PROPERTY_ELEMENT_NAME.equals(child.getLocalName())) {
|
||||
NamedNodeMap attributes = child.getAttributes();
|
||||
Node name = attributes.getNamedItem(JOB_PROPERTY_ELEMENT_NAME_ATTRIBUTE);
|
||||
Node value = attributes.getNamedItem(JOB_PROPERTY_ELEMENT_VALUE_ATTRIBUTE);
|
||||
|
||||
properties.setProperty(name.getNodeValue(), value.getNodeValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
private void resolvePropertyValues(Properties properties) {
|
||||
for (String propertyKey : properties.stringPropertyNames()) {
|
||||
String resolvedPropertyValue = resolvePropertyValue(properties.getProperty(propertyKey));
|
||||
|
||||
if(!properties.getProperty(propertyKey).equals(resolvedPropertyValue)) {
|
||||
properties.setProperty(propertyKey, resolvedPropertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String resolvePropertyValue(String propertyValue) {
|
||||
String resolvedValue = resolveValue(propertyValue);
|
||||
|
||||
Matcher jobParameterMatcher = OPERATOR_PATTERN.matcher(resolvedValue);
|
||||
|
||||
while (jobParameterMatcher.find()) {
|
||||
resolvedValue = resolvePropertyValue(resolvedValue);
|
||||
}
|
||||
|
||||
return resolvedValue;
|
||||
}
|
||||
|
||||
private String resolveValue(String value) {
|
||||
StringBuffer valueBuffer = new StringBuffer();
|
||||
Matcher jobParameterMatcher = OPERATOR_PATTERN.matcher(value);
|
||||
|
||||
while (jobParameterMatcher.find()) {
|
||||
Matcher jobParameterKeyMatcher = PROPERTY_KEY_SEPERATOR.matcher(jobParameterMatcher.group(1));
|
||||
|
||||
if (jobParameterKeyMatcher.find()) {
|
||||
String propertyType = jobParameterMatcher.group(2);
|
||||
String extractedProperty = jobParameterKeyMatcher.group(1);
|
||||
|
||||
Properties properties = propertyMap.get(propertyType);
|
||||
|
||||
if(properties == null) {
|
||||
throw new IllegalArgumentException("Unknown property type: " + propertyType);
|
||||
}
|
||||
|
||||
String resolvedProperty = properties.getProperty(extractedProperty, NULL);
|
||||
|
||||
if (NULL.equals(resolvedProperty)) {
|
||||
LOG.info(propertyType + " with key of: " + extractedProperty + " could not be resolved. Possible configuration error?");
|
||||
}
|
||||
|
||||
jobParameterMatcher.appendReplacement(valueBuffer, resolvedProperty);
|
||||
}
|
||||
}
|
||||
|
||||
jobParameterMatcher.appendTail(valueBuffer);
|
||||
String resolvedValue = valueBuffer.toString();
|
||||
|
||||
if (NULL.equals(resolvedValue)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return expressionParser.parseExpression(resolvedValue);
|
||||
}
|
||||
|
||||
private BeanDefinitionRegistry getBeanDefinitionRegistry() {
|
||||
return beanDefinitionRegistry != null ? beanDefinitionRegistry : getReaderContext().getRegistry();
|
||||
}
|
||||
|
||||
private void transformDocument(Element root) {
|
||||
DocumentTraversal traversal = (DocumentTraversal) root.getOwnerDocument();
|
||||
NodeIterator iterator = traversal.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, null, true);
|
||||
|
||||
for (Node n = iterator.nextNode(); n != null; n = iterator.nextNode()) {
|
||||
NamedNodeMap map = n.getAttributes();
|
||||
|
||||
if (map.getLength() > 0) {
|
||||
for (int i = 0; i < map.getLength(); i++) {
|
||||
Node node = map.item(i);
|
||||
String nodeValue = node.getNodeValue();
|
||||
String resolvedValue = resolveValue(nodeValue);
|
||||
|
||||
if(!nodeValue.equals(resolvedValue)) {
|
||||
node.setNodeValue(resolvedValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String nodeValue = n.getTextContent();
|
||||
String resolvedValue = resolveValue(nodeValue);
|
||||
|
||||
if(!nodeValue.equals(resolvedValue)) {
|
||||
n.setTextContent(resolvedValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Properties getJobParameters() {
|
||||
return propertyMap.get(JOB_PARAMETERS_KEY_NAME);
|
||||
}
|
||||
|
||||
protected Properties getJobProperties() {
|
||||
return propertyMap.get(JOB_PROPERTIES_KEY_NAME);
|
||||
}
|
||||
|
||||
private String elementToString(Element root) {
|
||||
DOMImplementationLS domImplLS = (DOMImplementationLS) root.getOwnerDocument().getImplementation();
|
||||
return domImplLS.createLSSerializer().writeToString(root);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.util.Properties;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* {@link GenericApplicationContext} implementation providing JSR-352 related context operations.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
public class JsrXmlApplicationContext extends GenericApplicationContext {
|
||||
private static final String JOB_PARAMETERS_BEAN_DEFINITION_NAME = "jsr_jobParameters";
|
||||
|
||||
private XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new context instance with no job parameters.
|
||||
* </p>
|
||||
*/
|
||||
public JsrXmlApplicationContext() {
|
||||
reader.setDocumentReaderClass(JsrBeanDefinitionDocumentReader.class);
|
||||
reader.setEnvironment(this.getEnvironment());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Create a new context instance using the provided {@link Properties} representing job
|
||||
* parameters when pre-processing the job definition document.
|
||||
* </p>
|
||||
*
|
||||
* @param jobParameters the {@link Properties} representing job parameters
|
||||
*/
|
||||
public JsrXmlApplicationContext(Properties jobParameters) {
|
||||
reader.setDocumentReaderClass(JsrBeanDefinitionDocumentReader.class);
|
||||
reader.setEnvironment(this.getEnvironment());
|
||||
|
||||
storeJobParameters(jobParameters);
|
||||
}
|
||||
|
||||
private void storeJobParameters(Properties properties) {
|
||||
BeanDefinition jobParameters = BeanDefinitionBuilder.genericBeanDefinition(Properties.class).getBeanDefinition();
|
||||
jobParameters.getConstructorArgumentValues().addGenericArgumentValue(properties != null ? properties : new Properties());
|
||||
|
||||
reader.getRegistry().registerBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME, jobParameters);
|
||||
}
|
||||
|
||||
protected XmlBeanDefinitionReader getReader() {
|
||||
return reader;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether to use XML validation. Default is <code>true</code>.
|
||||
*/
|
||||
public void setValidating(boolean validating) {
|
||||
this.reader.setValidating(validating);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load bean definitions from the given XML resources.
|
||||
* @param resources one or more resources to load from
|
||||
*/
|
||||
public void load(Resource... resources) {
|
||||
this.reader.loadBeanDefinitions(resources);
|
||||
}
|
||||
}
|
||||
@@ -42,6 +42,8 @@ public class ListenerParser {
|
||||
private static final String REF_ATTRIBUTE = "ref";
|
||||
private static final String LISTENER_ELEMENT = "listener";
|
||||
private static final String LISTENERS_ELEMENT = "listeners";
|
||||
private static final String SCOPE_STEP = "step";
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private Class listenerType;
|
||||
private String propertyKey;
|
||||
@@ -103,15 +105,35 @@ public class ListenerParser {
|
||||
}
|
||||
|
||||
protected void applyListenerScope(String beanName, BeanDefinitionRegistry beanDefinitionRegistry) {
|
||||
if (listenerType == JobListenerFactoryBean.class) {
|
||||
if (beanDefinitionRegistry.containsBeanDefinition(beanName)) {
|
||||
BeanDefinition beanDefinition = beanDefinitionRegistry.getBeanDefinition(beanName);
|
||||
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||
beanDefinition.setLazyInit(true);
|
||||
}
|
||||
BeanDefinition beanDefinition = getListenerBeanDefinition(beanName, beanDefinitionRegistry);
|
||||
beanDefinition.setScope(getListenerScope());
|
||||
beanDefinition.setLazyInit(isLazyInit());
|
||||
|
||||
if (!beanDefinitionRegistry.containsBeanDefinition(beanName)) {
|
||||
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition);
|
||||
}
|
||||
}
|
||||
|
||||
private BeanDefinition getListenerBeanDefinition(String beanName, BeanDefinitionRegistry beanDefinitionRegistry) {
|
||||
if (beanDefinitionRegistry.containsBeanDefinition(beanName)) {
|
||||
return beanDefinitionRegistry.getBeanDefinition(beanName);
|
||||
}
|
||||
|
||||
return BeanDefinitionBuilder.genericBeanDefinition(beanName).getBeanDefinition();
|
||||
}
|
||||
|
||||
private boolean isLazyInit() {
|
||||
return listenerType == JobListenerFactoryBean.class;
|
||||
}
|
||||
|
||||
private String getListenerScope() {
|
||||
if (listenerType == JobListenerFactoryBean.class) {
|
||||
return BeanDefinition.SCOPE_SINGLETON;
|
||||
}
|
||||
|
||||
return SCOPE_STEP;
|
||||
}
|
||||
|
||||
private BatchArtifact.BatchArtifactType getBatchArtifactType(String stepName) {
|
||||
return (stepName != null && !"".equals(stepName)) ? BatchArtifact.BatchArtifactType.STEP_ARTIFACT
|
||||
: BatchArtifact.BatchArtifactType.ARTIFACT;
|
||||
|
||||
@@ -55,7 +55,7 @@ import org.springframework.batch.core.converter.JobParametersConverter;
|
||||
import org.springframework.batch.core.explore.JobExplorer;
|
||||
import org.springframework.batch.core.jsr.JobContextFactoryBean;
|
||||
import org.springframework.batch.core.jsr.JsrJobParametersConverter;
|
||||
import org.springframework.batch.core.jsr.configuration.support.JobParameterResolvingBeanFactoryPostProcessor;
|
||||
import org.springframework.batch.core.jsr.configuration.xml.JsrXmlApplicationContext;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.scope.context.StepSynchronizationManager;
|
||||
import org.springframework.batch.core.step.NoSuchStepException;
|
||||
@@ -73,7 +73,6 @@ import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
|
||||
import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
@@ -450,7 +449,9 @@ public class JsrJobOperator implements JobOperator, InitializingBean {
|
||||
|
||||
String jobName = previousJobExecution.getJobInstance().getJobName();
|
||||
|
||||
final GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext();
|
||||
Properties jobRestartProperties = getJobRestartProperties(params, previousJobExecution);
|
||||
|
||||
final JsrXmlApplicationContext batchContext = new JsrXmlApplicationContext(jobRestartProperties);
|
||||
batchContext.setValidating(false);
|
||||
|
||||
Resource batchXml = new ClassPathResource("/META-INF/batch.xml");
|
||||
@@ -464,8 +465,6 @@ public class JsrJobOperator implements JobOperator, InitializingBean {
|
||||
batchContext.load(jobXml);
|
||||
}
|
||||
|
||||
batchContext.addBeanFactoryPostProcessor(new JobParameterResolvingBeanFactoryPostProcessor(params));
|
||||
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.jsr.JobContextFactoryBean").getBeanDefinition();
|
||||
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||
batchContext.registerBeanDefinition(JSR_JOB_CONTEXT_BEAN_NAME, beanDefinition);
|
||||
@@ -487,7 +486,6 @@ public class JsrJobOperator implements JobOperator, InitializingBean {
|
||||
final org.springframework.batch.core.JobExecution jobExecution;
|
||||
|
||||
try {
|
||||
Properties jobRestartProperties = getJobRestartProperties(params, previousJobExecution);
|
||||
JobParameters jobParameters = jobParametersConverter.getJobParameters(jobRestartProperties);
|
||||
jobExecution = jobRepository.createJobExecution(previousJobExecution.getJobInstance(), jobParameters, previousJobExecution.getJobConfigurationName());
|
||||
} catch (Exception e) {
|
||||
@@ -579,7 +577,7 @@ public class JsrJobOperator implements JobOperator, InitializingBean {
|
||||
@SuppressWarnings("resource")
|
||||
public long start(String jobName, Properties params) throws JobStartException,
|
||||
JobSecurityException {
|
||||
final GenericXmlApplicationContext batchContext = new GenericXmlApplicationContext();
|
||||
final JsrXmlApplicationContext batchContext = new JsrXmlApplicationContext(params);
|
||||
batchContext.setValidating(false);
|
||||
|
||||
Resource batchXml = new ClassPathResource("/META-INF/batch.xml");
|
||||
@@ -594,7 +592,6 @@ public class JsrJobOperator implements JobOperator, InitializingBean {
|
||||
batchContext.load(jobXml);
|
||||
}
|
||||
|
||||
batchContext.addBeanFactoryPostProcessor(new JobParameterResolvingBeanFactoryPostProcessor(params));
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.jsr.JobContextFactoryBean").getBeanDefinition();
|
||||
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
|
||||
batchContext.registerBeanDefinition(JSR_JOB_CONTEXT_BEAN_NAME, beanDefinition);
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
*/
|
||||
package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import javax.batch.api.BatchProperty;
|
||||
import javax.batch.api.Batchlet;
|
||||
@@ -28,18 +27,15 @@ import javax.batch.api.chunk.ItemProcessor;
|
||||
import javax.batch.api.chunk.ItemReader;
|
||||
import javax.batch.api.chunk.ItemWriter;
|
||||
import javax.batch.api.listener.StepListener;
|
||||
import javax.batch.runtime.BatchStatus;
|
||||
import javax.batch.runtime.JobExecution;
|
||||
import javax.batch.runtime.context.JobContext;
|
||||
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.JobParameters;
|
||||
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 org.springframework.batch.core.jsr.JsrTestUtils;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
@@ -47,20 +43,18 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
* @since 3.0
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JobPropertyTests {
|
||||
@Autowired
|
||||
private Job job;
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Test
|
||||
public void testJobPropertyConfiguration() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters());
|
||||
assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
|
||||
Properties jobParameters = new Properties();
|
||||
jobParameters.setProperty("allow.start.if.complete", "true");
|
||||
jobParameters.setProperty("deciderName", "stepDecider");
|
||||
jobParameters.setProperty("deciderNumber", "1");
|
||||
|
||||
JobExecution jobExecution = JsrTestUtils.runJob("jsrJobPropertyTests", jobParameters, 5000L);
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getBatchStatus());
|
||||
}
|
||||
|
||||
public static final class TestItemReader implements ItemReader {
|
||||
@@ -74,7 +68,7 @@ public class JobPropertyTests {
|
||||
@Inject @BatchProperty(name = "notDefinedAnnotationNamedProperty") String notDefinedAnnotationNamedProperty;
|
||||
@Inject @BatchProperty String jobPropertyName1;
|
||||
@Inject @BatchProperty String jobPropertyName2;
|
||||
@Inject InjectTestObj injectAnnotatedOnlyField;
|
||||
@Inject JobContext injectAnnotatedOnlyField;
|
||||
@BatchProperty String batchAnnotatedOnlyField;
|
||||
@Inject javax.batch.runtime.context.StepContext stepContext;
|
||||
|
||||
@@ -96,7 +90,7 @@ public class JobPropertyTests {
|
||||
org.springframework.util.Assert.isNull(notDefinedAnnotationNamedProperty);
|
||||
org.springframework.util.Assert.isNull(batchAnnotatedOnlyField);
|
||||
org.springframework.util.Assert.notNull(injectAnnotatedOnlyField);
|
||||
org.springframework.util.Assert.isTrue("Chris".equals(injectAnnotatedOnlyField.getName()));
|
||||
org.springframework.util.Assert.isTrue("job1".equals(injectAnnotatedOnlyField.getJobName()));
|
||||
org.springframework.util.Assert.isNull(readerPropertyName3);
|
||||
}
|
||||
|
||||
@@ -272,16 +266,4 @@ public class JobPropertyTests {
|
||||
public void stop() throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
public static class InjectTestObj {
|
||||
private String name;
|
||||
|
||||
public InjectTestObj(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.xml.DefaultDocumentLoader;
|
||||
import org.springframework.beans.factory.xml.DelegatingEntityResolver;
|
||||
import org.springframework.beans.factory.xml.DocumentLoader;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.util.xml.SimpleSaxErrorHandler;
|
||||
import org.w3c.dom.Document;
|
||||
import org.xml.sax.ErrorHandler;
|
||||
import org.xml.sax.InputSource;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test cases around {@link JsrBeanDefinitionDocumentReader}.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
*/
|
||||
public class JsrBeanDefinitionDocumentReaderTests {
|
||||
private static final String JOB_PARAMETERS_BEAN_DEFINITION_NAME = "jsr_jobParameters";
|
||||
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
private DocumentLoader documentLoader = new DefaultDocumentLoader();
|
||||
private ErrorHandler errorHandler = new SimpleSaxErrorHandler(logger);
|
||||
|
||||
@Test
|
||||
public void testGetJobParameters() {
|
||||
Properties jobParameters = new Properties();
|
||||
jobParameters.setProperty("jobParameter1", "jobParameter1Value");
|
||||
jobParameters.setProperty("jobParameter2", "jobParameter2Value");
|
||||
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext(jobParameters);
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.load(new ClassPathResource("baseContext.xml"),
|
||||
new ClassPathResource("/META-INF/batch.xml"),
|
||||
new ClassPathResource("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml"));
|
||||
applicationContext.refresh();
|
||||
|
||||
BeanDefinition beanDefinition = applicationContext.getBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME);
|
||||
|
||||
Properties processedJobParameters = (Properties) beanDefinition.getConstructorArgumentValues().getGenericArgumentValue(Properties.class).getValue();
|
||||
assertNotNull(processedJobParameters);
|
||||
assertTrue("Wrong number of job parameters", processedJobParameters.size() == 2);
|
||||
assertEquals("jobParameter1Value", processedJobParameters.getProperty("jobParameter1"));
|
||||
assertEquals("jobParameter2Value", processedJobParameters.getProperty("jobParameter2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJobProperties() {
|
||||
Document document = getDocument("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml");
|
||||
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext();
|
||||
JsrBeanDefinitionDocumentReader documentReader = new JsrBeanDefinitionDocumentReader(applicationContext);
|
||||
documentReader.initProperties(document.getDocumentElement());
|
||||
|
||||
Properties documentJobProperties = documentReader.getJobProperties();
|
||||
assertNotNull(documentJobProperties);
|
||||
assertTrue("Wrong number of job properties", documentJobProperties.size() == 3);
|
||||
assertEquals("jobProperty1Value", documentJobProperties.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty1Value", documentJobProperties.getProperty("jobProperty2"));
|
||||
assertEquals("", documentJobProperties.getProperty("jobProperty3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobParametersResolution() {
|
||||
Properties jobParameters = new Properties();
|
||||
jobParameters.setProperty("jobParameter1", "myfile.txt");
|
||||
jobParameters.setProperty("jobParameter2", "#{jobProperties['jobProperty2']}");
|
||||
jobParameters.setProperty("jobParameter3", "#{jobParameters['jobParameter1']}");
|
||||
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext(jobParameters);
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.load(new ClassPathResource("baseContext.xml"),
|
||||
new ClassPathResource("/META-INF/batch.xml"),
|
||||
new ClassPathResource("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml"));
|
||||
applicationContext.refresh();
|
||||
|
||||
Document document = getDocument("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml");
|
||||
|
||||
JsrBeanDefinitionDocumentReader documentReader = new JsrBeanDefinitionDocumentReader(applicationContext);
|
||||
documentReader.initProperties(document.getDocumentElement());
|
||||
|
||||
Properties resolvedParameters = documentReader.getJobParameters();
|
||||
|
||||
assertNotNull(resolvedParameters);
|
||||
assertTrue("Wrong number of job parameters", resolvedParameters.size() == 3);
|
||||
assertEquals("myfile.txt", resolvedParameters.getProperty("jobParameter1"));
|
||||
assertEquals("jobProperty1Value", resolvedParameters.getProperty("jobParameter2"));
|
||||
assertEquals("myfile.txt", resolvedParameters.getProperty("jobParameter3"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobPropertyResolution() {
|
||||
Properties jobParameters = new Properties();
|
||||
jobParameters.setProperty("file.name", "myfile.txt");
|
||||
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext(jobParameters);
|
||||
applicationContext.setValidating(false);
|
||||
applicationContext.load(new ClassPathResource("baseContext.xml"),
|
||||
new ClassPathResource("/META-INF/batch.xml"),
|
||||
new ClassPathResource("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml"));
|
||||
applicationContext.refresh();
|
||||
|
||||
Document document = getDocument("/META-INF/batch-jobs/jsrPropertyPreparseTestJob.xml");
|
||||
|
||||
JsrBeanDefinitionDocumentReader documentReader = new JsrBeanDefinitionDocumentReader(applicationContext);
|
||||
documentReader.initProperties(document.getDocumentElement());
|
||||
|
||||
Properties resolvedProperties = documentReader.getJobProperties();
|
||||
assertNotNull(resolvedProperties);
|
||||
assertTrue("Wrong number of job properties", resolvedProperties.size() == 3);
|
||||
assertEquals("jobProperty1Value", resolvedProperties.getProperty("jobProperty1"));
|
||||
assertEquals("jobProperty1Value", resolvedProperties.getProperty("jobProperty2"));
|
||||
assertEquals("myfile.txt", resolvedProperties.getProperty("jobProperty3"));
|
||||
}
|
||||
|
||||
private Document getDocument(String location) {
|
||||
InputStream inputStream = ClassLoader.class.getResourceAsStream(location);
|
||||
|
||||
try {
|
||||
return documentLoader.loadDocument(new InputSource(inputStream),
|
||||
new DelegatingEntityResolver(getClass().getClassLoader()), errorHandler, 0, true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
} finally {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) { }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import java.util.Properties;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertNotNull;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* Test cases around {@link JsrXmlApplicationContext}.
|
||||
* </p>
|
||||
*
|
||||
* @author Chris Schaefer
|
||||
*/
|
||||
public class JsrXmlApplicationContextTests {
|
||||
private static final String JOB_PARAMETERS_BEAN_DEFINITION_NAME = "jsr_jobParameters";
|
||||
|
||||
@Test
|
||||
public void testNullProperties() {
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext(null);
|
||||
|
||||
BeanDefinition beanDefinition = applicationContext.getBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME);
|
||||
Properties properties = (Properties) beanDefinition.getConstructorArgumentValues().getGenericArgumentValue(Properties.class).getValue();
|
||||
|
||||
assertNotNull("Properties should not be null", properties);
|
||||
assertTrue("Properties should be empty", properties.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWithProperties() {
|
||||
Properties properties = new Properties();
|
||||
properties.put("prop1key", "prop1val");
|
||||
|
||||
JsrXmlApplicationContext applicationContext = new JsrXmlApplicationContext(properties);
|
||||
|
||||
BeanDefinition beanDefinition = applicationContext.getBeanDefinition(JOB_PARAMETERS_BEAN_DEFINITION_NAME);
|
||||
Properties storedProperties = (Properties) beanDefinition.getConstructorArgumentValues().getGenericArgumentValue(Properties.class).getValue();
|
||||
|
||||
assertNotNull("Properties should not be null", storedProperties);
|
||||
assertFalse("Properties not be empty", storedProperties.isEmpty());
|
||||
assertEquals("prop1val", storedProperties.getProperty("prop1key"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<job id="job1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
|
||||
<!-- JSR Section 8.1.3 -->
|
||||
<properties>
|
||||
<property name="jobPropertyName1" value="jobPropertyValue1"/>
|
||||
<property name="jobPropertyName2" value="jobPropertyValue2"/>
|
||||
<property name="step2name" value="step2"/>
|
||||
</properties>
|
||||
|
||||
<step id="step1" allow-start-if-complete="#{jobParameters['allow.start.if.complete']}">
|
||||
<!-- JSR Section 8.2.3 -->
|
||||
<properties>
|
||||
<property name="step1PropertyName1" value="step1PropertyValue1"/>
|
||||
<property name="step1PropertyName2" value="step1PropertyValue2"/>
|
||||
</properties>
|
||||
<chunk checkpoint-policy="custom">
|
||||
<reader ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemReader">
|
||||
<!-- JSR Section 8.2.1.1.1 -->
|
||||
<properties>
|
||||
<property name="readerPropertyName1" value="readerPropertyValue1"/>
|
||||
<property name="readerPropertyName2" value="readerPropertyValue2"/>
|
||||
<property name="readerPropertyName3" value="#{jobParameters['shouldNotBeParsedByPostProcessor']}"/>
|
||||
<property name="annotationNamedReaderPropertyName" value="annotationNamedReaderPropertyValue"/>
|
||||
<property name="nonexistentReaderPropertyName" value="nonexistentReaderPropertyValue"/>
|
||||
</properties>
|
||||
</reader>
|
||||
<processor ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemProcessor">
|
||||
<!-- JSR Section 8.2.1.2.1 -->
|
||||
<properties>
|
||||
<property name="processorPropertyName1" value="processorPropertyValue1"/>
|
||||
<property name="processorPropertyName2" value="processorPropertyValue2"/>
|
||||
<property name="annotationNamedProcessorPropertyName"
|
||||
value="annotationNamedProcessorPropertyValue"/>
|
||||
<property name="nonexistentProcessorPropertyName" value="nonexistentProcessorPropertyValue"/>
|
||||
</properties>
|
||||
</processor>
|
||||
<writer ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemWriter">
|
||||
<!-- JSR Section 8.2.1.3.1 -->
|
||||
<properties>
|
||||
<property name="writerPropertyName1" value="writerPropertyValue1"/>
|
||||
<property name="writerPropertyName2" value="writerPropertyValue2"/>
|
||||
<property name="annotationNamedWriterPropertyName" value="annotationNamedWriterPropertyValue"/>
|
||||
<property name="nonexistentWriterPropertyName" value="nonexistentWriterPropertyValue"/>
|
||||
</properties>
|
||||
</writer>
|
||||
<checkpoint-algorithm
|
||||
ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestCheckpointAlgorithm">
|
||||
<!-- JSR Section 8.2.1.5.1 -->
|
||||
<properties>
|
||||
<property name="algorithmPropertyName1" value="algorithmPropertyValue1"/>
|
||||
<property name="algorithmPropertyName2" value="algorithmPropertyValue2"/>
|
||||
<property name="annotationNamedAlgorithmPropertyName"
|
||||
value="annotationNamedAlgorithmPropertyValue"/>
|
||||
<property name="nonexistentAlgorithmPropertyName" value="nonexistentAlgorithmPropertyValue"/>
|
||||
</properties>
|
||||
</checkpoint-algorithm>
|
||||
</chunk>
|
||||
<next on="*" to="#{jobParameters['deciderName']}#{jobParameters['deciderNumber']}"/>
|
||||
</step>
|
||||
<decision id="stepDecider1" ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestDecider">
|
||||
<properties>
|
||||
<property name="deciderPropertyName1" value="deciderPropertyValue1"/>
|
||||
<property name="deciderPropertyName2" value="deciderPropertyValue2"/>
|
||||
<property name="annotationNamedDeciderPropertyName" value="annotationNamedDeciderPropertyValue"/>
|
||||
<property name="nonexistentDeciderPropertyName" value="nonexistentDeciderPropertyValue"/>
|
||||
</properties>
|
||||
<next on="*" to="#{jobParameters['unresolving.prop']}?:#{jobProperties['step2name']};"/>
|
||||
</decision>
|
||||
<step id="step2">
|
||||
<!-- JSR Section 8.2.3 -->
|
||||
<properties>
|
||||
<property name="step2PropertyName1" value="step2PropertyValue1"/>
|
||||
<property name="step2PropertyName2" value="step2PropertyValue2"/>
|
||||
</properties>
|
||||
<!-- JSR Section 8.2.4.1 -->
|
||||
<listeners>
|
||||
<listener ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestStepListener">
|
||||
<properties>
|
||||
<property name="stepListenerPropertyName1" value="stepListenerPropertyValue1"/>
|
||||
<property name="stepListenerPropertyName2" value="stepListenerPropertyValue2"/>
|
||||
<property name="annotationNamedStepListenerPropertyName"
|
||||
value="annotationNamedStepListenerPropertyValue"/>
|
||||
<property name="nonexistentStepListenerPropertyName" value="nonexistentStepListenerPropertyValue"/>
|
||||
</properties>
|
||||
</listener>
|
||||
</listeners>
|
||||
<batchlet ref="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestBatchlet">
|
||||
<!-- JSR Section 8.2.2.2 -->
|
||||
<properties>
|
||||
<property name="batchletPropertyName1" value="batchletPropertyValue1"/>
|
||||
<property name="batchletPropertyName2" value="batchletPropertyValue2"/>
|
||||
<property name="annotationNamedBatchletPropertyName" value="annotationNamedBatchletPropertyValue"/>
|
||||
<property name="nonexistentBatchletPropertyName" value="nonexistentBatchletPropertyValue"/>
|
||||
</properties>
|
||||
</batchlet>
|
||||
</step>
|
||||
</job>
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<job id="jsrPropertyPreparseTestJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
|
||||
<properties>
|
||||
<property name="jobProperty1" value="jobProperty1Value"/>
|
||||
<property name="jobProperty2" value="#{jobProperties['jobProperty1']}"/>
|
||||
<property name="jobProperty3" value="#{jobParameters['file.name']}"/>
|
||||
</properties>
|
||||
<step id="step1" >
|
||||
<batchlet ref="testBatchlet">
|
||||
<properties>
|
||||
<property name="file" value="#{jobParameters['unresolving.prop']}?:myfile1.txt;"/>
|
||||
</properties>
|
||||
</batchlet>
|
||||
</step>
|
||||
</job>
|
||||
@@ -1,144 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:c="http://www.springframework.org/schema/c"
|
||||
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">
|
||||
<!-- JSR Section 8.1.3 -->
|
||||
<properties>
|
||||
<property name="jobPropertyName1" value="jobPropertyValue1"/>
|
||||
<property name="jobPropertyName2" value="jobPropertyValue2"/>
|
||||
<property name="step2name" value="step2"/>
|
||||
</properties>
|
||||
|
||||
<step id="step1" allow-start-if-complete="#{jobParameters['allow.start.if.complete']}">
|
||||
<!-- JSR Section 8.2.3 -->
|
||||
<properties>
|
||||
<property name="step1PropertyName1" value="step1PropertyValue1"/>
|
||||
<property name="step1PropertyName2" value="step1PropertyValue2"/>
|
||||
</properties>
|
||||
<chunk checkpoint-policy="custom">
|
||||
<reader ref="testReader">
|
||||
<!-- JSR Section 8.2.1.1.1 -->
|
||||
<properties>
|
||||
<property name="readerPropertyName1" value="readerPropertyValue1"/>
|
||||
<property name="readerPropertyName2" value="readerPropertyValue2"/>
|
||||
<property name="readerPropertyName3" value="#{jobParameters['shouldNotBeParsedByPostProcessor']}"/>
|
||||
<property name="annotationNamedReaderPropertyName" value="annotationNamedReaderPropertyValue"/>
|
||||
<property name="nonexistentReaderPropertyName" value="nonexistentReaderPropertyValue"/>
|
||||
</properties>
|
||||
</reader>
|
||||
<processor ref="testProcessor">
|
||||
<!-- JSR Section 8.2.1.2.1 -->
|
||||
<properties>
|
||||
<property name="processorPropertyName1" value="processorPropertyValue1"/>
|
||||
<property name="processorPropertyName2" value="processorPropertyValue2"/>
|
||||
<property name="annotationNamedProcessorPropertyName" value="annotationNamedProcessorPropertyValue"/>
|
||||
<property name="nonexistentProcessorPropertyName" value="nonexistentProcessorPropertyValue"/>
|
||||
</properties>
|
||||
</processor>
|
||||
<writer ref="testWriter">
|
||||
<!-- JSR Section 8.2.1.3.1 -->
|
||||
<properties>
|
||||
<property name="writerPropertyName1" value="writerPropertyValue1"/>
|
||||
<property name="writerPropertyName2" value="writerPropertyValue2"/>
|
||||
<property name="annotationNamedWriterPropertyName" value="annotationNamedWriterPropertyValue"/>
|
||||
<property name="nonexistentWriterPropertyName" value="nonexistentWriterPropertyValue"/>
|
||||
</properties>
|
||||
</writer>
|
||||
<checkpoint-algorithm ref="testCheckpointAlgorithm">
|
||||
<!-- JSR Section 8.2.1.5.1 -->
|
||||
<properties>
|
||||
<property name="algorithmPropertyName1" value="algorithmPropertyValue1"/>
|
||||
<property name="algorithmPropertyName2" value="algorithmPropertyValue2"/>
|
||||
<property name="annotationNamedAlgorithmPropertyName" value="annotationNamedAlgorithmPropertyValue"/>
|
||||
<property name="nonexistentAlgorithmPropertyName" value="nonexistentAlgorithmPropertyValue"/>
|
||||
</properties>
|
||||
</checkpoint-algorithm>
|
||||
</chunk>
|
||||
<next on="*" to="#{jobParameters['deciderName']}#{jobParameters['deciderNumber']}"/>
|
||||
</step>
|
||||
<decision id="stepDecider1" ref="testDecider">
|
||||
<properties>
|
||||
<property name="deciderPropertyName1" value="deciderPropertyValue1"/>
|
||||
<property name="deciderPropertyName2" value="deciderPropertyValue2"/>
|
||||
<property name="annotationNamedDeciderPropertyName" value="annotationNamedDeciderPropertyValue"/>
|
||||
<property name="nonexistentDeciderPropertyName" value="nonexistentDeciderPropertyValue"/>
|
||||
</properties>
|
||||
<next on="*" to="#{jobParameters['unresolving.prop']}?:#{jobProperties['step2name']};"/>
|
||||
</decision>
|
||||
<step id="step2">
|
||||
<!-- JSR Section 8.2.3 -->
|
||||
<properties>
|
||||
<property name="step2PropertyName1" value="step2PropertyValue1"/>
|
||||
<property name="step2PropertyName2" value="step2PropertyValue2"/>
|
||||
</properties>
|
||||
<!-- JSR Section 8.2.4.1 -->
|
||||
<listeners>
|
||||
<listener ref="testStepListener">
|
||||
<properties>
|
||||
<property name="stepListenerPropertyName1" value="stepListenerPropertyValue1"/>
|
||||
<property name="stepListenerPropertyName2" value="stepListenerPropertyValue2"/>
|
||||
<property name="annotationNamedStepListenerPropertyName" value="annotationNamedStepListenerPropertyValue"/>
|
||||
<property name="nonexistentStepListenerPropertyName" value="nonexistentStepListenerPropertyValue"/>
|
||||
</properties>
|
||||
</listener>
|
||||
</listeners>
|
||||
<batchlet ref="testBatchlet">
|
||||
<!-- JSR Section 8.2.2.2 -->
|
||||
<properties>
|
||||
<property name="batchletPropertyName1" value="batchletPropertyValue1"/>
|
||||
<property name="batchletPropertyName2" value="batchletPropertyValue2"/>
|
||||
<property name="annotationNamedBatchletPropertyName" value="annotationNamedBatchletPropertyValue"/>
|
||||
<property name="nonexistentBatchletPropertyName" value="nonexistentBatchletPropertyValue"/>
|
||||
</properties>
|
||||
</batchlet>
|
||||
</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.JobPropertyTests$TestItemReader"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testProcessor" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemProcessor"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testWriter" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestItemWriter"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testCheckpointAlgorithm" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestCheckpointAlgorithm"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testBatchlet" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestBatchlet"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testStepListener" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestStepListener"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="testDecider" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$TestDecider"
|
||||
scope="step"/>
|
||||
|
||||
<bean id="injectTestObj" class="org.springframework.batch.core.jsr.configuration.xml.JobPropertyTests$InjectTestObj"
|
||||
c:name="Chris"/>
|
||||
|
||||
<bean id="jobParameterResolvingBeanFactoryPostProcessor" class="org.springframework.batch.core.jsr.configuration.support.JobParameterResolvingBeanFactoryPostProcessor">
|
||||
<constructor-arg>
|
||||
<props>
|
||||
<prop key="allow.start.if.complete">true</prop>
|
||||
<prop key="deciderName">stepDecider</prop>
|
||||
<prop key="deciderNumber">1</prop>
|
||||
</props>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user