Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

BATCH-1473: Refactored context creation components

  • Loading branch information...
commit 891ff55bf0629c52c6c485b50c60486ce228dd7f 1 parent 4911ea7
dsyer authored
Showing with 748 additions and 363 deletions.
  1. +1 −1  spring-batch-core/.springBeans
  2. +167 −0 ...ng-batch-core/src/main/java/org/springframework/batch/core/configuration/support/AutomaticJobRegistrar.java
  3. +57 −21 ...c/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java
  4. +0 −208 ...ng-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoader.java
  5. +1 −1  ...-batch-core/src/main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java
  6. +166 −0 ...n/java/org/springframework/batch/core/configuration/support/ClasspathXmlApplicationContextsFactoryBean.java
  7. +115 −0 spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/DefaultJobLoader.java
  8. +1 −1  spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java
  9. +44 −0 spring-batch-core/src/main/java/org/springframework/batch/core/configuration/support/JobLoader.java
  10. +3 −3 .../main/java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java
  11. +47 −50 ...-batch-core/src/main/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
  12. +1 −1  ...onfiguration/support/{ClassPathXmlJobLoaderContextTests.java → AutomaticJobRegistrarContextTests.java}
  13. +68 −35 ...k/batch/core/configuration/support/{ClassPathXmlJobLoaderTests.java → AutomaticJobRegistrarTests.java}
  14. +5 −5 ...t/java/org/springframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java
  15. +0 −1  .../java/org/springframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java
  16. +8 −0 ...h-core/src/test/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java
  17. +20 −0 ...esources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml
  18. +0 −12 ...esources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml
  19. +18 −0 ...atch-core/src/test/resources/org/springframework/batch/core/launch/support/test-environment-with-loader.xml
  20. +26 −24 spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml
