Package tcg.scheduling

Source Code of tcg.scheduling.SchedulingAgent

/**
* SchedulingAgent.java
*
* Run a list of scheduled jobs configured in the database.
*
* Scheduling agent is running as a managed process under the Process Manager.
* As such it extends the scada common's ManagedProcess class.
*
* Scheduling agent is supposed to be executed as an agent by Process Manager from
* command line. As such it has main() function.
*
* @author    Wahyu Yoga Pratama (wahyu@stee.stengg.com)
*
* @created      Feb 08, 2006
* @version    $$
*
* HISTORY:
* - 2008/02/06  Created.
*
* TODO:
* -
*/

package tcg.scheduling;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Properties;
import java.io.IOException;
import java.io.InputStream;
import java.lang.StringBuilder;

//import oracle.jdbc.pool.OracleConnectionCacheImpl;
//import oracle.jdbc.pool.OracleConnectionPoolDataSource;

import org.apache.commons.cli.HelpFormatter;
import org.apache.log4j.Logger;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

import tcg.common.DatabaseManager;
import tcg.common.LoggerManager;
import tcg.common.Utilities;
import tcg.syscontrol.ManagedProcess;

public class SchedulingAgent extends ManagedProcess
{
  public static final String VERSION = "01.01 (20091112)";
  public static final String SCHEDULER_ARG_STRING = "Parent";
  public static final String ARGUMENT_ARG_STRING = "Arguments";
  public static final String TASK_ARG_STRING = "Task";
  public static final long   EXECUTION_DELAY_MILLIS = 30000;

  public static final String DEF_CRONTABLE = "SCHED_CRONMASTER";
 
  private static final String DEF_CRONDOMAIN = "TCG";

  // Number of threads
  private static final String DEF_THREADCOUNT = "2"
  // Simple Trigger
  public static final String DEF_STARTTIME = "";
  public static final String DEF_ENDTIME = "";
  public static final String DEF_REPEATCOUNT = "" + SimpleTrigger.REPEAT_INDEFINITELY;
  public static final String DEF_INTERVAL = "5000";
  // Cron Trigger
  public static final String DEF_CRONSTRING = "";

  private static Logger logger_ = LoggerManager.getLogger(SchedulingAgent.class.toString());

  private Scheduler scheduler_ = null
  private String domain_ = DEF_CRONDOMAIN;

  //the calendar instance
  private Calendar calendar_ = new GregorianCalendar();
 
  //the in-process thread
  private Thread  thread_ = null;

  /**
   * Main entry for in-process execution. This must run on its thread!
   */
  public void execute(String args)
  {
    String[] params = args.split(" ");
    thread_ = new Thread(new InProcessExecution(params));
    thread_.start();
  }
 
  /**
   * Main entry for command line execution.
   * @param args   - list of command line arguments
   */
  public static void main(String[] args)
  {
    //if arguments has "--version", print version number and quit
    String logfile = "";
    for (int i=0; i<args.length; i++)
    {
      if (args[i].equalsIgnoreCase("--version") || args[i].equalsIgnoreCase("-V")) {
        printVersion();
        return;
      } else if (args[i].equalsIgnoreCase("--help") || args[i].equalsIgnoreCase("-h")) {
        printUsage();
        return;
      } else if (args[i].equalsIgnoreCase("--logfile") || args[i].equalsIgnoreCase("-l")) {
        if (++i<args.length) logfile = args[i];
      }
    }
       
    //create the Scheduling Agent instance
    SchedulingAgent instance = new SchedulingAgent();   
        //reset logging
        if (logfile.length() > 0)
        {
          LoggerManager.setLogFile(logfile);
        }
        instance.setLogger(logger_);
           
        logger_.info("---- Scheduling Agent starting ----");
       
        if (!instance.initialize(args))
        {
          logger_.error("Failed to initialize. Quitting!");
          logger_.info("---- Scheduling Agent has shut down ----");     
          return;
        }
       
    //Print out all configuration as visual feedback (runtime)
        instance.printConfiguration();
   
        //run the agent
        logger_.info("---- Scheduling Agent is running ----");
      //instance.xxx_run();
      instance.run();
       
        //shutting down
      logger_.info("---- Scheduling Agent is shutting down ----");        
     
      //clean up
      //Nothing
     
      //done
      logger_.info("---- Scheduling Agent has shut down ----");        
  }
 
