IN PROGRESS - issue BATCH-159: JobExecutor should return a JobExecution (which itself contains the ExitStatus)
http://opensource.atlassian.com/projects/spring/browse/BATCH-159 APIs all pretty much in place now - JobLauncher returns JobExecution from the run methods. There is some polishing and test coverage work to do.
This commit is contained in:
@@ -81,11 +81,11 @@ public class Entity implements Serializable {
|
||||
if (!(other instanceof Entity)) {
|
||||
return false;
|
||||
}
|
||||
Entity step = (Entity) other;
|
||||
if (id == null || step.getId() == null) {
|
||||
return step == this;
|
||||
Entity entity = (Entity) other;
|
||||
if (id == null || entity.getId() == null) {
|
||||
return entity == this;
|
||||
}
|
||||
return id.equals(step.getId());
|
||||
return id.equals(entity.getId());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.executor;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobExecutionException extends Exception {
|
||||
|
||||
public JobExecutionException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public JobExecutionException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import org.springframework.batch.io.exception.BatchCriticalException;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class StepInterruptedException extends Exception {
|
||||
public class StepInterruptedException extends JobExecutionException {
|
||||
|
||||
public StepInterruptedException(String msg) {
|
||||
super(msg);
|
||||
|
||||
@@ -57,6 +57,29 @@ public class EntityTests extends TestCase {
|
||||
assertTrue(job.toString().indexOf("id=null") >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
|
||||
*/
|
||||
public void testEqualsSelf() {
|
||||
assertEquals(entity, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
|
||||
*/
|
||||
public void testEqualsSelfWithNullId() {
|
||||
entity = new Entity(null);
|
||||
assertEquals(entity, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
|
||||
*/
|
||||
public void testEqualsEntityWithNullId() {
|
||||
entity = new Entity(null);
|
||||
assertNotSame(entity, new Entity(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.batch.core.domain.Entity#equals(java.lang.Object)}.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.executor;
|
||||
|
||||
import org.springframework.batch.core.AbstractExceptionTests;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobExecutionExceptionTests extends AbstractExceptionTests {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
|
||||
*/
|
||||
public Exception getException(String msg) throws Exception {
|
||||
return new JobExecutionException(msg);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String, java.lang.Throwable)
|
||||
*/
|
||||
public Exception getException(String msg, Throwable t) throws Exception {
|
||||
return new JobExecutionException(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -209,9 +209,9 @@ public class BatchCommandLineLauncher {
|
||||
|
||||
if (!launcher.isRunning()) {
|
||||
if (jobName == null) {
|
||||
status = launcher.run();
|
||||
status = launcher.run().getExitStatus();
|
||||
} else {
|
||||
status = launcher.run(jobName);
|
||||
status = launcher.run(jobName).getExitStatus();
|
||||
}
|
||||
}
|
||||
} catch (NoSuchJobConfigurationException e) {
|
||||
|
||||
@@ -60,9 +60,9 @@ public class ThreadInterruptJobExecutionListener extends
|
||||
* Interrupt the thread that is running the job if the {@link ExitStatus}
|
||||
* indicates that it is still running.
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.JobExecutionListenerSupport#stop(org.springframework.batch.core.domain.JobExecution)
|
||||
* @see org.springframework.batch.execution.launch.JobExecutionListenerSupport#onStop(org.springframework.batch.core.domain.JobExecution)
|
||||
*/
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
if (execution==null || execution.getExitStatus().isRunning()) {
|
||||
processingThread.interrupt();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.launch;
|
||||
|
||||
import org.springframework.batch.core.executor.JobExecutionException;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobExecutionAlreadyRunningException extends JobExecutionException {
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
*/
|
||||
public JobExecutionAlreadyRunningException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param msg
|
||||
* @param cause
|
||||
*/
|
||||
public JobExecutionAlreadyRunningException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -46,5 +46,5 @@ public interface JobExecutionListener {
|
||||
*
|
||||
* @param execution
|
||||
*/
|
||||
void stop(JobExecution execution);
|
||||
void onStop(JobExecution execution);
|
||||
}
|
||||
|
||||
@@ -47,9 +47,9 @@ public class JobExecutionListenerSupport implements JobExecutionListener {
|
||||
/**
|
||||
* No-op for subclasses to extend.
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.JobExecutionListener#stop(org.springframework.batch.core.domain.JobExecution)
|
||||
* @see org.springframework.batch.execution.launch.JobExecutionListener#onStop(org.springframework.batch.core.domain.JobExecution)
|
||||
*/
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
package org.springframework.batch.execution.launch;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* Interface which defines a facade for running jobs. The interface is
|
||||
@@ -31,18 +31,29 @@ import org.springframework.batch.repeat.ExitStatus;
|
||||
interface JobExecutorFacade {
|
||||
|
||||
/**
|
||||
* Start a job execution identifiable by the {@link JobIdentifier}.
|
||||
* Implementations normally require a job configuration to be locatable
|
||||
* corresponding to the {@link JobIdentifier}, preferably matching them at
|
||||
* Prepare a job execution identifiable by the {@link JobIdentifier}. THis
|
||||
* can then be used to run the job with the {@link #start(JobExecution)}
|
||||
* method. Implementations normally require a job configuration to be
|
||||
* locatable corresponding to the {@link JobIdentifier}, matching them at
|
||||
* least by name.
|
||||
*
|
||||
* @param jobIdentifier
|
||||
* the identifier of the job to start
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
ExitStatus start(JobIdentifier jobIdentifier)
|
||||
JobExecution createNewExecution(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Start a job execution.
|
||||
*
|
||||
* @param execution
|
||||
* the execution of the job to start
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
void start(JobExecution execution) throws NoSuchJobConfigurationException;
|
||||
|
||||
/**
|
||||
* Stop the job execution that was started with this runtime information.
|
||||
*
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
package org.springframework.batch.execution.launch;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* Simple interface for controlling jobs, including possible ad-hoc executions,
|
||||
* based on different runtime identifiers. Implementations should concentrate on
|
||||
* managing jobs and delegate the launching to a {@link JobExecutorFacade}.
|
||||
* based on different runtime identifiers.
|
||||
*
|
||||
* @author Lucas Ward
|
||||
* @author Dave Syer
|
||||
@@ -36,9 +35,10 @@ public interface JobLauncher {
|
||||
*
|
||||
* @return the exit code from the job if it returns synchronously. If the
|
||||
* implementation is asynchronous, the status might well be unknown.
|
||||
* @throws JobExecutionAlreadyRunningException
|
||||
*
|
||||
*/
|
||||
public ExitStatus run() throws NoSuchJobConfigurationException;
|
||||
public JobExecution run() throws NoSuchJobConfigurationException, JobExecutionAlreadyRunningException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given name and other runtime information
|
||||
@@ -51,9 +51,10 @@ public interface JobLauncher {
|
||||
* implementation is asynchronous, the status might well be unknown.
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* @throws JobExecutionAlreadyRunningException
|
||||
*/
|
||||
public ExitStatus run(String jobName)
|
||||
throws NoSuchJobConfigurationException;
|
||||
public JobExecution run(String jobName)
|
||||
throws NoSuchJobConfigurationException, JobExecutionAlreadyRunningException;
|
||||
|
||||
/**
|
||||
* Start a job execution with the given runtime information.
|
||||
@@ -63,8 +64,8 @@ public interface JobLauncher {
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
public ExitStatus run(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException;
|
||||
public JobExecution run(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException, JobExecutionAlreadyRunningException;
|
||||
|
||||
/**
|
||||
* Stop the current job executions if there are any. If not, no action will
|
||||
|
||||
@@ -33,9 +33,9 @@ import org.springframework.batch.core.domain.JobInstance;
|
||||
import org.springframework.batch.core.executor.JobExecutor;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.execution.job.DefaultJobExecutor;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.batch.repeat.RepeatContext;
|
||||
import org.springframework.batch.statistics.StatisticsProvider;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -57,17 +57,17 @@ import org.springframework.util.Assert;
|
||||
*
|
||||
*/
|
||||
class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
JobExecutionListener, StatisticsProvider {
|
||||
JobExecutionListener, StatisticsProvider, InitializingBean {
|
||||
|
||||
private Map jobExecutionRegistry = new HashMap();
|
||||
|
||||
private JobExecutor jobExecutor = new DefaultJobExecutor();
|
||||
|
||||
|
||||
private JobRepository jobRepository;
|
||||
|
||||
|
||||
// there is no sensible default for this
|
||||
private JobConfigurationLocator jobConfigurationLocator;
|
||||
|
||||
|
||||
private List listeners = new ArrayList();
|
||||
|
||||
private int running = 0;
|
||||
@@ -84,6 +84,18 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check mandatory properties (jobConfigurationLocator,
|
||||
* jobRepository).
|
||||
*
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(jobRepository, "JobRepository must be provided.");
|
||||
Assert.notNull(jobConfigurationLocator,
|
||||
"JobConfigurationLocator must be provided.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Public accessor for the running property.
|
||||
*
|
||||
@@ -128,23 +140,18 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
* Locates a {@link JobConfiguration} by using the name of the provided
|
||||
* {@link JobIdentifier} and the {@link JobConfigurationLocator}.
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.JobExecutorFacade#start(org.springframework.batch.execution.common.domain.JobConfiguration,
|
||||
* org.springframework.batch.core.domain.JobIdentifier)
|
||||
* @param jobConfiguration
|
||||
*
|
||||
* @throws IllegalArgumentException
|
||||
* if the {@link JobIdentifier} is null or its name is null
|
||||
* @throws IllegalStateException
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* if the {@link JobConfigurationLocator} does not contain a
|
||||
* {@link JobConfiguration} with the name provided.
|
||||
* @throws IllegalStateException
|
||||
* if the {@link JobExecutor} is null
|
||||
* @throws IllegalStateException
|
||||
* if the {@link JobConfigurationLocator} is null
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.JobExecutorFacade#createNewExecution(org.springframework.batch.core.domain.JobIdentifier)
|
||||
*/
|
||||
public ExitStatus start(JobIdentifier jobIdentifier)
|
||||
public JobExecution createNewExecution(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException {
|
||||
|
||||
Assert.notNull(jobIdentifier, "JobIdentifier must not be null.");
|
||||
Assert.notNull(jobIdentifier.getName(),
|
||||
"JobIdentifier name must not be null.");
|
||||
@@ -153,16 +160,32 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
.state(!jobExecutionRegistry.containsKey(jobIdentifier),
|
||||
"A job with this JobRuntimeInformation is already executing in this container");
|
||||
|
||||
Assert.state(jobExecutor != null, "JobExecutor must be provided.");
|
||||
Assert.state(jobConfigurationLocator != null,
|
||||
"JobConfigurationLocator must be provided.");
|
||||
|
||||
JobConfiguration jobConfiguration = jobConfigurationLocator
|
||||
.getJobConfiguration(jobIdentifier.getName());
|
||||
|
||||
JobInstance job = jobRepository.findOrCreateJob(jobConfiguration,
|
||||
jobIdentifier);
|
||||
JobExecution execution = new JobExecution(job);
|
||||
return new JobExecution(job);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts a job execution that was previously acquired from the
|
||||
* {@link #createNewExecution(JobIdentifier)} method.
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.JobExecutorFacade#start(JobExecution)
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* if the {@link JobConfigurationLocator} does not contain a
|
||||
* {@link JobConfiguration} with the name provided by the
|
||||
* enclosed {@link JobIdentifier}.
|
||||
*
|
||||
*/
|
||||
public void start(JobExecution execution)
|
||||
throws NoSuchJobConfigurationException {
|
||||
|
||||
JobConfiguration jobConfiguration = jobConfigurationLocator
|
||||
.getJobConfiguration(execution.getJob().getIdentifier()
|
||||
.getName());
|
||||
|
||||
this.before(execution);
|
||||
try {
|
||||
@@ -171,7 +194,6 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
this.after(execution);
|
||||
}
|
||||
|
||||
return execution.getExitStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -180,11 +202,14 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
* order that they were given.
|
||||
*
|
||||
* @param execution
|
||||
*
|
||||
* @see JobExecutionListener#before(JobExecution)
|
||||
*/
|
||||
public void before(JobExecution execution) {
|
||||
synchronized (mutex) {
|
||||
running++;
|
||||
jobExecutionRegistry.put(execution.getJob().getIdentifier(), execution);
|
||||
jobExecutionRegistry.put(execution.getJob().getIdentifier(),
|
||||
execution);
|
||||
}
|
||||
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
|
||||
JobExecutionListener listener = (JobExecutionListener) iterator
|
||||
@@ -197,12 +222,14 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
* Broadcast stop signal to all the registered listeners.
|
||||
*
|
||||
* @param execution
|
||||
*
|
||||
* @see JobExecutionListener#onStop(JobExecution)
|
||||
*/
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
for (Iterator iterator = listeners.iterator(); iterator.hasNext();) {
|
||||
JobExecutionListener listener = (JobExecutionListener) iterator
|
||||
.next();
|
||||
listener.stop(execution);
|
||||
listener.onStop(execution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,6 +239,8 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
* then finally dealing with internal housekeeping.
|
||||
*
|
||||
* @param execution
|
||||
*
|
||||
* @see JobExecutionListener#after(JobExecution)
|
||||
*/
|
||||
public void after(JobExecution execution) {
|
||||
ArrayList reversed = new ArrayList(listeners);
|
||||
@@ -232,9 +261,9 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
/**
|
||||
* Send a stop signal to all the running executions by setting their
|
||||
* {@link RepeatContext} to terminate only. Then call the
|
||||
* {@link JobExecutionListener#stop(JobExecution)} method.
|
||||
* {@link JobExecutionListener#onStop(JobExecution)} method.
|
||||
*
|
||||
* @see org.springframework.batch.container.BatchContainer#stop(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
|
||||
* @see org.springframework.batch.container.BatchContainer#onStop(org.springframework.batch.container.common.runtime.JobRuntimeInformation)
|
||||
*/
|
||||
public void stop(JobIdentifier runtimeInformation)
|
||||
throws NoSuchJobExecutionException {
|
||||
@@ -254,10 +283,13 @@ class SimpleJobExecutorFacade implements JobExecutorFacade,
|
||||
RepeatContext context = (RepeatContext) iter.next();
|
||||
context.setTerminateOnly();
|
||||
}
|
||||
this.stop(execution);
|
||||
this.onStop(execution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a snapshot of properties from running jobs (the ones that were
|
||||
* launched from this {@link JobExecutorFacade).
|
||||
*
|
||||
* @return a read-only view of the state of the running jobs.
|
||||
*/
|
||||
public Properties getStatistics() {
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.springframework.batch.core.runtime.JobIdentifierFactory;
|
||||
import org.springframework.batch.execution.job.DefaultJobExecutor;
|
||||
import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory;
|
||||
import org.springframework.batch.io.exception.BatchConfigurationException;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.batch.repeat.interceptor.RepeatOperationsApplicationEvent;
|
||||
import org.springframework.batch.statistics.StatisticsProvider;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
@@ -52,8 +51,8 @@ import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for {@link JobLauncher} implementations making no choices about
|
||||
* concurrent processing of jobs.
|
||||
* Generic {@link JobLauncher} allowing choice of strategy for concurrent
|
||||
* execution and .
|
||||
*
|
||||
* @see JobLauncher
|
||||
* @author Dave Syer
|
||||
@@ -65,19 +64,22 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
.getLog(SimpleJobLauncher.class);
|
||||
|
||||
private JobExecutor jobExecutor = new DefaultJobExecutor();
|
||||
|
||||
|
||||
// there is no sensible default for this
|
||||
private JobRepository jobRepository;
|
||||
|
||||
|
||||
// there is no sensible default for this
|
||||
private JobConfigurationLocator jobConfigurationLocator;
|
||||
|
||||
private List listeners = new ArrayList();
|
||||
|
||||
// this can be defaulted from some other properties (see
|
||||
// afterPropertiesSet())
|
||||
private JobExecutorFacade jobExecutorFacade;
|
||||
|
||||
private String jobConfigurationName;
|
||||
private TaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
private List listeners = new ArrayList();
|
||||
|
||||
private String jobConfigurationName;
|
||||
|
||||
// Do not autostart by default - allow user to set job configuration
|
||||
// later and then manually start:
|
||||
@@ -85,12 +87,12 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
|
||||
private JobIdentifierFactory jobIdentifierFactory = new ScheduledJobIdentifierFactory();
|
||||
|
||||
private final Object monitor = new Object();
|
||||
|
||||
// A private registry for keeping track of running jobs.
|
||||
private volatile Map registry = new HashMap();
|
||||
|
||||
private TaskExecutor taskExecutor = new SyncTaskExecutor();
|
||||
|
||||
ApplicationEventPublisher applicationEventPublisher;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
/**
|
||||
* Setter for {@link JobIdentifierFactory}.
|
||||
@@ -122,7 +124,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
public void setAutoStart(boolean autoStart) {
|
||||
this.autoStart = autoStart;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Public setter for the listeners property.
|
||||
*
|
||||
@@ -134,7 +136,8 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for injection of {@link JobConfigurationLocator}.
|
||||
* Setter for injection of {@link JobConfigurationLocator}. Mandatory with
|
||||
* no default.
|
||||
*
|
||||
* @param jobConfigurationLocator
|
||||
* the jobConfigurationLocator to set
|
||||
@@ -145,7 +148,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link JobExecutor}.
|
||||
* Setter for {@link JobExecutor}. Defaults to a {@link DefaultJobExecutor}.
|
||||
*
|
||||
* @param jobExecutor
|
||||
*/
|
||||
@@ -154,35 +157,38 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link JobRepository}.
|
||||
* Setter for {@link JobRepository}. Mandatory with no default.
|
||||
*
|
||||
* @param jobRepository
|
||||
*/
|
||||
public void setJobRepository(JobRepository jobRepository) {
|
||||
this.jobRepository = jobRepository;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for {@link JobExecutorFacade}.
|
||||
* Setter for {@link JobExecutorFacade}. Package private because it is only
|
||||
* used for testing purposes.
|
||||
*/
|
||||
void setJobExecutorFacade(JobExecutorFacade jobExecutorFacade) {
|
||||
this.jobExecutorFacade = jobExecutorFacade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that mandatory properties are set.
|
||||
* Check that mandatory properties are set and create a {@link JobExecutor}
|
||||
* if one wasn't provided.
|
||||
*
|
||||
* @see #setJobExecutorFacade(JobExecutorFacade)
|
||||
* @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
|
||||
*/
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
if (jobExecutorFacade==null) {
|
||||
if (jobExecutorFacade == null) {
|
||||
logger.debug("Using SimpleJobExecutorFacade");
|
||||
Assert.notNull(jobConfigurationLocator);
|
||||
Assert.notNull(jobExecutor);
|
||||
Assert.notNull(jobRepository);
|
||||
SimpleJobExecutorFacade jobExecutorFacade = new SimpleJobExecutorFacade();
|
||||
jobExecutorFacade.setJobConfigurationLocator(jobConfigurationLocator);
|
||||
jobExecutorFacade
|
||||
.setJobConfigurationLocator(jobConfigurationLocator);
|
||||
jobExecutorFacade.setJobExecutionListeners(listeners);
|
||||
jobExecutorFacade.setJobExecutor(jobExecutor);
|
||||
jobExecutorFacade.setJobRepository(jobRepository);
|
||||
@@ -208,7 +214,10 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
run();
|
||||
} catch (NoSuchJobConfigurationException e) {
|
||||
throw new BatchConfigurationException(
|
||||
"Cannot start job on context refresh", e);
|
||||
"Cannot start job on context refresh because it does not exist", e);
|
||||
} catch (JobExecutionAlreadyRunningException e) {
|
||||
throw new BatchConfigurationException(
|
||||
"Cannot start job on context refresh because it is already running", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,19 +231,20 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
* @return
|
||||
* @throws NoSuchJobConfigurationException
|
||||
*/
|
||||
protected final ExitStatus runInternal(final JobIdentifier jobIdentifier)
|
||||
protected final void runInternal(JobExecution execution)
|
||||
throws NoSuchJobConfigurationException {
|
||||
|
||||
JobIdentifier jobIdentifier = execution.getJob().getIdentifier();
|
||||
|
||||
synchronized (monitor) {
|
||||
if (isInternalRunning(jobIdentifier)) {
|
||||
return ExitStatus.RUNNING;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
register(jobIdentifier);
|
||||
|
||||
register(execution);
|
||||
try {
|
||||
return jobExecutorFacade.start(jobIdentifier);
|
||||
jobExecutorFacade.start(execution);
|
||||
} finally {
|
||||
unregister(jobIdentifier);
|
||||
}
|
||||
@@ -244,16 +254,30 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
/**
|
||||
* Start the job using the task executor provided.
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* if the identifier cannot be used to locate a
|
||||
* {@link JobConfiguration}.
|
||||
*
|
||||
* @see org.springframework.batch.execution.launch.SimpleJobLauncher#run(org.springframework.batch.core.domain.JobIdentifier)
|
||||
*/
|
||||
public ExitStatus run(final JobIdentifier jobIdentifier) {
|
||||
public JobExecution run(final JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException,
|
||||
JobExecutionAlreadyRunningException {
|
||||
|
||||
Assert.state(taskExecutor != null, "TaskExecutor must be provided");
|
||||
if (get(jobIdentifier) != null) {
|
||||
throw new JobExecutionAlreadyRunningException(
|
||||
"A job is already executing with this identifier: ["
|
||||
+ jobIdentifier + "]");
|
||||
}
|
||||
final JobExecution execution = jobExecutorFacade
|
||||
.createNewExecution(jobIdentifier);
|
||||
// TODO: throw JobExecutionAlreadyRunningException if it is in a running
|
||||
// state (someone else launched it)
|
||||
|
||||
taskExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
runInternal(jobIdentifier);
|
||||
runInternal(execution);
|
||||
} catch (NoSuchJobConfigurationException e) {
|
||||
applicationEventPublisher
|
||||
.publishEvent(new RepeatOperationsApplicationEvent(
|
||||
@@ -266,7 +290,7 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
}
|
||||
});
|
||||
|
||||
return ExitStatus.UNKNOWN;
|
||||
return execution;
|
||||
|
||||
}
|
||||
|
||||
@@ -277,8 +301,9 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
* @param name
|
||||
* the name to assign to the job
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* @throws JobExecutionAlreadyRunningException
|
||||
*/
|
||||
public ExitStatus run(String name) throws NoSuchJobConfigurationException {
|
||||
public JobExecution run(String name) throws NoSuchJobConfigurationException, JobExecutionAlreadyRunningException {
|
||||
if (name == null) {
|
||||
throw new NoSuchJobConfigurationException(
|
||||
"Null job name cannot be located.");
|
||||
@@ -297,11 +322,12 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
*
|
||||
* @throws NoSuchJobConfigurationException
|
||||
* if the job configuration cannot be located
|
||||
* @throws JobExecutionAlreadyRunningException
|
||||
*
|
||||
* @see #setJobIdentifierFactory(JobIdentifierFactory)
|
||||
* @see org.springframework.context.Lifecycle#start()
|
||||
*/
|
||||
public ExitStatus run() throws NoSuchJobConfigurationException {
|
||||
public JobExecution run() throws NoSuchJobConfigurationException, JobExecutionAlreadyRunningException {
|
||||
if (jobConfigurationName != null) {
|
||||
return this.run(jobConfigurationName);
|
||||
}
|
||||
@@ -408,17 +434,30 @@ public class SimpleJobLauncher implements JobLauncher, InitializingBean,
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synchronized accessor for the registry. Can be used by
|
||||
* subclasses if necessary (but it isn't likely).
|
||||
* Convenient synchronized accessor for the registry.
|
||||
*
|
||||
* @param jobIdentifier
|
||||
*/
|
||||
private void register(JobIdentifier jobIdentifier) {
|
||||
private void register(JobExecution execution) {
|
||||
synchronized (registry) {
|
||||
registry.put(jobIdentifier, jobIdentifier);
|
||||
registry.put(execution.getJob().getIdentifier(), execution);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synchronized accessor for the registry.
|
||||
*
|
||||
* @param jobIdentifier
|
||||
*/
|
||||
private JobExecution get(JobIdentifier jobIdentifier) {
|
||||
synchronized (registry) {
|
||||
if (registry.containsKey(jobIdentifier)) {
|
||||
return (JobExecution) registry.get(jobIdentifier);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenient synchronized accessor for the registry. Must be used by
|
||||
* subclasses to release the {@link JobIdentifier} when a job is finished
|
||||
|
||||
@@ -17,6 +17,9 @@ package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobInstance;
|
||||
import org.springframework.batch.core.runtime.SimpleJobIdentifier;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.beans.factory.access.BeanFactoryLocator;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
@@ -81,7 +84,7 @@ public class BatchCommandLineLauncherTests extends TestCase {
|
||||
assertNotNull(jobLauncher);
|
||||
assertNotNull(systemExiter);
|
||||
|
||||
jobLauncher.setReturnValue(ExitStatus.FINISHED);
|
||||
setReturnValue(ExitStatus.FINISHED);
|
||||
|
||||
BatchCommandLineLauncher.main(new String[0]);
|
||||
|
||||
@@ -91,12 +94,18 @@ public class BatchCommandLineLauncherTests extends TestCase {
|
||||
StubJobLauncher.RUN_NO_ARGS);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.batch.execution.bootstrap.support.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public void testCustomJobName() {
|
||||
|
||||
buildContext(TEST_BATCH_ENVIRONMENT_KEY);
|
||||
assertNotNull(jobLauncher);
|
||||
assertNotNull(systemExiter);
|
||||
jobLauncher.setReturnValue(ExitStatus.FINISHED);
|
||||
setReturnValue(ExitStatus.FINISHED);
|
||||
|
||||
System.setProperty(JOB_NAME_KEY, "foo");
|
||||
BatchCommandLineLauncher.main(new String[0]);
|
||||
@@ -107,6 +116,12 @@ public class BatchCommandLineLauncherTests extends TestCase {
|
||||
StubJobLauncher.RUN_JOB_NAME);
|
||||
}
|
||||
|
||||
private void setReturnValue(ExitStatus status) {
|
||||
JobExecution execution = new JobExecution(new JobInstance(new SimpleJobIdentifier("foo")));
|
||||
execution.setExitStatus(status);
|
||||
jobLauncher.setReturnValue(execution);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.batch.execution.bootstrap.support.BatchCommandLineLauncher#main(java.lang.String[])}.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.springframework.batch.execution.bootstrap.support;
|
||||
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.execution.launch.JobLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* Mock Job Launcher. Normally, something like EasyMock would
|
||||
@@ -21,7 +21,7 @@ public class StubJobLauncher implements JobLauncher {
|
||||
public static final int RUN_JOB_IDENTIFIER =2 ;
|
||||
|
||||
private int lastRunCalled = RUN_NO_ARGS;
|
||||
private ExitStatus returnValue = ExitStatus.FINISHED;
|
||||
private JobExecution returnValue = null;
|
||||
|
||||
private boolean isRunning = false;
|
||||
|
||||
@@ -29,18 +29,18 @@ public class StubJobLauncher implements JobLauncher {
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
public ExitStatus run() throws NoSuchJobConfigurationException {
|
||||
public JobExecution run() throws NoSuchJobConfigurationException {
|
||||
lastRunCalled = RUN_NO_ARGS;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public ExitStatus run(String jobName)
|
||||
public JobExecution run(String jobName)
|
||||
throws NoSuchJobConfigurationException {
|
||||
lastRunCalled = RUN_JOB_NAME;
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
public ExitStatus run(JobIdentifier jobIdentifier)
|
||||
public JobExecution run(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException {
|
||||
lastRunCalled = RUN_JOB_IDENTIFIER;
|
||||
return returnValue;
|
||||
@@ -50,7 +50,7 @@ public class StubJobLauncher implements JobLauncher {
|
||||
|
||||
}
|
||||
|
||||
public void setReturnValue(ExitStatus returnValue){
|
||||
public void setReturnValue(JobExecution returnValue){
|
||||
this.returnValue = returnValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -60,12 +60,13 @@ public class InterruptJobTests extends TestCase {
|
||||
|
||||
registry.register(new JobConfiguration("foo"));
|
||||
final SimpleJobIdentifier identifier = new SimpleJobIdentifier("foo");
|
||||
final JobExecution execution = facade.createNewExecution(identifier);
|
||||
|
||||
TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
|
||||
Runnable launcherRunnable = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
facade.start(identifier);
|
||||
facade.start(execution);
|
||||
} catch (NoSuchJobConfigurationException e) {
|
||||
fail("Unexpected NoSuchJobConfigurationException");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.launch;
|
||||
|
||||
import org.springframework.batch.core.AbstractExceptionTests;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobExecutionAlreadyRunningExceptionTests extends AbstractExceptionTests {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String)
|
||||
*/
|
||||
public Exception getException(String msg) throws Exception {
|
||||
return new JobExecutionAlreadyRunningException(msg);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.io.exception.AbstractExceptionTests#getException(java.lang.String, java.lang.Throwable)
|
||||
*/
|
||||
public Exception getException(String msg, Throwable t) throws Exception {
|
||||
return new JobExecutionAlreadyRunningException(msg, t);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -70,13 +70,13 @@ public class JobExecutionListenerSupportTests extends TestCase {
|
||||
*/
|
||||
public void testStop() {
|
||||
JobExecutionListener listener = new JobExecutionListenerSupport() {
|
||||
public void stop(JobExecution execution) {
|
||||
super.stop(execution);
|
||||
public void onStop(JobExecution execution) {
|
||||
super.onStop(execution);
|
||||
list.add("stop");
|
||||
}
|
||||
};
|
||||
|
||||
listener.stop(null);
|
||||
listener.onStop(null);
|
||||
assertEquals(1, list.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,23 +78,32 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
jobExecutorFacade.setJobRepository(jobRepository);
|
||||
}
|
||||
|
||||
public void testNormalStart() throws Exception {
|
||||
public void testCreateNewExecution() throws Exception {
|
||||
|
||||
JobInstance job = setUpFacadeForNormalStart();
|
||||
jobExecutorFacade.start(jobIdentifier);
|
||||
jobExecution = jobExecutorFacade.createNewExecution(jobIdentifier);
|
||||
assertEquals(job, jobExecution.getJob());
|
||||
assertEquals("bar", job.getName());
|
||||
jobRepositoryControl.verify();
|
||||
|
||||
}
|
||||
|
||||
private JobInstance setUpFacadeForNormalStart() {
|
||||
public void testNormalStart() throws Exception {
|
||||
|
||||
JobInstance job = setUpFacadeForNormalStart();
|
||||
jobExecution = jobExecutorFacade.createNewExecution(jobIdentifier);
|
||||
jobExecutorFacade.start(jobExecution);
|
||||
assertEquals(job, jobExecution.getJob());
|
||||
assertEquals("bar", job.getName());
|
||||
jobRepositoryControl.verify();
|
||||
|
||||
}
|
||||
|
||||
private JobInstance setUpFacadeForNormalStart() throws NoSuchJobConfigurationException {
|
||||
jobIdentifier = new SimpleJobIdentifier("bar");
|
||||
jobRepository.findOrCreateJob(jobConfiguration, jobIdentifier);
|
||||
jobExecutor = new JobExecutor() {
|
||||
public ExitStatus run(JobConfiguration configuration,
|
||||
JobExecution execution)
|
||||
throws BatchCriticalException {
|
||||
JobExecution execution) throws BatchCriticalException {
|
||||
jobExecution = execution;
|
||||
return ExitStatus.FINISHED;
|
||||
}
|
||||
@@ -102,6 +111,7 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
jobExecutorFacade.setJobExecutor(jobExecutor);
|
||||
JobInstance job = new JobInstance(jobIdentifier);
|
||||
jobExecution = new JobExecution(job);
|
||||
jobRepository.findOrCreateJob(jobConfiguration, jobIdentifier);
|
||||
jobRepositoryControl.setReturnValue(job);
|
||||
jobRepositoryControl.replay();
|
||||
jobExecutorFacade
|
||||
@@ -117,8 +127,7 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
public void testIsRunning() throws Exception {
|
||||
jobExecutorFacade.setJobExecutor(new JobExecutor() {
|
||||
public ExitStatus run(JobConfiguration configuration,
|
||||
JobExecution execution)
|
||||
throws BatchCriticalException {
|
||||
JobExecution execution) throws BatchCriticalException {
|
||||
while (running) {
|
||||
try {
|
||||
Thread.sleep(100L);
|
||||
@@ -137,17 +146,12 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
return jobConfiguration;
|
||||
}
|
||||
});
|
||||
final SimpleJobIdentifier jobIdentifier = new SimpleJobIdentifier("foo");
|
||||
jobRepository.findOrCreateJob(jobConfiguration, jobIdentifier);
|
||||
JobInstance job = new JobInstance(jobIdentifier);
|
||||
jobRepositoryControl.setReturnValue(job);
|
||||
jobRepositoryControl.replay();
|
||||
|
||||
running = true;
|
||||
new Thread(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
jobExecutorFacade.start(jobIdentifier);
|
||||
jobExecutorFacade.start(jobExecution);
|
||||
} catch (NoSuchJobConfigurationException e) {
|
||||
System.err.println("Shouldn't happen");
|
||||
}
|
||||
@@ -162,17 +166,16 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
Thread.sleep(100L);
|
||||
}
|
||||
assertFalse(jobExecutorFacade.isRunning());
|
||||
jobRepositoryControl.verify();
|
||||
}
|
||||
|
||||
public void testInvalidState() throws Exception {
|
||||
public void testInvalidInitialisation() throws Exception {
|
||||
|
||||
jobExecutorFacade.setJobExecutor(null);
|
||||
jobExecutorFacade = new SimpleJobExecutorFacade();
|
||||
|
||||
try {
|
||||
jobExecutorFacade.start(new SimpleJobIdentifier("TestJob"));
|
||||
jobExecutorFacade.afterPropertiesSet();
|
||||
fail("Expected IllegalStateException");
|
||||
} catch (IllegalStateException ex) {
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
@@ -194,10 +197,10 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
"TestJob");
|
||||
JobExecution execution = new JobExecution(new JobInstance(
|
||||
runtimeInformation, new Long(0)));
|
||||
|
||||
|
||||
List listeners = new ArrayList();
|
||||
listeners.add(new JobExecutionListenerSupport() {
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
list.add("one");
|
||||
}
|
||||
});
|
||||
@@ -236,17 +239,17 @@ public class SimpleJobExecutorFacadeTests extends TestCase {
|
||||
public void testListenersCalledLastOnStop() throws Exception {
|
||||
List listeners = new ArrayList();
|
||||
listeners.add(new JobExecutionListenerSupport() {
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
list.add("one");
|
||||
}
|
||||
});
|
||||
listeners.add(new JobExecutionListenerSupport() {
|
||||
public void stop(JobExecution execution) {
|
||||
public void onStop(JobExecution execution) {
|
||||
list.add("two");
|
||||
}
|
||||
});
|
||||
jobExecutorFacade.setJobExecutionListeners(listeners);
|
||||
jobExecutorFacade.stop(jobExecution);
|
||||
jobExecutorFacade.onStop(jobExecution);
|
||||
assertEquals(2, list.size());
|
||||
assertEquals("two", list.get(1));
|
||||
}
|
||||
|
||||
@@ -20,12 +20,10 @@ import junit.framework.TestCase;
|
||||
|
||||
import org.springframework.batch.core.configuration.JobConfiguration;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.core.domain.JobInstance;
|
||||
import org.springframework.batch.core.runtime.SimpleJobIdentifierFactory;
|
||||
import org.springframework.batch.execution.launch.JobExecutionListener;
|
||||
import org.springframework.batch.execution.launch.JobExecutorFacade;
|
||||
import org.springframework.batch.execution.launch.SimpleJobLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
public class SimpleJobLauncherTests extends TestCase {
|
||||
|
||||
@@ -97,15 +95,14 @@ public class SimpleJobLauncherTests extends TestCase {
|
||||
}
|
||||
}
|
||||
|
||||
public ExitStatus start(JobIdentifier runtimeInformation) {
|
||||
public void start(JobExecution execution)
|
||||
throws NoSuchJobConfigurationException {
|
||||
run();
|
||||
return ExitStatus.FAILED;
|
||||
}
|
||||
|
||||
public ExitStatus start(JobIdentifier jobIdentifier,
|
||||
JobExecutionListener listener)
|
||||
public JobExecution createNewExecution(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException {
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
return new JobExecution(new JobInstance(jobIdentifier));
|
||||
}
|
||||
|
||||
public void stop(JobIdentifier runtimeInformation) {
|
||||
|
||||
@@ -25,13 +25,11 @@ import junit.framework.TestCase;
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.batch.core.configuration.JobConfiguration;
|
||||
import org.springframework.batch.core.configuration.NoSuchJobConfigurationException;
|
||||
import org.springframework.batch.core.domain.JobExecution;
|
||||
import org.springframework.batch.core.domain.JobIdentifier;
|
||||
import org.springframework.batch.core.domain.JobInstance;
|
||||
import org.springframework.batch.core.runtime.SimpleJobIdentifier;
|
||||
import org.springframework.batch.core.runtime.SimpleJobIdentifierFactory;
|
||||
import org.springframework.batch.execution.launch.JobExecutionListener;
|
||||
import org.springframework.batch.execution.launch.JobExecutorFacade;
|
||||
import org.springframework.batch.execution.launch.SimpleJobLauncher;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.batch.statistics.StatisticsProvider;
|
||||
import org.springframework.batch.support.PropertiesConverter;
|
||||
import org.springframework.context.ApplicationEvent;
|
||||
@@ -44,8 +42,7 @@ public class TaskExecutorJobLauncherTests extends TestCase {
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
launcher
|
||||
.setJobIdentifierFactory(new SimpleJobIdentifierFactory());
|
||||
launcher.setJobIdentifierFactory(new SimpleJobIdentifierFactory());
|
||||
}
|
||||
|
||||
public void testStopContainer() throws Exception {
|
||||
@@ -57,10 +54,37 @@ public class TaskExecutorJobLauncherTests extends TestCase {
|
||||
launcher.setJobExecutorFacade(container);
|
||||
launcher.setJobConfigurationName(new JobConfiguration("foo").getName());
|
||||
|
||||
launcher.run();
|
||||
// give the thread some time to start up...
|
||||
Thread.sleep(100);
|
||||
assertTrue(launcher.isRunning());
|
||||
launcher.stop();
|
||||
// ...and to shut down:
|
||||
Thread.sleep(400);
|
||||
assertFalse(launcher.isRunning());
|
||||
}
|
||||
|
||||
public void testRunTwice() throws Exception {
|
||||
|
||||
// Important (otherwise start() does not return!)
|
||||
launcher.setTaskExecutor(new SimpleAsyncTaskExecutor());
|
||||
|
||||
InterruptibleContainer container = new InterruptibleContainer();
|
||||
launcher.setJobExecutorFacade(container);
|
||||
launcher.setJobConfigurationName(new JobConfiguration("foo").getName());
|
||||
|
||||
launcher.run();
|
||||
// give the thread some time to start up:
|
||||
Thread.sleep(100);
|
||||
assertTrue(launcher.isRunning());
|
||||
try {
|
||||
launcher.run();
|
||||
fail("Expected JobExecutionAlreadyRunningException");
|
||||
} catch (JobExecutionAlreadyRunningException e) {
|
||||
// expected
|
||||
}
|
||||
// give the thread some time to start up...
|
||||
Thread.sleep(100);
|
||||
launcher.stop();
|
||||
// ...and to shut down:
|
||||
Thread.sleep(400);
|
||||
@@ -112,22 +136,21 @@ public class TaskExecutorJobLauncherTests extends TestCase {
|
||||
// for interrupt to be called;
|
||||
Thread.sleep(300);
|
||||
} catch (InterruptedException ex) {
|
||||
// thread intterrupted, allow to exit normally
|
||||
// thread interrupted, allow to exit normally
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ExitStatus start(JobIdentifier jobIdentifier,
|
||||
JobExecutionListener listener)
|
||||
|
||||
public void start(JobExecution execution)
|
||||
throws NoSuchJobConfigurationException {
|
||||
throw new UnsupportedOperationException("Not implemented");
|
||||
start();
|
||||
}
|
||||
|
||||
public ExitStatus start(JobIdentifier runtimeInformation) {
|
||||
start();
|
||||
return ExitStatus.FAILED;
|
||||
public JobExecution createNewExecution(JobIdentifier jobIdentifier)
|
||||
throws NoSuchJobConfigurationException {
|
||||
return new JobExecution(new JobInstance(jobIdentifier));
|
||||
}
|
||||
|
||||
|
||||
public void stop(JobIdentifier runtimeInformation) {
|
||||
running = false;
|
||||
}
|
||||
@@ -148,12 +171,15 @@ public class TaskExecutorJobLauncherTests extends TestCase {
|
||||
|
||||
MockControl control = MockControl
|
||||
.createControl(JobExecutorFacade.class);
|
||||
JobExecutorFacade batchContainer = (JobExecutorFacade) control
|
||||
.getMock();
|
||||
launcher.setJobExecutorFacade(batchContainer);
|
||||
JobExecutorFacade facade = (JobExecutorFacade) control.getMock();
|
||||
launcher.setJobExecutorFacade(facade);
|
||||
SimpleJobIdentifier jobRuntimeInformation = new SimpleJobIdentifier(
|
||||
"spam");
|
||||
batchContainer.start(jobRuntimeInformation);
|
||||
JobExecution execution = new JobExecution(new JobInstance(
|
||||
jobRuntimeInformation));
|
||||
control.expectAndReturn(facade
|
||||
.createNewExecution(jobRuntimeInformation), execution);
|
||||
facade.start(execution);
|
||||
control.setThrowable(new NoSuchJobConfigurationException("SPAM"));
|
||||
|
||||
control.replay();
|
||||
|
||||
@@ -13,7 +13,7 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public abstract class AbstractCustomerCreditIncreaseTests extends AbstractLifecycleSpringContextTests {
|
||||
public abstract class AbstractCustomerCreditIncreaseTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
private JdbcOperations jdbcTemplate;
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
|
||||
* @author Lucas Ward
|
||||
* @see AbstractDependencyInjectionSpringContextTests
|
||||
*/
|
||||
public abstract class AbstractLifecycleSpringContextTests extends AbstractBatchLauncherTests {
|
||||
public abstract class AbstractValidatingBatchLauncherTests extends AbstractBatchLauncherTests {
|
||||
|
||||
public void testLaunchJob() throws Exception {
|
||||
validatePreConditions();
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.batch.sample;
|
||||
|
||||
|
||||
public class BeanWrapperMapperSampleJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class BeanWrapperMapperSampleJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[]{"jobs/beanWrapperMapperSampleJob.xml"};
|
||||
|
||||
@@ -16,7 +16,7 @@ import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
|
||||
|
||||
public class CompositeProcessorSampleFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class CompositeProcessorSampleFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
private static final String GET_TRADES = "SELECT isin, quantity, price, customer FROM trade order by isin";
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.core.io.Resource;
|
||||
import org.springframework.jdbc.core.JdbcOperations;
|
||||
import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
|
||||
public class FixedLengthImportJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class FixedLengthImportJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
//expected line length in input file (sum of pattern lengths + 2, because the counter is appended twice)
|
||||
private static final int LINE_LENGTH = 29;
|
||||
|
||||
@@ -21,7 +21,7 @@ import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class MultilineJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class MultilineJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
private static final String EXPECTED_RESULT =
|
||||
"[Trade: [isin=UK21341EAH45,quantity=978,price=98.34,customer=customer1], Trade: [isin=UK21341EAH46,quantity=112,price=18.12,customer=customer2]]" +
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.springframework.core.io.FileSystemResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class MultilineOrderJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class MultilineOrderJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
//private static final Log log = LogFactory.getLog(MultilineOrderJobFunctionalTests.class);
|
||||
|
||||
private static final String EXPECTED_OUTPUT =
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
package org.springframework.batch.sample;
|
||||
|
||||
public class NflJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class NflJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
protected String[] getConfigLocations() {
|
||||
return new String[] {"jobs/nfljob.xml"};
|
||||
return new String[] {"jobs/nfljob.xmlXXX"};
|
||||
}
|
||||
|
||||
protected void validatePostConditions() throws Exception {
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.jdbc.core.RowCallbackHandler;
|
||||
|
||||
|
||||
|
||||
public class TradeJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class TradeJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
private static final String GET_TRADES = "SELECT isin, quantity, price, customer FROM trade";
|
||||
private static final String GET_CUSTOMERS = "SELECT name, credit FROM customer";
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.custommonkey.xmlunit.XMLAssert;
|
||||
import org.custommonkey.xmlunit.XMLUnit;
|
||||
|
||||
|
||||
public class XmlStaxJobFunctionalTests extends AbstractLifecycleSpringContextTests {
|
||||
public class XmlStaxJobFunctionalTests extends AbstractValidatingBatchLauncherTests {
|
||||
|
||||
private static final String OUTPUT_FILE = "20070918.testStream.xmlFileStep.output.xml";
|
||||
private static final String EXPECTED_OUTPUT_FILE = "src/main/resources/data/staxJob/output/expected-output.xml";
|
||||
|
||||
Reference in New Issue
Block a user