KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > joda > time > chrono > LimitChronology


1 /*
2  * Copyright 2001-2005 Stephen Colebourne
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.joda.time.chrono;
17
18 import java.util.HashMap JavaDoc;
19 import java.util.Locale JavaDoc;
20
21 import org.joda.time.Chronology;
22 import org.joda.time.DateTime;
23 import org.joda.time.DateTimeField;
24 import org.joda.time.DateTimeZone;
25 import org.joda.time.DurationField;
26 import org.joda.time.MutableDateTime;
27 import org.joda.time.ReadableDateTime;
28 import org.joda.time.field.DecoratedDateTimeField;
29 import org.joda.time.field.DecoratedDurationField;
30 import org.joda.time.field.FieldUtils;
31 import org.joda.time.format.DateTimeFormatter;
32 import org.joda.time.format.ISODateTimeFormat;
33
34 /**
35  * Wraps another Chronology to impose limits on the range of instants that
36  * the fields within a Chronology may support. The limits are applied to both
37  * DateTimeFields and DurationFields.
38  * <p>
39  * Methods in DateTimeField and DurationField throw an IllegalArgumentException
40  * whenever given an input instant that is outside the limits or when an
41  * attempt is made to move an instant outside the limits.
42  * <p>
43  * LimitChronology is thread-safe and immutable.
44  *
45  * @author Brian S O'Neill
46  * @author Stephen Colebourne
47  * @since 1.0
48  */

