Package sos.scheduler.cron

Source Code of sos.scheduler.cron.CronConverter

/********************************************************* begin of preamble
**
** Copyright (C) 2003-2010 Software- und Organisations-Service GmbH.
** All rights reserved.
**
** This file may be used under the terms of either the
**
**   GNU General Public License version 2.0 (GPL)
**
**   as published by the Free Software Foundation
**   http://www.gnu.org/licenses/gpl-2.0.txt and appearing in the file
**   LICENSE.GPL included in the packaging of this file.
**
** or the
** 
**   Agreement for Purchase and Licensing
**
**   as offered by Software- und Organisations-Service GmbH
**   in the respective terms of supply that ship with this file.
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
** IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
** THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
** PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
** BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
** CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
** SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
** INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
** CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
** ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
** POSSIBILITY OF SUCH DAMAGE.
********************************************************** end of preamble*/
/*
* CronConverter.java
* Created on 20.08.2007
*
*/
package sos.scheduler.cron;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.GnuParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionBuilder;
import org.apache.commons.cli.Options;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Comment;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import sos.util.SOSLogger;
import sos.util.SOSStandardLogger;

/**
* This Class converts a crontab file to a Job Scheduler XML Configuration
*
* @author Andreas Liebert
*/
public class CronConverter {
 
  private DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
  private DocumentBuilder docBuilder;
  /**
   * Regular Expression
   * -?([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+([^\s]+)\s+(.+)$
   * matches cron lines such as
   * 59 23  *  *  *   /usr/bin/xmessage.sh
   * with grouping
   */
  private final static String cronRegEx = "-?([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+(.+)$";
 
  /**
   * Regular Expression for system crontab has one more column (user)
   */
  private final static String cronRegExSystem = "-?([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)\\s+(.+)$";

  protected Pattern cronRegExPattern;
 
  protected Pattern cronRegExSystemPattern;
  private SOSLogger logger;
 
  private boolean systemCronTab = false;
 
  private boolean oldRunTime = false;
  private boolean usedNewRunTime = false;
 
  private String changeUserCommand = "";
 
  /**
   * Regular Expression
   * (@reboot|@yearly|@monthly|@weekly|@daily|@hourly)\s+(.+)$
   * matches cron lines with aliases such as
   * @monthly   test -x /usr/sbin/texpire && /usr/sbin/texpire
   */
  private final static String cronRegExAlias = "(@reboot|@yearly|@annually|@monthly|@weekly|@daily|@midnight|@hourly)\\s+(.+)$";
 
  protected Pattern cronRegExAliasPattern;
 
  /**
   * Regular Expression
   * ^\s*#\s*(.+)
   * matches cron comment lines
   */
  private final static String cronRegExComment = "^\\s*#\\s*(.+)";
 
  protected Pattern cronRegExCommentPattern;
 
  /**
   * Regular Expression
   * \s*job_name\s*=\s*(.+)
   * matches comments which set a job name
   */
  private final static String cronRegExJobName = "\\s*job_name\\s*=\\s*(.+)";
 
  protected Pattern cronRegExJobNamePattern;
 
  /**
   * Regular Expression
   * \s*job_title\s*=\s*(.+)
   * matches comments which set a job title
   */
  private final static String cronRegExJobTitle = "\\s*job_title\\s*=\\s*(.+)";
 
  protected Pattern cronRegExJobTitlePattern;
 
  /**
   * Regular Expression
   * \s*job_timeout\s*=\s*(.+)
   * matches comments which set a job timeout
   */
  private final static String cronRegExJobTimeout = "\\s*job_timeout\\s*=\\s*(.+)";
 
  protected Pattern cronRegExJobTimeoutPattern;
 
  /**
   * Regular Expression
   * ^\s*(\w+)\s*=\s*(.+)
   * matches environment variable settings
   */
  private final static String cronRegExEnvironment = "^\\s*(\\w+)\\s*=\\s*(.+)";
 
  protected Pattern cronRegExEnvironmentPattern;
 
  /**
   * Regular Expression
   * [^\s]* /[^\s]*
   * matches a path (at least one "/")
   */
  private final static String commandRegEx = "[^\\s]*/[^\\s]*";
 
  private Pattern commandRegExPattern;
 
  /**
   * Regular expression
   * (.*)_(\d*)$
   * Matches incremented job names
   */ 
  private final static String jobNameRegEx = "(.*)_(\\d*)$";
 
  private Pattern jobNameRegExPattern;
 
  private HashSet skipLines = new HashSet();
 
  private HashSet reservedJobNames = new HashSet();
 
  private String timeout = "600";
  protected Pattern currentCronPattern;
 
