Package de.innovationgate.wgpublisher.scheduler

Source Code of de.innovationgate.wgpublisher.scheduler.Job

/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher.scheduler;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.WriterAppender;
import org.dom4j.Element;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;

import de.innovationgate.utils.UIDGenerator;
import de.innovationgate.wgpublisher.WGACore;

/**
* Job runtime object
*/
public class Job {

  public static final String CUSTOM_TASK_UID_PREFIX = "custom_";
    public static final String QUARTZ_JOBGROUP_WGASCHEDULER = "WGAScheduler";
    private FileAppender _logAppender;
  private de.innovationgate.wgpublisher.scheduler.Scheduler _scheduler;
  private Object _lastResult;
  public static final Layout JOBLOG_LAYOUT = new PatternLayout("%d{dd.MM.yyyy HH:mm:ss} %p %m\n");
  public static final SimpleDateFormat DATE_FORMAT_LOG = new SimpleDateFormat("yyyyMMdd_hhmm");
    public static final int ORIGIN_WGACONFIG = 1;
    public static final int ORIGIN_CUSTOM = 2;
   

  private String _name;
  private String _description;
  private List<Task> _tasks = new ArrayList<Task>();
  private boolean _running = false;
  private boolean _failed = false;
  private Throwable _exception = null;
    private List _trigger = new ArrayList();
    private String _endMessage = null;
    private int _origin = ORIGIN_WGACONFIG;

  private Date _lastRun = null;
  private String _lastLog = "(Job has not been run yet)";
  private StringWriter _currentLog = null;
  private Map<String,String> _options = new HashMap<String,String>();
    private boolean _transient = false;
    private String _uid;
    public Job(de.innovationgate.wgpublisher.scheduler.Scheduler scheduler, de.innovationgate.wga.config.Job conf) throws ConfigurationException {

    // Base info
    _scheduler = scheduler;
       
        if (conf == null) {
            _name = "Custom Task";
            _description = "A custom task generated by the WGA runtime";
            _transient = true;
            _uid = CUSTOM_TASK_UID_PREFIX + UIDGenerator.generateUID();
            return;
        }
       
    _name = conf.getName();
    _uid = conf.getUid();

    _description = conf.getDescription();
    if (_description == null) {
      _description = "(no description)";
    }

    _options.putAll(conf.getOptions());

    // Tasks
    Iterator<de.innovationgate.wga.config.Task> tasks = conf.getTasks().iterator();
    while (tasks.hasNext()) {
      de.innovationgate.wga.config.Task taskConfig = tasks.next();
      String className = taskConfig.getImplClassName();
      try {
        Class taskClass = WGACore.getLibraryLoader().loadClass(className);
        Task task = (Task) taskClass.newInstance();
        task.init(this, taskConfig);
        task.configure(_scheduler.getCore());
        addTask(task);
      }
      catch (ClassNotFoundException e) {
        throw new ConfigurationException("Task class '" + className + "' cannot be found", e);
      }
      catch (NoClassDefFoundError e) {
                throw new ConfigurationException("Task class '" + className + "' cannot be instantiated bc. a dependency class is missing", e);
            }
      catch (InstantiationException e) {
        throw new ConfigurationException("Task class '" + className + "' cannot be instantiated: " + e.getMessage());
      }
      catch (IllegalAccessException e) {
        throw new ConfigurationException("Task class '" + className + "' default contructor is not visible");
      }
    }
  }

    public void addTask(Task task) {
        _tasks.add(task);
    }

    public void addToScheduler(List schedules, Scheduler quartzScheduler) throws ConfigurationException {
        JobDataMap jobDataMap = new JobDataMap();
        jobDataMap.put("Job", this);
        jobDataMap.put("WGACore", _scheduler.getCore());
       
        JobDetail jobDetail = new JobDetail();
        jobDetail.setName(getName());
        jobDetail.setGroup(QUARTZ_JOBGROUP_WGASCHEDULER);
        jobDetail.setDescription(_description);
        jobDetail.setJobClass(QuartzJobRunner.class);
        jobDetail.setJobDataMap(jobDataMap);
        jobDetail.setDurability(true);
        try {
            // To remove old job and also remove it's associated triggers
            quartzScheduler.deleteJob(getName(), QUARTZ_JOBGROUP_WGASCHEDULER);

            quartzScheduler.addJob(jobDetail, false);
        }
        catch (SchedulerException e1) {
            throw new ConfigurationException("Could not add job to scheduler: " + e1.getMessage());
        }
       
        // Add triggers
        addSchedules(schedules, quartzScheduler);
    }