  private static void printVersion()
  {
    System.out.println("Scheduling Agent Version " + VERSION);
  }
 
  protected static final void printUsage()
  {
    System.out.println("Scheduling Agent Version " + VERSION);
    System.out.println("");
    ManagedProcess.printUsage();
    System.out.println("");
    System.out.println("Scheduling Agent Additional Command Line Parameters:  ");
    System.out.println(" -d | --domain <domain-name>     Scheduling agent domain");
    System.out.println("");
    System.out.println("Event Agent Additional Java Properties (Configuration file or System properties):  ");
    System.out.println(" tcg.sched.domain         Default scheduler domain");   
    System.out.println(" tcg.sched.thread         No of worker thread for scheduler");   
    System.out.println(" tcg.sched.configfile     Scheduler properties files");   
    System.out.println("");
    System.out.println("Command line parameters will override java properties and configuration file value.");
    System.out.println("");
    System.out.println("Component Library Information:");
    System.out.println("\t - Quartz Scheduler Ver. 1.6.6");
    System.out.println("\t - Log4J Ver. 1.2.12");
    System.out.println("\t - Oracle JDBC Ver. 10.2");
    System.out.println("\t - JacORB Ver. 2.3");
    System.out.println("\t - Avalon Framework Ver. 4.1.5");
    System.out.println("");
    System.out.println("Other Component Information:");
    System.out.println("");
  }

  @Override
  public String getStatusString()
  {
    StringBuilder strbuffer = new StringBuilder();
    //list down all jobs and trigger
    try {
      String[] jobGroups;
      String[] jobsInGroup;
      int i;
      int j;

      jobGroups = scheduler_.getJobGroupNames();
      for (i = 0; i < jobGroups.length; i++) {
        strbuffer.append("Group: " + jobGroups[i] + " contains the following jobs\n");
        jobsInGroup = scheduler_.getJobNames(jobGroups[i]);
 
        for (j = 0; j < jobsInGroup.length; j++) {
          strbuffer.append("- " + jobsInGroup[j] + "\n");
          logger.info("- " + jobsInGroup[j]);
        }
      }
     
      String[] triggerGroups;
      String[] triggersInGroup;
     
      triggerGroups = scheduler_.getTriggerGroupNames();
      for (i = 0; i < triggerGroups.length; i++) {
        strbuffer.append("Group: " + triggerGroups[i] + " contains the following triggers\n");
        triggersInGroup = scheduler_.getTriggerNames(triggerGroups[i]);
     
        for (j = 0; j < triggersInGroup.length; j++) {
          strbuffer.append("- " + triggersInGroup[j] + "\n");
        }
      }
    } catch (Exception ex) {
      //Ignore
      strbuffer.append(ex.toString());
    }
   
    return strbuffer.toString();
  }

  @Override
  public boolean initialize2(String[] args, Properties props)
  {
    //Specific configuration setting
    //get the scheduling agent domain
        options.addOption("d", "domain", true, "Scheduling Agent Domain");
       
        //parser
        org.apache.commons.cli.Parser parser = new org.apache.commons.cli.GnuParser();
       
        //parse command line arguments
        org.apache.commons.cli.CommandLine cmd = null;
        try
        {
          cmd = parser.parse(options, args, true);
        }
        catch(org.apache.commons.cli.ParseException pe)
        {
      logger.error("Can not parse arguments: " + pe.getMessage());
      HelpFormatter formatter = new HelpFormatter();
      formatter.printHelp( "Parameters:", options );
      return false;
        }
       
        //get the value: agent port
        if (cmd.hasOption("d"))
        {
          domain_ = cmd.getOptionValue("d");
          props.put("tcg.runtime.domain", domain_);
        }
       
        //if the domain name is not given in the command line, use default
        if (domain_ == null || domain_.length() == 0)
        {
          domain_ = props.getProperty("tcg.sched.domain", DEF_CRONDOMAIN);
        }
       
        return true;
  }
 
