001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.config.types;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.util.L10N;
033: import com.caucho.util.QDate;
034:
035: import java.util.regex.Pattern;
036:
037: /**
038: * Class-loading TypeBuilder
039: */
040: public class CronType {
041: static L10N L = new L10N(CronType.class);
042:
043: private static final long DAY = 24L * 3600L * 1000L;
044:
045: private final QDate _localCalendar = QDate.createLocal();
046:
047: private boolean[] _minutes;
048: private boolean[] _hours;
049: private boolean[] _days;
050: private boolean[] _months;
051: private boolean[] _daysOfWeek;
052:
053: public CronType() {
054: }
055:
056: /**
057: * Sets the text.
058: */
059: public void addText(String text) throws ConfigException {
060: text = text.trim();
061:
062: String[] split = Pattern.compile("\\s+").split(text);
063:
064: if (split.length > 0)
065: _minutes = parseRange(split[0], 0, 59);
066:
067: if (split.length > 1)
068: _hours = parseRange(split[1], 0, 23);
069: else
070: _hours = parseRange("*", 0, 23);
071:
072: if (split.length > 2)
073: _days = parseRange(split[2], 1, 31);
074:
075: if (split.length > 3)
076: _months = parseRange(split[3], 1, 12);
077:
078: if (split.length > 4)
079: _daysOfWeek = parseRange(split[4], 0, 7);
080: }
081:
082: /**
083: * parses a range, following cron rules.
084: */
085: private boolean[] parseRange(String range, int rangeMin,
086: int rangeMax) throws ConfigException {
087: boolean[] values = new boolean[rangeMax + 1];
088:
089: int j = 0;
090: while (j < range.length()) {
091: char ch = range.charAt(j);
092:
093: int min = 0;
094: int max = 0;
095: int step = 1;
096:
097: if (ch == '*') {
098: min = rangeMin;
099: max = rangeMax;
100: j++;
101: } else if ('0' <= ch && ch <= '9') {
102: for (; j < range.length()
103: && '0' <= (ch = range.charAt(j)) && ch <= '9'; j++) {
104: min = 10 * min + ch - '0';
105: }
106:
107: if (j < range.length() && ch == '-') {
108: for (j++; j < range.length()
109: && '0' <= (ch = range.charAt(j))
110: && ch <= '9'; j++) {
111: max = 10 * max + ch - '0';
112: }
113: } else
114: max = min;
115: } else
116: throw new ConfigException(L.l(
117: "`{0}' is an illegal cron range", range));
118:
119: if (min < rangeMin)
120: throw new ConfigException(
121: L
122: .l(
123: "`{0}' is an illegal cron range (min value is too small)",
124: range));
125: else if (rangeMax < max)
126: throw new ConfigException(
127: L
128: .l(
129: "`{0}' is an illegal cron range (max value is too large)",
130: range));
131:
132: if (j < range.length() && (ch = range.charAt(j)) == '/') {
133: step = 0;
134:
135: for (j++; j < range.length()
136: && '0' <= (ch = range.charAt(j)) && ch <= '9'; j++) {
137: step = 10 * step + ch - '0';
138: }
139:
140: if (step == 0)
141: throw new ConfigException(L.l(
142: "`{0}' is an illegal cron range", range));
143: }
144:
145: if (range.length() <= j) {
146: } else if (ch == ',')
147: j++;
148: else {
149: throw new ConfigException(L.l(
150: "`{0}' is an illegal cron range", range));
151: }
152:
153: for (; min <= max; min += step)
154: values[min] = true;
155: }
156:
157: return values;
158: }
159:
160: public long nextTime(long now) {
161: QDate cal = _localCalendar;
162:
163: long time = now + 60000 - now % 60000;
164:
165: synchronized (cal) {
166: cal.setGMTTime(time);
167:
168: int minute = nextInterval(_minutes, cal.getMinute());
169:
170: if (minute < 0) {
171: minute = nextInterval(_minutes, 0);
172:
173: cal.setHour(cal.getHour() + 1);
174: }
175:
176: int hour = nextInterval(_hours, cal.getHour());
177: if (hour < 0) {
178: hour = nextInterval(_hours, 0);
179: minute = nextInterval(_minutes, 0);
180:
181: cal.setDayOfMonth(cal.getDayOfMonth() + 1);
182: }
183:
184: int day = cal.getDayOfMonth();
185:
186: if (_days != null) {
187: day = nextInterval(_days, cal.getDayOfMonth());
188:
189: if (day < 0) {
190: cal.setMonth(cal.getMonth() + 1);
191: cal.setDayOfMonth(1);
192:
193: day = nextInterval(_days, cal.getDayOfMonth());
194: hour = nextInterval(_hours, 0);
195: minute = nextInterval(_minutes, 0);
196: }
197: }
198:
199: if (_daysOfWeek != null) {
200: int oldDayOfWeek = cal.getDayOfWeek();
201: int dayOfWeek = nextInterval(_daysOfWeek, oldDayOfWeek);
202:
203: if (dayOfWeek > 0) {
204: day += (dayOfWeek - oldDayOfWeek);
205: } else {
206: dayOfWeek = nextInterval(_daysOfWeek, 0);
207:
208: day += (dayOfWeek - oldDayOfWeek + 7);
209: }
210: }
211:
212: int month = cal.getMonth();
213: int year = (int) cal.getYear();
214:
215: long nextTime = nextTime(year, month, day, hour, minute);
216:
217: if (now < nextTime)
218: return nextTime;
219: else
220: return nextTime(now + 3600000L); // DST
221: }
222: }
223:
224: private long nextTime(int year, int month, int day, int hour,
225: int minute) {
226: QDate cal = _localCalendar;
227:
228: cal.setLocalTime(0);
229:
230: cal.setYear(year);
231: cal.setMonth(month);
232: cal.setDayOfMonth(day);
233: cal.setHour(hour);
234: cal.setMinute(minute);
235:
236: return cal.getGMTTime();
237: }
238:
239: public int nextInterval(boolean[] values, int now) {
240: for (; now < values.length; now++) {
241: if (values[now])
242: return now;
243: }
244:
245: return -1;
246: }
247: }
|