RESOLVED - issue BATCH-1338: Allow segregation of jobs by type or origin
Added groupName and extension points in JobRegistryBeanPostProcessor and ClassPathXmlJobRegistry
This commit is contained in:
@@ -32,14 +32,28 @@ public class ApplicationContextJobFactory extends AbstractGroupAwareJobFactory {
|
||||
final ApplicationContextFactory applicationContextFactory;
|
||||
|
||||
/**
|
||||
* @param groupName the name of the group that the job belongs to
|
||||
* @param jobName the id of the {@link Job} in the application context to be
|
||||
* created
|
||||
* @param applicationContextFactory a factory for an application context
|
||||
* containing a job with the job name provided
|
||||
*/
|
||||
public ApplicationContextJobFactory(ApplicationContextFactory applicationContextFactory, String jobName) {
|
||||
super(jobName);
|
||||
public ApplicationContextJobFactory(String groupName, String jobName,
|
||||
ApplicationContextFactory applicationContextFactory) {
|
||||
super(groupName, jobName);
|
||||
this.applicationContextFactory = applicationContextFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jobName the id of the {@link Job} in the application context to be
|
||||
* created
|
||||
* @param applicationContextFactory a factory for an application context
|
||||
* containing a job with the job name provided
|
||||
*/
|
||||
public ApplicationContextJobFactory(String jobName, ApplicationContextFactory applicationContextFactory) {
|
||||
this(null, jobName, applicationContextFactory);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an {@link ApplicationContext} from the factory provided and pull
|
||||
* out a bean with the name given during initialization.
|
||||
|
||||
@@ -44,7 +44,10 @@ import org.springframework.core.io.Resource;
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @since 2.0
|
||||
* @since 2.1 this class does not implement {@link JobRegistry}: it is a
|
||||
* {@link ListableJobLocator}
|
||||
*/
|
||||
public class ClassPathXmlJobRegistry implements ListableJobLocator, ApplicationContextAware, InitializingBean,
|
||||
DisposableBean {
|
||||
@@ -114,8 +117,9 @@ public class ClassPathXmlJobRegistry implements ListableJobLocator, ApplicationC
|
||||
|
||||
for (String name : names) {
|
||||
logger.debug("Registering job: " + name + " from context: " + resource);
|
||||
ApplicationContextJobFactory jobFactory = new ApplicationContextJobFactory(applicationContextFactory,
|
||||
name);
|
||||
String groupName = getGroupName(context, resource, name);
|
||||
ApplicationContextJobFactory jobFactory = new ApplicationContextJobFactory(groupName, name,
|
||||
applicationContextFactory);
|
||||
jobRegistry.register(jobFactory);
|
||||
}
|
||||
}
|
||||
@@ -126,6 +130,20 @@ public class ClassPathXmlJobRegistry implements ListableJobLocator, ApplicationC
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a group name for the job to be registered. Default
|
||||
* implementation does nothing, but provides an extension point for
|
||||
* specialised subclasses.
|
||||
*
|
||||
* @param context the application context containing the job
|
||||
* @param resource the resource that was used to create the context
|
||||
* @param jobName the jobName
|
||||
* @return a group name for the job (or null if not needed)
|
||||
*/
|
||||
protected String getGroupName(ApplicationContext context, Resource resource, String jobName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the contexts that were created in {@link #afterPropertiesSet()}.
|
||||
*
|
||||
|
||||
@@ -24,28 +24,50 @@ import org.springframework.batch.core.configuration.JobLocator;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.FatalBeanException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* A {@link BeanPostProcessor} that registers {@link Job} beans
|
||||
* with a {@link JobRegistry}. Include a bean of this type along
|
||||
* with your job configuration, and use the same
|
||||
* {@link JobRegistry} as a {@link JobLocator} when
|
||||
* you need to locate a {@link JobLocator} to launch.
|
||||
* A {@link BeanPostProcessor} that registers {@link Job} beans with a
|
||||
* {@link JobRegistry}. Include a bean of this type along with your job
|
||||
* configuration, and use the same {@link JobRegistry} as a {@link JobLocator}
|
||||
* when you need to locate a {@link Job} to launch.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobRegistryBeanPostProcessor implements BeanPostProcessor, InitializingBean, DisposableBean {
|
||||
public class JobRegistryBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware, InitializingBean,
|
||||
DisposableBean {
|
||||
|
||||
// It doesn't make sense for this to have a default value...
|
||||
private JobRegistry jobRegistry = null;
|
||||
|
||||
private Collection<String> jobNames = new HashSet<String>();
|
||||
|
||||
private String groupName = null;
|
||||
|
||||
private DefaultListableBeanFactory beanFactory;
|
||||
|
||||
/**
|
||||
* The group name for jobs registered by this component. Optional (defaults
|
||||
* to null, which means that jobs are registered with their bean names).
|
||||
* Useful where there is a hierarchy of application contexts all
|
||||
* contributing to the same {@link JobRegistry}: child contexts can then
|
||||
* define an instance with a unique group name to avoid clashes between job
|
||||
* names.
|
||||
*
|
||||
* @param groupName the groupName to set
|
||||
*/
|
||||
public void setGroupName(String groupName) {
|
||||
this.groupName = groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection setter for {@link JobRegistry}.
|
||||
*
|
||||
@@ -55,6 +77,19 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
this.jobRegistry = jobRegistry;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.beans.factory.BeanFactoryAware#setBeanFactory(org
|
||||
* .springframework.beans.factory.BeanFactory)
|
||||
*/
|
||||
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
|
||||
if (beanFactory instanceof DefaultListableBeanFactory) {
|
||||
this.beanFactory = (DefaultListableBeanFactory) beanFactory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make sure the registry is set before use.
|
||||
*
|
||||
@@ -65,8 +100,8 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
}
|
||||
|
||||
/**
|
||||
* De-register all the {@link Job} instances that were
|
||||
* regsistered by this post processor.
|
||||
* De-register all the {@link Job} instances that were regsistered by this
|
||||
* post processor.
|
||||
* @see org.springframework.beans.factory.DisposableBean#destroy()
|
||||
*/
|
||||
public void destroy() throws Exception {
|
||||
@@ -78,8 +113,7 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
|
||||
/**
|
||||
* If the bean is an instance of {@link Job} then register it.
|
||||
* @throws FatalBeanException if there is a
|
||||
* {@link DuplicateJobException}.
|
||||
* @throws FatalBeanException if there is a {@link DuplicateJobException}.
|
||||
*
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object,
|
||||
* java.lang.String)
|
||||
@@ -88,8 +122,13 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
if (bean instanceof Job) {
|
||||
Job job = (Job) bean;
|
||||
try {
|
||||
jobRegistry.register(new ReferenceJobFactory(job));
|
||||
jobNames.add(job.getName());
|
||||
String groupName = this.groupName;
|
||||
if (beanFactory != null) {
|
||||
groupName = getGroupName(beanFactory.getBeanDefinition(beanName), job);
|
||||
}
|
||||
ReferenceJobFactory jobFactory = new ReferenceJobFactory(groupName, job);
|
||||
jobRegistry.register(jobFactory);
|
||||
jobNames.add(jobFactory.getJobName());
|
||||
}
|
||||
catch (DuplicateJobException e) {
|
||||
throw new FatalBeanException("Cannot register job configuration", e);
|
||||
@@ -98,6 +137,19 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine a group name for the job to be registered. Default
|
||||
* implementation just returns the {@link #setGroupName(String) groupName}
|
||||
* configured. Provides an extension point for specialised subclasses.
|
||||
*
|
||||
* @param beanDefinition the bean definition for the job
|
||||
* @param job the job
|
||||
* @return a group name for the job (or null if not needed)
|
||||
*/
|
||||
protected String getGroupName(BeanDefinition beanDefinition, Job job) {
|
||||
return groupName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Do nothing.
|
||||
*
|
||||
@@ -107,5 +159,4 @@ public class JobRegistryBeanPostProcessor implements BeanPostProcessor, Initiali
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,12 +29,20 @@ public class ReferenceJobFactory extends AbstractGroupAwareJobFactory {
|
||||
|
||||
private Job job;
|
||||
|
||||
/**
|
||||
* @param groupName the name of the group that this job belongs to
|
||||
* @param job the {@link Job} to return from {@link #createJob()}.
|
||||
*/
|
||||
public ReferenceJobFactory(String groupName, Job job) {
|
||||
super(groupName, job.getName());
|
||||
this.job = job;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param job the {@link Job} to return from {@link #createJob()}.
|
||||
*/
|
||||
public ReferenceJobFactory(Job job) {
|
||||
super(job.getName());
|
||||
this.job = job;
|
||||
this(null, job);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -129,7 +129,7 @@ public class JobRegistryBackgroundJobRunner {
|
||||
factory.setApplicationContext(parentContext);
|
||||
factory.setPath(path);
|
||||
logger.info("Registering Job definition: " + names[k]);
|
||||
registry.register(new ApplicationContextJobFactory(factory, names[k]));
|
||||
registry.register(new ApplicationContextJobFactory(names[k], factory));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
@@ -9,20 +10,25 @@ import org.springframework.context.support.StaticApplicationContext;
|
||||
|
||||
public class ApplicationContextJobFactoryTests {
|
||||
|
||||
private AbstractGroupAwareJobFactory factory = new ApplicationContextJobFactory(
|
||||
new StubApplicationContextFactory(), "job");
|
||||
|
||||
@Test
|
||||
public void testFactoryContext() throws Exception {
|
||||
ApplicationContextJobFactory factory = new ApplicationContextJobFactory("job",
|
||||
new StubApplicationContextFactory());
|
||||
assertNotNull(factory.createJob());
|
||||
}
|
||||
|
||||
private static class StubApplicationContextFactory implements
|
||||
ApplicationContextFactory {
|
||||
@Test
|
||||
public void testGroupName() throws Exception {
|
||||
ApplicationContextJobFactory factory = new ApplicationContextJobFactory("jobs", "job",
|
||||
new StubApplicationContextFactory());
|
||||
assertEquals("jobs$job", factory.getJobName());
|
||||
}
|
||||
|
||||
private static class StubApplicationContextFactory implements ApplicationContextFactory {
|
||||
public ConfigurableApplicationContext createApplicationContext() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
context.registerSingleton("job", JobSupport.class);
|
||||
return context ;
|
||||
return context;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,10 +15,14 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
@@ -29,11 +33,12 @@ import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobRegistryBeanPostProcessorTests extends TestCase {
|
||||
public class JobRegistryBeanPostProcessorTests {
|
||||
|
||||
private JobRegistryBeanPostProcessor processor = new JobRegistryBeanPostProcessor();
|
||||
|
||||
public void testInitialization() throws Exception {
|
||||
@Test
|
||||
public void testInitializationFails() throws Exception {
|
||||
try {
|
||||
processor.afterPropertiesSet();
|
||||
fail("Expected IllegalArgumentException");
|
||||
@@ -44,33 +49,48 @@ public class JobRegistryBeanPostProcessorTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeInitialization() throws Exception {
|
||||
// should be a no-op
|
||||
assertEquals("foo", processor.postProcessAfterInitialization("foo", "bar"));
|
||||
assertEquals("foo", processor.postProcessBeforeInitialization("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterInitializationWithWrongType() throws Exception {
|
||||
// should be a no-op
|
||||
assertEquals("foo", processor.postProcessAfterInitialization("foo", "bar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterInitializationWithCorrectType() throws Exception {
|
||||
MapJobRegistry registry = new MapJobRegistry();
|
||||
processor.setJobRegistry(registry);
|
||||
JobSupport configuration = new JobSupport();
|
||||
configuration.setBeanName("foo");
|
||||
assertEquals(configuration, processor.postProcessAfterInitialization(configuration, "bar"));
|
||||
assertEquals(configuration.getName(), registry.getJob("foo").getName());
|
||||
JobSupport job = new JobSupport();
|
||||
job.setBeanName("foo");
|
||||
assertEquals(job, processor.postProcessAfterInitialization(job, "bar"));
|
||||
assertEquals(job.getName(), registry.getJob("foo").getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterInitializationWithGroupName() throws Exception {
|
||||
MapJobRegistry registry = new MapJobRegistry();
|
||||
processor.setJobRegistry(registry);
|
||||
processor.setGroupName("jobs");
|
||||
JobSupport job = new JobSupport();
|
||||
job.setBeanName("foo");
|
||||
assertEquals(job, processor.postProcessAfterInitialization(job, "bar"));
|
||||
assertEquals("[jobs$foo]", registry.getJobNames().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAfterInitializationWithDuplicate() throws Exception {
|
||||
MapJobRegistry registry = new MapJobRegistry();
|
||||
processor.setJobRegistry(registry);
|
||||
JobSupport configuration = new JobSupport();
|
||||
configuration.setBeanName("foo");
|
||||
processor.postProcessAfterInitialization(configuration, "bar");
|
||||
JobSupport job = new JobSupport();
|
||||
job.setBeanName("foo");
|
||||
processor.postProcessAfterInitialization(job, "bar");
|
||||
try {
|
||||
processor.postProcessAfterInitialization(configuration, "spam");
|
||||
processor.postProcessAfterInitialization(job, "spam");
|
||||
fail("Expected FatalBeanException");
|
||||
}
|
||||
catch (FatalBeanException e) {
|
||||
@@ -79,12 +99,13 @@ public class JobRegistryBeanPostProcessorTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUnregisterOnDestroy() throws Exception {
|
||||
MapJobRegistry registry = new MapJobRegistry();
|
||||
processor.setJobRegistry(registry);
|
||||
JobSupport configuration = new JobSupport();
|
||||
configuration.setBeanName("foo");
|
||||
assertEquals(configuration, processor.postProcessAfterInitialization(configuration, "bar"));
|
||||
JobSupport job = new JobSupport();
|
||||
job.setBeanName("foo");
|
||||
assertEquals(job, processor.postProcessAfterInitialization(job, "bar"));
|
||||
processor.destroy();
|
||||
try {
|
||||
assertEquals(null, registry.getJob("foo"));
|
||||
@@ -95,6 +116,7 @@ public class JobRegistryBeanPostProcessorTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecutionWithApplicationContext() throws Exception {
|
||||
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("test-context.xml", getClass());
|
||||
MapJobRegistry registry = (MapJobRegistry) context.getBean("registry");
|
||||
@@ -117,4 +139,5 @@ public class JobRegistryBeanPostProcessorTests extends TestCase {
|
||||
assertEquals(context.getBean("test-job-with-concrete-parent-and-name"), registry.getJob("oof"));
|
||||
assertEquals(context.getBean("test-job-with-concrete-parent-and-bean-name"), registry.getJob("rab"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* 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 static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ReferenceJobFactoryTests {
|
||||
|
||||
@Test
|
||||
public void testGroupName() throws Exception {
|
||||
ReferenceJobFactory factory = new ReferenceJobFactory("jobs", new JobSupport("foo"));
|
||||
assertEquals("jobs$foo", factory.getJobName());
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user