lcn.module.batch.core.launch.support.CommandLineRunner.java Source code

Java tutorial

Introduction

Here is the source code for lcn.module.batch.core.launch.support.CommandLineRunner.java

Source

/*
 * Copyright 2006-2007 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
 *
 *      http://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 lcn.module.batch.core.launch.support;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobInstance;
import org.springframework.batch.core.JobParameter;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersIncrementer;
import org.springframework.batch.core.configuration.JobLocator;
import org.springframework.batch.core.converter.DefaultJobParametersConverter;
import org.springframework.batch.core.converter.JobParametersConverter;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.batch.core.launch.JobExecutionNotFailedException;
import org.springframework.batch.core.launch.JobExecutionNotRunningException;
import org.springframework.batch.core.launch.JobExecutionNotStoppedException;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.batch.core.launch.JobParametersNotFoundException;
import org.springframework.batch.core.launch.support.ExitCodeMapper;
import org.springframework.batch.core.launch.support.JvmSystemExiter;
import org.springframework.batch.core.launch.support.SimpleJvmExitCodeMapper;
import org.springframework.batch.core.launch.support.SystemExiter;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * @author 
 * @since 2012. 07.25
 * @version 1.0
 * @see <pre>
 *      ?(Modification Information)
 *   
 *   ?      ?           
 *  ------- -------- ---------------------------
 *  2012. 07.25        ?
 *  </pre>
 */
public class CommandLineRunner {

    //   Logger
    protected static final Log logger = LogFactory.getLog(CommandLineRunner.class);

    // ExitCode    ExitCodeMapper
    private ExitCodeMapper exitCodeMapper = new SimpleJvmExitCodeMapper();

    // Batch Job?  JobLauncher
    private JobLauncher launcher;

    //  ? Job? ?? JobLocator
    private JobLocator jobLocator;

    //    SystemExiter
    private static SystemExiter systemExiter = new JvmSystemExiter();

    // ? message 
    private static String message = "";

    // ? ? JobParameter  JobParameterConverter
    private JobParametersConverter jobParametersConverter = new DefaultJobParametersConverter();

    //JobExecution  ? ? JobExplorer
    private JobExplorer jobExplorer;

    // ? ? JobExecution, StepExecution  ? ? JobRepository 
    private JobRepository jobRepository;

    /**
     * JobLauncher .
     * 
     * @param launcher
     */
    public void setLauncher(JobLauncher launcher) {
        this.launcher = launcher;
    }

    /**
     * JobRepository .
     * 
     * @param jobRepository
     */
    public void setJobRepository(JobRepository jobRepository) {
        this.jobRepository = jobRepository;
    }

    /**
     * JobExplorer .
     * 
     * @param jobExplorer
     */
    public void setJobExplorer(JobExplorer jobExplorer) {
        this.jobExplorer = jobExplorer;
    }

    /**
     * ExitCodeMapper .
     * 
     * @param exitCodeMapper
     */
    public void setExitCodeMapper(ExitCodeMapper exitCodeMapper) {
        this.exitCodeMapper = exitCodeMapper;
    }

    /**
     * SystemExiter .
     */
    public static void presetSystemExiter(SystemExiter systemExiter) {
        CommandLineRunner.systemExiter = systemExiter;
    }

    /**
     * ? message .
     * 
     * @return message
     */
    public static String getErrorMessage() {
        return message;
    }

    /**
     * SystemExiter .
     */
    public void setSystemExiter(SystemExiter systemExiter) {
        CommandLineRunner.systemExiter = systemExiter;
    }

    /**
     * ? message .
     * 
     * @param message
     */
    public void setMessage(String message) {
        CommandLineRunner.message = message;
    }

    /**
     * JobParameters ?? ? JobParametersConverter ?.
     * 
     * @param jobParametersConverter
     */
    public void setJobParametersConverter(JobParametersConverter jobParametersConverter) {
        this.jobParametersConverter = jobParametersConverter;
    }

    /**
     * CommandLineRunner .
     * 
     * @param status
     */
    public void exit(int status) {
        systemExiter.exit(status);
    }

    /**
     * JobLocator ?.
     * 
     * @param jobLocator
     */
    public void setJobLocator(JobLocator jobLocator) {
        this.jobLocator = jobLocator;
    }

