2010-03-02 15 views
23

Estoy escribiendo una aplicación de programación en Java usando Quartz. Estoy usando CronTrigger, pero mis expresiones cron se ingresan en una base de datos antes de que se programen y se basan en las entradas del usuario.Verificación de una expresión cron válida en Java

¿Hay alguna manera de verificar que las expresiones cron son válidas cuando las capturo? Prefiero hacer esto y darle al usuario un mensaje de error apropiado que esperar hasta que se ejecute el planificador y obtengo una ParseException cuando intento crear el desencadenador. Lo cual podría ser días después de que el usuario ingrese los datos.

Respuesta

35

¿No puede simplemente crear un disparador sin ejecutarlo realmente? Simplemente podría dar su opinión adecuada en el caso de una ParseException. Si la expresión es correcta, persista la expresión a DB.

Editar: o simplemente hacer esto:

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

Tenga en cuenta que la validez como comprobó mediante este método no garantiza * * que una expresión funcionará. P.ej. 'isValidExpression (" 0 0 12 1/2 * MON-FRI * ")' devuelve verdadero, pero en el tiempo de ejecución arroja 'UnsupportedOperationException: Soporte para especificar un día de la semana Y un parámetro de día del mes no está implementado .' – Jonik

+0

De hecho, es mejor también iniciar una expresión y dejar que el constructor llame a buildExpression para que esté seguro de que esta es una expresión válida para Quartz –

+0

El método @AhmedHashem 'isValidExpression' ya inicia internamente un' CronExpression' y atrapa cualquier 'ParseException'. Entonces no debería ser diferente. – destan

12

He modificado el siguiente code añadido por @ ph4r05 para generar una expresión regular también; aquí está la expresión regular:

^\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}))?)*))$ 

Aquí está el código de 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; 
} 

Estoy de ninguna manera un experto en expresiones regulares, pero al menos esto parece funcionar en todos los ejemplos dados por el cuarzo documentation

+0

¡Muy bonito! Este es válido pero desafortunadamente no funciona: "0 8 9? 1/1 MON # 3 *". Supongo que tendré que repasar mi regex-fu para arreglar esto ... – vincentjames501

-1

Encontré la siguiente expresión regular en el proyecto "QuartzNet" en Github. Creo que puede ser lo que Quartz usa para validar expresiones cron.

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

Usted podría utilizar cron-utils No sólo se compruebe la cron es válida, pero se puede convertir de diferentes formatos de cron a la de destino (ej .: si el usuario introduce una Unix expresión cron, puede convertir fácilmente a Quartz y persistir en DB. A continuación se proporciona un fragmento:

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