001: /*
002: * Copyright 2004-2005 OpenSymphony
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy
006: * of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations
014: * under the License.
015: *
016: */
017:
018: /*
019: * Previously Copyright (c) 2001-2004 James House
020: * and Juergen Donnerstag (c) 2002, EDS 2002
021: */
022:
023: package org.quartz.impl.calendar;
024:
025: import java.io.Serializable;
026: import java.util.ArrayList;
027: import java.util.Collections;
028: import java.util.Comparator;
029: import java.util.Iterator;
030: import java.util.TimeZone;
031:
032: import org.quartz.Calendar;
033:
034: /**
035: * <p>
036: * This implementation of the Calendar excludes a set of days of the year. You
037: * may use it to exclude bank holidays which are on the same date every year.
038: * </p>
039: *
040: * @see org.quartz.Calendar
041: * @see org.quartz.impl.calendar.BaseCalendar
042: *
043: * @author Juergen Donnerstag
044: */
045: public class AnnualCalendar extends BaseCalendar implements Calendar,
046: Serializable {
047:
048: static final long serialVersionUID = 7346867105876610961L;
049:
050: private ArrayList excludeDays = new ArrayList();
051:
052: // true, if excludeDays is sorted
053: private boolean dataSorted = false;
054:
055: public AnnualCalendar() {
056: }
057:
058: public AnnualCalendar(Calendar baseCalendar) {
059: super (baseCalendar);
060: }
061:
062: public AnnualCalendar(TimeZone timeZone) {
063: super (timeZone);
064: }
065:
066: public AnnualCalendar(Calendar baseCalendar, TimeZone timeZone) {
067: super (baseCalendar, timeZone);
068: }
069:
070: /**
071: * <p>
072: * Get the array which defines the exclude-value of each day of month
073: * </p>
074: */
075: public ArrayList getDaysExcluded() {
076: return excludeDays;
077: }
078:
079: /**
080: * <p>
081: * Return true, if day is defined to be exluded.
082: * </p>
083: */
084: public boolean isDayExcluded(java.util.Calendar day) {
085: if (day == null) {
086: throw new IllegalArgumentException(
087: "Parameter day must not be null");
088: }
089:
090: int dmonth = day.get(java.util.Calendar.MONTH);
091: int dday = day.get(java.util.Calendar.DAY_OF_MONTH);
092:
093: if (dataSorted == false) {
094: Collections.sort(excludeDays, new CalendarComparator());
095: dataSorted = true;
096: }
097:
098: Iterator iter = excludeDays.iterator();
099: while (iter.hasNext()) {
100: java.util.Calendar cl = (java.util.Calendar) iter.next();
101:
102: // remember, the list is sorted
103: if (dmonth < cl.get(java.util.Calendar.MONTH)) {
104: return false;
105: }
106:
107: if (dday != cl.get(java.util.Calendar.DAY_OF_MONTH)) {
108: continue;
109: }
110:
111: if (dmonth != cl.get(java.util.Calendar.MONTH)) {
112: continue;
113: }
114:
115: return true;
116: }
117:
118: return false;
119: }
120:
121: /**
122: * <p>
123: * Redefine the array of days excluded. The array must of size greater or
124: * equal 31.
125: * </p>
126: */
127: public void setDaysExcluded(ArrayList days) {
128: if (days == null) {
129: excludeDays = new ArrayList();
130: }
131:
132: excludeDays = days;
133: dataSorted = false;
134: }
135:
136: /**
137: * <p>
138: * Redefine a certain day to be excluded (true) or included (false).
139: * </p>
140: */
141: public void setDayExcluded(java.util.Calendar day, boolean exclude) {
142: if (isDayExcluded(day)) {
143: return;
144: }
145:
146: excludeDays.add(day);
147: dataSorted = false;
148: }
149:
150: /**
151: * <p>
152: * Determine whether the given time (in milliseconds) is 'included' by the
153: * Calendar.
154: * </p>
155: *
156: * <p>
157: * Note that this Calendar is only has full-day precision.
158: * </p>
159: */
160: public boolean isTimeIncluded(long timeStamp) {
161: // Test the base calendar first. Only if the base calendar not already
162: // excludes the time/date, continue evaluating this calendar instance.
163: if (super .isTimeIncluded(timeStamp) == false) {
164: return false;
165: }
166:
167: java.util.Calendar day = createJavaCalendar(timeStamp);
168:
169: return !(isDayExcluded(day));
170: }
171:
172: /**
173: * <p>
174: * Determine the next time (in milliseconds) that is 'included' by the
175: * Calendar after the given time. Return the original value if timeStamp is
176: * included. Return 0 if all days are excluded.
177: * </p>
178: *
179: * <p>
180: * Note that this Calendar is only has full-day precision.
181: * </p>
182: */
183: public long getNextIncludedTime(long timeStamp) {
184: // Call base calendar implementation first
185: long baseTime = super .getNextIncludedTime(timeStamp);
186: if ((baseTime > 0) && (baseTime > timeStamp)) {
187: timeStamp = baseTime;
188: }
189:
190: // Get timestamp for 00:00:00
191: java.util.Calendar day = getStartOfDayJavaCalendar(timeStamp);
192: if (isDayExcluded(day) == false) {
193: return timeStamp; // return the original value
194: }
195:
196: while (isDayExcluded(day) == true) {
197: day.add(java.util.Calendar.DATE, 1);
198: }
199:
200: return day.getTime().getTime();
201: }
202: }
203:
204: class CalendarComparator implements Comparator {
205: public CalendarComparator() {
206: }
207:
208: /**
209: * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
210: */
211: public int compare(Object arg0, Object arg1) {
212: java.util.Calendar c1 = (java.util.Calendar) arg0;
213: java.util.Calendar c2 = (java.util.Calendar) arg1;
214:
215: if (c1.before(c2)) {
216: return -1;
217: } else if (c1.after(c2)) {
218: return 1;
219: } else {
220: return 0;
221: }
222: }
223: }
|