diff --git a/pom.xml b/pom.xml
index 04d208a59..f3d6ed067 100644
--- a/pom.xml
+++ b/pom.xml
@@ -289,6 +289,7 @@
samples
spring-batch-infrastructure-tests
+ spring-batch-core-tests
spring-batch-samples
archetypes
diff --git a/spring-batch-core-tests/.classpath b/spring-batch-core-tests/.classpath
new file mode 100644
index 000000000..575d9eaf5
--- /dev/null
+++ b/spring-batch-core-tests/.classpath
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-batch-core-tests/.project b/spring-batch-core-tests/.project
new file mode 100644
index 000000000..ac5013e29
--- /dev/null
+++ b/spring-batch-core-tests/.project
@@ -0,0 +1,30 @@
+
+
+ spring-batch-core-tests
+ This plugin is an archetype that creates a command line batch sample from Spring Batch. Once installed you can create the archetype project using<br/><pre>$ mvn archetype:create -DgroupId=com.mycompany -DartifactId=batch \ -DarchetypeGroupId=org.springframework.batch \ -DarchetypeArtifactId=spring-batch-cli -DarchetypeVersion=1.0-m3-SNAPSHOT</pre><br/> Then you should be able to "cd batch; mvn package exec:exec", and see the app run.
+
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ org.springframework.ide.eclipse.core.springbuilder
+
+
+
+
+ org.maven.ide.eclipse.maven2Builder
+
+
+
+
+
+ org.springframework.ide.eclipse.core.springnature
+ org.eclipse.jdt.core.javanature
+ org.maven.ide.eclipse.maven2Nature
+
+
diff --git a/spring-batch-core-tests/.settings/org.eclipse.jdt.core.prefs b/spring-batch-core-tests/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..58040bb0e
--- /dev/null
+++ b/spring-batch-core-tests/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,12 @@
+#Wed Jul 16 12:19:00 CEST 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.5
diff --git a/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.beans.core.prefs b/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.beans.core.prefs
new file mode 100644
index 000000000..9430d30f6
--- /dev/null
+++ b/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.beans.core.prefs
@@ -0,0 +1,3 @@
+#Wed Apr 15 09:55:29 BST 2009
+eclipse.preferences.version=1
+org.springframework.ide.eclipse.beans.core.ignoreMissingNamespaceHandler=false
diff --git a/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.core.prefs b/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.core.prefs
new file mode 100644
index 000000000..ddf8310c9
--- /dev/null
+++ b/spring-batch-core-tests/.settings/org.springframework.ide.eclipse.core.prefs
@@ -0,0 +1,82 @@
+#Wed Apr 15 09:55:29 BST 2009
+eclipse.preferences.version=1
+org.springframework.ide.eclipse.core.builders.enable.aopreferencemodelbuilder=true
+org.springframework.ide.eclipse.core.builders.enable.beanmetadatabuilder=false
+org.springframework.ide.eclipse.core.builders.enable.osgibundleupdater=true
+org.springframework.ide.eclipse.core.enable.project.preferences=false
+org.springframework.ide.eclipse.core.validator.enable.com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.bestpractices.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.com.springsource.sts.server.quickfix.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.core.springvalidator=false
+org.springframework.ide.eclipse.core.validator.enable.org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.applicationSymbolicNameRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.applicationVersionRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleActivationPolicyRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleActivatorRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleManifestVersionRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleNameRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleSymbolicNameRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.bundleVersionRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.exportPackageRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.importRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.parsingProblemsRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.platform.ide.manifest.core.requireBundleRule-com.springsource.platform.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.applicationVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivationPolicyRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleActivatorRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleManifestVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleSymbolicNameRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.bundleVersionRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.exportPackageRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.importRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.parsingProblemsRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.server.ide.manifest.core.requireBundleRule-com.springsource.server.ide.manifest.core.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.AvoidDriverManagerDataSource-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ImportElementsAtTopRulee-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.ParentBeanSpecifiesAbstractClassRule-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.RefElementRule-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.TooManyBeansInFileRule-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UnnecessaryValueElementRule-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.com.springsource.sts.bestpractices.UseBeanInheritance-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.importPackageVersionRule-com.springsource.sts.bestpractices.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.bestpractices.legacyxmlusage.jndiobjectfactory-com.springsource.sts.bestpractices.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importLibraryVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.importPackageVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.com.springsource.sts.server.quickfix.requireBundleVersionRule-com.springsource.sts.server.quickfix.manifestvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanAlias-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanClass-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanConstructorArgument-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinition-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanDefinitionHolder-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanFactory-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanInitDestroyMethod-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.beanReference-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.methodOverride-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.parsingProblems-org.springframework.ide.eclipse.beans.core.beansvalidator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.beans.core.requiredProperty-org.springframework.ide.eclipse.beans.core.beansvalidator=false
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.core.springClasspath-org.springframework.ide.eclipse.core.springvalidator=false
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.action-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.actionstate-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attribute-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.attributemapper-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.beanaction-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationaction-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.evaluationresult-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.exceptionhandler-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.import-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.inputattribute-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.mapping-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.outputattribute-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.set-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.state-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.subflowstate-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.transition-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.variable-org.springframework.ide.eclipse.webflow.core.validator=true
+org.springframework.ide.eclipse.core.validator.rule.enable.org.springframework.ide.eclipse.webflow.core.validation.webflowstate-org.springframework.ide.eclipse.webflow.core.validator=true
diff --git a/spring-batch-core-tests/.springBeans b/spring-batch-core-tests/.springBeans
new file mode 100644
index 000000000..20353ceac
--- /dev/null
+++ b/spring-batch-core-tests/.springBeans
@@ -0,0 +1,20 @@
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+ true
+ false
+
+
+
+
+
diff --git a/spring-batch-core-tests/pom.xml b/spring-batch-core-tests/pom.xml
new file mode 100644
index 000000000..d17480d94
--- /dev/null
+++ b/spring-batch-core-tests/pom.xml
@@ -0,0 +1,225 @@
+
+
+ 4.0.0
+ spring-batch-core-tests
+ jar
+ Tests for Spring Batch Core against Spring 3.0
+
+ org.springframework.batch
+ spring-batch-parent
+ 2.0.2.CI-SNAPSHOT
+
+
+ true
+ 3.0.0.BUILD-SNAPSHOT
+
+
+
+ strict
+
+ false
+
+
+
+ tiger
+
+ 1.5
+
+
+
+ stax
+ stax
+ 1.2.0
+
+
+
+
+ staging
+
+
+ staging
+ file:///${user.dir}/target/staging
+
+
+ staging
+ file:///${user.dir}/target/staging
+
+
+
+
+
+
+ junit
+ junit
+ 4.5
+ test
+
+
+ org.springframework
+ spring-test
+ ${spring.framework.version}
+ test
+
+
+ org.springframework
+ spring-expression
+ ${spring.framework.version}
+
+
+ org.springframework
+ spring-jdbc
+ ${spring.framework.version}
+
+
+ org.springframework.batch
+ spring-batch-core
+ ${pom.version}
+
+
+ org.springframework
+ spring-context
+
+
+ org.springframework
+ spring-aop
+
+
+
+
+ cglib
+ cglib-nodep
+
+
+ commons-dbcp
+ commons-dbcp
+
+
+ commons-io
+ commons-io
+
+
+ log4j
+ log4j
+
+
+ hsqldb
+ hsqldb
+
+
+ org.aspectj
+ aspectjrt
+
+
+ org.aspectj
+ aspectjweaver
+
+
+
+
+
+ org.springframework.build.aws
+ org.springframework.build.aws.maven
+ 2.0.0.RELEASE
+
+
+
+
+
+ com.springsource.bundlor
+ com.springsource.bundlor.maven
+ 1.0.0.M1B
+
+ ${project.basedir}/src/main/resources/META-INF/MANIFEST.MF
+
+
+
+ maven-assembly-plugin
+ false
+
+
+ project
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 1.5
+ 1.5
+
+
+
+ com.springsource.bundlor
+ com.springsource.bundlor.maven
+
+
+ bundlor-transform
+ package
+
+ transform
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+
+ **/*Tests.java
+
+
+ **/Abstract*.java
+
+ junit:junit
+
+
+
+ org.codehaus.mojo
+ exec-maven-plugin
+ 1.1
+
+ org.springframework.batch.core.launch.support.CommandLineJobRunner
+
+ classpath:/launch-context.xml
+ job1
+
+
+
+
+
+
+ http://www.springframework.org/download
+
+ staging
+ file:///${user.dir}/target/staging/org.springframework.batch.archetype/${pom.artifactId}
+
+
+ spring-milestone
+ Spring Milestone Repository
+ file:///${user.dir}/target/staging/milestone
+
+
+ spring-snapshot
+ Spring Snapshot Repository
+ file:///${user.dir}/target/staging/snapshot
+
+
+
+
+ spring-snapshots
+ http://s3.amazonaws.com/maven.springframework.org/snapshot
+
+ false
+
+
+ true
+
+
+
+
diff --git a/spring-batch-core-tests/src/site/site.xml b/spring-batch-core-tests/src/site/site.xml
new file mode 100644
index 000000000..4bba09c7c
--- /dev/null
+++ b/spring-batch-core-tests/src/site/site.xml
@@ -0,0 +1,25 @@
+
+
+
+
+ Spring Batch: ${project.name}
+ index.html
+
+
+
+ org.springframework.maven.skins
+ maven-spring-skin
+ 1.0.5
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/AsyncStepScopeIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/AsyncStepScopeIntegrationTests.java
new file mode 100644
index 000000000..ad2552cc2
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/AsyncStepScopeIntegrationTests.java
@@ -0,0 +1,151 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.FutureTask;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepContext;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.core.task.SimpleAsyncTaskExecutor;
+import org.springframework.core.task.TaskExecutor;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class AsyncStepScopeIntegrationTests implements BeanFactoryAware {
+
+ private Log logger = LogFactory.getLog(getClass());
+
+ @Autowired
+ @Qualifier("simple")
+ private Collaborator simple;
+
+ private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
+
+ private ListableBeanFactory beanFactory;
+
+ private int beanCount;
+
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (ListableBeanFactory) beanFactory;
+ }
+
+ @Before
+ public void countBeans() {
+ StepSynchronizationManager.release();
+ beanCount = beanFactory.getBeanDefinitionCount();
+ }
+
+ @After
+ public void cleanUp() {
+ StepSynchronizationManager.close();
+ // Check that all temporary bean definitions are cleaned up
+ assertEquals(beanCount, beanFactory.getBeanDefinitionCount());
+ }
+
+ @Test
+ public void testSimpleProperty() throws Exception {
+ StepExecution stepExecution = new StepExecution("step", new JobExecution(0L), 123L);
+ ExecutionContext executionContext = stepExecution.getExecutionContext();
+ executionContext.put("foo", "bar");
+ StepSynchronizationManager.register(stepExecution);
+ assertEquals("bar", simple.getName());
+ }
+
+ @Test
+ public void testGetMultipleInMultipleThreads() throws Exception {
+
+ List> tasks = new ArrayList>();
+
+ for (int i = 0; i < 12; i++) {
+ final String value = "foo" + i;
+ final Long id = 123L + i;
+ FutureTask task = new FutureTask(new Callable() {
+ public String call() throws Exception {
+ StepExecution stepExecution = new StepExecution(value, new JobExecution(0L), id);
+ ExecutionContext executionContext = stepExecution.getExecutionContext();
+ executionContext.put("foo", value);
+ StepContext context = StepSynchronizationManager.register(stepExecution);
+ logger.debug("Registered: " + context.getStepExecutionContext());
+ try {
+ return simple.getName();
+ }
+ finally {
+ StepSynchronizationManager.close();
+ }
+ }
+ });
+ tasks.add(task);
+ taskExecutor.execute(task);
+ }
+
+ int i = 0;
+ for (FutureTask task : tasks) {
+ assertEquals("foo" + i, task.get());
+ i++;
+ }
+
+ }
+
+ @Test
+ public void testGetSameInMultipleThreads() throws Exception {
+
+ List> tasks = new ArrayList>();
+ final StepExecution stepExecution = new StepExecution("foo", new JobExecution(0L), 123L);
+ ExecutionContext executionContext = stepExecution.getExecutionContext();
+ executionContext.put("foo", "foo");
+ StepSynchronizationManager.register(stepExecution);
+ assertEquals("foo", simple.getName());
+
+ for (int i = 0; i < 12; i++) {
+ final String value = "foo" + i;
+ FutureTask task = new FutureTask(new Callable() {
+ public String call() throws Exception {
+ ExecutionContext executionContext = stepExecution.getExecutionContext();
+ executionContext.put("foo", value);
+ StepContext context = StepSynchronizationManager.register(stepExecution);
+ logger.debug("Registered: " + context.getStepExecutionContext());
+ try {
+ return simple.getName();
+ }
+ finally {
+ StepSynchronizationManager.close();
+ }
+ }
+ });
+ tasks.add(task);
+ taskExecutor.execute(task);
+ }
+
+ int i = 0;
+ for (FutureTask task : tasks) {
+ assertEquals("foo", task.get());
+ i++;
+ }
+
+ // Don't close the outer scope until all tasks are finished. This should
+ // always be the case if using an AbstractStep
+ StepSynchronizationManager.close();
+
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/Collaborator.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/Collaborator.java
new file mode 100644
index 000000000..2bfc6759c
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/Collaborator.java
@@ -0,0 +1,9 @@
+package org.springframework.batch.core.scope;
+
+public interface Collaborator {
+
+ String getName();
+
+ Collaborator getParent();
+
+}
\ No newline at end of file
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/JobStartupRunner.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/JobStartupRunner.java
new file mode 100644
index 000000000..c02a5ed38
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/JobStartupRunner.java
@@ -0,0 +1,24 @@
+package org.springframework.batch.core.scope;
+
+import javax.annotation.PostConstruct;
+
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.StepExecution;
+
+public class JobStartupRunner {
+
+ private Step step;
+
+ public void setStep(Step step) {
+ this.step = step;
+ }
+
+ @PostConstruct
+ public void launch() throws Exception {
+ StepExecution stepExecution = new StepExecution("step", new JobExecution(1L), 0L);
+ step.execute(stepExecution);
+ // expect no errors
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/PlaceholderTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/PlaceholderTests.java
new file mode 100644
index 000000000..43bf79f4c
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/PlaceholderTests.java
@@ -0,0 +1,85 @@
+/*
+ * 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.core.scope;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+/**
+ * @author Dave Syer
+ *
+ */
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class PlaceholderTests {
+
+ @Autowired
+ private TestBean bean;
+
+ @Test
+ public void testString() throws Exception {
+ assertEquals("foo", bean.getName());
+ }
+
+ @Test
+ public void testInteger() throws Exception {
+ assertEquals(100, bean.getValue());
+ }
+
+ @Test
+ public void testStrings() throws Exception {
+ assertEquals(3, bean.getValues().length);
+ }
+
+ public static class TestBean {
+ private int value;
+
+ private String[] values;
+
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String[] getValues() {
+ return values;
+ }
+
+ public void setValues(String[] values) {
+ this.values = values;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public void setValue(int value) {
+ this.value = value;
+ }
+
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeDestructionCallbackIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeDestructionCallbackIntegrationTests.java
new file mode 100644
index 000000000..00a86b51b
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeDestructionCallbackIntegrationTests.java
@@ -0,0 +1,72 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopeDestructionCallbackIntegrationTests {
+
+ @Autowired
+ @Qualifier("proxied")
+ private Step proxied;
+
+ @Autowired
+ @Qualifier("nested")
+ private Step nested;
+
+ @Autowired
+ @Qualifier("foo")
+ private Collaborator foo;
+
+ @Before
+ @After
+ public void resetMessage() throws Exception {
+ TestDisposableCollaborator.message = "none";
+ TestAdvice.names.clear();
+ }
+
+ @Test
+ public void testDisposableScopedProxy() throws Exception {
+ assertNotNull(proxied);
+ proxied.execute(new StepExecution("step", new JobExecution(0L), 1L));
+ assertEquals("destroyed", TestDisposableCollaborator.message);
+ }
+
+ @Test
+ public void testDisposableInnerScopedProxy() throws Exception {
+ assertNotNull(nested);
+ nested.execute(new StepExecution("step", new JobExecution(0L), 1L));
+ assertEquals("destroyed", TestDisposableCollaborator.message);
+ }
+
+ @Test
+ public void testProxiedScopedProxy() throws Exception {
+ assertNotNull(nested);
+ nested.execute(new StepExecution("step", new JobExecution(0L), 1L));
+ assertEquals(4, TestAdvice.names.size());
+ assertEquals("bar", TestAdvice.names.get(0));
+ assertEquals("destroyed", TestDisposableCollaborator.message);
+ }
+
+ @Test
+ public void testProxiedNormalBean() throws Exception {
+ assertNotNull(nested);
+ String name = foo.getName();
+ assertEquals(1, TestAdvice.names.size());
+ assertEquals(name, TestAdvice.names.get(0));
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeIntegrationTests.java
new file mode 100644
index 000000000..099d668eb
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeIntegrationTests.java
@@ -0,0 +1,116 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopeIntegrationTests {
+
+ @Autowired
+ @Qualifier("vanilla")
+ private Step vanilla;
+
+ @Autowired
+ @Qualifier("proxied")
+ private Step proxied;
+
+ @Autowired
+ @Qualifier("nested")
+ private Step nested;
+
+ @Autowired
+ @Qualifier("enhanced")
+ private Step enhanced;
+
+ @Autowired
+ @Qualifier("double")
+ private Step doubleEnhanced;
+
+ @Before
+ @After
+ public void start() {
+ StepSynchronizationManager.close();
+ TestStep.reset();
+ }
+
+ @Test
+ public void testScopeCreation() throws Exception {
+ vanilla.execute(new StepExecution("foo", new JobExecution(11L), 12L));
+ assertNotNull(TestStep.getContext());
+ assertNull(StepSynchronizationManager.getContext());
+ }
+
+ @Test
+ public void testScopedProxy() throws Exception {
+ proxied.execute(new StepExecution("foo", new JobExecution(11L), 31L));
+ assertTrue(TestStep.getContext().attributeNames().length > 0);
+ String collaborator = (String) TestStep.getContext().getAttribute("collaborator");
+ assertNotNull(collaborator);
+ assertEquals("bar", collaborator);
+ assertTrue("Scoped proxy not created", ((String) TestStep.getContext().getAttribute("collaborator.class"))
+ .startsWith("class $Proxy"));
+ }
+
+ @Test
+ public void testNestedScopedProxy() throws Exception {
+ nested.execute(new StepExecution("foo", new JobExecution(11L), 31L));
+ assertTrue(TestStep.getContext().attributeNames().length > 0);
+ String collaborator = (String) TestStep.getContext().getAttribute("collaborator");
+ assertNotNull(collaborator);
+ assertEquals("foo", collaborator);
+ String parent = (String) TestStep.getContext().getAttribute("parent");
+ assertNotNull(parent);
+ assertEquals("bar", parent);
+ assertTrue("Scoped proxy not created", ((String) TestStep.getContext().getAttribute("parent.class"))
+ .startsWith("class $Proxy"));
+ }
+
+ @Test
+ public void testExecutionContext() throws Exception {
+ StepExecution stepExecution = new StepExecution("foo", new JobExecution(11L), 1L);
+ ExecutionContext executionContext = new ExecutionContext();
+ executionContext.put("name", "spam");
+ stepExecution.setExecutionContext(executionContext);
+ proxied.execute(stepExecution);
+ assertTrue(TestStep.getContext().attributeNames().length > 0);
+ String collaborator = (String) TestStep.getContext().getAttribute("collaborator");
+ assertNotNull(collaborator);
+ assertEquals("bar", collaborator);
+ }
+
+ @Test
+ public void testScopedProxyForReference() throws Exception {
+ enhanced.execute(new StepExecution("foo", new JobExecution(11L), 123L));
+ assertTrue(TestStep.getContext().attributeNames().length > 0);
+ String collaborator = (String) TestStep.getContext().getAttribute("collaborator");
+ assertNotNull(collaborator);
+ assertEquals("bar", collaborator);
+ }
+
+ @Test
+ public void testScopedProxyForSecondReference() throws Exception {
+ doubleEnhanced.execute(new StepExecution("foo", new JobExecution(11L), 321L));
+ assertTrue(TestStep.getContext().attributeNames().length > 0);
+ String collaborator = (String) TestStep.getContext().getAttribute("collaborator");
+ assertNotNull(collaborator);
+ assertEquals("bar", collaborator);
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeNestedIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeNestedIntegrationTests.java
new file mode 100644
index 000000000..66438ccb3
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeNestedIntegrationTests.java
@@ -0,0 +1,106 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.Step;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopeNestedIntegrationTests implements BeanFactoryAware {
+
+ @Autowired
+ @Qualifier("step1")
+ private Step step1;
+
+ @Autowired
+ @Qualifier("step2")
+ private Step step2;
+
+ @Autowired
+ @Qualifier("step3")
+ private Step step3;
+
+ @Autowired
+ @Qualifier("parent")
+ private Collaborator parent;
+
+ private StepExecution stepExecution;
+
+ private ConfigurableListableBeanFactory beanFactory;
+
+ private List names;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
+ }
+
+ @Before
+ public void setUp() {
+ TestStep.reset();
+ stepExecution = new StepExecution("step", new JobExecution(11L), 12L);
+ names = Arrays.asList(beanFactory.getBeanDefinitionNames());
+ }
+
+ @Test
+ public void testNestedScopedProxy() throws Exception {
+ assertNotNull(step1);
+ assertEquals("foo", parent.getName());
+ assertTrue("Proxy was not created for explicitly scoped bean", names.contains("lazyBindingProxy.bar"));
+ assertFalse("Proxy was created for unscoped bean", names.contains("foo"));
+ stepExecution.getExecutionContext().putString("bar", "bar");
+ step1.execute(stepExecution);
+ assertNotNull(stepExecution.getExecutionContext().getString("foo"));
+ assertEquals("bar", TestStep.getContext().getAttribute("collaborator"));
+ assertEquals("foo", TestStep.getContext().getAttribute("parent"));
+ }
+
+ @Test
+ public void testNestedUnScoped() throws Exception {
+ assertNotNull(step2);
+ assertTrue("Proxy was not created for explicitly scoped bean", names.contains("lazyBindingProxy.spam"));
+ assertFalse("Proxy was created for unscoped bean", names.contains("bucket"));
+ stepExecution.getExecutionContext().putString("spam", "spam");
+ step2.execute(stepExecution);
+ assertNotNull(stepExecution.getExecutionContext().getString("foo"));
+ assertEquals("spam", TestStep.getContext().getAttribute("collaborator"));
+ assertEquals("bucket", TestStep.getContext().getAttribute("parent"));
+ }
+
+ @Test
+ public void testTwiceNestedScopedProxy() throws Exception {
+ assertNotNull(step3);
+ assertTrue("Proxy was not created for explicitly scoped bean", names.contains("lazyBindingProxy.maps"));
+ assertFalse("Proxy was created for implicitly scoped bean", names.contains("lazyBindingProxy.rab"));
+ assertEquals("foo", parent.getName());
+ stepExecution.getExecutionContext().putString("maps", "maps");
+ stepExecution.getExecutionContext().putString("rab", "rab");
+ step3.execute(stepExecution);
+ assertNotNull(stepExecution.getExecutionContext().getString("foo"));
+ assertEquals("maps", TestStep.getContext().getAttribute("collaborator"));
+ assertEquals("rab", TestStep.getContext().getAttribute("parent"));
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePerformanceTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePerformanceTests.java
new file mode 100644
index 000000000..52baeb436
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePerformanceTests.java
@@ -0,0 +1,77 @@
+package org.springframework.batch.core.scope;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.batch.item.ItemStreamReader;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.util.StopWatch;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopePerformanceTests implements ApplicationContextAware {
+
+ private Log logger = LogFactory.getLog(getClass());
+
+ private ApplicationContext applicationContext;
+
+ public void setApplicationContext(ApplicationContext applicationContext)
+ throws BeansException {
+ this.applicationContext = applicationContext;
+
+ }
+
+ @Before
+ public void start() throws Exception {
+ int count = doTest("vanilla", "warmup");
+ logger.info("Item count: "+count);
+ StepSynchronizationManager.register(new StepExecution("step", new JobExecution(0L),1L));
+ }
+
+ @Before
+ @After
+ public void cleanup() {
+ StepSynchronizationManager.close();
+ }
+
+ @Test
+ public void testVanilla() throws Exception {
+ int count = doTest("vanilla", "vanilla");
+ logger.info("Item count: "+count);
+ }
+
+ @Test
+ public void testProxied() throws Exception {
+ int count = doTest("proxied", "proxied");
+ logger.info("Item count: "+count);
+ }
+
+ private int doTest(String name, String test) throws Exception {
+ @SuppressWarnings("unchecked")
+ ItemStreamReader reader = (ItemStreamReader) applicationContext.getBean(name);
+ reader.open(new ExecutionContext());
+ StopWatch stopWatch = new StopWatch(test);
+ stopWatch.start();
+ int count = 0;
+ while (reader.read() != null) {
+ // do nothing
+ count++;
+ }
+ stopWatch.stop();
+ reader.close();
+ logger.info(stopWatch.shortSummary());
+ return count;
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePlaceholderIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePlaceholderIntegrationTests.java
new file mode 100644
index 000000000..a526767bf
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopePlaceholderIntegrationTests.java
@@ -0,0 +1,104 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopePlaceholderIntegrationTests implements BeanFactoryAware {
+
+ @Autowired
+ @Qualifier("simple")
+ private Collaborator simple;
+
+ @Autowired
+ @Qualifier("compound")
+ private Collaborator compound;
+
+ @Autowired
+ @Qualifier("value")
+ private Collaborator value;
+
+ @Autowired
+ @Qualifier("ref")
+ private Collaborator ref;
+
+ @Autowired
+ @Qualifier("bar")
+ private Collaborator bar;
+
+ private StepExecution stepExecution;
+
+ private ListableBeanFactory beanFactory;
+
+ private int beanCount;
+
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (ListableBeanFactory) beanFactory;
+ }
+
+ @Before
+ public void start() {
+
+ StepSynchronizationManager.close();
+ stepExecution = new StepExecution("foo", new JobExecution(11L), 123L);
+
+ ExecutionContext executionContext = new ExecutionContext();
+ executionContext.put("foo", "bar");
+ executionContext.put("parent", bar);
+
+ stepExecution.setExecutionContext(executionContext);
+ StepSynchronizationManager.register(stepExecution);
+
+ beanCount = beanFactory.getBeanDefinitionCount();
+
+ }
+
+ @After
+ public void cleanUp() {
+ StepSynchronizationManager.close();
+ // Check that all temporary bean definitions are cleaned up
+ assertEquals(beanCount, beanFactory.getBeanDefinitionCount());
+ }
+
+ @Test
+ public void testSimpleProperty() throws Exception {
+ assertEquals("bar", simple.getName());
+ // Once the step context is set up it should be baked into the proxies
+ // so changing it now should have no effect
+ stepExecution.getExecutionContext().put("foo", "wrong!");
+ assertEquals("bar", simple.getName());
+ }
+
+ @Test
+ public void testCompoundProperty() throws Exception {
+ assertEquals("bar-bar", compound.getName());
+ }
+
+ @Test
+ public void testParentByRef() throws Exception {
+ assertEquals("bar", ref.getParent().getName());
+ }
+
+ @Test
+ public void testParentByValue() throws Exception {
+ assertEquals("bar", value.getParent().getName());
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeProxyTargetClassIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeProxyTargetClassIntegrationTests.java
new file mode 100644
index 000000000..8c1432819
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeProxyTargetClassIntegrationTests.java
@@ -0,0 +1,72 @@
+package org.springframework.batch.core.scope;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.batch.item.ExecutionContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.ListableBeanFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopeProxyTargetClassIntegrationTests implements BeanFactoryAware {
+
+ @Autowired
+ @Qualifier("simple")
+ private TestCollaborator simple;
+
+ private StepExecution stepExecution;
+
+ private ListableBeanFactory beanFactory;
+
+ private int beanCount;
+
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = (ListableBeanFactory) beanFactory;
+ }
+
+ @Before
+ public void start() {
+
+ StepSynchronizationManager.close();
+ stepExecution = new StepExecution("foo", new JobExecution(11L), 123L);
+
+ ExecutionContext executionContext = new ExecutionContext();
+ executionContext.put("foo", "bar");
+
+ stepExecution.setExecutionContext(executionContext);
+ StepSynchronizationManager.register(stepExecution);
+
+ beanCount = beanFactory.getBeanDefinitionCount();
+
+ }
+
+ @After
+ public void cleanUp() {
+ StepSynchronizationManager.close();
+ // Check that all temporary bean definitions are cleaned up
+ assertEquals(beanCount, beanFactory.getBeanDefinitionCount());
+ }
+
+ @Test
+ public void testSimpleProperty() throws Exception {
+ assertEquals("bar", simple.getName());
+ // Once the step context is set up it should be baked into the proxies
+ // so changing it now should have no effect
+ stepExecution.getExecutionContext().put("foo", "wrong!");
+ assertEquals("bar", simple.getName());
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeStartupIntegrationTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeStartupIntegrationTests.java
new file mode 100644
index 000000000..fab5e2a69
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeStartupIntegrationTests.java
@@ -0,0 +1,17 @@
+package org.springframework.batch.core.scope;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
+
+@ContextConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+public class StepScopeStartupIntegrationTests {
+
+ @Test
+ public void testScopedProxyDuringStartup() throws Exception {
+ }
+
+}
diff --git a/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeTests.java b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeTests.java
new file mode 100644
index 000000000..f32d5efff
--- /dev/null
+++ b/spring-batch-core-tests/src/test/java/org/springframework/batch/core/scope/StepScopeTests.java
@@ -0,0 +1,192 @@
+/*
+ * 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.core.scope;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.batch.core.StepExecution;
+import org.springframework.batch.core.scope.context.StepContext;
+import org.springframework.batch.core.scope.context.StepSynchronizationManager;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.ObjectFactory;
+import org.springframework.context.support.StaticApplicationContext;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class StepScopeTests {
+
+ private StepScope scope = new StepScope();
+
+ private StepExecution stepExecution = new StepExecution("foo", new JobExecution(0L), 123L);
+
+ private StepContext context;
+
+ @Before
+ public void setUp() throws Exception {
+ context = StepSynchronizationManager.register(stepExecution);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ StepSynchronizationManager.close();
+ }
+
+ @Test
+ public void testGetWithNoContext() throws Exception {
+ final String foo = "bar";
+ StepSynchronizationManager.close();
+ try {
+ scope.get("foo", new ObjectFactory() {
+ public String getObject() throws BeansException {
+ return foo;
+ }
+ });
+ fail("Expected IllegalStateException");
+ }
+ catch (IllegalStateException e) {
+ // expected
+ }
+
+ }
+
+ @Test
+ public void testGetWithNothingAlreadyThere() {
+ final String foo = "bar";
+ Object value = scope.get("foo", new ObjectFactory() {
+ public String getObject() throws BeansException {
+ return foo;
+ }
+ });
+ assertEquals(foo, value);
+ assertTrue(context.hasAttribute("foo"));
+ }
+
+ @Test
+ public void testGetWithSomethingAlreadyThere() {
+ context.setAttribute("foo", "bar");
+ Object value = scope.get("foo", new ObjectFactory