Code example for BitSet

Methods: cleargetset

0
 
	private final BitSet minutes = new BitSet(60);
 
	private final BitSet hours = new BitSet(24);
 
	private final BitSet daysOfWeek = new BitSet(7);
 
	private final BitSet daysOfMonth = new BitSet(31);
 
	private final BitSet months = new BitSet(12);
 
	private final String expression;
 
	private final TimeZone timeZone;
 
 
	/** 
	 * Construct a {@link CronSequenceGenerator} from the pattern provided, 
	 * using the default {@link TimeZone}. 
	 * @param expression a space-separated list of time fields 
	 * @throws IllegalArgumentException if the pattern cannot be parsed 
	 * @see java.util.TimeZone#getDefault() 
	 */ 
	public CronSequenceGenerator(String expression) {
		this(expression, TimeZone.getDefault());
	} 
 
	/** 
	 * Construct a {@link CronSequenceGenerator} from the pattern provided, 
	 * using the specified {@link TimeZone}. 
	 * @param expression a space-separated list of time fields 
	 * @param timeZone the TimeZone to use for generated trigger times 
	 * @throws IllegalArgumentException if the pattern cannot be parsed 
	 */ 
	public CronSequenceGenerator(String expression, TimeZone timeZone) {
		this.expression = expression;
		this.timeZone = timeZone;
		parse(expression);
	} 
 
 
	/** 
	 * Get the next {@link Date} in the sequence matching the Cron pattern and 
	 * after the value provided. The return value will have a whole number of 
	 * seconds, and will be after the input value. 
	 * @param date a seed value 
	 * @return the next value matching the pattern 
	 */ 
	public Date next(Date date) {
		/* 
		The plan: 
 
		1 Round up to the next whole second 
 
		2 If seconds match move on, otherwise find the next match: 
		2.1 If next match is in the next minute then roll forwards 
 
		3 If minute matches move on, otherwise find the next match 
		3.1 If next match is in the next hour then roll forwards 
		3.2 Reset the seconds and go to 2 
 
		4 If hour matches move on, otherwise find the next match 
		4.1 If next match is in the next day then roll forwards, 
		4.2 Reset the minutes and seconds and go to 2 
 
		... 
		*/ 
 
		Calendar calendar = new GregorianCalendar();
		calendar.setTimeZone(this.timeZone);
		calendar.setTime(date);
 
		// First, just reset the milliseconds and try to calculate from there... 
		calendar.set(Calendar.MILLISECOND, 0);
		long originalTimestamp = calendar.getTimeInMillis();
		doNext(calendar, calendar.get(Calendar.YEAR));
 
		if (calendar.getTimeInMillis() == originalTimestamp) {
			// We arrived at the original timestamp - round up to the next whole second and try again... 
			calendar.add(Calendar.SECOND, 1);
			doNext(calendar, calendar.get(Calendar.YEAR));
		} 
 
		return calendar.getTime();
	} 
 
	private void doNext(Calendar calendar, int dot) {
		List<Integer> resets = new ArrayList<Integer>();
 
		int second = calendar.get(Calendar.SECOND);
		List<Integer> emptyList = Collections.emptyList();
		int updateSecond = findNext(this.seconds, second, calendar, Calendar.SECOND, Calendar.MINUTE, emptyList);
		if (second == updateSecond) {
			resets.add(Calendar.SECOND);
		} 
 
		int minute = calendar.get(Calendar.MINUTE);
		int updateMinute = findNext(this.minutes, minute, calendar, Calendar.MINUTE, Calendar.HOUR_OF_DAY, resets);
		if (minute == updateMinute) {
			resets.add(Calendar.MINUTE);
		} 
		else { 
			doNext(calendar, dot);
		} 
 
		int hour = calendar.get(Calendar.HOUR_OF_DAY);
		int updateHour = findNext(this.hours, hour, calendar, Calendar.HOUR_OF_DAY, Calendar.DAY_OF_WEEK, resets);
		if (hour == updateHour) {
			resets.add(Calendar.HOUR_OF_DAY);
		} 
		else { 
			doNext(calendar, dot);
		} 
 
		int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
		int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
		int updateDayOfMonth = findNextDay(calendar, this.daysOfMonth, dayOfMonth, daysOfWeek, dayOfWeek, resets);
		if (dayOfMonth == updateDayOfMonth) {
			resets.add(Calendar.DAY_OF_MONTH);
		} 
		else { 
			doNext(calendar, dot);
		} 
 
		int month = calendar.get(Calendar.MONTH);
		int updateMonth = findNext(this.months, month, calendar, Calendar.MONTH, Calendar.YEAR, resets);
		if (month != updateMonth) {
			if (calendar.get(Calendar.YEAR) - dot > 4) {
				throw new IllegalArgumentException("Invalid cron expression \"" + this.expression +
						"\" led to runaway search for next trigger"); 
			} 
			doNext(calendar, dot);
		} 
 
	} 
 
	private int findNextDay(Calendar calendar, BitSet daysOfMonth, int dayOfMonth, BitSet daysOfWeek, int dayOfWeek,
			List<Integer> resets) {
 
		int count = 0;
		int max = 366;
		// the DAY_OF_WEEK values in java.util.Calendar start with 1 (Sunday), 
		// but in the cron pattern, they start with 0, so we subtract 1 here 
		while ((!daysOfMonth.get(dayOfMonth) || !daysOfWeek.get(dayOfWeek - 1)) && count++ < max) {
			calendar.add(Calendar.DAY_OF_MONTH, 1);
			dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH);
			dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
			reset(calendar, resets);
		} 
		if (count >= max) {
			throw new IllegalArgumentException("Overflow in day for expression \"" + this.expression + "\"");
		} 
		return dayOfMonth;
	} 
 
	/** 
	 * Search the bits provided for the next set bit after the value provided, 
	 * and reset the calendar. 
	 * @param bits a {@link BitSet} representing the allowed values of the field 
	 * @param value the current value of the field 
	 * @param calendar the calendar to increment as we move through the bits 
	 * @param field the field to increment in the calendar (@see 
	 * {@link Calendar} for the static constants defining valid fields) 
	 * @param lowerOrders the Calendar field ids that should be reset (i.e. the 
	 * ones of lower significance than the field of interest) 
	 * @return the value of the calendar field that is next in the sequence 
	 */ 
	private int findNext(BitSet bits, int value, Calendar calendar, int field, int nextField, List<Integer> lowerOrders) {
		int nextValue = bits.nextSetBit(value);
		// roll over if needed 
		if (nextValue == -1) {
			calendar.add(nextField, 1);
			reset(calendar, Arrays.asList(field));
			nextValue = bits.nextSetBit(0);
		} 
		if (nextValue != value) {
			calendar.set(field, nextValue);
			reset(calendar, lowerOrders);
		} 
		return nextValue;
	} 
 
	/** 
	 * Reset the calendar setting all the fields provided to zero. 
	 */ 
	private void reset(Calendar calendar, List<Integer> fields) {
		for (int field : fields) {
			calendar.set(field, field == Calendar.DAY_OF_MONTH ? 1 : 0);
		} 
	} 
 
 
	// Parsing logic invoked by the constructor 
 
	/** 
	 * Parse the given pattern expression. 
	 */ 
	private void parse(String expression) throws IllegalArgumentException {
		String[] fields = StringUtils.tokenizeToStringArray(expression, " ");
		if (fields.length != 6) {
			throw new IllegalArgumentException(String.format(
					"Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
		} 
		setNumberHits(this.seconds, fields[0], 0, 60);
		setNumberHits(this.minutes, fields[1], 0, 60);
		setNumberHits(this.hours, fields[2], 0, 24);
		setDaysOfMonth(this.daysOfMonth, fields[3]);
		setMonths(this.months, fields[4]);
		setDays(this.daysOfWeek, replaceOrdinals(fields[5], "SUN,MON,TUE,WED,THU,FRI,SAT"), 8);
		if (this.daysOfWeek.get(7)) {
			// Sunday can be represented as 0 or 7 
			this.daysOfWeek.set(0);
			this.daysOfWeek.clear(7);
		} 
	} 
 
	/** 
	 * Replace the values in the commaSeparatedList (case insensitive) with