-
+
+
@@ -453,6 +453,12 @@
spring-web
${spring.framework.version}
+
+ xerces
+ xercesImpl
+ 2.8.1
+ optional
+
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncher.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncher.java
index 0c5c11026..d4f380c3e 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncher.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncher.java
@@ -18,9 +18,13 @@ package org.springframework.batch.execution.bootstrap.support;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.springframework.batch.core.domain.Job;
+import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.NoSuchJobException;
import org.springframework.batch.core.executor.ExitCodeExceptionClassifier;
+import org.springframework.batch.core.runtime.JobIdentifierFactory;
import org.springframework.batch.execution.launch.JobLauncher;
+import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
import org.springframework.batch.execution.step.simple.SimpleExitCodeExceptionClassifier;
import org.springframework.batch.repeat.ExitStatus;
import org.springframework.beans.factory.access.BeanFactoryLocator;
@@ -45,22 +49,22 @@ import org.springframework.util.Assert;
*
*
* With any launch of a batch job within Spring Batch, a minimum of two contexts
- * must be loaded. One is the context containing the Job, the other
- * contains the 'Execution Environment'. That is, the JobExecutorFacade (which
- * contains all the executors, plus the repository), the JobIdentifierFactory,
- * and a normal JobLauncher. This command line launcher loads these application
- * contexts by first loading the execution environment context via a
+ * must be loaded. One is the context containing the Job, the other contains the
+ * 'Execution Environment'. That is, the JobExecutorFacade (which contains all
+ * the executors, plus the repository), the JobIdentifierFactory, and a normal
+ * JobLauncher. This command line launcher loads these application contexts by
+ * first loading the execution environment context via a
* {@link ContextSingletonBeanFactoryLocator}, which will search for the
* default key from classpath*:beanRefContext.xml to return the context. This
- * will then be used as the parent to the Job context. All required
- * dependencies of the launcher will then be satisfied by autowiring by type
- * from the combined application context. Default values are provided for all
- * fields except the JobLauncher. Therefore, if autowiring fails to set it (it
- * should be noted that dependency checking is disabled because most of the
- * fields have default values and thus don't require dependencies to be
- * fulfilled via autowiring) then an exception will be thrown. It should also be
- * noted that even if an exception is thrown by this class, it will be mapped to
- * an integer and returned.
+ * will then be used as the parent to the Job context. All required dependencies
+ * of the launcher will then be satisfied by autowiring by type from the
+ * combined application context. Default values are provided for all fields
+ * except the JobLauncher. Therefore, if autowiring fails to set it (it should
+ * be noted that dependency checking is disabled because most of the fields have
+ * default values and thus don't require dependencies to be fulfilled via
+ * autowiring) then an exception will be thrown. It should also be noted that
+ * even if an exception is thrown by this class, it will be mapped to an integer
+ * and returned.
*
*
*
@@ -76,8 +80,7 @@ import org.springframework.util.Assert;
* method are optional, VM arguments are used:
*
*
- * - -Djob.configuration.path: the classpath location of the Job
- * to use
+ *
- -Djob.configuration.path: the classpath location of the Job to use
*
- -Djob.name: job name to be passed to the {@link JobLauncher}
*
- -Dbatch.execution.environment.key: the key in beanRefContext.xml used to
* load the execution envrionement.
@@ -89,27 +92,33 @@ import org.springframework.util.Assert;
*/
public class BatchCommandLineLauncher {
- protected static final Log logger = LogFactory
- .getLog(BatchCommandLineLauncher.class);
+ protected static final Log logger = LogFactory.getLog(BatchCommandLineLauncher.class);
/**
* The default key for the parent context.
*/
public static final String DEFAULT_PARENT_KEY = "batchExecutionEnvironment";
+
/**
* The default path to the job configuration.
*/
public static final String DEFAULT_JOB_CONFIGURATION_PATH = "job-configuration.xml";
+
/**
* The default path to the bean reference context.
*/
public static final String DEFAULT_BEAN_REF_CONTEXT_PATH = "beanRefContext.xml";
private static final String JOB_CONFIGURATION_PATH_KEY = "job.configuration.path";
+
private static final String JOB_NAME_KEY = "job.name";
+
private static final String BATCH_EXECUTION_ENVIRONMENT_KEY = "batch.execution.environment.key";
+
private static final String BEAN_REF_CONTEXT_KEY = "bean.ref.context";
+ private JobIdentifierFactory jobIdentifierFactory = new ScheduledJobIdentifierFactory();
+
private BeanFactoryLocator beanFactoryLocator;
private ExitCodeMapper exitCodeMapper = new SimpleJvmExitCodeMapper();
@@ -120,16 +129,34 @@ public class BatchCommandLineLauncher {
private SystemExiter systemExiter = new JvmSystemExiter();
+ private String defaultJobName;
+
public BatchCommandLineLauncher(String beanRefContextPath) {
- beanFactoryLocator = ContextSingletonBeanFactoryLocator
- .getInstance(beanRefContextPath);
+ beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance(beanRefContextPath);
+ }
+
+ /**
+ * Setter for the name of the {@link Job} that this launcher will run.
+ *
+ * @param jobName the job name to set
+ */
+ public void setDefaultJobName(String defaultJobName) {
+ this.defaultJobName = defaultJobName;
+ }
+
+ /**
+ * Setter for {@link JobIdentifierFactory}.
+ *
+ * @param jobIdentifierFactory the {@link JobIdentifierFactory} to set
+ */
+ public void setJobIdentifierFactory(JobIdentifierFactory jobIdentifierFactory) {
+ this.jobIdentifierFactory = jobIdentifierFactory;
}
/**
* Injection setter for the {@link JobLauncher}.
*
- * @param launcher
- * the launcher to set
+ * @param launcher the launcher to set
*/
public void setLauncher(JobLauncher launcher) {
this.launcher = launcher;
@@ -140,16 +167,14 @@ public class BatchCommandLineLauncher {
*
* @param exceptionClassifier
*/
- public void setExceptionClassifier(
- ExitCodeExceptionClassifier exceptionClassifier) {
+ public void setExceptionClassifier(ExitCodeExceptionClassifier exceptionClassifier) {
this.exceptionClassifier = exceptionClassifier;
}
/**
* Injection setter for the {@link JvmExitCodeMapper}.
*
- * @param exitCodeMapper
- * the exitCodeMapper to set
+ * @param exitCodeMapper the exitCodeMapper to set
*/
public void setExitCodeMapper(ExitCodeMapper exitCodeMapper) {
this.exitCodeMapper = exitCodeMapper;
@@ -174,15 +199,13 @@ public class BatchCommandLineLauncher {
}
/**
- * @param path
- * the path to a Spring context configuration for this job
- * @param jobName
- * the name of the job execution to use
+ * @param path the path to a Spring context configuration for this job
+ * @param jobName the name of the job execution to use
* @parm parentKey the key to be loaded by
- * ContextSingletonBeanFactoryLocator and used as the parent context.
+ * ContextSingletonBeanFactoryLocator and used as the parent context.
* @throws NoSuchJobException
- * @throws IllegalStateException
- * if JobLauncher is not autowired by the ApplicationContext
+ * @throws IllegalStateException if JobLauncher is not autowired by the
+ * ApplicationContext
*/
int start(String path, String jobName, String parentKey) {
@@ -190,8 +213,8 @@ public class BatchCommandLineLauncher {
ClassPathXmlApplicationContext context = null;
try {
- ConfigurableApplicationContext parent = (ConfigurableApplicationContext) beanFactoryLocator
- .useBeanFactory(parentKey).getFactory();
+ ConfigurableApplicationContext parent = (ConfigurableApplicationContext) beanFactoryLocator.useBeanFactory(
+ parentKey).getFactory();
parent.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
@@ -200,39 +223,50 @@ public class BatchCommandLineLauncher {
path = path + ".xml";
}
- context = new ClassPathXmlApplicationContext(new String[] { path },
- parent);
+ context = new ClassPathXmlApplicationContext(new String[] { path }, parent);
- context.getAutowireCapableBeanFactory().autowireBeanProperties(
- this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
+ context.getAutowireCapableBeanFactory().autowireBeanProperties(this,
+ AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
- Assert
- .state(
- launcher != null,
- "JobLauncher must be provided in the parent ApplicationContext"
- + ", check the context created within classpath*:beanRefContext.xml to ensure a JobLauncher"
- + " is declared");
+ Assert.state(launcher != null, "JobLauncher must be provided in the parent ApplicationContext"
+ + ", check the context created within classpath*:beanRefContext.xml to ensure a JobLauncher"
+ + " is declared");
- if (!launcher.isRunning()) {
- if (jobName == null) {
- status = launcher.run().getExitStatus();
- } else {
- status = launcher.run(jobName).getExitStatus();
+ if (jobName == null) {
+ String[] names = context.getBeanNamesForType(Job.class);
+ if (names.length==1) {
+ Job job = (Job) context.getBean(names[0]);
+ jobName = job.getName();
}
}
- } catch (NoSuchJobException e) {
- logger.fatal("Could not locate JobConfiguration \"" + jobName
- + "\"", e);
- status = new ExitStatus(false,
- ExitCodeMapper.NO_SUCH_JOB);
- } catch (Throwable t) {
+
+ if (jobName == null) {
+ jobName = defaultJobName;
+ }
+
+ if (jobName == null) {
+ throw new NoSuchJobException("Null job name cannot be located.");
+ }
+ JobIdentifier runtimeInformation = jobIdentifierFactory.getJobIdentifier(jobName);
+
+ if (!launcher.isRunning()) {
+ status = launcher.run(runtimeInformation).getExitStatus();
+ }
+ }
+ catch (NoSuchJobException e) {
+ logger.fatal("Could not locate JobConfiguration \"" + jobName + "\"", e);
+ status = new ExitStatus(false, ExitCodeMapper.NO_SUCH_JOB);
+ }
+ catch (Throwable t) {
logger.fatal(t);
status = exceptionClassifier.classifyForExitCode(t);
- } finally {
+ }
+ finally {
if (context != null) {
try {
context.stop();
- } finally {
+ }
+ finally {
context.close();
}
}
@@ -249,29 +283,23 @@ public class BatchCommandLineLauncher {
* Spring context).
*
* @param args
- *
- * - -Djob.configuration.path: the classpath location of the
- * JobConfiguration to use
- *
- -Djob.name: job name to be passed to the
- * {@link JobLauncher}
- *
- -Dbatch.execution.environment.key: the key in
- * beanRefContext.xml used to load the execution envrionment.
- *
- -Dbean.ref.context: an altrernative location for
- * beanRefContext.xml.
- *
+ *
+ * - -Djob.configuration.path: the classpath location of the
+ * JobConfiguration to use
+ *
- -Djob.name: job name to be passed to the {@link JobLauncher}
+ *
- -Dbatch.execution.environment.key: the key in beanRefContext.xml
+ * used to load the execution envrionment.
+ *
- -Dbean.ref.context: an altrernative location for beanRefContext.xml.
+ *
*/
public static void main(String[] args) {
- String path = System.getProperty(JOB_CONFIGURATION_PATH_KEY,
- DEFAULT_JOB_CONFIGURATION_PATH);
+ String path = System.getProperty(JOB_CONFIGURATION_PATH_KEY, DEFAULT_JOB_CONFIGURATION_PATH);
String name = System.getProperty(JOB_NAME_KEY);
- String beanRefContextPath = System.getProperty(BEAN_REF_CONTEXT_KEY,
- DEFAULT_BEAN_REF_CONTEXT_PATH);
- String parentKey = System.getProperty(BATCH_EXECUTION_ENVIRONMENT_KEY,
- DEFAULT_PARENT_KEY);
+ String beanRefContextPath = System.getProperty(BEAN_REF_CONTEXT_KEY, DEFAULT_BEAN_REF_CONTEXT_PATH);
+ String parentKey = System.getProperty(BATCH_EXECUTION_ENVIRONMENT_KEY, DEFAULT_PARENT_KEY);
- BatchCommandLineLauncher command = new BatchCommandLineLauncher(
- beanRefContextPath);
+ BatchCommandLineLauncher command = new BatchCommandLineLauncher(beanRefContextPath);
int result = command.start(path, name, parentKey);
command.exit(result);
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptor.java
index edc059541..dc9723eef 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptor.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptor.java
@@ -19,11 +19,14 @@ package org.springframework.batch.execution.bootstrap.support;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.beans.SimpleTypeConverter;
import org.springframework.beans.TypeConverter;
+import org.springframework.beans.TypeMismatchException;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -47,8 +50,7 @@ public class TypeConverterMethodInterceptor implements MethodInterceptor {
* where exception reporting is a little weak (and in addition the class of
* the exception might not be available remotely).
*
- * @param convertException
- * the flag to set (default false)
+ * @param convertException the flag to set (default false)
*/
public void setConvertException(boolean convertException) {
this.convertException = convertException;
@@ -58,8 +60,7 @@ public class TypeConverterMethodInterceptor implements MethodInterceptor {
* Public setter for the {@link TypeConverter} property. Defaults to a
* {@link SimpleTypeConverter}.
*
- * @param typeConverter
- * the typeConverter to set
+ * @param typeConverter the typeConverter to set
*/
public void setTypeConverter(TypeConverter typeConverter) {
this.typeConverter = typeConverter;
@@ -72,20 +73,48 @@ public class TypeConverterMethodInterceptor implements MethodInterceptor {
*
* @return an object that satisfies the signature of the proxy method.
*
- * @throws TypeMismatchException
- * if the target method returns an object that cannot be
- * converted to the desired type.
+ * @throws TypeMismatchException if the target method returns an object that
+ * cannot be converted to the desired type.
*
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
*/
public Object invoke(MethodInvocation invocation) throws Throwable {
// The method called on the proxy
- Method invoked = invocation.getMethod();
+ final Method invoked = invocation.getMethod();
// The corresponding method on the target if there is one...
- Method method = ReflectionUtils.findMethod(invocation.getThis()
- .getClass(), invoked.getName(), invoked.getParameterTypes());
+ Method method = ReflectionUtils.findMethod(invocation.getThis().getClass(), invoked.getName(), invoked
+ .getParameterTypes());
+
+ Object[] arguments = invocation.getArguments();
+
+ // If there was no such method look for one with String args
+ if (method == null) {
+ final List methods = new ArrayList();
+ ReflectionUtils.doWithMethods(invocation.getThis().getClass(), new ReflectionUtils.MethodCallback() {
+ public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {
+ methods.add(method);
+ }
+
+ }, new ReflectionUtils.MethodFilter() {
+ public boolean matches(Method method) {
+ if (method.getName().equals(invoked.getName())
+ && method.getParameterTypes().length == invoked.getParameterTypes().length) {
+ return true;
+ }
+ return false;
+ }
+
+ });
+ if (methods.size()==1) {
+ method = (Method) methods.get(0);
+ for (int i = 0; i < arguments.length; i++) {
+ Object arg = arguments[i];
+ arguments[i] = convert(arg, method.getParameterTypes()[i]);
+ }
+ }
+ }
// If there was no such method do nothing... TODO: throw Exception?
if (method == null) {
@@ -96,12 +125,13 @@ public class TypeConverterMethodInterceptor implements MethodInterceptor {
Object result = null;
try {
- result = ReflectionUtils.invokeMethod(method, invocation.getThis(),
- invocation.getArguments());
- } catch (Throwable e) {
+ result = ReflectionUtils.invokeMethod(method, invocation.getThis(), arguments);
+ }
+ catch (Throwable e) {
if (convertException) {
result = e;
- } else {
+ }
+ else {
throw e;
}
}
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/JobLauncher.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/JobLauncher.java
index f224360a7..6554d2f08 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/JobLauncher.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/JobLauncher.java
@@ -30,33 +30,6 @@ import org.springframework.batch.core.repository.JobExecutionAlreadyRunningExcep
public interface JobLauncher {
- /**
- * Start a job execution with default name and other runtime information
- * generated on the fly.
- *
- * @return the exit code from the job if it returns synchronously. If the
- * implementation is asynchronous, the status might well be unknown.
- * @throws JobExecutionAlreadyRunningException
- *
- */
- public JobExecution run() throws NoSuchJobException, JobExecutionAlreadyRunningException;
-
- /**
- * Start a job execution with the given name and other runtime information
- * generated on the fly. The name is used to locate a job configuration, and
- * the other runtime information is used to identify the job instance.
- *
- * @param name
- * the name to assign to the job configuration
- * @return the exit code from the job if it returns synchronously. If the
- * implementation is asynchronous, the status might well be unknown.
- *
- * @throws NoSuchJobException
- * @throws JobExecutionAlreadyRunningException
- */
- public JobExecution run(String jobName)
- throws NoSuchJobException, JobExecutionAlreadyRunningException;
-
/**
* Start a job execution with the given runtime information.
*
diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
index 577156033..b8643e7c8 100644
--- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
+++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/launch/SimpleJobLauncher.java
@@ -38,15 +38,11 @@ import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.runtime.JobIdentifierFactory;
import org.springframework.batch.execution.job.DefaultJobExecutor;
import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
-import org.springframework.batch.io.exception.BatchConfigurationException;
import org.springframework.batch.repeat.interceptor.RepeatOperationsApplicationEvent;
import org.springframework.batch.statistics.StatisticsProvider;
import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.util.Assert;
@@ -58,11 +54,10 @@ import org.springframework.util.Assert;
* @see JobLauncher
* @author Dave Syer
*/
-public class SimpleJobLauncher implements JobLauncher, InitializingBean,
- ApplicationListener, ApplicationEventPublisherAware, StatisticsProvider {
+public class SimpleJobLauncher implements JobLauncher, InitializingBean, ApplicationEventPublisherAware,
+ StatisticsProvider {
- protected static final Log logger = LogFactory
- .getLog(SimpleJobLauncher.class);
+ protected static final Log logger = LogFactory.getLog(SimpleJobLauncher.class);
private JobExecutor jobExecutor = new DefaultJobExecutor();
@@ -80,12 +75,6 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
private List listeners = new ArrayList();
- private String jobName;
-
- // Do not autostart by default - allow user to set a job
- // later and then manually start:
- private volatile boolean autoStart = false;
-
private JobIdentifierFactory jobIdentifierFactory = new ScheduledJobIdentifierFactory();
private final Object monitor = new Object();
@@ -98,53 +87,28 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
/**
* Setter for {@link JobIdentifierFactory}.
*
- * @param jobIdentifierFactory
- * the {@link JobIdentifierFactory} to set
+ * @param jobIdentifierFactory the {@link JobIdentifierFactory} to set
*/
- public void setJobIdentifierFactory(
- JobIdentifierFactory jobIdentifierFactory) {
+ public void setJobIdentifierFactory(JobIdentifierFactory jobIdentifierFactory) {
this.jobIdentifierFactory = jobIdentifierFactory;
}
- /**
- * Setter for the {@link Job} that this launcher will run.
- *
- * @param jobName
- * the job name to set
- */
- public void setJobName(String jobName) {
- this.jobName = jobName;
- }
-
- /**
- * Setter for autostart flag. If this is true then the container will be
- * started when the Spring context is refreshed. Defaults to false.
- *
- * @param autoStart
- */
- public void setAutoStart(boolean autoStart) {
- this.autoStart = autoStart;
- }
-
/**
* Public setter for the listeners property.
*
- * @param listeners
- * the listeners to set - a list of {@link JobExecutionListener}.
+ * @param listeners the listeners to set - a list of
+ * {@link JobExecutionListener}.
*/
public void setJobExecutionListeners(List listeners) {
this.listeners = listeners;
}
/**
- * Setter for injection of {@link JobLocator}. Mandatory with
- * no default.
+ * Setter for injection of {@link JobLocator}. Mandatory with no default.
*
- * @param jobLocator
- * the jobLocator to set
+ * @param jobLocator the jobLocator to set
*/
- public void setJobLocator(
- JobLocator jobLocator) {
+ public void setJobLocator(JobLocator jobLocator) {
this.jobLocator = jobLocator;
}
@@ -188,8 +152,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
Assert.notNull(jobExecutor);
Assert.notNull(jobRepository);
SimpleJobExecutorFacade jobExecutorFacade = new SimpleJobExecutorFacade();
- jobExecutorFacade
- .setJobLocator(jobLocator);
+ jobExecutorFacade.setJobLocator(jobLocator);
jobExecutorFacade.setJobExecutionListeners(listeners);
jobExecutorFacade.setJobExecutor(jobExecutor);
jobExecutorFacade.setJobRepository(jobRepository);
@@ -197,34 +160,6 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
}
}
- /**
- * If autostart flag is on, initialise on context start-up and call
- * {@link #run()}.
- *
- * @throws BatchConfigurationException
- * if the job tries to but cannot start because of a
- * {@link NoSuchJobException}.
- *
- * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent)
- *
- */
- public void onApplicationEvent(ApplicationEvent event) {
- if ((event instanceof ContextRefreshedEvent) && this.autoStart
- && !isRunning()) {
- try {
- run();
- } catch (NoSuchJobException e) {
- throw new BatchConfigurationException(
- "Cannot start job on context refresh because it does not exist",
- e);
- } catch (JobExecutionAlreadyRunningException e) {
- throw new BatchConfigurationException(
- "Cannot start job on context refresh because it is already running",
- e);
- }
- }
- }
-
/**
* This method is wrapped in a Runnable by {@link #run(JobIdentifier)}, so
* that the internal housekeeping is done consistently. Subclasses should be
@@ -234,21 +169,21 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* @return
* @throws NoSuchJobException
*/
- protected final void runInternal(JobExecution execution)
- throws NoSuchJobException {
+ protected final void runInternal(JobExecution execution) throws NoSuchJobException {
JobIdentifier jobIdentifier = execution.getJobInstance().getIdentifier();
-
- if (getJobExecution(jobIdentifier)==null) {
- logger.info("Job already stopped (not launching): "+jobIdentifier);
+
+ if (getJobExecution(jobIdentifier) == null) {
+ logger.info("Job already stopped (not launching): " + jobIdentifier);
return;
}
try {
- logger.info("Launching: "+jobIdentifier);
+ logger.info("Launching: " + jobIdentifier);
jobExecutorFacade.start(execution);
- logger.info("Completed successfully: "+jobIdentifier);
- } finally {
+ logger.info("Completed successfully: " + jobIdentifier);
+ }
+ finally {
unregister(jobIdentifier);
}
@@ -257,23 +192,19 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
/**
* Start the job using the task executor provided.
*
- * @throws NoSuchJobException
- * if the identifier cannot be used to locate a
- * {@link Job}.
+ * @throws NoSuchJobException if the identifier cannot be used to locate a
+ * {@link Job}.
*
* @see org.springframework.batch.execution.launch.SimpleJobLauncher#run(org.springframework.batch.core.domain.JobIdentifier)
*/
- public JobExecution run(final JobIdentifier jobIdentifier)
- throws NoSuchJobException,
+ public JobExecution run(final JobIdentifier jobIdentifier) throws NoSuchJobException,
JobExecutionAlreadyRunningException {
if (getJobExecution(jobIdentifier) != null) {
- throw new JobExecutionAlreadyRunningException(
- "A job is already executing with this identifier: ["
- + jobIdentifier + "]");
+ throw new JobExecutionAlreadyRunningException("A job is already executing with this identifier: ["
+ + jobIdentifier + "]");
}
- final JobExecution execution = jobExecutorFacade
- .createExecutionFrom(jobIdentifier);
+ final JobExecution execution = jobExecutorFacade.createExecutionFrom(jobIdentifier);
// TODO: throw JobExecutionAlreadyRunningException if it is in a running
// state (someone else launched it)
final JobExecutionHolder holder = register(execution);
@@ -284,23 +215,21 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
synchronized (monitor) {
if (isInternalRunning(jobIdentifier)) {
- logger.info("This job is already running, so not re-launched: "+jobIdentifier);
+ logger.info("This job is already running, so not re-launched: " + jobIdentifier);
return;
}
}
holder.start();
runInternal(execution);
-
- } catch (NoSuchJobException e) {
- applicationEventPublisher
- .publishEvent(new RepeatOperationsApplicationEvent(
- jobIdentifier, "No such job",
- RepeatOperationsApplicationEvent.ERROR));
- logger.error(
- "Job could not be located inside Runnable for identifier: ["
- + jobIdentifier + "]", e);
- } finally {
+
+ }
+ catch (NoSuchJobException e) {
+ applicationEventPublisher.publishEvent(new RepeatOperationsApplicationEvent(jobIdentifier,
+ "No such job", RepeatOperationsApplicationEvent.ERROR));
+ logger.error("Job could not be located inside Runnable for identifier: [" + jobIdentifier + "]", e);
+ }
+ finally {
holder.stop();
}
}
@@ -310,59 +239,14 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
}
- /**
- * Start a job execution with the given name. If a job is already running
- * has no effect.
- *
- * @param name
- * the name to assign to the job
- * @throws NoSuchJobException
- * @throws JobExecutionAlreadyRunningException
- */
- public JobExecution run(String name)
- throws NoSuchJobException,
- JobExecutionAlreadyRunningException {
- if (name == null) {
- throw new NoSuchJobException(
- "Null job name cannot be located.");
- }
- JobIdentifier runtimeInformation = jobIdentifierFactory
- .getJobIdentifier(name);
- return this.run(runtimeInformation);
- }
-
- /**
- * Start a job execution with default name and other runtime information
- * provided by the factory. If a job is already running has no effect. The
- * default name is taken from the enclosed {@link Job}.
- *
- * @throws NoSuchJobException
- *
- * @throws NoSuchJobException
- * if the job cannot be located
- * @throws JobExecutionAlreadyRunningException
- *
- * @see #setJobIdentifierFactory(JobIdentifierFactory)
- * @see org.springframework.context.Lifecycle#start()
- */
- public JobExecution run() throws NoSuchJobException,
- JobExecutionAlreadyRunningException {
- if (jobName != null) {
- return this.run(jobName);
- }
- throw new NoSuchJobException(
- "Null default job name cannot be located.");
- }
-
/**
* Extension point for subclasses to stop a specific job.
*
* @throws NoSuchJobExecutionException
*/
- protected void doStop(JobIdentifier jobIdentifier)
- throws NoSuchJobExecutionException {
+ protected void doStop(JobIdentifier jobIdentifier) throws NoSuchJobExecutionException {
JobExecution execution = getJobExecution(jobIdentifier);
- logger.info("Stopping job: "+jobIdentifier);
+ logger.info("Stopping job: " + jobIdentifier);
if (execution != null) {
jobExecutorFacade.stop(execution);
}
@@ -378,12 +262,12 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* @see org.springframework.batch.execution.launch.JobLauncher#stop()
*/
final public void stop() {
- for (Iterator iter = new HashSet(registry.keySet()).iterator(); iter
- .hasNext();) {
+ for (Iterator iter = new HashSet(registry.keySet()).iterator(); iter.hasNext();) {
JobIdentifier context = (JobIdentifier) iter.next();
try {
stop(context);
- } catch (NoSuchJobExecutionException e) {
+ }
+ catch (NoSuchJobExecutionException e) {
logger.error(e);
}
}
@@ -398,8 +282,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* @see org.springframework.batch.execution.launch.JobLauncher#stop(org.springframework.batch.core.domain.JobIdentifier)
* @see BatchContainer#stop(JobRuntimeInformation))
*/
- final public void stop(JobIdentifier runtimeInformation)
- throws NoSuchJobExecutionException {
+ final public void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException {
synchronized (monitor) {
doStop(runtimeInformation);
}
@@ -437,8 +320,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
private boolean isInternalRunning(JobIdentifier jobIdentifier) {
synchronized (registry) {
JobExecutionHolder jobExecutionHolder = getJobExecutionHolder(jobIdentifier);
- return isRunning(jobIdentifier)
- && jobExecutionHolder!=null && jobExecutionHolder.isRunning();
+ return isRunning(jobIdentifier) && jobExecutionHolder != null && jobExecutionHolder.isRunning();
}
}
@@ -447,10 +329,9 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* {@link JobIdentifier} to see if it is running. As long as at least one
* job is running the launcher is deemed to be running.
*
- * @param jobIdentifier
- * a {@link JobIdentifier}
+ * @param jobIdentifier a {@link JobIdentifier}
* @return always true. Subclasses can override and provide more accurate
- * information.
+ * information.
*/
protected boolean isRunning(JobIdentifier jobIdentifier) {
return true;
@@ -515,8 +396,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* Setter for the {@link TaskExecutor}. Defaults to a
* {@link SyncTaskExecutor}.
*
- * @param taskExecutor
- * the taskExecutor to set
+ * @param taskExecutor the taskExecutor to set
*/
public void setTaskExecutor(TaskExecutor taskExecutor) {
this.taskExecutor = taskExecutor;
@@ -532,29 +412,32 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
* only.
*
* @return Properties representing the {@link JobExecution} objects passed
- * up from the underlying execution. If there are no jobs running it
- * will be empty.
+ * up from the underlying execution. If there are no jobs running it will be
+ * empty.
*/
public Properties getStatistics() {
if (jobExecutorFacade instanceof StatisticsProvider) {
return ((StatisticsProvider) jobExecutorFacade).getStatistics();
- } else {
+ }
+ else {
return new Properties();
}
}
- public void setApplicationEventPublisher(
- ApplicationEventPublisher applicationEventPublisher) {
+ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
this.applicationEventPublisher = applicationEventPublisher;
}
private class JobExecutionHolder {
private static final int NEW = 0;
+
private static final int STARTED = 1;
+
private static final int STOPPED = 2;
-
+
private JobExecution execution;
+
private int status = NEW;
public JobExecutionHolder(JobExecution execution) {
@@ -566,7 +449,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
}
boolean isRunning() {
- return status==STARTED;
+ return status == STARTED;
}
void start() {
diff --git a/spring-batch-execution/src/main/sql/destroy.sql.vpp b/spring-batch-execution/src/main/sql/destroy.sql.vpp
index c2260004e..6803b5a4d 100644
--- a/spring-batch-execution/src/main/sql/destroy.sql.vpp
+++ b/spring-batch-execution/src/main/sql/destroy.sql.vpp
@@ -3,6 +3,7 @@ DROP TABLE $!{IFEXISTSBEFORE} BATCH_STEP_EXECUTION $!{IFEXISTS};
DROP TABLE $!{IFEXISTSBEFORE} BATCH_JOB_EXECUTION $!{IFEXISTS};
DROP TABLE $!{IFEXISTSBEFORE} BATCH_STEP_INSTANCE $!{IFEXISTS};
DROP TABLE $!{IFEXISTSBEFORE} BATCH_JOB_INSTANCE $!{IFEXISTS};
+DROP TABLE $!{IFEXISTSBEFORE} BATCH_JOB_INSTANCE_PROPERTIES $!{IFEXISTS};
DROP ${SEQUENCE} $!{IFEXISTSBEFORE} BATCH_STEP_EXECUTION_SEQ $!{IFEXISTS};
DROP ${SEQUENCE} $!{IFEXISTSBEFORE} BATCH_STEP_SEQ $!{IFEXISTS};
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncherTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncherTests.java
index 3aba37af1..560a4c7f7 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncherTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/BatchCommandLineLauncherTests.java
@@ -91,7 +91,7 @@ public class BatchCommandLineLauncherTests extends TestCase {
assertEquals(ExitCodeMapper.JVM_EXITCODE_COMPLETED, systemExiter
.getStatus());
assertEquals(jobLauncher.getLastRunCalled(),
- StubJobLauncher.RUN_NO_ARGS);
+ StubJobLauncher.RUN_JOB_IDENTIFIER);
}
/**
@@ -113,7 +113,7 @@ public class BatchCommandLineLauncherTests extends TestCase {
assertEquals(ExitCodeMapper.JVM_EXITCODE_COMPLETED, systemExiter
.getStatus());
assertEquals(jobLauncher.getLastRunCalled(),
- StubJobLauncher.RUN_JOB_NAME);
+ StubJobLauncher.RUN_JOB_IDENTIFIER);
}
private void setReturnValue(ExitStatus status) {
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/StubJobLauncher.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/StubJobLauncher.java
index a0f4a6cd0..d06bc2637 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/StubJobLauncher.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/StubJobLauncher.java
@@ -29,17 +29,6 @@ public class StubJobLauncher implements JobLauncher {
return isRunning;
}
- public JobExecution run() throws NoSuchJobException {
- lastRunCalled = RUN_NO_ARGS;
- return returnValue;
- }
-
- public JobExecution run(String jobName)
- throws NoSuchJobException {
- lastRunCalled = RUN_JOB_NAME;
- return returnValue;
- }
-
public JobExecution run(JobIdentifier jobIdentifier)
throws NoSuchJobException {
lastRunCalled = RUN_JOB_IDENTIFIER;
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptorTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptorTests.java
index 55120f9e4..7f0ac1d36 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptorTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/bootstrap/support/TypeConverterMethodInterceptorTests.java
@@ -1,7 +1,9 @@
package org.springframework.batch.execution.bootstrap.support;
+import java.beans.PropertyEditorSupport;
import java.util.ArrayList;
import java.util.List;
+import java.util.regex.Pattern;
import junit.framework.TestCase;
@@ -70,6 +72,21 @@ public class TypeConverterMethodInterceptorTests extends TestCase {
assertEquals("FOO:true", proxy.getBean());
}
+ public void testInvokeWithMethodParameterConversionToBoolean() throws Exception {
+ ProxyFactory factory = new ProxyFactory(Test.class, interceptor);
+ factory.setTarget(new TestBean(true));
+ Test proxy = (Test) factory.getProxy();
+ assertEquals("flag:true", proxy.grab("true"));
+ }
+
+ public void testInvokeWithMethodParameterConversionToPattern() throws Exception {
+ ProxyFactory factory = new ProxyFactory(Test.class, interceptor);
+ factory.setTarget(new TestBean(true));
+ Test proxy = (Test) factory.getProxy();
+ Pattern pattern = Pattern.compile("[a-z]*");
+ assertEquals(pattern.toString(), proxy.relayPattern("[a-z]*"));
+ }
+
public void testInvalidConversion() throws Exception {
ProxyFactory factory = new ProxyFactory(Test.class, interceptor);
factory.setTarget(new TestBean(true));
@@ -95,16 +112,37 @@ public class TypeConverterMethodInterceptorTests extends TestCase {
assertEquals(testCase, proxy.getInvalid());
}
+ public void testInvokeWithMethodParameterConversionWithPropertyEditor() throws Exception {
+ final TestBean bean = new TestBean(false);
+ SimpleTypeConverter converter = new SimpleTypeConverter();
+ converter.registerCustomEditor(TestBean.class, new PropertyEditorSupport() {
+ public void setAsText(String text) throws IllegalArgumentException {
+ setValue(bean);
+ }
+ });
+ interceptor.setTypeConverter(converter);
+ ProxyFactory factory = new ProxyFactory(Test.class, interceptor);
+ factory.setTarget(new TestBean(true));
+ Test proxy = (Test) factory.getProxy();
+ assertEquals(bean.toString(), proxy.relayBean("foo"));
+ }
+
public interface Test {
boolean isTest();
String getBean();
+ String relayPattern(String pattern);
+
TestCase getInvalid();
int getValue();
void operate();
+
+ String grab(String value);
+
+ String relayBean(String value);
}
// N.B. TestBean intentionally does not implement Test!
@@ -124,6 +162,14 @@ public class TypeConverterMethodInterceptorTests extends TestCase {
return this;
}
+ public TestBean relayBean(TestBean bean) {
+ return bean;
+ }
+
+ public Pattern relayPattern(Pattern pattern) {
+ return pattern;
+ }
+
public TestBean getInvalid() {
return this;
}
@@ -135,6 +181,10 @@ public class TypeConverterMethodInterceptorTests extends TestCase {
public void operate() {
list.add("FOO");
}
+
+ public String grab(boolean flag) {
+ return "flag:"+flag;
+ }
public String toString() {
return "FOO:" + test;
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
index cccd78306..c9f915b37 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/SimpleJobLauncherTests.java
@@ -18,11 +18,12 @@ package org.springframework.batch.execution.launch;
import junit.framework.TestCase;
-import org.springframework.batch.core.domain.Job;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobInstance;
import org.springframework.batch.core.domain.NoSuchJobException;
+import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
+import org.springframework.batch.core.runtime.SimpleJobIdentifier;
import org.springframework.batch.core.runtime.SimpleJobIdentifierFactory;
public class SimpleJobLauncherTests extends TestCase {
@@ -40,8 +41,14 @@ public class SimpleJobLauncherTests extends TestCase {
public void testInitializeWithNoConfiguration() throws Exception {
final SimpleJobLauncher launcher = new SimpleJobLauncher();
+ launcher.setJobExecutorFacade(new SimpleJobExecutorFacade() {
+ public JobExecution createExecutionFrom(JobIdentifier jobIdentifier) throws NoSuchJobException,
+ JobExecutionAlreadyRunningException {
+ throw new NoSuchJobException("No null job, stupid!");
+ }
+ });
try {
- launcher.run();
+ launcher.run(new SimpleJobIdentifier(null));
// should do nothing
fail("Expected NoSuchJobConfigurationException");
} catch (NoSuchJobException e) {
@@ -56,10 +63,9 @@ public class SimpleJobLauncherTests extends TestCase {
launcher.setJobIdentifierFactory(new SimpleJobIdentifierFactory());
InterruptibleFacade jobExecutorFacade = new InterruptibleFacade();
launcher.setJobExecutorFacade(jobExecutorFacade);
- launcher.setJobName(new Job("foo").getName());
- launcher.run();
+ launcher.run(new SimpleJobIdentifier("foo"));
assertFalse(launcher.isRunning());
- launcher.run();
+ launcher.run(new SimpleJobIdentifier("foo"));
// Both jobs finished running because they were not launched in a new
// Thread
assertFalse(launcher.isRunning());
diff --git a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/TaskExecutorJobLauncherTests.java b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/TaskExecutorJobLauncherTests.java
index e29d13c93..e42117cfc 100644
--- a/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/TaskExecutorJobLauncherTests.java
+++ b/spring-batch-execution/src/test/java/org/springframework/batch/execution/launch/TaskExecutorJobLauncherTests.java
@@ -25,7 +25,6 @@ import java.util.TimerTask;
import junit.framework.TestCase;
import org.easymock.MockControl;
-import org.springframework.batch.core.domain.Job;
import org.springframework.batch.core.domain.JobExecution;
import org.springframework.batch.core.domain.JobIdentifier;
import org.springframework.batch.core.domain.JobInstance;
@@ -57,9 +56,8 @@ public class TaskExecutorJobLauncherTests extends TestCase {
InterruptibleContainer container = new InterruptibleContainer();
launcher.setJobExecutorFacade(container);
- launcher.setJobName(new Job("foo").getName());
- JobExecution execution = launcher.run();
+ JobExecution execution = launcher.run(new SimpleJobIdentifier("foo"));
// give the thread some time to start up...
Thread.sleep(100);
assertTrue(launcher.isRunning());
@@ -91,9 +89,8 @@ public class TaskExecutorJobLauncherTests extends TestCase {
InterruptibleContainer container = new InterruptibleContainer();
launcher.setJobExecutorFacade(container);
- launcher.setJobName("foo");
- JobExecution execution = launcher.run();
+ JobExecution execution = launcher.run(new SimpleJobIdentifier("foo"));
// give the thread some time to start up...
Thread.sleep(100);
// The launcher thinks it has started the job...
@@ -117,14 +114,13 @@ public class TaskExecutorJobLauncherTests extends TestCase {
InterruptibleContainer container = new InterruptibleContainer();
launcher.setJobExecutorFacade(container);
- launcher.setJobName(new Job("foo").getName());
- launcher.run();
+ launcher.run(new SimpleJobIdentifier("foo"));
// give the thread some time to start up:
Thread.sleep(100);
assertTrue(launcher.isRunning());
try {
- launcher.run();
+ launcher.run(new SimpleJobIdentifier("foo"));
fail("Expected JobExecutionAlreadyRunningException");
} catch (JobExecutionAlreadyRunningException e) {
// expected
@@ -137,12 +133,6 @@ public class TaskExecutorJobLauncherTests extends TestCase {
assertFalse(launcher.isRunning());
}
- public void testNormalApplicationEventNotRecognized() throws Exception {
- launcher.onApplicationEvent(new ApplicationEvent("foo") {
- });
- // nothing happens
- }
-
public void testStatisticsRetrieved() throws Exception {
MockControl control = MockControl
.createControl(JobExecutorFacadeWithStatistics.class);
diff --git a/spring-batch-execution/src/test/resources/org/springframework/batch/execution/repository/dao/destroy.sql b/spring-batch-execution/src/test/resources/org/springframework/batch/execution/repository/dao/destroy.sql
index e26536405..704b88390 100644
--- a/spring-batch-execution/src/test/resources/org/springframework/batch/execution/repository/dao/destroy.sql
+++ b/spring-batch-execution/src/test/resources/org/springframework/batch/execution/repository/dao/destroy.sql
@@ -3,6 +3,7 @@ DROP TABLE BATCH_STEP_EXECUTION IF EXISTS;
DROP TABLE BATCH_JOB_EXECUTION IF EXISTS;
DROP TABLE BATCH_STEP_INSTANCE IF EXISTS;
DROP TABLE BATCH_JOB_INSTANCE IF EXISTS;
+DROP TABLE BATCH_JOB_INSTANCE_PROPERTIES IF EXISTS;
DROP TABLE BATCH_STEP_EXECUTION_SEQ IF EXISTS;
DROP TABLE BATCH_STEP_SEQ IF EXISTS;
diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/mapping/FieldSet.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/mapping/FieldSet.java
index 0e981ee38..df35b523a 100644
--- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/mapping/FieldSet.java
+++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/io/file/mapping/FieldSet.java
@@ -1,80 +1,363 @@
+/*
+ * Copyright 2006-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
package org.springframework.batch.io.file.mapping;
import java.math.BigDecimal;
+import java.sql.ResultSet;
import java.util.Date;
import java.util.Properties;
+/**
+ * Interface used by flat file input sources to encapsulate concerns of
+ * converting an array of Strings to Java native types. A bit like the role
+ * played by {@link ResultSet} in JDBC, clients will know the name or position
+ * of strongly typed fields that they want to extract.
+ *
+ * @author Dave Syer
+ *
+ */
public interface FieldSet {
- public String[] getNames();
+ /**
+ * Accessor for the names of the fields.
+ *
+ * @return the names
+ *
+ * @throws IllegalStateException if the names are not defined
+ */
+ String[] getNames();
- public String[] getValues();
-
- public String readString(int index);
-
- public String readString(String name);
-
- public boolean readBoolean(int index);
-
- public boolean readBoolean(String name);
-
- public boolean readBoolean(int index, String trueValue);
-
- public boolean readBoolean(String name, String trueValue);
-
- public char readChar(int index);
-
- public char readChar(String name);
-
- public byte readByte(int index);
-
- public byte readByte(String name);
-
- public short readShort(int index);
-
- public short readShort(String name);
-
- public int readInt(int index);
-
- public int readInt(String name);
-
- public int readInt(int index, int defaultValue);
-
- public int readInt(String name, int defaultValue);
-
- public long readLong(int index);
-
- public long readLong(String name);
-
- public long readLong(int index, long defaultValue);
-
- public long readLong(String name, long defaultValue);
-
- public float readFloat(int index);
-
- public float readFloat(String name);
-
- public double readDouble(int index);
-
- public double readDouble(String name);
-
- public BigDecimal readBigDecimal(int index);
-
- public BigDecimal readBigDecimal(String name);
-
- public BigDecimal readBigDecimal(int index, BigDecimal defaultValue);
-
- public BigDecimal readBigDecimal(String name, BigDecimal defaultValue);
-
- public Date readDate(int index);
-
- public Date readDate(String name);
-
- public Date readDate(int index, String pattern);
-
- public Date readDate(String name, String pattern);
-
- public int getFieldCount();
+ /**
+ * @return fields wrapped by this 'FieldSet' instance as
+ * String values.
+ */
+ String[] getValues();
- public Properties getProperties();
-}
+ /**
+ * Read the {@link String} value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ String readString(int index);
+
+ /**
+ * Read the {@link String} value from column with given 'name'.
+ *
+ * @param name the field name.
+ */
+ String readString(String name);
+
+ /**
+ * Read the 'boolean' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ boolean readBoolean(int index);
+
+ /**
+ * Read the 'boolean' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ boolean readBoolean(String name);
+
+ /**
+ * Read the 'boolean' value at index 'index'.
+ *
+ * @param index the field index.
+ * @param trueValue the value that signifies {@link Boolean#TRUE true};
+ * case-sensitive.
+ * @throws IndexOutOfBoundsException if the index is out of bounds, or if
+ * the supplied trueValue is null.
+ */
+ boolean readBoolean(int index, String trueValue);
+
+ /**
+ * Read the 'boolean' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @param trueValue the value that signifies {@link Boolean#TRUE true};
+ * case-sensitive.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined, or if the supplied trueValue is null.
+ */
+ boolean readBoolean(String name, String trueValue);
+
+ /**
+ * Read the 'char' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ char readChar(int index);
+
+ /**
+ * Read the 'char' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ char readChar(String name);
+
+ /**
+ * Read the 'byte' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ byte readByte(int index);
+
+ /**
+ * Read the 'byte' value from column with given 'name'.
+ *
+ * @param name the field name.
+ */
+ byte readByte(String name);
+
+ /**
+ * Read the 'short' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ short readShort(int index);
+
+ /**
+ * Read the 'short' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ short readShort(String name);
+
+ /**
+ * Read the 'int' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ int readInt(int index);
+
+ /**
+ * Read the 'int' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ int readInt(String name);
+
+ /**
+ * Read the 'int' value at index 'index',
+ * using the supplied defaultValue if the field value is
+ * blank.
+ *
+ * @param index the field index..
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ int readInt(int index, int defaultValue);
+
+ /**
+ * Read the 'int' value from column with given 'name',
+ * using the supplied defaultValue if the field value is
+ * blank.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ int readInt(String name, int defaultValue);
+
+ /**
+ * Read the 'long' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ long readLong(int index);
+
+ /**
+ * Read the 'long' value from column with given 'name'.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ long readLong(String name);
+
+ /**
+ * Read the 'long' value at index 'index',
+ * using the supplied defaultValue if the field value is
+ * blank.
+ *
+ * @param index the field index..
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ long readLong(int index, long defaultValue);
+
+ /**
+ * Read the 'long' value from column with given 'name',
+ * using the supplied defaultValue if the field value is
+ * blank.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ long readLong(String name, long defaultValue);
+
+ /**
+ * Read the 'float' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ float readFloat(int index);
+
+ /**
+ * Read the 'float' value from column with given 'name.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ float readFloat(String name);
+
+ /**
+ * Read the 'double' value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ double readDouble(int index);
+
+ /**
+ * Read the 'double' value from column with given 'name.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ double readDouble(String name);
+
+ /**
+ * Read the {@link java.math.BigDecimal} value at index 'index'.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ BigDecimal readBigDecimal(int index);
+
+ /**
+ * Read the {@link java.math.BigDecimal} value from column with given 'name.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ BigDecimal readBigDecimal(String name);
+
+ /**
+ * Read the {@link BigDecimal} value at index 'index',
+ * returning the supplied defaultValue if the trimmed string
+ * value at index 'index' is blank.
+ *
+ * @param index the field index.
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ */
+ BigDecimal readBigDecimal(int index, BigDecimal defaultValue);
+
+ /**
+ * Read the {@link BigDecimal} value from column with given 'name,
+ * returning the supplied defaultValue if the trimmed string
+ * value at index 'index' is blank.
+ *
+ * @param name the field name.
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ */
+ BigDecimal readBigDecimal(String name, BigDecimal defaultValue);
+
+ /**
+ * Read the java.util.Date value in default format at
+ * designated column index.
+ *
+ * @param index the field index.
+ * @param pattern the pattern describing the date and time format
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ * @see #DEFAULT_DATE_PATTERN
+ */
+ Date readDate(int index);
+
+ /**
+ * Read the java.sql.Date value in given format from column
+ * with given name.
+ *
+ * @param name the field name.
+ * @param pattern the pattern describing the date and time format
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined.
+ * @see #DEFAULT_DATE_PATTERN
+ */
+ Date readDate(String name);
+
+ /**
+ * Read the java.util.Date value in default format at
+ * designated column index.
+ *
+ * @param index the field index.
+ * @param pattern the pattern describing the date and time format
+ * @throws IndexOutOfBoundsException if the index is out of bounds.
+ * @throws IllegalArgumentException if the date cannot be parsed.
+ *
+ */
+ Date readDate(int index, String pattern);
+
+ /**
+ * Read the java.sql.Date value in given format from column
+ * with given name.
+ *
+ * @param name the field name.
+ * @param pattern the pattern describing the date and time format
+ * @throws IllegalArgumentException if a column with given name is not
+ * defined or if the specified field cannot be parsed
+ *
+ */
+ Date readDate(String name, String pattern);
+
+ /**
+ * Return the number of fields in this 'FieldSet'.
+ */
+ int getFieldCount();
+
+ /**
+ * Construct name-value pairs from the field names and string values. Null
+ * values are omitted.
+ *
+ * @return some properties representing the field set.
+ *
+ * @throws IllegalStateException if the field name meta data is not
+ * available.
+ */
+ Properties getProperties();
+
+}
\ No newline at end of file
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/OrderItemReader.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/OrderItemReader.java
index abc2c417a..fc8dfa9da 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/OrderItemReader.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/item/reader/OrderItemReader.java
@@ -22,8 +22,8 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.domain.Step;
import org.springframework.batch.core.domain.StepExecution;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.reader.AbstractItemReader;
import org.springframework.batch.item.validator.Validator;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/AddressFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/AddressFieldSetMapper.java
index 2c3d8e7d9..d2c06b7d4 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/AddressFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/AddressFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.Address;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/BillingFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/BillingFieldSetMapper.java
index 87c4da93f..c546f3bbf 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/BillingFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/BillingFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.BillingInfo;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/CustomerFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/CustomerFieldSetMapper.java
index 6e174c308..43e9b5f49 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/CustomerFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/CustomerFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.Customer;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/GameMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/GameMapper.java
index 568fa7616..1776ebadd 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/GameMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/GameMapper.java
@@ -1,7 +1,7 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.Game;
public class GameMapper implements FieldSetMapper {
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/HeaderFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/HeaderFieldSetMapper.java
index 6bb809440..e8e501023 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/HeaderFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/HeaderFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.Order;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/OrderItemFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/OrderItemFieldSetMapper.java
index 794c7677a..a41c1921b 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/OrderItemFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/OrderItemFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.LineItem;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/PlayerMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/PlayerMapper.java
index 5bf65ffa0..0ea87f454 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/PlayerMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/PlayerMapper.java
@@ -1,7 +1,7 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.Player;
public class PlayerMapper implements FieldSetMapper {
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/ShippingFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/ShippingFieldSetMapper.java
index 59c06a898..fa1083135 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/ShippingFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/ShippingFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.sample.domain.ShippingInfo;
diff --git a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/TradeFieldSetMapper.java b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/TradeFieldSetMapper.java
index 7cee9fe6a..0c90f7f35 100644
--- a/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/TradeFieldSetMapper.java
+++ b/spring-batch-samples/src/main/java/org/springframework/batch/sample/mapping/TradeFieldSetMapper.java
@@ -16,8 +16,8 @@
package org.springframework.batch.sample.mapping;
-import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.io.file.mapping.FieldSetMapper;
+import org.springframework.batch.io.file.mapping.FieldSet;
import org.springframework.batch.item.reader.AggregateItemReader;
import org.springframework.batch.sample.domain.Trade;
diff --git a/spring-batch-samples/src/main/resources/business-schema-mysql.sql b/spring-batch-samples/src/main/resources/business-schema-mysql.sql
new file mode 100644
index 000000000..dcac1a46a
--- /dev/null
+++ b/spring-batch-samples/src/main/resources/business-schema-mysql.sql
@@ -0,0 +1,89 @@
+-- Autogenerated: do not edit this file
+DROP TABLE IF EXISTS BATCH_STAGING_SEQ ;
+DROP TABLE IF EXISTS TRADE_SEQ ;
+DROP TABLE IF EXISTS CUSTOMER_SEQ ;
+DROP TABLE IF EXISTS BATCH_STAGING ;
+DROP TABLE IF EXISTS TRADE ;
+DROP TABLE IF EXISTS CUSTOMER ;
+DROP TABLE IF EXISTS PLAYERS ;
+DROP TABLE IF EXISTS GAMES ;
+DROP TABLE IF EXISTS PLAYER_SUMMARY ;
+
+-- Autogenerated: do not edit this file
+
+CREATE TABLE CUSTOMER_SEQ (ID BIGINT NOT NULL) type=MYISAM;
+INSERT INTO CUSTOMER_SEQ values(0);
+CREATE TABLE BATCH_STAGING_SEQ (ID BIGINT NOT NULL) type=MYISAM;
+INSERT INTO BATCH_STAGING_SEQ values(0);
+CREATE TABLE TRADE_SEQ (ID BIGINT NOT NULL) type=MYISAM;
+INSERT INTO TRADE_SEQ values(0);
+
+CREATE TABLE BATCH_STAGING (
+ ID BIGINT unsigned PRIMARY KEY ,
+ JOB_ID BIGINT NOT NULL,
+ VALUE ${BLOB} NOT NULL,
+ PROCESSED CHAR(1) NOT NULL
+);
+
+CREATE TABLE TRADE (
+ ID BIGINT unsigned PRIMARY KEY ,
+ VERSION BIGINT,
+ ISIN VARCHAR(45) NOT NULL,
+ QUANTITY BIGINT,
+ PRICE FLOAT,
+ CUSTOMER VARCHAR(45)
+);
+
+CREATE TABLE CUSTOMER (
+ ID BIGINT unsigned PRIMARY KEY ,
+ VERSION BIGINT,
+ NAME VARCHAR(45),
+ CREDIT FLOAT
+);
+
+INSERT INTO customer (id, version, name, credit) VALUES (1, 0, 'customer1', 100000);
+INSERT INTO customer (id, version, name, credit) VALUES (2, 0, 'customer2', 100000);
+INSERT INTO customer (id, version, name, credit) VALUES (3, 0, 'customer3', 100000);
+INSERT INTO customer (id, version, name, credit) VALUES (4, 0, 'customer4', 100000);
+
+CREATE TABLE PLAYERS (
+ PLAYER_ID char(8) NOT NULL PRIMARY KEY,
+ LAST_NAME varchar(35) not null,
+ FIRST_NAME varchar(25) not null,
+ POS varchar(10),
+ YEAR_OF_BIRTH BIGINT not null,
+ YEAR_DRAFTED BIGINT not null
+);
+
+CREATE TABLE GAMES (
+ PLAYER_ID char(8) not null,
+ YEAR_NO BIGINT not null,
+ TEAM char(3) not null,
+ WEEK BIGINT not null,
+ OPPONENT char(3),
+ COMPLETES BIGINT,
+ ATTEMPTS BIGINT,
+ PASSING_YARDS BIGINT,
+ PASSING_TD BIGINT,
+ INTERCEPTIONS BIGINT,
+ RUSHES BIGINT,
+ RUSH_YARDS BIGINT,
+ RECEPTIONS BIGINT,
+ RECEPTIONS_YARDS BIGINT,
+ TOTAL_TD BIGINT
+);
+
+CREATE TABLE PLAYER_SUMMARY (
+ ID CHAR(8) NOT NULL,
+ YEAR_NO BIGINT NOT NULL,
+ COMPLETES BIGINT NOT NULL ,
+ ATTEMPTS BIGINT NOT NULL ,
+ PASSING_YARDS BIGINT NOT NULL ,
+ PASSING_TD BIGINT NOT NULL ,
+ INTERCEPTIONS BIGINT NOT NULL ,
+ RUSHES BIGINT NOT NULL ,
+ RUSH_YARDS BIGINT NOT NULL ,
+ RECEPTIONS BIGINT NOT NULL ,
+ RECEPTIONS_YARDS BIGINT NOT NULL ,
+ TOTAL_TD BIGINT NOT NULL
+);
\ No newline at end of file
diff --git a/spring-batch-samples/src/main/resources/jobs/adhocLoopJob.xml b/spring-batch-samples/src/main/resources/jobs/adhocLoopJob.xml
index 1b32f0328..9522b1da3 100644
--- a/spring-batch-samples/src/main/resources/jobs/adhocLoopJob.xml
+++ b/spring-batch-samples/src/main/resources/jobs/adhocLoopJob.xml
@@ -138,8 +138,6 @@
-
-