All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.batch.core.launch.support.JobRegistryBackgroundJobRunner Maven / Gradle / Ivy

/*
 * Copyright 2006-2023 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
 *
 *      https://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.core.launch.support;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.DuplicateJobException;
import org.springframework.batch.core.configuration.JobFactory;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.DefaultJobLoader;
import org.springframework.batch.core.configuration.support.GenericApplicationContextFactory;
import org.springframework.batch.core.configuration.support.JobLoader;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.util.Assert;

/**
 * 

* Command line launcher for registering jobs with a {@link JobRegistry}. Normally this * will be used in conjunction with an external trigger for the jobs registered, e.g. a * JMX MBean wrapper for a {@link JobLauncher}, or a Quartz trigger. *

* *

* With any launch of a batch job within Spring Batch, a Spring context containing the * {@link Job} has to be created. Using this launcher, the jobs are all registered with a * {@link JobRegistry} defined in a parent application context. The jobs are then set up * in child contexts. All dependencies of the runner will then be satisfied by autowiring * by type from the parent application context. Default values are provided for all fields * except the {@link JobRegistry}. Therefore, if autowiring fails to set it then an * exception will be thrown. *

* * @author Dave Syer * @author Mahmoud Ben Hassine * @deprecated since 5.0 with no replacement. Scheduled for removal in 5.2. * */ @Deprecated(since = "5.0", forRemoval = true) public class JobRegistryBackgroundJobRunner { /** * System property key that switches the runner to "embedded" mode (returning * immediately from the main method). Useful for testing purposes. */ public static final String EMBEDDED = JobRegistryBackgroundJobRunner.class.getSimpleName() + ".EMBEDDED"; private static final Log logger = LogFactory.getLog(JobRegistryBackgroundJobRunner.class); private JobLoader jobLoader; private ApplicationContext parentContext = null; public static boolean testing = false; final private String parentContextPath; private JobRegistry jobRegistry; private static final List errors = Collections.synchronizedList(new ArrayList<>()); /** * @param parentContextPath the parentContextPath to be used by the * JobRegistryBackgroundJobRunner. */ public JobRegistryBackgroundJobRunner(String parentContextPath) { super(); this.parentContextPath = parentContextPath; } /** * A loader for the jobs that are going to be registered. * @param jobLoader the {@link JobLoader} to set */ public void setJobLoader(JobLoader jobLoader) { this.jobLoader = jobLoader; } /** * A job registry that can be used to create a job loader (if none is provided). * @param jobRegistry the {@link JobRegistry} to set */ public void setJobRegistry(JobRegistry jobRegistry) { this.jobRegistry = jobRegistry; } /** * Public getter for the startup errors encountered during parent context creation. * @return the errors */ public static List getErrors() { synchronized (errors) { return new ArrayList<>(errors); } } private void register(String[] paths) throws DuplicateJobException, IOException { maybeCreateJobLoader(); for (String s : paths) { Resource[] resources = parentContext.getResources(s); for (Resource path : resources) { if (logger.isInfoEnabled()) { logger.info("Registering Job definitions from " + Arrays.toString(resources)); } GenericApplicationContextFactory factory = new GenericApplicationContextFactory(path); factory.setApplicationContext(parentContext); jobLoader.load(factory); } } } /** * If there is no {@link JobLoader} then try and create one from existing bean * definitions. */ private void maybeCreateJobLoader() { if (jobLoader != null) { return; } String[] names = parentContext.getBeanNamesForType(JobLoader.class); if (names.length == 0) { if (parentContext.containsBean("jobLoader")) { jobLoader = parentContext.getBean("jobLoader", JobLoader.class); return; } if (jobRegistry != null) { jobLoader = new DefaultJobLoader(jobRegistry); return; } } jobLoader = parentContext.getBean(names[0], JobLoader.class); } /** * Supply a list of application context locations, starting with the parent context, * and followed by the children. The parent must contain a {@link JobRegistry} and the * child contexts are expected to contain {@link Job} definitions, each of which will * be registered wit the registry. *

* Example usage: * *

	 * $ java -classpath ... JobRegistryBackgroundJobRunner job-registry-context.xml job1.xml job2.xml ...
	 * 
* * The child contexts are created only when needed though the {@link JobFactory} * interface (but the XML is validated on startup by using it to create a * {@link BeanFactory} which is then discarded). *

* The parent context is created in a separate thread, and the program will pause for * input in an infinite loop until the user hits any key. * @param args the context locations to use (first one is for parent) * @throws Exception if anything goes wrong with the context creation */ public static void main(String... args) throws Exception { Assert.state(args.length >= 1, "At least one argument (the parent context path) must be provided."); final JobRegistryBackgroundJobRunner launcher = new JobRegistryBackgroundJobRunner(args[0]); errors.clear(); if (logger.isInfoEnabled()) { logger.info("Starting job registry in parent context from XML at: [" + args[0] + "]"); } new Thread(() -> { try { launcher.run(); } catch (RuntimeException e) { errors.add(e); throw e; } }).start(); logger.info("Waiting for parent context to start."); while (launcher.parentContext == null && errors.isEmpty()) { Thread.sleep(100L); } synchronized (errors) { if (!errors.isEmpty()) { if (logger.isInfoEnabled()) { logger.info(errors.size() + " errors detected on startup of parent context. Rethrowing."); } throw errors.get(0); } } errors.clear(); // Paths to individual job configurations. final String[] paths = new String[args.length - 1]; System.arraycopy(args, 1, paths, 0, paths.length); if (logger.isInfoEnabled()) { logger.info("Parent context started. Registering jobs from paths: " + Arrays.asList(paths)); } launcher.register(paths); if (System.getProperty(EMBEDDED) != null) { launcher.destroy(); return; } synchronized (JobRegistryBackgroundJobRunner.class) { System.out.println( "Started application. Interrupt (CTRL-C) or call JobRegistryBackgroundJobRunner.stop() to exit."); JobRegistryBackgroundJobRunner.class.wait(); } launcher.destroy(); } /** * Unregister all the {@link Job} instances that were registered by this post * processor. * @see org.springframework.beans.factory.DisposableBean#destroy() */ private void destroy() throws Exception { jobLoader.clear(); } private void run() { final ApplicationContext parent = new ClassPathXmlApplicationContext(parentContextPath); parent.getAutowireCapableBeanFactory() .autowireBeanProperties(this, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false); parent.getAutowireCapableBeanFactory().initializeBean(this, getClass().getSimpleName()); this.parentContext = parent; } /** * If embedded in a JVM, call this method to terminate the main method. */ public static void stop() { synchronized (JobRegistryBackgroundJobRunner.class) { JobRegistryBackgroundJobRunner.class.notify(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy