Save This Page
Home » org.springframework.batch-2.0.0.RELEASE-with-dependencies » org.springframework.batch » core » launch » support » [javadoc | source]
    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 java.util.Properties;
   19   
   20   import org.apache.commons.logging.Log;
   21   import org.apache.commons.logging.LogFactory;
   22   import org.springframework.batch.core.ExitStatus;
   23   import org.springframework.batch.core.Job;
   24   import org.springframework.batch.core.JobExecution;
   25   import org.springframework.batch.core.JobParameters;
   26   import org.springframework.batch.core.configuration.JobLocator;
   27   import org.springframework.batch.core.converter.DefaultJobParametersConverter;
   28   import org.springframework.batch.core.converter.JobParametersConverter;
   29   import org.springframework.batch.core.launch.JobLauncher;
   30   import org.springframework.beans.factory.BeanDefinitionStoreException;
   31   import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
   32   import org.springframework.context.ConfigurableApplicationContext;
   33   import org.springframework.context.support.ClassPathXmlApplicationContext;
   34   import org.springframework.util.Assert;
   35   import org.springframework.util.StringUtils;
   36   
   37   /**
   38    * <p>
   39    * Basic launcher for starting jobs from the command line. In general, it is
   40    * assumed that this launcher will primarily be used to start a job via a script
   41    * from an Enterprise Scheduler. Therefore, exit codes are mapped to integers so
   42    * that schedulers can use the returned values to determine the next course of
   43    * action. The returned values can also be useful to operations teams in
   44    * determining what should happen upon failure. For example, a returned code of
   45    * 5 might mean that some resource wasn't available and the job should be
   46    * restarted. However, a code of 10 might mean that something critical has
   47    * happened and the issue should be escalated.
   48    * </p>
   49    * 
   50    * <p>
   51    * With any launch of a batch job within Spring Batch, a Spring context
   52    * containing the {@link Job} and some execution context has to be created. This
   53    * command line launcher can be used to load the job and its context from a
   54    * single location. All dependencies of the launcher will then be satisfied by
   55    * autowiring by type from the combined application context. Default values are
   56    * provided for all fields except the {@link JobLauncher} and {@link JobLocator}.
   57    * Therefore, if autowiring fails to set it (it should be noted that dependency
   58    * checking is disabled because most of the fields have default values and thus
   59    * don't require dependencies to be fulfilled via autowiring) then an exception
   60    * will be thrown. It should also be noted that even if an exception is thrown
   61    * by this class, it will be mapped to an integer and returned.
   62    * </p>
   63    * 
   64    * <p>
   65    * Notice a property is available to set the {@link SystemExiter}. This class
   66    * is used to exit from the main method, rather than calling System.exit()
   67    * directly. This is because unit testing a class the calls System.exit() is
   68    * impossible without kicking off the test within a new Jvm, which it is
   69    * possible to do, however it is a complex solution, much more so than
   70    * strategizing the exiter.
   71    * </p>
   72    * 
   73    * <p>
   74    * The arguments to this class are roughly as follows:
   75    * </p>
   76    * 
   77    * <code>
   78    * java jobPath jobName jobLauncherPath jobParameters...
   79    * </code>
   80    * 
   81    * <p>
   82    * <ul>
   83    * <li>jobPath: the xml application context containing a {@link Job}
   84    * <li>jobName: the bean id of the job.
   85    * <li>jobLauncherPath: the xml application context containing a
   86    * {@link JobLauncher}
   87    * <li>jobParameters: 0 to many parameters that will be used to launch a job.
   88    * </ul>
   89    * </p>
   90    * 
   91    * <p>
   92    * The combined application context must contain only one instance of
   93    * {@link JobLauncher}. The job parameters passed in to the command line will
   94    * be converted to {@link Properties} by assuming that each individual element
   95    * is one parameter that is separated by an equals sign. For example,
   96    * "vendor.id=290232". Below is an example arguments list: "
   97    * 
   98    * <p>
   99    * <code>
  100    * java org.springframework.batch.execution.bootstrap.support.CommandLineJobRunner testJob.xml 
  101    * testJob schedule.date=2008/01/24 vendor.id=3902483920 
  102    * <code></p>
  103    * 
  104    * <p>Once arguments have been successfully parsed, autowiring will be used to set 
  105    * various dependencies.  The {@JobLauncher} for example, will be loaded this way.  If
  106    * none is contained in the bean factory (it searches by type) then a 
  107    * {@link BeanDefinitionStoreException} will be thrown.  The same exception will also
  108    * be thrown if there is more than one present.  Assuming the JobLauncher has been
  109    * set correctly, the jobName argument will be used to obtain an actual {@link Job}.
  110    * If a {@link JobLocator} has been set, then it will be used, if not the beanFactory
  111    * will be asked, using the jobName as the bean id.</p>
  112    * 
  113    * @author Dave Syer
  114    * @author Lucas Ward
  115    * @since 1.0
  116    */
  117   public class CommandLineJobRunner {
  118   
  119   	protected static final Log logger = LogFactory.getLog(CommandLineJobRunner.class);
  120   
  121   	private ExitCodeMapper exitCodeMapper = new SimpleJvmExitCodeMapper();
  122   
  123   	private JobLauncher launcher;
  124   
  125   	private JobLocator jobLocator;
  126   
  127   	private SystemExiter systemExiter = new JvmSystemExiter();
  128   
  129   	private JobParametersConverter jobParametersConverter = new DefaultJobParametersConverter();
  130   
  131   	/**
  132   	 * Injection setter for the {@link JobLauncher}.
  133   	 * 
  134   	 * @param launcher the launcher to set
  135   	 */
  136   	public void setLauncher(JobLauncher launcher) {
  137   		this.launcher = launcher;
  138   	}
  139   
  140   	/**
  141   	 * Injection setter for the {@link ExitCodeMapper}.
  142   	 * 
  143   	 * @param exitCodeMapper the exitCodeMapper to set
  144   	 */
  145   	public void setExitCodeMapper(ExitCodeMapper exitCodeMapper) {
  146   		this.exitCodeMapper = exitCodeMapper;
  147   	}
  148   
  149   	/**
  150   	 * Injection setter for the {@link SystemExiter}.
  151   	 * 
  152   	 * @param systemExitor
  153   	 */
  154   	public void setSystemExiter(SystemExiter systemExitor) {
  155   		this.systemExiter = systemExitor;
  156   	}
  157   
  158   	/**
  159   	 * Injection setter for {@link JobParametersConverter}.
  160   	 * 
  161   	 * @param jobParametersConverter
  162   	 */
  163   	public void setJobParametersConverter(JobParametersConverter jobParametersConverter) {
  164   		this.jobParametersConverter = jobParametersConverter;
  165   	}
  166   
  167   	/**
  168   	 * Delegate to the exiter to (possibly) exit the VM gracefully.
  169   	 * 
  170   	 * @param status
  171   	 */
  172   	public void exit(int status) {
  173   		systemExiter.exit(status);
  174   	}
  175   
  176   	public void setJobLocator(JobLocator jobLocator) {
  177   		this.jobLocator = jobLocator;
  178   	}
  179   
  180   	/*
  181   	 * Start a job by obtaining a combined classpath using the job launcher and
  182   	 * job paths. If a JobLocator has been set, then use it to obtain an actual
  183   	 * job, if not ask the context for it.
  184   	 */
  185   	int start(String jobPath, String jobName, String[] parameters) {
  186   
  187   		ConfigurableApplicationContext context = null;
  188   
  189   		try {
  190   			context = new ClassPathXmlApplicationContext(jobPath);
  191   			context.getAutowireCapableBeanFactory().autowireBeanProperties(this,
  192   					AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);
  193   			
  194   			Assert.notNull(launcher,"A JobLauncher must be provided.  Please add one to the configuration.");
  195   
  196   			Job job;
  197   			if (jobLocator != null) {
  198   				job = jobLocator.getJob(jobName);
  199   			}
  200   			else {
  201   				job = (Job) context.getBean(jobName);
  202   			}
  203   
  204   			JobParameters jobParameters = jobParametersConverter.getJobParameters(StringUtils
  205   					.splitArrayElementsIntoProperties(parameters, "="));
  206   
  207   			JobExecution jobExecution = launcher.run(job, jobParameters);
  208   			return exitCodeMapper.intValue(jobExecution.getExitStatus().getExitCode());
  209   		}
  210   		catch (Throwable e) {
  211   			logger.error("Job Terminated in error:", e);
  212   			return exitCodeMapper.intValue(ExitStatus.FAILED.getExitCode());
  213   		}
  214   		finally {
  215   			if (context != null) {
  216   				context.close();
  217   			}
  218   		}
  219   	}
  220   
  221   	/**
  222   	 * Launch a batch job using a {@link CommandLineJobRunner}. Creates a new
  223   	 * Spring context for the job execution, and uses a common parent for all
  224   	 * such contexts. No exception are thrown from this method, rather
  225   	 * exceptions are logged and an integer returned through the exit status in
  226   	 * a {@link JvmSystemExiter} (which can be overridden by defining one in the
  227   	 * Spring context).<br/> Parameters can be provided in the form key=value,
  228   	 * and will be converted using the injected {@link JobParametersConverter}.
  229   	 * 
  230   	 * @param args
  231   	 * <p>
  232   	 * <ul>
  233   	 * <li>jobPath: the xml application context containing a {@link Job}
  234   	 * <li>jobName: the bean id of the job.
  235   	 * <li>jobParameters: 0 to many parameters that will be used to launch a
  236   	 * job.
  237   	 * </ul>
  238   	 * </p>
  239   	 */
  240   	public static void main(String[] args) {
  241   
  242   		CommandLineJobRunner command = new CommandLineJobRunner();
  243   
  244   		if (args.length < 2) {
  245   			logger.error("At least 2 arguments are required: JobPath and JobName.");
  246   			command.exit(1);
  247   		}
  248   
  249   		String jobPath = args[0];
  250   		String jobName = args[1];
  251   		String[] parameters = new String[args.length - 2];
  252   		System.arraycopy(args, 2, parameters, 0, args.length - 2);
  253   
  254   		int result = command.start(jobPath, jobName, parameters);
  255   		command.exit(result);
  256   	}
  257   
  258   }

Save This Page
Home » org.springframework.batch-2.0.0.RELEASE-with-dependencies » org.springframework.batch » core » launch » support » [javadoc | source]