StepRegistry is now a first-class (optional) component:
- MapJobRegistry no longer implements StepRegistry - DefaultJobLoader updates the stepRegistry when it is available - Added more tests to cover the cases where the step registry is not available
This commit is contained in:
committed by
Michael Minella
parent
2870628c85
commit
8abd2ec69f
@@ -38,10 +38,12 @@ import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link JobLoader}. Uses a {@link JobRegistry} to
|
||||
* manage a population of loaded jobs and clears them up when asked.
|
||||
* manage a population of loaded jobs and clears them up when asked. An optional
|
||||
* {@link StepRegistry} might also be set to register the step(s) available for
|
||||
* each registered job.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
|
||||
@@ -63,14 +65,11 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
|
||||
/**
|
||||
* Creates a job loader with the job registry provided.
|
||||
* <p/>
|
||||
* If the specified {@link JobRegistry} is also a {@link StepRegistry} it
|
||||
* is registered as the step registry to use for this instance.
|
||||
*
|
||||
* @param jobRegistry a {@link JobRegistry}
|
||||
*/
|
||||
public DefaultJobLoader(JobRegistry jobRegistry) {
|
||||
this(jobRegistry, jobRegistry instanceof StepRegistry ? (StepRegistry) jobRegistry : null);
|
||||
this(jobRegistry, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -91,9 +90,6 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
*/
|
||||
public void setJobRegistry(JobRegistry jobRegistry) {
|
||||
this.jobRegistry = jobRegistry;
|
||||
if (stepRegistry == null && jobRegistry instanceof StepRegistry) {
|
||||
setStepRegistry((StepRegistry) jobRegistry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,8 +114,7 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
}
|
||||
}
|
||||
for (String jobName : jobRegistry.getJobNames()) {
|
||||
jobRegistry.unregister(jobName);
|
||||
stepRegistry.unregisterStepsFromJob(jobName);
|
||||
doUnregister(jobName);
|
||||
}
|
||||
contexts.clear();
|
||||
}
|
||||
@@ -131,8 +126,7 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
ConfigurableApplicationContext context = contexts.get(factory);
|
||||
for (String name : contextToJobNames.get(context)) {
|
||||
logger.debug("Unregistering job: " + name + " from context: " + context.getDisplayName());
|
||||
jobRegistry.unregister(name);
|
||||
stepRegistry.unregisterStepsFromJob(name);
|
||||
doUnregister(name);
|
||||
}
|
||||
context.close();
|
||||
}
|
||||
@@ -180,16 +174,12 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
// On reload try to unregister first
|
||||
if (unregister) {
|
||||
logger.debug("Unregistering job: " + jobName + " from context: " + context.getDisplayName());
|
||||
jobRegistry.unregister(jobName);
|
||||
stepRegistry.unregisterStepsFromJob(jobName);
|
||||
doUnregister(jobName);
|
||||
}
|
||||
|
||||
logger.debug("Registering job: " + jobName + " from context: " + context.getDisplayName());
|
||||
JobFactory jobFactory = new ReferenceJobFactory(job);
|
||||
jobRegistry.register(jobFactory);
|
||||
doRegister(context, job);
|
||||
jobsRegistered.add(jobName);
|
||||
stepRegistry.register(job.getName(), getSteps(job, context));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -213,20 +203,17 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all the {@link Step} instances defined by the specified {@link Job}.
|
||||
* Returns all the {@link Step} instances defined by the specified {@link StepLocator}.
|
||||
* <p/>
|
||||
* The specified <tt>jobApplicationContext</tt> is used to collect additional steps that
|
||||
* are not exposed by the step locator
|
||||
*
|
||||
* @param job the given job
|
||||
* @param stepLocator the given step locator
|
||||
* @param jobApplicationContext the application context of the job
|
||||
* @return all the {@link Step} defined in the given job
|
||||
* @return all the {@link Step} defined by the given step locator and context
|
||||
* @see StepLocator
|
||||
*/
|
||||
private Collection<Step> getSteps(final Job job, final ApplicationContext jobApplicationContext) {
|
||||
// TODO: that sounds like we need a stronger contract here
|
||||
if (!(job instanceof StepLocator)) {
|
||||
throw new UnsupportedOperationException("Cannot locate step from a Job that is not a StepLocator: job="
|
||||
+ job.getName() + " does not implement StepLocator");
|
||||
}
|
||||
final StepLocator stepLocator = (StepLocator) job;
|
||||
private Collection<Step> getSteps(final StepLocator stepLocator, final ApplicationContext jobApplicationContext) {
|
||||
final Collection<String> stepNames = stepLocator.getStepNames();
|
||||
final Collection<Step> result = new ArrayList<Step>();
|
||||
for (String stepName : stepNames) {
|
||||
@@ -246,9 +233,42 @@ public class DefaultJobLoader implements JobLoader, InitializingBean {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the specified {@link Job} defined in the specified {@link ConfigurableApplicationContext}.
|
||||
* <p/>
|
||||
* Makes sure to update the {@link StepRegistry} if it is available.
|
||||
*
|
||||
* @param context the context in which the job is defined
|
||||
* @param job the job to register
|
||||
* @throws DuplicateJobException if that job is already registered
|
||||
*/
|
||||
private void doRegister(ConfigurableApplicationContext context, Job job) throws DuplicateJobException {
|
||||
final JobFactory jobFactory = new ReferenceJobFactory(job);
|
||||
jobRegistry.register(jobFactory);
|
||||
|
||||
if (stepRegistry != null) {
|
||||
if (!(job instanceof StepLocator)) {
|
||||
throw new UnsupportedOperationException("Cannot locate steps from a Job that is not a StepLocator: job="
|
||||
+ job.getName() + " does not implement StepLocator");
|
||||
}
|
||||
stepRegistry.register(job.getName(), getSteps((StepLocator) job, context));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregisters the job identified by the specified <tt>jobName</tt>.
|
||||
*
|
||||
* @param jobName the name of the job to unregister
|
||||
*/
|
||||
private void doUnregister(String jobName) {
|
||||
jobRegistry.unregister(jobName);
|
||||
if (stepRegistry != null) {
|
||||
stepRegistry.unregisterStepsFromJob(jobName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() {
|
||||
Assert.notNull(jobRegistry, "Job registry could not be null.");
|
||||
Assert.notNull(stepRegistry, "Step registry could not be null. Should be set if the Job registry " +
|
||||
"implementation does not implement StepRegistry.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,15 +16,12 @@
|
||||
package org.springframework.batch.core.configuration.support;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.configuration.JobRegistry;
|
||||
import org.springframework.batch.core.configuration.StepRegistry;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -36,14 +33,13 @@ import java.util.concurrent.ConcurrentMap;
|
||||
* @author Dave Syer
|
||||
* @author Robert Fischer
|
||||
*/
|
||||
public class MapJobRegistry implements JobRegistry, StepRegistry {
|
||||
public class MapJobRegistry implements JobRegistry {
|
||||
|
||||
/**
|
||||
* The map holding the registered job factories.
|
||||
*/
|
||||
// The "final" ensures that it is visible and initialized when the constructor resolves.
|
||||
private final ConcurrentMap<String, JobFactory> map = new ConcurrentHashMap<String, JobFactory>();
|
||||
private final MapStepRegistry stepRegistry = new MapStepRegistry();
|
||||
|
||||
public void register(JobFactory jobFactory) throws DuplicateJobException {
|
||||
Assert.notNull(jobFactory);
|
||||
@@ -77,16 +73,4 @@ public class MapJobRegistry implements JobRegistry, StepRegistry {
|
||||
return Collections.unmodifiableSet(map.keySet());
|
||||
}
|
||||
|
||||
public void register(String jobName, Collection<Step> steps) throws DuplicateJobException {
|
||||
stepRegistry.register(jobName, steps);
|
||||
}
|
||||
|
||||
public void unregisterStepsFromJob(String jobName) {
|
||||
stepRegistry.unregisterStepsFromJob(jobName);
|
||||
}
|
||||
|
||||
public Step getStep(String jobName, String stepName) throws NoSuchJobException {
|
||||
return stepRegistry.getStep(jobName, stepName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ public class DefaultJobLoaderTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWithJobRegistryWhichIsAStepRegistry() {
|
||||
public void createWithOnlyJobRegistry() {
|
||||
final DefaultJobLoader loader = new DefaultJobLoader();
|
||||
loader.setJobRegistry(jobRegistry);
|
||||
|
||||
@@ -132,6 +132,43 @@ public class DefaultJobLoaderTests {
|
||||
assertStepDoNotExist("job2", "step11", "step12");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoStepRegistryAvailable() throws DuplicateJobException {
|
||||
final JobLoader loader = new DefaultJobLoader(jobRegistry);
|
||||
ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory(
|
||||
new ClassPathResource("job-context-with-steps.xml", getClass()));
|
||||
loader.load(factory);
|
||||
// No step registry available so just registering the jobs
|
||||
assertEquals(2, jobRegistry.getJobNames().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadWithJobThatIsNotAStepLocator() throws DuplicateJobException {
|
||||
ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory(
|
||||
new ByteArrayResource(BASIC_JOB_XML.getBytes()));
|
||||
try {
|
||||
jobLoader.load(factory);
|
||||
fail("Should have failed with a ["+UnsupportedOperationException.class.getName()+"] as job does not" +
|
||||
"implement StepLocator.");
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// Job is not a step locator, can't register steps
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoadWithJobThatIsNotAStepLocatorNoStepRegistry() throws DuplicateJobException {
|
||||
final JobLoader loader = new DefaultJobLoader(jobRegistry);
|
||||
ClassPathXmlApplicationContextFactory factory = new ClassPathXmlApplicationContextFactory(
|
||||
new ByteArrayResource(BASIC_JOB_XML.getBytes()));
|
||||
try {
|
||||
loader.load(factory);
|
||||
} catch (UnsupportedOperationException e) {
|
||||
fail("Should not have failed with a [" + UnsupportedOperationException.class.getName() + "] as " +
|
||||
"stepRegistry is not available for this JobLoader instance.");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReload() throws Exception {
|
||||
GenericApplicationContextFactory factory = new GenericApplicationContextFactory(new ClassPathResource(
|
||||
@@ -182,13 +219,19 @@ public class DefaultJobLoaderTests {
|
||||
}
|
||||
}
|
||||
|
||||
private static final String BASIC_JOB_XML = String
|
||||
.format(
|
||||
"<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-2.5.xsd'><bean class='%s$BasicStubJob'/></beans>",
|
||||
DefaultJobLoaderTests.class.getName());
|
||||
|
||||
private static final String JOB_XML = String
|
||||
.format(
|
||||
"<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-2.5.xsd'><bean class='%s$StubJob'/></beans>",
|
||||
DefaultJobLoaderTests.class.getName());
|
||||
|
||||
public static class StubJob implements Job, StepLocator {
|
||||
public static class BasicStubJob implements Job {
|
||||
|
||||
@Override
|
||||
public void execute(JobExecution execution) {
|
||||
@@ -213,6 +256,9 @@ public class DefaultJobLoaderTests {
|
||||
public JobParametersValidator getJobParametersValidator() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static class StubJob extends BasicStubJob implements StepLocator {
|
||||
|
||||
@Override
|
||||
public Collection<String> getStepNames() {
|
||||
|
||||
@@ -21,8 +21,6 @@ import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.core.configuration.DuplicateJobException;
|
||||
import org.springframework.batch.core.configuration.JobFactory;
|
||||
import org.springframework.batch.core.configuration.support.MapJobRegistry;
|
||||
import org.springframework.batch.core.configuration.support.ReferenceJobFactory;
|
||||
import org.springframework.batch.core.job.JobSupport;
|
||||
import org.springframework.batch.core.launch.NoSuchJobException;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user