  /**
   * @param args
   */
  public static void main(String[] args) {
    /*try {
        test();
      } catch(Exception ex){
        ex.printStackTrace();
      }
    */
    try {
      //SOSArguments arguments = new SOSArguments(args);
      SOSLogger sosLogger;
      String sourceFile="";
      String targetFile="";
      String changeUser ="";
      File source=null;
      File target=null;
      int logLevel=0;
      boolean sysTab = false;
      boolean useOldRunTime = false;
      String jobTimeout="";
      /*
      try {
        sourceFile = arguments.as_string("-crontab=");
        if (sourceFile.equalsIgnoreCase("/etc/crontab")) sysTab = true;
        targetFile = arguments.as_string("-target=");
        logLevel = arguments.as_int("-v=",SOSStandardLogger.INFO);       
        sysTab = arguments.as_bool("-system=",sysTab);
        useOldRunTime = arguments.as_bool("-oldRunTime=",false);
        changeUser = arguments.as_string("-change-user=", "su");
      } catch (Exception e1) {
        System.out.println(e1.getMessage());
        showUsage();
        System.exit(0);
      }*/
      Options options = new Options();     
      Option optSysTab = OptionBuilder.withArgName("0|1").hasArg().withDescription("set to 1 if source is the system crontab (with user field)").create("systab");
      Option optSourceFile = OptionBuilder.withArgName("file").hasArgs().isRequired()
          .withDescription("crontab file").create("crontab");
      Option optTargetFile = OptionBuilder.withArgName("file").hasArgs().isRequired()
        .withDescription("xml configuration file").create("target");
      Option optLogLevel = OptionBuilder.withArgName("level").hasArg().withType(new Integer(0))
        .withDescription("loglevel [0=info] [1=debug1]...[9=debug9]").create("v");
      Option optChangeUser = OptionBuilder.withArgName("command").hasArgs()
          .withDescription("change user command for -systab=1. 'su' or 'sudo' or define your own command using $SCHEDULER_CRONTAB_USER.")
          .create("changeuser");
      Option optTimeOut = OptionBuilder.withArgName("seconds").hasArg()
        .withDescription("job timeout (0 for unlimited").create("timeout");
      Option optOldRunTime = new Option("oldRunTime","");
     
      options.addOption(optSysTab);
      options.addOption(optSourceFile);
      options.addOption(optTargetFile);
      options.addOption(optLogLevel);
      options.addOption(optChangeUser);
     
      CommandLineParser parser = new GnuParser();
      CommandLine line=null;
      try{
        line = parser.parse(options, args);
      } catch(Exception e){
        HelpFormatter formatter = new HelpFormatter();
        formatter.printHelp("cronconverter", options, true);
        System.exit(0);
      }
     
      sourceFile = getWholeArgument(line.getOptionValues("crontab"));
      if (sourceFile.equalsIgnoreCase("/etc/crontab")) sysTab = true;
      targetFile = getWholeArgument(line.getOptionValues("target"));
     
      String ll = line.getOptionValue("v", ""+SOSStandardLogger.INFO);
      logLevel = Integer.parseInt(ll);
      if (line.hasOption(optSysTab.getOpt())){
        sysTab =(line.getOptionValue(optSysTab.getOpt()).trim().equals("1"));
      }   
      useOldRunTime = line.hasOption("oldRunTime");
      changeUser = "";
      if (line.hasOption("changeuser")){
        changeUser = getWholeArgument(line.getOptionValues("changeuser"));
      }     
           
      jobTimeout = line.getOptionValue("timeout");
      if (logLevel==0) logLevel=SOSLogger.INFO;
      sosLogger = new SOSStandardLogger(logLevel);     
           
      target = new File(targetFile);
      source = new File(sourceFile);
     
      CronConverter cc = new CronConverter(sosLogger);
      if (jobTimeout!=null && jobTimeout.length()>0) cc.setTimeout(jobTimeout);
      cc.setChangeUserCommand(changeUser);
      cc.setSystemCronTab(sysTab);
      cc.oldRunTime = useOldRunTime;
      cc.cronFile2SchedulerXMLFile(source, target);
     
    } catch (Exception e) {
      e.printStackTrace();
    }
   
  }
 
 
  private static String getWholeArgument(String[] optionValues) {
    String value="";
    for (int i = 0; i < optionValues.length; i++) {
      value += optionValues[i];
      if (i+1<optionValues.length) value+=" ";
    }
    return value;
  }
 
 
  private static void test() throws Exception {
    SOSLogger log = new SOSStandardLogger(SOSLogger.DEBUG9);
    CronConverter cc = new CronConverter(log);
//    File inputFile = new File("J:\\E\\java\\al\\sos.scheduler\\config\\crontab");
//    File outputFile = new File("J:\\E\\java\\al\\sos.scheduler\\config\\scheduler_cron.xml");
    File inputFile = new File("c:/temp/cronfile.cron");
    File outputFile = new File("c:/temp/scheduler_cron.xml");
   
    cc.cronFile2SchedulerXMLFile(inputFile, outputFile);
   
    // von http://www.newbie-net.de/anleitung_cron.html
    //Document job = cc.line2Job("5 22  *  *  *   test -x /usr/sbin/texpire && /usr/sbin/texpire");
    //Document job = cc.line2Job("5 22  *  *  *   test -x bla");
    //Document job = cc.line2Job("5 22  3  *  *   test -x bla");
    //Document job = cc.line2Job("5 22  3,5,8-12  *  *   test -x bla");
    //Document job = cc.line2Job("1  0  *  *  1   /usr/bin/xsoftwaresamba.sh");
   
    //Ein Bindestrich  -  gibt einen Zeitraum an. Jeden Tag von 12-24 Uhr (jede Stunde) ...:
    //Document job = cc.line2Job("0  12-24  *  *  *   /usr/bin/xsoftwaresamba.sh");
    
    // Ein Schr�gstrich  /  teilt einen Zeitraum ein. Zwischen 6 und 23 Uhr alle 15 Minuten ...:
    //Document job = cc.line2Job("*/15  6-23  *  *  *   /usr/bin/xsoftwaresamba.sh");
      
    // Jeden Tag um 0:00 und um 12:00 Uhr wird das Script xmessage.sh aufgerufen:
    //Document job = cc.line2Job("0  0,12  *  *  *  /usr/bin/xmesssage.sh");
   
   
    // von http://docs.phplist.com/CronJobExamples
    // ...I want the script to run every 15 minutes starting at 5 p.m. (17) and running through 11:00 p.m. (23). This should happen Tue. (2) through Sat. (6)
    //Document job = cc.line2Job("*/15 17-23 * * 2,3,4,5,6 /sbin/phplist -pprocessqueue");
    //Document job = cc.line2Job("*/15 17-23 * * Tue-sat /sbin/phplist -pprocessqueue");

    //Document job = cc.line2Job("15,30,45,00 * * * * /var/www/www.domain.com/phplist phplist-2.10.2/bin/phplist -p processqueue > /dev/null");
   
    // von http://www.pantz.org/os/linux/programs/cron.shtml
    // This line executes the "ping" and the "ls" command every 12am and 12pm on the 1st day of every 2nd month
    // Document job = cc.line2Job("0 0,12 1 */2 * /sbin/ping -c 192.168.0.1; ls -la >>/var/log/cronrun");
   
    // von http://www.monetizers.com/cronjob.php
    // every day 23 minutes after every even hour (0:23, 2:23, ...)
    //Document job = cc.line2Job("23 0-23/2 * * * $HOME/report.sh");
   
   
    /*StringWriter out = new StringWriter();
    OutputFormat format = new OutputFormat(job);   
    format.setIndenting(true);
    format.setIndent(2);
        XMLSerializer serializer = new XMLSerializer(out, format);
        serializer.serialize(job);
        log.info(out.toString());*/
       
  }

