1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.springframework.batch.core.configuration.support;
17
18 import java.util.ArrayList;
19 import java.util.Collection;
20 import java.util.HashSet;
21 import java.util.Map;
22 import java.util.concurrent.ConcurrentHashMap;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.springframework.batch.core.Job;
27 import org.springframework.batch.core.Step;
28 import org.springframework.batch.core.configuration.DuplicateJobException;
29 import org.springframework.batch.core.configuration.JobFactory;
30 import org.springframework.batch.core.configuration.JobRegistry;
31 import org.springframework.batch.core.configuration.StepRegistry;
32 import org.springframework.batch.core.launch.NoSuchJobException;
33 import org.springframework.batch.core.step.StepLocator;
34 import org.springframework.beans.factory.InitializingBean;
35 import org.springframework.context.ApplicationContext;
36 import org.springframework.context.ConfigurableApplicationContext;
37 import org.springframework.util.Assert;
38
39
40
41
42
43
44
45
46
47
48 public class DefaultJobLoader implements JobLoader, InitializingBean {
49
50 private static Log logger = LogFactory.getLog(DefaultJobLoader.class);
51
52 private JobRegistry jobRegistry;
53 private StepRegistry stepRegistry;
54
55 private Map<ApplicationContextFactory, ConfigurableApplicationContext> contexts = new ConcurrentHashMap<ApplicationContextFactory, ConfigurableApplicationContext>();
56
57 private Map<ConfigurableApplicationContext, Collection<String>> contextToJobNames = new ConcurrentHashMap<ConfigurableApplicationContext, Collection<String>>();
58
59
60
61
62 public DefaultJobLoader() {
63 this(null, null);
64 }
65
66
67
68
69
70
71 public DefaultJobLoader(JobRegistry jobRegistry) {
72 this(jobRegistry, null);
73 }
74
75
76
77
78
79
80
81 public DefaultJobLoader(JobRegistry jobRegistry, StepRegistry stepRegistry) {
82 this.jobRegistry = jobRegistry;
83 this.stepRegistry = stepRegistry;
84 }
85
86
87
88
89
90
91 public void setJobRegistry(JobRegistry jobRegistry) {
92 this.jobRegistry = jobRegistry;
93 }
94
95
96
97
98
99
100 public void setStepRegistry(StepRegistry stepRegistry) {
101 this.stepRegistry = stepRegistry;
102 }
103
104
105
106
107
108
109
110 @Override
111 public void clear() {
112 for (ConfigurableApplicationContext context : contexts.values()) {
113 if (context.isActive()) {
114 context.close();
115 }
116 }
117 for (String jobName : jobRegistry.getJobNames()) {
118 doUnregister(jobName);
119 }
120 contexts.clear();
121 }
122
123 @Override
124 public Collection<Job> reload(ApplicationContextFactory factory) {
125
126
127 if (contexts.containsKey(factory)) {
128 ConfigurableApplicationContext context = contexts.get(factory);
129 for (String name : contextToJobNames.get(context)) {
130 logger.debug("Unregistering job: " + name + " from context: " + context.getDisplayName());
131 doUnregister(name);
132 }
133 context.close();
134 }
135
136 try {
137 return doLoad(factory, true);
138 }
139 catch (DuplicateJobException e) {
140 throw new IllegalStateException("Found duplicate job in reload (it should have been unregistered "
141 + "if it was previously registered in this loader)", e);
142 }
143 }
144
145 @Override
146 public Collection<Job> load(ApplicationContextFactory factory) throws DuplicateJobException {
147 return doLoad(factory, false);
148 }
149
150 private Collection<Job> doLoad(ApplicationContextFactory factory, boolean unregister) throws DuplicateJobException {
151
152 Collection<String> jobNamesBefore = jobRegistry.getJobNames();
153 ConfigurableApplicationContext context = factory.createApplicationContext();
154 Collection<String> jobNamesAfter = jobRegistry.getJobNames();
155
156 boolean autoRegistrationDetected = jobNamesAfter.size() > jobNamesBefore.size();
157
158 Collection<String> jobsRegistered = new HashSet<String>();
159 if (autoRegistrationDetected) {
160 for (String name : jobNamesAfter) {
161 if (!jobNamesBefore.contains(name)) {
162 jobsRegistered.add(name);
163 }
164 }
165 }
166
167 contexts.put(factory, context);
168 String[] names = context.getBeanNamesForType(Job.class);
169
170 for (String name : names) {
171
172 if (!autoRegistrationDetected) {
173
174 Job job = (Job) context.getBean(name);
175 String jobName = job.getName();
176
177
178 if (unregister) {
179 logger.debug("Unregistering job: " + jobName + " from context: " + context.getDisplayName());
180 doUnregister(jobName);
181 }
182
183 logger.debug("Registering job: " + jobName + " from context: " + context.getDisplayName());
184 doRegister(context, job);
185 jobsRegistered.add(jobName);
186 }
187
188 }
189
190 Collection<Job> result = new ArrayList<Job>();
191 for (String name : jobsRegistered) {
192 try {
193 result.add(jobRegistry.getJob(name));
194 }
195 catch (NoSuchJobException e) {
196
197 throw new IllegalStateException("Could not retrieve job that was should have been registered", e);
198 }
199
200 }
201
202 contextToJobNames.put(context, jobsRegistered);
203
204 return result;
205
206 }
207
208
209
210
211
212
213
214
215
216
217
218
219 private Collection<Step> getSteps(final StepLocator stepLocator, final ApplicationContext jobApplicationContext) {
220 final Collection<String> stepNames = stepLocator.getStepNames();
221 final Collection<Step> result = new ArrayList<Step>();
222 for (String stepName : stepNames) {
223 result.add(stepLocator.getStep(stepName));
224 }
225
226
227
228
229 @SuppressWarnings("unchecked")
230 final Map<String, Step> allSteps = jobApplicationContext.getBeansOfType(Step.class);
231 for (Map.Entry<String, Step> entry : allSteps.entrySet()) {
232 if (!stepNames.contains(entry.getKey())) {
233 result.add(entry.getValue());
234 }
235 }
236 return result;
237 }
238
239
240
241
242
243
244
245
246
247
248 private void doRegister(ConfigurableApplicationContext context, Job job) throws DuplicateJobException {
249 final JobFactory jobFactory = new ReferenceJobFactory(job);
250 jobRegistry.register(jobFactory);
251
252 if (stepRegistry != null) {
253 if (!(job instanceof StepLocator)) {
254 throw new UnsupportedOperationException("Cannot locate steps from a Job that is not a StepLocator: job="
255 + job.getName() + " does not implement StepLocator");
256 }
257 stepRegistry.register(job.getName(), getSteps((StepLocator) job, context));
258 }
259 }
260
261
262
263
264
265
266 private void doUnregister(String jobName) {
267 jobRegistry.unregister(jobName);
268 if (stepRegistry != null) {
269 stepRegistry.unregisterStepsFromJob(jobName);
270 }
271
272 }
273
274 @Override
275 public void afterPropertiesSet() {
276 Assert.notNull(jobRegistry, "Job registry could not be null.");
277 }
278 }