2010-03-02 19 views
23

J'écris une application de planification en Java en utilisant Quartz. J'utilise le CronTrigger, mais mes expressions cron sont entrées dans une base de données avant d'être planifiées et sont basées sur les entrées de l'utilisateur.La vérification d'une expression cron est valide en Java

Y at-il un moyen de vérifier que les expressions cron sont valides lorsque je les capture? Je préfère faire cela et donner à l'utilisateur un message d'erreur approprié plutôt que d'attendre que le planificateur soit exécuté et que j'obtienne une exception ParseException lorsque j'essaie de créer le déclencheur. Ce qui peut être quelques jours après que l'utilisateur a entré les données. Vous ne pouvez pas simplement créer un déclencheur sans l'exécuter réellement?

Répondre

35

Vous pouvez simplement donner des informations appropriées en cas d'exception ParseException. Si l'expression est correcte, laissez l'expression à DB.

Edit: ou tout simplement faire:

org.quartz.CronExpression.isValidExpression(expression); 
+8

Notez que la validité vérifiée par cette méthode ne * garantie * que l'expression fonctionnera. Par exemple. 'isValidExpression (" 0 0 12 1/2 * MON-FRI * ")' renvoie true, mais à l'exécution, il lève 'UnsupportedOperationException: la prise en charge de la spécification d'un paramètre day-of-week ET day-of-month n'est pas implémentée .' – Jonik

+0

En effet, il est donc préférable d'initier une expression, et de laisser le constructeur appeler l'expression buildExpression donc vous êtes sûr que c'est une expression valide pour Quartz –

+0

@AhmedHashem 'isValidExpression' méthode déjà initie en interne une' CronExpression' et attrape tout 'ParseException'. Donc, ça ne devrait pas être différent. – destan

12

J'ai modifié le code ajouté par @ ph4r05 suivante pour générer une expression régulière ainsi; voici la regex:

^\s*($|#|\w+\s*=|(\?|\*|(?:[0-5]?\d)(?:(?:-|\/|\,)(?:[0-5]?\d))?(?:,(?:[0-5]?\d)(?:(?:-|\/|\,)(?:[0-5]?\d))?)*)\s+(\?|\*|(?:[0-5]?\d)(?:(?:-|\/|\,)(?:[0-5]?\d))?(?:,(?:[0-5]?\d)(?:(?:-|\/|\,)(?:[0-5]?\d))?)*)\s+(\?|\*|(?:[01]?\d|2[0-3])(?:(?:-|\/|\,)(?:[01]?\d|2[0-3]))?(?:,(?:[01]?\d|2[0-3])(?:(?:-|\/|\,)(?:[01]?\d|2[0-3]))?)*)\s+(\?|\*|(?:0?[1-9]|[12]\d|3[01])(?:(?:-|\/|\,)(?:0?[1-9]|[12]\d|3[01]))?(?:,(?:0?[1-9]|[12]\d|3[01])(?:(?:-|\/|\,)(?:0?[1-9]|[12]\d|3[01]))?)*)\s+(\?|\*|(?:[1-9]|1[012])(?:(?:-|\/|\,)(?:[1-9]|1[012]))?(?:L|W)?(?:,(?:[1-9]|1[012])(?:(?:-|\/|\,)(?:[1-9]|1[012]))?(?:L|W)?)*|\?|\*|(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?(?:,(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(?:(?:-)(?:JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)*)\s+(\?|\*|(?:[0-6])(?:(?:-|\/|\,|#)(?:[0-6]))?(?:L)?(?:,(?:[0-6])(?:(?:-|\/|\,|#)(?:[0-6]))?(?:L)?)*|\?|\*|(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?(?:,(?:MON|TUE|WED|THU|FRI|SAT|SUN)(?:(?:-)(?:MON|TUE|WED|THU|FRI|SAT|SUN))?)*)(|\s)+(\?|\*|(?:|\d{4})(?:(?:-|\/|\,)(?:|\d{4}))?(?:,(?:|\d{4})(?:(?:-|\/|\,)(?:|\d{4}))?)*))$ 

Voici le code java:

private static String cronRegex = null; 

public static String getCronRegex() 
{ 
    if (cronRegex == null) 
    { 
    // numbers intervals and regex 
    Map<String, String> numbers = new HashMap<String, String>(); 
    numbers.put("sec", "[0-5]?\\d"); 
    numbers.put("min", "[0-5]?\\d"); 
    numbers.put("hour", "[01]?\\d|2[0-3]"); 
    numbers.put("day", "0?[1-9]|[12]\\d|3[01]"); 
    numbers.put("month", "[1-9]|1[012]"); 
    numbers.put("dow", "[0-6]"); 
    numbers.put("year", "|\\d{4}"); 

    Map<String, String> field_re = new HashMap<String, String>(); 

    // expand regex to contain different time specifiers 
    for (String field : numbers.keySet()) 
    { 
     String number = numbers.get(field); 
     String range = "(?:" + number + ")(?:(?:-|\\/|\\," + ("dow".equals(field)? "|#" : "") + 

     ")(?:" + number + "))?" + ("dow".equals(field)? "(?:L)?" : ("month".equals(field)? "(?:L|W)?" : "")); 
     field_re.put(field, "\\?|\\*|" + range + "(?:," + range + ")*"); 
    } 

    // add string specifiers 
    String monthRE = field_re.get("month"); 
    String monthREVal = "JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC"; 
    String monthRERange = "(?:" + monthREVal + ")(?:(?:-)(?:" + monthREVal + "))?" ; 
    monthRE = monthRE + "|\\?|\\*|" + monthRERange + "(?:," + monthRERange + ")*" ; 
    field_re.put("month", monthRE); 

    String dowRE = field_re.get("dow"); 
    String dowREVal = "MON|TUE|WED|THU|FRI|SAT|SUN"; 
    String dowRERange = "(?:" + dowREVal + ")(?:(?:-)(?:" + dowREVal + "))?" ; 

    dowRE = dowRE + "|\\?|\\*|" + dowRERange + "(?:," + dowRERange + ")*" ; 
    field_re.put("dow", dowRE); 

    StringBuilder fieldsReSB = new StringBuilder(); 
    fieldsReSB.append("^\\s*(").append("$") // 
     .append("|#") // 
     .append("|\\w+\\s*=") // 
     .append("|") // 
     .append("(")// 
     .append(field_re.get("sec")).append(")\\s+(")// 
     .append(field_re.get("min")).append(")\\s+(")// 
     .append(field_re.get("hour")).append(")\\s+(")// 
     .append(field_re.get("day")).append(")\\s+(")// 
     .append(field_re.get("month")).append(")\\s+(")// 
     .append(field_re.get("dow")).append(")(|\\s)+(")// 
     .append(field_re.get("year"))// 
     .append(")")// 
     .append(")")// 
     .append("$"); 

    cronRegex = fieldsReSB.toString(); 
    } 
    return cronRegex; 
} 

Je suis en aucun cas un expert regex, mais au moins cela semble fonctionner sur tous les exemples donnés par le quartz documentation

+0

Très bien! Celui-ci est valide mais malheureusement ne fonctionne pas: "0 8 9? 1/1 MON # 3 *". Je suppose que je vais devoir rafraîchir mon regex-fu pour réparer ça ... – vincentjames501

-1

J'ai trouvé l'expression régulière suivante dans le projet "QuartzNet" sur Github. Je pense que c'est peut-être ce que Quartz utilise pour valider les expressions cron.

Lien: https://github.com/quartznet/quartznet/blob/master/src/Quartz/Xml/job_scheduling_data_2_0.xsd

(((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\?])|([\*]))[\s](((([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?,)*([0-9]|[0-5][0-9])(-([0-9]|[0-5][0-9]))?)|(([\*]|[0-9]|[0-5][0-9])/([0-9]|[0-5][0-9]))|([\?])|([\*]))[\s](((([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?,)*([0-9]|[0-1][0-9]|[2][0-3])(-([0-9]|[0-1][0-9]|[2][0-3]))?)|(([\*]|[0-9]|[0-1][0-9]|[2][0-3])/([0-9]|[0-1][0-9]|[2][0-3]))|([\?])|([\*]))[\s](((([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?,)*([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(-([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1]))?(C)?)|(([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])/([1-9]|[0][1-9]|[1-2][0-9]|[3][0-1])(C)?)|(L(-[0-9])?)|(L(-[1-2][0-9])?)|(L(-[3][0-1])?)|(LW)|([1-9]W)|([1-3][0-9]W)|([\?])|([\*]))[\s](((([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?,)*([1-9]|0[1-9]|1[0-2])(-([1-9]|0[1-9]|1[0-2]))?)|(([1-9]|0[1-9]|1[0-2])/([1-9]|0[1-9]|1[0-2]))|(((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?,)*(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)(-(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))?)|((JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC)/(JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC))|([\?])|([\*]))[\s]((([1-7](-([1-7]))?,)*([1-7])(-([1-7]))?)|([1-7]/([1-7]))|(((MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?,)*(MON|TUE|WED|THU|FRI|SAT|SUN)(-(MON|TUE|WED|THU|FRI|SAT|SUN))?(C)?)|((MON|TUE|WED|THU|FRI|SAT|SUN)/(MON|TUE|WED|THU|FRI|SAT|SUN)(C)?)|(([1-7]|(MON|TUE|WED|THU|FRI|SAT|SUN))?(L|LW)?)|(([1-7]|MON|TUE|WED|THU|FRI|SAT|SUN)#([1-7])?)|([\?])|([\*]))([\s]?(([\*])?|(19[7-9][0-9])|(20[0-9][0-9]))?| (((19[7-9][0-9])|(20[0-9][0-9]))/((19[7-9][0-9])|(20[0-9][0-9])))?| ((((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?,)*((19[7-9][0-9])|(20[0-9][0-9]))(-((19[7-9][0-9])|(20[0-9][0-9])))?)?) 
1

Vous pouvez utiliser cron-utils Non seulement vérifiera la Cron est valide, mais vous pouvez convertir différents formats de Cron à la cible un (ex .: si l'utilisateur entre un Unix expression cron, vous pouvez facilement convertir en Quartz et persister celui-là en DB). Ci-dessous nous fournissons quelques extraits:

// Turn cron expressions into another format by using CronMapper: 
CronMapper cronMapper = CronMapper.fromUnixToQuartz(); 

Cron quartzCron = cronMapper.map(unixCron); 
// and to get a String representation of it, we can use 
quartzCron.asString(); 

//validate the cron expression! 
quartzCron.validate()