  public CronConverter(SOSLogger log) throws Exception{
    docBuilder = docFactory.newDocumentBuilder();
    cronRegExAliasPattern = Pattern.compile(cronRegExAlias);
    cronRegExPattern = Pattern.compile(cronRegEx);
    cronRegExSystemPattern = Pattern.compile(cronRegExSystem);
    cronRegExCommentPattern = Pattern.compile(cronRegExComment);
    cronRegExEnvironmentPattern = Pattern.compile(cronRegExEnvironment);
    commandRegExPattern = Pattern.compile(commandRegEx);
    jobNameRegExPattern = Pattern.compile(jobNameRegEx);
    cronRegExJobNamePattern = Pattern.compile(cronRegExJobName);
    cronRegExJobTitlePattern = Pattern.compile(cronRegExJobTitle);
    cronRegExJobTimeoutPattern = Pattern.compile(cronRegExJobTimeout);
   
    currentCronPattern = cronRegExPattern;
    logger = log;
  }
 
  public void cronFile2SchedulerXMLFile(File cronFile, File schedulerXML) throws Exception{
    try{
      Document configurationDocument = cronFile2SchedulerXML(cronFile, new HashMap());
      logger.debug("writing "+schedulerXML.getAbsolutePath());
      OutputStream fout = new FileOutputStream(schedulerXML,false);         
          OutputStreamWriter out = new OutputStreamWriter(fout, "UTF-8");
      OutputFormat format = new OutputFormat(configurationDocument);
      format.setEncoding("UTF-8");
      format.setIndenting(true);
      format.setIndent(2);
          XMLSerializer serializer = new XMLSerializer(out, format);
          serializer.serialize(configurationDocument);
          out.close();
    } catch (Exception e){
      throw new Exception ("Error writing Job Scheduler configuration file: "+e,e);
    }
  } 
 
 
  /**
   * Converts a crontab to a Scheduler XML as DOM document and
   * provides easy access to the job elements by putting them to the vector
   * jobs
   * @param cronFile crontab file
   * @param cron2jobMapping empty vector which will be filled with cron lines mapped to job DOM Elements
   * @return DOM Document with scheduler configuration
   * @throws Exception
   */
  public Document cronFile2SchedulerXML(File cronFile, HashMap cron2jobMapping) throws Exception{
    try{
      HashSet jobNames = new HashSet();
      if(reservedJobNames!=null) jobNames.addAll(reservedJobNames);
      HashMap environmentVariables = new HashMap();
      Document configurationDoc = docBuilder.newDocument();
      Element spoolerElement = configurationDoc.createElement("spooler");
      configurationDoc.appendChild(spoolerElement);
      Element configElement = configurationDoc.createElement("config");
      spoolerElement.appendChild(configElement);
      Element jobsElement = configurationDoc.createElement("jobs");
      configElement.appendChild(jobsElement);
     
      BufferedReader in = new BufferedReader ( new FileReader (cronFile) );
     
      String currentLine ="";
      String lastComment = "";
      String lastCommentJobName = "";
      String lastCommentJobTitle = "";
      String lastCommentJobTimeout = "";
     
      while( (currentLine = in.readLine()) != null ) {
        if (currentLine.trim().length()==0){
          lastComment="";
          continue;
        }
        if (skipLines!=null && skipLines.contains(currentLine)){
          logger.debug6("Skipping line "+currentLine);
          lastComment="";
          lastCommentJobName ="";
          lastCommentJobTitle = "";
          lastCommentJobTimeout = "";
          continue;
        }
        Matcher commentMatcher = cronRegExCommentPattern.matcher(currentLine);
        if (commentMatcher.matches()){                 
          Matcher jobNameMatcher = cronRegExJobNamePattern.matcher(commentMatcher.group(1));
          Matcher jobTitleMatcher = cronRegExJobTitlePattern.matcher(commentMatcher.group(1));
          Matcher jobTimeoutMatcher = cronRegExJobTimeoutPattern.matcher(commentMatcher.group(1));
          if (jobNameMatcher.matches()){
            lastCommentJobName = jobNameMatcher.group(1);
            logger.debug5("Found job name in comment: "+lastCommentJobName);
            continue;
          }
          if (jobTitleMatcher.matches()){
            lastCommentJobTitle = jobTitleMatcher.group(1);
            logger.debug5("Found job title in comment: "+lastCommentJobTitle);
            continue;
          }
          if (jobTimeoutMatcher.matches()){
            lastCommentJobTimeout = jobTimeoutMatcher.group(1);
            logger.debug5("Found job timeout in comment: "+lastCommentJobTimeout);
            continue;
          }
          if (lastComment.length()>0) lastComment+="\n";
          lastComment+=commentMatcher.group(1);
          continue;
        }
        Matcher environmentMatcher = cronRegExEnvironmentPattern.matcher(currentLine);
        if(environmentMatcher.matches()){
          String envName = environmentMatcher.group(1);
          String envValue = environmentMatcher.group(2);
          logger.debug3("Found environment variable ["+envName+"]: "+envValue);
          if (envValue.startsWith("\"") && envValue.endsWith("\"")){
            envValue=envValue.substring(1, envValue.length()-1);
          }
          environmentVariables.put(envName, envValue);
          lastComment = "";
        }
        Matcher cronMatcher = currentCronPattern.matcher(currentLine);
        Matcher cronAliasMatcher = cronRegExAliasPattern.matcher(currentLine);
        if (cronMatcher.matches() || cronAliasMatcher.matches()){
          Document jobDocument = line2Job(currentLine, environmentVariables);
          Element jobElement = jobDocument.getDocumentElement();
          //NodeList jobChildren = jobElement.getChildNodes();
          //Element paramsElement = null;
          /*for (int i=0; i<jobChildren.getLength() && paramsElement==null;i++){
            Node currentNode = jobChildren.item(i);
            if (currentNode.getNodeName().equals("params")) paramsElement = (Element) currentNode;
          }*/
         
         
          boolean jobNameChanged = false;
          if (lastCommentJobName.length()>0) {
            jobElement.setAttribute("name", lastCommentJobName.replaceAll("/", "_"));
            lastCommentJobName = "";
          }
          if (lastCommentJobTitle.length()>0){
            jobElement.setAttribute("title", lastCommentJobTitle);
            lastCommentJobTitle = "";
          }
          if (lastCommentJobTimeout.length()>0){
            jobElement.setAttribute("timeout", lastCommentJobTimeout);
            lastCommentJobTimeout = "";
          }
          String jobName = jobElement.getAttribute("name");
          while(jobNames.contains(jobName)){
            logger.debug3("Configuration already contains a job named \""+jobName+"\". Looking for new name.");
            jobName = incrementJobName(jobName);
            jobNameChanged=true;
          }
          if (jobNameChanged){
            logger.debug3("Setting new job name \""+jobName+"\"");
            jobElement.setAttribute("name", jobName);
          }
          jobNames.add(jobName);
          Node importedJob = configurationDoc.importNode(jobElement, true);
          cron2jobMapping.put(currentLine, jobElement);         
          if (lastComment.length()>0){
            Comment jobComment = configurationDoc.createComment(lastComment);
            jobsElement.appendChild(jobComment);
          }
          jobsElement.appendChild(importedJob);
          lastComment="";
        }       
      }
      in.close();
      return configurationDoc;
    }catch (Exception e){
      throw new Exception("Error converting file "+cronFile.getAbsolutePath()+" to Job Scheduler XML: "+e,e);
    }
   
  } 
 
