/**
* Copyright (c)2010-2011 Enterprise Website Content Management System(EWCMS), All rights reserved.
* EWCMS PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
* http://www.ewcms.com
*/
package com.ewcms.scheduling.generate.validator;
import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;
import java.util.regex.Pattern;
import org.quartz.DateBuilder;
import org.springframework.stereotype.Service;
import com.ewcms.scheduling.BaseException;
import com.ewcms.scheduling.generate.common.ValidationError;
import com.ewcms.scheduling.generate.common.ValidationErrors;
import com.ewcms.scheduling.generate.common.ValidationErrorsable;
import com.ewcms.scheduling.model.JobCalendarTrigger;
import com.ewcms.scheduling.model.JobInfo;
import com.ewcms.scheduling.model.JobSimpleTrigger;
import com.ewcms.scheduling.model.JobTrigger;
/**
* 调度任务时间表达式效验
*
* @author 吴智俊
*/
@Service
public class JobInfoValidator implements JobInfoValidatorable {
private static final Pattern PATTERN_CRON_MINUTES;
private static final Pattern PATTERN_CRON_HOURS;
private static final Pattern PATTERN_CRON_MONTH_DAYS;
// private static final Pattern PATTERN_TIMESTAMP_FORMAT;
static {
String allPattern = "(\\*)";
String minPattern = "(\\d|[0-5]\\d)";
String minRangePattern = "(" + minPattern + "(\\-" + minPattern + ")?)";
String minuteIncrementPattern = "(" + minPattern + "\\/\\d+)";
PATTERN_CRON_MINUTES = Pattern.compile("^(" + minRangePattern + "(," + minRangePattern + ")*)|" + minuteIncrementPattern + "|" + allPattern + "$");
String hourPattern = "(\\d|[01]\\d|2[0-3])";
String hourRangePattern = "(" + hourPattern + "(\\-" + hourPattern + ")?)";
String hourIncrementPattern = "(" + hourPattern + "\\/\\d+)";
PATTERN_CRON_HOURS = Pattern.compile("^(" + hourRangePattern + "(," + hourRangePattern + ")*)|" + hourIncrementPattern + "|" + allPattern + "$");
String dayPattern = "([1-9]|[012]\\d|3[01])";
String dayRangePattern = "(" + dayPattern + "(\\-" + dayPattern + ")?)";
String dayIncrementPattern = "(" + dayPattern + "\\/\\d+)";
PATTERN_CRON_MONTH_DAYS = Pattern.compile("^(" + dayRangePattern + "(," + dayRangePattern + ")*)|" + dayIncrementPattern + "|" + allPattern + "$");
// PATTERN_TIMESTAMP_FORMAT = Pattern.compile("(\\p{L}|\\p{N}|(\\_)|(\\.)|(\\-))+");
}
public ValidationErrorsable validateJob(JobInfo job) throws BaseException {
ValidationErrorsable errors = new ValidationErrors();
validateJobDetails(errors, job);
validateJobTrigger(errors, job);
return errors;
}
protected void validateJobDetails(ValidationErrorsable errors, JobInfo job) {
checkString(errors, "label", "名称", job.getLabel(), true, 100);
checkString(errors, "description", "描述", job.getDescription(), false, 2000);
}
protected void validateJobTrigger(ValidationErrorsable errors, JobInfo job) throws BaseException {
JobTrigger trigger = job.getTrigger();
if (trigger == null) {
errors.add(new ValidationError("error.alqc.job.no.trigger", null, "没有触发器指向任务.", "trigger"));
return;
}
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
Date now = calendar.getTime();
String tzId = trigger.getTimeZone();
if (tzId != null && tzId.length() > 0) {
TimeZone tz = TimeZone.getTimeZone(tzId);
now = DateBuilder.translateTime(now, tz, TimeZone.getDefault());
}
if (trigger.getStartType() == JobTrigger.START_TYPE_SCHEDULE) {
Date startDate = trigger.getStartDate();
if (startDate == null) {
errors.add(new ValidationError("error.not.empty", null, "开始日期不能为空.", "trigger.startDate"));
// } else if (startDate.before(now)) {
// errors.add(new ValidationError("error.before.current.date", null, "开始日期不能在过去.", "trigger.startDate"));
}
}
if (trigger.getEndDate() != null) {
if (trigger.getStartType() == JobTrigger.START_TYPE_NOW) {
if (trigger.getEndDate().before(now)) {
errors.add(new ValidationError("error.before.current.date", null, "结束日期不能在过去.", "trigger.endDate"));
}
} else if (trigger.getStartType() == JobTrigger.START_TYPE_SCHEDULE) {
if (trigger.getEndDate().before(now)) {
errors.add(new ValidationError("error.before.current.date", null, "结束日期不能在过去.", "trigger.endDate"));
}
if (trigger.getStartDate() != null && trigger.getEndDate().before(trigger.getStartDate())) {
errors.add(new ValidationError("error.before.start.date", null, "结束日期不能早于开始日期.", "trigger.endDate"));
}
}
}
if (trigger instanceof JobSimpleTrigger) {
validateJobSimpleTrigger(errors, (JobSimpleTrigger) trigger);
} else if (trigger instanceof JobCalendarTrigger) {
validateJobCalendarTrigger(errors, (JobCalendarTrigger) trigger);
} else {
// String quotedTriggerType = "\"" + trigger.getClass().getName() + "\"";
// throw new JSException("jsexception.job.unknown.trigger.type", new Object[] {quotedTriggerType});
throw new BaseException("不能识别任务中的触发器类型", "不能识别任务中的触发器类型");
}
}
protected void validateJobSimpleTrigger(ValidationErrorsable errors, JobSimpleTrigger trigger) throws BaseException {
if (trigger.getOccurrenceCount() == null){
throw new BaseException("次数不能为空","次数不能为空");
}
int occurrenceCount = trigger.getOccurrenceCount();
if (occurrenceCount != JobSimpleTrigger.RECUR_INDEFINITELY && occurrenceCount < 1) {
errors.add(new ValidationError("error.invalid", null, "次数不能少于0", "trigger.occurrenceCount"));
} else if (occurrenceCount > 1 || occurrenceCount == JobSimpleTrigger.RECUR_INDEFINITELY) {
if (trigger.getRecurrenceInterval() == null) {
errors.add(new ValidationError("error.not.empty", null, "间隔数不能为空.", "trigger.recurrenceInterval"));
} else if (trigger.getRecurrenceInterval().intValue() <= 0) {
errors.add(new ValidationError("error.positive", null, "间隔数不能小于0", "trigger.recurrenceInterval"));
}
if (trigger.getRecurrenceIntervalUnit() == null) {
errors.add(new ValidationError("error.not.empty", null, "间隔单位不能为空.", "trigger.recurrenceIntervalUnit"));
}
}
}
protected void validateJobCalendarTrigger(ValidationErrorsable errors, JobCalendarTrigger trigger) throws BaseException {
if (checkString(errors, "trigger.minutes", "分钟", trigger.getMinutes(), true, 200)) {
validateCronMinutes(errors, trigger.getMinutes());
}
if (checkString(errors, "trigger.hours", "小时", trigger.getHours(), true, 80)) {
validateCronHours(errors, trigger.getHours());
}
if (trigger.getDaysType().intValue() == JobCalendarTrigger.DAYS_TYPE_ALL.intValue()) {
} else if (trigger.getDaysType().intValue() == JobCalendarTrigger.DAYS_TYPE_WEEK.intValue()) {
if (trigger.getWeekDays() == null || trigger.getWeekDays().length() == 0) {
errors.add(new ValidationError("error.not.empty", null, "一周内不能为空.", "trigger.weekDays"));
}
} else if (trigger.getDaysType().intValue() == JobCalendarTrigger.DAYS_TYPE_MONTH.intValue()) {
if (checkString(errors, "trigger.monthDays", "一个月内", trigger.getMonthDays(), true, 100)) {
validateCronMonthDays(errors, trigger.getMonthDays());
}
} else {
throw new BaseException("不能识别任务中的复杂触发器天数类型", "不能识别任务中的复杂触发器天数类型");
}
if (trigger.getMonths() == null || trigger.getMonths().length() == 0) {
errors.add(new ValidationError("error.not.empty", null, "月份不能为空.", "trigger.months"));
}
}
protected void validateCronMinutes(ValidationErrorsable errors, String minutes) {
if (!PATTERN_CRON_MINUTES.matcher(minutes).matches()) {
errors.add(new ValidationError("error.pattern", null, "分钟无效.", "trigger.minutes"));
}
}
protected void validateCronHours(ValidationErrorsable errors, String hours) {
if (!PATTERN_CRON_HOURS.matcher(hours).matches()) {
errors.add(new ValidationError("error.pattern", null, "小时无效.", "trigger.hours"));
}
}
protected void validateCronMonthDays(ValidationErrorsable errors, String days) {
if (!PATTERN_CRON_MONTH_DAYS.matcher(days).matches()) {
errors.add(new ValidationError("error.pattern", null, "小时无效.", "trigger.monthDays"));
}
}
protected boolean checkString(ValidationErrorsable errors, String field, String name, String value, boolean mandatory, int maxLength) {
boolean valid = true;
boolean empty = value == null || value.length() == 0;
if (empty) {
if (mandatory) {
errors.add(new ValidationError("error.not.empty", null, name + "不能为空.", field));
valid = false;
}
} else {
if (value.length() > maxLength) {
errors.add(new ValidationError("error.length", new Object[]{Integer.valueOf(maxLength)}, "最大长度为{0 ,数量,整数}.", field));
valid = false;
}
}
return valid;
}
}