    private void addSchedules(List schedulesList, Scheduler quartzScheduler) throws ConfigurationException {
       
        Iterator schedules = schedulesList.iterator();
        int triggerCount = 0;
        while (schedules.hasNext()) {
            triggerCount++;
            JobSchedule schedule = (JobSchedule) schedules.next();
            if (!schedule.isEnabled()) {
                continue;
            }
           
            String type = schedule.getType();
            String text = schedule.getScheduleData();
            Date startingDate = schedule.getStartingDate();
            Date endingDate = schedule.getEndingDate();
           
            Trigger trigger = null;
            if (type.equals(JobSchedule.TYPE_SIMPLE)) {
                trigger = createSimpletrigger(triggerCount, text, startingDate, endingDate);
            }
            else if (type.equals(JobSchedule.TYPE_CRON)) {
                trigger = createCronTrigger(triggerCount, text, startingDate, endingDate);
            }
                                  
            if (trigger != null) {
                trigger.setJobName(getName());
                trigger.setJobGroup(QUARTZ_JOBGROUP_WGASCHEDULER);
                try {
                    quartzScheduler.scheduleJob(trigger);
                }
                catch (SchedulerException e) {
                   throw new ConfigurationException("Could not schedule job: " + e.getMessage());
                }
                catch (UnsupportedOperationException e) {
                    throw new ConfigurationException("Could not schedule job: " + e.getMessage());
                }
                addTrigger(trigger);
            }
        }
    }





    private Trigger createCronTrigger(int triggerCount, String text, Date startingDate, Date endingDate) throws ConfigurationException {
        Trigger trigger;
        CronTrigger cronTrigger = new CronTrigger(getName() + triggerCount, QUARTZ_JOBGROUP_WGASCHEDULER);
        cronTrigger.setMisfireInstruction(CronTrigger.MISFIRE_INSTRUCTION_DO_NOTHING);
        try {
            cronTrigger.setCronExpression(text);
        }
        catch (ParseException e) {
            throw new ConfigurationException("Error parsing cron pattern for job: " + e.getClass().getName() + " - " + e.getMessage());
        }
       
        if (startingDate != null) {
            cronTrigger.setStartTime(startingDate);
        }
        if (endingDate != null) {
            cronTrigger.setEndTime(endingDate);
        }
        trigger = cronTrigger;
        return trigger;
    }