  private String incrementJobName(String jobName) {
    Matcher jobNameMatcher = jobNameRegExPattern.matcher(jobName);
    if (jobNameMatcher.matches()){
      String baseName = jobNameMatcher.group(1);
      String counter = jobNameMatcher.group(2);
      int iCounter = Integer.parseInt(counter);
      iCounter++;
      jobName = baseName + "_" + iCounter;
    }else{
      jobName = jobName+"_1";
    }
    return jobName;
  }
 
  public Document line2Job(String cronline) throws Exception{
    return line2Job(cronline, new HashMap());
  }

  public Document line2Job(String cronline, HashMap environmentVariables) throws Exception{
    try{
      logger.info("processing line: "+cronline);
      Document jobDoc = docBuilder.newDocument();
      Element jobElement = jobDoc.createElement("job");
      Matcher cronRegExAliasMatcher = cronRegExAliasPattern.matcher(cronline);
      if (cronRegExAliasMatcher.matches()){
        logger.debug3("Current line matches pattern "+cronRegExAlias);
        cronline = convertAlias(cronRegExAliasMatcher);
      }
      Matcher cronRegExMatcher = cronRegExPattern.matcher(cronline);
      int commandIndex = 6;
     
      if (isSystemCronTab()) {
        commandIndex = 7;
        cronRegExMatcher = cronRegExSystemPattern.matcher(cronline);
      }
      if (!cronRegExMatcher.matches()){
        throw new Exception("Faile to parse cron line \""+cronline+"\"");
      }
      String jobname = getJobName(cronRegExMatcher.group(commandIndex));
      jobElement.setAttribute("name", jobname);
      jobElement.setAttribute("title", "Cron Job "+cronRegExMatcher.group(commandIndex).trim());
      //jobElement.setAttribute("replace", "yes");
      if(timeout!=null && !timeout.equals("0")){
        jobElement.setAttribute("timeout", timeout);
      }
     
      String schedulerUser = "";
      String command = cronRegExMatcher.group(commandIndex);
      if (isSystemCronTab()){
        schedulerUser = cronRegExMatcher.group(6);
        command = (changeUserCommand+" "+command).trim();
      }
     
      /*logger.debug9("Creating params element");
      Element paramsElement = jobDoc.createElement("params");
      logger.debug9("Creating param element (command)");
      Element paramCommandElement = jobDoc.createElement("param");
      paramCommandElement.setAttribute("name", "command");
      paramCommandElement.setAttribute("value", command);
      paramsElement.appendChild(paramCommandElement);
      jobElement.appendChild(paramsElement);
      */
     
      logger.debug9("Creating script element");
      Element scriptElement = jobDoc.createElement("script");
      //scriptElement.setAttribute("language", "java");
      //scriptElement.setAttribute("java_class", "sos.scheduler.managed.JobSchedulerManagedExecutableJob");
      scriptElement.setAttribute("language", "shell");
      String script = "\n";
      if (schedulerUser.length()>0) script += "export SCHEDULER_CRONTAB_USER="+schedulerUser+"\n";
      Iterator envIter = environmentVariables.keySet().iterator();
      // set environment variables on job
      while(envIter.hasNext()){
        String envName = envIter.next().toString();
        String envValue = environmentVariables.get(envName).toString();
        script += "export "+envName+"="+envValue+"\n";
      }
      script+=command;
      Node scriptData = jobDoc.createCDATASection(script);
      scriptElement.appendChild(scriptData);
      jobElement.appendChild(scriptElement);
     
      Element runTimeElement = jobDoc.createElement("run_time");
      createRunTime(cronRegExMatcher, runTimeElement);
     
      if (usedNewRunTime && oldRunTime){
        // workaround while <month> Element is not available
        // can later be deleted (keep only else branch)
        usedNewRunTime = false;
        Document runTimeDocument = docBuilder.newDocument();
        runTimeDocument.appendChild(runTimeDocument.importNode(runTimeElement, true));
        StringWriter out = new StringWriter();
        OutputFormat format = new OutputFormat(runTimeDocument);   
        format.setIndenting(true);
        format.setIndent(2);
        format.setOmitXMLDeclaration(true);
            XMLSerializer serializer = new XMLSerializer(out, format);
            serializer.serialize(runTimeDocument);
            Comment runTimeComment = jobDoc.createComment("This run_time is currently not supported:\n"+out.toString());
            jobElement.appendChild(runTimeComment);
      } else{
        jobElement.appendChild(runTimeElement);
      }
      jobDoc.appendChild(jobElement);
      return jobDoc;
    } catch (Exception e){
      throw new Exception ("Error occured creating job from cron line: "+e);
    }
  }

