La vérification d’une expression cron est valide en Java

J’écris une application de planification en Java avec Quartz. J’utilise CronTrigger, mais mes expressions cron sont entrées dans une firebase database avant leur planification et sont basées sur les entrées de l’utilisateur.

Existe-t-il un moyen de vérifier que les expressions cron sont valides lorsque je les capture? Je préfère le faire 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 pourrait être des jours après que l’utilisateur entre les données.

    Ne pouvez-vous pas simplement créer un déclencheur sans l’exécuter réellement? Vous pouvez simplement donner un retour d’information approprié dans le cas d’une exception ParseException. Si l’expression est correcte, persistez l’expression dans la firebase database.

    Edit: ou simplement faire ceci:

    org.quartz.CronExpression.isValidExpression(expression); 

    J’ai modifié le code suivant ajouté par @ ph4r05 pour générer également une regex; 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 Ssortingng cronRegex = null; public static Ssortingng getCronRegex() { if (cronRegex == null) { // numbers intervals and regex Map numbers = new HashMap(); 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 field_re = new HashMap(); // expand regex to contain different time specifiers for (Ssortingng field : numbers.keySet()) { Ssortingng number = numbers.get(field); Ssortingng range = "(?:" + number + ")(?:(?:-|\\/|\\," + ("dow".equals(field)? "|#" : "") + ")(?:" + number + "))?" + ("dow".equals(field)? "(?:L)?" : ("month".equals(field)? "(?:L|W)?" : "")); field_re.put(field, "\\?|\\*|" + range + "(?:," + range + ")*"); } // add ssortingng specifiers Ssortingng monthRE = field_re.get("month"); Ssortingng monthREVal = "JAN|FEB|MAR|APR|MAY|JUN|JUL|AUG|SEP|OCT|NOV|DEC"; Ssortingng monthRERange = "(?:" + monthREVal + ")(?:(?:-)(?:" + monthREVal + "))?" ; monthRE = monthRE + "|\\?|\\*|" + monthRERange + "(?:," + monthRERange + ")*" ; field_re.put("month", monthRE); Ssortingng dowRE = field_re.get("dow"); Ssortingng dowREVal = "MON|TUE|WED|THU|FRI|SAT|SUN"; Ssortingng dowRERange = "(?:" + dowREVal + ")(?:(?:-)(?:" + dowREVal + "))?" ; dowRE = dowRE + "|\\?|\\*|" + dowRERange + "(?:," + dowRERange + ")*" ; field_re.put("dow", dowRE); SsortingngBuilder fieldsReSB = new SsortingngBuilder(); 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.toSsortingng(); } return cronRegex; } 

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

    Vous pouvez utiliser cron-utils Non seulement vérifiera si le cron est valide, mais vous pourrez convertir différents formats de cron en formats cibles (par exemple, si l’utilisateur saisit une expression Unix cron, vous pourrez facilement convertir en Quartz et conserver celle-ci). à DB). Ci-dessous, nous fournissons des extraits:

     // Turn cron expressions into another format by using CronMapper: CronMapper cronMapper = CronMapper.fromUnixToQuartz(); Cron quartzCron = cronMapper.map(unixCron); // and to get a Ssortingng representation of it, we can use quartzCron.asSsortingng(); //validate the cron expression! quartzCron.validate() 

    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])))?)?)