49 public final class LimitChronology extends AssembledChronology {
50
51     /** Serialization lock */
52     private static final long serialVersionUID = 7670866536893052522L;
53
54     /**
55      * Wraps another chronology, with datetime limits. When withUTC or
56      * withZone is called, the returned LimitChronology instance has
57      * the same limits, except they are time zone adjusted.
58      *
59      * @param base base chronology to wrap
60      * @param lowerLimit inclusive lower limit, or null if none
61      * @param upperLimit exclusive upper limit, or null if none
62      * @throws IllegalArgumentException if chronology is null or limits are invalid
63      */

64     public static LimitChronology getInstance(Chronology base,
65                                               ReadableDateTime lowerLimit,
66                                               ReadableDateTime upperLimit) {
67         if (base == null) {
68             throw new IllegalArgumentException JavaDoc("Must supply a chronology");
69         }
70
71         lowerLimit = lowerLimit == null ? null : lowerLimit.toDateTime();
72         upperLimit = upperLimit == null ? null : upperLimit.toDateTime();
73
74         if (lowerLimit != null && upperLimit != null) {
75             if (!lowerLimit.isBefore(upperLimit)) {
76                 throw new IllegalArgumentException JavaDoc
77                     ("The lower limit must be come before than the upper limit");
78             }
79         }
80
81         return new LimitChronology(base, (DateTime)lowerLimit, (DateTime)upperLimit);
82     }
83
84     final DateTime iLowerLimit;
85     final DateTime iUpperLimit;
86
87     private transient LimitChronology iWithUTC;
88
89     /**
90      * Wraps another chronology, with datetime limits. When withUTC or
91      * withZone is called, the returned LimitChronology instance has
92      * the same limits, except they are time zone adjusted.
93      *
94      * @param lowerLimit inclusive lower limit, or null if none
95      * @param upperLimit exclusive upper limit, or null if none
96      */

97     private LimitChronology(Chronology base,
98                             DateTime lowerLimit, DateTime upperLimit) {
99         super(base, null);
100         // These can be set after assembly.
101
iLowerLimit = lowerLimit;
102         iUpperLimit = upperLimit;
103     }
104
105     /**
106      * Returns the inclusive lower limit instant.
107      *
108      * @return lower limit
109      */

110     public DateTime getLowerLimit() {
111         return iLowerLimit;
112     }
113
114     /**
115      * Returns the inclusive upper limit instant.
116      *
117      * @return upper limit
118      */

119     public DateTime getUpperLimit() {
120         return iUpperLimit;
121     }
122
123     /**
124      * If this LimitChronology is already UTC, then this is
125      * returned. Otherwise, a new instance is returned, with the limits
126      * adjusted to the new time zone.
127      */

128     public Chronology withUTC() {
129         return withZone(DateTimeZone.UTC);
130     }
131
132     /**
133      * If this LimitChronology has the same time zone as the one given, then
134      * this is returned. Otherwise, a new instance is returned, with the limits
135      * adjusted to the new time zone.
136      */

137     public Chronology withZone(DateTimeZone zone) {
138         if (zone == null) {
139             zone = DateTimeZone.getDefault();
140         }
141         if (zone == getZone()) {
142             return this;
143         }
144
145         if (zone == DateTimeZone.UTC && iWithUTC != null) {
146             return iWithUTC;
147         }
148
149         DateTime lowerLimit = iLowerLimit;
150         if (lowerLimit != null) {
151             MutableDateTime mdt = lowerLimit.toMutableDateTime();
152             mdt.setZoneRetainFields(zone);
153             lowerLimit = mdt.toDateTime();
154         }
155
156         DateTime upperLimit = iUpperLimit;
157         if (upperLimit != null) {
158             MutableDateTime mdt = upperLimit.toMutableDateTime();
159             mdt.setZoneRetainFields(zone);
160             upperLimit = mdt.toDateTime();
161         }
162         
163         LimitChronology chrono = getInstance
164             (getBase().withZone(zone), lowerLimit, upperLimit);
165
166         if (zone == DateTimeZone.UTC) {
167             iWithUTC = chrono;
168         }
169
170         return chrono;
171     }
172
173     public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
174                                   int millisOfDay)
175         throws IllegalArgumentException JavaDoc
176     {
177         long instant = getBase().getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
178         checkLimits(instant, "resulting");
179         return instant;
180     }
181
182     public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
183                                   int hourOfDay, int minuteOfHour,
184                                   int secondOfMinute, int millisOfSecond)
185         throws IllegalArgumentException JavaDoc
186     {
187         long instant = getBase().getDateTimeMillis
188             (year, monthOfYear, dayOfMonth,
189              hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
190         checkLimits(instant, "resulting");
191         return instant;
192     }
193
194     public long getDateTimeMillis(long instant,
195                                   int hourOfDay, int minuteOfHour,
196                                   int secondOfMinute, int millisOfSecond)
197         throws IllegalArgumentException JavaDoc
198     {
199         checkLimits(instant, null);
200         instant = getBase().getDateTimeMillis
201             (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
202         checkLimits(instant, "resulting");
203         return instant;
204     }
205
206     protected void assemble(Fields fields) {
207         // Keep a local cache of converted fields so as not to create redundant
208
// objects.
209
HashMap JavaDoc converted = new HashMap JavaDoc();
210
211         // Convert duration fields...
212

213         fields.eras = convertField(fields.eras, converted);
214         fields.centuries = convertField(fields.centuries, converted);
215         fields.years = convertField(fields.years, converted);
216         fields.months = convertField(fields.months, converted);
217         fields.weekyears = convertField(fields.weekyears, converted);
218         fields.weeks = convertField(fields.weeks, converted);
219         fields.days = convertField(fields.days, converted);
220
221         fields.halfdays = convertField(fields.halfdays, converted);
222         fields.hours = convertField(fields.hours, converted);
223         fields.minutes = convertField(fields.minutes, converted);
224         fields.seconds = convertField(fields.seconds, converted);
225         fields.millis = convertField(fields.millis, converted);
226
227         // Convert datetime fields...
228

229         fields.year = convertField(fields.year, converted);
230         fields.yearOfEra = convertField(fields.yearOfEra, converted);
231         fields.yearOfCentury = convertField(fields.yearOfCentury, converted);
232         fields.centuryOfEra = convertField(fields.centuryOfEra, converted);
233         fields.era = convertField(fields.era, converted);
234         fields.dayOfWeek = convertField(fields.dayOfWeek, converted);
235         fields.dayOfMonth = convertField(fields.dayOfMonth, converted);
236         fields.dayOfYear = convertField(fields.dayOfYear, converted);
237         fields.monthOfYear = convertField(fields.monthOfYear, converted);
238         fields.weekOfWeekyear = convertField(fields.weekOfWeekyear, converted);
239         fields.weekyear = convertField(fields.weekyear, converted);
240         fields.weekyearOfCentury = convertField(fields.weekyearOfCentury, converted);
241
242         fields.millisOfSecond = convertField(fields.millisOfSecond, converted);
243         fields.millisOfDay = convertField(fields.millisOfDay, converted);
244         fields.secondOfMinute = convertField(fields.secondOfMinute, converted);
245         fields.secondOfDay = convertField(fields.secondOfDay, converted);
246         fields.minuteOfHour = convertField(fields.minuteOfHour, converted);
247         fields.minuteOfDay = convertField(fields.minuteOfDay, converted);
248         fields.hourOfDay = convertField(fields.hourOfDay, converted);
249         fields.hourOfHalfday = convertField(fields.hourOfHalfday, converted);
250         fields.clockhourOfDay = convertField(fields.clockhourOfDay, converted);
251         fields.clockhourOfHalfday = convertField(fields.clockhourOfHalfday, converted);
252         fields.halfdayOfDay = convertField(fields.halfdayOfDay, converted);
253     }
254
255     private DurationField convertField(DurationField field, HashMap JavaDoc converted) {
256         if (field == null || !field.isSupported()) {
257             return field;
258         }
259         if (converted.containsKey(field)) {
260             return (DurationField)converted.get(field);
261         }
262         LimitDurationField limitField = new LimitDurationField(field);
263         converted.put(field, limitField);
264         return limitField;
265     }
266
267     private DateTimeField convertField(DateTimeField field, HashMap JavaDoc converted) {
268         if (field == null || !field.isSupported()) {
269             return field;
270         }
271         if (converted.containsKey(field)) {
272             return (DateTimeField)converted.get(field);
273         }
274         LimitDateTimeField limitField =
275             new LimitDateTimeField(field,
276                                    convertField(field.getDurationField(), converted),
277                                    convertField(field.getRangeDurationField(), converted),
278                                    convertField(field.getLeapDurationField(), converted));
279         converted.put(field, limitField);
280         return limitField;
281     }
282
283     void checkLimits(long instant, String JavaDoc desc) {
284         DateTime limit;
285         if ((limit = iLowerLimit) != null && instant < limit.getMillis()) {
286             throw new LimitException(desc, true);
287         }
288         if ((limit = iUpperLimit) != null && instant >= limit.getMillis()) {
289             throw new LimitException(desc, false);
290         }
291     }
292
293     //-----------------------------------------------------------------------
294
/**
295      * A limit chronology is only equal to a limit chronology with the
296      * same base chronology and limits.
297      *
298      * @param obj the object to compare to
299      * @return true if equal
300      * @since 1.4
301      */

302     public boolean equals(Object JavaDoc obj) {
303         if (this == obj) {
304             return true;
305         }
306         if (obj instanceof LimitChronology == false) {
307             return false;
308         }
309         LimitChronology chrono = (LimitChronology) obj;
310         return
311             getBase().equals(chrono.getBase()) &&
312             FieldUtils.equals(getLowerLimit(), chrono.getLowerLimit()) &&
313             FieldUtils.equals(getUpperLimit(), chrono.getUpperLimit());
314     }
315
316     /**
317      * A suitable hashcode for the chronology.
318      *
319      * @return the hashcode
320      * @since 1.4
321      */

322     public int hashCode() {
323         int hash = 317351877;
324         hash += (getLowerLimit() != null ? getLowerLimit().hashCode() : 0);
325         hash += (getUpperLimit() != null ? getUpperLimit().hashCode() : 0);
326         hash += getBase().hashCode() * 7;
327         return hash;
328     }
329
330     /**
331      * A debugging string for the chronology.
332      *
333      * @return the debugging string
334      */

335     public String JavaDoc toString() {
336         return "LimitChronology[" + getBase().toString() + ", " +
337             (getLowerLimit() == null ? "NoLimit" : getLowerLimit().toString()) + ", " +
338             (getUpperLimit() == null ? "NoLimit" : getUpperLimit().toString()) + ']';
339     }
340
341     //-----------------------------------------------------------------------
342
/**
343      * Extends IllegalArgumentException such that the exception message is not
344      * generated unless it is actually requested.
345      */

346     private class LimitException extends IllegalArgumentException JavaDoc {
347         private static final long serialVersionUID = -5924689995607498581L;
348
349         private final boolean iIsLow;
350
351         LimitException(String JavaDoc desc, boolean isLow) {
352             super(desc);
353             iIsLow = isLow;
354         }
355
356         public String JavaDoc getMessage() {
357             StringBuffer JavaDoc buf = new StringBuffer JavaDoc(85);
358             buf.append("The");
359             String JavaDoc desc = super.getMessage();
360             if (desc != null) {
361                 buf.append(' ');
362                 buf.append(desc);
363             }
364             buf.append(" instant is ");
365
366             DateTimeFormatter p = ISODateTimeFormat.dateTime();
367             p = p.withChronology(getBase());
368             if (iIsLow) {
369                 buf.append("below the supported minimum of ");
370                 p.printTo(buf, getLowerLimit().getMillis());
371             } else {
372                 buf.append("above the supported maximum of ");
373                 p.printTo(buf, getUpperLimit().getMillis());
374             }
375             
376             buf.append(" (");
377             buf.append(getBase());
378             buf.append(')');
379
380             return buf.toString();
381         }
382
383         public String JavaDoc toString() {
384             return "IllegalArgumentException: " + getMessage();
385         }
386     }
387
388     private class LimitDurationField extends DecoratedDurationField {
389         private static final long serialVersionUID = 8049297699408782284L;
390
391         LimitDurationField(DurationField field) {
392             super(field, field.getType());
393         }
394
395         public int getValue(long duration, long instant) {
396             checkLimits(instant, null);
397             return getWrappedField().getValue(duration, instant);
398         }
399
400         public long getValueAsLong(long duration, long instant) {
401             checkLimits(instant, null);
402             return getWrappedField().getValueAsLong(duration, instant);
403         }
404
405         public long getMillis(int value, long instant) {
406             checkLimits(instant, null);
407             return getWrappedField().getMillis(value, instant);
408         }
409
410         public long getMillis(long value, long instant) {
411             checkLimits(instant, null);
412             return getWrappedField().getMillis(value, instant);
413         }
414
415         public long add(long instant, int amount) {
416             checkLimits(instant, null);
417             long result = getWrappedField().add(instant, amount);
418             checkLimits(result, "resulting");
419             return result;
420         }
421
422         public long add(long instant, long amount) {
423             checkLimits(instant, null);
424             long result = getWrappedField().add(instant, amount);
425             checkLimits(result, "resulting");
426             return result;
427         }
428
429         public int getDifference(long minuendInstant, long subtrahendInstant) {
430             checkLimits(minuendInstant, "minuend");
431             checkLimits(subtrahendInstant, "subtrahend");
432             return getWrappedField().getDifference(minuendInstant, subtrahendInstant);
433         }
434
435         public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
436             checkLimits(minuendInstant, "minuend");
437             checkLimits(subtrahendInstant, "subtrahend");
438             return getWrappedField().getDifferenceAsLong(minuendInstant, subtrahendInstant);
439         }
440
441     }
442
443     private class LimitDateTimeField extends DecoratedDateTimeField {
444         private static final long serialVersionUID = -2435306746995699312L;
445
446         private final DurationField iDurationField;
447         private final DurationField iRangeDurationField;
448         private final DurationField iLeapDurationField;
449
450         LimitDateTimeField(DateTimeField field,
451                            DurationField durationField,
452                            DurationField rangeDurationField,
453                            DurationField leapDurationField) {
454             super(field, field.getType());
455             iDurationField = durationField;
456             iRangeDurationField = rangeDurationField;
457             iLeapDurationField = leapDurationField;
458         }
459
460         public int get(long instant) {
461             checkLimits(instant, null);
462             return getWrappedField().get(instant);
463         }
464         
465         public String JavaDoc getAsText(long instant, Locale JavaDoc locale) {
466             checkLimits(instant, null);
467             return getWrappedField().getAsText(instant, locale);
468         }
469         
470         public String JavaDoc getAsShortText(long instant, Locale JavaDoc locale) {
471             checkLimits(instant, null);
472             return getWrappedField().getAsShortText(instant, locale);
473         }
474         
475         public long add(long instant, int amount) {
476             checkLimits(instant, null);
477             long result = getWrappedField().add(instant, amount);
478             checkLimits(result, "resulting");
479             return result;
480         }
481
482         public long add(long instant, long amount) {
483             checkLimits(instant, null);
484             long result = getWrappedField().add(instant, amount);
485             checkLimits(result, "resulting");
486             return result;
487         }
488
489         public long addWrapField(long instant, int amount) {
490             checkLimits(instant, null);
491             long result = getWrappedField().addWrapField(instant, amount);
492             checkLimits(result, "resulting");
493             return result;
494         }
495         
496         public int getDifference(long minuendInstant, long subtrahendInstant) {
497             checkLimits(minuendInstant, "minuend");
498             checkLimits(subtrahendInstant, "subtrahend");
499             return getWrappedField().getDifference(minuendInstant, subtrahendInstant);
500         }
501         
502         public long getDifferenceAsLong(long minuendInstant, long subtrahendInstant) {
503             checkLimits(minuendInstant, "minuend");
504             checkLimits(subtrahendInstant, "subtrahend");
505             return getWrappedField().getDifferenceAsLong(minuendInstant, subtrahendInstant);
506         }
507         
508         public long set(long instant, int value) {
509             checkLimits(instant, null);
510             long result = getWrappedField().set(instant, value);
511             checkLimits(result, "resulting");
512             return result;
513         }
514         
515         public long set(long instant, String JavaDoc text, Locale JavaDoc locale) {
516             checkLimits(instant, null);
517             long result = getWrappedField().set(instant, text, locale);
518             checkLimits(result, "resulting");
519             return result;
520         }
521         
522         public final DurationField getDurationField() {
523             return iDurationField;
524         }
525
526         public final DurationField getRangeDurationField() {
527             return iRangeDurationField;
528         }
529
530         public boolean isLeap(long instant) {
531             checkLimits(instant, null);
532             return getWrappedField().isLeap(instant);
533         }
534         
535         public int getLeapAmount(long instant) {
536             checkLimits(instant, null);
537             return getWrappedField().getLeapAmount(instant);
538         }
539         
540         public final DurationField getLeapDurationField() {
541             return iLeapDurationField;
542         }
543         
544         public long roundFloor(long instant) {
545             checkLimits(instant, null);
546             long result = getWrappedField().roundFloor(instant);
547             checkLimits(result, "resulting");
548             return result;
549         }
550         
551         public long roundCeiling(long instant) {
552             checkLimits(instant, null);
553             long result = getWrappedField().roundCeiling(instant);
554             checkLimits(result, "resulting");
555             return result;
556         }
557         
558         public long roundHalfFloor(long instant) {
559             checkLimits(instant, null);
560             long result = getWrappedField().roundHalfFloor(instant);
561             checkLimits(result, "resulting");
562             return result;
563         }
564         
565         public long roundHalfCeiling(long instant) {
566             checkLimits(instant, null);
567             long result = getWrappedField().roundHalfCeiling(instant);
568             checkLimits(result, "resulting");
569             return result;
570         }
571         
572         public long roundHalfEven(long instant) {
573             checkLimits(instant, null);
574             long result = getWrappedField().roundHalfEven(instant);
575             checkLimits(result, "resulting");
576             return result;
577         }
578         
579         public long remainder(long instant) {
580             checkLimits(instant, null);
581             long result = getWrappedField().remainder(instant);
582             checkLimits(result, "resulting");
583             return result;
584         }
585
586         public int getMinimumValue(long instant) {
587             checkLimits(instant, null);
588             return getWrappedField().getMinimumValue(instant);
589         }
590
591         public int getMaximumValue(long instant) {
592             checkLimits(instant, null);
593             return getWrappedField().getMaximumValue(instant);
594         }
595
596         public int getMaximumTextLength(Locale JavaDoc locale) {
597             return getWrappedField().getMaximumTextLength(locale);
598         }
599
600         public int getMaximumShortTextLength(Locale JavaDoc locale) {
601             return getWrappedField().getMaximumShortTextLength(locale);
602         }
603
604     }
605
606 }
607
Popular Tags