  private void createRunTime(Matcher cronRegExMatcher, Element runTimeElement) throws Exception{
    try {
      String minutes = cronRegExMatcher.group(1);
      String hours = cronRegExMatcher.group(2);
      String days = cronRegExMatcher.group(3);
      String months = cronRegExMatcher.group(4);
      String weekdays = cronRegExMatcher.group(5);
     
      if (minutes.equals("@reboot")){
        runTimeElement.setAttribute("once", "yes");
        return;
      }
      Vector childElements = new Vector();
      Element periodElement = runTimeElement.getOwnerDocument().createElement("period");
     
      logger.debug6("processing hours ["+hours+"] and minutes ["+minutes+"]");
      if (minutes.startsWith("*")){
        if (minutes.equalsIgnoreCase("*")){
          // every minute
          periodElement.setAttribute("repeat", "60");
        }
        else{ // repeat interval is given
          String repeat = minutes.substring(2);
          repeat = formatTwoDigits(repeat);
          periodElement.setAttribute("repeat", "00:"+repeat);
        }       
        if (hours.startsWith("*")){
          if (!hours.equalsIgnoreCase("*")){
            // repeat interval is given for hours and minutes. Doesn't make sense.
            // e.g. */2 */3 every 3 hours repeat every 2 minutes
            throw new Exception("Combination of minutes and hours not supported: "+minutes+" "+hours);
          }
          // every hour: keep interval from minutes
          childElements.add(periodElement);
        } else{
          logger.debug9("Found specific hours, creating periods with begin and end.");
          String[] hourArray = hours.split(",");
          for (int i = 0; i < hourArray.length; i++) {
            String currentHour = hourArray[i];
            if (currentHour.indexOf("/")!=-1){
              String[] additionalHours = getArrayFromColumn(currentHour);
              hourArray = combineArrays(hourArray, additionalHours);
              continue;
            }
            String[] currentHourArray = currentHour.split("-");
            Element currentPeriodElement = (Element) periodElement.cloneNode(true);
            String beginHour = currentHourArray[0];
           
            int iEndHour = (Integer.parseInt(beginHour)+1) % 24;
            // workaround, bis endhour am n�chsten Tag erlaubt
            if (iEndHour==0) iEndHour=24;
            String endHour = ""+iEndHour;
            if (currentHourArray.length>1) endHour= currentHourArray[1];
            beginHour = formatTwoDigits(beginHour);
            endHour = formatTwoDigits(endHour);
            currentPeriodElement.setAttribute("begin", beginHour+":00");
            currentPeriodElement.setAttribute("end", endHour+":00");
            childElements.add(currentPeriodElement);
          }
        }
      } // end if  minutes.startsWith("*")
      else{ // one or more minutes are fixed       
        String[] minutesArray = getArrayFromColumn(minutes);
        for (int i = 0; i < minutesArray.length; i++) {
          Element currentPeriodElement = (Element) periodElement.cloneNode(true);
          String currentMinute = minutesArray[i];
                   
          currentMinute=formatTwoDigits(currentMinute);
          if (hours.startsWith("*")){
            currentPeriodElement.setAttribute("absolute_repeat", "01:00");
            usedNewRunTime = true;
            if (!hours.equalsIgnoreCase("*")){// repeat interval is given for hours
              String repeat = hours.substring(2);
              repeat=formatTwoDigits(repeat);             
              currentPeriodElement.setAttribute("absolute_repeat", repeat+":00");
            }
            currentPeriodElement.setAttribute("begin", "00:"+currentMinute);
            childElements.add(currentPeriodElement)
          } else{ //fixed hour(s) is set
            String[] hourArray = hours.split(",");
            for (int j = 0; j < hourArray.length; j++) {
              currentPeriodElement = (Element) periodElement.cloneNode(true);
              String currentHour = hourArray[j];
              if (currentHour.indexOf("-")==-1){
                // fixed hour and fixed minute --> create single_start               
                currentHour = formatTwoDigits(currentHour);
                currentPeriodElement.setAttribute("single_start", currentHour+":"+currentMinute);
              }else{
                // range of hours is set, create begin and end attributes               
                String[] currentHourArray = currentHour.split("[-/]");               
                int beginHour = Integer.parseInt(currentHourArray[0]);
                int endHour = Integer.parseInt(currentHourArray[1]);
                int beginMinute = Integer.parseInt(currentMinute);
                int endMinute = beginMinute+1;
                // workaround, bis endhour am n�chsten Tag erlaubt
                endMinute = beginMinute;
                if (endMinute==60){
                  endMinute = 0;
                  endHour = (endHour+1);
                }
                endHour = endHour%24;
                // workaround, bis endhour am n�chsten Tag erlaubt
                if (endHour==0) endHour=24;
                String stepSize = "1";
                if (currentHourArray.length==3){
                  stepSize=formatTwoDigits(currentHourArray[2]);
                }
                currentPeriodElement.setAttribute("absolute_repeat", stepSize+":00");
                usedNewRunTime = true;
                currentPeriodElement.setAttribute("begin", formatTwoDigits(beginHour)+":"+formatTwoDigits(beginMinute));
                currentPeriodElement.setAttribute("end", formatTwoDigits(endHour)+":"+formatTwoDigits(endMinute));
              }
              childElements.add(currentPeriodElement);
            }
          }         
        }
       
      }
     
      logger.debug6("processing days ["+days+"]");
      boolean monthDaysSet = false;
      if (days.startsWith("*")){
        if (days.equals("*")){
          // every day - do nothing, just keep periods
        }else{
          // repeat interval is given for days
          // this is not possible in the Job Scheduler but can be poorly emulated
          Element monthDaysElement = runTimeElement.getOwnerDocument().createElement("monthdays");
          String repeat = days.substring(2);
          int iRepeat = Integer.parseInt(repeat);
          // use only 30 days
          for(int i=1; i<=30; i=i+iRepeat){
            String day = ""+i;
            addDay(day,monthDaysElement,childElements);
          }
          childElements.clear();
          childElements.add(monthDaysElement);
          monthDaysSet = true;
        }
      } else {
        Element monthDaysElement = runTimeElement.getOwnerDocument().createElement("monthdays");       
        String [] daysArray = getArrayFromColumn(days);       
        for (int i = 0; i < daysArray.length; i++) {
          String day = daysArray[i];
          addDay(day,monthDaysElement,childElements);         
        }
        childElements.clear();
        childElements.add(monthDaysElement);
        monthDaysSet = true;
      }
     
      if (!weekdays.equals("*") && monthDaysSet){
        logger.info("Weekdays will not be processed as days are already set in current line.");
      }else{
        logger.debug6("processing weekdays ["+weekdays+"]");
        weekdays = replaceDayNames(weekdays);
        if(weekdays.startsWith("*/")) throw new Exception("Repeat intervals for the weekdays column ["+weekdays+"] are not supported. Please use the days column.");
        if(weekdays.equals("*")){
          // all weekdays, do nothing
        }else{
          Element weekDaysElement = runTimeElement.getOwnerDocument().createElement("weekdays");       
          String [] daysArray = getArrayFromColumn(weekdays);       
          for (int i = 0; i < daysArray.length; i++) {
            String day = daysArray[i];
            addDay(day,weekDaysElement,childElements);         
          }
          childElements.clear();
          childElements.add(weekDaysElement);
        }
      }
     
      logger.debug6("processing months ["+months+"]");
      if (months.startsWith("*")){
        if (months.equals("*")){
          // every month - do nothing
        }else{
          months = replaceMonthNames(months);
          // repeat interval is given for months
          // this is not possible in the Job Scheduler but can be poorly emulated
          Vector newChildElements = new Vector();
          String repeat = months.substring(2);
          int iRepeat = Integer.parseInt(repeat);
       
          for(int i=1; i<=12; i=i+iRepeat){
            String month = ""+i;
            Element monthElement = runTimeElement.getOwnerDocument().createElement("month");
            usedNewRunTime = true;
            monthElement.setAttribute("month", month);
            Iterator iter = childElements.iterator();
            while (iter.hasNext()){
              Element child = (Element) iter.next();
              monthElement.appendChild(child.cloneNode(true));
            }
            newChildElements.add(monthElement);
          }
          childElements = newChildElements;
        }
      }else{// list of months is given
        Vector newChildElements = new Vector();
        String[] monthArray = getArrayFromColumn(months);
        for (int i = 0; i < monthArray.length; i++) {
          String month = monthArray[i];
          Element monthElement = runTimeElement.getOwnerDocument().createElement("month");
          usedNewRunTime = true;
          monthElement.setAttribute("month", month);
          Iterator iter = childElements.iterator();
          while (iter.hasNext()){
            Element child = (Element) iter.next();
            monthElement.appendChild(child.cloneNode(true));
          }
          newChildElements.add(monthElement);
        }
        childElements = newChildElements;
      }
     
      // add topmost child elements to run_time element
      Iterator iter = childElements.iterator();
      while (iter.hasNext()){
        Element someElement = (Element) iter.next();
        runTimeElement.appendChild(someElement);
      }     
    } catch (Exception e) {
      throw new Exception("Error creating run time: "+e,e);
    }
   
  }

