EMMA Coverage Report (generated Thu May 22 12:08:10 CDT 2014)
[all classes][org.springframework.batch.core.configuration.support]

COVERAGE SUMMARY FOR SOURCE FILE [DefaultJobLoader.java]

nameclass, %method, %block, %line, %
DefaultJobLoader.java100% (1/1)100% (14/14)92%  (379/414)91%  (81.9/90)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class DefaultJobLoader100% (1/1)100% (14/14)92%  (379/414)91%  (81.9/90)
doLoad (ApplicationContextFactory, boolean): Collection 100% (1/1)83%  (134/162)80%  (24.9/31)
reload (ApplicationContextFactory): Collection 100% (1/1)88%  (51/58)80%  (8/10)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)
DefaultJobLoader (): void 100% (1/1)100% (5/5)100% (2/2)
DefaultJobLoader (JobRegistry): void 100% (1/1)100% (5/5)100% (2/2)
DefaultJobLoader (JobRegistry, StepRegistry): void 100% (1/1)100% (19/19)100% (6/6)
afterPropertiesSet (): void 100% (1/1)100% (5/5)100% (2/2)
clear (): void 100% (1/1)100% (38/38)100% (9/9)
doRegister (ConfigurableApplicationContext, Job): void 100% (1/1)100% (41/41)100% (7/7)
doUnregister (String): void 100% (1/1)100% (12/12)100% (4/4)
getSteps (StepLocator, ApplicationContext): Collection 100% (1/1)100% (52/52)100% (11/11)
load (ApplicationContextFactory): Collection 100% (1/1)100% (5/5)100% (1/1)
setJobRegistry (JobRegistry): void 100% (1/1)100% (4/4)100% (2/2)
setStepRegistry (StepRegistry): void 100% (1/1)100% (4/4)100% (2/2)

1/*
2 * Copyright 2006-2013 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 */
16package org.springframework.batch.core.configuration.support;
17 
18import java.util.ArrayList;
19import java.util.Collection;
20import java.util.HashSet;
21import java.util.Map;
22import java.util.concurrent.ConcurrentHashMap;
23 
24import org.apache.commons.logging.Log;
25import org.apache.commons.logging.LogFactory;
26import org.springframework.batch.core.Job;
27import org.springframework.batch.core.Step;
28import org.springframework.batch.core.configuration.DuplicateJobException;
29import org.springframework.batch.core.configuration.JobFactory;
30import org.springframework.batch.core.configuration.JobRegistry;
31import org.springframework.batch.core.configuration.StepRegistry;
32import org.springframework.batch.core.launch.NoSuchJobException;
33import org.springframework.batch.core.step.StepLocator;
34import org.springframework.beans.factory.InitializingBean;
35import org.springframework.context.ApplicationContext;
36import org.springframework.context.ConfigurableApplicationContext;
37import org.springframework.util.Assert;
38 
39/**
40 * Default implementation of {@link JobLoader}. Uses a {@link JobRegistry} to
41 * manage a population of loaded jobs and clears them up when asked. An optional
42 * {@link StepRegistry} might also be set to register the step(s) available for
43 * each registered job.
44 *
45 * @author Dave Syer
46 * @author Stephane Nicoll
47 */
48public 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         * Default constructor useful for declarative configuration.
61         */
62        public DefaultJobLoader() {
63                this(null, null);
64        }
65 
66        /**
67         * Creates a job loader with the job registry provided.
68         *
69         * @param jobRegistry a {@link JobRegistry}
70         */
71        public DefaultJobLoader(JobRegistry jobRegistry) {
72                this(jobRegistry, null);
73        }
74 
75        /**
76         * Creates a job loader with the job and step registries provided.
77         *
78         * @param jobRegistry a {@link JobRegistry}
79         * @param stepRegistry a {@link StepRegistry}
80         */
81        public DefaultJobLoader(JobRegistry jobRegistry, StepRegistry stepRegistry) {
82                this.jobRegistry = jobRegistry;
83                this.stepRegistry = stepRegistry;
84        }
85 
86        /**
87         * The {@link JobRegistry} to use for jobs created.
88         *
89         * @param jobRegistry the job registry
90         */
91        public void setJobRegistry(JobRegistry jobRegistry) {
92                this.jobRegistry = jobRegistry;
93        }
94 
95        /**
96         * The {@link StepRegistry} to use for the steps of created jobs.
97         *
98         * @param stepRegistry the step registry
99         */
100        public void setStepRegistry(StepRegistry stepRegistry) {
101                this.stepRegistry = stepRegistry;
102        }
103 
104        /**
105         * Unregister all the jobs and close all the contexts created by this
106         * loader.
107         *
108         * @see JobLoader#clear()
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                // If the same factory is loaded twice the context can be closed
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                // Try to detect auto-registration (e.g. through a bean post processor)
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                                // On reload try to unregister first
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                                // should not happen;
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         * Returns all the {@link Step} instances defined by the specified {@link StepLocator}.
210         * <p/>
211         * The specified <tt>jobApplicationContext</tt> is used to collect additional steps that
212         * are not exposed by the step locator
213         *
214         * @param stepLocator the given step locator
215         * @param jobApplicationContext the application context of the job
216         * @return all the {@link Step} defined by the given step locator and context
217         * @see StepLocator
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                // Because some steps are referenced by name, we need to look in the context to see if there
227                // are more Step instances defined. Right now they are registered as being available in the
228                // context of the job but we have no idea if they are linked to that Job or not.
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         * Registers the specified {@link Job} defined in the specified {@link ConfigurableApplicationContext}.
241         * <p/>
242         * Makes sure to update the {@link StepRegistry} if it is available.
243         *
244         * @param context the context in which the job is defined
245         * @param job the job to register
246         * @throws DuplicateJobException if that job is already registered
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         * Unregisters the job identified by the specified <tt>jobName</tt>.
263         *
264         * @param jobName the name of the job to unregister
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}

[all classes][org.springframework.batch.core.configuration.support]
EMMA 2.0.5312 (C) Vladimir Roubtsov