IN PROGRESS - issue BATCH-24: Provide exit code for job executed as a main method
http://opensource.atlassian.com/projects/spring/browse/BATCH-24 Applied Stijn's refactoring of ExitCodes and moved BatchCommandLineLauncher to bootstrap.support
This commit is contained in:
@@ -1,78 +1,81 @@
|
||||
/*
|
||||
* 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.execution.bootstrap;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.runtime.JobIdentifier;
|
||||
import org.springframework.batch.execution.facade.JobExecutorFacade;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* Simple interface for controlling jobs from the job configuration registry,
|
||||
* including possible ad-hoc executions, based on different runtime identifiers.
|
||||
* Implementations should concentrate on managing jobs and delegate the
|
||||
* launching to a {@link JobExecutorFacade}.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
*/
|
||||
|
||||
public interface JobLauncher {
|
||||
|
||||
/**
|
||||
* Start a job execution with default name and other runtime information
|
||||
* generated on the fly.<br/>
|
||||
*
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
*
|
||||
*/
|
||||
public ExitStatus run() throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given name and other runtime information
|
||||
* generated on the fly.
|
||||
*
|
||||
* @param name
|
||||
* the name to assign to the job
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(String jobName)
|
||||
throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given runtime information.
|
||||
*
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Stop the current job executions if there are any. If not, no action will
|
||||
* be taken.
|
||||
*
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
*/
|
||||
public void stop();
|
||||
|
||||
/**
|
||||
* Return whether or not a job execution is currently running.
|
||||
*/
|
||||
public boolean isRunning();
|
||||
|
||||
}
|
||||
/*
|
||||
* 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.execution.bootstrap;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.runtime.JobIdentifier;
|
||||
import org.springframework.batch.execution.facade.JobExecutorFacade;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* Simple interface for controlling jobs from the job configuration registry,
|
||||
* including possible ad-hoc executions, based on different runtime identifiers.
|
||||
* Implementations should concentrate on managing jobs and delegate the
|
||||
* launching to a {@link JobExecutorFacade}.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
*/
|
||||
|
||||
public interface JobLauncher {
|
||||
|
||||
public static final String NO_SUCH_JOB_CONFIGURATION = "NO_SUCH_JOB_CONFIGURATION";
|
||||
public static final String JOB_CONFIGURATION_NOT_PROVIDED = "JOB_CONFIGURATION_NOT_PROVIDED";
|
||||
|
||||
/**
|
||||
* Start a job execution with default name and other runtime information
|
||||
* generated on the fly.<br/>
|
||||
*
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
*
|
||||
*/
|
||||
public ExitStatus run() throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given name and other runtime information
|
||||
* generated on the fly.
|
||||
*
|
||||
* @param name
|
||||
* the name to assign to the job
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(String jobName)
|
||||
throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given runtime information.
|
||||
*
|
||||
* @return the exit code from the job if it returns synchronously.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Stop the current job executions if there are any. If not, no action will
|
||||
* be taken.
|
||||
*
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
*/
|
||||
public void stop();
|
||||
|
||||
/**
|
||||
* Return whether or not a job execution is currently running.
|
||||
*/
|
||||
public boolean isRunning();
|
||||
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public interface JvmExitCodeMapper extends ExitCodeMapper {
|
||||
|
||||
static int JVM_EXITCODE_COMPLETED = 0;
|
||||
static int JVM_EXITCODE_GENERIC_ERROR = 1;
|
||||
static int JVM_EXITCODE_NO_SUCH_JOBCONFIGURATION = 2;
|
||||
static int JVM_EXITCODE_JOB_CONFIGURATION_ERROR = 2;
|
||||
|
||||
/**
|
||||
* Transform the exitcode known by the batchframework into a JVM return
|
||||
|
||||
@@ -1,192 +1,192 @@
|
||||
/*
|
||||
* 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.execution.bootstrap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.configuration.JobConfiguration;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.runtime.JobIdentifier;
|
||||
import org.springframework.batch.core.runtime.JobIdentifierFactory;
|
||||
import org.springframework.batch.execution.facade.JobExecutorFacade;
|
||||
import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple bootstrapping mechanism for running a single job execution in a
|
||||
* {@link JobExecutorFacade}.
|
||||
*
|
||||
* <p>
|
||||
* This simple implementation does not run the job asynchronously, so the start
|
||||
* method will not return before the job ends. However, the job execution to be
|
||||
* interrupted via the stop method in another thread.
|
||||
* </p>
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
* @since 2.1
|
||||
*/
|
||||
public class SimpleJobLauncher implements JobLauncher {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SimpleJobLauncher.class);
|
||||
|
||||
private volatile Thread processingThread;
|
||||
|
||||
private volatile boolean running = false;
|
||||
|
||||
private JobExecutorFacade jobExecutorFacade;
|
||||
|
||||
private JobIdentifierFactory jobIdentifierFactory = new ScheduledJobIdentifierFactory();;
|
||||
|
||||
private String jobConfigurationName;
|
||||
|
||||
/**
|
||||
* Check that mandatory properties are set.
|
||||
*
|
||||
* @see #setJobExecutorFacade(JobExecutorFacade)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(jobExecutorFacade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the container is currently running. This is done by
|
||||
* checking the thread to see if it is still alive.
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return running && processingThread != null && processingThread.isAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the provided facade. The current thread will first be saved.
|
||||
* This may seem odd at first, however, this simple bootstrap requires that
|
||||
* only one thread can kick off a container, and that the first thread that
|
||||
* calls start is the 'processing thread'. If the container has already been
|
||||
* started, no exception will be thrown.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* @see Lifecycle#start().
|
||||
*
|
||||
* @throws IllegalStateException if JobConfiguration is null.
|
||||
*/
|
||||
public ExitStatus run(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException {
|
||||
|
||||
Assert.notNull(jobIdentifier, "JobIdentifier must not be null.");
|
||||
Assert.isTrue(!isRunning(), "SynchronousLaunchers can run only one job at at time.");
|
||||
|
||||
/*
|
||||
* There is no reason to kick off a new thread, since only one thread
|
||||
* should be processing at once. However, a handle to the thread should
|
||||
* be maintained to allow for interrupt
|
||||
*/
|
||||
processingThread = Thread.currentThread();
|
||||
|
||||
running = true;
|
||||
try {
|
||||
return jobExecutorFacade.start(jobIdentifier);
|
||||
}
|
||||
finally {
|
||||
running = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a job execution with the given name. If a job is already running
|
||||
* has no effect.
|
||||
*
|
||||
* @param name the name to assign to the job
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(String name) throws NoSuchJobConfigurationException {
|
||||
JobIdentifier runtimeInformation = jobIdentifierFactory.getJobIdentifier(name);
|
||||
return this.run(runtimeInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a job execution with default name and other runtime information
|
||||
* provided by the factory. If a job is already running has no effect. The
|
||||
* default name is taken from the enclosed {@link JobConfiguration}.
|
||||
* @throws NoSuchJobConfigurationException if the job configuration cannot be located
|
||||
*
|
||||
* @see #setJobIdentifierFactory(JobIdentifierFactory)
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
*/
|
||||
public ExitStatus run(){
|
||||
if (jobConfigurationName==null) {
|
||||
return new ExitStatus(false, "JOB_CONFIGURATION_NOT_PROVIDED", "No JobConfiguration was " +
|
||||
"provided to the launcher.");
|
||||
}
|
||||
try {
|
||||
return this.run(jobConfigurationName);
|
||||
}
|
||||
catch (NoSuchJobConfigurationException e) {
|
||||
logger.error("JobExecutorFacade failed to find a JobConfiguration" +
|
||||
" for the provided JobIdentifier", e);
|
||||
return new ExitStatus(false, "NO_SUCH_JOB_CONFIGURATION", "JobExecutor Facade failed" +
|
||||
"to find a JobConfiguration for the provided JobIdentifier");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the job if it is running by interrupting its thread. If no job is
|
||||
* running, no action will be taken.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
*/
|
||||
public void stop() {
|
||||
|
||||
if (isRunning()) {
|
||||
processingThread.interrupt();
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The facade to which job launching will be delegated.
|
||||
*
|
||||
* @param jobExecutorFacade a {@link JobExecutorFacade}.
|
||||
*/
|
||||
public void setJobExecutorFacade(JobExecutorFacade jobExecutorFacade) {
|
||||
this.jobExecutorFacade = jobExecutorFacade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for injecting {@link JobIdentifierFactory}. When a job is
|
||||
* launched by name the factory needs to be used to create a new identifier
|
||||
* for it. Defaults to a {@link ScheduledJobIdentifierFactory}.
|
||||
*
|
||||
* @param jobIdentifierFactory
|
||||
* the {@link JobIdentifierFactory} to use when constructing
|
||||
* identifiers for jobs.
|
||||
*/
|
||||
public void setJobIdentifierFactory(
|
||||
JobIdentifierFactory jobIdentifierFactory) {
|
||||
this.jobIdentifierFactory = jobIdentifierFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the default job configuration name to launch if none is specified.
|
||||
*
|
||||
* @param jobConfigurationName the name of a {@link JobConfiguration} in the registry.
|
||||
*/
|
||||
public void setJobConfigurationName(String jobConfigurationName) {
|
||||
this.jobConfigurationName = jobConfigurationName;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 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.execution.bootstrap;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.configuration.JobConfiguration;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.runtime.JobIdentifier;
|
||||
import org.springframework.batch.core.runtime.JobIdentifierFactory;
|
||||
import org.springframework.batch.execution.facade.JobExecutorFacade;
|
||||
import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Simple bootstrapping mechanism for running a single job execution in a
|
||||
* {@link JobExecutorFacade}.
|
||||
*
|
||||
* <p>
|
||||
* This simple implementation does not run the job asynchronously, so the start
|
||||
* method will not return before the job ends. However, the job execution to be
|
||||
* interrupted via the stop method in another thread.
|
||||
* </p>
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
* @since 2.1
|
||||
*/
|
||||
public class SimpleJobLauncher implements JobLauncher {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(SimpleJobLauncher.class);
|
||||
|
||||
private volatile Thread processingThread;
|
||||
|
||||
private volatile boolean running = false;
|
||||
|
||||
private JobExecutorFacade jobExecutorFacade;
|
||||
|
||||
private JobIdentifierFactory jobIdentifierFactory = new ScheduledJobIdentifierFactory();;
|
||||
|
||||
private String jobConfigurationName;
|
||||
|
||||
/**
|
||||
* Check that mandatory properties are set.
|
||||
*
|
||||
* @see #setJobExecutorFacade(JobExecutorFacade)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(jobExecutorFacade);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return whether or not the container is currently running. This is done by
|
||||
* checking the thread to see if it is still alive.
|
||||
*/
|
||||
public boolean isRunning() {
|
||||
return running && processingThread != null && processingThread.isAlive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Start the provided facade. The current thread will first be saved.
|
||||
* This may seem odd at first, however, this simple bootstrap requires that
|
||||
* only one thread can kick off a container, and that the first thread that
|
||||
* calls start is the 'processing thread'. If the container has already been
|
||||
* started, no exception will be thrown.
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* @see Lifecycle#start().
|
||||
*
|
||||
* @throws IllegalStateException if JobConfiguration is null.
|
||||
*/
|
||||
public ExitStatus run(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException {
|
||||
|
||||
Assert.notNull(jobIdentifier, "JobIdentifier must not be null.");
|
||||
Assert.isTrue(!isRunning(), "SynchronousLaunchers can run only one job at at time.");
|
||||
|
||||
/*
|
||||
* There is no reason to kick off a new thread, since only one thread
|
||||
* should be processing at once. However, a handle to the thread should
|
||||
* be maintained to allow for interrupt
|
||||
*/
|
||||
processingThread = Thread.currentThread();
|
||||
|
||||
running = true;
|
||||
try {
|
||||
return jobExecutorFacade.start(jobIdentifier);
|
||||
}
|
||||
finally {
|
||||
running = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a job execution with the given name. If a job is already running
|
||||
* has no effect.
|
||||
*
|
||||
* @param name the name to assign to the job
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(String name) throws NoSuchJobConfigurationException {
|
||||
JobIdentifier runtimeInformation = jobIdentifierFactory.getJobIdentifier(name);
|
||||
return this.run(runtimeInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start a job execution with default name and other runtime information
|
||||
* provided by the factory. If a job is already running has no effect. The
|
||||
* default name is taken from the enclosed {@link JobConfiguration}.
|
||||
* @throws NoSuchJobConfigurationException if the job configuration cannot be located
|
||||
*
|
||||
* @see #setJobIdentifierFactory(JobIdentifierFactory)
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
*/
|
||||
public ExitStatus run(){
|
||||
if (jobConfigurationName==null) {
|
||||
return new ExitStatus(false, JOB_CONFIGURATION_NOT_PROVIDED, "No JobConfiguration was " +
|
||||
"provided to the launcher.");
|
||||
}
|
||||
try {
|
||||
return this.run(jobConfigurationName);
|
||||
}
|
||||
catch (NoSuchJobConfigurationException e) {
|
||||
logger.error("JobExecutorFacade failed to find a JobConfiguration" +
|
||||
" for the provided JobIdentifier", e);
|
||||
return new ExitStatus(false, NO_SUCH_JOB_CONFIGURATION, "JobExecutor Facade failed" +
|
||||
"to find a JobConfiguration for the provided JobIdentifier");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop the job if it is running by interrupting its thread. If no job is
|
||||
* running, no action will be taken.
|
||||
*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.context.Lifecycle#stop()
|
||||
*/
|
||||
public void stop() {
|
||||
|
||||
if (isRunning()) {
|
||||
processingThread.interrupt();
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The facade to which job launching will be delegated.
|
||||
*
|
||||
* @param jobExecutorFacade a {@link JobExecutorFacade}.
|
||||
*/
|
||||
public void setJobExecutorFacade(JobExecutorFacade jobExecutorFacade) {
|
||||
this.jobExecutorFacade = jobExecutorFacade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for injecting {@link JobIdentifierFactory}. When a job is
|
||||
* launched by name the factory needs to be used to create a new identifier
|
||||
* for it. Defaults to a {@link ScheduledJobIdentifierFactory}.
|
||||
*
|
||||
* @param jobIdentifierFactory
|
||||
* the {@link JobIdentifierFactory} to use when constructing
|
||||
* identifiers for jobs.
|
||||
*/
|
||||
public void setJobIdentifierFactory(
|
||||
JobIdentifierFactory jobIdentifierFactory) {
|
||||
this.jobIdentifierFactory = jobIdentifierFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the default job configuration name to launch if none is specified.
|
||||
*
|
||||
* @param jobConfigurationName the name of a {@link JobConfiguration} in the registry.
|
||||
*/
|
||||
public void setJobConfigurationName(String jobConfigurationName) {
|
||||
this.jobConfigurationName = jobConfigurationName;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,21 +14,19 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.execution.bootstrap;
|
||||
package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.executor.ExitCodeExceptionClassifier;
|
||||
import org.springframework.batch.execution.bootstrap.support.JvmSystemExiter;
|
||||
import org.springframework.batch.execution.bootstrap.support.SimpleJvmExitCodeMapper;
|
||||
import org.springframework.batch.execution.bootstrap.JobLauncher;
|
||||
import org.springframework.batch.execution.bootstrap.JvmExitCodeMapper;
|
||||
import org.springframework.batch.execution.bootstrap.SystemExiter;
|
||||
import org.springframework.batch.execution.step.simple.SimpleExitCodeExceptionClassifier;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.beans.factory.BeanDefinitionStoreException;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -69,7 +67,7 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
/**
|
||||
* Injection setter for the {@link JobLauncher}.
|
||||
*
|
||||
*
|
||||
* @param launcher
|
||||
* the launcher to set
|
||||
*/
|
||||
@@ -79,7 +77,7 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
/**
|
||||
* Injection setter for the {@link ExitCodeExceptionClassifier}
|
||||
*
|
||||
*
|
||||
* @param exceptionClassifier
|
||||
*/
|
||||
public void setExceptionClassifier(
|
||||
@@ -89,7 +87,7 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
/**
|
||||
* Injection setter for the {@link JvmExitCodeMapper}.
|
||||
*
|
||||
*
|
||||
* @param exitCodeMapper
|
||||
* the exitCodeMapper to set
|
||||
*/
|
||||
@@ -99,7 +97,7 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
/**
|
||||
* Injection setter for the {@link SystemExiter}.
|
||||
*
|
||||
*
|
||||
* @param systemExitor
|
||||
*/
|
||||
public void setSystemExiter(SystemExiter systemExitor) {
|
||||
@@ -123,7 +121,7 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
ExitStatus status = ExitStatus.FAILED;
|
||||
ClassPathXmlApplicationContext context = null;
|
||||
|
||||
|
||||
try {
|
||||
ClassPathXmlApplicationContext parent = (ClassPathXmlApplicationContext) beanFactoryLocator
|
||||
.useBeanFactory(parentKey).getFactory();
|
||||
@@ -174,7 +172,7 @@ public class BatchCommandLineLauncher {
|
||||
* Launch a batch job using a {@link BatchCommandLineLauncher}. Creates a
|
||||
* new Spring context for the job execution, and uses a common parent for
|
||||
* all such contexts.
|
||||
*
|
||||
*
|
||||
* @param args
|
||||
* <ol>
|
||||
* <li> classpath location of resource to load job configuration
|
||||
@@ -21,7 +21,10 @@ import java.util.Map;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.execution.bootstrap.JobLauncher;
|
||||
import org.springframework.batch.execution.bootstrap.JvmExitCodeMapper;
|
||||
import org.springframework.batch.execution.bootstrap.SimpleJobLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
|
||||
/**
|
||||
@@ -40,12 +43,14 @@ public class SimpleJvmExitCodeMapper implements JvmExitCodeMapper {
|
||||
|
||||
public SimpleJvmExitCodeMapper(){
|
||||
mapping = new HashMap();
|
||||
mapping.put(BATCH_EXITCODE_COMPLETED,
|
||||
mapping.put(ExitStatus.FINISHED.getExitCode(),
|
||||
new Integer(JVM_EXITCODE_COMPLETED));
|
||||
mapping.put(BATCH_EXITCODE_GENERIC_ERROR,
|
||||
mapping.put(ExitStatus.FAILED.getExitCode(),
|
||||
new Integer(JVM_EXITCODE_GENERIC_ERROR));
|
||||
mapping.put(BATCH_EXITCODE_NO_SUCH_JOBCONFIGURATION,
|
||||
new Integer(JVM_EXITCODE_NO_SUCH_JOBCONFIGURATION));
|
||||
mapping.put(JobLauncher.JOB_CONFIGURATION_NOT_PROVIDED,
|
||||
new Integer(JVM_EXITCODE_JOB_CONFIGURATION_ERROR));
|
||||
mapping.put(JobLauncher.NO_SUCH_JOB_CONFIGURATION,
|
||||
new Integer(JVM_EXITCODE_JOB_CONFIGURATION_ERROR));
|
||||
}
|
||||
|
||||
public Map getMapping() {
|
||||
|
||||
@@ -13,11 +13,12 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.execution.bootstrap;
|
||||
package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.execution.bootstrap.BatchCommandLineLauncher;
|
||||
import org.springframework.batch.execution.bootstrap.JvmExitCodeMapper;
|
||||
import org.springframework.batch.execution.bootstrap.support.BatchCommandLineLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
@@ -32,43 +33,43 @@ import junit.framework.TestCase;
|
||||
*
|
||||
*/
|
||||
public class BatchCommandLineLauncherTests extends TestCase {
|
||||
|
||||
|
||||
private static final String DEFAULT_PARENT_KEY = "batchExecutionEnvironment";
|
||||
private static final String DEFAULT_JOB_CONFIGURATION_PATH = "job-configuration.xml";
|
||||
|
||||
|
||||
private static final String JOB_CONFIGURATION_PATH_KEY = "job.configuration.path";
|
||||
private static final String JOB_NAME_KEY = "job.name";
|
||||
private static final String BATCH_EXECUTION_ENVIRONMENT_KEY = "batch.execution.environment.key";
|
||||
|
||||
|
||||
private static final String TEST_BATCH_ENVIRONMENT_KEY = "testBatchEnvironment";
|
||||
private static final String TEST_BATCH_ENVIRONMENT_NO_LAUNCHER_KEY = "testBatchEnvironmentNoLauncher";
|
||||
|
||||
|
||||
BeanFactoryLocator beanFactoryLocator = ContextSingletonBeanFactoryLocator.getInstance();
|
||||
|
||||
|
||||
ClassPathXmlApplicationContext context;
|
||||
|
||||
|
||||
MockJobLauncher mockJobLauncher;
|
||||
MockSystemExiter mockSystemExiter;
|
||||
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
|
||||
context = (ClassPathXmlApplicationContext)beanFactoryLocator.useBeanFactory(TEST_BATCH_ENVIRONMENT_KEY).getFactory();
|
||||
context.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
|
||||
System.setProperty(BATCH_EXECUTION_ENVIRONMENT_KEY, TEST_BATCH_ENVIRONMENT_KEY);
|
||||
}
|
||||
|
||||
|
||||
protected void tearDown() throws Exception {
|
||||
super.tearDown();
|
||||
System.clearProperty(JOB_CONFIGURATION_PATH_KEY);
|
||||
System.clearProperty(JOB_NAME_KEY);
|
||||
System.clearProperty(BATCH_EXECUTION_ENVIRONMENT_KEY);
|
||||
}
|
||||
|
||||
|
||||
public void setMockJobLauncher(MockJobLauncher mockJobLauncher){
|
||||
this.mockJobLauncher = mockJobLauncher;
|
||||
}
|
||||
|
||||
|
||||
public void setMockSystemExiter(MockSystemExiter mockSystemExiter) {
|
||||
this.mockSystemExiter = mockSystemExiter;
|
||||
}
|
||||
@@ -77,53 +78,53 @@ public class BatchCommandLineLauncherTests extends TestCase {
|
||||
context = (ClassPathXmlApplicationContext)beanFactoryLocator.useBeanFactory(TEST_BATCH_ENVIRONMENT_NO_LAUNCHER_KEY).getFactory();
|
||||
context.getAutowireCapableBeanFactory().autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
|
||||
System.setProperty(BATCH_EXECUTION_ENVIRONMENT_KEY, TEST_BATCH_ENVIRONMENT_NO_LAUNCHER_KEY);
|
||||
|
||||
|
||||
BatchCommandLineLauncher.main(new String[0]);
|
||||
|
||||
|
||||
assertEquals(JvmExitCodeMapper.JVM_EXITCODE_GENERIC_ERROR, mockSystemExiter.getStatus());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.execution.bootstrap.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
* @throws Exception
|
||||
* Test method for {@link org.springframework.batch.execution.bootstrap.support.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testDefaultNameAndPath() throws Exception {
|
||||
|
||||
mockJobLauncher.setReturnValue(ExitStatus.FINISHED);
|
||||
|
||||
|
||||
BatchCommandLineLauncher.main(new String[0]);
|
||||
|
||||
|
||||
assertEquals(JvmExitCodeMapper.JVM_EXITCODE_COMPLETED, mockSystemExiter.getStatus());
|
||||
assertEquals(mockJobLauncher.getLastRunCalled(), MockJobLauncher.RUN_NO_ARGS);
|
||||
}
|
||||
|
||||
|
||||
public void testCustomJobName(){
|
||||
|
||||
|
||||
mockJobLauncher.setReturnValue(ExitStatus.FINISHED);
|
||||
|
||||
|
||||
System.setProperty(JOB_NAME_KEY, "foo");
|
||||
BatchCommandLineLauncher.main(new String[0]);
|
||||
|
||||
|
||||
assertEquals(JvmExitCodeMapper.JVM_EXITCODE_COMPLETED, mockSystemExiter.getStatus());
|
||||
assertEquals(mockJobLauncher.getLastRunCalled(), MockJobLauncher.RUN_JOB_NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.execution.bootstrap.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
* @throws Exception
|
||||
* Test method for {@link org.springframework.batch.execution.bootstrap.support.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testMainWithDefaultArguments() throws Exception {
|
||||
//can't test this without running the whole test in another jvm.
|
||||
//BatchCommandLineLauncher.main(new String[0]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void testInvalidJobConfig(){
|
||||
//also not testable without kicking off in a new jvm, since autowiring happens
|
||||
//after the context is loaded.
|
||||
/* System.setProperty(JOB_CONFIGURATION_PATH_KEY, "foo");
|
||||
|
||||
|
||||
BatchCommandLineLauncher.main(new String[0]);*/
|
||||
}
|
||||
}
|
||||
@@ -1,39 +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.execution.bootstrap.support;
|
||||
|
||||
import org.springframework.batch.execution.bootstrap.SystemExiter;
|
||||
|
||||
/**
|
||||
* Implementation of the {@link SystemExiter} interface
|
||||
* that calls the standards System.exit method. It should
|
||||
* be noted that there will be no unit tests for this class,
|
||||
* since there is only one line of actual code, that would only
|
||||
* be testable by mocking System or Runtime.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
public class JvmSystemExiter implements SystemExiter {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.execution.bootstrap.SystemExiter#exit(int)
|
||||
*/
|
||||
public void exit(int status) {
|
||||
System.exit(status);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package org.springframework.batch.execution.bootstrap;
|
||||
package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.runtime.JobIdentifier;
|
||||
import org.springframework.batch.execution.bootstrap.JobLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
@@ -9,7 +10,7 @@ import org.springframework.batch.repeat.ExitStatus;
|
||||
* be used to mock an interface, however, because of the nature
|
||||
* of launching a batch job from the command line, the mocked
|
||||
* class cannot be injected.
|
||||
*
|
||||
*
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
@@ -18,12 +19,12 @@ public class MockJobLauncher implements JobLauncher {
|
||||
public static final int RUN_NO_ARGS = 0;
|
||||
public static final int RUN_JOB_NAME = 1;
|
||||
public static final int RUN_JOB_IDENTIFIER =2 ;
|
||||
|
||||
|
||||
private int lastRunCalled = RUN_NO_ARGS;
|
||||
private ExitStatus returnValue = ExitStatus.FINISHED;
|
||||
|
||||
|
||||
private boolean isRunning = false;
|
||||
|
||||
|
||||
public boolean isRunning() {
|
||||
return isRunning;
|
||||
}
|
||||
@@ -48,11 +49,11 @@ public class MockJobLauncher implements JobLauncher {
|
||||
public void stop() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
public void setReturnValue(ExitStatus returnValue){
|
||||
this.returnValue = returnValue;
|
||||
}
|
||||
|
||||
|
||||
public void setIsRunning(boolean isRunning){
|
||||
this.isRunning = isRunning;
|
||||
}
|
||||
@@ -13,20 +13,22 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.execution.bootstrap;
|
||||
package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import org.springframework.batch.execution.bootstrap.SystemExiter;
|
||||
|
||||
/**
|
||||
* @author Lucas Ward
|
||||
*
|
||||
*/
|
||||
class MockSystemExiter implements SystemExiter{
|
||||
|
||||
|
||||
private int status;
|
||||
|
||||
|
||||
public void exit(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
@@ -19,14 +19,12 @@ package org.springframework.batch.execution.bootstrap.support;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.batch.execution.bootstrap.JvmExitCodeMapper;
|
||||
import org.springframework.batch.repeat.ExitCodeMapper;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.execution.bootstrap.JobLauncher;
|
||||
import org.springframework.batch.execution.bootstrap.JvmExitCodeMapper;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
public class SimpleJvmExitCodeMapperTests extends TestCase {
|
||||
|
||||
private SimpleJvmExitCodeMapper ecm;
|
||||
@@ -40,9 +38,10 @@ public class SimpleJvmExitCodeMapperTests extends TestCase {
|
||||
|
||||
ecm2 = new SimpleJvmExitCodeMapper();
|
||||
Map ecm2Map = new HashMap();
|
||||
ecm2Map.put(JvmExitCodeMapper.BATCH_EXITCODE_COMPLETED, new Integer(-1));
|
||||
ecm2Map.put(JvmExitCodeMapper.BATCH_EXITCODE_GENERIC_ERROR, new Integer(-2));
|
||||
ecm2Map.put(JvmExitCodeMapper.BATCH_EXITCODE_NO_SUCH_JOBCONFIGURATION, new Integer(-3));
|
||||
ecm2Map.put(ExitStatus.FINISHED.getExitCode(), new Integer(-1));
|
||||
ecm2Map.put(ExitStatus.FAILED.getExitCode(), new Integer(-2));
|
||||
ecm2Map.put(JobLauncher.JOB_CONFIGURATION_NOT_PROVIDED, new Integer(-3));
|
||||
ecm2Map.put(JobLauncher.NO_SUCH_JOB_CONFIGURATION, new Integer(-3));
|
||||
ecm2.setMapping(ecm2Map);
|
||||
}
|
||||
|
||||
@@ -52,24 +51,29 @@ public class SimpleJvmExitCodeMapperTests extends TestCase {
|
||||
|
||||
public void testGetExitCodeWithpPredefinedCodes() {
|
||||
assertEquals(
|
||||
ecm.getExitCode(ExitCodeMapper.BATCH_EXITCODE_COMPLETED),
|
||||
ecm.getExitCode(ExitStatus.FINISHED.getExitCode()),
|
||||
JvmExitCodeMapper.JVM_EXITCODE_COMPLETED);
|
||||
assertEquals(
|
||||
ecm.getExitCode(ExitCodeMapper.BATCH_EXITCODE_GENERIC_ERROR),
|
||||
ecm.getExitCode(ExitStatus.FAILED.getExitCode()),
|
||||
JvmExitCodeMapper.JVM_EXITCODE_GENERIC_ERROR);
|
||||
assertEquals(
|
||||
ecm.getExitCode(ExitCodeMapper.BATCH_EXITCODE_NO_SUCH_JOBCONFIGURATION),
|
||||
JvmExitCodeMapper.JVM_EXITCODE_NO_SUCH_JOBCONFIGURATION);
|
||||
ecm.getExitCode(JobLauncher.JOB_CONFIGURATION_NOT_PROVIDED),
|
||||
JvmExitCodeMapper.JVM_EXITCODE_JOB_CONFIGURATION_ERROR);
|
||||
assertEquals(
|
||||
ecm.getExitCode(JobLauncher.NO_SUCH_JOB_CONFIGURATION),
|
||||
JvmExitCodeMapper.JVM_EXITCODE_JOB_CONFIGURATION_ERROR);
|
||||
}
|
||||
|
||||
public void testGetExitCodeWithPredefinedCodesOverridden() {
|
||||
System.out.println(ecm2.getExitCode(ExitCodeMapper.BATCH_EXITCODE_COMPLETED));
|
||||
System.out.println(ecm2.getExitCode(ExitStatus.FINISHED.getExitCode()));
|
||||
assertEquals(
|
||||
ecm2.getExitCode(ExitCodeMapper.BATCH_EXITCODE_COMPLETED), -1);
|
||||
ecm2.getExitCode(ExitStatus.FINISHED.getExitCode()), -1);
|
||||
assertEquals(
|
||||
ecm2.getExitCode(ExitCodeMapper.BATCH_EXITCODE_GENERIC_ERROR), -2);
|
||||
ecm2.getExitCode(ExitStatus.FAILED.getExitCode()), -2);
|
||||
assertEquals(
|
||||
ecm2.getExitCode(ExitCodeMapper.BATCH_EXITCODE_NO_SUCH_JOBCONFIGURATION), -3);
|
||||
ecm2.getExitCode(JobLauncher.JOB_CONFIGURATION_NOT_PROVIDED), -3);
|
||||
assertEquals(
|
||||
ecm2.getExitCode(JobLauncher.NO_SUCH_JOB_CONFIGURATION), -3);
|
||||
}
|
||||
|
||||
public void testGetExitCodeWithCustomCode() {
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
|
||||
<bean id="testBatchEnvironment" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg>
|
||||
<value>org/springframework/batch/execution/bootstrap/test-batch-environment.xml</value>
|
||||
<value>org/springframework/batch/execution/bootstrap/support/test-batch-environment.xml</value>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="testBatchEnvironmentNoLauncher" class="org.springframework.context.support.ClassPathXmlApplicationContext">
|
||||
<constructor-arg>
|
||||
<value>org/springframework/batch/execution/bootstrap/test-batch-environment-no-launcher.xml</value>
|
||||
<value>org/springframework/batch/execution/bootstrap/support/test-batch-environment-no-launcher.xml</value>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
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">
|
||||
|
||||
|
||||
<bean id="jobConfigurationRegistry" class="org.springframework.batch.execution.configuration.MapJobConfigurationRegistry"/>
|
||||
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.support.SimpleJvmExitCodeMapper" />
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.MockSystemExiter" />
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.support.MockSystemExiter" />
|
||||
|
||||
</beans>
|
||||
@@ -6,13 +6,13 @@
|
||||
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">
|
||||
|
||||
<bean id="simpleContainerLauncher" class="org.springframework.batch.execution.bootstrap.MockJobLauncher" />
|
||||
|
||||
<bean id="simpleContainerLauncher" class="org.springframework.batch.execution.bootstrap.support.MockJobLauncher" />
|
||||
|
||||
<bean id="jobConfigurationRegistry" class="org.springframework.batch.execution.configuration.MapJobConfigurationRegistry"/>
|
||||
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.support.SimpleJvmExitCodeMapper" />
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.MockSystemExiter" />
|
||||
|
||||
<bean class="org.springframework.batch.execution.bootstrap.support.MockSystemExiter" />
|
||||
|
||||
</beans>
|
||||
Reference in New Issue
Block a user