diff --git a/core/src/main/java/hudson/scheduler/CronTab.java b/core/src/main/java/hudson/scheduler/CronTab.java index 6eee0da5868264dd21ba7f871734c66c563f8cc7..7390e763b0fd24d458e01919bc846df426484a34 100644 --- a/core/src/main/java/hudson/scheduler/CronTab.java +++ b/core/src/main/java/hudson/scheduler/CronTab.java @@ -23,6 +23,11 @@ public final class CronTab { int dayOfWeek; + /** + * Textual representation. + */ + private String spec; + public CronTab(String format) throws ANTLRException { this(format,1); } @@ -35,6 +40,7 @@ public final class CronTab { CrontabLexer lexer = new CrontabLexer(new StringReader(format)); lexer.setLine(line); CrontabParser parser = new CrontabParser(lexer); + spec = format; parser.startRule(this); if((dayOfWeek&(1<<7))!=0) @@ -83,4 +89,34 @@ public final class CronTab { private String toString(String key, long bit) { return key+'='+Long.toHexString(bit); } + + /** + * Checks if this crontab entry looks reasonable, + * and if not, return an warning message. + * + *

+ * The point of this method is to catch syntactically correct + * but semantically suspicious combinations, like + * "* 0 * * *" + */ + public String checkSanity() { + for( int i=0; i<5; i++ ) { + for( int j=LOWER_BOUNDS[i]; j<=UPPER_BOUNDS[i]; j++ ) { + if(!checkBits(bits[i],j)) { + // this rank has a sparse entry. + // if we have a sparse rank, one of them better be the left-most. + if(i>0) + return "Do you really mean \"every minute\" when you say \""+spec+"\"?"; + // once we find a sparse rank, upper ranks don't matter + return null; + } + } + } + + return null; + } + + // lower/uppser bounds of fields + private static final int[] LOWER_BOUNDS = new int[] {0,0,1,0,0}; + private static final int[] UPPER_BOUNDS = new int[] {59,23,31,12,7}; } diff --git a/core/src/main/java/hudson/scheduler/CronTabList.java b/core/src/main/java/hudson/scheduler/CronTabList.java index d15eac5bf50f66cf6e87414b6bbda8ab41d4430f..f07014323ecf8850d942e91d636b78e01be57800 100644 --- a/core/src/main/java/hudson/scheduler/CronTabList.java +++ b/core/src/main/java/hudson/scheduler/CronTabList.java @@ -26,6 +26,23 @@ public final class CronTabList { return false; } + /** + * Checks if this crontab entry looks reasonable, + * and if not, return an warning message. + * + *

+ * The point of this method is to catch syntactically correct + * but semantically suspicious combinations, like + * "* 0 * * *" + */ + public String checkSanity() { + for (CronTab tab : tabs) { + String s = tab.checkSanity(); + if(s!=null) return s; + } + return null; + } + public static CronTabList create(String format) throws ANTLRException { Vector r = new Vector(); int lineNumber = 0; diff --git a/core/src/main/java/hudson/triggers/TimerTrigger.java b/core/src/main/java/hudson/triggers/TimerTrigger.java index a196fe5f4d83f5ce49e3bf226bcd57ff0b4b0932..a35988037c7a78532679d8c9b4b9e7f8d42ab451 100644 --- a/core/src/main/java/hudson/triggers/TimerTrigger.java +++ b/core/src/main/java/hudson/triggers/TimerTrigger.java @@ -59,8 +59,11 @@ public class TimerTrigger extends Trigger { new FormFieldValidator(req,rsp,true) { protected void check() throws IOException, ServletException { try { - CronTabList.create(fixNull(request.getParameter("value"))); - ok(); + String msg = CronTabList.create(fixNull(request.getParameter("value"))).checkSanity(); + if(msg!=null) + warning(msg); + else + ok(); } catch (ANTLRException e) { error(e.getMessage()); }