  private static String[] combineArrays(String[] hourArray, String[] additionalHours) {
    String[] newArray = new String[hourArray.length+additionalHours.length];
    for (int i = 0; i < hourArray.length; i++) {
      newArray[i]=hourArray[i];
    }
    for (int i = 0; i < additionalHours.length; i++) {
      newArray[i+hourArray.length] = additionalHours[i];
    }
    return newArray;
  }

  private void addDay(String day, Element parentDaysElement, Vector childElements) throws Exception{   
    logger.debug9("adding day: "+day);
    Element dayElement = parentDaysElement.getOwnerDocument().createElement("day");
    dayElement.setAttribute("day", day);
    Iterator iter = childElements.iterator();
    while (iter.hasNext()){
      Element child = (Element) iter.next();
      dayElement.appendChild(child.cloneNode(true));
    }         
    parentDaysElement.appendChild(dayElement);
  }
 

  private String[] getArrayFromColumn(String column) {
    String[] elements = column.split(",");
    Vector result = new Vector();
    for (int i = 0; i < elements.length; i++) {
      String element = elements[i];     
      if (element.indexOf("-")==-1){
        result.add(element);
      } else{
        String[] range = element.split("[-/]");
        if(range.length<2 || range.length>3){
          try{
            logger.warn("unknown crontab synthax: "+element);
          } catch (Exception e){}
        } else{
          int from = Integer.parseInt(range[0]);
          int to = Integer.parseInt(range[1]);
          int stepSize = 1;
          // if e.g. 8-20/2
          if (range.length==3) stepSize=Integer.parseInt(range[2]);
          for (int j=from;j<=to;j=j+stepSize) result.add(""+j);
        }
      }
    }
    String[] dummy=new String[1];
    return (String[]) result.toArray(dummy);
  }

