BATCH-2089: Added ability to remap ExitStatus
This commit is contained in:
committed by
Chris Schaefer
parent
10e58baf80
commit
fba258c8e5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2008 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -39,7 +39,8 @@ import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
@@ -86,7 +87,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
* Convenience method for subclasses to set the job factory reference if it
|
||||
* is available (null is fine, but the quality of error reports is better if
|
||||
* it is available).
|
||||
*
|
||||
*
|
||||
* @param jobFactoryRef
|
||||
*/
|
||||
protected void setJobFactoryRef(String jobFactoryRef) {
|
||||
@@ -95,7 +96,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
*
|
||||
* @see AbstractSingleBeanDefinitionParser#getBeanClass(Element)
|
||||
*/
|
||||
@Override
|
||||
@@ -168,16 +169,15 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
}
|
||||
}
|
||||
|
||||
ManagedList managedList = new ManagedList();
|
||||
@SuppressWarnings( { "unchecked", "unused" })
|
||||
boolean dummy = managedList.addAll(stateTransitions);
|
||||
ManagedList<BeanDefinition> managedList = new ManagedList<BeanDefinition>();
|
||||
managedList.addAll(stateTransitions);
|
||||
builder.addPropertyValue("stateTransitions", managedList);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all of the elements that are pointed to by this element.
|
||||
*
|
||||
*
|
||||
* @param element
|
||||
* @return a collection of reachable element names
|
||||
*/
|
||||
@@ -206,7 +206,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
|
||||
/**
|
||||
* Find all of the elements reachable from the startElement.
|
||||
*
|
||||
*
|
||||
* @param startElement
|
||||
* @param reachableElementMap
|
||||
* @param accumulator a collection of reachable element names
|
||||
@@ -295,7 +295,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
* @param element
|
||||
* @param parserContext the parser context for the bean factory
|
||||
*/
|
||||
private static void verifyUniquePattern(Element transitionElement, List<String> patterns, Element element,
|
||||
protected static void verifyUniquePattern(Element transitionElement, List<String> patterns, Element element,
|
||||
ParserContext parserContext) {
|
||||
String onAttribute = transitionElement.getAttribute(ON_ATTR);
|
||||
if (patterns.contains(onAttribute)) {
|
||||
@@ -344,7 +344,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* references
|
||||
*/
|
||||
private static Collection<BeanDefinition> createTransition(FlowExecutionStatus status, String on, String next,
|
||||
protected static Collection<BeanDefinition> createTransition(FlowExecutionStatus status, String on, String next,
|
||||
String exitCode, BeanDefinition stateDef, ParserContext parserContext, boolean abandon) {
|
||||
|
||||
BeanDefinition endState = null;
|
||||
@@ -389,7 +389,7 @@ public abstract class AbstractFlowParser extends AbstractSingleBeanDefinitionPar
|
||||
* @param elementName An end transition element name
|
||||
* @return the BatchStatus corresponding to the transition name
|
||||
*/
|
||||
private static FlowExecutionStatus getBatchStatusFromEndTransitionName(String elementName) {
|
||||
protected static FlowExecutionStatus getBatchStatusFromEndTransitionName(String elementName) {
|
||||
elementName = stripNamespace(elementName);
|
||||
if (STOP_ELE.equals(elementName)) {
|
||||
return FlowExecutionStatus.STOPPED;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2009 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -15,8 +15,11 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator;
|
||||
import org.springframework.batch.core.job.flow.support.StateTransition;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
@@ -32,6 +35,7 @@ import org.w3c.dom.Element;
|
||||
* Utility methods used in parsing of the batch core namespace
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @author Michael Minella
|
||||
*/
|
||||
public class CoreNamespaceUtils {
|
||||
|
||||
@@ -51,6 +55,7 @@ public class CoreNamespaceUtils {
|
||||
checkForStepScope(parserContext, source);
|
||||
addRangePropertyEditor(parserContext);
|
||||
addCoreNamespacePostProcessor(parserContext);
|
||||
addStateTransitionComparator(parserContext);
|
||||
}
|
||||
|
||||
private static void checkForStepScope(ParserContext parserContext, Object source) {
|
||||
@@ -73,19 +78,36 @@ public class CoreNamespaceUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a {@link Comparator} to be used to sort {@link StateTransition}s
|
||||
*
|
||||
* @param parserContext
|
||||
*/
|
||||
private static void addStateTransitionComparator(ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (!stateTransitionComparatorAlreadyDefined(registry)) {
|
||||
AbstractBeanDefinition defaultStateTransitionComparator = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
DefaultStateTransitionComparator.class).getBeanDefinition();
|
||||
registry.registerBeanDefinition(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR, defaultStateTransitionComparator);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean stateTransitionComparatorAlreadyDefined(BeanDefinitionRegistry registry) {
|
||||
return registry.containsBeanDefinition(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a RangePropertyEditor if one does not already exist.
|
||||
*
|
||||
* @param parserContext
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private static void addRangePropertyEditor(ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (!rangeArrayEditorAlreadyDefined(registry)) {
|
||||
AbstractBeanDefinition customEditorConfigurer = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
CUSTOM_EDITOR_CONFIGURER_CLASS_NAME).getBeanDefinition();
|
||||
customEditorConfigurer.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
ManagedMap editors = new ManagedMap();
|
||||
ManagedMap<String, String> editors = new ManagedMap<String, String>();
|
||||
editors.put(RANGE_ARRAY_CLASS_NAME, RANGE_ARRAY_EDITOR_CLASS_NAME);
|
||||
customEditorConfigurer.getPropertyValues().addPropertyValue("customEditors", editors);
|
||||
registry.registerBeanDefinition(CUSTOM_EDITOR_CONFIGURER_CLASS_NAME, customEditorConfigurer);
|
||||
@@ -176,7 +198,8 @@ public class CoreNamespaceUtils {
|
||||
|
||||
private static boolean matchesVersionInternal(Element element) {
|
||||
String schemaLocation = element.getAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "schemaLocation");
|
||||
return schemaLocation.matches("(?m).*spring-batch-2.2.xsd.*")
|
||||
return schemaLocation.matches("(?m).*spring-batch-3.0.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-batch-2.2.xsd.*")
|
||||
|| schemaLocation.matches("(?m).*spring-batch.xsd.*")
|
||||
|| !schemaLocation.matches("(?m).*spring-batch.*");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2008 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -15,23 +15,26 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class InlineFlowParser extends AbstractFlowParser {
|
||||
|
||||
|
||||
private final String flowName;
|
||||
|
||||
/**
|
||||
* Construct a {@link InlineFlowParser} with the specified name and using the
|
||||
* provided job repository ref.
|
||||
*
|
||||
*
|
||||
* @param flowName the name of the flow
|
||||
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
|
||||
* from the enclosing tag
|
||||
@@ -51,6 +54,7 @@ public class InlineFlowParser extends AbstractFlowParser {
|
||||
|
||||
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
|
||||
builder.addPropertyValue("name", flowName);
|
||||
builder.addPropertyValue("stateTransitionComparator", new RuntimeBeanReference(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR));
|
||||
super.doParse(element, parserContext, builder);
|
||||
builder.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.batch.core.configuration.xml;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.job.flow.Flow;
|
||||
@@ -40,6 +41,7 @@ import org.springframework.util.Assert;
|
||||
* that form, in which case it is not modified).
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
@@ -51,6 +53,12 @@ public class SimpleFlowFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
private String prefix;
|
||||
|
||||
private Comparator<StateTransition> stateTransitionComparator;
|
||||
|
||||
public void setStateTransitionComparator(Comparator<StateTransition> stateTransitionComparator) {
|
||||
this.stateTransitionComparator = stateTransitionComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the flow that is created by this factory.
|
||||
*
|
||||
@@ -87,6 +95,8 @@ public class SimpleFlowFactoryBean implements FactoryBean, InitializingBean {
|
||||
|
||||
SimpleFlow flow = new SimpleFlow(name);
|
||||
|
||||
flow.setStateTransitionComparator(stateTransitionComparator);
|
||||
|
||||
List<StateTransition> updatedTransitions = new ArrayList<StateTransition>();
|
||||
for (StateTransition stateTransition : stateTransitions) {
|
||||
State state = getProxyState(stateTransition.getState());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2008 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -15,6 +15,8 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
@@ -22,7 +24,8 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class TopLevelFlowParser extends AbstractFlowParser {
|
||||
|
||||
@@ -40,6 +43,7 @@ public class TopLevelFlowParser extends AbstractFlowParser {
|
||||
String flowName = element.getAttribute(ID_ATTR);
|
||||
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
|
||||
builder.addPropertyValue("name", flowName);
|
||||
builder.addPropertyValue("stateTransitionComparator", new RuntimeBeanReference(DefaultStateTransitionComparator.STATE_TRANSITION_COMPARATOR));
|
||||
String abstractAttr = element.getAttribute(ABSTRACT_ATTR);
|
||||
if (StringUtils.hasText(abstractAttr)) {
|
||||
builder.setAbstract(abstractAttr.equals("true"));
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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.job.flow.support;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Sorts by decreasing specificity of pattern, based on just counting
|
||||
* wildcards (with * taking precedence over ?). If wildcard counts are equal
|
||||
* then falls back to alphabetic comparison. Hence * > foo* > ??? >
|
||||
* fo? > foo.
|
||||
*
|
||||
* @see Comparator
|
||||
* @author Michael Minella
|
||||
* @since 3.0
|
||||
*/
|
||||
public class DefaultStateTransitionComparator implements Comparator<StateTransition> {
|
||||
public static final String STATE_TRANSITION_COMPARATOR = "batch_state_transition_comparator";
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public int compare(StateTransition arg0, StateTransition arg1) {
|
||||
String value = arg1.getPattern();
|
||||
if (arg0.getPattern().equals(value)) {
|
||||
return 0;
|
||||
}
|
||||
int patternCount = StringUtils.countOccurrencesOf(arg0.getPattern(), "*");
|
||||
int valueCount = StringUtils.countOccurrencesOf(value, "*");
|
||||
if (patternCount > valueCount) {
|
||||
return 1;
|
||||
}
|
||||
if (patternCount < valueCount) {
|
||||
return -1;
|
||||
}
|
||||
patternCount = StringUtils.countOccurrencesOf(arg0.getPattern(), "?");
|
||||
valueCount = StringUtils.countOccurrencesOf(value, "?");
|
||||
if (patternCount > valueCount) {
|
||||
return 1;
|
||||
}
|
||||
if (patternCount < valueCount) {
|
||||
return -1;
|
||||
}
|
||||
return arg0.getPattern().compareTo(value);
|
||||
}
|
||||
}
|
||||
@@ -17,12 +17,13 @@ package org.springframework.batch.core.job.flow.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.SortedSet;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -55,7 +56,7 @@ public class SimpleFlow implements Flow, InitializingBean {
|
||||
|
||||
private State startState;
|
||||
|
||||
private Map<String, SortedSet<StateTransition>> transitionMap = new HashMap<String, SortedSet<StateTransition>>();
|
||||
private Map<String, Set<StateTransition>> transitionMap = new HashMap<String, Set<StateTransition>>();
|
||||
|
||||
private Map<String, State> stateMap = new HashMap<String, State>();
|
||||
|
||||
@@ -63,6 +64,12 @@ public class SimpleFlow implements Flow, InitializingBean {
|
||||
|
||||
private final String name;
|
||||
|
||||
private Comparator<StateTransition> stateTransitionComparator;
|
||||
|
||||
public void setStateTransitionComparator(Comparator<StateTransition> stateTransitionComparator) {
|
||||
this.stateTransitionComparator = stateTransitionComparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a flow with the given name.
|
||||
*
|
||||
@@ -270,9 +277,15 @@ public class SimpleFlow implements Flow, InitializingBean {
|
||||
|
||||
String name = state.getName();
|
||||
|
||||
SortedSet<StateTransition> set = transitionMap.get(name);
|
||||
Set<StateTransition> set = transitionMap.get(name);
|
||||
if (set == null) {
|
||||
set = new TreeSet<StateTransition>();
|
||||
// If no comparator is provided, we will maintain the order of insertion
|
||||
if(stateTransitionComparator == null) {
|
||||
set = new LinkedHashSet<StateTransition>();
|
||||
} else {
|
||||
set = new TreeSet<StateTransition>(stateTransitionComparator);
|
||||
}
|
||||
|
||||
transitionMap.put(name, set);
|
||||
}
|
||||
set.add(stateTransition);
|
||||
|
||||
@@ -28,9 +28,10 @@ import org.springframework.util.StringUtils;
|
||||
* execution of the originating State.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Michael Minella
|
||||
* @since 2.0
|
||||
*/
|
||||
public final class StateTransition implements Comparable<StateTransition> {
|
||||
public final class StateTransition {
|
||||
|
||||
private final State state;
|
||||
|
||||
@@ -38,6 +39,13 @@ public final class StateTransition implements Comparable<StateTransition> {
|
||||
|
||||
private final String next;
|
||||
|
||||
/**
|
||||
* @return the pattern the {@link ExitStatus#getExitCode()} will be compared against.
|
||||
*/
|
||||
public String getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new end state {@link StateTransition} specification. This
|
||||
* transition explicitly goes unconditionally to an end state (i.e. no more
|
||||
@@ -158,38 +166,6 @@ public final class StateTransition implements Comparable<StateTransition> {
|
||||
return next == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts by decreasing specificity of pattern, based on just counting
|
||||
* wildcards (with * taking precedence over ?). If wildcard counts are equal
|
||||
* then falls back to alphabetic comparison. Hence * > foo* > ??? >
|
||||
* fo? > foo.
|
||||
* @see Comparable#compareTo(Object)
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(StateTransition other) {
|
||||
String value = other.pattern;
|
||||
if (pattern.equals(value)) {
|
||||
return 0;
|
||||
}
|
||||
int patternCount = StringUtils.countOccurrencesOf(pattern, "*");
|
||||
int valueCount = StringUtils.countOccurrencesOf(value, "*");
|
||||
if (patternCount > valueCount) {
|
||||
return 1;
|
||||
}
|
||||
if (patternCount < valueCount) {
|
||||
return -1;
|
||||
}
|
||||
patternCount = StringUtils.countOccurrencesOf(pattern, "?");
|
||||
valueCount = StringUtils.countOccurrencesOf(value, "?");
|
||||
if (patternCount > valueCount) {
|
||||
return 1;
|
||||
}
|
||||
if (patternCount < valueCount) {
|
||||
return -1;
|
||||
}
|
||||
return pattern.compareTo(value);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.batch.core.jsr.configuration.xml;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
@@ -24,10 +25,13 @@ import java.util.Set;
|
||||
|
||||
import org.springframework.batch.core.configuration.xml.AbstractFlowParser;
|
||||
import org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean;
|
||||
import org.springframework.batch.core.job.flow.FlowExecutionStatus;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
@@ -47,6 +51,10 @@ public class FlowParser extends AbstractFlowParser {
|
||||
private StepParser stepParser = new StepParser();
|
||||
private String flowName;
|
||||
|
||||
/**
|
||||
* @param flowName The name of the flow
|
||||
* @param jobFactoryRef The bean name for the job factory
|
||||
*/
|
||||
public FlowParser(String flowName, String jobFactoryRef) {
|
||||
super.setJobFactoryRef(jobFactoryRef);
|
||||
this.flowName = flowName;
|
||||
@@ -58,7 +66,6 @@ public class FlowParser extends AbstractFlowParser {
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
|
||||
builder.addPropertyValue("name", flowName);
|
||||
@@ -91,8 +98,70 @@ public class FlowParser extends AbstractFlowParser {
|
||||
}
|
||||
}
|
||||
|
||||
ManagedList managedList = new ManagedList();
|
||||
ManagedList<BeanDefinition> managedList = new ManagedList<BeanDefinition>();
|
||||
managedList.addAll(stateTransitions);
|
||||
builder.addPropertyValue("stateTransitions", managedList);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, BeanDefinition stateDef,
|
||||
Element element) {
|
||||
return getNextElements(parserContext, null, stateDef, element);
|
||||
}
|
||||
|
||||
public static Collection<BeanDefinition> getNextElements(ParserContext parserContext, String stepId,
|
||||
BeanDefinition stateDef, Element element) {
|
||||
|
||||
Collection<BeanDefinition> list = new ArrayList<BeanDefinition>();
|
||||
|
||||
String shortNextAttribute = element.getAttribute("next");
|
||||
boolean hasNextAttribute = StringUtils.hasText(shortNextAttribute);
|
||||
if (hasNextAttribute) {
|
||||
list.add(getStateTransitionReference(parserContext, stateDef, null, shortNextAttribute));
|
||||
}
|
||||
|
||||
boolean transitionElementExists = false;
|
||||
List<String> patterns = new ArrayList<String>();
|
||||
for (String transitionName : new String[] { "next", "stop", "end", "fail" }) {
|
||||
List<Element> transitionElements = DomUtils.getChildElementsByTagName(element, transitionName);
|
||||
for (Element transitionElement : transitionElements) {
|
||||
verifyUniquePattern(transitionElement, patterns, element, parserContext);
|
||||
list.addAll(parseTransitionElement(transitionElement, stepId, stateDef, parserContext));
|
||||
transitionElementExists = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!transitionElementExists) {
|
||||
list.addAll(createTransition(FlowExecutionStatus.FAILED, FlowExecutionStatus.FAILED.getName(), null, null,
|
||||
stateDef, parserContext, false));
|
||||
list.addAll(createTransition(FlowExecutionStatus.UNKNOWN, FlowExecutionStatus.UNKNOWN.getName(), null, null,
|
||||
stateDef, parserContext, false));
|
||||
if (!hasNextAttribute) {
|
||||
list.addAll(createTransition(FlowExecutionStatus.COMPLETED, null, null, null, stateDef, parserContext,
|
||||
false));
|
||||
}
|
||||
}
|
||||
else if (hasNextAttribute) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The <" + element.getNodeName() + "/> may not contain a 'next"
|
||||
+ "' attribute and a transition element", element);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected static Collection<BeanDefinition> parseTransitionElement(Element transitionElement, String stateId,
|
||||
BeanDefinition stateDef, ParserContext parserContext) {
|
||||
|
||||
FlowExecutionStatus status = getBatchStatusFromEndTransitionName(transitionElement.getNodeName());
|
||||
String onAttribute = transitionElement.getAttribute("on");
|
||||
String restartAttribute = transitionElement.getAttribute("restart");
|
||||
String nextAttribute = transitionElement.getAttribute("to");
|
||||
if (!StringUtils.hasText(nextAttribute)) {
|
||||
nextAttribute = restartAttribute;
|
||||
}
|
||||
boolean abandon = stateId != null && StringUtils.hasText(restartAttribute) && !restartAttribute.equals(stateId);
|
||||
String exitCodeAttribute = transitionElement.getAttribute("exit-status");
|
||||
|
||||
return createTransition(status, onAttribute, nextAttribute, exitCodeAttribute, stateDef, parserContext, abandon);
|
||||
}}
|
||||
|
||||
@@ -37,6 +37,16 @@ public class JsrFlowExecutor extends JobFlowExecutor {
|
||||
super(jobRepository, stepHandler, execution);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.job.flow.JobFlowExecutor#addExitStatus(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addExitStatus(String code) {
|
||||
if((exitStatus != null && isNonDefaultExitStauts(exitStatus.getExitCode())) && !isNonDefaultExitStauts(code)) {
|
||||
exitStatus = exitStatus.and(new ExitStatus(code));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.job.flow.JobFlowExecutor#updateJobExecutionStatus(org.springframework.batch.core.job.flow.FlowExecutionStatus)
|
||||
*/
|
||||
@@ -47,16 +57,23 @@ public class JsrFlowExecutor extends JobFlowExecutor {
|
||||
execution.setStatus(findBatchStatus(status));
|
||||
|
||||
ExitStatus curStatus = execution.getExitStatus();
|
||||
if(curStatus == null ||
|
||||
curStatus.getExitCode() == null ||
|
||||
curStatus.getExitCode().equals(ExitStatus.COMPLETED.getExitCode()) ||
|
||||
curStatus.getExitCode().equals(ExitStatus.EXECUTING.getExitCode()) ||
|
||||
curStatus.getExitCode().equals(ExitStatus.FAILED.getExitCode()) ||
|
||||
curStatus.getExitCode().equals(ExitStatus.NOOP.getExitCode()) ||
|
||||
curStatus.getExitCode().equals(ExitStatus.STOPPED.getExitCode()) ||
|
||||
curStatus.getExitCode().equals(ExitStatus.UNKNOWN.getExitCode())) {
|
||||
if(isNonDefaultExitStauts(curStatus.getExitCode())) {
|
||||
exitStatus = exitStatus.and(new ExitStatus(status.getName()));
|
||||
execution.setExitStatus(exitStatus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param curStatus the exit code to be evaluated
|
||||
* @return true if the value matches a known exit code
|
||||
*/
|
||||
protected boolean isNonDefaultExitStauts(String curStatus) {
|
||||
return curStatus == null ||
|
||||
curStatus.equals(ExitStatus.COMPLETED.getExitCode()) ||
|
||||
curStatus.equals(ExitStatus.EXECUTING.getExitCode()) ||
|
||||
curStatus.equals(ExitStatus.FAILED.getExitCode()) ||
|
||||
curStatus.equals(ExitStatus.NOOP.getExitCode()) ||
|
||||
curStatus.equals(ExitStatus.STOPPED.getExitCode()) ||
|
||||
curStatus.equals(ExitStatus.UNKNOWN.getExitCode());
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,6 +35,7 @@ import org.springframework.batch.core.JobInterruptedException;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.job.flow.support.DefaultStateTransitionComparator;
|
||||
import org.springframework.batch.core.job.flow.support.SimpleFlow;
|
||||
import org.springframework.batch.core.job.flow.support.StateTransition;
|
||||
import org.springframework.batch.core.job.flow.support.state.DecisionState;
|
||||
@@ -49,6 +50,7 @@ import org.springframework.batch.core.step.StepSupport;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class FlowJobTests {
|
||||
@@ -422,6 +424,7 @@ public class FlowJobTests {
|
||||
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end2")));
|
||||
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end3")));
|
||||
flow.setStateTransitions(transitions);
|
||||
flow.setStateTransitionComparator(new DefaultStateTransitionComparator());
|
||||
job.setFlow(flow);
|
||||
job.afterPropertiesSet();
|
||||
job.doExecute(jobExecution);
|
||||
@@ -473,6 +476,7 @@ public class FlowJobTests {
|
||||
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.FAILED, "end2")));
|
||||
transitions.add(StateTransition.createEndStateTransition(new EndState(FlowExecutionStatus.COMPLETED, "end3")));
|
||||
flow.setStateTransitions(transitions);
|
||||
flow.setStateTransitionComparator(new DefaultStateTransitionComparator());
|
||||
|
||||
job.setFlow(flow);
|
||||
job.doExecute(jobExecution);
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.job.flow.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.job.flow.State;
|
||||
import org.springframework.batch.core.job.flow.StateSupport;
|
||||
|
||||
public class DefaultStateTransitionComparatorTests {
|
||||
|
||||
private State state = new StateSupport("state1");
|
||||
private Comparator<StateTransition> comparator;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
comparator = new DefaultStateTransitionComparator();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingEqual() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN???LE", "start");
|
||||
assertEquals(0, comparator.compare(transition, transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMoreGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN???LE", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, comparator.compare(transition, other));
|
||||
assertEquals(-1, comparator.compare(other, transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMostGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, comparator.compare(transition, other));
|
||||
assertEquals(-1, comparator.compare(other, transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubstringAndWildcard() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, comparator.compare(transition, other));
|
||||
assertEquals(-1, comparator.compare(other, transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMostToNextGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "C?", "start");
|
||||
assertEquals(1, comparator.compare(transition, other));
|
||||
assertEquals(-1, comparator.compare(other, transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingAdjacent() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CON*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CON?", "start");
|
||||
assertEquals(1, comparator.compare(transition, other));
|
||||
assertEquals(-1, comparator.compare(other, transition));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -36,7 +36,8 @@ import org.springframework.batch.core.job.flow.StateSupport;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class SimpleFlowTests {
|
||||
|
||||
@@ -177,7 +178,8 @@ public class SimpleFlowTests {
|
||||
flow.setStateTransitions(collect(StateTransition.createStateTransition(new StubState("step1"), "step2"),
|
||||
StateTransition.createStateTransition(new StubState("step1"), ExitStatus.COMPLETED.getExitCode(), "step3"),
|
||||
StateTransition.createEndStateTransition(new StubState("step2")), StateTransition
|
||||
.createEndStateTransition(new StubState("step3"))));
|
||||
.createEndStateTransition(new StubState("step3"))));
|
||||
flow.setStateTransitionComparator(new DefaultStateTransitionComparator());
|
||||
flow.afterPropertiesSet();
|
||||
FlowExecution execution = flow.start(executor);
|
||||
assertEquals(FlowExecutionStatus.COMPLETED, execution.getStatus());
|
||||
@@ -224,7 +226,7 @@ public class SimpleFlowTests {
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*
|
||||
*/
|
||||
private static class StubState extends StateSupport {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
* Copyright 2006-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.
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.batch.core.job.flow.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@@ -25,12 +24,13 @@ import org.springframework.batch.core.job.flow.StateSupport;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
public class StateTransitionTests {
|
||||
|
||||
State state = new StateSupport("state1");
|
||||
|
||||
|
||||
@Test
|
||||
public void testIsEnd() {
|
||||
StateTransition transition = StateTransition.createEndStateTransition(state, "");
|
||||
@@ -74,52 +74,6 @@ public class StateTransitionTests {
|
||||
assertTrue(transition.matches("CONTINUABLE"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingEqual() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN???LE", "start");
|
||||
assertEquals(0, transition.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMoreGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN???LE", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, transition.compareTo(other));
|
||||
assertEquals(-1, other.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMostGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, transition.compareTo(other));
|
||||
assertEquals(-1, other.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubstringAndWildcard() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CONTINUABLE", "start");
|
||||
assertEquals(1, transition.compareTo(other));
|
||||
assertEquals(-1, other.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingMostToNextGeneral() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "C?", "start");
|
||||
assertEquals(1, transition.compareTo(other));
|
||||
assertEquals(-1, other.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleOrderingAdjacent() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CON*", "start");
|
||||
StateTransition other = StateTransition.createStateTransition(state, "CON?", "start");
|
||||
assertEquals(1, transition.compareTo(other));
|
||||
assertEquals(-1, other.compareTo(transition));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToString() {
|
||||
StateTransition transition = StateTransition.createStateTransition(state, "CONTIN???LE", "start");
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.batch.api.Decider;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
@@ -59,7 +61,7 @@ import org.springframework.batch.core.step.StepSupport;
|
||||
*/
|
||||
public class JsrFlowJobTests {
|
||||
|
||||
private JsrFlowJob job = new JsrFlowJob();
|
||||
private JsrFlowJob job;
|
||||
|
||||
private JobExecution jobExecution;
|
||||
|
||||
@@ -71,6 +73,7 @@ public class JsrFlowJobTests {
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
job = new JsrFlowJob();
|
||||
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
|
||||
factory.afterPropertiesSet();
|
||||
jobExecutionDao = factory.getJobExecutionDao();
|
||||
@@ -431,7 +434,7 @@ public class JsrFlowJobTests {
|
||||
job.setFlow(flow);
|
||||
job.afterPropertiesSet();
|
||||
job.doExecute(jobExecution);
|
||||
StepExecution stepExecution = getStepExecution(jobExecution, "step3");
|
||||
StepExecution stepExecution = getStepExecution(jobExecution, "step2");
|
||||
assertEquals(ExitStatus.COMPLETED, stepExecution.getExitStatus());
|
||||
assertEquals(2, jobExecution.getStepExecutions().size());
|
||||
}
|
||||
@@ -455,19 +458,21 @@ public class JsrFlowJobTests {
|
||||
public void testDecisionFlow() throws Throwable {
|
||||
|
||||
SimpleFlow flow = new SimpleFlow("job");
|
||||
JobExecutionDecider decider = new JobExecutionDecider() {
|
||||
Decider decider = new Decider() {
|
||||
|
||||
@Override
|
||||
public FlowExecutionStatus decide(JobExecution jobExecution, StepExecution stepExecution) {
|
||||
assertNotNull(stepExecution);
|
||||
return new FlowExecutionStatus("SWITCH");
|
||||
public String decide(javax.batch.runtime.StepExecution[] executions)
|
||||
throws Exception {
|
||||
assertNotNull(executions);
|
||||
return "SWITCH";
|
||||
}
|
||||
};
|
||||
|
||||
List<StateTransition> transitions = new ArrayList<StateTransition>();
|
||||
transitions.add(StateTransition.createStateTransition(new StepState(new StubStep("step1")), "decision"));
|
||||
DecisionState decision = new DecisionState(decider, "decision");
|
||||
transitions.add(StateTransition.createStateTransition(decision, "step2"));
|
||||
StepState decision = new StepState(new StubDecisionStep("decision", decider));
|
||||
transitions.add(StateTransition.createStateTransition(decision, "SWITCH", "step3"));
|
||||
transitions.add(StateTransition.createStateTransition(decision, "step2"));
|
||||
StepState step2 = new StepState(new StubStep("step2"));
|
||||
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.COMPLETED.getExitCode(), "end0"));
|
||||
transitions.add(StateTransition.createStateTransition(step2, ExitStatus.FAILED.getExitCode(), "end1"));
|
||||
@@ -482,13 +487,14 @@ public class JsrFlowJobTests {
|
||||
|
||||
job.setFlow(flow);
|
||||
job.doExecute(jobExecution);
|
||||
|
||||
StepExecution stepExecution = getStepExecution(jobExecution, "step3");
|
||||
if (!jobExecution.getAllFailureExceptions().isEmpty()) {
|
||||
throw jobExecution.getAllFailureExceptions().get(0);
|
||||
}
|
||||
|
||||
assertEquals(BatchStatus.COMPLETED, stepExecution.getStatus());
|
||||
assertEquals(2, jobExecution.getStepExecutions().size());
|
||||
assertEquals(3, jobExecution.getStepExecutions().size());
|
||||
|
||||
}
|
||||
|
||||
@@ -672,7 +678,6 @@ public class JsrFlowJobTests {
|
||||
assertEquals("[step1, step2]", names.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
@@ -692,6 +697,32 @@ public class JsrFlowJobTests {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @author Michael Minella
|
||||
*
|
||||
*/
|
||||
private class StubDecisionStep extends StepSupport {
|
||||
|
||||
private Decider decider;
|
||||
|
||||
private StubDecisionStep(String name, Decider decider) {
|
||||
super(name);
|
||||
this.decider = decider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(StepExecution stepExecution) throws JobInterruptedException {
|
||||
stepExecution.setStatus(BatchStatus.COMPLETED);
|
||||
try {
|
||||
stepExecution.setExitStatus(new ExitStatus(decider.decide(new javax.batch.runtime.StepExecution [] {new org.springframework.batch.core.jsr.StepExecution(stepExecution)})));
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
jobRepository.update(stepExecution);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jobExecution
|
||||
* @param stepName
|
||||
|
||||
Reference in New Issue
Block a user