View Javadoc

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.io.IOException;
19  import java.io.ObjectInputStream;
20  
21  import org.joda.time.Chronology;
22  import org.joda.time.DateTimeField;
23  import org.joda.time.DateTimeZone;
24  import org.joda.time.DurationField;
25  
26  /**
27   * Abstract Chronology that enables chronologies to be assembled from
28   * a container of fields.
29   * <p>
30   * AssembledChronology is thread-safe and immutable.
31   *
32   * @author Brian S O'Neill
33   * @since 1.0
34   */
35  public abstract class AssembledChronology extends BaseChronology {
36  
37      private static final long serialVersionUID = -6728465968995518215L;
38  
39      private final Chronology iBase;
40      private final Object iParam;
41  
42      private transient DurationField iMillis;
43      private transient DurationField iSeconds;
44      private transient DurationField iMinutes;
45      private transient DurationField iHours;
46      private transient DurationField iHalfdays;
47  
48      private transient DurationField iDays;
49      private transient DurationField iWeeks;
50      private transient DurationField iWeekyears;
51      private transient DurationField iMonths;
52      private transient DurationField iYears;
53      private transient DurationField iCenturies;
54      private transient DurationField iEras;
55  
56      private transient DateTimeField iMillisOfSecond;
57      private transient DateTimeField iMillisOfDay;
58      private transient DateTimeField iSecondOfMinute;
59      private transient DateTimeField iSecondOfDay;
60      private transient DateTimeField iMinuteOfHour;
61      private transient DateTimeField iMinuteOfDay;
62      private transient DateTimeField iHourOfDay;
63      private transient DateTimeField iClockhourOfDay;
64      private transient DateTimeField iHourOfHalfday;
65      private transient DateTimeField iClockhourOfHalfday;
66      private transient DateTimeField iHalfdayOfDay;
67  
68      private transient DateTimeField iDayOfWeek;
69      private transient DateTimeField iDayOfMonth;
70      private transient DateTimeField iDayOfYear;
71      private transient DateTimeField iWeekOfWeekyear;
72      private transient DateTimeField iWeekyear;
73      private transient DateTimeField iWeekyearOfCentury;
74      private transient DateTimeField iMonthOfYear;
75      private transient DateTimeField iYear;
76      private transient DateTimeField iYearOfEra;
77      private transient DateTimeField iYearOfCentury;
78      private transient DateTimeField iCenturyOfEra;
79      private transient DateTimeField iEra;
80  
81      // Bit set determines which base fields are used
82      // bit 1 set: hourOfDay, minuteOfHour, secondOfMinute, and millisOfSecond fields
83      // bit 2 set: millisOfDayField
84      // bit 3 set: year, monthOfYear, and dayOfMonth fields
85      private transient int iBaseFlags;
86  
87      /**
88       * Constructor calls the assemble method, enabling subclasses to define its
89       * supported fields. If a base chronology is supplied, the field set
90       * initially contains references to each base chronology field.
91       * <p>
92       * Other methods in this class will delegate to the base chronology, if it
93       * can be determined that the base chronology will produce the same results
94       * as AbstractChronology.
95       *
96       * @param base optional base chronology to copy initial fields from
97       * @param param optional param object avalable for assemble method
98       */
99      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, int dayOfMonth,
114                                   int millisOfDay)
115         throws IllegalArgumentException
116     {
117         Chronology base;
118         if ((base = iBase) != null && (iBaseFlags & 6) == 6) {
119             // Only call specialized implementation if applicable fields are the same.
120             return base.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
121         }
122         return super.getDateTimeMillis(year, monthOfYear, dayOfMonth, millisOfDay);
123     }
124 
125     public long getDateTimeMillis(int year, int monthOfYear, int dayOfMonth,
126                                   int hourOfDay, int minuteOfHour,
127                                   int secondOfMinute, int millisOfSecond)
128         throws IllegalArgumentException
129     {
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, dayOfMonth,
134                                           hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
135         }
136         return super.getDateTimeMillis(year, monthOfYear, dayOfMonth,
137                                        hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
138     }
139 
140     public long getDateTimeMillis(long instant,
141                                   int hourOfDay, int minuteOfHour,
142                                   int secondOfMinute, int millisOfSecond)
143         throws IllegalArgumentException
144     {
145         Chronology base;
146         if ((base = iBase) != null && (iBaseFlags & 1) == 1) {
147             // Only call specialized implementation if applicable fields are the same.
148             return base.getDateTimeMillis
149                 (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
150         }
151         return super.getDateTimeMillis
152             (instant, hourOfDay, minuteOfHour, secondOfMinute, millisOfSecond);
153     }
154 
155     public final DurationField millis() {
156         return iMillis;
157     }
158 
159     public final DateTimeField millisOfSecond() {
160         return iMillisOfSecond;
161     }
162 
163     public final DateTimeField millisOfDay() {
164         return iMillisOfDay;
165     }
166 
167     public final DurationField seconds() {
168         return iSeconds;
169     }
170 
171     public final DateTimeField secondOfMinute() {
172         return iSecondOfMinute;
173     }
174 
175     public final DateTimeField secondOfDay() {
176         return iSecondOfDay;
177     }
178 
179     public final DurationField minutes() {
180         return iMinutes;
181     }
182 
183     public final DateTimeField minuteOfHour() {
184         return iMinuteOfHour;
185     }
186 
187     public final DateTimeField minuteOfDay() {
188         return iMinuteOfDay;
189     }
190 
191     public final DurationField hours() {
192         return iHours;
193     }
194 
195     public final DateTimeField hourOfDay() {
196         return iHourOfDay;
197     }
198 
199     public final DateTimeField clockhourOfDay() {
200         return iClockhourOfDay;
201     }
202 
203     public final DurationField halfdays() {
204         return iHalfdays;
205     }
206 
207     public final DateTimeField hourOfHalfday() {
208         return iHourOfHalfday;
209     }
210 
211     public final DateTimeField clockhourOfHalfday() {
212         return iClockhourOfHalfday;
213     }
214 
215     public final DateTimeField halfdayOfDay() {
216         return iHalfdayOfDay;
217     }
218 
219     public final DurationField days() {
220         return iDays;
221     }
222 
223     public final DateTimeField dayOfWeek() {
224         return iDayOfWeek;
225     }
226 
227     public final DateTimeField dayOfMonth() {
228         return iDayOfMonth;
229     }
230 
231     public final DateTimeField dayOfYear() {
232         return iDayOfYear;
233     }
234 
235     public final DurationField weeks() {
236         return iWeeks;
237     }
238 
239     public final DateTimeField weekOfWeekyear() {
240         return iWeekOfWeekyear;
241     }
242 
243     public final DurationField weekyears() {
244         return iWeekyears;
245     }
246 
247     public final DateTimeField weekyear() {
248         return iWeekyear;
249     }
250 
251     public final DateTimeField weekyearOfCentury() {
252         return iWeekyearOfCentury;
253     }
254 
255     public final DurationField months() {
256         return iMonths;
257     }
258 
259     public final DateTimeField monthOfYear() {
260         return iMonthOfYear;
261     }
262 
263     public final DurationField years() {
264         return iYears;
265     }
266 
267     public final DateTimeField year() {
268         return iYear;
269     }
270 
271     public final DateTimeField yearOfEra() {
272         return iYearOfEra;
273     }
274 
275     public final DateTimeField yearOfCentury() {
276         return iYearOfCentury;
277     }
278 
279     public final DurationField centuries() {
280         return iCenturies;
281     }
282 
283     public final DateTimeField centuryOfEra() {
284         return iCenturyOfEra;
285     }
286 
287     public final DurationField eras() {
288         return iEras;
289     }
290 
291     public final DateTimeField era() {
292         return iEra;
293     }
294 
295     /**
296      * Invoked by the constructor and after deserialization to allow subclasses
297      * to define all of its supported fields. All unset fields default to
298      * unsupported instances.
299      *
300      * @param fields container of fields
301      */
302     protected abstract void assemble(Fields fields);
303 
304     /**
305      * Returns the same base chronology as passed into the constructor.
306      */
307     protected final Chronology getBase() {
308         return iBase;
309     }
310 
311     /**
312      * Returns the same param object as passed into the constructor.
313      */
314     protected final Object getParam() {
315         return iParam;
316     }
317 
318     private void setFields() {
319         Fields fields = new Fields();
320         if (iBase != null) {
321             fields.copyFieldsFrom(iBase);
322         }
323         assemble(fields);
324 
325         {
326             DurationField f;
327             iMillis    = (f = fields.millis)    != null ? f : super.millis();
328             iSeconds   = (f = fields.seconds)   != null ? f : super.seconds();
329             iMinutes   = (f = fields.minutes)   != null ? f : super.minutes();
330             iHours     = (f = fields.hours)     != null ? f : super.hours();
331             iHalfdays  = (f = fields.halfdays)  != null ? f : super.halfdays();
332             iDays      = (f = fields.days)      != null ? f : super.days();
333             iWeeks     = (f = fields.weeks)     != null ? f : super.weeks();
334             iWeekyears = (f = fields.weekyears) != null ? f : super.weekyears();
335             iMonths    = (f = fields.months)    != null ? f : super.months();
336             iYears     = (f = fields.years)     != null ? f : super.years();
337             iCenturies = (f = fields.centuries) != null ? f : super.centuries();
338             iEras      = (f = fields.eras)      != null ? f : super.eras();
339         }
340 
341         {
342             DateTimeField f;
343             iMillisOfSecond     = (f = fields.millisOfSecond)     != null ? f : super.millisOfSecond();
344             iMillisOfDay        = (f = fields.millisOfDay)        != null ? f : super.millisOfDay();
345             iSecondOfMinute     = (f = fields.secondOfMinute)     != null ? f : super.secondOfMinute();
346             iSecondOfDay        = (f = fields.secondOfDay)        != null ? f : super.secondOfDay();
347             iMinuteOfHour       = (f = fields.minuteOfHour)       != null ? f : super.minuteOfHour();
348             iMinuteOfDay        = (f = fields.minuteOfDay)        != null ? f : super.minuteOfDay();
349             iHourOfDay          = (f = fields.hourOfDay)          != null ? f : super.hourOfDay();
350             iClockhourOfDay     = (f = fields.clockhourOfDay)     != null ? f : super.clockhourOfDay();
351             iHourOfHalfday      = (f = fields.hourOfHalfday)      != null ? f : super.hourOfHalfday();
352             iClockhourOfHalfday = (f = fields.clockhourOfHalfday) != null ? f : super.clockhourOfHalfday();
353             iHalfdayOfDay       = (f = fields.halfdayOfDay)       != null ? f : super.halfdayOfDay();
354             iDayOfWeek          = (f = fields.dayOfWeek)          != null ? f : super.dayOfWeek();
355             iDayOfMonth         = (f = fields.dayOfMonth)         != null ? f : super.dayOfMonth();
356             iDayOfYear          = (f = fields.dayOfYear)          != null ? f : super.dayOfYear();
357             iWeekOfWeekyear     = (f = fields.weekOfWeekyear)     != null ? f : super.weekOfWeekyear();
358             iWeekyear           = (f = fields.weekyear)           != null ? f : super.weekyear();
359             iWeekyearOfCentury  = (f = fields.weekyearOfCentury)  != null ? f : super.weekyearOfCentury();
360             iMonthOfYear        = (f = fields.monthOfYear)        != null ? f : super.monthOfYear();
361             iYear               = (f = fields.year)               != null ? f : super.year();
362             iYearOfEra          = (f = fields.yearOfEra)          != null ? f : super.yearOfEra();
363             iYearOfCentury      = (f = fields.yearOfCentury)      != null ? f : super.yearOfCentury();
364             iCenturyOfEra       = (f = fields.centuryOfEra)       != null ? f : super.centuryOfEra();
365             iEra                = (f = fields.era)                != null ? f : super.era();
366         }
367 
368         int flags;
369         if (iBase == null) {
370             flags = 0;
371         } else {
372             flags = 
373                 ((iHourOfDay      == iBase.hourOfDay()      &&
374                   iMinuteOfHour   == iBase.minuteOfHour()   &&
375                   iSecondOfMinute == iBase.secondOfMinute() &&
376                   iMillisOfSecond == iBase.millisOfSecond()   ) ? 1 : 0) |
377 
378                 ((iMillisOfDay == iBase.millisOfDay()) ? 2 : 0) |
379 
380                 ((iYear        == iBase.year()        &&
381                   iMonthOfYear == iBase.monthOfYear() &&
382                   iDayOfMonth  == iBase.dayOfMonth()    ) ? 4 : 0);
383         }
384 
385         iBaseFlags = flags;
386     }
387 
388     private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
389         in.defaultReadObject();
390         setFields();
391     }
392 
393     /**
394      * A container of fields used for assembling a chronology.
395      */
396     public static final class Fields {
397         public DurationField millis;
398         public DurationField seconds;
399         public DurationField minutes;
400         public DurationField hours;
401         public DurationField halfdays;
402     
403         public DurationField days;
404         public DurationField weeks;
405         public DurationField weekyears;
406         public DurationField months;
407         public DurationField years;
408         public DurationField centuries;
409         public DurationField eras;
410     
411         public DateTimeField millisOfSecond;
412         public DateTimeField millisOfDay;
413         public DateTimeField secondOfMinute;
414         public DateTimeField secondOfDay;
415         public DateTimeField minuteOfHour;
416         public DateTimeField minuteOfDay;
417         public DateTimeField hourOfDay;
418         public DateTimeField clockhourOfDay;
419         public DateTimeField hourOfHalfday;
420         public DateTimeField clockhourOfHalfday;
421         public DateTimeField halfdayOfDay;
422     
423         public DateTimeField dayOfWeek;
424         public DateTimeField dayOfMonth;
425         public DateTimeField dayOfYear;
426         public DateTimeField weekOfWeekyear;
427         public DateTimeField weekyear;
428         public DateTimeField weekyearOfCentury;
429         public DateTimeField monthOfYear;
430         public DateTimeField year;
431         public DateTimeField yearOfEra;
432         public DateTimeField yearOfCentury;
433         public DateTimeField centuryOfEra;
434         public DateTimeField era;
435 
436         Fields() {
437         }
438 
439         /**
440          * Copy the supported fields from a chronology into this container.
441          */
442         public void copyFieldsFrom(Chronology chrono) {
443             {
444                 DurationField f;
445                 if (isSupported(f = chrono.millis())) {
446                     millis = f;
447                 }
448                 if (isSupported(f = chrono.seconds())) {
449                     seconds = f;
450                 }
451                 if (isSupported(f = chrono.minutes())) {
452                     minutes = f;
453                 }
454                 if (isSupported(f = chrono.hours())) {
455                     hours = f;
456                 }
457                 if (isSupported(f = chrono.halfdays())) {
458                     halfdays = f;
459                 }
460                 if (isSupported(f = chrono.days())) {
461                     days = f;
462                 }
463                 if (isSupported(f = chrono.weeks())) {
464                     weeks = f;
465                 }
466                 if (isSupported(f = chrono.weekyears())) {
467                     weekyears = f;
468                 }
469                 if (isSupported(f = chrono.months())) {
470                     months = f;
471                 }
472                 if (isSupported(f = chrono.years())) {
473                     years = f;
474                 }
475                 if (isSupported(f = chrono.centuries())) {
476                     centuries = f;
477                 }
478                 if (isSupported(f = chrono.eras())) {
479                     eras = f;
480                 }
481             }
482 
483             {
484                 DateTimeField f;
485                 if (isSupported(f = chrono.millisOfSecond())) {
486                     millisOfSecond = f;
487                 }
488                 if (isSupported(f = chrono.millisOfDay())) {
489                     millisOfDay = f;
490                 }
491                 if (isSupported(f = chrono.secondOfMinute())) {
492                     secondOfMinute = f;
493                 }
494                 if (isSupported(f = chrono.secondOfDay())) {
495                     secondOfDay = f;
496                 }
497                 if (isSupported(f = chrono.minuteOfHour())) {
498                     minuteOfHour = f;
499                 }
500                 if (isSupported(f = chrono.minuteOfDay())) {
501                     minuteOfDay = f;
502                 }
503                 if (isSupported(f = chrono.hourOfDay())) {
504                     hourOfDay = f;
505                 }
506                 if (isSupported(f = chrono.clockhourOfDay())) {
507                     clockhourOfDay = f;
508                 }
509                 if (isSupported(f = chrono.hourOfHalfday())) {
510                     hourOfHalfday = f;
511                 }
512                 if (isSupported(f = chrono.clockhourOfHalfday())) {
513                     clockhourOfHalfday = f;
514                 }
515                 if (isSupported(f = chrono.halfdayOfDay())) {
516                     halfdayOfDay = f;
517                 }
518                 if (isSupported(f = chrono.dayOfWeek())) {
519                     dayOfWeek = f;
520                 }
521                 if (isSupported(f = chrono.dayOfMonth())) {
522                     dayOfMonth = f;
523                 }
524                 if (isSupported(f = chrono.dayOfYear())) {
525                     dayOfYear = f;
526                 }
527                 if (isSupported(f = chrono.weekOfWeekyear())) {
528                     weekOfWeekyear = f;
529                 }
530                 if (isSupported(f = chrono.weekyear())) {
531                     weekyear = f;
532                 }
533                 if (isSupported(f = chrono.weekyearOfCentury())) {
534                     weekyearOfCentury = f;
535                 }
536                 if (isSupported(f = chrono.monthOfYear())) {
537                     monthOfYear = f;
538                 }
539                 if (isSupported(f = chrono.year())) {
540                     year = f;
541                 }
542                 if (isSupported(f = chrono.yearOfEra())) {
543                     yearOfEra = f;
544                 }
545                 if (isSupported(f = chrono.yearOfCentury())) {
546                     yearOfCentury = f;
547                 }
548                 if (isSupported(f = chrono.centuryOfEra())) {
549                     centuryOfEra = f;
550                 }
551                 if (isSupported(f = chrono.era())) {
552                     era = f;
553                 }
554             }
555         }
556 
557         private static boolean isSupported(DurationField field) {
558             return field == null ? false : field.isSupported();
559         }
560 
561         private static boolean isSupported(DateTimeField field) {
562             return field == null ? false : field.isSupported();
563         }
564     }
565 }