2010-03-02 6 views
23

Sto scrivendo un'applicazione di pianificazione in Java utilizzando Quartz. Sto usando CronTrigger, ma le mie espressioni cron sono inserite in un database prima che siano pianificate e basate sull'input dell'utente.Verificare che un'espressione cron sia valida in Java

C'è un modo per verificare che le espressioni cron siano valide quando le acquisisco? Preferirei fare questo e dare all'utente un messaggio di errore appropriato di aspettare fino a quando non viene eseguito lo scheduler e ottengo un ParseException quando provo a creare il trigger. Quali potrebbero essere giorni dopo che l'utente ha inserito i dati.

risposta

35

Non è possibile semplicemente creare un trigger senza eseguirlo effettivamente? Potresti semplicemente dare un feedback appropriato in caso di ParseException. Se l'espressione è corretta, continua l'espressione su DB.

Edit: o semplicemente fare questo:

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

Nota che la validità, come verificato con questo metodo non * garanzia * che un'espressione funzionerà. Per esempio. 'isValidExpression (" 0 0 12 1/2 * MON-FRI * ")' restituisce true, ma in fase di esecuzione genera 'UnsupportedOperationException: il supporto per specificare sia un parametro giorno-della-settimana che un giorno-del-mese non è implementato .' – Jonik

+0

In effetti, è meglio anche iniziare un'espressione e lasciare che il costruttore chiami il buildExpression così sei sicuro che questa è un'espressione valida per Quartz –

+0

@AhmedHashem Il metodo 'isValidExpression' inizia già internamente a' CronExpression' e cattura qualsiasi 'ParseException'. Quindi non dovrebbe essere diverso. – destan

12

Ho modificato il seguente code aggiunto da @ ph4r05 per generare una regex pure; ecco 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}))?)*))$ 

Ecco il codice 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; 
} 

sono affatto un esperto di espressione regolare, ma almeno questo sembra funzionare su tutti gli esempi forniti dal quarzo documentation

+0

Molto bello! Questo è valido ma sfortunatamente non funziona: "0 8 9? 1/1 MON # 3 *". Suppongo che avrò bisogno di rispolverare il mio regex-fu per sistemare questa cosa ... – vincentjames501

-1

Ho trovato la seguente espressione regolare nel progetto "QuartzNet" su Github. Penso che possa essere ciò che Quartz usa per convalidare le espressioni di cron.

Link: 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

Si potrebbe utilizzare cron-utils Non solo controllerà il cron è valida, ma si potrebbe convertire da diversi formati cron al bersaglio uno (es .: se l'utente immette un'Unix espressione cron, potresti facilmente convertire in Quartz e persistere da uno a DB). Di seguito forniamo alcuni frammenti:

// 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()