1 | /* |
2 | * Copyright 2006-2008 the original author or authors. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | package org.springframework.batch.core.launch.support; |
17 | |
18 | import org.apache.commons.logging.Log; |
19 | import org.apache.commons.logging.LogFactory; |
20 | import org.springframework.batch.core.Job; |
21 | import org.springframework.batch.core.JobExecution; |
22 | import org.springframework.batch.core.JobInstance; |
23 | import org.springframework.batch.core.JobParameters; |
24 | import org.springframework.batch.core.launch.JobLauncher; |
25 | import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException; |
26 | import org.springframework.batch.core.repository.JobRestartException; |
27 | import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException; |
28 | import org.springframework.batch.core.repository.JobRepository; |
29 | import org.springframework.beans.factory.InitializingBean; |
30 | import org.springframework.core.task.SyncTaskExecutor; |
31 | import org.springframework.core.task.TaskExecutor; |
32 | import org.springframework.util.Assert; |
33 | |
34 | /** |
35 | * Simple implementation of the {@link JobLauncher} interface. The Spring Core {@link TaskExecutor} |
36 | * interface is used to launch a {@link Job}. This means that the type of executor set is very |
37 | * important. If a {@link SyncTaskExecutor} is used, then the job will be processed <strong>within |
38 | * the same thread that called the launcher.</strong> Care should be taken to ensure any users of |
39 | * this class understand fully whether or not the implementation of TaskExecutor used will start |
40 | * tasks synchronously or asynchronously. The default setting uses a synchronous task executor. |
41 | * |
42 | * There is only one required dependency of this Launcher, a {@link JobRepository}. The |
43 | * JobRepository is used to obtain a valid JobExecution. The Repository must be used because the |
44 | * provided {@link Job} could be a restart of an existing {@link JobInstance}, and only the |
45 | * Repository can reliably recreate it. |
46 | * |
47 | * @author Lucas Ward |
48 | * @since 1.0 |
49 | * @see JobRepository |
50 | * @see TaskExecutor |
51 | */ |
52 | public class SimpleJobLauncher implements JobLauncher, InitializingBean { |
53 | |
54 | protected static final Log logger = LogFactory.getLog(SimpleJobLauncher.class); |
55 | |
56 | private JobRepository jobRepository; |
57 | |
58 | private TaskExecutor taskExecutor; |
59 | |
60 | /** |
61 | * Run the provided job with the given {@link JobParameters}. The {@link JobParameters} will be |
62 | * used to determine if this is an execution of an existing job instance, or if a new one should |
63 | * be created. |
64 | * |
65 | * @param job the job to be run. |
66 | * @param jobParameters the {@link JobParameters} for this particular execution. |
67 | * @return JobExecutionAlreadyRunningException if the JobInstance already exists and has an |
68 | * execution already running. |
69 | * @throws JobRestartException if the execution would be a re-start, but a re-start is either |
70 | * not allowed or not needed. |
71 | * @throws JobInstanceAlreadyCompleteException |
72 | */ |
73 | public JobExecution run(final Job job, final JobParameters jobParameters) |
74 | throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException { |
75 | |
76 | Assert.notNull(job, "The Job must not be null."); |
77 | Assert.notNull(jobParameters, "The JobParameters must not be null."); |
78 | |
79 | final JobExecution jobExecution = jobRepository.createJobExecution(job, jobParameters); |
80 | |
81 | taskExecutor.execute(new Runnable() { |
82 | |
83 | public void run() { |
84 | try { |
85 | logger.info("Job: [" + job + "] launched with the following parameters: [" + jobParameters + "]"); |
86 | job.execute(jobExecution); |
87 | logger.info("Job: [" + job + "] completed successfully with the following parameters: [" |
88 | + jobParameters + "]"); |
89 | } catch (Throwable t) { |
90 | logger.info("Job: [" + job + "] failed with the following parameters: [" + jobParameters + "]", t); |
91 | rethrow(t); |
92 | } |
93 | } |
94 | |
95 | private void rethrow(Throwable t) { |
96 | if (t instanceof RuntimeException) { |
97 | throw (RuntimeException) t; |
98 | } |
99 | throw new RuntimeException(t); |
100 | } |
101 | }); |
102 | |
103 | return jobExecution; |
104 | } |
105 | |
106 | /** |
107 | * Set the JobRepsitory. |
108 | * |
109 | * @param jobRepository |
110 | */ |
111 | public void setJobRepository(JobRepository jobRepository) { |
112 | this.jobRepository = jobRepository; |
113 | } |
114 | |
115 | /** |
116 | * Set the TaskExecutor. (Optional) |
117 | * |
118 | * @param taskExecutor |
119 | */ |
120 | public void setTaskExecutor(TaskExecutor taskExecutor) { |
121 | this.taskExecutor = taskExecutor; |
122 | } |
123 | |
124 | /** |
125 | * Ensure the required dependencies of a {@link JobRepository} have been set. |
126 | */ |
127 | public void afterPropertiesSet() throws Exception { |
128 | Assert.state(jobRepository != null, "A JobRepository has not been set."); |
129 | if (taskExecutor == null) { |
130 | logger.info("No TaskExecutor has been set, defaulting to synchronous executor."); |
131 | taskExecutor = new SyncTaskExecutor(); |
132 | } |
133 | } |
134 | |
135 | } |