001: /*
002: * Copyright 2001-2005 Stephen Colebourne
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy 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,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.joda.time.chrono;
017:
018: import java.io.IOException;
019: import java.io.ObjectInputStream;
020:
021: import org.joda.time.Chronology;
022: import org.joda.time.DateTimeField;
023: import org.joda.time.DateTimeZone;
024: import org.joda.time.DurationField;
025:
026: /**
027: * Abstract Chronology that enables chronologies to be assembled from
028: * a container of fields.
029: * <p>
030: * AssembledChronology is thread-safe and immutable.
031: *
032: * @author Brian S O'Neill
033: * @since 1.0
034: */
035: public abstract class AssembledChronology extends BaseChronology {
036:
037: private static final long serialVersionUID = -6728465968995518215L;
038:
039: private final Chronology iBase;
040: private final Object iParam;
041:
042: private transient DurationField iMillis;
043: private transient DurationField iSeconds;
044: private transient DurationField iMinutes;
045: private transient DurationField iHours;
046: private transient DurationField iHalfdays;
047:
048: private transient DurationField iDays;
049: private transient DurationField iWeeks;
050: private transient DurationField iWeekyears;
051: private transient DurationField iMonths;
052: private transient DurationField iYears;
053: private transient DurationField iCenturies;
054: private transient DurationField iEras;
055:
056: private transient DateTimeField iMillisOfSecond;
057: private transient DateTimeField iMillisOfDay;
058: private transient DateTimeField iSecondOfMinute;
059: private transient DateTimeField iSecondOfDay;
060: private transient DateTimeField iMinuteOfHour;
061: private transient DateTimeField iMinuteOfDay;
062: private transient DateTimeField iHourOfDay;
063: private transient DateTimeField iClockhourOfDay;
064: private transient DateTimeField iHourOfHalfday;
065: private transient DateTimeField iClockhourOfHalfday;
066: private transient DateTimeField iHalfdayOfDay;
067:
068: private transient DateTimeField iDayOfWeek;
069: private transient DateTimeField iDayOfMonth;
070: private transient DateTimeField iDayOfYear;
071: private transient DateTimeField iWeekOfWeekyear;
072: private transient DateTimeField iWeekyear;
073: private transient DateTimeField iWeekyearOfCentury;
074: private transient DateTimeField iMonthOfYear;
075: private transient DateTimeField iYear;
076: private transient DateTimeField iYearOfEra;
077: private transient DateTimeField iYearOfCentury;
078: private transient DateTimeField iCenturyOfEra;
079: private transient DateTimeField iEra;
080:
081: // Bit set determines which base fields are used
082: // bit 1 set: hourOfDay, minuteOfHour, secondOfMinute, and millisOfSecond fields
083: // bit 2 set: millisOfDayField
084: // bit 3 set: year, monthOfYear, and dayOfMonth fields
085: private transient int iBaseFlags;
086:
087: /**
088: * Constructor calls the assemble method, enabling subclasses to define its
089: * supported fields. If a base chronology is supplied, the field set
090: * initially contains references to each base chronology field.
091: * <p>
092: * Other methods in this class will delegate to the base chronology, if it
093: * can be determined that the base chronology will produce the same results
094: * as AbstractChronology.
095: *
096: * @param base optional base chronology to copy initial fields from
097: * @param param optional param object avalable for assemble method
098: */
099: protected AssembledChronology(Chronology base, Object param) {
100: iBase = base;
101: iParam = param;
102: setFields();
103: }
104:
105: public DateTimeZone getZone() {
106: Chronology base;
107: if ((base = iBase) != null) {
108: return base.getZone();
109: }
110: return null;
111: }
112:
113: public long getDateTimeMillis(int year, int monthOfYear,
114: int dayOfMonth, int millisOfDay)
115: throws IllegalArgumentException {
116: Chronology base;
117: if ((base = iBase) != null && (iBaseFlags & 6) == 6) {
118: // Only call specialized implementation if applicable fields are the same.
119: return base.getDateTimeMillis(year, monthOfYear,
120: dayOfMonth, millisOfDay);
121: }
122: return super .getDateTimeMillis(year, monthOfYear, dayOfMonth,
123: millisOfDay);
124: }
125:
126: public long getDateTimeMillis(int year, int monthOfYear,
127: int dayOfMonth, int hourOfDay, int minuteOfHour,
128: int secondOfMinute, int millisOfSecond)
129: throws IllegalArgumentException {
130: Chronology base;
131: if ((base = iBase) != null && (iBaseFlags & 5) == 5) {
132: // Only call specialized implementation if applicable fields are the same.
133: return base.getDateTimeMillis(year, monthOfYear,
134: dayOfMonth, hourOfDay, minuteOfHour,
135: secondOfMinute, millisOfSecond);
136: }
137: return super
138: .getDateTimeMillis(year, monthOfYear, dayOfMonth,
139: hourOfDay, minuteOfHour, secondOfMinute,
140: millisOfSecond);
141: }
142:
143: public long getDateTimeMillis(long instant, int hourOfDay,
144: int minuteOfHour, int secondOfMinute, int millisOfSecond)
145: throws IllegalArgumentException {
146: Chronology base;
147: if ((base = iBase) != null && (iBaseFlags & 1) == 1) {
148: // Only call specialized implementation if applicable fields are the same.
149: return base.getDateTimeMillis(instant, hourOfDay,
150: minuteOfHour, secondOfMinute, millisOfSecond);
151: }
152: return super .getDateTimeMillis(instant, hourOfDay,
153: minuteOfHour, secondOfMinute, millisOfSecond);
154: }
155:
156: public final DurationField millis() {
157: return iMillis;
158: }
159:
160: public final DateTimeField millisOfSecond() {
161: return iMillisOfSecond;
162: }
163:
164: public final DateTimeField millisOfDay() {
165: return iMillisOfDay;
166: }
167:
168: public final DurationField seconds() {
169: return iSeconds;
170: }
171:
172: public final DateTimeField secondOfMinute() {
173: return iSecondOfMinute;
174: }
175:
176: public final DateTimeField secondOfDay() {
177: return iSecondOfDay;
178: }
179:
180: public final DurationField minutes() {
181: return iMinutes;
182: }
183:
184: public final DateTimeField minuteOfHour() {
185: return iMinuteOfHour;
186: }
187:
188: public final DateTimeField minuteOfDay() {
189: return iMinuteOfDay;
190: }
191:
192: public final DurationField hours() {
193: return iHours;
194: }
195:
196: public final DateTimeField hourOfDay() {
197: return iHourOfDay;
198: }
199:
200: public final DateTimeField clockhourOfDay() {
201: return iClockhourOfDay;
202: }
203:
204: public final DurationField halfdays() {
205: return iHalfdays;
206: }
207:
208: public final DateTimeField hourOfHalfday() {
209: return iHourOfHalfday;
210: }
211:
212: public final DateTimeField clockhourOfHalfday() {
213: return iClockhourOfHalfday;
214: }
215:
216: public final DateTimeField halfdayOfDay() {
217: return iHalfdayOfDay;
218: }
219:
220: public final DurationField days() {
221: return iDays;
222: }
223:
224: public final DateTimeField dayOfWeek() {
225: return iDayOfWeek;
226: }
227:
228: public final DateTimeField dayOfMonth() {
229: return iDayOfMonth;
230: }
231:
232: public final DateTimeField dayOfYear() {
233: return iDayOfYear;
234: }
235:
236: public final DurationField weeks() {
237: return iWeeks;
238: }
239:
240: public final DateTimeField weekOfWeekyear() {
241: return iWeekOfWeekyear;
242: }
243:
244: public final DurationField weekyears() {
245: return iWeekyears;
246: }
247:
248: public final DateTimeField weekyear() {
249: return iWeekyear;
250: }
251:
252: public final DateTimeField weekyearOfCentury() {
253: return iWeekyearOfCentury;
254: }
255:
256: public final DurationField months() {
257: return iMonths;
258: }
259:
260: public final DateTimeField monthOfYear() {
261: return iMonthOfYear;
262: }
263:
264: public final DurationField years() {
265: return iYears;
266: }
267:
268: public final DateTimeField year() {
269: return iYear;
270: }
271:
272: public final DateTimeField yearOfEra() {
273: return iYearOfEra;
274: }
275:
276: public final DateTimeField yearOfCentury() {
277: return iYearOfCentury;
278: }
279:
280: public final DurationField centuries() {
281: return iCenturies;
282: }
283:
284: public final DateTimeField centuryOfEra() {
285: return iCenturyOfEra;
286: }
287:
288: public final DurationField eras() {
289: return iEras;
290: }
291:
292: public final DateTimeField era() {
293: return iEra;
294: }
295:
296: /**
297: * Invoked by the constructor and after deserialization to allow subclasses
298: * to define all of its supported fields. All unset fields default to
299: * unsupported instances.
300: *
301: * @param fields container of fields
302: */
303: protected abstract void assemble(Fields fields);
304:
305: /**
306: * Returns the same base chronology as passed into the constructor.
307: */
308: protected final Chronology getBase() {
309: return iBase;
310: }
311:
312: /**
313: * Returns the same param object as passed into the constructor.
314: */
315: protected final Object getParam() {
316: return iParam;
317: }
318:
319: private void setFields() {
320: Fields fields = new Fields();
321: if (iBase != null) {
322: fields.copyFieldsFrom(iBase);
323: }
324: assemble(fields);
325:
326: {
327: DurationField f;
328: iMillis = (f = fields.millis) != null ? f : super .millis();
329: iSeconds = (f = fields.seconds) != null ? f : super
330: .seconds();
331: iMinutes = (f = fields.minutes) != null ? f : super
332: .minutes();
333: iHours = (f = fields.hours) != null ? f : super .hours();
334: iHalfdays = (f = fields.halfdays) != null ? f : super
335: .halfdays();
336: iDays = (f = fields.days) != null ? f : super .days();
337: iWeeks = (f = fields.weeks) != null ? f : super .weeks();
338: iWeekyears = (f = fields.weekyears) != null ? f : super
339: .weekyears();
340: iMonths = (f = fields.months) != null ? f : super .months();
341: iYears = (f = fields.years) != null ? f : super .years();
342: iCenturies = (f = fields.centuries) != null ? f : super
343: .centuries();
344: iEras = (f = fields.eras) != null ? f : super .eras();
345: }
346:
347: {
348: DateTimeField f;
349: iMillisOfSecond = (f = fields.millisOfSecond) != null ? f
350: : super .millisOfSecond();
351: iMillisOfDay = (f = fields.millisOfDay) != null ? f : super
352: .millisOfDay();
353: iSecondOfMinute = (f = fields.secondOfMinute) != null ? f
354: : super .secondOfMinute();
355: iSecondOfDay = (f = fields.secondOfDay) != null ? f : super
356: .secondOfDay();
357: iMinuteOfHour = (f = fields.minuteOfHour) != null ? f
358: : super .minuteOfHour();
359: iMinuteOfDay = (f = fields.minuteOfDay) != null ? f : super
360: .minuteOfDay();
361: iHourOfDay = (f = fields.hourOfDay) != null ? f : super
362: .hourOfDay();
363: iClockhourOfDay = (f = fields.clockhourOfDay) != null ? f
364: : super .clockhourOfDay();
365: iHourOfHalfday = (f = fields.hourOfHalfday) != null ? f
366: : super .hourOfHalfday();
367: iClockhourOfHalfday = (f = fields.clockhourOfHalfday) != null ? f
368: : super .clockhourOfHalfday();
369: iHalfdayOfDay = (f = fields.halfdayOfDay) != null ? f
370: : super .halfdayOfDay();
371: iDayOfWeek = (f = fields.dayOfWeek) != null ? f : super
372: .dayOfWeek();
373: iDayOfMonth = (f = fields.dayOfMonth) != null ? f : super
374: .dayOfMonth();
375: iDayOfYear = (f = fields.dayOfYear) != null ? f : super
376: .dayOfYear();
377: iWeekOfWeekyear = (f = fields.weekOfWeekyear) != null ? f
378: : super .weekOfWeekyear();
379: iWeekyear = (f = fields.weekyear) != null ? f : super
380: .weekyear();
381: iWeekyearOfCentury = (f = fields.weekyearOfCentury) != null ? f
382: : super .weekyearOfCentury();
383: iMonthOfYear = (f = fields.monthOfYear) != null ? f : super
384: .monthOfYear();
385: iYear = (f = fields.year) != null ? f : super .year();
386: iYearOfEra = (f = fields.yearOfEra) != null ? f : super
387: .yearOfEra();
388: iYearOfCentury = (f = fields.yearOfCentury) != null ? f
389: : super .yearOfCentury();
390: iCenturyOfEra = (f = fields.centuryOfEra) != null ? f
391: : super .centuryOfEra();
392: iEra = (f = fields.era) != null ? f : super .era();
393: }
394:
395: int flags;
396: if (iBase == null) {
397: flags = 0;
398: } else {
399: flags = ((iHourOfDay == iBase.hourOfDay()
400: && iMinuteOfHour == iBase.minuteOfHour()
401: && iSecondOfMinute == iBase.secondOfMinute() && iMillisOfSecond == iBase
402: .millisOfSecond()) ? 1 : 0)
403: |
404:
405: ((iMillisOfDay == iBase.millisOfDay()) ? 2 : 0)
406: |
407:
408: ((iYear == iBase.year()
409: && iMonthOfYear == iBase.monthOfYear() && iDayOfMonth == iBase
410: .dayOfMonth()) ? 4 : 0);
411: }
412:
413: iBaseFlags = flags;
414: }
415:
416: private void readObject(ObjectInputStream in) throws IOException,
417: ClassNotFoundException {
418: in.defaultReadObject();
419: setFields();
420: }
421:
422: /**
423: * A container of fields used for assembling a chronology.
424: */
425: public static final class Fields {
426: public DurationField millis;
427: public DurationField seconds;
428: public DurationField minutes;
429: public DurationField hours;
430: public DurationField halfdays;
431:
432: public DurationField days;
433: public DurationField weeks;
434: public DurationField weekyears;
435: public DurationField months;
436: public DurationField years;
437: public DurationField centuries;
438: public DurationField eras;
439:
440: public DateTimeField millisOfSecond;
441: public DateTimeField millisOfDay;
442: public DateTimeField secondOfMinute;
443: public DateTimeField secondOfDay;
444: public DateTimeField minuteOfHour;
445: public DateTimeField minuteOfDay;
446: public DateTimeField hourOfDay;
447: public DateTimeField clockhourOfDay;
448: public DateTimeField hourOfHalfday;
449: public DateTimeField clockhourOfHalfday;
450: public DateTimeField halfdayOfDay;
451:
452: public DateTimeField dayOfWeek;
453: public DateTimeField dayOfMonth;
454: public DateTimeField dayOfYear;
455: public DateTimeField weekOfWeekyear;
456: public DateTimeField weekyear;
457: public DateTimeField weekyearOfCentury;
458: public DateTimeField monthOfYear;
459: public DateTimeField year;
460: public DateTimeField yearOfEra;
461: public DateTimeField yearOfCentury;
462: public DateTimeField centuryOfEra;
463: public DateTimeField era;
464:
465: Fields() {
466: }
467:
468: /**
469: * Copy the supported fields from a chronology into this container.
470: */
471: public void copyFieldsFrom(Chronology chrono) {
472: {
473: DurationField f;
474: if (isSupported(f = chrono.millis())) {
475: millis = f;
476: }
477: if (isSupported(f = chrono.seconds())) {
478: seconds = f;
479: }
480: if (isSupported(f = chrono.minutes())) {
481: minutes = f;
482: }
483: if (isSupported(f = chrono.hours())) {
484: hours = f;
485: }
486: if (isSupported(f = chrono.halfdays())) {
487: halfdays = f;
488: }
489: if (isSupported(f = chrono.days())) {
490: days = f;
491: }
492: if (isSupported(f = chrono.weeks())) {
493: weeks = f;
494: }
495: if (isSupported(f = chrono.weekyears())) {
496: weekyears = f;
497: }
498: if (isSupported(f = chrono.months())) {
499: months = f;
500: }
501: if (isSupported(f = chrono.years())) {
502: years = f;
503: }
504: if (isSupported(f = chrono.centuries())) {
505: centuries = f;
506: }
507: if (isSupported(f = chrono.eras())) {
508: eras = f;
509: }
510: }
511:
512: {
513: DateTimeField f;
514: if (isSupported(f = chrono.millisOfSecond())) {
515: millisOfSecond = f;
516: }
517: if (isSupported(f = chrono.millisOfDay())) {
518: millisOfDay = f;
519: }
520: if (isSupported(f = chrono.secondOfMinute())) {
521: secondOfMinute = f;
522: }
523: if (isSupported(f = chrono.secondOfDay())) {
524: secondOfDay = f;
525: }
526: if (isSupported(f = chrono.minuteOfHour())) {
527: minuteOfHour = f;
528: }
529: if (isSupported(f = chrono.minuteOfDay())) {
530: minuteOfDay = f;
531: }
532: if (isSupported(f = chrono.hourOfDay())) {
533: hourOfDay = f;
534: }
535: if (isSupported(f = chrono.clockhourOfDay())) {
536: clockhourOfDay = f;
537: }
538: if (isSupported(f = chrono.hourOfHalfday())) {
539: hourOfHalfday = f;
540: }
541: if (isSupported(f = chrono.clockhourOfHalfday())) {
542: clockhourOfHalfday = f;
543: }
544: if (isSupported(f = chrono.halfdayOfDay())) {
545: halfdayOfDay = f;
546: }
547: if (isSupported(f = chrono.dayOfWeek())) {
548: dayOfWeek = f;
549: }
550: if (isSupported(f = chrono.dayOfMonth())) {
551: dayOfMonth = f;
552: }
553: if (isSupported(f = chrono.dayOfYear())) {
554: dayOfYear = f;
555: }
556: if (isSupported(f = chrono.weekOfWeekyear())) {
557: weekOfWeekyear = f;
558: }
559: if (isSupported(f = chrono.weekyear())) {
560: weekyear = f;
561: }
562: if (isSupported(f = chrono.weekyearOfCentury())) {
563: weekyearOfCentury = f;
564: }
565: if (isSupported(f = chrono.monthOfYear())) {
566: monthOfYear = f;
567: }
568: if (isSupported(f = chrono.year())) {
569: year = f;
570: }
571: if (isSupported(f = chrono.yearOfEra())) {
572: yearOfEra = f;
573: }
574: if (isSupported(f = chrono.yearOfCentury())) {
575: yearOfCentury = f;
576: }
577: if (isSupported(f = chrono.centuryOfEra())) {
578: centuryOfEra = f;
579: }
580: if (isSupported(f = chrono.era())) {
581: era = f;
582: }
583: }
584: }
585:
586: private static boolean isSupported(DurationField field) {
587: return field == null ? false : field.isSupported();
588: }
589:
590: private static boolean isSupported(DateTimeField field) {
591: return field == null ? false : field.isSupported();
592: }
593: }
594: }
|