    private Trigger createSimpletrigger(int triggerCount, String text, Date startingDate, Date endingDate) {
        try {
            Trigger trigger;
            String repeatIntervalStr = text.substring(0, text.length() - 1);
            long repeatInterval = Long.parseLong(repeatIntervalStr);
           
            String repeatType = text.substring(text.length() - 1);
            if (repeatType.equals("h")) {
                repeatInterval = repeatInterval * 1000 * 60 * 60;
            }
            else if (repeatType.equals("m")) {
                repeatInterval = repeatInterval * 1000 * 60;
            }
           
            SimpleTrigger simpleTrigger = new SimpleTrigger(getName() + triggerCount, QUARTZ_JOBGROUP_WGASCHEDULER);
            simpleTrigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
            simpleTrigger.setRepeatInterval(repeatInterval);
            simpleTrigger.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT);
           
            if (startingDate != null) {
                simpleTrigger.setStartTime(startingDate);
            }
            if (endingDate != null) {
                simpleTrigger.setEndTime(endingDate);
            }
            trigger = simpleTrigger;
            return trigger;
        }
        catch (NumberFormatException e) {
            _scheduler.getCore().getLog().error("Cannot create schedule bc. of number formatting error", e);
            return null;
        }
        catch (IllegalArgumentException e) {
            _scheduler.getCore().getLog().error("Cannot create schedule bc. of illegal argument", e);
            return null;
        }
    }
   
    public void shutdown() {
       Scheduler quartzScheduler = _scheduler.getCore().getQuartzScheduler();
      
       // Quartz scheduler already terminated
       if (quartzScheduler == null) {
           return;
       }
      
      
       try {
        quartzScheduler.deleteJob(getName(), QUARTZ_JOBGROUP_WGASCHEDULER);
    }
    catch (SchedulerException e) {
       _scheduler.getCore().getLog().error("Error on shutdown of job " + getName(), e);
    }
    }

  public String getLog() {

    if (isRunning() && _currentLog != null) {
      return _currentLog.toString();
    }
    else {
      return _lastLog;
    }

  }

  protected synchronized void run(WGACore core, Map customOptions, JobExecutionContext quartzContext, String executor) {

    Logger logger = Logger.getLogger("wga.job." + _name);
        logger.setLevel(Level.INFO);
    _currentLog = new StringWriter();
    WriterAppender tempAppender = new WriterAppender(JOBLOG_LAYOUT, _currentLog);
        logger.addAppender(tempAppender);
    _failed = false;
    _exception = null;
        _running = true;

    try {
      // Prepare logging
      _lastRun = new Date();

      if (_scheduler.getLoggingDir() != null) {
        initPermanentLog(logger);
      }

      // Prepare jobContext
      JobContext jobContext = new JobContext(this, quartzContext, core, logger);
      if (customOptions != null) {
        jobContext.getCustomOptions().putAll(customOptions);
      }

      // Run tasks
            if (executor != null) {
                logger.info("Starting job " + _name + " started by admin account '" + executor + "'");
            }
            else {
                logger.info("Starting job " + _name + " triggered by WGA Scheduler");
            }
      runTasks(logger, jobContext);

      logger.info("Job execution finished");
      if (jobContext.getResult() != null) {
        logger.info("End result: " + String.valueOf(jobContext.getResult()));
        _lastResult = jobContext.getResult();
      }
    }
    catch (Exception e) {
      logger.error("Exception executing job", e);
      _exception = e;
      _failed = true;
    }
    catch (Error e) {
      logger.error("Error executing job", e);
      _exception = e;
      _failed = true;
    }
    finally {

     
      // We switch off stats on the currently registered job of this name
      Job currentJob = _scheduler.getJob(_name);
      closeStats(logger, currentJob);
      if (currentJob != this) {
          closeStats(logger, this);
      }
            if (tempAppender != null) {
                tempAppender.close();
                logger.removeAppender(tempAppender);
            }
    }

  }

    private void closeStats(Logger logger, Job currentJob) {
        currentJob._running = false;
        currentJob._lastLog = _currentLog.toString();
        currentJob._currentLog = null;
        if (currentJob._logAppender != null) {
            currentJob._logAppender.close();
          logger.removeAppender(currentJob._logAppender);
          currentJob._logAppender = null;       
        }
    }

    private void runTasks(Logger logger, JobContext jobContext) throws JobFailedException {
        Iterator tasksIt = _tasks.iterator();
        while (tasksIt.hasNext()) {
          Task task = (Task) tasksIt.next();
          logger.info("--- Running task: " + task.getTitle(Locale.getDefault()) + "------------------------------------------------");
          try {
              jobContext.setCurrentTask(task);
              task.setCustomOptions(jobContext.getCustomOptions());
            task.execute(jobContext);
            logger.info("Task successfully executed");
          }
          catch (TaskException e) {
            logger.error("Task canceled with error: " + task.getTitle(Locale.getDefault()), e);
            if (task.isCancelJobOnFail()) {
              logger.fatal("Canceling job!");
              throw new JobFailedException(
                "Canceled because of failure of task: " + task.getTitle(Locale.getDefault()), e);
            }
          }

          jobContext.setPreviousResult(jobContext.getResult());
          jobContext.setResult(null);

        }
    }

    private void initPermanentLog(Logger logger) throws JobFailedException {
        int counter = 0;
        File loggingFile;
        do {
          counter++;
          loggingFile = new File(_scheduler.getLoggingDir(), "job_" + getName() + "_" + DATE_FORMAT_LOG.format(_lastRun) + "_" + counter + ".log");
        }
        while (loggingFile.exists());
       
       
        try {
          loggingFile.createNewFile();
          _logAppender = new FileAppender(JOBLOG_LAYOUT, loggingFile.getPath());
          logger.addAppender(_logAppender);
        }
        catch (IOException e) {
          throw new JobFailedException("Could not create logging file - " + e.getClass().getName() + ": " + e.getMessage());
        }
    }

  /**
   * @return
   */
  public Map<String,String> getOptions() {
    return _options;
  }

  /**
   * @return
   */
  public Date getLastRun() {
    return _lastRun;
  }

  /**
   * @return
   */
  public String getName() {
    return _name;
  }

  /**
   * @return
   */
  public List<Task> getTasks() {
    return _tasks;
  }

  /**
   * @param previousJob
   */
  public void retrieveStats(Job previousJob) {
    _lastLog = previousJob._lastLog;
    _lastRun = previousJob._lastRun;
    _lastResult = previousJob._lastResult;
    _failed = previousJob._failed;
    _exception = previousJob._exception;
        _endMessage = previousJob._endMessage;
        _currentLog = previousJob._currentLog;
        _running = previousJob._running;
  }

  /**
   * @return
   */
  public String getDescription() {
    return _description;
  }

  /**
   * @param string
   */
  public void setDescription(String string) {
    _description = string;
  }

  /**
   * @return
   */
  public boolean isRunning() {
    return _running;
  }

  /**
   * @return
   */
  public boolean isFailed() {
    return _failed;
  }

  public void clearLog() {
    _lastLog = "";
  }
   
    public void addTrigger(Trigger trigger) {
        _trigger.add(trigger);
    }
   
    public Date nextScheduledRun() {
       
        Iterator trigger = _trigger.iterator();
        Date nextRun = null;
        while (trigger.hasNext()) {
            Trigger element = (Trigger) trigger.next();
            if (nextRun == null || element.getNextFireTime().before(nextRun)) {
                nextRun = element.getNextFireTime();
            }
        }
       
        return nextRun;
       
    }

    public boolean isTransient() {
        return _transient;
    }

    public void setName(String name) {
        _name = name;
    }

    public String getEndMessage() {
        return _endMessage;
    }

    public void setEndMessage(String endMessage) {
        _endMessage = endMessage;
    }

    public void setTransient(boolean transient1) {
        _transient = transient1;
    }

    public int getOrigin() {
        return _origin;
    }

    public void setOrigin(int origin) {
        _origin = origin;
    }
   
        protected Throwable getException() {
        return _exception;
    }

        public String getUid() {
            return _uid;
        }

        public de.innovationgate.wgpublisher.scheduler.Scheduler getScheduler() {
            return _scheduler;
        }

}
TOP

Related Classes of de.innovationgate.wgpublisher.scheduler.Job

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.