  private static String replaceDayNames(String element) {
    element = element.replaceAll("(?i)mon", "1");
    element = element.replaceAll("(?i)tue", "2");
    element = element.replaceAll("(?i)wed", "3");
    element = element.replaceAll("(?i)thu", "4");
    element = element.replaceAll("(?i)fri", "5");
    element = element.replaceAll("(?i)sat", "6");
    element = element.replaceAll("(?i)sun", "7");
    return element;
  }
 
  private static String replaceMonthNames(String element) {
    element = element.replaceAll("(?i)jan", "1");
    element = element.replaceAll("(?i)feb", "2");
    element = element.replaceAll("(?i)mar", "3");
    element = element.replaceAll("(?i)apr", "4");
    element = element.replaceAll("(?i)may", "5");
    element = element.replaceAll("(?i)jun", "6");
    element = element.replaceAll("(?i)jul", "7");
    element = element.replaceAll("(?i)aug", "8");
    element = element.replaceAll("(?i)sep", "9");
    element = element.replaceAll("(?i)oct", "10");
    element = element.replaceAll("(?i)nov", "11");
    element = element.replaceAll("(?i)dec", "12");   
    return element;
  }

  private String getJobName(String command) {
    Matcher commandMatcher = commandRegExPattern.matcher(command);
    if (commandMatcher.find()){
      command = commandMatcher.group();
    } else {
      int space = command.indexOf(" ");
      if (space!=-1){
        command = command.substring(0, space);
      }
    }
    if (command.startsWith("/")) command=command.substring(1);
    command = command.replaceAll("/", "_");
    return command;
  }

