diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/CommandLineJobRunner.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/CommandLineJobRunner.java deleted file mode 100644 index a0cdde6ea..000000000 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/CommandLineJobRunner.java +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright 2006-2008 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.execution.bootstrap.support; - -import java.util.Properties; - -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.JobExecution; -import org.springframework.batch.core.domain.JobLocator; -import org.springframework.batch.core.domain.JobParameters; -import org.springframework.batch.core.executor.ExitCodeExceptionClassifier; -import org.springframework.batch.core.runtime.JobParametersFactory; -import org.springframework.batch.execution.launch.JobLauncher; -import org.springframework.batch.execution.step.simple.SimpleExitCodeExceptionClassifier; -import org.springframework.beans.factory.BeanDefinitionStoreException; -import org.springframework.beans.factory.config.AutowireCapableBeanFactory; -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.util.StringUtils; - -/** - *

- * Basic launcher for starting jobs from the command line. In general, it is - * assumed that this launcher will primarily be used to start a job via a script - * from an Enterprise Scheduler. Therefore, exit codes are mapped to integers so - * that schedulers can use the returned values to determine the next course of - * action. The returned values can also be useful to operations teams in - * determining what should happen upon failure. For example, a returned code of - * 5 might mean that some resource wasn't available and the job should be - * restarted. However, a code of 10 might mean that something critical has - * happened and the issue should be escalated. - *

- * - *

- * With any launch of a batch job within Spring Batch, a Spring context - * containing the Job and the 'Execution Environment' has to be created. This - * command line launcher can be used to load that context from a single - * location. It can also load the job as well All 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 - * {@link JobLauncher} and {@link JobLocator}. 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. - *

- * - *

- * Notice a property is available to set the {@link SystemExiter}. This class - * is used to exit from the main method, rather than calling System.exit() - * directly. This is because unit testing a class the calls System.exit() is - * impossible without kicking off the test within a new Jvm, which it is - * possible to do, however it is a complex solution, much more so than - * strategizing the exiter. - *

- * - *

- * The arguments to this class are roughly as follows: - *

- * - * - * java jobPath jobName jobLauncherPath jobParameters... - * - * - *

- *

- *

- * - *

- * The combined application context must only contain one instance of a - * {@link JobLauncher}. The job parameters passed in to the command line will - * be converted to {@link Properties} by assuming that each individual element - * is one parameter that is separated by an equals sign. For example, - * "vendor.id=290232". Below is an example arguments list: " - * - *

- * - * java org.springframework.batch.execution.bootstrap.support.CommandLineJobRunner testJob.xml - * testJob standard-job-launcher.xml schedule.date=2008/01/24 vendor.id=3902483920 - *

- * - *

Once arguments have been successfully parsed, autowiring will be used to set - * various dependencies. The {@JobLauncher} for example, will be loaded this way. If - * none is contained in the bean factory (it searches by type) then a - * {@link BeanDefinitionStoreException} will be thrown. The same exception will also - * be thrown if there is more than one present. Assuming the JobLauncher has been - * set correctly, the jobName argument will be used to obtain an actual {@link Job}. - * If a {@link JobLocator} has been set, then it will be used, if not the beanFactory - * will be asked, using the jobName as the bean id.

- * - * @author Dave Syer - * @author Lucas Ward - * @since 1.0 - */ -public class CommandLineJobRunner { - - protected static final Log logger = LogFactory - .getLog(CommandLineJobRunner.class); - - private ExitCodeMapper exitCodeMapper = new SimpleJvmExitCodeMapper(); - - private ExitCodeExceptionClassifier exceptionClassifier = new SimpleExitCodeExceptionClassifier(); - - private JobLauncher launcher; - - private JobLocator jobLocator; - - private SystemExiter systemExiter = new JvmSystemExiter(); - - private JobParametersFactory jobParametersFactory = new DefaultJobParametersFactory(); - - /** - * Injection setter for the {@link JobLauncher}. - * - * @param launcher - * the launcher to set - */ - public void setLauncher(JobLauncher launcher) { - this.launcher = launcher; - } - - /** - * Injection setter for the {@link ExitCodeExceptionClassifier} - * - * @param exceptionClassifier - */ - public void setExceptionClassifier( - ExitCodeExceptionClassifier exceptionClassifier) { - this.exceptionClassifier = exceptionClassifier; - } - - /** - * Injection setter for the {@link JvmExitCodeMapper}. - * - * @param exitCodeMapper - * the exitCodeMapper to set - */ - public void setExitCodeMapper(ExitCodeMapper exitCodeMapper) { - this.exitCodeMapper = exitCodeMapper; - } - - /** - * Injection setter for the {@link SystemExiter}. - * - * @param systemExitor - */ - public void setSystemExiter(SystemExiter systemExitor) { - this.systemExiter = systemExitor; - } - - /** - * Delegate to the exiter to (possibly) exit the VM gracefully. - * - * @param status - */ - public void exit(int status) { - systemExiter.exit(status); - } - - public void setJobLocator(JobLocator jobLocator) { - this.jobLocator = jobLocator; - } - - /* - * Start a job by obtaining a combined classpath using the job launcher and - * job paths. If a JobLocator has been set, then use it to obtain an actual - * job, if not ask the context for it. - */ - int start(String jobPath, String jobLauncherPath, String jobName, - String[] parameters) { - - try { - ApplicationContext context = new ClassPathXmlApplicationContext( - new String[] { jobPath, jobLauncherPath }); - context.getAutowireCapableBeanFactory().autowireBeanProperties( - this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); - - Job job; - if (jobLocator != null) { - job = jobLocator.getJob(jobName); - } else { - job = (Job) context.getBean(jobName); - } - - JobParameters jobParameters = jobParametersFactory - .getJobParameters(StringUtils - .splitArrayElementsIntoProperties(parameters, "=")); - - JobExecution jobExecution = launcher.run(job, jobParameters); - return exitCodeMapper.getExitCode(jobExecution.getExitStatus() - .getExitCode()); - } catch (Throwable e) { - logger.error("Job Terminated in error:", e); - return exitCodeMapper.getExitCode(exceptionClassifier - .classifyForExitCode(e).getExitCode()); - } - } - - /** - * Launch a batch job using a {@link CommandLineJobRunner}. Creates a - * new Spring context for the job execution, and uses a common parent for - * all such contexts. No exception are thrown from this method, rather - * exceptions are logged and an integer returned through the exit status in - * a {@link JvmSystemExiter} (which can be overridden by defining one in the - * Spring context). - * - * @param args - *

- *

- *

- */ - public static void main(String[] args) { - - CommandLineJobRunner command = new CommandLineJobRunner(); - - if (args.length < 3) { - logger - .error("At least 3 arguments are required: JobPath, JobName, and ExecutionPath."); - command.exit(1); - } - - String jobPath = args[0]; - String jobName = args[1]; - String jobLauncherPath = args[2]; - String[] parameters = new String[args.length - 3]; - System.arraycopy(args, 2, parameters, 0, args.length - 3); - - int result = command.start(jobPath, jobLauncherPath, jobName, - parameters); - command.exit(result); - } - -} diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java index 6b76919cd..c866803ef 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/DefaultJobParametersFactory.java @@ -29,7 +29,6 @@ import java.util.Map.Entry; import org.springframework.batch.core.domain.JobParameters; import org.springframework.batch.core.domain.JobParametersBuilder; import org.springframework.batch.core.runtime.JobParametersFactory; -import org.springframework.util.Assert; import org.springframework.util.StringUtils; /** diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java index 04748ac17..4711ae0f5 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/bootstrap/support/ScheduledJobParametersFactory.java @@ -27,7 +27,6 @@ import java.util.Map.Entry; import org.springframework.batch.core.domain.JobParameters; import org.springframework.batch.core.domain.JobParametersBuilder; import org.springframework.batch.core.runtime.JobParametersFactory; -import org.springframework.util.Assert; /** * @author Lucas Ward diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/SimpleStepContext.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/SimpleStepContext.java index b476f839d..ba8b4b16e 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/SimpleStepContext.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/SimpleStepContext.java @@ -21,10 +21,13 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Properties; import java.util.Set; import org.springframework.batch.core.domain.StepExecution; import org.springframework.batch.repeat.context.SynchronizedAttributeAccessor; +import org.springframework.batch.statistics.StatisticsProvider; +import org.springframework.batch.statistics.StatisticsService; /** * Simple implementation of {@link StepContext}. @@ -33,25 +36,55 @@ import org.springframework.batch.repeat.context.SynchronizedAttributeAccessor; * */ public class SimpleStepContext extends SynchronizedAttributeAccessor implements - StepContext { + StepContext, StatisticsProvider { private Map callbacks = new HashMap(); private StepContext parent; private StepExecution stepExecution; + private StatisticsService statisticsService; /** * Default constructor. */ - public SimpleStepContext() { - this(null); + public SimpleStepContext(StepExecution stepExecution) { + this(stepExecution, null, null); + } + + /** + * Default constructor. + */ + public SimpleStepContext(StepExecution stepExecution, StepContext parent) { + this(stepExecution, parent, null); } /** * @param object */ - public SimpleStepContext(StepContext parent) { + public SimpleStepContext(StepExecution stepExecution, StepContext parent, StatisticsService statisticsService) { super(); this.parent = parent; + this.statisticsService = statisticsService; + this.stepExecution = stepExecution; + } + + /* (non-Javadoc) + * @see org.springframework.batch.repeat.context.SynchronizedAttributeAccessor#setAttribute(java.lang.String, java.lang.Object) + */ + public void setAttribute(String name, Object value) { + super.setAttribute(name, value); + if (statisticsService!=null && (value instanceof StatisticsProvider)) { + statisticsService.register(this, (StatisticsProvider) value); + } + } + + /* (non-Javadoc) + * @see org.springframework.batch.statistics.StatisticsProvider#getStatistics() + */ + public Properties getStatistics() { + if (statisticsService==null) { + return new Properties(); + } + return statisticsService.getStatistics(this); } /* @@ -86,10 +119,10 @@ public class SimpleStepContext extends SynchronizedAttributeAccessor implements } } - /* - * Package access because only needed internally. + /* (non-Javadoc) + * @see org.springframework.batch.execution.scope.StepContext#close() */ - void close() { + public void close() { List errors = new ArrayList(); @@ -133,13 +166,6 @@ public class SimpleStepContext extends SynchronizedAttributeAccessor implements throw (RuntimeException) errors.get(0); } - /** - * @param stepExecution - */ - public void setStepExecution(StepExecution stepExecution) { - this.stepExecution = stepExecution; - } - /* * (non-Javadoc) * diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepContext.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepContext.java index 61cafb629..0df4f248f 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepContext.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepContext.java @@ -16,6 +16,7 @@ package org.springframework.batch.execution.scope; import org.springframework.batch.core.domain.StepExecution; +import org.springframework.batch.statistics.StatisticsProvider; import org.springframework.core.AttributeAccessor; /** @@ -24,7 +25,7 @@ import org.springframework.core.AttributeAccessor; * @author Dave Syer * */ -public interface StepContext extends AttributeAccessor { +public interface StepContext extends AttributeAccessor, StatisticsProvider { /** * Accessor for the {@link StepExecution} associated with the currently @@ -45,4 +46,9 @@ public interface StepContext extends AttributeAccessor { * Register a destruction callback for the end of life of the scope. */ void registerDestructionCallback(String name, Runnable callback); + + /** + * Clean up any resources held during the context of the step. + */ + void close(); } \ No newline at end of file diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepScope.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepScope.java index 75781f063..69cb6d976 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepScope.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepScope.java @@ -36,10 +36,17 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { private Object mutex = new Object(); + /** + * @param order the order value to set priority of callback execution for + * the {@link BeanFactoryPostProcessor} part of this scope bean. + */ public void setOrder(int order) { this.order = order; } + /* (non-Javadoc) + * @see org.springframework.core.Ordered#getOrder() + */ public int getOrder() { return order; } @@ -48,16 +55,17 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * Context key for clients to use for conversation identifier. */ public static final String ID_KEY = "JOB_IDENTIFIER"; + private String name = "step"; /* * (non-Javadoc) * * @see org.springframework.beans.factory.config.Scope#get(java.lang.String, - * org.springframework.beans.factory.ObjectFactory) + * org.springframework.beans.factory.ObjectFactory) */ public Object get(String name, ObjectFactory objectFactory) { - SimpleStepContext context = getContext(); + StepContext context = getContext(); Object scopedObject = context.getAttribute(name); if (scopedObject == null) { synchronized (mutex) { @@ -80,7 +88,7 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * @see org.springframework.beans.factory.config.Scope#getConversationId() */ public String getConversationId() { - SimpleStepContext context = getContext(); + StepContext context = getContext(); Object id = context.getAttribute(ID_KEY); return "" + id; } @@ -89,7 +97,7 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * (non-Javadoc) * * @see org.springframework.beans.factory.config.Scope#registerDestructionCallback(java.lang.String, - * java.lang.Runnable) + * java.lang.Runnable) */ public void registerDestructionCallback(String name, Runnable callback) { StepContext context = getContext(); @@ -102,7 +110,7 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * @see org.springframework.beans.factory.config.Scope#remove(java.lang.String) */ public Object remove(String name) { - SimpleStepContext context = getContext(); + StepContext context = getContext(); return context.removeAttribute(name); } @@ -111,13 +119,12 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * can be used to store scoped bean instances. * * @return the current step context which we can use as a scope storage - * medium + * medium */ - private SimpleStepContext getContext() { - SimpleStepContext context = StepSynchronizationManager.getContext(); + private StepContext getContext() { + StepContext context = StepSynchronizationManager.getContext(); if (context == null) { - throw new IllegalStateException( - "No context holder available for step scope"); + throw new IllegalStateException("No context holder available for step scope"); } return context; } @@ -125,13 +132,10 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { /** * Register this scope with the enclosing BeanFactory. * - * @param beanFactory - * the BeanFactory to register with - * @throws BeansException - * if there is a problem. + * @param beanFactory the BeanFactory to register with + * @throws BeansException if there is a problem. */ - public void postProcessBeanFactory( - ConfigurableListableBeanFactory beanFactory) throws BeansException { + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { beanFactory.registerScope(name, this); } @@ -139,8 +143,7 @@ public class StepScope implements Scope, BeanFactoryPostProcessor, Ordered { * Public setter for the name property. This can then be used as a bean * definition attribute, e.g. scope="step". Defaults to "step". * - * @param name - * the name to set for this scope. + * @param name the name to set for this scope. */ public void setName(String name) { this.name = name; diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepSynchronizationManager.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepSynchronizationManager.java deleted file mode 100644 index b7b53380f..000000000 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/scope/StepSynchronizationManager.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.execution.scope; - -/** - * @author Dave Syer - * - */ -public class StepSynchronizationManager { - - private static final ThreadLocal contextHolder = new InheritableThreadLocal(); - - /** - * Getter for the current context.. - * - * @return the current {@link SimpleStepContext} or null if there is none - * (if we are not in a step). - */ - public static SimpleStepContext getContext() { - return (SimpleStepContext) contextHolder.get(); - } - - /** - * Method for registering a context - should only be used by - * {@link StepExecutor} implementations to ensure that {@link #getContext()} - * always returns the correct value. - * - * @return a new context at the start of a batch. - */ - public static SimpleStepContext open() { - StepContext oldSession = getContext(); - SimpleStepContext context = new SimpleStepContext(oldSession); - StepSynchronizationManager.contextHolder.set(context); - return context; - } - - /** - * Method for de-registering the current context - should only be used by - * {@link StepExecutor} implementations to ensure that {@link #getContext()} - * always returns the correct value. - * - * @return the old value if there was one. - */ - public static StepContext close() { - SimpleStepContext oldSession = getContext(); - if (oldSession == null) { - return null; - } - oldSession.close(); - StepContext context = oldSession.getParent(); - StepSynchronizationManager.contextHolder.set(context); - return context; - } - - /** - * Used internally by {@link StepExecutor} implementations to clear the - * current context at the end of a batch. - * - * @return the old value if there was one. - */ - public static StepContext clear() { - StepContext context = getContext(); - StepSynchronizationManager.contextHolder.set(null); - return context; - } - -} diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java index 3c3252b0e..6b17c3751 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/simple/SimpleStepExecutor.java @@ -30,6 +30,7 @@ import org.springframework.batch.core.executor.StepInterruptedException; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.tasklet.Tasklet; import org.springframework.batch.execution.scope.SimpleStepContext; +import org.springframework.batch.execution.scope.StepContext; import org.springframework.batch.execution.scope.StepScope; import org.springframework.batch.execution.scope.StepSynchronizationManager; import org.springframework.batch.execution.step.RepeatOperationsHolder; @@ -47,7 +48,9 @@ import org.springframework.batch.repeat.support.RepeatTemplate; import org.springframework.batch.repeat.synch.BatchTransactionSynchronizationManager; import org.springframework.batch.restart.RestartData; import org.springframework.batch.restart.Restartable; +import org.springframework.batch.statistics.SimpleStatisticsService; import org.springframework.batch.statistics.StatisticsProvider; +import org.springframework.batch.statistics.StatisticsService; import org.springframework.batch.support.transaction.ResourcelessTransactionManager; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionStatus; @@ -91,6 +94,26 @@ public class SimpleStepExecutor implements StepExecutor { // Not for production use... protected PlatformTransactionManager transactionManager = new ResourcelessTransactionManager(); + private StatisticsService statisticsService = new SimpleStatisticsService(); + + /** + * Public setter for the {@link StatisticsService}. This will be used to + * create the {@link StepContext}, and hence any component that is a + * {@link StatisticsProvider} and in step scope will be registered with the + * service. The {@link StepContext} is then a source of aggregate statistics + * for the step. + * + * @param statisticsService the {@link StatisticsService} to set. Default is + * a {@link SimpleStatisticsService}. + */ + public void setStatisticsService(StatisticsService statisticsService) { + this.statisticsService = statisticsService; + } + + /** + * Injected strategy for transaction management + * @param transactionManager + */ public void setTransactionManager(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } @@ -142,8 +165,8 @@ public class SimpleStepExecutor implements StepExecutor { * execution * @see StepExecutor#process(Step, StepExecution) */ - public ExitStatus process(final Step step, final StepExecution stepExecution) - throws BatchCriticalException, StepInterruptedException { + public ExitStatus process(final Step step, final StepExecution stepExecution) throws BatchCriticalException, + StepInterruptedException { final StepInstance stepInstance = stepExecution.getStep(); boolean isRestart = stepInstance.getStepExecutionCount() > 0 ? true : false; @@ -153,8 +176,10 @@ public class SimpleStepExecutor implements StepExecutor { ExitStatus status = ExitStatus.FAILED; - final SimpleStepContext stepScopeContext = StepSynchronizationManager.open(); - stepScopeContext.setStepExecution(stepExecution); + StepContext parentStepScopeContext = StepSynchronizationManager.getContext(); + final StepContext stepScopeContext = new SimpleStepContext(stepExecution, parentStepScopeContext, + statisticsService); + StepSynchronizationManager.register(stepScopeContext); // Add the job identifier so that it can be used to identify // the conversation in StepScope stepScopeContext.setAttribute(StepScope.ID_KEY, stepExecution.getJobExecution().getId()); @@ -198,8 +223,8 @@ public class SimpleStepExecutor implements StepExecutor { // TODO: Statistics are not thread safe // - we cannot guarantee that they are - // up to date. (Maybe we never can?) - Properties statistics = getStatistics(module); + // up to date. (Maybe we never can?) + Properties statistics = stepScopeContext.getStatistics(); contribution.setStatistics(statistics); contribution.incrementCommitCount(); // Apply the contribution to the step @@ -301,8 +326,8 @@ public class SimpleStepExecutor implements StepExecutor { * outside this method, so subclasses that override do not need to create a * transaction. * - * @param step the current step containing the {@link Tasklet} - * with the business logic. + * @param step the current step containing the {@link Tasklet} with the + * business logic. * @return true if there is more data to process. */ protected final ExitStatus processChunk(final Step step, final StepContribution contribution) { @@ -378,15 +403,6 @@ public class SimpleStepExecutor implements StepExecutor { } } - private Properties getStatistics(Tasklet tasklet) { - if (tasklet instanceof StatisticsProvider) { - return ((StatisticsProvider) tasklet).getStatistics(); - } - else { - return null; - } - } - /** * Setter for the {@link StepInterruptionPolicy}. The policy is used to * check whether an external request has been made to interrupt the job @@ -414,9 +430,9 @@ public class SimpleStepExecutor implements StepExecutor { *