com.clican.pluto.fsm.engine.impl.JobContextImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.clican.pluto.fsm.engine.impl.JobContextImpl.java

Source

/**
 * The Clican-Pluto software suit is Copyright 2009, Clican Company and individual contributors, and is licensed under the GNU LGPL.
 *
 * @author wei.zhang
 *
 */
package com.clican.pluto.fsm.engine.impl;

import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.transaction.annotation.Transactional;

import com.clican.pluto.common.calendar.BusinessCalendar;
import com.clican.pluto.common.calendar.Duration;
import com.clican.pluto.common.util.TimeUtils;
import com.clican.pluto.fsm.engine.EngineContext;
import com.clican.pluto.fsm.engine.IState;
import com.clican.pluto.fsm.engine.JobContext;
import com.clican.pluto.fsm.engine.JobService;
import com.clican.pluto.fsm.enumeration.JobStatus;
import com.clican.pluto.fsm.enumeration.Status;
import com.clican.pluto.fsm.listener.TimeOutListener;
import com.clican.pluto.fsm.model.Job;

/**
 * ??Job ??Job
 * <p>
 * Spring???? schedule<code>Timer</code>
 * 
 * 
 * @author wei.zhang
 * 
 */
public class JobContextImpl implements JobContext, ApplicationContextAware {

    private final static Log log = LogFactory.getLog(JobContextImpl.class);

    private ApplicationContext applicationContext;

