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, 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    }