diff --git a/execution/src/main/java/org/springframework/batch/execution/bootstrap/AbstractJobLauncher.java b/execution/src/main/java/org/springframework/batch/execution/bootstrap/AbstractJobLauncher.java index 9b0918e4b..23b6c376e 100644 --- a/execution/src/main/java/org/springframework/batch/execution/bootstrap/AbstractJobLauncher.java +++ b/execution/src/main/java/org/springframework/batch/execution/bootstrap/AbstractJobLauncher.java @@ -31,6 +31,8 @@ import org.springframework.batch.core.runtime.JobIdentifierFactory; import org.springframework.batch.execution.JobExecutorFacade; import org.springframework.batch.execution.NoSuchJobExecutionException; import org.springframework.batch.execution.runtime.ScheduledJobIdentifierFactory; +import org.springframework.batch.io.exception.BatchConfigurationException; +import org.springframework.batch.repeat.ExitStatus; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationEvent; import org.springframework.context.ApplicationListener; @@ -38,8 +40,8 @@ import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.util.Assert; /** - * Base class for {@link JobLauncher} implementations making no - * choices about concurrent processing of jobs. + * Base class for {@link JobLauncher} implementations making no choices about + * concurrent processing of jobs. * * @see JobLauncher * @author Lucas Ward @@ -47,7 +49,8 @@ import org.springframework.util.Assert; public abstract class AbstractJobLauncher implements JobLauncher, InitializingBean, ApplicationListener { - private static final Log logger = LogFactory.getLog(AbstractJobLauncher.class); + private static final Log logger = LogFactory + .getLog(AbstractJobLauncher.class); protected JobExecutorFacade batchContainer; @@ -67,17 +70,19 @@ public abstract class AbstractJobLauncher implements JobLauncher, /** * Setter for {@link JobIdentifier}. * - * @param jobRuntimeInformationFactory the jobRuntimeInformationFactory to - * set + * @param jobRuntimeInformationFactory + * the jobRuntimeInformationFactory to set */ - public void setJobRuntimeInformationFactory(JobIdentifierFactory jobRuntimeInformationFactory) { + public void setJobRuntimeInformationFactory( + JobIdentifierFactory jobRuntimeInformationFactory) { this.jobRuntimeInformationFactory = jobRuntimeInformationFactory; } /** * Setter for the {@link JobConfiguration} that this launcher will run. * - * @param jobConfiguration the jobConfiguration to set + * @param jobConfiguration + * the jobConfiguration to set */ public void setJobConfigurationName(String jobConfiguration) { this.jobConfigurationName = jobConfiguration; @@ -113,24 +118,37 @@ public abstract class AbstractJobLauncher implements JobLauncher, } /** - * If autostart flag is on, initialise on context start-up. + * If autostart flag is on, initialise on context start-up and call {@link #run()}. + * + * @throws BatchConfigurationException + * if the job tries to but cannot start because of a + * {@link NoSuchJobConfigurationException}. * * @see org.springframework.context.ApplicationListener#onApplicationEvent(org.springframework.context.ApplicationEvent) + * */ public void onApplicationEvent(ApplicationEvent event) { - if ((event instanceof ContextRefreshedEvent) && this.autoStart && !isRunning()) { - start(); + if ((event instanceof ContextRefreshedEvent) && this.autoStart + && !isRunning()) { + try { + run(); + } catch (NoSuchJobConfigurationException e) { + throw new BatchConfigurationException( + "Cannot start job on context refresh", e); + } } } /** * Extension point for subclasses. Implementations might choose to start the * job in a new thread or in the current thread.
- * @param runtimeInformation the {@link JobIdentifier} to start the - * launcher with. - * @throws NoSuchJobConfigurationException + * + * @param runtimeInformation + * the {@link JobIdentifier} to start the launcher with. + * @throws NoSuchJobConfigurationException */ - protected abstract void doStart(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException; + protected abstract void doStart(JobIdentifier jobIdentifier) + throws NoSuchJobConfigurationException; /** * Start the provided container. The current thread will first be saved. @@ -138,15 +156,19 @@ public abstract class AbstractJobLauncher implements JobLauncher, * 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 if the container cannot locate a job configuration - * @throws IllegalStateException if JobConfiguration is null. + * + * @throws NoSuchJobConfigurationException + * if the container cannot locate a job configuration + * @throws IllegalStateException + * if JobConfiguration is null. * @see Lifecycle#start(). */ - public void start(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException { + public ExitStatus run(JobIdentifier jobIdentifier) + throws NoSuchJobConfigurationException { synchronized (monitor) { if (isRunning(jobIdentifier)) { - return; + return ExitStatus.RUNNING; } } @@ -159,63 +181,69 @@ public abstract class AbstractJobLauncher implements JobLauncher, * without waiting for the job to finish, then we will have a job * running that is not in the registry. */ + + return ExitStatus.RUNNING; } /** * 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 + * @param name + * the name to assign to the job + * @throws NoSuchJobConfigurationException */ - public void start(String name) throws NoSuchJobConfigurationException { - JobIdentifier runtimeInformation = jobRuntimeInformationFactory.getJobIdentifier(name); - this.start(runtimeInformation); + public ExitStatus run(String name) throws NoSuchJobConfigurationException { + JobIdentifier runtimeInformation = jobRuntimeInformationFactory + .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 + * + * @throws NoSuchJobConfigurationException + * + * @throws NoSuchJobConfigurationException + * if the job configuration cannot be located * * @see #setJobRuntimeInformationFactory(JobIdentifierFactory) * @see org.springframework.context.Lifecycle#start() */ - public void start() { - if (jobConfigurationName==null) { - return; - } - try { - this.start(jobConfigurationName); - } - catch (NoSuchJobConfigurationException e) { - logger.error("Could not start", e); + public ExitStatus run() throws NoSuchJobConfigurationException { + if (jobConfigurationName != null) { + return this.run(jobConfigurationName); } + return ExitStatus.FAILED; } /** * Extension point for subclasses to stop a specific job. - * @throws NoSuchJobExecutionException + * + * @throws NoSuchJobExecutionException * * @see org.springframework.batch.container.bootstrap.BatchContainerLauncher#stop(JobRuntimeInformation)) */ - protected abstract void doStop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException; + protected abstract void doStop(JobIdentifier runtimeInformation) + throws NoSuchJobExecutionException; /** * Stop all jobs if any are running. If not, no action will be taken. * Delegates to the {@link #doStop()} method. - * @throws NoSuchJobExecutionException + * + * @throws NoSuchJobExecutionException * @see org.springframework.context.Lifecycle#stop() * @see org.springframework.batch.execution.bootstrap.JobLauncher#stop() */ final public void stop() { - for (Iterator iter = new HashSet(registry.keySet()).iterator(); iter.hasNext();) { + for (Iterator iter = new HashSet(registry.keySet()).iterator(); iter + .hasNext();) { JobIdentifier context = (JobIdentifier) iter.next(); try { stop(context); - } - catch (NoSuchJobExecutionException e) { + } catch (NoSuchJobExecutionException e) { logger.error(e); } } @@ -224,21 +252,24 @@ public abstract class AbstractJobLauncher implements JobLauncher, /** * Stop a job with this {@link JobIdentifier}. Delegates to the * {@link #doStop(JobIdentifier)} method. - * @throws NoSuchJobExecutionException + * + * @throws NoSuchJobExecutionException * * @see org.springframework.batch.execution.bootstrap.JobLauncher#stop(org.springframework.batch.core.runtime.JobIdentifier) * @see BatchContainer#stop(JobRuntimeInformation)) */ - final public void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException { + final public void stop(JobIdentifier runtimeInformation) + throws NoSuchJobExecutionException { synchronized (monitor) { doStop(runtimeInformation); } } /** - * Stop all jobs with {@link JobIdentifier} having this name. - * Delegates to the {@link #stop(JobIdentifier)}. - * @throws NoSuchJobExecutionException + * Stop all jobs with {@link JobIdentifier} having this name. Delegates to + * the {@link #stop(JobIdentifier)}. + * + * @throws NoSuchJobExecutionException * * @see org.springframework.batch.execution.bootstrap.JobLauncher#stop(java.lang.String) */ @@ -248,6 +279,7 @@ public abstract class AbstractJobLauncher implements JobLauncher, /* * (non-Javadoc) + * * @see org.springframework.batch.container.bootstrap.BatchContainerLauncher#isRunning() */ public boolean isRunning() { @@ -270,6 +302,7 @@ public abstract class AbstractJobLauncher implements JobLauncher, /** * Convenient synchronized accessor for the registry. Can be used by * subclasses if necessary (but it isn't likely). + * * @param runtimeInformation */ protected void register(JobIdentifier runtimeInformation) { @@ -280,8 +313,8 @@ public abstract class AbstractJobLauncher implements JobLauncher, /** * Convenient synchronized accessor for the registry. Must be used by - * subclasses to release the {@link JobIdentifier} when a job is - * finished (or stopped). + * subclasses to release the {@link JobIdentifier} when a job is finished + * (or stopped). * * @param runtimeInformation */ diff --git a/execution/src/main/java/org/springframework/batch/execution/bootstrap/BatchCommandLineLauncher.java b/execution/src/main/java/org/springframework/batch/execution/bootstrap/BatchCommandLineLauncher.java index 73e2cafe0..591973d2f 100644 --- a/execution/src/main/java/org/springframework/batch/execution/bootstrap/BatchCommandLineLauncher.java +++ b/execution/src/main/java/org/springframework/batch/execution/bootstrap/BatchCommandLineLauncher.java @@ -35,7 +35,7 @@ public class BatchCommandLineLauncher { private ConfigurableApplicationContext parent; - private SynchronousJobLauncher launcher; + private JobLauncher launcher; /** * Default constructor for the launcher. Sets up the parent context to use @@ -51,7 +51,7 @@ public class BatchCommandLineLauncher { * * @param launcher the launcher to set */ - public void setLauncher(SynchronousJobLauncher launcher) { + public void setLauncher(JobLauncher launcher) { this.launcher = launcher; } diff --git a/execution/src/main/java/org/springframework/batch/execution/bootstrap/JobLauncher.java b/execution/src/main/java/org/springframework/batch/execution/bootstrap/JobLauncher.java index 639227754..333469903 100644 --- a/execution/src/main/java/org/springframework/batch/execution/bootstrap/JobLauncher.java +++ b/execution/src/main/java/org/springframework/batch/execution/bootstrap/JobLauncher.java @@ -1,91 +1,39 @@ -/* - * 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.JobExecutorFacade; -import org.springframework.batch.execution.NoSuchJobExecutionException; -import org.springframework.context.Lifecycle; - -/** - * Simple interface for controlling a {@link JobExecutorFacade} for a single job - * configuration, and also possibly ad-hoc executions, based on different - * runtime information. Implementations should concentrate on launching and - * controlling a single job, as configured in a {@link JobExecutorFacade} instance. - * - * @author Dave Syer - * @since 2.1 - */ -public interface JobLauncher extends Lifecycle { - - /** - * Return whether or not a job execution is currently running. - */ - boolean isRunning(); - - /** - * Start a job execution with the given runtime information. - * @throws NoSuchJobConfigurationException - */ - void start(JobIdentifier runtimeInformation) 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 - * @throws NoSuchJobConfigurationException - */ - void start(String name) throws NoSuchJobConfigurationException; - - /** - * Start a job execution with default name and other runtime information - * generated on the fly.
- * - * Because {@link Lifecycle#start()} does not throw checked exceptions this - * also does not, so an error message and stack trace will be logged if the - * required job(s) cannot be started. - * - * @see org.springframework.context.Lifecycle#start() - */ - public void start(); - - /** - * Stop the job execution that was started with this runtime information. - * @param runtimeInformation the {@link JobIdentifier}. - * @throws NoSuchJobExecutionException - */ - void stop(JobIdentifier runtimeInformation) throws NoSuchJobExecutionException; - - /** - * Stop all currently executing jobs matching the given name. All jobs - * started with {@link JobIdentifier} having this name will be - * stopped. - * @throws NoSuchJobExecutionException - */ - void stop(String name) throws NoSuchJobExecutionException; - - /** - * Stop the current job executions if there are any. If not, no action will - * be taken. - * @throws NoSuchJobExecutionException - * - * @see org.springframework.context.Lifecycle#stop() - */ - public void stop(); -} +/* + * 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.repeat.ExitStatus; + +/** + * + * @author Lucas Ward + */ + +public interface JobLauncher { + + public ExitStatus run() throws NoSuchJobConfigurationException; + + public ExitStatus run(String jobName) throws NoSuchJobConfigurationException; + + public ExitStatus run(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException; + + public void stop(); + + public boolean isRunning(); + +} diff --git a/execution/src/main/java/org/springframework/batch/execution/bootstrap/SimpleJobLauncher.java b/execution/src/main/java/org/springframework/batch/execution/bootstrap/SimpleJobLauncher.java index 0024de97c..87014e491 100644 --- a/execution/src/main/java/org/springframework/batch/execution/bootstrap/SimpleJobLauncher.java +++ b/execution/src/main/java/org/springframework/batch/execution/bootstrap/SimpleJobLauncher.java @@ -43,7 +43,7 @@ import org.springframework.util.Assert; * @author Dave Syer * @since 2.1 */ -public class SimpleJobLauncher implements SynchronousJobLauncher { +public class SimpleJobLauncher implements JobLauncher { private static final Log logger = LogFactory.getLog(SimpleJobLauncher.class); diff --git a/execution/src/main/java/org/springframework/batch/execution/bootstrap/SynchronousJobLauncher.java b/execution/src/main/java/org/springframework/batch/execution/bootstrap/SynchronousJobLauncher.java deleted file mode 100644 index 6927f0628..000000000 --- a/execution/src/main/java/org/springframework/batch/execution/bootstrap/SynchronousJobLauncher.java +++ /dev/null @@ -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; - -import org.springframework.batch.core.configuration.NoSuchJobConfigurationException; -import org.springframework.batch.core.runtime.JobIdentifier; -import org.springframework.batch.repeat.ExitStatus; - -/** - * - * @author Lucas Ward - */ - -public interface SynchronousJobLauncher { - - public ExitStatus run(); - - public ExitStatus run(String jobName) throws NoSuchJobConfigurationException; - - public ExitStatus run(JobIdentifier jobIdentifier) throws NoSuchJobConfigurationException; - - public void stop(); - - public boolean isRunning(); - -} diff --git a/execution/src/test/java/org/springframework/batch/execution/bootstrap/TaskExecutorJobLauncherTests.java b/execution/src/test/java/org/springframework/batch/execution/bootstrap/TaskExecutorJobLauncherTests.java index d88377169..821b3ee9c 100644 --- a/execution/src/test/java/org/springframework/batch/execution/bootstrap/TaskExecutorJobLauncherTests.java +++ b/execution/src/test/java/org/springframework/batch/execution/bootstrap/TaskExecutorJobLauncherTests.java @@ -43,12 +43,12 @@ import org.springframework.jmx.export.notification.UnableToSendNotificationExcep public class TaskExecutorJobLauncherTests extends TestCase { - private TaskExecutorJobLauncher bootstrap = new TaskExecutorJobLauncher(); + private TaskExecutorJobLauncher launcher = new TaskExecutorJobLauncher(); protected void setUp() throws Exception { super.setUp(); final SimpleJobIdentifier runtimeInformation = new SimpleJobIdentifier("foo"); - bootstrap.setJobRuntimeInformationFactory(new JobIdentifierFactory() { + launcher.setJobRuntimeInformationFactory(new JobIdentifierFactory() { public JobIdentifier getJobIdentifier(String name) { return runtimeInformation; } @@ -58,46 +58,46 @@ public class TaskExecutorJobLauncherTests extends TestCase { public void testStopContainer() throws Exception { // Important (otherwise start() does not return!) - bootstrap.setTaskExecutor(new SimpleAsyncTaskExecutor()); + launcher.setTaskExecutor(new SimpleAsyncTaskExecutor()); InterruptibleContainer container = new InterruptibleContainer(); - bootstrap.setBatchContainer(container); - bootstrap.setJobConfigurationName(new JobConfiguration("foo").getName()); + launcher.setBatchContainer(container); + launcher.setJobConfigurationName(new JobConfiguration("foo").getName()); - bootstrap.start(); + launcher.run(); // give the thread some time to start up: Thread.sleep(100); - assertTrue(bootstrap.isRunning()); - bootstrap.stop(); + assertTrue(launcher.isRunning()); + launcher.stop(); // ...and to shut down: Thread.sleep(400); - assertFalse(bootstrap.isRunning()); + assertFalse(launcher.isRunning()); } public void testNormalApplicationEventNotRecognized() throws Exception { - bootstrap.onApplicationEvent(new ApplicationEvent("foo") {}); + launcher.onApplicationEvent(new ApplicationEvent("foo") {}); // nothing happens } public void testRepeatOperationsBeforeNotUsed() throws Exception { final List list = new ArrayList(); - bootstrap.setNotificationPublisher(new NotificationPublisher() { + launcher.setNotificationPublisher(new NotificationPublisher() { public void sendNotification(Notification notification) throws UnableToSendNotificationException { list.add(notification); } }); - bootstrap.onApplicationEvent(new RepeatOperationsApplicationEvent(this, "foo", RepeatOperationsApplicationEvent.BEFORE) {}); + launcher.onApplicationEvent(new RepeatOperationsApplicationEvent(this, "foo", RepeatOperationsApplicationEvent.BEFORE) {}); assertEquals(0, list.size()); } public void testRepeatOperationsOpenUsed() throws Exception { final List list = new ArrayList(); - bootstrap.setNotificationPublisher(new NotificationPublisher() { + launcher.setNotificationPublisher(new NotificationPublisher() { public void sendNotification(Notification notification) throws UnableToSendNotificationException { list.add(notification); } }); - bootstrap.onApplicationEvent(new RepeatOperationsApplicationEvent(this, "foo", RepeatOperationsApplicationEvent.OPEN)); + launcher.onApplicationEvent(new RepeatOperationsApplicationEvent(this, "foo", RepeatOperationsApplicationEvent.OPEN)); assertEquals(1, list.size()); assertEquals("foo", ((Notification) list.get(0)).getMessage().substring(0, 3)); } @@ -105,24 +105,24 @@ public class TaskExecutorJobLauncherTests extends TestCase { public void testStatisticsRetrieved() throws Exception { MockControl control = MockControl.createControl(JobExecutorFacadeWithStatistics.class); JobExecutorFacadeWithStatistics batchContainer = (JobExecutorFacadeWithStatistics) control.getMock(); - bootstrap.setBatchContainer(batchContainer); + launcher.setBatchContainer(batchContainer); Properties properties = PropertiesConverter.stringToProperties("a=b"); control.expectAndReturn(batchContainer.getStatistics(), properties); control.replay(); - assertEquals(properties, bootstrap.getStatistics()); + assertEquals(properties, launcher.getStatistics()); control.verify(); } public void testStatisticsNotRetrieved() throws Exception { MockControl control = MockControl.createControl(JobExecutorFacade.class); JobExecutorFacade batchContainer = (JobExecutorFacade) control.getMock(); - bootstrap.setBatchContainer(batchContainer); + launcher.setBatchContainer(batchContainer); Properties properties = new Properties(); control.replay(); - assertEquals(properties, bootstrap.getStatistics()); + assertEquals(properties, launcher.getStatistics()); control.verify(); } @@ -160,7 +160,7 @@ public class TaskExecutorJobLauncherTests extends TestCase { public void testPublishApplicationEvent() throws Exception { final List list = new ArrayList(); - bootstrap.setApplicationEventPublisher(new ApplicationEventPublisher() { + launcher.setApplicationEventPublisher(new ApplicationEventPublisher() { public void publishEvent(ApplicationEvent event) { list.add(event); } @@ -168,13 +168,13 @@ public class TaskExecutorJobLauncherTests extends TestCase { MockControl control = MockControl.createControl(JobExecutorFacade.class); JobExecutorFacade batchContainer = (JobExecutorFacade) control.getMock(); - bootstrap.setBatchContainer(batchContainer); + launcher.setBatchContainer(batchContainer); SimpleJobIdentifier jobRuntimeInformation = new SimpleJobIdentifier("spam"); batchContainer.start(jobRuntimeInformation); control.setThrowable(new NoSuchJobConfigurationException("SPAM")); control.replay(); - bootstrap.start(jobRuntimeInformation); + launcher.run(jobRuntimeInformation); assertEquals(1, list.size()); control.verify(); }