--- 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 <code>Calendar</code> 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 @@
* <code>ERA</code> through <code>DST_OFFSET</code>.
* @serial
*/
+ @SuppressWarnings("ProtectedField")
protected int fields[];
/**
@@ -760,6 +821,7 @@
* <code>ERA</code> through <code>DST_OFFSET</code>.
* @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 @@
* <code>time</code>.
* @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
* <code>field</code> in the given <code>style</code>, or
* <code>null</code> 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 <code>Map</code> 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<String,Integer> shortNames = getDisplayNamesImpl(field, SHORT, locale);
- if (field == ERA || field == AM_PM) {
- return shortNames;
- }
- Map<String,Integer> 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 <code>field</code> is on in the
* <code>fieldMask</code>.
*/
- 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 <em>Unicode Locale Data Markup Language (LDML)</em>
+ * specification.
+ *
+ * <p>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 <a href="Locale.html#def_extensions">Locale extensions</a>
+ * @see Locale.Builder#setLocale(Locale)
+ * @see Locale.Builder#setUnicodeLocaleKeyword(String, String)
+ */
+ public String getCalendarType() {
+ return this.getClass().getName();
+ }
+
+ /**
* Compares this <code>Calendar</code> to the specified
* <code>Object</code>. The result is <code>true</code> if and only if
* the argument is a <code>Calendar</code> object of the same calendar
@@ -1900,9 +2005,12 @@
* @return <code>true</code> if this object is equal to <code>obj</code>;
* <code>false</code> 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 <code>field</code> is negative,
* equal to or greater then <code>FIELD_COUNT</code>.
*/
- 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<FIELD_COUNT; ++i)
+ for (int i=0; i<FIELD_COUNT; ++i) {
stamp[i] = isSet[i] ? COMPUTED : UNSET;
+ }
}
serialVersionOnStream = currentSerialVersion;
@@ -2787,6 +2909,7 @@
try {
zi = AccessController.doPrivileged(
new PrivilegedExceptionAction<ZoneInfo>() {
+ @Override
public ZoneInfo run() throws Exception {
return (ZoneInfo) input.readObject();
}