diff -r 16f0af616ea0 -r dc0017b1a452 jdk/src/share/classes/java/util/Calendar.java --- a/jdk/src/share/classes/java/util/Calendar.java Tue Aug 21 13:42:08 2012 +0100 +++ b/jdk/src/share/classes/java/util/Calendar.java Tue Aug 21 11:00:30 2012 -0700 @@ -53,9 +53,11 @@ import java.text.DateFormatSymbols; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.spi.CalendarDataProvider; import sun.util.BuddhistCalendar; +import sun.util.locale.provider.LocaleProviderAdapter; import sun.util.calendar.ZoneInfo; -import sun.util.resources.LocaleData; +import sun.util.locale.provider.CalendarDataUtility; /** * The Calendar class is an abstract class that provides methods @@ -707,17 +709,24 @@ * getDisplayNames} indicating names in all styles, such as * "January" and "Jan". * + * @see #SHORT_FORMAT + * @see #LONG_FORMAT + * @see #SHORT_STANDALONE + * @see #LONG_STANDALONE * @see #SHORT * @see #LONG * @since 1.6 */ public static final int ALL_STYLES = 0; + static final int STANDALONE_MASK = 0x8000; + /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) - * getDisplayNames} indicating a short name, such as "Jan". + * getDisplayNames} equivalent to {@link #SHORT_FORMAT}. * + * @see #SHORT_STANDALONE * @see #LONG * @since 1.6 */ @@ -726,13 +735,64 @@ /** * A style specifier for {@link #getDisplayName(int, int, Locale) * getDisplayName} and {@link #getDisplayNames(int, int, Locale) - * getDisplayNames} indicating a long name, such as "January". + * getDisplayNames} equivalent to {@link #LONG_FORMAT}. * + * @see #LONG_STANDALONE * @see #SHORT * @since 1.6 */ public static final int LONG = 2; + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a short name used for format. + * + * @see #SHORT_STANDALONE + * @see #LONG_FORMAT + * @see #LONG_STANDALONE + * @since 1.8 + */ + public static final int SHORT_FORMAT = 1; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a long name used for format. + * + * @see #LONG_STANDALONE + * @see #SHORT_FORMAT + * @see #SHORT_STANDALONE + * @since 1.8 + */ + public static final int LONG_FORMAT = 2; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a short name used independently, + * such as a month abbreviation as calendar headers. + * + * @see #SHORT_FORMAT + * @see #LONG_FORMAT + * @see #LONG_STANDALONE + * @since 1.8 + */ + public static final int SHORT_STANDALONE = SHORT | STANDALONE_MASK; + + /** + * A style specifier for {@link #getDisplayName(int, int, Locale) + * getDisplayName} and {@link #getDisplayNames(int, int, Locale) + * getDisplayNames} indicating a long name used independently, + * such as a month name as calendar headers. + * + * @see #LONG_FORMAT + * @see #SHORT_FORMAT + * @see #SHORT_STANDALONE + * @since 1.8 + */ + public static final int LONG_STANDALONE = LONG | STANDALONE_MASK; + // Internal notes: // Calendar contains two kinds of time representations: current "time" in // milliseconds, and a set of calendar "fields" representing the current time. @@ -750,6 +810,7 @@ * ERA through DST_OFFSET. * @serial */ + @SuppressWarnings("ProtectedField") protected int fields[]; /** @@ -760,6 +821,7 @@ * ERA through DST_OFFSET. * @serial */ + @SuppressWarnings("ProtectedField") protected boolean isSet[]; /** @@ -775,6 +837,7 @@ * @see #isTimeSet * @serial */ + @SuppressWarnings("ProtectedField") protected long time; /** @@ -783,6 +846,7 @@ * @see #time * @serial */ + @SuppressWarnings("ProtectedField") protected boolean isTimeSet; /** @@ -792,6 +856,7 @@ * time. * @serial */ + @SuppressWarnings("ProtectedField") protected boolean areFieldsSet; /** @@ -910,6 +975,7 @@ static final long serialVersionUID = -1807547505821590642L; // Mask values for calendar fields + @SuppressWarnings("PointlessBitwiseExpression") final static int ERA_MASK = (1 << ERA); final static int YEAR_MASK = (1 << YEAR); final static int MONTH_MASK = (1 << MONTH); @@ -1018,27 +1084,38 @@ { Calendar cal = null; + if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); - if (caltype == null) { - // Calendar type is not specified. - // If the specified locale is a Thai locale, - // returns a BuddhistCalendar instance. - if ("th".equals(aLocale.getLanguage()) - && ("TH".equals(aLocale.getCountry()))) { + if (caltype != null) { + switch (caltype) { + case "buddhist": cal = new BuddhistCalendar(zone, aLocale); + break; + case "japanese": + cal = new JapaneseImperialCalendar(zone, aLocale); + break; + case "gregory": + cal = new GregorianCalendar(zone, aLocale); + break; + } + } + } + if (cal == null) { + // If no known calendar type is explicitly specified, + // perform the traditional way to create a Calendar: + // create a BuddhistCalendar for th_TH locale, + // a JapaneseImperialCalendar for ja_JP_JP locale, or + // a GregorianCalendar for any other locales. + // NOTE: The language, country and variant strings are interned. + if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { + cal = new BuddhistCalendar(zone, aLocale); + } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" + && aLocale.getCountry() == "JP") { + cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } - } else if (caltype.equals("japanese")) { - cal = new JapaneseImperialCalendar(zone, aLocale); - } else if (caltype.equals("buddhist")) { - cal = new BuddhistCalendar(zone, aLocale); - } else { - // Unsupported calendar type. - // Use Gregorian calendar as a fallback. - cal = new GregorianCalendar(zone, aLocale); } - return cal; } @@ -1393,10 +1470,12 @@ * the calendar field for which the string representation * is returned * @param style - * the style applied to the string representation; one of - * {@link #SHORT} or {@link #LONG}. + * the style applied to the string representation; one of {@link + * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, + * {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * @param locale * the locale for the string representation + * (any calendar types specified by {@code locale} are ignored) * @return the string representation of the given * field in the given style, or * null if no string representation is @@ -1410,11 +1489,18 @@ * @since 1.6 */ public String getDisplayName(int field, int style, Locale locale) { - if (!checkDisplayNameParams(field, style, ALL_STYLES, LONG, locale, - ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { + if (!checkDisplayNameParams(field, style, SHORT, LONG, locale, + ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } + // the standalone styles are supported only through CalendarDataProviders. + if (isStandaloneStyle(style)) { + return CalendarDataUtility.retrieveFieldValueName(getCalendarType(), + field, get(field), + style, locale); + } + DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale); String[] strings = getFieldStrings(field, style, symbols); if (strings != null) { @@ -1453,8 +1539,9 @@ * @param field * the calendar field for which the display names are returned * @param style - * the style applied to the display names; one of {@link - * #SHORT}, {@link #LONG}, or {@link #ALL_STYLES}. + * the style applied to the string representation; one of {@link + * #SHORT_FORMAT} ({@link #SHORT}), {@link #SHORT_STANDALONE}, + * {@link #LONG_FORMAT} ({@link #LONG}) or {@link #LONG_STANDALONE}. * @param locale * the locale for the display names * @return a Map containing all display names in @@ -1474,23 +1561,9 @@ ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) { return null; } - - // ALL_STYLES - if (style == ALL_STYLES) { - Map shortNames = getDisplayNamesImpl(field, SHORT, locale); - if (field == ERA || field == AM_PM) { - return shortNames; - } - Map longNames = getDisplayNamesImpl(field, LONG, locale); - if (shortNames == null) { - return longNames; - } - if (longNames != null) { - shortNames.putAll(longNames); - } - return shortNames; + if (style == ALL_STYLES || isStandaloneStyle(style)) { + return CalendarDataUtility.retrieveFieldValueNames(getCalendarType(), field, style, locale); } - // SHORT or LONG return getDisplayNamesImpl(field, style, locale); } @@ -1513,8 +1586,9 @@ boolean checkDisplayNameParams(int field, int style, int minStyle, int maxStyle, Locale locale, int fieldMask) { + int baseStyle = getBaseStyle(style); // Ignore the standalone mask if (field < 0 || field >= fields.length || - style < minStyle || style > maxStyle) { + baseStyle < minStyle || baseStyle > maxStyle) { throw new IllegalArgumentException(); } if (locale == null) { @@ -1524,6 +1598,7 @@ } private String[] getFieldStrings(int field, int style, DateFormatSymbols symbols) { + int baseStyle = getBaseStyle(style); // ignore the standalone mask String[] strings = null; switch (field) { case ERA: @@ -1531,11 +1606,11 @@ break; case MONTH: - strings = (style == LONG) ? symbols.getMonths() : symbols.getShortMonths(); + strings = (baseStyle == LONG) ? symbols.getMonths() : symbols.getShortMonths(); break; case DAY_OF_WEEK: - strings = (style == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); + strings = (baseStyle == LONG) ? symbols.getWeekdays() : symbols.getShortWeekdays(); break; case AM_PM: @@ -1554,8 +1629,9 @@ */ protected void complete() { - if (!isTimeSet) + if (!isTimeSet) { updateTime(); + } if (!areFieldsSet || !areAllFieldsSet) { computeFields(); // fills in unset fields areAllFieldsSet = areFieldsSet = true; @@ -1689,7 +1765,7 @@ * Returns whether the specified field is on in the * fieldMask. */ - static final boolean isFieldSet(int fieldMask, int field) { + static boolean isFieldSet(int fieldMask, int field) { return (fieldMask & (1 << field)) != 0; } @@ -1865,13 +1941,21 @@ return fieldMask; } + int getBaseStyle(int style) { + return style & ~STANDALONE_MASK; + } + + boolean isStandaloneStyle(int style) { + return (style & STANDALONE_MASK) != 0; + } + /** * Returns the pseudo-time-stamp for two fields, given their * individual pseudo-time-stamps. If either of the fields * is unset, then the aggregate is unset. Otherwise, the * aggregate is the later of the two stamps. */ - private static final int aggregateStamp(int stamp_a, int stamp_b) { + private static int aggregateStamp(int stamp_a, int stamp_b) { if (stamp_a == UNSET || stamp_b == UNSET) { return UNSET; } @@ -1879,6 +1963,27 @@ } /** + * Returns the calendar type of this {@code Calendar}. Calendar types are + * defined by the Unicode Locale Data Markup Language (LDML) + * specification. + * + *

The default implementation of this method returns the class name of + * this {@code Calendar} instance. Any subclasses that implement + * LDML-defined calendar systems should override this method to return + * appropriate calendar types. + * + * @return the LDML-defined calendar type or the class name of this + * {@code Calendar} instance + * @since 1.8 + * @see Locale extensions + * @see Locale.Builder#setLocale(Locale) + * @see Locale.Builder#setUnicodeLocaleKeyword(String, String) + */ + public String getCalendarType() { + return this.getClass().getName(); + } + + /** * Compares this Calendar to the specified * Object. The result is true if and only if * the argument is a Calendar object of the same calendar @@ -1900,9 +2005,12 @@ * @return true if this object is equal to obj; * false otherwise. */ + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass") + @Override public boolean equals(Object obj) { - if (this == obj) + if (this == obj) { return true; + } try { Calendar that = (Calendar)obj; return compareTo(getMillisOf(that)) == 0 && @@ -1924,6 +2032,7 @@ * @return a hash code value for this object. * @since 1.2 */ + @Override public int hashCode() { // 'otheritems' represents the hash code for the previous versions. int otheritems = (lenient ? 1 : 0) @@ -1995,6 +2104,7 @@ * any invalid calendar values. * @since 1.5 */ + @Override public int compareTo(Calendar anotherCalendar) { return compareTo(getMillisOf(anotherCalendar)); } @@ -2468,8 +2578,9 @@ // if we're counting weeks, set the day of the week to Sunday. We know the // last week of a month or year will contain the first day of the week. - if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) + if (field == WEEK_OF_YEAR || field == WEEK_OF_MONTH) { work.set(DAY_OF_WEEK, firstDayOfWeek); + } // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that @@ -2494,6 +2605,7 @@ * * @return a copy of this object. */ + @Override public Object clone() { try { @@ -2531,7 +2643,7 @@ * @exception IndexOutOfBoundsException if field is negative, * equal to or greater then FIELD_COUNT. */ - static final String getFieldName(int field) { + static String getFieldName(int field) { return FIELD_NAME[field]; } @@ -2543,6 +2655,7 @@ * * @return a string representation of this calendar. */ + @Override public String toString() { // NOTE: BuddhistCalendar.toString() interprets the string // produced by this method so that the Gregorian year number @@ -2567,7 +2680,7 @@ // =======================privates=============================== - private static final void appendValue(StringBuilder sb, String item, boolean valid, long value) { + private static void appendValue(StringBuilder sb, String item, boolean valid, long value) { sb.append(item).append('='); if (valid) { sb.append(value); @@ -2587,10 +2700,12 @@ /* try to get the Locale data from the cache */ int[] data = cachedLocaleData.get(desiredLocale); if (data == null) { /* cache miss */ - ResourceBundle bundle = LocaleData.getCalendarData(desiredLocale); + LocaleProviderAdapter adapter = LocaleProviderAdapter.getAdapter(CalendarDataProvider.class, desiredLocale); + CalendarDataProvider provider = adapter.getCalendarDataProvider(); data = new int[2]; - data[0] = Integer.parseInt(bundle.getString("firstDayOfWeek")); - data[1] = Integer.parseInt(bundle.getString("minimalDaysInFirstWeek")); + data[0] = provider.getFirstDayOfWeek(desiredLocale); + data[1] = provider.getMinimalDaysInFirstWeek(desiredLocale); + assert data[0] != 0 && data[1] != 0; cachedLocaleData.putIfAbsent(desiredLocale, data); } firstDayOfWeek = data[0]; @@ -2614,7 +2729,7 @@ return (thisTime > t) ? 1 : (thisTime == t) ? 0 : -1; } - private static final long getMillisOf(Calendar calendar) { + private static long getMillisOf(Calendar calendar) { if (calendar.isTimeSet) { return calendar.time; } @@ -2627,7 +2742,7 @@ * Adjusts the stamp[] values before nextStamp overflow. nextStamp * is set to the next stamp value upon the return. */ - private final void adjustStamp() { + private void adjustStamp() { int max = MINIMUM_USER_STAMP; int newStamp = MINIMUM_USER_STAMP; @@ -2752,6 +2867,8 @@ new ProtectionDomain(null, perms) }); } + private CalendarAccessControlContext() { + } } /** @@ -2771,13 +2888,18 @@ if (serialVersionOnStream >= 2) { isTimeSet = true; - if (fields == null) fields = new int[FIELD_COUNT]; - if (isSet == null) isSet = new boolean[FIELD_COUNT]; + if (fields == null) { + fields = new int[FIELD_COUNT]; + } + if (isSet == null) { + isSet = new boolean[FIELD_COUNT]; + } } else if (serialVersionOnStream >= 0) { - for (int i=0; i() { + @Override public ZoneInfo run() throws Exception { return (ZoneInfo) input.readObject(); }