Skip to Main Content

Java Programming

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Quartz Cron validator: Help improve

r035198xMar 18 2010 — edited Mar 18 2010
Greetings,

I've had to implement a quartz cron validator : format.

I decided to split the parts and validate each one separately. My tests seem to confirm that the results are accepatable but I feel that the approach may not be optimal. My regex is not all that good either.

I need help in improving any aspects of this code.
Critiques are also welcome and you don't have to hold back.
package cib.ibot.core.util;

import java.util.regex.Pattern;

public class CronValidate {
	enum Day {
		MON, TUE, WED, THU, FRI, SAT, SUN
	}
	enum Month {
		JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
	}
	public static boolean validQuartzCron(String cronExpression) {
		if (cronExpression == null || cronExpression.trim().equals("")) {
			return false;
		}
		String[] parts = cronExpression.split(" ");
		if (parts.length != 6 && parts.length != 7) {
			return false;
		}
		// seconds
		if (!CronValidate.validateField(parts[0], CronValidate.zero59(), false)) {
			return false;
		}
		// minutes
		if (!CronValidate.validateField(parts[1], CronValidate.zero59(), false)) {
			return false;
		}
		// hours
		if (!CronValidate.validateField(parts[2], CronValidate.zero23(), false)) {
			return false;
		}
		// Day of Month
		if ((parts[3].contains("L") || parts[3].contains("W"))) {
			return CronValidate.validateLWMonth(parts[3]);
		}
		else if (!CronValidate.validateField(parts[3], CronValidate.one31(), true)) {
			return false;
		}
		
		// Month
		if (!CronValidate.validateField(CronValidate.convertToAllNumbers(parts[4]), CronValidate.one12(), false)) {
			return false;
		}
		// Day of Week
		if ((parts[5].contains("L") || parts[5].contains("#"))) {
			return CronValidate.validateLHashDayOfWeek(parts[5]);

		}
		else if (!CronValidate.validateField(CronValidate.convertToAllNumbers(parts[5]), CronValidate.one7(), false)) {
			return false;
		}
		
		// year
		if (parts.length == 7 && !CronValidate.validYear(parts[6])) {
			return false;
		}
		// if you got this far you are ok.
		return true;
	}

	public static boolean validateField(String cronExpression, String basicFieldRegex, boolean allowQMark) {
		if (cronExpression.toString().equals("")) {
			return false;
		}
		if (cronExpression.equals("*")) {
			return true;
		}
		if (allowQMark && cronExpression.equals("?")) {
			return true;
		}
		if (CronValidate.validateRegex(basicFieldRegex, cronExpression)) {
			return true;
		}
		if (!cronExpression.contains(",") && !cronExpression.contains("/") && !cronExpression.contains("-")) {
			return CronValidate.validateRegex(basicFieldRegex, cronExpression);
		}
		if (cronExpression.contains(",")) {
			String[] parts = cronExpression.split(",");
			for (String part : parts) {
				if (part.contains("-")) {
					String[] pieces = part.split("\\-");
					for (String piece : pieces) {
						if (!CronValidate.validateRegex(basicFieldRegex, piece)) {
							return false;
						}
					}

				} else if (part.contains("/")) {
					String[] pieces = part.split("/");
					if (pieces.length != 2) {
						return false;
					}
					if (!CronValidate.validateRegex(basicFieldRegex, pieces[0]) || !CronValidate.validateRegex(basicFieldRegex, pieces[1])) {
						return false;
					}
				}

				else if (!CronValidate.validateRegex(basicFieldRegex, part)) {
					return false;

				}
			}
			return true;
		}
		if (cronExpression.contains("/")) {
			String[] parts = cronExpression.split("/");
			if (parts.length != 2) {
				return false;
			}
			if (!CronValidate.validateRegex(basicFieldRegex, parts[0]) || !CronValidate.validateRegex(basicFieldRegex, parts[1])) {
				return false;
			}
		}
		if (cronExpression.contains("-")) {
			String[] pieces = cronExpression.split("\\-");
			for (String piece : pieces) {
				if (!CronValidate.validateRegex(basicFieldRegex, piece)) {
					return false;
				}
			}
		}

		return true;

	}
	
	// exceptionals
	private static boolean validateLHashDayOfWeek(String dayOfWeekCron) {
		if (dayOfWeekCron.equals("L") || dayOfWeekCron.matches("^([1-7])L$") || dayOfWeekCron.matches("^([1-7]#[1-7])$")) {
			return true;
		}
		return false;
	}

	private static boolean validateLWMonth(String dayOfMonthCron) {
		if (dayOfMonthCron.equals("L") || dayOfMonthCron.equals("LW") || dayOfMonthCron.equals("W") || dayOfMonthCron.matches("^([1-9]|1[0-9]|2[0-9]|3[0-1])W$")) {
			return true;
		}
		return false;
	}
	private static boolean validYear(String yearCron) {
		if (yearCron.equals("*")) {
			return true;
		}
		if (yearCron.matches(CronValidate.yearRange())) {
			return true;
		}
		if (yearCron.matches(CronValidate.year())) {
			return true;
		}
		if(yearCron.contains(",")) {
			String[] parts = yearCron.split(",");
			// each part must be a year range or a simple year
			for(String part : parts) {
				if (part.matches(CronValidate.yearRange()) || part.matches(CronValidate.year())) {
					return true;
				}
			}
		}
		return false;
	}

	// utilities
	public static String convertToAllNumbers(String cron) {
		for (Day day : Day.values()) {
			if (cron.contains(day.name())) {
				cron = cron.replaceAll(day.name(), "" + (day.ordinal() + 1));
			}
		}
		for (Month month : Month.values()) {
			if (cron.contains(month.name())) {
				cron = cron.replaceAll(month.name(), "" + (month.ordinal() + 1));
			}
		}
		return cron;
	}

	public static boolean validateRegex(String regex, String input) {
		return Pattern.matches(regex, input);
	}
	// Regexes
	private static String zero59() {
		return "^([0-5]?[0-9])$";
	}

	private static String zero23() {
		return "^([0-9]|1[0-9]|2[0-3])$";
	}

	private static String one31() {
		return "^([1-9]|1[0-9]|2[0-9]|3[0-1])$";
	}

	private static String one12() {
		return "^([1-9]|1[0-2])$";
	}
	private static String one7() {
		return "^([1-7])$";
	}
	private static String yearRange() {
		return "^[0-9]{1,4}-[0-9]{1,4}$";
	}
	private static String year() {
		return "[0-9]{1,4}";
	}
}
It looks like a lot of code but that's just because I split the stuff into many smaller methods to keep things clear in my head.


I'll post the test cases I used just now.
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Apr 15 2010
Added on Mar 18 2010
9 comments
2,376 views