  private String convertAlias(Matcher matcher) throws Exception {
    logger.debug5("Converting alias...");
    try{
      String alias = matcher.group(1);
      String rest = matcher.group(2);
      String result = "";
      if (alias.equals("@yearly") || alias.equals("@annually"))  result = "0 0 1 1 * ";
      if (alias.equals("@monthly")) result = "0 0 1 * * ";
      if (alias.equals("@weekly"))  result = "0 0 * * 0 ";
      if (alias.equals("@daily") || alias.equals("@midnight"))   result = "0 0 * * * ";
      if (alias.equals("@hourly"))  result = "0 * * * * ";
      if (alias.equals("@reboot"))  result = "@reboot @reboot @reboot @reboot @reboot";
      result += rest;
      logger.debug5("Alias converted to "+result);
      return result;
    } catch(Exception e){
      throw new Exception ("Error converting alias: "+e);
    }
  }

  private static String formatTwoDigits(String number){
    if (number.length()==1) return "0"+number;
    return number;
  }
 
  private static String formatTwoDigits(int number){   
    return formatTwoDigits(""+number);
  }

  /**
   * This function does not anylyse the crontab, it only
   * returns what type of crontab the converter is configured
   * to parse
   * @return the  value for systemCronTab
   */
  public boolean isSystemCronTab() {
    return systemCronTab;
  }

  /**
   * Sets if the current crontab is a system crontab
   * which has one more column (user)
   * @param systemCronTab true=current crontab is a system crontab
   */
  public void setSystemCronTab(boolean systemCronTab) {
    if (systemCronTab) {
      currentCronPattern = cronRegExSystemPattern;
    } else currentCronPattern = cronRegExPattern;
    this.systemCronTab = systemCronTab;
  }

  /**
   * @return the oldRunTime
   */
  protected boolean isOldRunTime() {
    return oldRunTime;
  }

  /**
   * @param oldRunTime the oldRunTime to set
   */
  protected void setOldRunTime(boolean oldRunTime) {
    this.oldRunTime = oldRunTime;
  }

  /**
   * @return the skipLines
   */
  public HashSet getSkipLines() {
    return skipLines;
  }

  /**
   * The cron lines contained in this set will be skipped when
   * converting a cron file
   * @param skipLines
   */
  public void setSkipLines(HashSet skipLines) {
    this.skipLines = skipLines;
  }

  /**
   * @return the reservedJobNames
   */
  public HashSet getReservedJobNames() {
    return reservedJobNames;
  }

  /**
   * Sets reserved job names. Reserved job names will not be used as job names.
   * @param reservedJobNames HashSet of reserved job names
   */
  public void setReservedJobNames(HashSet reservedJobNames) {
    this.reservedJobNames = reservedJobNames;
  }

  /**
   * @return the docBuilder
   */
  protected DocumentBuilder getDocBuilder() {
    return docBuilder;
  }


  /**
   * @return the changeUserCommand
   */
  public String getChangeUserCommand() {
    return changeUserCommand;
  }


  /**
   * @param changeUserCommand the changeUserCommand to set
   */
  public void setChangeUserCommand(String changeUserCommand) {
    if (changeUserCommand.equalsIgnoreCase("su")) changeUserCommand = "su $SCHEDULER_CRONTAB_USER -c";
    if (changeUserCommand.equalsIgnoreCase("sudo")) changeUserCommand = "sudo -u $SCHEDULER_CRONTAB_USER";
    this.changeUserCommand = changeUserCommand;
  }


  /**
   * @return the timeout
   */
  public String getTimeout() {
    return timeout;
  }


  /**
   * @param timeout the timeout to set
   */
  public void setTimeout(String timeout) {
    this.timeout = timeout;
  }
}
TOP

Related Classes of sos.scheduler.cron.CronConverter

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.