  @Override
  public boolean configureApplication2()
  {
    //nothing to do since database configuration is already performed in
    //ManagedProcess class
    return true;
  }
 
  @Override
  /**
   * The following properties is required:
   * - ste.sched.configFile  : Quartz scheduler configuration file
   * - ste.sched.thread    : No of threads in the scheduler thread pool
   */
  public boolean startControl()
  {
    boolean status = false;

    //Start the scheduler
    Connection conn = DatabaseManager.getConnection();
    if (conn == null)
    {
      return false;
    }

    StdSchedulerFactory factory;
    int          errorCode = 0;
    try
    {
            //Initialize scheduler
        logger.info("Initializing Quartz java scheduler");

        String quartzConfigFile = props.getProperty("tcg.sched.configfile", "");
            String threadNo = props.getProperty("tcg.sched.thread", DEF_THREADCOUNT);
           
            //load properties from file
          Properties quartzProps = new Properties();
          if (quartzConfigFile.length() >= 0)
          {
               InputStream in = Utilities.getInputStream(quartzConfigFile);
               if (in != null)
               {
                 quartzProps.load(in);
                   try
                   {
                     in.close();
                   }
                   catch(IOException ioe)
                   {
                     //ignore
                   }
               }
          }

          //override properties with some of our setting
          quartzProps.setProperty("org.quartz.threadPool.threadCount", threadNo);
          String str = quartzProps.getProperty("org.quartz.threadPool.class");
          if (str == null || str.length() == 0)
          {
            quartzProps.setProperty("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
          }
         
          //create the scheduler
          factory = new StdSchedulerFactory(quartzProps);
          scheduler_ = factory.getScheduler();
     
          //Schedule all the jobs
          scheduleJobs(scheduler_, conn);
         
            //Start the scheduler
        logger.info("Starting Quartz java scheduler");
          scheduler_.start();
         
          //successful
          status = true;
      }
    catch (SQLException sqle)
    {
           logger.error("Database access error: " + sqle.getMessage());
        logger.error("--------------------------------------------\n");
          sqle.printStackTrace(loggerWriter);
        logger.error("--------------------------------------------\n");
        errorCode = sqle.getErrorCode();
    }
    catch (SchedulerException se) {
          logger.error("Scheduler initialization error: " + se.getMessage());
          logger.error("--------------------------------------------\n");
            se.printStackTrace(loggerWriter);
          logger.error("--------------------------------------------\n");
        }
    catch (Exception ex) {
          logger.error("Exception: " + ex.getMessage());
          logger.error("--------------------------------------------\n");
            ex.printStackTrace(loggerWriter);
          logger.error("--------------------------------------------\n");
    }

    DatabaseManager.returnConnection(errorCode);
   
    if (status)
    {
        logger.info("---- Scheduling Agent is running CONTROL ----");        
    }

     return status;
  }

  @Override
  public boolean startMonitor()
  {
      logger.info("---- Scheduling Agent is running MONITOR ----");        
    //in monitor mode, we just sit idly!
    return true;
  }

  @Override
  public boolean stopControl()
  {
        if (scheduler_ == null)
          return false;

        //Do I really need this one?
        logger.info("Shutting down Quartz java scheduler")
    try
    {
      scheduler_.shutdown();       
          scheduler_ = null;
    }
    catch (Exception e)
    {
           //ignore
      logger.error("Exception: " + e.getMessage());
          logger.error("--------------------------------------------\n");
            e.printStackTrace(loggerWriter);
          logger.error("--------------------------------------------\n");
     }
    return true;
  }

  @Override
  public boolean stopMonitor()
  {
    //Since in monitor mode it sits idle, nothing need to be stopped
    return true;
  }

//  @Override
//  public void eventHandler(CosNotificationEventEnum event, String eventInfo) {
//    //ignore all events
//  }
 
  /**
   *
   * @param Scheduler   Quartz scheduler object
   * @param Connection   Database connectionn
   * @throws SQLException
   *
   * Read all schedule jobs from database and insert it into the scheduler.
   *
   * This function expect a database table in the following structure
   * Table CRONMASTER
   * - TASK_ID      : String. Unique task id
   * - DOMAIN        : String. Task domain.
   * - JOB_CLASS      : String. Java class that perform the job
   * - ARGUMENTS      : String. Arguments to the java class
   * - TRIGGER_TYPE    : String. Trigger type ('CronTrigger' or 'SimpleTrigger').
   * - TRIGGER_CRON    : String. Cron trigger's cron statement
   * - TRIGGER_START    : Date.   Simple trigger's start time
   * - TRIGGER_END    : Date.    Simple trigger's end type
   * - TRIGGER_REPEAT    : Number. Simple trigger's no of repeat
   * - TRIGGER_INTERVAL  : Number. Simple trigger's interval
   * - ENABLED      : Char.   Enabled flag ('Y' or 'N')
   * - TOUPDATE      : Char.   Update flage ('Y' or 'N') used by MasterCronJob to update job definition
   */
  private void scheduleJobs(Scheduler sched, Connection conn) throws SQLException
  {
    String taskGroup = domain_;
   
    Statement stmt = conn.createStatement();
      String query = "select * from " + DEF_CRONTABLE + " " +
              "where DOMAIN='" + domain_ + "' and ENABLED='Y'";
      ResultSet rs = stmt.executeQuery(query);
          
    String curTask;
    String taskJob, taskTrigger, taskArgs;
    boolean isSimpleTrigger;
    String taskCron="";
    Date taskStartTime=null, taskEndTime=null;
    int taskRepeat=0, taskInterval=0;
    Class<?> jobClass = null;
    Date startTime = null;;
    Date endTime = null;
    Date curTime = new Date();
    int repeat=0;
    long interval=0;
    Trigger trigger = null;
    JobDetail jobDetail = null;
   
    while (rs.next()) {
      curTask = rs.getString("TASK_ID");
      taskJob = rs.getString("JOB_CLASS");
      taskArgs = rs.getString("ARGUMENTS");
      if (taskArgs == null)
      {
        taskArgs = "";
      }
      taskTrigger = rs.getString("TRIGGER_TYPE");
     
      //verbose
      logger.info("Task " + curTask);
      logger.info("Task " + curTask + " - Job Class    = " + taskJob);
      logger.info("Task " + curTask + " - Trigger Type = " + taskTrigger);
      logger.info("Task " + curTask + " - Arguments    = " + taskArgs);
     
      //validation
      if (taskJob.length() == 0 || taskTrigger.length() == 0)
      {
        logger.error("You must provide both Job class and Trigger type for task "
                + curTask + "!");
        continue;
      }
     
      //get the trigger setting
      if (taskTrigger.compareToIgnoreCase("CronTrigger") == 0)
      {
        taskCron = rs.getString("TRIGGER_CRON");
        if (null == taskCron) {
          taskCron = DEF_CRONSTRING;
        } else {
          taskCron = taskCron.trim();
        }
        isSimpleTrigger = false;
        //verbose
        logger.info("Task " + curTask + " - Cron Value   = " + taskCron);
      }
      else if (taskTrigger.compareToIgnoreCase("SimpleTrigger") == 0)
      {
        taskStartTime = rs.getDate("TRIGGER_START");
        if (taskStartTime == null)
        {
          taskStartTime = new Date();
        }
        taskEndTime = rs.getDate("TRIGGER_END");
        taskRepeat = rs.getInt("TRIGGER_REPEAT");
        taskInterval = rs.getInt("TRIGGER_INTERVAL");
        isSimpleTrigger = true;
        //verbose
        logger.info("Task " + curTask + " - Start Time   = " + taskStartTime);
        logger.info("Task " + curTask + " - End Time     = " + taskEndTime);
        logger.info("Task " + curTask + " - Repeat Count = " + taskRepeat);
        logger.info("Task " + curTask + " - Interval     = " + taskInterval);
        if (taskEndTime != null &&
            (curTime.after(taskEndTime) || !taskStartTime.before(taskEndTime)))
        {
          logger.warn("Task " + curTask + " is OBSOLETE! Ignored.");
          continue;
        }
      }
      else
      {
        logger.error("Invalid trigger type ("+ taskTrigger + ") for task " + curTask + "!");
        continue;
      }
     
      //interpret parameters
      try
      {
        jobClass = Class.forName(taskJob);
        if (jobClass == null)
        {
          logger.error("Invalid job class (" + taskJob + ") for task " + curTask + "!");
          continue;
        }
      }
      catch (ClassNotFoundException e)
      {
        logger.error("Invalid job class (" + taskJob + ") for task " + curTask + "!");
        continue;
      }
      catch (NoClassDefFoundError e)
      {
        //NOTE: NoClassDefFoundError does not seem to extend Exception
        logger.error("Can not load class " + taskJob + ". Exception: " + e.toString());
        continue;
      }
      catch (Exception e)
      { 
        logger.error("Can not load class " + taskJob + ". Exception: " + e.toString());
        continue;
      }

      if (isSimpleTrigger)
      {
        //delay the execution until the agent is properly started
        startTime = new Date();
        startTime.setTime(startTime.getTime()+EXECUTION_DELAY_MILLIS);   
        if (taskStartTime != null && taskStartTime.after(startTime)) {
          startTime = taskStartTime;
        }
        endTime = taskEndTime;
        if (taskRepeat < 0) {
          repeat = SimpleTrigger.REPEAT_INDEFINITELY;
        } else {
          repeat = taskRepeat;
        }
        if (taskInterval < 0) {
          interval = 0;
        } else {
          interval = taskInterval;
        }
      }
     
      //create trigger
      logger.info("Task " + curTask + " - Creating trigger...");
      trigger = null;
      if (isSimpleTrigger) {
        try {
          trigger = new SimpleTrigger(curTask + "_Trigger", null, startTime, endTime, repeat, interval);
        } catch (Exception e) {
          logger.error("Cannot create trigger for task " + curTask + "!");
          logger.error("Exception: "+e.getMessage());
          continue;         
        }
      } else {
        try {
          trigger = new CronTrigger(curTask + "_Trigger", null, taskCron);
        } catch (ParseException e) {
          logger.error("Invalid cron epression (" + taskCron + ") for task " + curTask + "!");
          continue;
        }
      }

      trigger.getJobDataMap().put(SCHEDULER_ARG_STRING, this);
      trigger.getJobDataMap().put(TASK_ARG_STRING, curTask);
      trigger.getJobDataMap().put(ARGUMENT_ARG_STRING,taskArgs);
      trigger.setGroup(taskGroup);
     
      //create job
      logger.info("Task " + curTask + " - Creating job...");
      jobDetail = null;
      try {
        jobDetail = new JobDetail(curTask, null, jobClass);
      } catch (Exception e) {
        logger.error("Cannot create job for task " + curTask + "!");
        logger.error("Exception: "+e.getMessage());
        continue;         
      }
      jobDetail.setGroup(taskGroup);
     
      //schedulling the job/trigger
      logger.info("Task " + curTask + " - Schedulling the job...");
      try {
        sched.scheduleJob(jobDetail, trigger);
      } catch (SchedulerException e) {
        logger.error("Cannot schedule job for task " + curTask + "!");
        logger.error("Exception: "+e.getMessage());
        continue;
      }
    }   
    rs.close();
   
    //update status
    stmt.execute("update " + DEF_CRONTABLE + " set TOUPDATE='N' where DOMAIN='"
            + domain_ + "'");   
    stmt.close();

 

  public String getDomain()
  {
    return domain_;
  }
 
  public Calendar getCalendar()
  {
    return calendar_;
  }
 
  /**
   * Thread for running this agent as in-process thread.
   * @author Yoga
   */
  class InProcessExecution implements Runnable
  {
    private String[] args_ = null;
   
    /**
     * Ctor. Provide the command line argument
     * @param args  - command line argument
     */
    public InProcessExecution(String[] args)
    {
      args_ = args;
    }
   
    /**
     * Main execution thread
     */
    public void run()
    {
      //just run the static main() in its own thread
      SchedulingAgent.main(args_);
    }
  }
}
TOP

Related Classes of tcg.scheduling.SchedulingAgent

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.