    /**
     * Batch Job? .
     * ?  , Job ? / JobExecutionID, Job Parameter
     *  CommandLineRunner Option ? .
     * 
     * @param jobPath : Job Context ? XML ?  
     * @param jobIdentifier : Job ? /JobExecutionID
     * @param parameters : Job Parameter 
     * @param opts : CommandLineRunner (-restart, -next, -stop, -abandon)
     */
    public int start(String jobPath, String jobIdentifier, String[] parameters, Set<String> opts) {

        ConfigurableApplicationContext context = null;

        try {
            //  ApplicationContext ?.
            context = new ClassPathXmlApplicationContext(jobPath);
            context.getAutowireCapableBeanFactory().autowireBeanProperties(this,
                    AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, false);

            Assert.state(launcher != null, "A JobLauncher must be provided.  Please add one to the configuration.");
            // ? Batch Job? , ? Batch Job?  ? JobExplorer  ?.
            if (opts.contains("-restart") || opts.contains("-next")) {
                Assert.state(jobExplorer != null,
                        "A JobExplorer must be provided for a restart or start next operation.  Please add one to the configuration.");
            }

            // Job? ?? .
            String jobName = jobIdentifier;

            // JobParameters ?.
            JobParameters jobParameters = jobParametersConverter
                    .getJobParameters(StringUtils.splitArrayElementsIntoProperties(parameters, "="));
            Assert.isTrue(parameters == null || parameters.length == 0 || !jobParameters.isEmpty(),
                    "Invalid JobParameters " + Arrays.asList(parameters)
                            + ". If parameters are provided they should be in the form name=value (no whitespace).");

            // Batch Job? .
            if (opts.contains("-stop")) {
                List<JobExecution> jobExecutions = getRunningJobExecutions(jobIdentifier);
                if (jobExecutions == null) {
                    throw new JobExecutionNotRunningException(
                            "No running execution found for job=" + jobIdentifier);
                }
                for (JobExecution jobExecution : jobExecutions) {
                    jobExecution.setStatus(BatchStatus.STOPPING);
                    jobRepository.update(jobExecution);
                }
                return exitCodeMapper.intValue(ExitStatus.COMPLETED.getExitCode());
            }

            // ? Batch Job? ? abandon .
            if (opts.contains("-abandon")) {
                List<JobExecution> jobExecutions = getStoppedJobExecutions(jobIdentifier);
                if (jobExecutions == null) {
                    throw new JobExecutionNotStoppedException(
                            "No stopped execution found for job=" + jobIdentifier);
                }
                for (JobExecution jobExecution : jobExecutions) {
                    jobExecution.setStatus(BatchStatus.ABANDONED);
                    jobRepository.update(jobExecution);
                }
                return exitCodeMapper.intValue(ExitStatus.COMPLETED.getExitCode());
            }

            // Batch Job? .
            if (opts.contains("-restart")) {
                JobExecution jobExecution = getLastFailedJobExecution(jobIdentifier);
                if (jobExecution == null) {
                    throw new JobExecutionNotFailedException(
                            "No failed or stopped execution found for job=" + jobIdentifier);
                }
                jobParameters = jobExecution.getJobInstance().getJobParameters();
                jobName = jobExecution.getJobInstance().getJobName();
            }

            Job job;

            // JobLocator  Job?  null? ApplicationContext? Job? .
            if (jobLocator != null) {
                job = jobLocator.getJob(jobName);
            } else {
                job = (Job) context.getBean(jobName);
            }

            // ? Batch Job?   Job Parameters ?.
            if (opts.contains("-next")) {
                JobParameters nextParameters = getNextJobParameters(job);
                Map<String, JobParameter> map = new HashMap<String, JobParameter>(nextParameters.getParameters());
                map.putAll(jobParameters.getParameters());
                jobParameters = new JobParameters(map);
            }

            // Batch Job? .
            JobExecution jobExecution = launcher.run(job, jobParameters);
            logger.warn("CommandLineRunner's Job Information");
            logger.warn("jobName=" + jobExecution.getJobInstance().getJobName());
            logger.warn("jobParamters=" + jobParameters.toString());
            logger.warn("jobExecutionTime="
                    + (jobExecution.getEndTime().getTime() - jobExecution.getStartTime().getTime()) / 1000f + "s");

            return exitCodeMapper.intValue(jobExecution.getExitStatus().getExitCode());
        } catch (Throwable e) {
            String message = "Job Terminated in error: " + e.getMessage();
            logger.error(message, e);
            CommandLineRunner.message = message;
            return exitCodeMapper.intValue(ExitStatus.FAILED.getExitCode());
        } finally {
            if (context != null) {
                context.close();
            }
        }
    }

