Home | History | Annotate | Download | only in jdkadapter
      1 /*
      2  *******************************************************************************
      3  * Copyright (C) 2008, International Business Machines Corporation and         *
      4  * others. All Rights Reserved.                                                *
      5  *******************************************************************************
      6  */
      7 package com.ibm.icu.impl.jdkadapter;
      8 
      9 import java.util.HashMap;
     10 import java.util.Locale;
     11 import java.util.Map;
     12 import java.util.TimeZone;
     13 
     14 import com.ibm.icu.impl.icuadapter.TimeZoneJDK;
     15 import com.ibm.icu.text.DateFormatSymbols;
     16 import com.ibm.icu.util.Calendar;
     17 
     18 /**
     19  * CalendarICU is an adapter class which wraps ICU4J Calendar and
     20  * implements java.util.Calendar APIs.
     21  */
     22 public class CalendarICU extends java.util.Calendar {
     23 
     24     private static final long serialVersionUID = -8641226371713600671L;
     25 
     26     private Calendar fIcuCal;
     27 
     28     private CalendarICU(Calendar icuCal) {
     29         fIcuCal = icuCal;
     30         init();
     31     }
     32 
     33     public static java.util.Calendar wrap(Calendar icuCal) {
     34         return new CalendarICU(icuCal);
     35     }
     36 
     37     public Calendar unwrap() {
     38         sync();
     39         return fIcuCal;
     40     }
     41 
     42     @Override
     43     public void add(int field, int amount) {
     44         sync();
     45         fIcuCal.add(field, amount);
     46     }
     47 
     48     // Note:    We do not need to override followings.  These methods
     49     //          call int compareTo(Calendar anotherCalendar) and we
     50     //          override the method.
     51     //public boolean after(Object when)
     52     //public boolean before(Object when)
     53 
     54     // Note:    Jeez!  These methods are final and we cannot override them.
     55     //          We do not want to rewrite ICU Calendar implementation classes
     56     //          as subclasses of java.util.Calendar.  This adapter class
     57     //          wraps an ICU Calendar instance and the calendar calculation
     58     //          is actually done independently from java.util.Calendar
     59     //          implementation.  Thus, we need to monitor the status of
     60     //          superclass fields in some methods and call ICU Calendar's
     61     //          clear if superclass clear update the status of superclass's
     62     //          calendar fields.  See private void sync().
     63     //public void clear()
     64     //public void clear(int field)
     65 
     66     @Override
     67     public Object clone() {
     68         sync();
     69         CalendarICU other = (CalendarICU)super.clone();
     70         other.fIcuCal = (Calendar)fIcuCal.clone();
     71         return other;
     72     }
     73 
     74     public int compareTo(Calendar anotherCalendar)  {
     75         sync();
     76         long thisMillis = getTimeInMillis();
     77         long otherMillis = anotherCalendar.getTimeInMillis();
     78         return thisMillis > otherMillis ? 1 : (thisMillis == otherMillis ? 0 : -1);
     79     }
     80 
     81     // Note:    These methods are supposed to be implemented by java.util.Calendar
     82     //          subclasses.  But we actually use a instance of ICU Calendar
     83     //          for all calendar calculation, we do nothing here.
     84     @Override
     85     protected void complete() {}
     86     @Override
     87     protected void computeFields() {}
     88     @Override
     89     protected void computeTime() {}
     90 
     91     @Override
     92     public boolean equals(Object obj) {
     93         if (obj instanceof CalendarICU) {
     94             sync();
     95             return ((CalendarICU)obj).fIcuCal.equals(fIcuCal);
     96         }
     97         return false;
     98     }
     99 
    100     @Override
    101     public int get(int field) {
    102         sync();
    103         return fIcuCal.get(field);
    104     }
    105 
    106     @Override
    107     public int getActualMaximum(int field) {
    108         return fIcuCal.getActualMaximum(field);
    109     }
    110 
    111     @Override
    112     public int getActualMinimum(int field) {
    113         return fIcuCal.getActualMinimum(field);
    114     }
    115 
    116     @Override
    117     public String getDisplayName(int field, int style, Locale locale) {
    118         if (field < 0 || field >= FIELD_COUNT || (style != SHORT && style != LONG && style != ALL_STYLES)) {
    119             throw new IllegalArgumentException("Bad field or style.");
    120         }
    121         DateFormatSymbols dfs = DateFormatSymbols.getInstance(locale);
    122         String[] array = getFieldStrings(field, style, dfs);
    123         if (array != null) {
    124             int fieldVal = get(field);
    125             if (fieldVal < array.length) {
    126                 return array[fieldVal];
    127             }
    128         }
    129         return null;
    130     }
    131 
    132     @Override
    133     public Map<String,Integer> getDisplayNames(int field, int style, Locale locale) {
    134         if (field < 0 || field >= FIELD_COUNT || (style != SHORT && style != LONG && style != ALL_STYLES)) {
    135             throw new IllegalArgumentException("Bad field or style.");
    136         }
    137         DateFormatSymbols dfs = DateFormatSymbols.getInstance(locale);
    138         if (style != ALL_STYLES) {
    139             return getFieldStringsMap(field, style, dfs);
    140         }
    141 
    142         Map<String,Integer> result = getFieldStringsMap(field, SHORT, dfs);
    143         if (result == null) {
    144             return null;
    145         }
    146         if (field == MONTH || field == DAY_OF_WEEK) {
    147             Map<String,Integer> longMap = getFieldStringsMap(field, LONG, dfs);
    148             if (longMap != null) {
    149                 result.putAll(longMap);
    150             }
    151         }
    152         return result;
    153     }
    154 
    155     @Override
    156     public int getGreatestMinimum(int field) {
    157         return fIcuCal.getGreatestMinimum(field);
    158     }
    159 
    160     @Override
    161     public int getLeastMaximum(int field) {
    162         return fIcuCal.getLeastMaximum(field);
    163     }
    164 
    165     @Override
    166     public int getMaximum(int field) {
    167         return fIcuCal.getMaximum(field);
    168     }
    169 
    170     @Override
    171     public int getMinimalDaysInFirstWeek() {
    172         return fIcuCal.getMinimalDaysInFirstWeek();
    173     }
    174 
    175     @Override
    176     public int getMinimum(int field) {
    177         return fIcuCal.getMinimum(field);
    178     }
    179 
    180     // Note:    getTime() calls getTimeInMillis()
    181     //public Date getTime()
    182 
    183     @Override
    184     public long getTimeInMillis() {
    185         sync();
    186         return fIcuCal.getTimeInMillis();
    187     }
    188 
    189     @Override
    190     public TimeZone getTimeZone() {
    191         return TimeZoneICU.wrap(fIcuCal.getTimeZone());
    192     }
    193 
    194     @Override
    195     public int hashCode() {
    196         sync();
    197         return fIcuCal.hashCode();
    198     }
    199 
    200     //protected int internalGet(int field)
    201 
    202     @Override
    203     public boolean isLenient() {
    204         return fIcuCal.isLenient();
    205     }
    206 
    207     //public boolean isSet(int field)
    208 
    209     @Override
    210     public void roll(int field, boolean up) {
    211         sync();
    212         fIcuCal.roll(field, up);
    213     }
    214 
    215     @Override
    216     public void roll(int field, int amount) {
    217         sync();
    218         fIcuCal.roll(field, amount);
    219     }
    220 
    221     @Override
    222     public void set(int field, int value) {
    223         sync();
    224         fIcuCal.set(field, value);
    225     }
    226 
    227     // Note:    These set methods call set(int field, int value) for each field.
    228     //          These are final, so we cannot override them, but we override
    229     //          set(int field, int value), so the superclass implementations
    230     //          still work as we want.
    231     //public void set(int year, int month, int date)
    232     //public void set(int year, int month, int date, int hourOfDay, int minute)
    233     //public void set(int year, int month, int date, int hourOfDay, int minute, int second)
    234 
    235     @Override
    236     public void setFirstDayOfWeek(int value) {
    237         fIcuCal.setFirstDayOfWeek(value);
    238     }
    239 
    240     @Override
    241     public void setLenient(boolean lenient) {
    242         fIcuCal.setLenient(lenient);
    243     }
    244 
    245     @Override
    246     public void setMinimalDaysInFirstWeek(int value) {
    247         fIcuCal.setMinimalDaysInFirstWeek(value);
    248     }
    249 
    250     // Note:    This method calls setTimeInMillis(long millis).
    251     //          This method is final, so we cannot override it, but we
    252     //          override setTimeInMillis(long millis), so the superclass
    253     //          implementation still works as we want.
    254     //public void setTime(Date date)
    255 
    256     @Override
    257     public void setTimeInMillis(long millis) {
    258         fIcuCal.setTimeInMillis(millis);
    259     }
    260 
    261     @Override
    262     public void setTimeZone(TimeZone value) {
    263         fIcuCal.setTimeZone(TimeZoneJDK.wrap(value));
    264     }
    265 
    266     @Override
    267     public String toString() {
    268         sync();
    269         return "CalendarICU: " + fIcuCal.toString();
    270     }
    271 
    272     private void sync() {
    273         // Check if clear is called for each JDK Calendar field.
    274         // If it was, then call clear for the field in the wrapped
    275         // ICU Calendar.
    276         for (int i = 0; i < isSet.length; i++) {
    277             if (!isSet[i]) {
    278                 isSet[i] = true;
    279                 try {
    280                     fIcuCal.clear(i);
    281                 } catch (ArrayIndexOutOfBoundsException e) {
    282                     // More fields in JDK calendar, which is unlikely
    283                 }
    284             }
    285         }
    286     }
    287 
    288     private void init() {
    289         // Mark "set" for all fields, so we can detect the invocation of
    290         // clear() later.
    291         for (int i = 0; i < isSet.length; i++) {
    292             isSet[i] = true;
    293         }
    294     }
    295 
    296     private static String[] getFieldStrings(int field, int style, DateFormatSymbols dfs) {
    297         String[] result = null;
    298         switch (field) {
    299         case AM_PM:
    300             result = dfs.getAmPmStrings();
    301             break;
    302         case DAY_OF_WEEK:
    303             result = (style == LONG) ? dfs.getWeekdays() : dfs.getShortWeekdays();
    304             break;
    305         case ERA:
    306             //result = (style == LONG) ? dfs.getEraNames() : dfs.getEras();
    307             result = dfs.getEras();
    308             break;
    309         case MONTH:
    310             result = (style == LONG) ? dfs.getMonths() : dfs.getShortMonths();
    311             break;
    312         }
    313         return result;
    314     }
    315 
    316     private static Map<String,Integer> getFieldStringsMap(int field, int style, DateFormatSymbols dfs) {
    317         String[] strings = getFieldStrings(field, style, dfs);
    318         if (strings == null) {
    319             return null;
    320         }
    321         Map<String,Integer> res = new HashMap<String,Integer>();
    322         for (int i = 0; i < strings.length; i++) {
    323             if (strings[i].length() != 0) {
    324                 res.put(strings[i], Integer.valueOf(i));
    325             }
    326         }
    327         return res;
    328     }
    329 }
    330