diff --git a/pom.xml b/pom.xml index 40c5d3bb7..4495d7fc9 100644 --- a/pom.xml +++ b/pom.xml @@ -204,9 +204,9 @@ - - + + @@ -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 @@ - -