    /**
     *  BatchStatus?  ? BatchStatus  JobExecution? .
     * @param jobIdentifier 
     * @param minStatus 
     * @return List<JobExecution> : JobExecution ?
     */
    private List<JobExecution> getJobExecutionsWithStatusGreaterThan(String jobIdentifier, BatchStatus minStatus) {

        Long executionId = getLongIdentifier(jobIdentifier);
        if (executionId != null) {
            JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
            if (jobExecution.getStatus().isGreaterThan(minStatus)) {
                return Arrays.asList(jobExecution);
            }
            return Collections.emptyList();
        }

        int start = 0;
        int count = 100;
        List<JobExecution> executions = new ArrayList<JobExecution>();
        List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobIdentifier, start, count);

        while (!lastInstances.isEmpty()) {

            for (JobInstance jobInstance : lastInstances) {
                List<JobExecution> jobExecutions = jobExplorer.getJobExecutions(jobInstance);
                if (jobExecutions == null || jobExecutions.isEmpty()) {
                    continue;
                }
                for (JobExecution jobExecution : jobExecutions) {
                    if (jobExecution.getStatus().isGreaterThan(minStatus)) {
                        executions.add(jobExecution);
                    }
                }
            }

            start += count;
            lastInstances = jobExplorer.getJobInstances(jobIdentifier, start, count);

        }

        return executions;

    }

    /**
     * ?   ? JobExecution? .
     * 
     * @param jobIdentifier
     * @return jobExecution : ?  JobExecution
     */
    private JobExecution getLastFailedJobExecution(String jobIdentifier) {
        List<JobExecution> jobExecutions = getJobExecutionsWithStatusGreaterThan(jobIdentifier,
                BatchStatus.STOPPING);
        if (jobExecutions.isEmpty()) {
            return null;
        }
        return jobExecutions.get(0);
    }

    /**
     *  JobExecution ?? .
     * 
     * @param jobIdentifier
     * @return List<JobExecution> :  JobExecution ?
     */
    private List<JobExecution> getStoppedJobExecutions(String jobIdentifier) {
        List<JobExecution> jobExecutions = getJobExecutionsWithStatusGreaterThan(jobIdentifier,
                BatchStatus.STARTED);
        if (jobExecutions.isEmpty()) {
            return null;
        }
        List<JobExecution> result = new ArrayList<JobExecution>();
        for (JobExecution jobExecution : jobExecutions) {
            if (jobExecution.getStatus() != BatchStatus.ABANDONED) {
                result.add(jobExecution);
            }
        }
        return result.isEmpty() ? null : result;
    }

    /**
     *  ? JobExecution ?? .
     * 
     * @param jobIdentifier
     * @return List<JobExecution> :  ? JobExecution ?
     */
    private List<JobExecution> getRunningJobExecutions(String jobIdentifier) {
        List<JobExecution> jobExecutions = getJobExecutionsWithStatusGreaterThan(jobIdentifier,
                BatchStatus.COMPLETED);
        if (jobExecutions.isEmpty()) {
            return null;
        }
        List<JobExecution> result = new ArrayList<JobExecution>();
        for (JobExecution jobExecution : jobExecutions) {
            if (jobExecution.isRunning()) {
                result.add(jobExecution);
            }
        }
        return result.isEmpty() ? null : result;
    }

    /**
     * JobIdentifier? JobName  String ? JobExecutionId   Long .
     * 
     * @param jobIdentifier
     * @return
     */
    private Long getLongIdentifier(String jobIdentifier) {
        try {
            return Long.valueOf(jobIdentifier);
        } catch (NumberFormatException e) {
            return null;
        }
    }

    /**
     * ?  ? Batch Job? Job Parameter ?.
     * 
     * @param job
     * @return JobParameters
     * @throws JobParametersNotFoundException 
     */
    private JobParameters getNextJobParameters(Job job) throws JobParametersNotFoundException {
        String jobIdentifier = job.getName();
        JobParameters jobParameters;
        List<JobInstance> lastInstances = jobExplorer.getJobInstances(jobIdentifier, 0, 1);

        JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
        if (incrementer == null) {
            throw new JobParametersNotFoundException(
                    "No job parameters incrementer found for job=" + jobIdentifier);
        }

        if (lastInstances.isEmpty()) {
            jobParameters = incrementer.getNext(new JobParameters());
            if (jobParameters == null) {
                throw new JobParametersNotFoundException(
                        "No bootstrap parameters found from incrementer for job=" + jobIdentifier);
            }
        } else {
            jobParameters = incrementer.getNext(lastInstances.get(0).getJobParameters());
        }
        return jobParameters;
    }

}