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

COVERAGE SUMMARY FOR SOURCE FILE [JobRegistryBackgroundJobRunner.java]

nameclass, %method, %block, %line, %
JobRegistryBackgroundJobRunner.java100% (2/2)93%  (14/15)78%  (285/366)79%  (64.6/82)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class JobRegistryBackgroundJobRunner$1100% (1/1)100% (2/2)61%  (11/18)57%  (4/7)
run (): void 100% (1/1)42%  (5/12)50%  (3/6)
JobRegistryBackgroundJobRunner$1 (JobRegistryBackgroundJobRunner): void 100% (1/1)100% (6/6)100% (1/1)
     
class JobRegistryBackgroundJobRunner100% (1/1)92%  (12/13)79%  (274/348)81%  (61.6/76)
access$100 (): List 0%   (0/1)0%   (0/2)0%   (0/1)
maybeCreateJobLoader (): void 100% (1/1)58%  (28/48)67%  (8/12)
stop (): void 100% (1/1)67%  (10/15)91%  (3.6/4)
getErrors (): List 100% (1/1)69%  (11/16)67%  (2/3)
main (String []): void 100% (1/1)70%  (96/138)68%  (18.3/27)
<static initializer> 100% (1/1)100% (21/21)100% (4/4)
JobRegistryBackgroundJobRunner (String): void 100% (1/1)100% (9/9)100% (4/4)
access$000 (JobRegistryBackgroundJobRunner): void 100% (1/1)100% (3/3)100% (1/1)
destroy (): void 100% (1/1)100% (4/4)100% (2/2)
register (String []): void 100% (1/1)100% (60/60)100% (10/10)
run (): void 100% (1/1)100% (24/24)100% (5/5)
setJobLoader (JobLoader): void 100% (1/1)100% (4/4)100% (2/2)
setJobRegistry (JobRegistry): 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.launch.support;
17 
18import java.io.IOException;
19import java.util.ArrayList;
20import java.util.Arrays;
21import java.util.Collections;
22import java.util.List;
23 
24import org.apache.commons.logging.Log;
25import org.apache.commons.logging.LogFactory;
26import org.springframework.batch.core.Job;
27import org.springframework.batch.core.configuration.DuplicateJobException;
28import org.springframework.batch.core.configuration.JobFactory;
29import org.springframework.batch.core.configuration.JobRegistry;
30import org.springframework.batch.core.configuration.support.DefaultJobLoader;
31import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory;
32import org.springframework.batch.core.configuration.support.JobLoader;
33import org.springframework.batch.core.launch.JobLauncher;
34import org.springframework.beans.factory.BeanFactory;
35import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
36import org.springframework.context.ApplicationContext;
37import org.springframework.context.support.ClassPathXmlApplicationContext;
38import org.springframework.core.io.Resource;
39import org.springframework.util.Assert;
40 
41/**
42 * <p>
43 * Command line launcher for registering jobs with a {@link JobRegistry}.
44 * Normally this will be used in conjunction with an external trigger for the
45 * jobs registered, e.g. a JMX MBean wrapper for a {@link JobLauncher}, or a
46 * Quartz trigger.
47 * </p>
48 *
49 * <p>
50 * With any launch of a batch job within Spring Batch, a Spring context
51 * containing the {@link Job} has to be created. Using this launcher, the jobs
52 * are all registered with a {@link JobRegistry} defined in a parent application
53 * context. The jobs are then set up in child contexts. All dependencies of the
54 * runner will then be satisfied by autowiring by type from the parent
55 * application context. Default values are provided for all fields except the
56 * {@link JobRegistry}. Therefore, if autowiring fails to set it then an
57 * exception will be thrown.
58 * </p>
59 *
60 * @author Dave Syer
61 *
62 */
63public class JobRegistryBackgroundJobRunner {
64 
65        /**
66         * System property key that switches the runner to "embedded" mode
67         * (returning immediately from the main method). Useful for testing
68         * purposes.
69         */
70        public static final String EMBEDDED = JobRegistryBackgroundJobRunner.class.getSimpleName() + ".EMBEDDED";
71 
72        private static Log logger = LogFactory.getLog(JobRegistryBackgroundJobRunner.class);
73 
74        private JobLoader jobLoader;
75 
76        private ApplicationContext parentContext = null;
77 
78        public static boolean testing = false;
79 
80        final private String parentContextPath;
81 
82        private JobRegistry jobRegistry;
83 
84        private static List<Exception> errors = Collections.synchronizedList(new ArrayList<Exception>());
85 
86        /**
87         * @param parentContextPath
88         */
89        public JobRegistryBackgroundJobRunner(String parentContextPath) {
90                super();
91                this.parentContextPath = parentContextPath;
92        }
93 
94        /**
95         * A loader for the jobs that are going to be registered.
96         *
97         * @param jobLoader the {@link JobLoader} to set
98         */
99        public void setJobLoader(JobLoader jobLoader) {
100                this.jobLoader = jobLoader;
101        }
102 
103        /**
104         * A job registry that can be used to create a job loader (if none is provided).
105         *
106         * @param jobRegistry the {@link JobRegistry} to set
107         */
108        public void setJobRegistry(JobRegistry jobRegistry) {
109                this.jobRegistry = jobRegistry;
110        }
111 
112        /**
113         * Public getter for the startup errors encountered during parent context
114         * creation.
115         * @return the errors
116         */
117        public static List<Exception> getErrors() {
118                synchronized (errors) {
119                        return new ArrayList<Exception>(errors);
120                }
121        }
122 
123        private void register(String[] paths) throws DuplicateJobException, IOException {
124 
125                maybeCreateJobLoader();
126 
127                for (int i = 0; i < paths.length; i++) {
128 
129                        Resource[] resources = parentContext.getResources(paths[i]);
130 
131                        for (int j = 0; j < resources.length; j++) {
132 
133                                Resource path = resources[j];
134                                logger.info("Registering Job definitions from " + Arrays.toString(resources));
135 
136                                GenericApplicationContextFactory factory = new GenericApplicationContextFactory(path);
137                                factory.setApplicationContext(parentContext);
138                                jobLoader.load(factory);
139                        }
140 
141                }
142 
143        }
144 
145        /**
146         * If there is no {@link JobLoader} then try and create one from existing
147         * bean definitions.
148         */
149        private void maybeCreateJobLoader() {
150 
151                if (jobLoader != null) {
152                        return;
153                }
154 
155                String[] names = parentContext.getBeanNamesForType(JobLoader.class);
156                if (names.length == 0) {
157                        if (parentContext.containsBean("jobLoader")) {
158                                jobLoader = parentContext.getBean("jobLoader", JobLoader.class);
159                                return;
160                        }
161                        if (jobRegistry != null) {
162                                jobLoader = new DefaultJobLoader(jobRegistry);
163                                return;
164                        }
165                }
166 
167                jobLoader = parentContext.getBean(names[0], JobLoader.class);
168                return;
169 
170        }
171 
172        /**
173         * Supply a list of application context locations, starting with the parent
174         * context, and followed by the children. The parent must contain a
175         * {@link JobRegistry} and the child contexts are expected to contain
176         * {@link Job} definitions, each of which will be registered wit the
177         * registry.
178         *
179         * Example usage:
180         *
181         * <pre>
182         * $ java -classpath ... JobRegistryBackgroundJobRunner job-registry-context.xml job1.xml job2.xml ...
183         * </pre>
184         *
185         * The child contexts are created only when needed though the
186         * {@link JobFactory} interface (but the XML is validated on startup by
187         * using it to create a {@link BeanFactory} which is then discarded).
188         *
189         * The parent context is created in a separate thread, and the program will
190         * pause for input in an infinite loop until the user hits any key.
191         *
192         * @param args the context locations to use (first one is for parent)
193         * @throws Exception if anything goes wrong with the context creation
194         */
195        public static void main(String... args) throws Exception {
196 
197                Assert.state(args.length >= 1, "At least one argument (the parent context path) must be provided.");
198 
199                final JobRegistryBackgroundJobRunner launcher = new JobRegistryBackgroundJobRunner(args[0]);
200                errors.clear();
201 
202                logger.info("Starting job registry in parent context from XML at: [" + args[0] + "]");
203 
204                new Thread(new Runnable() {
205                        @Override
206                        public void run() {
207                                try {
208                                        launcher.run();
209                                }
210                                catch (RuntimeException e) {
211                                        errors.add(e);
212                                        throw e;
213                                }
214                        };
215                }).start();
216 
217                logger.info("Waiting for parent context to start.");
218                while (launcher.parentContext == null && errors.isEmpty()) {
219                        Thread.sleep(100L);
220                }
221 
222                synchronized (errors) {
223                        if (!errors.isEmpty()) {
224                                logger.info(errors.size() + " errors detected on startup of parent context.  Rethrowing.");
225                                throw errors.get(0);
226                        }
227                }
228                errors.clear();
229 
230                // Paths to individual job configurations.
231                final String[] paths = new String[args.length - 1];
232                System.arraycopy(args, 1, paths, 0, paths.length);
233 
234                logger.info("Parent context started.  Registering jobs from paths: " + Arrays.asList(paths));
235                launcher.register(paths);
236 
237                if (System.getProperty(EMBEDDED) != null) {
238                        launcher.destroy();
239                        return;
240                }
241 
242                synchronized (JobRegistryBackgroundJobRunner.class) {
243                        System.out
244                        .println("Started application.  Interrupt (CTRL-C) or call JobRegistryBackgroundJobRunner.stop() to exit.");
245                        JobRegistryBackgroundJobRunner.class.wait();
246                }
247                launcher.destroy();
248 
249        }
250 
251        /**
252         * De-register all the {@link Job} instances that were regsistered by this
253         * post processor.
254         * @see org.springframework.beans.factory.DisposableBean#destroy()
255         */
256        private void destroy() throws Exception {
257                jobLoader.clear();
258        }
259 
260        private void run() {
261                final ApplicationContext parent = new ClassPathXmlApplicationContext(parentContextPath);
262                parent.getAutowireCapableBeanFactory().autowireBeanProperties(this,
263                                AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
264                parent.getAutowireCapableBeanFactory().initializeBean(this, getClass().getSimpleName());
265                this.parentContext = parent;
266        }
267 
268        /**
269         * If embedded in a JVM, call this method to terminate the main method.
270         */
271        public static void stop() {
272                synchronized (JobRegistryBackgroundJobRunner.class) {
273                        JobRegistryBackgroundJobRunner.class.notify();
274                }
275        }
276 
277}

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