diff --git a/spring-batch-core/.springBeans b/spring-batch-core/.springBeans
index 0729082d2..2fe6e96d3 100644
--- a/spring-batch-core/.springBeans
+++ b/spring-batch-core/.springBeans
@@ -64,7 +64,6 @@
src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceErrorTests-context.xml
src/test/resources/org/springframework/batch/core/configuration/support/child-context.xml
src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml
- src/test/resources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml
src/test/resources/org/springframework/batch/core/configuration/xml/DuplicateTransitionJobParserTests-context.xml
src/test/resources/org/springframework/batch/core/launch/support/error.xml
src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml
@@ -103,6 +102,7 @@
src/test/resources/org/springframework/batch/core/configuration/xml/PartitionStepParserTests-context.xml
src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementSkipPolicyParserTests-context.xml
src/test/resources/org/springframework/batch/core/configuration/xml/JobStepParserTests-context.xml
+ src/test/resources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrar.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrar.java
new file mode 100644
index 000000000..5937af919
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrar.java
@@ -0,0 +1,167 @@
+/*
+ * 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.configuration.support;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.configuration.DuplicateJobException;
+import org.springframework.batch.core.configuration.JobRegistry;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.ApplicationEvent;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.Lifecycle;
+import org.springframework.context.event.ContextClosedEvent;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.util.Assert;
+
+/**
+ * Loads and unloads {@link Job Jobs} when the application context is created
+ * and destroyed. Each resource provided is loaded as an application context
+ * with the current context as its parent, and then all the jobs from the child
+ * context are registered under their bean names. A {@link JobRegistry} is
+ * required.
+ *
+ * @author Lucas Ward
+ * @author Dave Syer
+ *
+ * @since 2.1
+ */
+public class AutomaticJobRegistrar implements Lifecycle, ApplicationListener, ApplicationContextAware, InitializingBean {
+
+ private Collection applicationContextFactories = new ArrayList();
+
+ private JobLoader jobLoader;
+
+ private ApplicationContext applicationContext;
+
+ private volatile boolean running = false;
+
+ private Object lifecycleMonitor = new Object();
+
+ /**
+ * The enclosing application context, which can be used to check if
+ * {@link ApplicationEvent events} come from the expected source.
+ *
+ * @param applicationContext the enclosing application context if there is
+ * one
+ * @see ApplicationContextAware#setApplicationContext(ApplicationContext)
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+ /**
+ * Add some factories to the set that will be used to load contexts and jobs.
+ *
+ * @param applicationContextFactories the {@link ApplicationContextFactory}
+ * values to use
+ */
+ public void setApplicationContextFactories(ApplicationContextFactory[] applicationContextFactories) {
+ for (ApplicationContextFactory applicationContextFactory : applicationContextFactories) {
+ this.applicationContextFactories.add(applicationContextFactory);
+ }
+ }
+
+ /**
+ * The job loader that will be used to load and manage jobs.
+ *
+ * @param jobLoader the {@link JobLoader} to set
+ */
+ public void setJobLoader(JobLoader jobLoader) {
+ this.jobLoader = jobLoader;
+ }
+
+ /**
+ * @throws Exception
+ */
+ public void afterPropertiesSet() {
+
+ Assert.state(jobLoader != null, "A JobLoader must be provided");
+
+ }
+
+ /**
+ * Creates all the application contexts required and set up job registry
+ * entries with all the instances of {@link Job} found therein. Also closes
+ * the contexts when the enclosing context is closed.
+ *
+ * @see InitializingBean#afterPropertiesSet()
+ */
+ public final void onApplicationEvent(ApplicationEvent event) {
+ // TODO: With Spring 3 a SmartLifecycle is started automatically
+ if (event.getSource() == applicationContext) {
+ if (event instanceof ContextRefreshedEvent) {
+ start();
+ }
+ else if (event instanceof ContextClosedEvent) {
+ stop();
+ }
+ }
+ }
+
+ /**
+ * Delegates to {@link JobLoader#clear()}.
+ *
+ * @see Lifecycle#stop()
+ */
+ public void stop() {
+ synchronized (this.lifecycleMonitor) {
+ jobLoader.clear();
+ running = false;
+ }
+ }
+
+ /**
+ * Take all the contexts from the factories provided and pass them to teh
+ * {@link JobLoader}.
+ *
+ * @see Lifecycle#start()
+ */
+ public void start() {
+ synchronized (this.lifecycleMonitor) {
+ if (running) {
+ return;
+ }
+ for (ApplicationContextFactory factory : applicationContextFactories) {
+ try {
+ jobLoader.load(factory);
+ }
+ catch (DuplicateJobException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ running = true;
+ }
+ }
+
+ /**
+ * Check if this component has been started.
+ *
+ * @return true if started successfully and not stopped
+ * @see Lifecycle#isRunning()
+ */
+ public boolean isRunning() {
+ synchronized (this.lifecycleMonitor) {
+ return running;
+ }
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java
index 619c6cf0d..d00ae9990 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java
@@ -18,9 +18,14 @@ package org.springframework.batch.core.configuration.support;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.beans.factory.config.CustomEditorConfigurer;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
@@ -43,22 +48,31 @@ import org.springframework.util.Assert;
*/
public class ClassPathXmlApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware {
+ private static final Log logger = LogFactory.getLog(ClassPathXmlApplicationContextFactory.class);
+
+ private Resource resource;
+
private ConfigurableApplicationContext parent;
-
- private Resource path;
-
- private ResourceXmlApplicationContext context;
-
+
private boolean copyConfiguration = true;
private Collection> beanFactoryPostProcessorClasses;
- private final Object lock = new Object();
+ private Collection> beanPostProcessorExcludeClasses;
public ClassPathXmlApplicationContextFactory() {
beanFactoryPostProcessorClasses = new ArrayList>();
beanFactoryPostProcessorClasses.add(PropertyPlaceholderConfigurer.class);
beanFactoryPostProcessorClasses.add(CustomEditorConfigurer.class);
+ beanPostProcessorExcludeClasses = new ArrayList>();
+ /*
+ * Assume that a BeanPostProcessor that is BeanFactoryAware must be
+ * specific to the parent and remove it from the child (e.g. an
+ * AutoProxyCreator will not work properly). Unfortunately there might
+ * still be a a BeanPostProcessor with a dependency that itself is
+ * BeanFactoryAware, but we can legislate for that here.
+ */
+ beanPostProcessorExcludeClasses.add(BeanFactoryAware.class);
}
/**
@@ -66,10 +80,10 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
* {@link ApplicationContext}. Use imports to centralise the configuration
* in one file.
*
- * @param path the resource path to the xml to load for the child context.
+ * @param resource the resource path to the xml to load for the child context.
*/
- public void setPath(Resource path) {
- this.path = path;
+ public void setResource(Resource resource) {
+ this.resource = resource;
}
/**
@@ -109,6 +123,23 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
}
}
+ /**
+ * Determines by exclusion which bean post processors should be copied from
+ * the parent context. Defaults to {@link BeanFactoryAware} (so any post
+ * processors that have a reference to the parent bean factory are not
+ * copied into the child). Note that these classes do not themselves have to
+ * be {@link BeanPostProcessor} implementations or sub-interfaces.
+ *
+ * @param beanPostProcessorExcludeClasses the classes to set
+ */
+ public void setBeanPostProcessorExcludeClasses(Class>[] beanPostProcessorExcludeClasses) {
+ this.beanPostProcessorExcludeClasses = new ArrayList>();
+ for (int i = 0; i < beanPostProcessorExcludeClasses.length; i++) {
+ this.beanPostProcessorExcludeClasses.add(beanPostProcessorExcludeClasses[i]);
+ }
+
+ }
+
/**
* Protected access to the list of bean factory post processor classes that
* should be copied over to the context from the parent.
@@ -125,6 +156,9 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
*/
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+ if (applicationContext==null) {
+ return;
+ }
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
parent = (ConfigurableApplicationContext) applicationContext;
}
@@ -136,19 +170,11 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
*/
public ConfigurableApplicationContext createApplicationContext() {
- if (path == null) {
+ if (resource == null) {
return parent;
}
- if (context == null) {
- // Lazy initialization of cached context
- synchronized (lock) {
- if (context == null) {
- context = new ResourceXmlApplicationContext(parent);
- }
- }
- }
- return context;
+ return new ResourceXmlApplicationContext(parent);
}
@@ -188,7 +214,7 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
@Override
protected Resource[] getConfigResources() {
- return new Resource[] { path };
+ return new Resource[] { resource };
}
}
@@ -218,7 +244,8 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
/**
* Extension point for special subclasses that want to do more complex
* things with the bean factory prior to refresh. The default implementation
- * copies all configuration from the parent according to the flag set.
+ * copies all configuration from the parent according to the
+ * {@link #setCopyConfiguration(boolean) flag} set.
*
* @param parent the parent bean factory for the new context (will never be
* null)
@@ -231,7 +258,16 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
protected void prepareBeanFactory(DefaultListableBeanFactory parent, DefaultListableBeanFactory beanFactory) {
if (copyConfiguration && parent != null) {
beanFactory.copyConfigurationFrom(parent);
+ @SuppressWarnings("unchecked")
+ List beanPostProcessors = beanFactory.getBeanPostProcessors();
+ for (BeanPostProcessor beanPostProcessor : new ArrayList(beanPostProcessors)) {
+ for (Class> cls : beanPostProcessorExcludeClasses) {
+ if (cls.isAssignableFrom(beanPostProcessor.getClass())) {
+ logger.debug("Removing bean post processor: " + beanPostProcessor + " of type " + cls);
+ beanPostProcessors.remove(beanPostProcessor);
+ }
+ }
+ }
}
}
-
}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoader.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoader.java
deleted file mode 100644
index f64a63a98..000000000
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoader.java
+++ /dev/null
@@ -1,208 +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.core.configuration.support;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.batch.core.Job;
-import org.springframework.batch.core.configuration.DuplicateJobException;
-import org.springframework.batch.core.configuration.JobFactory;
-import org.springframework.batch.core.configuration.JobLocator;
-import org.springframework.batch.core.configuration.JobRegistry;
-import org.springframework.batch.core.configuration.ListableJobLocator;
-import org.springframework.batch.core.launch.NoSuchJobException;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.DisposableBean;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.ApplicationEvent;
-import org.springframework.context.ApplicationListener;
-import org.springframework.context.ConfigurableApplicationContext;
-import org.springframework.context.event.ContextClosedEvent;
-import org.springframework.context.event.ContextRefreshedEvent;
-import org.springframework.core.io.Resource;
-import org.springframework.util.Assert;
-
-/**
- * Implementation of the {@link ListableJobLocator} interface that assumes all
- * Jobs will be loaded from class path xml resources. Each resource provided is
- * loaded as an application context with the current context as its parent, and
- * then all the jobs from the child context are registered under their bean
- * names. A {@link JobRegistry} is required.
- *
- * @author Lucas Ward
- * @author Dave Syer
- *
- * @since 2.0
- * @since 2.1 this class does not implement {@link JobRegistry}
- */
-public class ClassPathXmlJobLoader implements ApplicationContextAware, ApplicationListener, InitializingBean {
-
- private static Log logger = LogFactory.getLog(ClassPathXmlJobLoader.class);
-
- private List jobPaths;
-
- private ApplicationContext parent;
-
- private JobRegistry jobRegistry;
-
- private Collection contexts = new HashSet();
-
- /**
- * A set of resources to load. Each resource should be a Spring
- * configuration file which is loaded into an application context whose
- * parent is the current context. In a configuration file the resources can
- * be given as a pattern (e.g.
- * classpath*:/config/*-job-context.xml).
- *
- * @param jobPaths
- */
- public void setJobPaths(Resource[] jobPaths) {
- this.jobPaths = Arrays.asList(jobPaths);
- }
-
- /**
- * The {@link JobRegistry} to use for jobs created. If not provided an
- * instance will be discovered from the application context.
- *
- * @param jobRegistry
- */
- public void setJobRegistry(JobRegistry jobRegistry) {
- this.jobRegistry = jobRegistry;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see
- * org.springframework.context.ApplicationContextAware#setApplicationContext
- * (org.springframework.context.ApplicationContext)
- */
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
- parent = applicationContext;
- }
-
- /**
- * @throws Exception
- */
- public void afterPropertiesSet() throws Exception {
- Assert.state(jobRegistry != null, "A JobRegistry must be provided");
- }
-
- /**
- * Creates all the application contexts required and set up job registry
- * entries with all the instances of {@link Job} found therein. Also closes
- * the contexts when their parent is closed.
- *
- * @see InitializingBean#afterPropertiesSet()
- */
- public final void onApplicationEvent(ApplicationEvent event) {
- if (event.getSource() == parent) {
- if (event instanceof ContextRefreshedEvent) {
- try {
- initialize();
- }
- catch (DuplicateJobException e) {
- throw new IllegalStateException(e);
- }
- catch (NoSuchJobException e) {
- throw new IllegalStateException(e);
- }
- }
- else if (event instanceof ContextClosedEvent) {
- clear();
- }
- }
- }
-
- /**
- * Create jobs as instructed and register them so they can be accessed via
- * the {@link JobLocator} interface. Normally called from
- * {@link #onApplicationEvent(ApplicationEvent)} when the parent context is
- * refreshed.
- *
- * @throws DuplicateJobException if the job registry detects a duplicate job
- * @throws NoSuchJobException if no jobs are registered, since this is
- * usually an error
- */
- protected void initialize() throws DuplicateJobException, NoSuchJobException {
-
- for (Resource resource : jobPaths) {
-
- ConfigurableApplicationContext context = createApplicationContext(parent, resource);
- contexts.add(context);
- String[] names = context.getBeanNamesForType(Job.class);
-
- for (String name : names) {
- logger.debug("Registering job: " + name + " from context: " + resource);
- JobFactory jobFactory = new ReferenceJobFactory((Job) context.getBean(name));
- jobRegistry.register(jobFactory);
- }
-
- }
-
- if (!jobPaths.isEmpty() && jobRegistry.getJobNames().isEmpty()) {
- throw new NoSuchJobException("Could not locate any jobs in resources provided.");
- }
-
- }
-
- /**
- * Create an application context from the resource provided. Extension point
- * for subclasses if they need to customize the context in any way. The
- * default uses a {@link ClassPathXmlApplicationContextFactory}.
- *
- * @param parent the parent application context (or null if there is none)
- * @param resource the location of the XML configuration
- *
- * @return an application context containing jobs
- */
- protected ConfigurableApplicationContext createApplicationContext(ApplicationContext parent, Resource resource) {
- ClassPathXmlApplicationContextFactory applicationContextFactory = new ClassPathXmlApplicationContextFactory();
- applicationContextFactory.setPath(resource);
- if (parent != null) {
- applicationContextFactory.setApplicationContext(parent);
- }
- return applicationContextFactory.createApplicationContext();
- }
-
- /**
- * Close the contexts that were created in {@link #afterPropertiesSet()}.
- *
- * @see DisposableBean#destroy()
- */
- protected void clear() {
-
- for (ConfigurableApplicationContext context : contexts) {
- if (context.isActive()) {
- context.close();
- }
- }
- for (String jobName : jobRegistry.getJobNames()) {
- jobRegistry.unregister(jobName);
- }
- contexts.clear();
-
- }
-
-}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java
index d215727ff..728c7a8f4 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java
@@ -5,7 +5,7 @@ package org.springframework.batch.core.configuration.support;
*
* @author Dave Syer
*
- * @deprecated in version 2.1, please us {@link ClassPathXmlJobLoader} instead
+ * @deprecated in version 2.1, please us {@link AutomaticJobRegistrar} instead
*/
public abstract class ClassPathXmlJobRegistry {
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClasspathXmlApplicationContextsFactoryBean.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClasspathXmlApplicationContextsFactoryBean.java
new file mode 100644
index 000000000..e44e82034
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClasspathXmlApplicationContextsFactoryBean.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2006-2010 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.configuration.support;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.FactoryBean;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.beans.factory.config.CustomEditorConfigurer;
+import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.io.Resource;
+
+/**
+ * A convenient factory for creating a set of {@link ApplicationContextFactory}
+ * components from a set of {@link Resource resources}.
+ *
+ * @author Dave Syer
+ *
+ */
+public class ClasspathXmlApplicationContextsFactoryBean implements FactoryBean, ApplicationContextAware {
+
+ private List resources = new ArrayList();
+
+ private boolean copyConfiguration = true;
+
+ private Class extends BeanFactoryPostProcessor>[] beanFactoryPostProcessorClasses;
+
+ private Class>[] beanPostProcessorExcludeClasses;
+
+ private ApplicationContext applicationContext;
+
+ /**
+ * A set of resources to load using a
+ * {@link ClassPathXmlApplicationContextFactory}. Each resource should be a
+ * Spring configuration file which is loaded into an application context
+ * whose parent is the current context. In a configuration file the
+ * resources can be given as a pattern (e.g.
+ * classpath*:/config/*-context.xml).
+ *
+ * @param resources
+ */
+ public void setResources(Resource[] resources) {
+ this.resources = Arrays.asList(resources);
+ }
+
+ /**
+ * Flag to indicate that configuration such as bean post processors and
+ * custom editors should be copied from the parent context. Defaults to
+ * true.
+ *
+ * @param copyConfiguration the flag value to set
+ */
+ public void setCopyConfiguration(boolean copyConfiguration) {
+ this.copyConfiguration = copyConfiguration;
+ }
+
+ /**
+ * Determines which bean factory post processors (like property
+ * placeholders) should be copied from the parent context. Defaults to
+ * {@link PropertyPlaceholderConfigurer} and {@link CustomEditorConfigurer}.
+ *
+ * @param copyBeanFactoryPostProcessors the flag value to set
+ */
+
+ public void setBeanFactoryPostProcessorClasses(
+ Class extends BeanFactoryPostProcessor>[] beanFactoryPostProcessorClasses) {
+ this.beanFactoryPostProcessorClasses = beanFactoryPostProcessorClasses;
+ }
+
+ /**
+ * Determines by exclusion which bean post processors should be copied from
+ * the parent context. Defaults to {@link BeanFactoryAware} (so any post
+ * processors that have a reference to the parent bean factory are not
+ * copied into the child). Note that these classes do not themselves have to
+ * be {@link BeanPostProcessor} implementations or sub-interfaces.
+ *
+ * @param beanPostProcessorExcludeClasses the classes to set
+ */
+ public void setBeanPostProcessorExcludeClasses(Class>[] beanPostProcessorExcludeClasses) {
+ this.beanPostProcessorExcludeClasses = beanPostProcessorExcludeClasses;
+ }
+
+ /**
+ * Create an {@link ApplicationContextFactory} from each resource provided
+ * in {@link #setResources(Resource[])}.
+ *
+ * @return an array of {@link ApplicationContextFactory}
+ * @throws Exception
+ * @see org.springframework.beans.factory.FactoryBean#getObject()
+ */
+ public Object getObject() throws Exception {
+
+ if (resources == null) {
+ return new ApplicationContextFactory[0];
+ }
+
+ List applicationContextFactories = new ArrayList();
+ for (Resource resource : resources) {
+ ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory();
+ factory.setCopyConfiguration(copyConfiguration);
+ if (beanFactoryPostProcessorClasses != null) {
+ factory.setBeanFactoryPostProcessorClasses(beanFactoryPostProcessorClasses);
+ }
+ if (beanPostProcessorExcludeClasses != null) {
+ factory.setBeanPostProcessorExcludeClasses(beanPostProcessorExcludeClasses);
+ }
+ factory.setResource(resource);
+ factory.setApplicationContext(applicationContext);
+ applicationContextFactories.add(factory);
+ }
+ return applicationContextFactories.toArray(new ApplicationContextFactory[applicationContextFactories.size()]);
+ }
+
+ /**
+ * The type of obkect returned by this factory - an array of
+ * {@link ApplicationContextFactory}.
+ *
+ * @return array of {@link ApplicationContextFactory}
+ * @see FactoryBean#getObjectType()
+ */
+ public Class> getObjectType() {
+ return ApplicationContextFactory[].class;
+ }
+
+ /**
+ * Oprimization hint for bean factory.
+ * @return true
+ * @see FactoryBean#isSingleton()
+ */
+ public boolean isSingleton() {
+ return true;
+ }
+
+ /**
+ * An application context that can be used as a parent context for all the
+ * factories.
+ *
+ * @param applicationContext the {@link ApplicationContext} to set
+ * @throws BeansException
+ * @see ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) {
+ this.applicationContext = applicationContext;
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultJobLoader.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultJobLoader.java
new file mode 100644
index 000000000..f935301e9
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultJobLoader.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2006-2010 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.configuration.support;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.configuration.DuplicateJobException;
+import org.springframework.batch.core.configuration.JobFactory;
+import org.springframework.batch.core.configuration.JobRegistry;
+import org.springframework.batch.core.launch.NoSuchJobException;
+import org.springframework.context.ConfigurableApplicationContext;
+
+/**
+ * @author Dave Syer
+ *
+ */
+public class DefaultJobLoader implements JobLoader {
+
+ private static Log logger = LogFactory.getLog(DefaultJobLoader.class);
+
+ private JobRegistry jobRegistry;
+
+ private Collection contexts = new HashSet();
+
+ /**
+ * Default constructor useful for decalarative configuration.
+ */
+ public DefaultJobLoader() {
+ this(null);
+ }
+
+ /**
+ * Create a job loader with the job registry provided.
+ * @param jobRegistry a {@link JobRegistry}
+ */
+ public DefaultJobLoader(JobRegistry jobRegistry) {
+ this.jobRegistry = jobRegistry;
+ }
+
+ /**
+ * The {@link JobRegistry} to use for jobs created.
+ *
+ * @param jobRegistry
+ */
+ public void setJobRegistry(JobRegistry jobRegistry) {
+ this.jobRegistry = jobRegistry;
+ }
+
+ /**
+ * Unregister all the jobs and close all the contexts created by this
+ * loader.
+ *
+ * @see JobLoader#clear()
+ */
+ public void clear() {
+ for (ConfigurableApplicationContext context : contexts) {
+ if (context.isActive()) {
+ context.close();
+ }
+ }
+ for (String jobName : jobRegistry.getJobNames()) {
+ jobRegistry.unregister(jobName);
+ }
+ contexts.clear();
+ }
+
+ public Collection load(ApplicationContextFactory factory) throws DuplicateJobException {
+
+ Collection jobNamesBefore = jobRegistry.getJobNames();
+ ConfigurableApplicationContext context = factory.createApplicationContext();
+ // Try to detect auto-registration (e.g. through a bean post processor)
+ boolean autoRegistrationDetected = jobRegistry.getJobNames().size() > jobNamesBefore.size();
+
+ contexts.add(context);
+ String[] names = context.getBeanNamesForType(Job.class);
+ Collection result = new ArrayList();
+
+ for (String name : names) {
+ if (!autoRegistrationDetected) {
+ logger.debug("Registering job: " + name + " from context: " + context.getDisplayName());
+ JobFactory jobFactory = new ReferenceJobFactory((Job) context.getBean(name));
+ jobRegistry.register(jobFactory);
+ }
+ try {
+ result.add(jobRegistry.getJob(name));
+ }
+ catch (NoSuchJobException e) {
+ // should not happen;
+ throw new IllegalStateException("Could not retrieve job that was should have been registered", e);
+ }
+ }
+
+ return result;
+
+ }
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java
index e087b06e2..3b3e6ba23 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java
@@ -24,7 +24,7 @@ import org.springframework.batch.core.JobParametersIncrementer;
* to make it fit a naming convention for type or origin. E.g. the source job
* might be overnightJob and the group
* financeDepartment, which would result in a {@link Job} with
- * identical functionality but named financeDepartment$overnightJob
+ * identical functionality but named financeDepartment.overnightJob
* . The use of a "." separator for elements is deliberate, since it is a "safe"
* character in a URL.
*
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobLoader.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobLoader.java
new file mode 100644
index 000000000..b856ff0b4
--- /dev/null
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobLoader.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2009-2010 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.configuration.support;
+
+import java.util.Collection;
+
+import org.springframework.batch.core.Job;
+import org.springframework.batch.core.configuration.DuplicateJobException;
+
+
+/**
+ * @author Dave Syer
+ *
+ * @since 2.1
+ */
+public interface JobLoader {
+
+ /**
+ * @param factory a factory for an application context (containing jobs)
+ * @return a collection of the jobs created
+ *
+ * @throws DuplicateJobException if a job with the same name was already registered
+ */
+ Collection load(ApplicationContextFactory factory) throws DuplicateJobException;
+
+ /**
+ * Unregister all the jobs and close all the contexts created by this loader.
+ */
+ void clear();
+
+}
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java
index c4e7aad9d..3d5734a0f 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java
@@ -25,10 +25,10 @@ import org.springframework.osgi.context.BundleContextAware;
import org.springframework.osgi.context.support.OsgiBundleXmlApplicationContext;
/**
- * @author Dave Syer
+ * {@link ApplicationContextFactory} that can be used to load a context from an
+ * XML location in a bundle.
*
- * @deprecated with no plans to replace (stateful creation of application
- * context should no longer be required as it was in Spring Batch 1.1.x)
+ * @author Dave Syer
*
*/
public class OsgiBundleXmlApplicationContextFactory implements BundleContextAware, ApplicationContextFactory,
diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
index b0ca7a8e6..2f4e1bac7 100644
--- a/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
+++ b/spring-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
@@ -18,9 +18,7 @@ package org.springframework.batch.core.launch.support;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
-import java.util.HashSet;
import java.util.List;
import org.apache.commons.logging.Log;
@@ -30,13 +28,12 @@ import org.springframework.batch.core.configuration.DuplicateJobException;
import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.ClassPathXmlApplicationContextFactory;
-import org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor;
-import org.springframework.batch.core.configuration.support.ReferenceJobFactory;
+import org.springframework.batch.core.configuration.support.DefaultJobLoader;
+import org.springframework.batch.core.configuration.support.JobLoader;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;
@@ -74,7 +71,7 @@ public class JobRegistryBackgroundJobRunner {
private static Log logger = LogFactory.getLog(JobRegistryBackgroundJobRunner.class);
- private JobRegistry registry;
+ private JobLoader jobLoader;
private ApplicationContext parentContext = null;
@@ -82,7 +79,7 @@ public class JobRegistryBackgroundJobRunner {
final private String parentContextPath;
- private Collection contexts = new HashSet();
+ private JobRegistry jobRegistry;
private static List errors = Collections.synchronizedList(new ArrayList());
@@ -95,11 +92,21 @@ public class JobRegistryBackgroundJobRunner {
}
/**
- * Public setter for the {@link JobRegistry}.
- * @param registry the registry to set
+ * A loader for the jobs that are going to be registered.
+ *
+ * @param jobLoader the {@link JobLoader} to set
*/
- public void setRegistry(JobRegistry registry) {
- this.registry = registry;
+ public void setJobLoader(JobLoader jobLoader) {
+ this.jobLoader = jobLoader;
+ }
+
+ /**
+ * A job registry that can be used to create a job loader (if none is provided).
+ *
+ * @param jobRegistry the {@link JobRegistry} to set
+ */
+ public void setJobRegistry(JobRegistry jobRegistry) {
+ this.jobRegistry = jobRegistry;
}
/**
@@ -115,9 +122,10 @@ public class JobRegistryBackgroundJobRunner {
private void register(String[] paths) throws DuplicateJobException, IOException {
+ maybeCreateJobLoader();
+
for (int i = 0; i < paths.length; i++) {
- boolean postProcessorExists = parentContext.getBeanNamesForType(JobRegistryBeanPostProcessor.class).length > 0;
Resource[] resources = parentContext.getResources(paths[i]);
for (int j = 0; j < resources.length; j++) {
@@ -125,21 +133,10 @@ public class JobRegistryBackgroundJobRunner {
Resource path = resources[j];
logger.info("Registering Job definitions from " + Arrays.toString(resources));
- ConfigurableApplicationContext context = createApplicationContext(parentContext, path);
- contexts.add(context);
- String[] names = context.getBeanNamesForType(Job.class);
-
- Collection registered = registry.getJobNames();
- // If there is a JobRegistryBeanPostProcessor in there already
- // then they can be registered automatically
- for (String name : names) {
- if (!registered.contains(name) && postProcessorExists) {
- logger.debug("Registering job: " + name + " from context: " + path);
- JobFactory jobFactory = new ReferenceJobFactory((Job) context.getBean(name));
- registry.register(jobFactory);
- }
- }
-
+ ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory();
+ factory.setApplicationContext(parentContext);
+ factory.setResource(path);
+ jobLoader.load(factory);
}
}
@@ -147,22 +144,30 @@ public class JobRegistryBackgroundJobRunner {
}
/**
- * Create an application context from the resource provided. Extension point
- * for subclasses if they need to customize the context in any way. The
- * default uses a {@link ClassPathXmlApplicationContextFactory}.
- *
- * @param parent the parent application context (or null if there is none)
- * @param resource the location of the XML configuration
- *
- * @return an application context containing jobs
+ * If there is no {@link JobLoader} then try and create one from existing
+ * bean definitions.
*/
- protected ConfigurableApplicationContext createApplicationContext(ApplicationContext parent, Resource resource) {
- ClassPathXmlApplicationContextFactory applicationContextFactory = new ClassPathXmlApplicationContextFactory();
- applicationContextFactory.setPath(resource);
- if (parent != null) {
- applicationContextFactory.setApplicationContext(parent);
+ private void maybeCreateJobLoader() {
+
+ if (jobLoader != null) {
+ return;
}
- return applicationContextFactory.createApplicationContext();
+
+ String[] names = parentContext.getBeanNamesForType(JobLoader.class);
+ if (names.length == 0) {
+ if (parentContext.containsBean("jobLoader")) {
+ jobLoader = (JobLoader) parentContext.getBean("jobLoader", JobLoader.class);
+ return;
+ }
+ if (jobRegistry != null) {
+ jobLoader = new DefaultJobLoader(jobRegistry);
+ return;
+ }
+ }
+
+ jobLoader = (JobLoader) parentContext.getBean(names[0], JobLoader.class);
+ return;
+
}
/**
@@ -249,15 +254,7 @@ public class JobRegistryBackgroundJobRunner {
* @see org.springframework.beans.factory.DisposableBean#destroy()
*/
private void destroy() throws Exception {
- for (ConfigurableApplicationContext context : contexts) {
- if (context.isActive()) {
- context.close();
- }
- }
- for (String jobName : registry.getJobNames()) {
- registry.unregister(jobName);
- }
- contexts.clear();
+ jobLoader.clear();
}
private void run() {
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests.java
similarity index 95%
rename from spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests.java
rename to spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests.java
index 3b5c52b4b..0c9b3ea2c 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests.java
@@ -21,7 +21,7 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
-public class ClassPathXmlJobLoaderContextTests {
+public class AutomaticJobRegistrarContextTests {
@Autowired
private JobRegistry registry;
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarTests.java
similarity index 58%
rename from spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderTests.java
rename to spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarTests.java
index 0f646a4a6..26fbd9a38 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarTests.java
@@ -1,16 +1,18 @@
package org.springframework.batch.core.configuration.support;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import java.util.ArrayList;
import java.util.Collection;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.core.Job;
-import org.springframework.batch.core.launch.NoSuchJobException;
import org.springframework.beans.factory.BeanCreationException;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.support.ClassPathXmlApplicationContext;
@@ -20,18 +22,21 @@ import org.springframework.core.io.Resource;
/**
*
- *
+ * @author Dave Syer
* @author Lucas Ward
*
*/
-public class ClassPathXmlJobLoaderTests {
+public class AutomaticJobRegistrarTests {
+
+ private AutomaticJobRegistrar registrar = new AutomaticJobRegistrar();
- private ClassPathXmlJobLoader loader = new ClassPathXmlJobLoader();
private MapJobRegistry registry = new MapJobRegistry();
-
+
@Before
public void setUp() {
- loader.setJobRegistry(registry);
+ DefaultJobLoader jobLoader = new DefaultJobLoader();
+ jobLoader.setJobRegistry(registry);
+ registrar.setJobLoader(jobLoader);
}
@Test
@@ -41,11 +46,11 @@ public class ClassPathXmlJobLoaderTests {
new ClassPathResource("org/springframework/batch/core/launch/support/job.xml"),
new ClassPathResource("org/springframework/batch/core/launch/support/job2.xml") };
- loader.setJobPaths(jobPaths);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
- loader.setApplicationContext(applicationContext);
- loader.initialize();
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.setApplicationContext(applicationContext);
+ registrar.start();
Collection names = registry.getJobNames();
assertEquals(2, names.size());
@@ -58,16 +63,16 @@ public class ClassPathXmlJobLoaderTests {
assertEquals("test-job2", job.getName());
}
- @Test(expected = NoSuchJobException.class)
+ @Test
public void testNoJobFound() throws Exception {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/test-environment.xml") };
- loader.setJobPaths(jobPaths);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
- loader.setApplicationContext(applicationContext);
- loader.initialize();
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.setApplicationContext(applicationContext);
+ registrar.start();
}
@Test
@@ -75,11 +80,11 @@ public class ClassPathXmlJobLoaderTests {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
- loader.setJobPaths(jobPaths);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
- loader.setApplicationContext(applicationContext);
- loader.initialize();
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.setApplicationContext(applicationContext);
+ registrar.start();
assertEquals(2, registry.getJobNames().size());
}
@@ -88,10 +93,11 @@ public class ClassPathXmlJobLoaderTests {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
- loader.setApplicationContext(new ClassPathXmlApplicationContext(
- "/org/springframework/batch/core/launch/support/test-environment-with-registry-and-auto-register.xml"));
- loader.setJobPaths(jobPaths);
- loader.initialize();
+ ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(
+ "/org/springframework/batch/core/launch/support/test-environment-with-registry-and-auto-register.xml");
+ registrar.setApplicationContext(applicationContext);
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.start();
assertEquals(2, registry.getJobNames().size());
}
@@ -101,9 +107,9 @@ public class ClassPathXmlJobLoaderTests {
Resource[] jobPaths = new Resource[] {
new ClassPathResource("org/springframework/batch/core/launch/support/2jobs.xml"),
new ClassPathResource("org/springframework/batch/core/launch/support/error.xml") };
- loader.setJobPaths(jobPaths);
+ setUpApplicationContextFactories(jobPaths, null);
try {
- loader.initialize();
+ registrar.start();
fail("Expected BeanCreationException");
}
catch (BeanCreationException e) {
@@ -112,47 +118,74 @@ public class ClassPathXmlJobLoaderTests {
}
@Test
- public void testDestroy() throws Exception {
+ public void testClear() throws Exception {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
- loader.setJobPaths(jobPaths);
- loader.initialize();
+ setUpApplicationContextFactories(jobPaths, null);
+ registrar.start();
assertEquals(2, registry.getJobNames().size());
- loader.clear();
+ registrar.stop();
assertEquals(0, registry.getJobNames().size());
}
+ @Test
+ public void testStartStopRunning() throws Exception {
+
+ Resource[] jobPaths = new Resource[] { new ClassPathResource(
+ "org/springframework/batch/core/launch/support/2jobs.xml") };
+ setUpApplicationContextFactories(jobPaths, null);
+ registrar.start();
+ assertTrue(registrar.isRunning());
+ registrar.start();
+ assertEquals(2, registry.getJobNames().size());
+ registrar.stop();
+ assertFalse(registrar.isRunning());
+
+ }
+
@Test
public void testInitCalledOnContextRefreshed() throws Exception {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
- loader.setApplicationContext(new ClassPathXmlApplicationContext(
+ registrar.setApplicationContext(new ClassPathXmlApplicationContext(
"/org/springframework/batch/core/launch/support/test-environment-with-registry-and-auto-register.xml"));
- loader.setJobPaths(jobPaths);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
- loader.setApplicationContext(applicationContext);
- loader.onApplicationEvent(new ContextRefreshedEvent(applicationContext));
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.setApplicationContext(applicationContext);
+ registrar.onApplicationEvent(new ContextRefreshedEvent(applicationContext));
assertEquals(2, registry.getJobNames().size());
}
@Test
- public void testDestroyCalledOnContextClosed() throws Exception {
+ public void testClearCalledOnContextClosed() throws Exception {
Resource[] jobPaths = new Resource[] { new ClassPathResource(
"org/springframework/batch/core/launch/support/2jobs.xml") };
- loader.setJobPaths(jobPaths);
GenericApplicationContext applicationContext = new GenericApplicationContext();
applicationContext.refresh();
- loader.setApplicationContext(applicationContext);
- loader.initialize();
+ setUpApplicationContextFactories(jobPaths, applicationContext);
+ registrar.setApplicationContext(applicationContext);
+ registrar.start();
assertEquals(2, registry.getJobNames().size());
- loader.onApplicationEvent(new ContextClosedEvent(applicationContext));
+ registrar.onApplicationEvent(new ContextClosedEvent(applicationContext));
assertEquals(0, registry.getJobNames().size());
}
+ private void setUpApplicationContextFactories(Resource[] jobPaths, ApplicationContext parent) {
+ Collection applicationContextFactories = new ArrayList();
+ for (Resource resource : jobPaths) {
+ ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory();
+ factory.setResource(resource);
+ factory.setApplicationContext(parent);
+ applicationContextFactories.add(factory);
+ }
+ registrar.setApplicationContextFactories(applicationContextFactories
+ .toArray(new ApplicationContextFactory[jobPaths.length]));
+ }
+
}
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java
index 60af27a6b..25ccdaac1 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java
@@ -36,20 +36,20 @@ public class ClassPathXmlApplicationContextFactoryTests {
@Test
public void testCreateJob() {
- factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
+ factory.setResource(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
assertNotNull(factory.createApplicationContext());
}
@Test
public void testGetJobName() {
- factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
+ factory.setResource(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "trivial-context.xml")));
assertEquals("test-job", factory.createApplicationContext().getBeanNamesForType(Job.class)[0]);
}
@Test
public void testParentConfigurationInherited() {
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
- factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
+ factory.setResource(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
ConfigurableApplicationContext context = factory.createApplicationContext();
assertEquals("test-job", context.getBeanNamesForType(Job.class)[0]);
assertEquals("bar", ((Job) context.getBean("test-job", Job.class)).getName());
@@ -59,7 +59,7 @@ public class ClassPathXmlApplicationContextFactoryTests {
@Test
public void testBeanFactoryPostProcessorsNotCopied() {
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
- factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
+ factory.setResource(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
@SuppressWarnings("unchecked")
Class extends BeanFactoryPostProcessor>[] classes = (Class extends BeanFactoryPostProcessor>[]) new Class>[0];
factory.setBeanFactoryPostProcessorClasses(classes);
@@ -72,7 +72,7 @@ public class ClassPathXmlApplicationContextFactoryTests {
@Test
public void testBeanFactoryConfigurationNotCopied() {
factory.setApplicationContext(new ClassPathXmlApplicationContext(ClassUtils.addResourcePathToPackagePath(getClass(), "parent-context.xml")));
- factory.setPath(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
+ factory.setResource(new ClassPathResource(ClassUtils.addResourcePathToPackagePath(getClass(), "child-context.xml")));
factory.setCopyConfiguration(false);
ConfigurableApplicationContext context = factory.createApplicationContext();
assertEquals("test-job", context.getBeanNamesForType(Job.class)[0]);
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java
index c5ba04c75..1c94c2673 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java
@@ -30,7 +30,6 @@ import org.springframework.util.ClassUtils;
* @author Dave Syer
*
*/
-@SuppressWarnings("deprecation")
public class OsgiBundleXmlApplicationContextFactoryTests {
private OsgiBundleXmlApplicationContextFactory factory = new OsgiBundleXmlApplicationContextFactory();
diff --git a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java
index f2d817698..43db9ca37 100644
--- a/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java
+++ b/spring-batch-core/src/test/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java
@@ -48,6 +48,14 @@ public class JobRegistryBackgroundJobRunnerTests {
assertEquals(0, JobRegistryBackgroundJobRunner.getErrors().size());
}
+ @Test
+ public void testMainWithJobLoader() throws Exception {
+ JobRegistryBackgroundJobRunner.main(
+ ClassUtils.addResourcePathToPackagePath(getClass(), "test-environment-with-loader.xml"), ClassUtils
+ .addResourcePathToPackagePath(getClass(), "job.xml"));
+ assertEquals(0, JobRegistryBackgroundJobRunner.getErrors().size());
+ }
+
@Before
public void setUp() throws Exception {
JobRegistryBackgroundJobRunner.getErrors().clear();
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml
new file mode 100644
index 000000000..e124e6e83
--- /dev/null
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml
deleted file mode 100644
index f9b49e6d2..000000000
--- a/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
diff --git a/spring-batch-core/src/test/resources/org/springframework/batch/core/launch/support/test-environment-with-loader.xml b/spring-batch-core/src/test/resources/org/springframework/batch/core/launch/support/test-environment-with-loader.xml
new file mode 100644
index 000000000..4255234ad
--- /dev/null
+++ b/spring-batch-core/src/test/resources/org/springframework/batch/core/launch/support/test-environment-with-loader.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml b/spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml
index 33b0eb244..d30b8d632 100644
--- a/spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml
+++ b/spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml
@@ -1,46 +1,48 @@
-
-
+
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+