    private ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 20, 0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>());

    private BusinessCalendar businessCalendar;

    private int maxThreadNum = 200;

    private AtomicLong activeThreadCount = new AtomicLong();

    private Timer timer = new Timer();

    private JobService jobService;

    private long refreshTime;

    private EngineContext engineContext;

    private boolean running = false;

    public void setRefreshTime(String refreshTime) {
        this.refreshTime = TimeUtils.getMillisionSecond(refreshTime);
    }

    public void setJobService(JobService jobService) {
        this.jobService = jobService;
    }

    public void setEngineContext(EngineContext engineContext) {
        this.engineContext = engineContext;
    }

    public void setMaxThreadNum(int maxThreadNum) {
        this.maxThreadNum = maxThreadNum;
    }

    public void setBusinessCalendar(BusinessCalendar businessCalendar) {
        this.businessCalendar = businessCalendar;
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    @Transactional
    public void addJob(final Job job) {
        if (log.isDebugEnabled()) {
            log.debug("add a new name=[" + job.getName() + "]");
        }
        // Calendar current = Calendar.getInstance();
        // Date date = job.getExecuteTime();
        // long gap = date.getTime() - current.getTimeInMillis();
        // if (gap < refreshTime * 2) {
        // if (log.isDebugEnabled()) {
        // log.debug("execute the job=[" + job.getId() + "], job hash=" +
        // job.hashCode());
        // }
        // job.setStatus(JobStatus.EXECUTING.getStatus());
        // jobService.saveJob(job);
        //
        // if (log.isDebugEnabled()) {
        // log.debug("check: after saving job id =" + job.getId() +
        // ", job hash=" + job.hashCode());
        // }
        //
        // executor.submit(getRunnable(job));
        // } else {
        if (log.isDebugEnabled()) {
            log.debug("save the job=[" + job.getId() + "] into database queue");
        }
        jobService.saveJob(job);
        // }
    }

    public void loadJobs() {
        if (!running) {
            start();
        }
        if (!running || activeThreadCount.longValue() > maxThreadNum) {
            if (log.isDebugEnabled()) {
                log.debug("Running=[" + running + "],activeThreadCount=[" + activeThreadCount.longValue()
                        + "],maxThreadNum=[" + maxThreadNum + "] This loading is ignored");
            }
            return;
        }
        Calendar current = Calendar.getInstance();
        current.setTimeInMillis(current.getTimeInMillis() + refreshTime);
        List<Job> jobList = jobService.findJobByExecuteTime(current.getTime(), JobStatus.IDLE);
        if (log.isTraceEnabled()) {
            log.trace("find " + jobList.size() + " jobs to execute");
        }
        for (Job job : jobList) {
            job.setStatus(JobStatus.EXECUTING.getStatus());
            jobService.updateJob(job);
            if (log.isDebugEnabled()) {
                log.debug("find a job [" + job + "] and prepare to execute it");
            }
            executor.submit(getRunnable(job));
        }
    }

    @Transactional
    public void removeJob(Job job) {
        jobService.deleteJob(job);
    }

    @Transactional
    public void executeJob(Job job) {
        job = jobService.findJobById(job.getId());
        job.setStatus(JobStatus.EXECUTING.getStatus());
        jobService.updateJob(job);
        IState istate = engineContext.getState(job.getState().getSession().getName(),
                job.getState().getSession().getVersion(), job.getState().getName());
        TimeOutListener listener = istate.getTimeoutListeners().get(job.getName());
        listener.onTimeOut(job);
    }

    public void start() {
        Calendar current = Calendar.getInstance();
        List<Job> jobList = jobService.findJobByExecuteTime(current.getTime(), JobStatus.EXECUTING);
        for (Job job : jobList) {
            executor.submit(getRunnable(job));
        }
        running = true;
    }

    public void stop() {
        running = false;
        timer.cancel();
    }

    private Runnable getRunnable(final Job job) {
        return new Runnable() {

            public void run() {
                activeThreadCount.getAndIncrement();
                TimerTask task = new TimeOutTask(job);
                if (log.isDebugEnabled()) {
                    log.debug("prepare to execute this job [" + job.getId() + "] after "
                            + (job.getExecuteTime().getTime() - new Date().getTime()) / 1000 + " seconds");
                }
                timer.schedule(task, job.getExecuteTime());
            }
        };
    }

    private class TimeOutTask extends TimerTask {

        private Job job;

        public TimeOutTask(Job job) {
            this.job = job;
        }

        public void run() {
            try {
                if (log.isDebugEnabled()) {
                    log.debug("TimeOutTask: try to execute job" + job.getId());
                }
                if (job.getRepeatTime() - job.getRepeatedTime() < 0) {
                    if (log.isDebugEnabled()) {
                        log.debug("TimeOutTask returns for {job.getRepeatTime() - job.getRepeatedTime() < 0}");
                    }
                    return;
                }
                job = jobService.findJobById(job.getId());
                if (job == null) {
                    if (log.isDebugEnabled()) {
                        log.debug("TimeOutTask returns for {job == null}");
                    }
                    return;
                }
                if (!JobStatus.EXECUTING.getStatus().equals(job.getStatus())) {
                    if (log.isDebugEnabled()) {
                        log.debug(
                                "TimeOutTask returns for {!JobStatus.EXECUTING.getStatus().equals(job.getStatus())}");
                    }
                    return;
                }

                if (Status.convert(job.getState().getStatus()) != Status.ACTIVE) {
                    log.debug("The state [" + job.getState().getName() + "(" + job.getState().getId()
                            + ")] has been inactived, we ingore this job[" + job.getName() + "(" + job.getId()
                            + ")] running");
                    return;
                }
                if (Status.convert(job.getState().getSession().getStatus()) != Status.ACTIVE) {
                    log.debug("The state [" + job.getState().getSession().getName() + "("
                            + job.getState().getSession().getId() + ")] has been inactived, we ingore this job["
                            + job.getName() + "(" + job.getId() + ")] running");
                    return;
                }
                IState istate = engineContext.getState(job.getState().getSession().getName(),
                        job.getState().getSession().getVersion(), job.getState().getName());

                TimeOutListener listener = istate.getTimeoutListeners().get(job.getName());
                if (log.isDebugEnabled()) {
                    log.debug("execute this job [" + job + "] jobId = [" + job.getId() + "]");
                }
                listener.onTimeOut(job);
                job = jobService.findJobById(job.getId());
            } catch (Throwable e) {
                log.error("", e);
            } finally {
                try {
                    activeThreadCount.decrementAndGet();
                    if (job != null && JobStatus.EXECUTED.getStatus().equals(job.getStatus())) {
                        jobService.deleteJob(job);
                        return;
                    }
                    if (job != null) {
                        if (job.getRepeatTime() - job.getRepeatedTime() <= 0) {
                            jobService.deleteJob(job);
                        } else {
                            job.setRepeatedTime(job.getRepeatedTime() + 1);
                            job.setStatus(JobStatus.IDLE.getStatus());
                            BusinessCalendar businessCalendar = JobContextImpl.this.businessCalendar;
                            if (StringUtils.isNotEmpty(job.getBusinessCalendarName())) {
                                try {
                                    businessCalendar = (BusinessCalendar) applicationContext
                                            .getBean(job.getBusinessCalendarName());
                                } catch (Exception e) {
                                    log.error("", e);
                                }
                            }
                            if (StringUtils.isNotEmpty(job.getRepeatDuration())) {
                                Date nextExecuteTime = businessCalendar.add(job.getExecuteTime(),
                                        new Duration(job.getRepeatDuration()));
                                job.getExecuteTime().setTime(nextExecuteTime.getTime());
                                jobService.updateJob(job);
                            } else {
                                jobService.deleteJob(job);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.error("", e);
                }
            }
        }
    }
}

// $Id$