View
2  spring-batch-core/.springBeans
@@ -64,7 +64,6 @@
<config>src/test/resources/org/springframework/batch/core/scope/util/PlaceholderTargetSourceErrorTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/support/child-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementParentAttributeParserTests-context.xml</config>
- <config>src/test/resources/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/DuplicateTransitionJobParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/launch/support/error.xml</config>
<config>src/test/resources/org/springframework/batch/core/step/item/FaultTolerantExceptionClassesTests-context.xml</config>
@@ -103,6 +102,7 @@
<config>src/test/resources/org/springframework/batch/core/configuration/xml/PartitionStepParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/ChunkElementSkipPolicyParserTests-context.xml</config>
<config>src/test/resources/org/springframework/batch/core/configuration/xml/JobStepParserTests-context.xml</config>
+ <config>src/test/resources/org/springframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml</config>
</configs>
<configSets>
<configSet>
View
167 ...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<ApplicationContextFactory> applicationContextFactories = new ArrayList<ApplicationContextFactory>();
+
+ 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;
+ }
+ }
+
+}
View
78 ...ringframework/batch/core/configuration/support/ClassPathXmlApplicationContextFactory.java
@@ -18,9 +18,14 @@
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 @@
*/
public class ClassPathXmlApplicationContextFactory implements ApplicationContextFactory, ApplicationContextAware {
- private ConfigurableApplicationContext parent;
-
- private Resource path;
+ private static final Log logger = LogFactory.getLog(ClassPathXmlApplicationContextFactory.class);
- private ResourceXmlApplicationContext context;
+ private Resource resource;
+ private ConfigurableApplicationContext parent;
+
private boolean copyConfiguration = true;
private Collection<Class<? extends BeanFactoryPostProcessor>> beanFactoryPostProcessorClasses;
- private final Object lock = new Object();
+ private Collection<Class<?>> beanPostProcessorExcludeClasses;
public ClassPathXmlApplicationContextFactory() {
beanFactoryPostProcessorClasses = new ArrayList<Class<? extends BeanFactoryPostProcessor>>();
beanFactoryPostProcessorClasses.add(PropertyPlaceholderConfigurer.class);
beanFactoryPostProcessorClasses.add(CustomEditorConfigurer.class);
+ beanPostProcessorExcludeClasses = new ArrayList<Class<?>>();
+ /*
+ * 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 ClassPathXmlApplicationContextFactory() {
* {@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;
}
/**
@@ -110,6 +124,23 @@ public void setBeanFactoryPostProcessorClasses(
}
/**
+ * 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<Class<?>>();
+ 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 void setBeanFactoryPostProcessorClasses(
* @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 void setApplicationContext(ApplicationContext applicationContext) throws
*/
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 @@ protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
@Override
protected Resource[] getConfigResources() {
- return new Resource[] { path };
+ return new Resource[] { resource };
}
}
@@ -218,7 +244,8 @@ protected void prepareContext(ConfigurableApplicationContext parent, Configurabl
/**
* 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 @@ protected void prepareContext(ConfigurableApplicationContext parent, Configurabl
protected void prepareBeanFactory(DefaultListableBeanFactory parent, DefaultListableBeanFactory beanFactory) {
if (copyConfiguration && parent != null) {
beanFactory.copyConfigurationFrom(parent);
+ @SuppressWarnings("unchecked")
+ List<BeanPostProcessor> beanPostProcessors = beanFactory.getBeanPostProcessors();
+ for (BeanPostProcessor beanPostProcessor : new ArrayList<BeanPostProcessor>(beanPostProcessors)) {
+ for (Class<?> cls : beanPostProcessorExcludeClasses) {
+ if (cls.isAssignableFrom(beanPostProcessor.getClass())) {
+ logger.debug("Removing bean post processor: " + beanPostProcessor + " of type " + cls);
+ beanPostProcessors.remove(beanPostProcessor);
+ }
+ }
+ }
}
}
-
}
View
208 ...main/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobLoader.java
@@ -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<Resource> jobPaths;
-
- private ApplicationContext parent;
-
- private JobRegistry jobRegistry;
-
- private Collection<ConfigurableApplicationContext> contexts = new HashSet<ConfigurableApplicationContext>();
-
- /**
- * 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.
- * <code>classpath*:/config/*-job-context.xml</code>).
- *
- * @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();
-
- }
-
-}
View
2  ...in/java/org/springframework/batch/core/configuration/support/ClassPathXmlJobRegistry.java
@@ -5,7 +5,7 @@
*
* @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 {
View
166 ...ramework/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<Resource> resources = new ArrayList<Resource>();
+
+ 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.
+ * <code>classpath*:/config/*-context.xml</code>).
+ *
+ * @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<ApplicationContextFactory> applicationContextFactories = new ArrayList<ApplicationContextFactory>();
+ 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;
+ }
+
+}
View
115 .../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<ConfigurableApplicationContext> contexts = new HashSet<ConfigurableApplicationContext>();
+
+ /**
+ * 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<Job> load(ApplicationContextFactory factory) throws DuplicateJobException {
+
+ Collection<String> 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<Job> result = new ArrayList<Job>();
+
+ 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;
+
+ }
+
+}
View
2  ...ore/src/main/java/org/springframework/batch/core/configuration/support/GroupAwareJob.java
@@ -24,7 +24,7 @@
* to make it fit a naming convention for type or origin. E.g. the source job
* might be <code>overnightJob</code> and the group
* <code>financeDepartment</code>, which would result in a {@link Job} with
- * identical functionality but named <code>financeDepartment$overnightJob</code>
+ * identical functionality but named <code>financeDepartment.overnightJob</code>
* . The use of a "." separator for elements is deliberate, since it is a "safe"
* character in a <a href="http://www.w3.org/Addressing/URL">URL</a>.
*
View
44 ...ch-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<Job> load(ApplicationContextFactory factory) throws DuplicateJobException;
+
+ /**
+ * Unregister all the jobs and close all the contexts created by this loader.
+ */
+ void clear();
+
+}
View
6 ...ingframework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactory.java
@@ -25,10 +25,10 @@
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,
View
97 ...in/java/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunner.java
@@ -18,9 +18,7 @@
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.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 @@
private static Log logger = LogFactory.getLog(JobRegistryBackgroundJobRunner.class);
- private JobRegistry registry;
+ private JobLoader jobLoader;
private ApplicationContext parentContext = null;
@@ -82,7 +79,7 @@
final private String parentContextPath;
- private Collection<ConfigurableApplicationContext> contexts = new HashSet<ConfigurableApplicationContext>();
+ private JobRegistry jobRegistry;
private static List<Exception> errors = Collections.synchronizedList(new ArrayList<Exception>());
@@ -95,11 +92,21 @@ public JobRegistryBackgroundJobRunner(String parentContextPath) {
}
/**
- * 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 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 setRegistry(JobRegistry registry) {
- this.registry = registry;
+ public void setJobRegistry(JobRegistry jobRegistry) {
+ this.jobRegistry = jobRegistry;
}
/**
@@ -115,9 +122,10 @@ public void setRegistry(JobRegistry registry) {
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 @@ private void register(String[] paths) throws DuplicateJobException, IOException
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<String> 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 @@ private void register(String[] paths) throws DuplicateJobException, IOException
}
/**
- * 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;
+ }
+
+ 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;
+ }
}
- return applicationContextFactory.createApplicationContext();
+
+ jobLoader = (JobLoader) parentContext.getBean(names[0], JobLoader.class);
+ return;
+
}
/**
@@ -249,15 +254,7 @@ public void run() {
* @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() {
View
2  ...rt/ClassPathXmlJobLoaderContextTests.java → ...rt/AutomaticJobRegistrarContextTests.java
@@ -21,7 +21,7 @@
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
-public class ClassPathXmlJobLoaderContextTests {
+public class AutomaticJobRegistrarContextTests {
@Autowired
private JobRegistry registry;
View
103 ...n/support/ClassPathXmlJobLoaderTests.java → ...n/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 @@
/**
*
- *
+ * @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 void testLocateJob() throws Exception {
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<String> names = registry.getJobNames();
assertEquals(2, names.size());
@@ -58,16 +63,16 @@ public void testLocateJob() throws Exception {
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 void testDuplicateJobsInFile() 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());
}
@@ -88,10 +93,11 @@ public void testChildContextOverridesBeanPostProcessor() throws Exception {
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 void testErrorInContext() throws Exception {
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 void testErrorInContext() throws Exception {
}
@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<ApplicationContextFactory> applicationContextFactories = new ArrayList<ApplicationContextFactory>();
+ 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]));
+ }
+
}
View
10 ...ramework/batch/core/configuration/support/ClassPathXmlApplicationContextFactoryTests.java
@@ -36,20 +36,20 @@
@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 void testParentConfigurationInherited() {
@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 void testBeanFactoryPostProcessorsNotCopied() {
@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]);
View
1  ...amework/batch/core/configuration/support/OsgiBundleXmlApplicationContextFactoryTests.java
@@ -30,7 +30,6 @@
* @author Dave Syer
*
*/
-@SuppressWarnings("deprecation")
public class OsgiBundleXmlApplicationContextFactoryTests {
private OsgiBundleXmlApplicationContextFactory factory = new OsgiBundleXmlApplicationContextFactory();
View
8 ...va/org/springframework/batch/core/launch/support/JobRegistryBackgroundJobRunnerTests.java
@@ -48,6 +48,14 @@ public void testMainWithAutoRegister() throws Exception {
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();
View
20 ...gframework/batch/core/configuration/support/AutomaticJobRegistrarContextTests-context.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
+
+ <bean class="org.springframework.batch.core.configuration.support.AutomaticJobRegistrar">
+ <property name="applicationContextFactories">
+ <bean class="org.springframework.batch.core.configuration.support.ClasspathXmlApplicationContextsFactoryBean">
+ <property name="resources" value="classpath*:org/springframework/batch/core/launch/support/job*.xml" />
+ </bean>
+ </property>
+ <property name="jobLoader">
+ <bean class="org.springframework.batch.core.configuration.support.DefaultJobLoader">
+ <property name="jobRegistry" ref="jobRegistry" />
+ </bean>
+ </property>
+ </bean>
+
+ <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
+
+</beans>
View
12 ...gframework/batch/core/configuration/support/ClassPathXmlJobLoaderContextTests-context.xml
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
-
- <bean class="org.springframework.batch.core.configuration.support.ClassPathXmlJobLoader">
- <property name="jobPaths" value="classpath*:org/springframework/batch/core/launch/support/job*.xml" />
- <property name="jobRegistry" ref="jobRegistry"/>
- </bean>
-
- <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
-
-</beans>
View
18 .../resources/org/springframework/batch/core/launch/support/test-environment-with-loader.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
+ xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
+ http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
+ http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
+
+ <import resource="test-environment.xml" />
+
+ <bean id="jobLoader" class="org.springframework.batch.core.configuration.support.DefaultJobLoader">
+ <property name="jobRegistry" ref="jobRegistry"/>
+ </bean>
+
+ <bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
+
+</beans>
View
50 spring-batch-samples/src/main/resources/skipSample-job-launcher-context.xml
@@ -1,46 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:batch="http://www.springframework.org/schema/batch"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:p="http://www.springframework.org/schema/p"
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:batch="http://www.springframework.org/schema/batch"
+ xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<import resource="data-source-context.xml" />
<import resource="classpath:/org/springframework/batch/sample/config/common-context.xml" />
-
+
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
-
- <bean id="jobRepository"
- class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
+
+ <bean id="jobRepository" class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
-
- <bean id="mapJobRepository"
- class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
+
+ <bean id="mapJobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"
lazy-init="true" autowire-candidate="false" />
-
- <bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator"
- p:jobLauncher-ref="jobLauncher" p:jobExplorer-ref="jobExplorer" p:jobRepository-ref="jobRepository"
- p:jobRegistry-ref="jobRegistry" />
-
- <bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
+
+ <bean id="jobOperator" class="org.springframework.batch.core.launch.support.SimpleJobOperator" p:jobLauncher-ref="jobLauncher"
+ p:jobExplorer-ref="jobExplorer" p:jobRepository-ref="jobRepository" p:jobRegistry-ref="jobRegistry" />
+
+ <bean id="jobExplorer" class="org.springframework.batch.core.explore.support.JobExplorerFactoryBean"
p:dataSource-ref="dataSource" />
-
- <bean id="jobLoader" class="org.springframework.batch.core.configuration.support.ClassPathXmlJobLoader" >
- <property name="jobPaths" value="jobs/skipSampleJob.xml" />
- <property name="jobRegistry" ref="jobRegistry"/>
+
+ <bean class="org.springframework.batch.core.configuration.support.AutomaticJobRegistrar">
+ <property name="applicationContextFactories">
+ <bean class="org.springframework.batch.core.configuration.support.ClasspathXmlApplicationContextsFactoryBean">
+ <property name="resources" value="classpath*:jobs/skipSampleJob.xml" />
+ </bean>
+ </property>
+ <property name="jobLoader">
+ <bean class="org.springframework.batch.core.configuration.support.DefaultJobLoader">
+ <property name="jobRegistry" ref="jobRegistry" />
+ </bean>
+ </property>
</bean>
<bean id="jobRegistry" class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
-
+
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource" />
</bean>
-
+
<bean id="logAdvice" class="org.springframework.batch.sample.common.LogAdvice" />
</beans>
Please sign in to comment.
Something went wrong with that request. Please try again.