BATCH-1474: Added reload() feature to JobLoader.
This commit is contained in:
@@ -53,14 +53,27 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
private Resource resource;
|
||||
|
||||
private ConfigurableApplicationContext parent;
|
||||
|
||||
|
||||
private boolean copyConfiguration = true;
|
||||
|
||||
private Collection<Class<? extends BeanFactoryPostProcessor>> beanFactoryPostProcessorClasses;
|
||||
|
||||
private Collection<Class<?>> beanPostProcessorExcludeClasses;
|
||||
|
||||
/**
|
||||
* Convenient constructor for configuration purposes.
|
||||
*/
|
||||
public ClassPathXmlApplicationContextFactory() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a factory instance with the resource specified. The resource is a
|
||||
* Spring XML configuration file.
|
||||
*/
|
||||
public ClassPathXmlApplicationContextFactory(Resource resource) {
|
||||
|
||||
this.resource = resource;
|
||||
beanFactoryPostProcessorClasses = new ArrayList<Class<? extends BeanFactoryPostProcessor>>();
|
||||
beanFactoryPostProcessorClasses.add(PropertyPlaceholderConfigurer.class);
|
||||
beanFactoryPostProcessorClasses.add(CustomEditorConfigurer.class);
|
||||
@@ -80,7 +93,8 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
* {@link ApplicationContext}. Use imports to centralise the configuration
|
||||
* in one file.
|
||||
*
|
||||
* @param resource 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 setResource(Resource resource) {
|
||||
this.resource = resource;
|
||||
@@ -156,7 +170,7 @@ 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) {
|
||||
if (applicationContext == null) {
|
||||
return;
|
||||
}
|
||||
Assert.isInstanceOf(ConfigurableApplicationContext.class, applicationContext);
|
||||
@@ -270,4 +284,24 @@ public class ClassPathXmlApplicationContextFactory implements ApplicationContext
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ClassPathXmlApplicationContextFactory [resource=" + resource + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
return toString().equals(obj.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.batch.core.configuration.support;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -29,6 +31,9 @@ import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link JobLoader}. Uses a {@link JobRegistry} to
|
||||
* manage a population of loaded jobs and clears them up when asked.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@@ -38,10 +43,12 @@ public class DefaultJobLoader implements JobLoader {
|
||||
|
||||
private JobRegistry jobRegistry;
|
||||
|
||||
private Collection<ConfigurableApplicationContext> contexts = new HashSet<ConfigurableApplicationContext>();
|
||||
|
||||
private Map<ApplicationContextFactory, ConfigurableApplicationContext> contexts = new ConcurrentHashMap<ApplicationContextFactory, ConfigurableApplicationContext>();
|
||||
|
||||
private Map<ConfigurableApplicationContext, Collection<String>> contextToJobNames = new ConcurrentHashMap<ConfigurableApplicationContext, Collection<String>>();
|
||||
|
||||
/**
|
||||
* Default constructor useful for declarative configuration.
|
||||
* Default constructor useful for declarative configuration.
|
||||
*/
|
||||
public DefaultJobLoader() {
|
||||
this(null);
|
||||
@@ -71,7 +78,7 @@ public class DefaultJobLoader implements JobLoader {
|
||||
* @see JobLoader#clear()
|
||||
*/
|
||||
public void clear() {
|
||||
for (ConfigurableApplicationContext context : contexts) {
|
||||
for (ConfigurableApplicationContext context : contexts.values()) {
|
||||
if (context.isActive()) {
|
||||
context.close();
|
||||
}
|
||||
@@ -82,22 +89,68 @@ public class DefaultJobLoader implements JobLoader {
|
||||
contexts.clear();
|
||||
}
|
||||
|
||||
public Collection<Job> reload(ApplicationContextFactory factory) {
|
||||
|
||||
// If the same factory is loaded twice the context can be closed
|
||||
if (contexts.containsKey(factory)) {
|
||||
ConfigurableApplicationContext context = contexts.get(factory);
|
||||
for (String name : contextToJobNames.get(context)) {
|
||||
logger.debug("Unregistering job: " + name + " from context: " + context.getDisplayName());
|
||||
jobRegistry.unregister(name);
|
||||
}
|
||||
context.close();
|
||||
}
|
||||
|
||||
try {
|
||||
return doLoad(factory, true);
|
||||
}
|
||||
catch (DuplicateJobException e) {
|
||||
throw new IllegalStateException("Found duplicte job in reload (it should have been unregistered "
|
||||
+ "if it was previously registered in this loader)", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Collection<Job> load(ApplicationContextFactory factory) throws DuplicateJobException {
|
||||
return doLoad(factory, false);
|
||||
}
|
||||
|
||||
private Collection<Job> doLoad(ApplicationContextFactory factory, boolean unregister) throws DuplicateJobException {
|
||||
|
||||
Collection<String> jobNamesBefore = jobRegistry.getJobNames();
|
||||
ConfigurableApplicationContext context = factory.createApplicationContext();
|
||||
Collection<String> jobNamesAfter = jobRegistry.getJobNames();
|
||||
// Try to detect auto-registration (e.g. through a bean post processor)
|
||||
boolean autoRegistrationDetected = jobRegistry.getJobNames().size() > jobNamesBefore.size();
|
||||
boolean autoRegistrationDetected = jobNamesAfter.size() > jobNamesBefore.size();
|
||||
|
||||
contexts.add(context);
|
||||
Collection<String> jobsRegistered = new HashSet<String>();
|
||||
if (autoRegistrationDetected) {
|
||||
for (String name : jobNamesAfter) {
|
||||
if (!jobNamesBefore.contains(name)) {
|
||||
jobsRegistered.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
contexts.put(factory, context);
|
||||
String[] names = context.getBeanNamesForType(Job.class);
|
||||
|
||||
Collection<Job> result = new ArrayList<Job>();
|
||||
|
||||
for (String name : names) {
|
||||
|
||||
if (!autoRegistrationDetected) {
|
||||
|
||||
// On reload try to unregister first
|
||||
if (unregister) {
|
||||
logger.debug("Unregistering job: " + name + " from context: " + context.getDisplayName());
|
||||
jobRegistry.unregister(name);
|
||||
}
|
||||
|
||||
logger.debug("Registering job: " + name + " from context: " + context.getDisplayName());
|
||||
JobFactory jobFactory = new ReferenceJobFactory((Job) context.getBean(name));
|
||||
jobRegistry.register(jobFactory);
|
||||
jobsRegistered.add(name);
|
||||
|
||||
}
|
||||
try {
|
||||
result.add(jobRegistry.getJob(name));
|
||||
@@ -106,8 +159,11 @@ public class DefaultJobLoader implements JobLoader {
|
||||
// should not happen;
|
||||
throw new IllegalStateException("Could not retrieve job that was should have been registered", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
contextToJobNames.put(context, jobsRegistered);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
@@ -20,25 +20,42 @@ 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 {
|
||||
|
||||
|
||||
/**
|
||||
* Load an application context and register all the jobs.
|
||||
*
|
||||
* @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
|
||||
* @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.
|
||||
* Load an application context and register all the jobs, having first
|
||||
* unregistered them if already registered. Implementations should also take
|
||||
* care to close and clean up the application context previously created if
|
||||
* possible (either from this factory or from one with the same jobs).
|
||||
*
|
||||
* @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> reload(ApplicationContextFactory factory);
|
||||
|
||||
/**
|
||||
* Unregister all the jobs and close all the contexts created by this
|
||||
* loader.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ package org.springframework.batch.core.configuration.support;
|
||||
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.JobLocator;
|
||||
@@ -45,6 +47,8 @@ import org.springframework.util.Assert;
|
||||
public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
|
||||
DisposableBean {
|
||||
|
||||
private static Log logger = LogFactory.getLog(JobRegistryBeanPostProcessor.class);
|
||||
|
||||
// It doesn't make sense for this to have a default value...
|
||||
private JobRegistry jobRegistry = null;
|
||||
|
||||
@@ -106,6 +110,7 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFact
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
for (String name : jobNames) {
|
||||
logger.debug("Unregistering job: " + name);
|
||||
jobRegistry.unregister(name);
|
||||
}
|
||||
jobNames.clear();
|
||||
@@ -128,8 +133,10 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFact
|
||||
}
|
||||
job = groupName==null ? job : new GroupAwareJob(groupName, job);
|
||||
ReferenceJobFactory jobFactory = new ReferenceJobFactory(job);
|
||||
String name = jobFactory.getJobName();
|
||||
logger.debug("Registering job: " + name);
|
||||
jobRegistry.register(jobFactory);
|
||||
jobNames.add(jobFactory.getJobName());
|
||||
jobNames.add(name);
|
||||
}
|
||||
catch (DuplicateJobException e) {
|
||||
throw new FatalBeanException("Cannot register job configuration", e);
|
||||
|
||||
@@ -91,4 +91,25 @@ public class OsgiBundleXmlApplicationContextFactory implements BundleContextAwar
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String bundleId = bundleContext == null ? null : (bundleContext.getBundle() == null ? bundleContext.toString()
|
||||
: "" + bundleContext.getBundle().getBundleId());
|
||||
return "OsgiBundleXmlApplicationContext [path=" + path + ", bundle=" + bundleId + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return toString().hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
return toString().equals(obj.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user