Merge "MethodHandle: Add tests for invokeWithArguments(List<?>)"
diff --git a/dex/src/main/java/com/android/dex/DexFormat.java b/dex/src/main/java/com/android/dex/DexFormat.java
index c598eee..1367f65 100644
--- a/dex/src/main/java/com/android/dex/DexFormat.java
+++ b/dex/src/main/java/com/android/dex/DexFormat.java
@@ -51,7 +51,12 @@
* completed and is not considered a valid dex file format.
* </p>
*/
- public static final String VERSION_CURRENT = "037";
+ public static final String VERSION_CURRENT = "038";
+
+ /**
+ * Versions currently supported.
+ */
+ static final String [] VERSIONS_SUPPORTED = { "035", "037", "038" };
/** dex file version number for API level 13 and earlier */
public static final String VERSION_FOR_API_13 = "035";
@@ -91,9 +96,13 @@
String version = "" + ((char) magic[4]) + ((char) magic[5]) +((char) magic[6]);
- if (version.equals(VERSION_CURRENT)) {
- return API_CURRENT;
- } else if (version.equals(VERSION_FOR_API_13)) {
+ for (String supported : VERSIONS_SUPPORTED) {
+ if (version.equals(supported)) {
+ return API_CURRENT;
+ }
+ }
+
+ if (version.equals(VERSION_FOR_API_13)) {
return API_NO_EXTENDED_OPCODES;
}
diff --git a/dex/src/main/java/com/android/dex/TableOfContents.java b/dex/src/main/java/com/android/dex/TableOfContents.java
index 583f195..b33a749 100644
--- a/dex/src/main/java/com/android/dex/TableOfContents.java
+++ b/dex/src/main/java/com/android/dex/TableOfContents.java
@@ -36,6 +36,8 @@
public final Section fieldIds = new Section(0x0004);
public final Section methodIds = new Section(0x0005);
public final Section classDefs = new Section(0x0006);
+ public final Section callSiteIds = new Section(0x0007);
+ public final Section methodHandles = new Section(0x0008);
public final Section mapList = new Section(0x1000);
public final Section typeLists = new Section(0x1001);
public final Section annotationSetRefLists = new Section(0x1002);
@@ -48,9 +50,9 @@
public final Section encodedArrays = new Section(0x2005);
public final Section annotationsDirectories = new Section(0x2006);
public final Section[] sections = {
- header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList,
- typeLists, annotationSetRefLists, annotationSets, classDatas, codes, stringDatas,
- debugInfos, annotations, encodedArrays, annotationsDirectories
+ header, stringIds, typeIds, protoIds, fieldIds, methodIds, classDefs, mapList, callSiteIds,
+ methodHandles, typeLists, annotationSetRefLists, annotationSets, classDatas, codes,
+ stringDatas, debugInfos, annotations, encodedArrays, annotationsDirectories
};
public int apiLevel;
@@ -76,7 +78,12 @@
byte[] magic = headerIn.readByteArray(8);
if (!DexFormat.isSupportedDexMagic(magic)) {
- throw new DexException("Unexpected magic: " + Arrays.toString(magic));
+ String msg =
+ String.format("Unexpected magic: [0x%02x, 0x%02x, 0x%02x, 0x%02x, "
+ + "0x%02x, 0x%02x, 0x%02x, 0x%02x]",
+ magic[0], magic[1], magic[2], magic[3],
+ magic[4], magic[5], magic[6], magic[7]);
+ throw new DexException(msg);
}
apiLevel = DexFormat.magicToApi(magic);
diff --git a/expectations/brokentests.txt b/expectations/brokentests.txt
index 5dc7ad8..c638f90 100644
--- a/expectations/brokentests.txt
+++ b/expectations/brokentests.txt
@@ -45,16 +45,10 @@
description: "Some tests depend on ICU data, which has changed. Others make assumptions about floating point rounding",
result: EXEC_FAILED,
names: [
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_BigDecimalExceptionOrder",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_DateTimeConversion",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionE",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionF",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatConversionG",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_FloatDoubleBigDecimalExceptionOrder",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_GeneralConversionOther",
"org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_LineSeparator",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent",
- "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Width"
+ "org.apache.harmony.tests.java.util.FormatterTest#test_formatLjava_lang_String$Ljava_lang_Object_Percent"
]
},
{
@@ -67,16 +61,6 @@
]
},
{
- description: "(Needs investigation) Test failures from the harmony import of external/apache-harmony/archive",
- bug: 12189307,
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testNul",
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testRead",
- "org.apache.harmony.tests.java.util.jar.ManifestTest#testStreamConstructor"
- ]
-},
-{
description: "Potentially flakey because they rely on a specific local TCP port being free.",
result: EXEC_FAILED,
names: [
@@ -123,13 +107,6 @@
]
},
{
- description: "Suffers from side effect of other, currently unknown test",
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.luni.tests.internal.net.www.protocol.http.HttpURLConnectionTest#testProxyAuthorization"
- ]
-},
-{
description: "Support_TestWebServer requires isolation.",
result: EXEC_FAILED,
names: [
diff --git a/expectations/knownfailures.txt b/expectations/knownfailures.txt
index a5764f5..da96678 100644
--- a/expectations/knownfailures.txt
+++ b/expectations/knownfailures.txt
@@ -1294,19 +1294,6 @@
name: "org.apache.harmony.tests.java.lang.MathTest#test_powDD"
},
{
- description: "Known failures in PropertiesTest: We don't deal with comments in store()",
- bug: 11686302,
- result: EXEC_FAILED,
- names: [
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario0",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario1",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario2",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario3",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario9",
- "org.apache.harmony.tests.java.util.PropertiesTest#testStore_scenario11"
- ]
-},
-{
description: "Known failures in URLTest and URLDecoderTest",
bug: 11686814,
names: [
@@ -1413,14 +1400,6 @@
]
},
{
- description: "Known precision issue in DecimalFormat",
- bug: 17656132,
- names: [
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_bug17656132",
- "org.apache.harmony.tests.java.text.DecimalFormatTest#test_formatDouble_roundingProblemCases"
- ]
-},
-{
description: "Known failure in GregorianCalendarTest",
bug: 12778197,
name: "org.apache.harmony.tests.java.util.GregorianCalendarTest#test_computeTime"
@@ -1435,7 +1414,7 @@
},
{
description: "libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale assumes fallback to locale other than en_US_POSIX.",
- bug: 17374604,
+ bug: 17422813,
names: [
"libcore.java.text.DecimalFormatSymbolsTest#test_getInstance_unknown_or_invalid_locale"
]
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
index 902caef..29470d1 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DecimalFormatTest.java
@@ -1699,7 +1699,7 @@
// double 9999999999.999998 is decimal 9999999999.9999980926513671875
assertEquals("9999999999.999998", df.format(9999999999.999998));
// double 1E23 is decimal 99999999999999991611392
- assertEquals("9999999999999999", df.format(1E23));
+ assertEquals("99999999999999990000000", df.format(1E23));
}
public void test_getDecimalFormatSymbols() {
diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
index 13e9317..5a84c8e 100644
--- a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
+++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
@@ -106,6 +106,9 @@
// Hardcode default value for AVA. b/28174137
{ "com.sun.security.preserveOldDCEncoding", null },
+
+ // Hardcode default value for LogManager. b/28174137
+ { "java.util.logging.manager", null },
};
}
diff --git a/libart/src/main/java/java/lang/DexCache.java b/libart/src/main/java/java/lang/DexCache.java
index 8465a24..fb55475 100644
--- a/libart/src/main/java/java/lang/DexCache.java
+++ b/libart/src/main/java/java/lang/DexCache.java
@@ -48,12 +48,24 @@
private long dexFile;
/**
+ * References to CallSite (C array pointer) as they become resolved following
+ * interpreter semantics.
+ */
+ private long resolvedCallSites;
+
+ /**
* References to fields (C array pointer) as they become resolved following
* interpreter semantics. May refer to fields defined in other dex files.
*/
private long resolvedFields;
/**
+ * References to MethodType (C array pointer) as they become resolved following
+ * interpreter semantics.
+ */
+ private long resolvedMethodTypes;
+
+ /**
* References to methods (C array pointer) as they become resolved following
* interpreter semantics. May refer to methods defined in other dex files.
*/
@@ -72,10 +84,9 @@
private long strings;
/**
- * References to MethodType (C array pointer) as they become resolved following
- * interpreter semantics.
+ * The number of elements in the native call sites array.
*/
- private long resolvedMethodTypes;
+ private int numResolvedCallSites;
/**
* The number of elements in the native resolvedFields array.
@@ -83,6 +94,11 @@
private int numResolvedFields;
/**
+ * The number of elements in the native method types array.
+ */
+ private int numResolvedMethodTypes;
+
+ /**
* The number of elements in the native resolvedMethods array.
*/
private int numResolvedMethods;
@@ -97,11 +113,6 @@
*/
private int numStrings;
- /**
- * The number of elements in the native method types array.
- */
- private int numResolvedMethodTypes;
-
// Only created by the VM.
private DexCache() {}
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index dc5741f..ad7151d 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -257,13 +257,9 @@
public void test_gc() {
Runtime rt = Runtime.getRuntime();
- Vector<StringBuffer> vec = new Vector<StringBuffer>();
- long beforeTest = rt.totalMemory() - rt.freeMemory();
- while (rt.totalMemory() - rt.freeMemory() < beforeTest * 2) {
- vec.add(new StringBuffer(1000));
- }
+ byte[] data = new byte[2 * 1024 * 1024];
long beforeGC = rt.totalMemory() - rt.freeMemory();
- vec = null;
+ data = null;
System.gc();
System.runFinalization();
long afterGC = rt.totalMemory() - rt.freeMemory();
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
index 08bc8db..9bf02ef 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandleCombinersTest.java
@@ -121,6 +121,23 @@
}
}
+ public static void testDropArguments_List() throws Throwable {
+ MethodHandle delegate = MethodHandles.lookup().findStatic(MethodHandleCombinersTest.class,
+ "dropArguments_delegate",
+ MethodType.methodType(void.class, new Class<?>[]{String.class, long.class}));
+
+ MethodHandle transform = MethodHandles.dropArguments(
+ delegate, 0, Arrays.asList(int.class, Object.class));
+
+ transform.invokeExact(45, new Object(), "foo", 42l);
+ transform.invoke(45, new Object(), "foo", 42l);
+
+ // Check that asType works as expected.
+ transform = transform.asType(MethodType.methodType(void.class,
+ new Class<?>[]{short.class, Object.class, String.class, long.class}));
+ transform.invokeExact((short) 45, new Object(), "foo", 42l);
+ }
+
public static String testCatchException_target(String arg1, long arg2, String exceptionMessage)
throws Throwable {
if (exceptionMessage != null) {
diff --git a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
index 8381cbd..774f102 100644
--- a/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
+++ b/luni/src/test/java/libcore/java/lang/invoke/MethodHandlesTest.java
@@ -965,7 +965,7 @@
assertEquals(testPattern, s);
}
- private static void testReferenceReturnValueConversions() throws Throwable {
+ public void testReferenceReturnValueConversions() throws Throwable {
MethodHandle mh = MethodHandles.lookup().findStatic(
Float.class, "valueOf", MethodType.methodType(Float.class, String.class));
@@ -1023,7 +1023,7 @@
assertEquals(0, c.compareTo(Float.valueOf(2.125f)));
}
- private static void testPrimitiveReturnValueConversions() throws Throwable {
+ public void testPrimitiveReturnValueConversions() throws Throwable {
MethodHandle mh = MethodHandles.lookup().findStatic(
Math.class, "min", MethodType.methodType(int.class, int.class, int.class));
@@ -1155,11 +1155,6 @@
}
}
- public static void testReturnValueConversions() throws Throwable {
- testReferenceReturnValueConversions();
- testPrimitiveReturnValueConversions();
- }
-
public static class BaseVariableArityTester {
public String update(Float f0, Float... floats) {
return "base " + f0 + ", " + Arrays.toString(floats);
diff --git a/luni/src/test/java/libcore/java/security/ProviderTest.java b/luni/src/test/java/libcore/java/security/ProviderTest.java
index ac64315..ffba98a 100644
--- a/luni/src/test/java/libcore/java/security/ProviderTest.java
+++ b/luni/src/test/java/libcore/java/security/ProviderTest.java
@@ -35,6 +35,7 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
+import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -45,6 +46,7 @@
import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
+import java.util.TreeSet;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -85,6 +87,20 @@
Set<Provider.Service> services = provider.getServices();
assertNotNull(services);
assertFalse(services.isEmpty());
+ if (LOG_DEBUG) {
+ Set<Provider.Service> originalServices = services;
+ services = new TreeSet<Provider.Service>(
+ new Comparator<Provider.Service>() {
+ public int compare(Provider.Service a, Provider.Service b) {
+ int typeCompare = a.getType().compareTo(b.getType());
+ if (typeCompare != 0) {
+ return typeCompare;
+ }
+ return a.getAlgorithm().compareTo(b.getAlgorithm());
+ }
+ });
+ services.addAll(originalServices);
+ }
for (Provider.Service service : services) {
String type = service.getType();
diff --git a/luni/src/test/java/libcore/java/util/CalendarBuilderTest.java b/luni/src/test/java/libcore/java/util/CalendarBuilderTest.java
new file mode 100644
index 0000000..5e4ac96
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/CalendarBuilderTest.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package libcore.java.util;
+
+import org.junit.Before;
+import org.junit.Test;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
+
+/**
+ * Tests {@link java.util.Calendar.Builder}.
+ */
+public class CalendarBuilderTest {
+
+
+ @Test
+ public void test_default_values() {
+ Calendar.Builder builder = new Calendar.Builder();
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setCalendarType_iso8601() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setCalendarType("iso8601");
+ // ISO 8601 represents a gregorian calendar with a specific configuration
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setGregorianChange(new Date(Long.MIN_VALUE));
+ expected.setFirstDayOfWeek(Calendar.MONDAY);
+ expected.setMinimalDaysInFirstWeek(4);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setCalendarType_invalid() {
+ Calendar.Builder builder = new Calendar.Builder();
+ try {
+ builder.setCalendarType(null);
+ fail("Should have thrown NPE");
+ } catch (NullPointerException expected) {}
+
+ for (String unsupported : new String[] { "buddhist", "japanese", "notACalendarType" }) {
+ try {
+ // not supported
+ builder.setCalendarType(unsupported);
+ fail("Unsupported calendar type " + unsupported + " should have thrown.");
+ } catch (IllegalArgumentException expected) {}
+ }
+ }
+
+ @Test
+ public void test_setCalendarType_reset() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setCalendarType("gregorian");
+ try {
+ builder.setCalendarType("iso8601");
+ fail("Should not accept second setCalendarType() call");
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void test_setDate() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setDate(2000, Calendar.FEBRUARY, 3);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.set(2000, Calendar.FEBRUARY, 3);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setTimeOfDay() {
+ Calendar.Builder builder = new Calendar.Builder();
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ builder.setTimeOfDay(10, 11, 12);
+ expected.set(1970, Calendar.JANUARY, 1, 10, 11, 12);
+ assertEquals(expected, builder.build());
+ builder.setTimeOfDay(10, 11, 12, 13);
+ expected.set(Calendar.MILLISECOND, 13);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setWeekDate() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setWeekDate(1, 2000, Calendar.TUESDAY);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setWeekDate(1, 2000, Calendar.TUESDAY);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setLenient() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.set(Calendar.HOUR_OF_DAY, 25);
+ builder.setLenient(false);
+ try {
+ builder.build();
+ fail("Should have failed to build.");
+ } catch (IllegalArgumentException expected) {}
+ builder.setLenient(true);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setLenient(true);
+ expected.set(Calendar.HOUR_OF_DAY, 25);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setLocale() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setLocale(Locale.GERMANY);
+ GregorianCalendar expected = new GregorianCalendar(Locale.GERMANY);
+ expected.clear();
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setLocale_thTH() {
+ // See http://b/35138741
+ Calendar.Builder builder = new Calendar.Builder();
+ Locale th = new Locale("th", "TH");
+ builder.setLocale(th);
+ GregorianCalendar expected = new GregorianCalendar(th);
+ expected.clear();
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_set() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.set(Calendar.YEAR, 2000);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.set(Calendar.YEAR, 2000);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_set_negative_field() {
+ new Calendar.Builder().set(-1, 1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_set_field_too_high() {
+ new Calendar.Builder().set(Calendar.FIELD_COUNT, 1);
+ }
+
+ @Test
+ public void test_set_after_setInstant() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setInstant(0L);
+ try {
+ builder.set(Calendar.YEAR, 2000);
+ fail("Setting a field after setInstant should fail.");
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void test_setFields() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setFields(Calendar.YEAR, 2000, Calendar.MONTH, Calendar.FEBRUARY);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.set(Calendar.YEAR, 2000);
+ expected.set(Calendar.MONTH, Calendar.FEBRUARY);
+ assertEquals(expected, builder.build());
+
+ // field values can be re-set and order of fields matter
+ builder.setFields(Calendar.DAY_OF_WEEK_IN_MONTH, 1,
+ Calendar.DAY_OF_MONTH, 20, // this will effectively be ignored
+ Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
+ expected.set(Calendar.DAY_OF_WEEK_IN_MONTH, 1);
+ expected.set(Calendar.DAY_OF_MONTH, 20);
+ expected.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
+ assertEquals(expected, builder.build());
+ // 20th February 2000 would have been a Sunday, but we set the DOW last.
+ assertEquals(Calendar.WEDNESDAY, builder.build().get(Calendar.DAY_OF_WEEK));
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_setFields_null() {
+ new Calendar.Builder().setFields(null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_setFields_oddNumberOfArguments() {
+ new Calendar.Builder().setFields(Calendar.YEAR);
+ }
+
+ @Test
+ public void test_setFields_after_setInstant() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setInstant(0L);
+ try {
+ builder.setFields(Calendar.YEAR, 2000);
+ fail("Setting a field after setInstant should fail.");
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void test_setInstant() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setInstant(Long.MIN_VALUE);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setTimeInMillis(Long.MIN_VALUE);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test
+ public void test_setInstant_after_set() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.set(Calendar.YEAR, 2000);
+ try {
+ builder.setInstant(0L);
+ fail("Setting the instant after setting a field should fail.");
+ } catch (IllegalStateException expected) {}
+ }
+
+ @Test
+ public void test_setInstant_Date() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setInstant(new Date(Long.MAX_VALUE));
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setTimeInMillis(Long.MAX_VALUE);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_setInstant_Date_null() {
+ new Calendar.Builder().setInstant(null);
+ }
+
+ @Test
+ public void test_setTimeZone() {
+ TimeZone london = TimeZone.getTimeZone("Europe/London");
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setTimeZone(london);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setTimeZone(london);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void test_setTimeZone_null() {
+ new Calendar.Builder().setTimeZone(null);
+ }
+
+ @Test
+ public void test_setWeekDefinition() {
+ Calendar.Builder builder = new Calendar.Builder();
+ builder.setWeekDefinition(Calendar.TUESDAY, 7);
+ GregorianCalendar expected = new GregorianCalendar();
+ expected.clear();
+ expected.setFirstDayOfWeek(Calendar.TUESDAY);
+ expected.setMinimalDaysInFirstWeek(7);
+ assertEquals(expected, builder.build());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_setWeekDefinition_invalid_first_dow() {
+ new Calendar.Builder().setWeekDefinition(-1, 1);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void test_setWeekDefinition_invalid_minimum_days() {
+ new Calendar.Builder().setWeekDefinition(Calendar.WEDNESDAY, 8);
+ }
+
+}
diff --git a/luni/src/test/java/libcore/java/util/DateTest.java b/luni/src/test/java/libcore/java/util/DateTest.java
index 6185f12..df86a38 100644
--- a/luni/src/test/java/libcore/java/util/DateTest.java
+++ b/luni/src/test/java/libcore/java/util/DateTest.java
@@ -81,49 +81,63 @@
}
/**
- * The minimum long value below which {@link Instant#toEpochMilli()} will
- * throw is not clearly documented. This test discovers if that minimum
- * value ever changes, and also checks that it is also the minimum Instant
- * (at a millisecond boundary) that can be converted to a Date.
+ * Test that conversion between Date and Instant works when the
+ * Instant is based on a millisecond value (and thus can be
+ * represented as a Date).
*/
- public void test_convertFromInstant_lowerBound() {
- // smallest millisecond Instant that can be converted to Date
- long minConvertible = -9223372036854775000L;
+ public void test_convertFromAndToInstant_milliseconds() {
+ check_convertFromAndToInstant_milliseconds(Long.MIN_VALUE);
+ check_convertFromAndToInstant_milliseconds(Long.MAX_VALUE);
- // show that this value is < 1 sec away from Long.MIN_VALUE
- assertEquals(Long.MIN_VALUE + 808, minConvertible);
-
- Instant inBound = Instant.ofEpochMilli(minConvertible);
- assertEquals(new Date(minConvertible), Date.from(inBound));
- assertEquals(minConvertible, inBound.toEpochMilli());
-
- Instant outOfBound = Instant.ofEpochMilli(minConvertible - 1);
- try {
- Date.from(outOfBound);
- fail();
- } catch (IllegalArgumentException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
- }
-
- try {
- outOfBound.toEpochMilli();
- fail();
- } catch (ArithmeticException expected) {
-
- }
+ check_convertFromAndToInstant_milliseconds(-1);
+ check_convertFromAndToInstant_milliseconds(0);
+ check_convertFromAndToInstant_milliseconds(123456789);
}
- public void test_convertFromInstant_upperBound() {
- Date.from(Instant.ofEpochMilli(Long.MAX_VALUE));
+ private static void check_convertFromAndToInstant_milliseconds(long millis) {
+ assertEquals(new Date(millis), Date.from(Instant.ofEpochMilli(millis)));
+ assertEquals(new Date(millis).toInstant(), Instant.ofEpochMilli(millis));
+ }
- Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 0));
- Date.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 999999999));
- Instant outOfBound = Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1, 0);
+ /**
+ * Checks the minimum/maximum Instant values (based on seconds and
+ * nanos) that can be converted to a Date, i.e. that can be converted
+ * to milliseconds without overflowing a long. Note that the rounding
+ * is such that the lower bound is exactly Long.MIN_VALUE msec whereas
+ * the upper bound is 999,999 nanos beyond Long.MAX_VALUE msec. This
+ * makes some sense in that the magnitude of the upper/lower bound
+ * nanos differ only by 1, just like the magnitude of Long.MIN_VALUE /
+ * MAX_VALUE differ only by 1.
+ */
+ public void test_convertFromInstant_secondsAndNanos() {
+ // Documentation for how the below bounds relate to long boundaries for milliseconds
+ assertEquals(-808, Long.MIN_VALUE % 1000);
+ assertEquals(807, Long.MAX_VALUE % 1000);
+
+ // Lower bound
+ long minSecond = Long.MIN_VALUE / 1000;
+ Date.from(Instant.ofEpochSecond(minSecond));
+ // This instant exactly corresponds to Long.MIN_VALUE msec because
+ // Long.MIN_VALUE % 1000 == -808 == (-1000 + 192)
+ Date.from(Instant.ofEpochSecond(minSecond - 1, 192000000));
+ assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 0));
+ assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 191999999));
+
+ // Upper bound
+ long maxSecond = Long.MAX_VALUE / 1000;
+ Date.from(Instant.ofEpochSecond(maxSecond, 0));
+ // This Instant is 999,999 nanos beyond Long.MAX_VALUE msec because
+ // (Long.MAX_VALUE % 1000) == 807
+ Date.from(Instant.ofEpochSecond(maxSecond, 807999999));
+ assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond + 1, 0));
+ assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond, 808000000));
+ }
+
+ private static void assertArithmeticOverflowDateFrom(Instant instant) {
try {
- Date.from(outOfBound);
- fail();
+ Date.from(instant);
+ fail(instant + " should not have been convertible to Date");
} catch (IllegalArgumentException expected) {
- assertEquals(ArithmeticException.class, expected.getCause().getClass());
}
}
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index 02afcdd..2b3347c 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -4626,14 +4626,14 @@
if (s.getType().equals("Cipher")) {
if (s.getAlgorithm().startsWith("AES_128/")) {
Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
- assertTrue(checkAES_keyConstraint(c, 128));
- assertFalse(checkAES_keyConstraint(c, 192));
- assertFalse(checkAES_keyConstraint(c, 256));
+ assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
} else if (s.getAlgorithm().startsWith("AES_256/")) {
Cipher c = Cipher.getInstance(s.getAlgorithm(), p);
- assertFalse(checkAES_keyConstraint(c, 128));
- assertFalse(checkAES_keyConstraint(c, 192));
- assertTrue(checkAES_keyConstraint(c, 256));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 128));
+ assertFalse(s.getAlgorithm(), checkAES_keyConstraint(c, 192));
+ assertTrue(s.getAlgorithm(), checkAES_keyConstraint(c, 256));
}
}
}
diff --git a/ojluni/src/main/java/java/lang/BootstrapMethodError.java b/ojluni/src/main/java/java/lang/BootstrapMethodError.java
new file mode 100644
index 0000000..a1509a0
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/BootstrapMethodError.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+/**
+ * Thrown to indicate that an {@code invokedynamic} instruction has
+ * failed to find its bootstrap method,
+ * or the bootstrap method has failed to provide a
+ * {@linkplain java.lang.invoke.CallSite call site} with a {@linkplain java.lang.invoke.CallSite#getTarget target}
+ * of the correct {@linkplain java.lang.invoke.MethodHandle#type method type}.
+ *
+ * @author John Rose, JSR 292 EG
+ * @since 1.7
+ */
+public class BootstrapMethodError extends LinkageError {
+ private static final long serialVersionUID = 292L;
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with no detail message.
+ */
+ public BootstrapMethodError() {
+ super();
+ }
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with the specified
+ * detail message.
+ *
+ * @param s the detail message.
+ */
+ public BootstrapMethodError(String s) {
+ super(s);
+ }
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with the specified
+ * detail message and cause.
+ *
+ * @param s the detail message.
+ * @param cause the cause, may be {@code null}.
+ */
+ public BootstrapMethodError(String s, Throwable cause) {
+ super(s, cause);
+ }
+
+ /**
+ * Constructs a {@code BootstrapMethodError} with the specified
+ * cause.
+ *
+ * @param cause the cause, may be {@code null}.
+ */
+ public BootstrapMethodError(Throwable cause) {
+ // cf. Throwable(Throwable cause) constructor.
+ super(cause == null ? null : cause.toString());
+ initCause(cause);
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/CallSite.java b/ojluni/src/main/java/java/lang/invoke/CallSite.java
new file mode 100644
index 0000000..f9338e6
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/CallSite.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: Not using Empty
+//import sun.invoke.empty.Empty;
+import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
+
+/**
+ * A {@code CallSite} is a holder for a variable {@link MethodHandle},
+ * which is called its {@code target}.
+ * An {@code invokedynamic} instruction linked to a {@code CallSite} delegates
+ * all calls to the site's current target.
+ * A {@code CallSite} may be associated with several {@code invokedynamic}
+ * instructions, or it may be "free floating", associated with none.
+ * In any case, it may be invoked through an associated method handle
+ * called its {@linkplain #dynamicInvoker dynamic invoker}.
+ * <p>
+ * {@code CallSite} is an abstract class which does not allow
+ * direct subclassing by users. It has three immediate,
+ * concrete subclasses that may be either instantiated or subclassed.
+ * <ul>
+ * <li>If a mutable target is not required, an {@code invokedynamic} instruction
+ * may be permanently bound by means of a {@linkplain ConstantCallSite constant call site}.
+ * <li>If a mutable target is required which has volatile variable semantics,
+ * because updates to the target must be immediately and reliably witnessed by other threads,
+ * a {@linkplain VolatileCallSite volatile call site} may be used.
+ * <li>Otherwise, if a mutable target is required,
+ * a {@linkplain MutableCallSite mutable call site} may be used.
+ * </ul>
+ * <p>
+ * A non-constant call site may be <em>relinked</em> by changing its target.
+ * The new target must have the same {@linkplain MethodHandle#type() type}
+ * as the previous target.
+ * Thus, though a call site can be relinked to a series of
+ * successive targets, it cannot change its type.
+ * <p>
+ * Here is a sample use of call sites and bootstrap methods which links every
+ * dynamic call site to print its arguments:
+<blockquote><pre><!-- see indy-demo/src/PrintArgsDemo.java -->
+static void test() throws Throwable {
+ // THE FOLLOWING LINE IS PSEUDOCODE FOR A JVM INSTRUCTION
+ InvokeDynamic[#bootstrapDynamic].baz("baz arg", 2, 3.14);
+}
+private static void printArgs(Object... args) {
+ System.out.println(java.util.Arrays.deepToString(args));
+}
+private static final MethodHandle printArgs;
+static {
+ MethodHandles.Lookup lookup = MethodHandles.lookup();
+ Class thisClass = lookup.lookupClass(); // (who am I?)
+ printArgs = lookup.findStatic(thisClass,
+ "printArgs", MethodType.methodType(void.class, Object[].class));
+}
+private static CallSite bootstrapDynamic(MethodHandles.Lookup caller, String name, MethodType type) {
+ // ignore caller and name, but match the type:
+ return new ConstantCallSite(printArgs.asType(type));
+}
+</pre></blockquote>
+ * @author John Rose, JSR 292 EG
+ */
+abstract
+public class CallSite {
+ // Android-changed: not used.
+ // static { MethodHandleImpl.initStatics(); }
+
+ // The actual payload of this call site:
+ /*package-private*/
+ MethodHandle target; // Note: This field is known to the JVM. Do not change.
+
+ /**
+ * Make a blank call site object with the given method type.
+ * An initial target method is supplied which will throw
+ * an {@link IllegalStateException} if called.
+ * <p>
+ * Before this {@code CallSite} object is returned from a bootstrap method,
+ * it is usually provided with a more useful target method,
+ * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+ * @throws NullPointerException if the proposed type is null
+ */
+
+ /*package-private*/
+ CallSite(MethodType type) {
+ // Android-changed: No cache for these so create uninitializedCallSite target here using
+ // method handle transformations to create a method handle that has the expected method
+ // type but throws an IllegalStateException.
+ // target = type.invokers().uninitializedCallSite();
+ this.target = MethodHandles.throwException(type.returnType(), IllegalStateException.class);
+ this.target = MethodHandles.insertArguments(
+ this.target, 0, new IllegalStateException("uninitialized call site"));
+ if (type.parameterCount() > 0) {
+ this.target = MethodHandles.dropArguments(this.target, 0, type.ptypes());
+ }
+
+ // Android-changed: Using initializer method for GET_TARGET
+ // rather than complex static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Make a call site object equipped with an initial target method handle.
+ * @param target the method handle which will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ /*package-private*/
+ CallSite(MethodHandle target) {
+ target.type(); // null check
+ this.target = target;
+
+ // Android-changed: Using initializer method for GET_TARGET
+ // rather than complex static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Make a call site object equipped with an initial target method handle.
+ * @param targetType the desired type of the call site
+ * @param createTargetHook a hook which will bind the call site to the target method handle
+ * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+ * or if the target returned by the hook is not of the given {@code targetType}
+ * @throws NullPointerException if the hook returns a null value
+ * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+ * @throws Throwable anything else thrown by the the hook function
+ */
+ /*package-private*/
+ CallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+ this(targetType);
+ ConstantCallSite selfCCS = (ConstantCallSite) this;
+ MethodHandle boundTarget = (MethodHandle) createTargetHook.invokeWithArguments(selfCCS);
+ checkTargetChange(this.target, boundTarget);
+ this.target = boundTarget;
+
+ // Android-changed: Using initializer method for GET_TARGET
+ // rather than complex static initializer.
+ initializeGetTarget();
+ }
+
+ /**
+ * Returns the type of this call site's target.
+ * Although targets may change, any call site's type is permanent, and can never change to an unequal type.
+ * The {@code setTarget} method enforces this invariant by refusing any new target that does
+ * not have the previous target's type.
+ * @return the type of the current target, which is also the type of any future target
+ */
+ public MethodType type() {
+ // warning: do not call getTarget here, because CCS.getTarget can throw IllegalStateException
+ return target.type();
+ }
+
+ /**
+ * Returns the target method of the call site, according to the
+ * behavior defined by this call site's specific class.
+ * The immediate subclasses of {@code CallSite} document the
+ * class-specific behaviors of this method.
+ *
+ * @return the current linkage state of the call site, its target method handle
+ * @see ConstantCallSite
+ * @see VolatileCallSite
+ * @see #setTarget
+ * @see ConstantCallSite#getTarget
+ * @see MutableCallSite#getTarget
+ * @see VolatileCallSite#getTarget
+ */
+ public abstract MethodHandle getTarget();
+
+ /**
+ * Updates the target method of this call site, according to the
+ * behavior defined by this call site's specific class.
+ * The immediate subclasses of {@code CallSite} document the
+ * class-specific behaviors of this method.
+ * <p>
+ * The type of the new target must be {@linkplain MethodType#equals equal to}
+ * the type of the old target.
+ *
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see CallSite#getTarget
+ * @see ConstantCallSite#setTarget
+ * @see MutableCallSite#setTarget
+ * @see VolatileCallSite#setTarget
+ */
+ public abstract void setTarget(MethodHandle newTarget);
+
+ void checkTargetChange(MethodHandle oldTarget, MethodHandle newTarget) {
+ MethodType oldType = oldTarget.type();
+ MethodType newType = newTarget.type(); // null check!
+ if (!newType.equals(oldType))
+ throw wrongTargetType(newTarget, oldType);
+ }
+
+ private static WrongMethodTypeException wrongTargetType(MethodHandle target, MethodType type) {
+ return new WrongMethodTypeException(String.valueOf(target)+" should be of type "+type);
+ }
+
+ /**
+ * Produces a method handle equivalent to an invokedynamic instruction
+ * which has been linked to this call site.
+ * <p>
+ * This method is equivalent to the following code:
+ * <blockquote><pre>
+ * MethodHandle getTarget, invoker, result;
+ * getTarget = MethodHandles.publicLookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class));
+ * invoker = MethodHandles.exactInvoker(this.type());
+ * result = MethodHandles.foldArguments(invoker, getTarget)
+ * </pre></blockquote>
+ *
+ * @return a method handle which always invokes this call site's current target
+ */
+ public abstract MethodHandle dynamicInvoker();
+
+ /*non-public*/ MethodHandle makeDynamicInvoker() {
+ // Android-changed: Use bindTo() rather than bindReceiver() (not implemented).
+ MethodHandle getTarget = GET_TARGET.bindTo(this);
+ MethodHandle invoker = MethodHandles.exactInvoker(this.type());
+ return MethodHandles.foldArguments(invoker, getTarget);
+ }
+
+ // Android-changed: no longer final. GET_TARGET assigned in initializeGetTarget().
+ private static MethodHandle GET_TARGET = null;
+
+ private void initializeGetTarget() {
+ // Android-changed: moved from static initializer for
+ // GET_TARGET to avoid issues with running early. Called from
+ // constructors. CallSite creation is not performance critical.
+ synchronized (CallSite.class) {
+ if (GET_TARGET == null) {
+ try {
+ GET_TARGET = IMPL_LOOKUP.
+ findVirtual(CallSite.class, "getTarget",
+ MethodType.methodType(MethodHandle.class));
+ } catch (ReflectiveOperationException e) {
+ throw new InternalError(e);
+ }
+ }
+ }
+ }
+
+ /* Android-changed: not used. */
+ // /** This guy is rolled into the default target if a MethodType is supplied to the constructor. */
+ // /*package-private*/
+ // static Empty uninitializedCallSite() {
+ // throw new IllegalStateException("uninitialized call site");
+ // }
+
+ // unsafe stuff:
+ private static final long TARGET_OFFSET;
+ static {
+ try {
+ TARGET_OFFSET = UNSAFE.objectFieldOffset(CallSite.class.getDeclaredField("target"));
+ } catch (Exception ex) { throw new Error(ex); }
+ }
+
+ /*package-private*/
+ void setTargetNormal(MethodHandle newTarget) {
+ // Android-changed: Set value directly.
+ // MethodHandleNatives.setCallSiteTargetNormal(this, newTarget);
+ target = newTarget;
+ }
+ /*package-private*/
+ MethodHandle getTargetVolatile() {
+ return (MethodHandle) UNSAFE.getObjectVolatile(this, TARGET_OFFSET);
+ }
+ /*package-private*/
+ void setTargetVolatile(MethodHandle newTarget) {
+ // Android-changed: Set value directly.
+ // MethodHandleNatives.setCallSiteTargetVolatile(this, newTarget);
+ UNSAFE.putObjectVolatile(this, TARGET_OFFSET, newTarget);
+ }
+
+ /* Android-changed: not used. */
+ // this implements the upcall from the JVM, MethodHandleNatives.makeDynamicCallSite:
+ // static CallSite makeSite(MethodHandle bootstrapMethod,
+ // // Callee information:
+ // String name, MethodType type,
+ // // Extra arguments for BSM, if any:
+ // Object info,
+ // // Caller information:
+ // Class<?> callerClass) {
+ // Object caller = IMPL_LOOKUP.in(callerClass);
+ // CallSite site;
+ // try {
+ // Object binding;
+ // info = maybeReBox(info);
+ // if (info == null) {
+ // binding = bootstrapMethod.invoke(caller, name, type);
+ // } else if (!info.getClass().isArray()) {
+ // binding = bootstrapMethod.invoke(caller, name, type, info);
+ // } else {
+ // Object[] argv = (Object[]) info;
+ // maybeReBoxElements(argv);
+ // if (3 + argv.length > 255)
+ // throw new BootstrapMethodError("too many bootstrap method arguments");
+ // MethodType bsmType = bootstrapMethod.type();
+ // if (bsmType.parameterCount() == 4 && bsmType.parameterType(3) == Object[].class)
+ // binding = bootstrapMethod.invoke(caller, name, type, argv);
+ // else
+ // binding = MethodHandles.spreadInvoker(bsmType, 3)
+ // .invoke(bootstrapMethod, caller, name, type, argv);
+ // }
+ // //System.out.println("BSM for "+name+type+" => "+binding);
+ // if (binding instanceof CallSite) {
+ // site = (CallSite) binding;
+ // } else {
+ // throw new ClassCastException("bootstrap method failed to produce a CallSite");
+ // }
+ // if (!site.getTarget().type().equals(type))
+ // throw new WrongMethodTypeException("wrong type: "+site.getTarget());
+ // } catch (Throwable ex) {
+ // BootstrapMethodError bex;
+ // if (ex instanceof BootstrapMethodError)
+ // bex = (BootstrapMethodError) ex;
+ // else
+ // bex = new BootstrapMethodError("call site initialization exception", ex);
+ // throw bex;
+ // }
+ // return site;
+ // }
+ // private static Object maybeReBox(Object x) {
+ // if (x instanceof Integer) {
+ // int xi = (int) x;
+ // if (xi == (byte) xi)
+ // x = xi; // must rebox; see JLS 5.1.7
+ // }
+ // return x;
+ // }
+ // private static void maybeReBoxElements(Object[] xa) {
+ // for (int i = 0; i < xa.length; i++) {
+ // xa[i] = maybeReBox(xa[i]);
+ // }
+ // }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java b/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java
new file mode 100644
index 0000000..2d9fede
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+/**
+ * A {@code ConstantCallSite} is a {@link CallSite} whose target is permanent, and can never be changed.
+ * An {@code invokedynamic} instruction linked to a {@code ConstantCallSite} is permanently
+ * bound to the call site's target.
+ * @author John Rose, JSR 292 EG
+ */
+public class ConstantCallSite extends CallSite {
+ private final boolean isFrozen;
+
+ /**
+ * Creates a call site with a permanent target.
+ * @param target the target to be permanently associated with this call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public ConstantCallSite(MethodHandle target) {
+ super(target);
+ isFrozen = true;
+ }
+
+ /**
+ * Creates a call site with a permanent target, possibly bound to the call site itself.
+ * <p>
+ * During construction of the call site, the {@code createTargetHook} is invoked to
+ * produce the actual target, as if by a call of the form
+ * {@code (MethodHandle) createTargetHook.invoke(this)}.
+ * <p>
+ * Note that user code cannot perform such an action directly in a subclass constructor,
+ * since the target must be fixed before the {@code ConstantCallSite} constructor returns.
+ * <p>
+ * The hook is said to bind the call site to a target method handle,
+ * and a typical action would be {@code someTarget.bindTo(this)}.
+ * However, the hook is free to take any action whatever,
+ * including ignoring the call site and returning a constant target.
+ * <p>
+ * The result returned by the hook must be a method handle of exactly
+ * the same type as the call site.
+ * <p>
+ * While the hook is being called, the new {@code ConstantCallSite}
+ * object is in a partially constructed state.
+ * In this state,
+ * a call to {@code getTarget}, or any other attempt to use the target,
+ * will result in an {@code IllegalStateException}.
+ * It is legal at all times to obtain the call site's type using the {@code type} method.
+ *
+ * @param targetType the type of the method handle to be permanently associated with this call site
+ * @param createTargetHook a method handle to invoke (on the call site) to produce the call site's target
+ * @throws WrongMethodTypeException if the hook cannot be invoked on the required arguments,
+ * or if the target returned by the hook is not of the given {@code targetType}
+ * @throws NullPointerException if the hook returns a null value
+ * @throws ClassCastException if the hook returns something other than a {@code MethodHandle}
+ * @throws Throwable anything else thrown by the the hook function
+ */
+ protected ConstantCallSite(MethodType targetType, MethodHandle createTargetHook) throws Throwable {
+ super(targetType, createTargetHook);
+ isFrozen = true;
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a {@code final} field of the {@code ConstantCallSite}.
+ * That is, the the target is always the original value passed
+ * to the constructor call which created this instance.
+ *
+ * @return the immutable linkage state of this call site, a constant method handle
+ * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+ */
+ @Override public final MethodHandle getTarget() {
+ if (!isFrozen) throw new IllegalStateException();
+ return target;
+ }
+
+ /**
+ * Always throws an {@link UnsupportedOperationException}.
+ * This kind of call site cannot change its target.
+ * @param ignore a new target proposed for the call site, which is ignored
+ * @throws UnsupportedOperationException because this kind of call site cannot change its target
+ */
+ @Override public final void setTarget(MethodHandle ignore) {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns this call site's permanent target.
+ * Since that target will never change, this is a correct implementation
+ * of {@link CallSite#dynamicInvoker CallSite.dynamicInvoker}.
+ * @return the immutable linkage state of this call site, a constant method handle
+ * @throws IllegalStateException if the {@code ConstantCallSite} constructor has not completed
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return getTarget();
+ }
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
index c41e0c2..9e26196 100644
--- a/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
+++ b/ojluni/src/main/java/java/lang/invoke/MethodHandles.java
@@ -665,6 +665,9 @@
*/
static final Lookup PUBLIC_LOOKUP = new Lookup(Object.class, PUBLIC);
+ /** Package-private version of lookup which is trusted. */
+ static final Lookup IMPL_LOOKUP = new Lookup(Object.class, ALL_MODES);
+
private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
String name = lookupClass.getName();
if (name.startsWith("java.lang.invoke."))
@@ -1656,7 +1659,7 @@
}
}
- public void throwMakeAccessException(String message, Object from) throws
+ private void throwMakeAccessException(String message, Object from) throws
IllegalAccessException{
message = message + ": "+ toString();
if (from != null) message += ", from " + from;
diff --git a/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java b/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java
new file mode 100644
index 0000000..37ca324
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/MutableCallSite.java
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: not used.
+// import java.util.concurrent.atomic.AtomicInteger;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code MutableCallSite} is a {@link CallSite} whose target variable
+ * behaves like an ordinary field.
+ * An {@code invokedynamic} instruction linked to a {@code MutableCallSite} delegates
+ * all calls to the site's current target.
+ * The {@linkplain CallSite#dynamicInvoker dynamic invoker} of a mutable call site
+ * also delegates each call to the site's current target.
+ * <p>
+ * Here is an example of a mutable call site which introduces a
+ * state variable into a method handle chain.
+ * <!-- JavaDocExamplesTest.testMutableCallSite -->
+ * <blockquote><pre>
+MutableCallSite name = new MutableCallSite(MethodType.methodType(String.class));
+MethodHandle MH_name = name.dynamicInvoker();
+MethodType MT_str1 = MethodType.methodType(String.class);
+MethodHandle MH_upcase = MethodHandles.lookup()
+ .findVirtual(String.class, "toUpperCase", MT_str1);
+MethodHandle worker1 = MethodHandles.filterReturnValue(MH_name, MH_upcase);
+name.setTarget(MethodHandles.constant(String.class, "Rocky"));
+assertEquals("ROCKY", (String) worker1.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Fred"));
+assertEquals("FRED", (String) worker1.invokeExact());
+// (mutation can be continued indefinitely)
+ * </pre></blockquote>
+ * <p>
+ * The same call site may be used in several places at once.
+ * <blockquote><pre>
+MethodType MT_str2 = MethodType.methodType(String.class, String.class);
+MethodHandle MH_cat = lookup().findVirtual(String.class,
+ "concat", methodType(String.class, String.class));
+MethodHandle MH_dear = MethodHandles.insertArguments(MH_cat, 1, ", dear?");
+MethodHandle worker2 = MethodHandles.filterReturnValue(MH_name, MH_dear);
+assertEquals("Fred, dear?", (String) worker2.invokeExact());
+name.setTarget(MethodHandles.constant(String.class, "Wilma"));
+assertEquals("WILMA", (String) worker1.invokeExact());
+assertEquals("Wilma, dear?", (String) worker2.invokeExact());
+ * </pre></blockquote>
+ * <p>
+ * <em>Non-synchronization of target values:</em>
+ * A write to a mutable call site's target does not force other threads
+ * to become aware of the updated value. Threads which do not perform
+ * suitable synchronization actions relative to the updated call site
+ * may cache the old target value and delay their use of the new target
+ * value indefinitely.
+ * (This is a normal consequence of the Java Memory Model as applied
+ * to object fields.)
+ * <p>
+ * For target values which will be frequently updated, consider using
+ * a {@linkplain VolatileCallSite volatile call site} instead.
+ * @author John Rose, JSR 292 EG
+ */
+public class MutableCallSite extends CallSite {
+ /**
+ * Creates a blank call site object with the given method type.
+ * The initial target is set to a method handle of the given type
+ * which will throw an {@link IllegalStateException} if called.
+ * <p>
+ * The type of the call site is permanently set to the given type.
+ * <p>
+ * Before this {@code CallSite} object is returned from a bootstrap method,
+ * or invoked in some other manner,
+ * it is usually provided with a more useful target method,
+ * via a call to {@link CallSite#setTarget(MethodHandle) setTarget}.
+ * @param type the method type that this call site will have
+ * @throws NullPointerException if the proposed type is null
+ */
+ public MutableCallSite(MethodType type) {
+ super(type);
+ }
+
+ /**
+ * Creates a call site object with an initial target method handle.
+ * The type of the call site is permanently set to the initial target's type.
+ * @param target the method handle that will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public MutableCallSite(MethodHandle target) {
+ super(target);
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a normal field of the {@code MutableCallSite}.
+ * <p>
+ * The interactions of {@code getTarget} with memory are the same
+ * as of a read from an ordinary variable, such as an array element or a
+ * non-volatile, non-final field.
+ * <p>
+ * In particular, the current thread may choose to reuse the result
+ * of a previous read of the target from memory, and may fail to see
+ * a recent update to the target by another thread.
+ *
+ * @return the linkage state of this call site, a method handle which can change over time
+ * @see #setTarget
+ */
+ @Override public final MethodHandle getTarget() {
+ return target;
+ }
+
+ /**
+ * Updates the target method of this call site, as a normal variable.
+ * The type of the new target must agree with the type of the old target.
+ * <p>
+ * The interactions with memory are the same
+ * as of a write to an ordinary variable, such as an array element or a
+ * non-volatile, non-final field.
+ * <p>
+ * In particular, unrelated threads may fail to see the updated target
+ * until they perform a read from memory.
+ * Stronger guarantees can be created by putting appropriate operations
+ * into the bootstrap method and/or the target methods used
+ * at any given call site.
+ *
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see #getTarget
+ */
+ @Override public void setTarget(MethodHandle newTarget) {
+ checkTargetChange(this.target, newTarget);
+ setTargetNormal(newTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return makeDynamicInvoker();
+ }
+
+ // Android-changed: not exposing incomplete implementation.
+ // /**
+ // * Performs a synchronization operation on each call site in the given array,
+ // * forcing all other threads to throw away any cached values previously
+ // * loaded from the target of any of the call sites.
+ // * <p>
+ // * This operation does not reverse any calls that have already started
+ // * on an old target value.
+ // * (Java supports {@linkplain java.lang.Object#wait() forward time travel} only.)
+ // * <p>
+ // * The overall effect is to force all future readers of each call site's target
+ // * to accept the most recently stored value.
+ // * ("Most recently" is reckoned relative to the {@code syncAll} itself.)
+ // * Conversely, the {@code syncAll} call may block until all readers have
+ // * (somehow) decached all previous versions of each call site's target.
+ // * <p>
+ // * To avoid race conditions, calls to {@code setTarget} and {@code syncAll}
+ // * should generally be performed under some sort of mutual exclusion.
+ // * Note that reader threads may observe an updated target as early
+ // * as the {@code setTarget} call that install the value
+ // * (and before the {@code syncAll} that confirms the value).
+ // * On the other hand, reader threads may observe previous versions of
+ // * the target until the {@code syncAll} call returns
+ // * (and after the {@code setTarget} that attempts to convey the updated version).
+ // * <p>
+ // * This operation is likely to be expensive and should be used sparingly.
+ // * If possible, it should be buffered for batch processing on sets of call sites.
+ // * <p>
+ // * If {@code sites} contains a null element,
+ // * a {@code NullPointerException} will be raised.
+ // * In this case, some non-null elements in the array may be
+ // * processed before the method returns abnormally.
+ // * Which elements these are (if any) is implementation-dependent.
+ // *
+ // * <h3>Java Memory Model details</h3>
+ // * In terms of the Java Memory Model, this operation performs a synchronization
+ // * action which is comparable in effect to the writing of a volatile variable
+ // * by the current thread, and an eventual volatile read by every other thread
+ // * that may access one of the affected call sites.
+ // * <p>
+ // * The following effects are apparent, for each individual call site {@code S}:
+ // * <ul>
+ // * <li>A new volatile variable {@code V} is created, and written by the current thread.
+ // * As defined by the JMM, this write is a global synchronization event.
+ // * <li>As is normal with thread-local ordering of write events,
+ // * every action already performed by the current thread is
+ // * taken to happen before the volatile write to {@code V}.
+ // * (In some implementations, this means that the current thread
+ // * performs a global release operation.)
+ // * <li>Specifically, the write to the current target of {@code S} is
+ // * taken to happen before the volatile write to {@code V}.
+ // * <li>The volatile write to {@code V} is placed
+ // * (in an implementation specific manner)
+ // * in the global synchronization order.
+ // * <li>Consider an arbitrary thread {@code T} (other than the current thread).
+ // * If {@code T} executes a synchronization action {@code A}
+ // * after the volatile write to {@code V} (in the global synchronization order),
+ // * it is therefore required to see either the current target
+ // * of {@code S}, or a later write to that target,
+ // * if it executes a read on the target of {@code S}.
+ // * (This constraint is called "synchronization-order consistency".)
+ // * <li>The JMM specifically allows optimizing compilers to elide
+ // * reads or writes of variables that are known to be useless.
+ // * Such elided reads and writes have no effect on the happens-before
+ // * relation. Regardless of this fact, the volatile {@code V}
+ // * will not be elided, even though its written value is
+ // * indeterminate and its read value is not used.
+ // * </ul>
+ // * Because of the last point, the implementation behaves as if a
+ // * volatile read of {@code V} were performed by {@code T}
+ // * immediately after its action {@code A}. In the local ordering
+ // * of actions in {@code T}, this read happens before any future
+ // * read of the target of {@code S}. It is as if the
+ // * implementation arbitrarily picked a read of {@code S}'s target
+ // * by {@code T}, and forced a read of {@code V} to precede it,
+ // * thereby ensuring communication of the new target value.
+ // * <p>
+ // * As long as the constraints of the Java Memory Model are obeyed,
+ // * implementations may delay the completion of a {@code syncAll}
+ // * operation while other threads ({@code T} above) continue to
+ // * use previous values of {@code S}'s target.
+ // * However, implementations are (as always) encouraged to avoid
+ // * livelock, and to eventually require all threads to take account
+ // * of the updated target.
+ // *
+ // * <p style="font-size:smaller;">
+ // * <em>Discussion:</em>
+ // * For performance reasons, {@code syncAll} is not a virtual method
+ // * on a single call site, but rather applies to a set of call sites.
+ // * Some implementations may incur a large fixed overhead cost
+ // * for processing one or more synchronization operations,
+ // * but a small incremental cost for each additional call site.
+ // * In any case, this operation is likely to be costly, since
+ // * other threads may have to be somehow interrupted
+ // * in order to make them notice the updated target value.
+ // * However, it may be observed that a single call to synchronize
+ // * several sites has the same formal effect as many calls,
+ // * each on just one of the sites.
+ // *
+ // * <p style="font-size:smaller;">
+ // * <em>Implementation Note:</em>
+ // * Simple implementations of {@code MutableCallSite} may use
+ // * a volatile variable for the target of a mutable call site.
+ // * In such an implementation, the {@code syncAll} method can be a no-op,
+ // * and yet it will conform to the JMM behavior documented above.
+ // *
+ // * @param sites an array of call sites to be synchronized
+ // * @throws NullPointerException if the {@code sites} array reference is null
+ // * or the array contains a null
+ // */
+ // public static void syncAll(MutableCallSite[] sites) {
+ // if (sites.length == 0) return;
+ // STORE_BARRIER.lazySet(0);
+ // for (int i = 0; i < sites.length; i++) {
+ // sites[i].getClass(); // trigger NPE on first null
+ // }
+ // // FIXME: NYI
+ // }
+ // private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+}
diff --git a/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java b/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java
new file mode 100644
index 0000000..6444335
--- /dev/null
+++ b/ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang.invoke;
+
+// Android-changed: removed references to MutableCallSite.syncAll().
+/**
+ * A {@code VolatileCallSite} is a {@link CallSite} whose target acts like a volatile variable.
+ * An {@code invokedynamic} instruction linked to a {@code VolatileCallSite} sees updates
+ * to its call site target immediately, even if the update occurs in another thread.
+ * There may be a performance penalty for such tight coupling between threads.
+ * <p>
+ * In other respects, a {@code VolatileCallSite} is interchangeable
+ * with {@code MutableCallSite}.
+ * @see MutableCallSite
+ * @author John Rose, JSR 292 EG
+ */
+public class VolatileCallSite extends CallSite {
+ /**
+ * Creates a call site with a volatile binding to its target.
+ * The initial target is set to a method handle
+ * of the given type which will throw an {@code IllegalStateException} if called.
+ * @param type the method type that this call site will have
+ * @throws NullPointerException if the proposed type is null
+ */
+ public VolatileCallSite(MethodType type) {
+ super(type);
+ }
+
+ /**
+ * Creates a call site with a volatile binding to its target.
+ * The target is set to the given value.
+ * @param target the method handle that will be the initial target of the call site
+ * @throws NullPointerException if the proposed target is null
+ */
+ public VolatileCallSite(MethodHandle target) {
+ super(target);
+ }
+
+ /**
+ * Returns the target method of the call site, which behaves
+ * like a {@code volatile} field of the {@code VolatileCallSite}.
+ * <p>
+ * The interactions of {@code getTarget} with memory are the same
+ * as of a read from a {@code volatile} field.
+ * <p>
+ * In particular, the current thread is required to issue a fresh
+ * read of the target from memory, and must not fail to see
+ * a recent update to the target by another thread.
+ *
+ * @return the linkage state of this call site, a method handle which can change over time
+ * @see #setTarget
+ */
+ @Override public final MethodHandle getTarget() {
+ return getTargetVolatile();
+ }
+
+ /**
+ * Updates the target method of this call site, as a volatile variable.
+ * The type of the new target must agree with the type of the old target.
+ * <p>
+ * The interactions with memory are the same as of a write to a volatile field.
+ * In particular, any threads is guaranteed to see the updated target
+ * the next time it calls {@code getTarget}.
+ * @param newTarget the new target
+ * @throws NullPointerException if the proposed new target is null
+ * @throws WrongMethodTypeException if the proposed new target
+ * has a method type that differs from the previous target
+ * @see #getTarget
+ */
+ @Override public void setTarget(MethodHandle newTarget) {
+ checkTargetChange(getTargetVolatile(), newTarget);
+ setTargetVolatile(newTarget);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final MethodHandle dynamicInvoker() {
+ return makeDynamicInvoker();
+ }
+}
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index deb186c..a932893 100644
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -895,15 +895,6 @@
algorithm = algorithm.toUpperCase(ENGLISH);
this.algorithm = intern ? algorithm.intern() : algorithm;
}
- // BEGIN ANDROID-CHANGED
- // The above constructor is not amenable to compile-time execution as Locale.ENGLISH
- // cannot be retrieved. Special-case a constructor for the static field "previousKey".
- private ServiceKey() {
- this.type = "";
- this.originalAlgorithm = "";
- this.algorithm = "";
- }
- // END ANDROID-CHANGED
public int hashCode() {
return type.hashCode() + algorithm.hashCode();
}
@@ -1088,10 +1079,7 @@
// list and queries each provider with the same values until it finds
// a matching service
private static volatile ServiceKey previousKey =
- // BEGIN ANDROID-CHANGED
- // was: new ServiceKey("", "", false);
- new ServiceKey();
- // END ANDROID-CHANGED
+ new ServiceKey("", "", false);
/**
* Get an unmodifiable Set of all services supported by
diff --git a/ojluni/src/main/java/java/time/Instant.java b/ojluni/src/main/java/java/time/Instant.java
index 91a177c..9b9efa5 100644
--- a/ojluni/src/main/java/java/time/Instant.java
+++ b/ojluni/src/main/java/java/time/Instant.java
@@ -1229,8 +1229,14 @@
* @throws ArithmeticException if numeric overflow occurs
*/
public long toEpochMilli() {
- long millis = Math.multiplyExact(seconds, 1000);
- return millis + nanos / 1000_000;
+ if (seconds < 0 && nanos > 0) {
+ long millis = Math.multiplyExact(seconds+1, 1000);
+ long adjustment = nanos / 1000_000 - 1000;
+ return Math.addExact(millis, adjustment);
+ } else {
+ long millis = Math.multiplyExact(seconds, 1000);
+ return Math.addExact(millis, nanos / 1000_000);
+ }
}
//-----------------------------------------------------------------------
diff --git a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
index 15f7d84..29e503e 100644
--- a/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
+++ b/ojluni/src/main/java/java/time/chrono/JapaneseChronology.java
@@ -132,7 +132,7 @@
private static final Locale LOCALE = Locale.forLanguageTag("ja-JP-u-ca-japanese");
static Calendar createCalendar() {
- return Calendar.getJapanesImperialInstance(TimeZone.getDefault(), LOCALE);
+ return Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), LOCALE);
}
/**
diff --git a/ojluni/src/main/java/java/util/Calendar.java b/ojluni/src/main/java/java/util/Calendar.java
index 60c1c97..8593403 100644
--- a/ojluni/src/main/java/java/util/Calendar.java
+++ b/ojluni/src/main/java/java/util/Calendar.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1161,12 +1161,13 @@
return this;
}
+ // Android-changed: fix typo in example code.
/**
* Sets field parameters to their values given by
* {@code fieldValuePairs} that are pairs of a field and its value.
* For example,
* <pre>
- * setFeilds(Calendar.YEAR, 2013,
+ * setFields(Calendar.YEAR, 2013,
* Calendar.MONTH, Calendar.DECEMBER,
* Calendar.DAY_OF_MONTH, 23);</pre>
* is equivalent to the sequence of the following
@@ -1464,12 +1465,17 @@
type = locale.getUnicodeLocaleType("ca");
}
if (type == null) {
+ // Android-changed: don't switch to buddhist calendar based on locale.
+ // See http://b/35138741
+ /*
if (locale.getCountry() == "TH"
- && locale.getLanguage() == "th") {
+ && locale.getLanguage() == "th") {
type = "buddhist";
} else {
type = "gregory";
}
+ */
+ type = "gregory";
}
switch (type) {
case "gregory":
@@ -1483,6 +1489,15 @@
setWeekDefinition(MONDAY, 4);
cal = gcal;
break;
+// Android-changed BEGIN: removed support for "buddhist" and "japanese".
+// case "buddhist":
+// cal = new BuddhistCalendar(zone, locale);
+// cal.clear();
+// break;
+// case "japanese":
+// cal = new JapaneseImperialCalendar(zone, locale, true);
+// break;
+// Android-changed END: removed support for "buddhist" and "japanese".
default:
throw new IllegalArgumentException("unknown calendar type: " + type);
}
@@ -1579,6 +1594,7 @@
*/
protected Calendar(TimeZone zone, Locale aLocale)
{
+ // Android-added BEGIN: Allow aLocale == null
// http://b/16938922.
//
// TODO: This is for backwards compatibility only. Seems like a better idea to throw
@@ -1586,6 +1602,7 @@
if (aLocale == null) {
aLocale = Locale.getDefault();
}
+ // Android-added END: Allow aLocale == null
fields = new int[FIELD_COUNT];
isSet = new boolean[FIELD_COUNT];
stamp = new int[FIELD_COUNT];
@@ -1649,18 +1666,22 @@
return createCalendar(zone, aLocale);
}
+ // Android-added BEGIN: add getJapaneseImperialInstance()
/**
* Create a Japanese Imperial Calendar.
* @hide
*/
- public static Calendar getJapanesImperialInstance(TimeZone zone, Locale aLocale) {
+ public static Calendar getJapaneseImperialInstance(TimeZone zone, Locale aLocale) {
return new JapaneseImperialCalendar(zone, aLocale);
}
+ // Android-added END: add getJapaneseImperialInstance()
private static Calendar createCalendar(TimeZone zone,
Locale aLocale)
{
+ // Android-changed BEGIN: only support GregorianCalendar here
return new GregorianCalendar(zone, aLocale);
+ // Android-changed END: only support GregorianCalendar here
}
/**
@@ -1751,7 +1772,12 @@
public void setTimeInMillis(long millis) {
// If we don't need to recalculate the calendar field values,
// do nothing.
+// Android-changed BEGIN: Removed ZoneInfo support
if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet) {
+// if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
+// && (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
+// Android-changed END: Removed ZoneInfo support
+
return;
}
time = millis;
@@ -2034,11 +2060,13 @@
* @since 1.6
*/
public String getDisplayName(int field, int style, Locale locale) {
- // Android-changed: Android has traditionally treated ALL_STYLES as SHORT, even though
+ // Android-changed BEGIN: Treat ALL_STYLES as SHORT
+ // Android has traditionally treated ALL_STYLES as SHORT, even though
// it's not documented to be a valid value for style.
if (style == ALL_STYLES) {
style = SHORT;
}
+ // Android-changed END: Treat ALL_STYLES as SHORT
if (!checkDisplayNameParams(field, style, SHORT, NARROW_FORMAT, locale,
ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null;
@@ -2132,6 +2160,7 @@
ERA_MASK|MONTH_MASK|DAY_OF_WEEK_MASK|AM_PM_MASK)) {
return null;
}
+ // Android-added: Add complete() here to fix leniency, see http://b/35382060
complete();
String calendarType = getCalendarType();
@@ -2179,10 +2208,12 @@
baseStyle < minStyle || baseStyle > maxStyle) {
throw new IllegalArgumentException();
}
- // Android-changed: 3 is not a valid base style (1, 2 and 4 are, though), throw if used.
+ // Android-added BEGIN: Check for invalid baseStyle == 3
+ // 3 is not a valid base style (unlike 1, 2 and 4). Throw if used.
if (baseStyle == 3) {
throw new IllegalArgumentException();
}
+ // Android-added END: Check for invalid baseStyle == 3
if (locale == null) {
throw new NullPointerException();
}
@@ -2595,6 +2626,7 @@
static {
Set<String> set = new HashSet<>(3);
set.add("gregory");
+ // Android-changed: removed "buddhist" and "japanese".
SET = Collections.unmodifiableSet(set);
}
private AvailableCalendarTypes() {
diff --git a/ojluni/src/main/java/java/util/Formatter.java b/ojluni/src/main/java/java/util/Formatter.java
index ca1b990..43d5043 100644
--- a/ojluni/src/main/java/java/util/Formatter.java
+++ b/ojluni/src/main/java/java/util/Formatter.java
@@ -2710,6 +2710,7 @@
if (s != null) {
try {
// Android-changed: FormatSpecifierParser passes in correct String.
+ // index = Integer.parseInt(s.substring(0, s.length() - 1));
index = Integer.parseInt(s);
} catch (NumberFormatException x) {
assert(false);
@@ -2757,6 +2758,8 @@
precision = -1;
if (s != null) {
try {
+ // Android-changed: FormatSpecifierParser passes in correct String.
+ // precision = Integer.parseInt(s.substring(1));
precision = Integer.parseInt(s);
if (precision < 0)
throw new IllegalFormatPrecisionException(precision);
@@ -2789,7 +2792,7 @@
return c;
}
- // Android-changed: FormatSpecifierParser passes in the values instead of a Matcher.
+ // Android-changed BEGIN: FormatSpecifierParser passes in the values instead of a Matcher.
FormatSpecifier(String indexStr, String flagsStr, String widthStr,
String precisionStr, String tTStr, String convStr) {
int idx = 1;
@@ -2806,7 +2809,7 @@
}
conversion(convStr);
-
+ // Android-changed END: FormatSpecifierParser passes in the values instead of a Matcher.
if (dt)
checkDateTime();
else if (Conversion.isGeneral(c))
@@ -2998,6 +3001,7 @@
s = s.substring(0, precision);
if (f.contains(Flags.UPPERCASE)) {
// Android-changed: Use provided locale instead of default, if it is non-null.
+ // s = s.toUpperCase();
s = s.toUpperCase(l != null ? l : Locale.getDefault());
}
a.append(justify(s));
@@ -3369,12 +3373,13 @@
newW = adjustWidth(width - exp.length - 1, f, neg);
localizedMagnitude(sb, mant, f, newW, l);
- // Android-changed: Use localized exponent separator for %e.
+ // Android-changed BEGIN: Use localized exponent separator for %e.
Locale separatorLocale = (l != null) ? l : Locale.getDefault();
LocaleData localeData = LocaleData.get(separatorLocale);
sb.append(f.contains(Flags.UPPERCASE) ?
localeData.exponentSeparator.toUpperCase(separatorLocale) :
localeData.exponentSeparator.toLowerCase(separatorLocale));
+ // Android-changed END: Use localized exponent separator for %e.
Flags flags = f.dup().remove(Flags.GROUP);
char sign = exp[0];
@@ -4455,14 +4460,14 @@
grpSep = dfs.getGroupingSeparator();
DecimalFormat df = (DecimalFormat) NumberFormat.getIntegerInstance(l);
grpSize = df.getGroupingSize();
- // Android-changed: http://b/33245708 : Some locales have a group separator but
- // also patterns without groups. If we do not clear the group separator in these
- // cases a divide by zero is thrown when determining where to place the
- // separators.
+ // Android-changed BEGIN: http://b/33245708
+ // Some locales have a group separator but also patterns without groups.
+ // If we do not clear the group separator in these cases a divide by zero
+ // is thrown when determining where to place the separators.
if (!df.isGroupingUsed() || df.getGroupingSize() == 0) {
grpSep = '\0';
}
- // Android-changed: end http://b/33245708.
+ // Android-changed END: http://b/33245708.
}
}
diff --git a/ojluni/src/main/java/java/util/GregorianCalendar.java b/ojluni/src/main/java/java/util/GregorianCalendar.java
index 3d8a7c79..15c7652 100644
--- a/ojluni/src/main/java/java/util/GregorianCalendar.java
+++ b/ojluni/src/main/java/java/util/GregorianCalendar.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1996, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -739,10 +739,12 @@
gdate = (BaseCalendar.Date) gcal.newCalendarDate(getZone());
}
+ // Android-added BEGIN
GregorianCalendar(long milliseconds) {
this();
setTimeInMillis(milliseconds);
}
+ // Android-added END
/////////////////
// Public methods
@@ -1078,8 +1080,7 @@
}
fd += delta; // fd is the expected fixed date after the calculation
-
- // Android changed: move time zone related calculation to separate method.
+ // Android-changed BEGIN: time zone related calculation via helper methods
// Calculate the time in the UTC time zone.
long utcTime = (fd - EPOCH_OFFSET) * ONE_DAY + timeOfDay;
@@ -1092,6 +1093,7 @@
// Update the time and recompute the fields.
setTimeInMillis(millis);
+ // Android-changed END: time zone related calculation via helper methods
}
}
@@ -2344,9 +2346,12 @@
}
if (tzMask != (ZONE_OFFSET_MASK|DST_OFFSET_MASK)) {
if (tz instanceof ZoneInfo) {
- // Android changed: libcore ZoneInfo uses different method to get offsets.
+ // Android changed BEGIN: use libcore.util.ZoneInfo
+ // The method name to get offsets differs from sun.util.calendar.ZoneInfo
+ // zoneOffset = ((ZoneInfo)tz).getOffsets(time, zoneOffsets);
ZoneInfo zoneInfo = (ZoneInfo) tz;
zoneOffset = zoneInfo.getOffsetsByUtcTime(time, zoneOffsets);
+ // Android-changed END: use libcore.util.ZoneInfo
} else {
zoneOffset = tz.getOffset(time);
zoneOffsets[0] = tz.getRawOffset();
@@ -2796,11 +2801,11 @@
// We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
// or DST_OFFSET fields; then we use those fields.
TimeZone zone = getZone();
- // Android changed: move time zone related calculation to separate method.
-
+ // Android-changed BEGIN: time zone related calculation via helper methods
int tzMask = fieldMask & (ZONE_OFFSET_MASK|DST_OFFSET_MASK);
millis = adjustForZoneAndDaylightSavingsTime(tzMask, millis, zone);
+ // Android-changed END: time zone related calculation via helper methods
// Set this calendar's time in milliseconds
time = millis;
@@ -2823,6 +2828,7 @@
setFieldsNormalized(mask);
}
+ // Android-added BEGIN: helper methods for time zone related calculation
/**
* Calculates the time in milliseconds that this calendar represents using the UTC time,
* timezone information (specifically Daylight Savings Time (DST) rules, if any) and knowledge
@@ -2992,6 +2998,7 @@
}
return dstOffset;
}
+ // Android-added END: helper methods for time zone related calculation
/**
* Computes the fixed date under either the Gregorian or the
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index 9c75a32..45949c6 100644
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -886,7 +886,8 @@
*/
public static Locale getDefault() {
// do not synchronize this method - see 4071298
- return defaultLocale;
+ // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+ return NoImagePreloadHolder.defaultLocale;
}
/**
@@ -972,6 +973,8 @@
}
private static Locale initDefault(Locale.Category category) {
+ // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+ final Locale defaultLocale = NoImagePreloadHolder.defaultLocale;
return getInstance(
System.getProperty(category.languageKey, defaultLocale.getLanguage()),
System.getProperty(category.scriptKey, defaultLocale.getScript()),
@@ -1012,7 +1015,8 @@
public static synchronized void setDefault(Locale newLocale) {
setDefault(Category.DISPLAY, newLocale);
setDefault(Category.FORMAT, newLocale);
- defaultLocale = newLocale;
+ // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+ NoImagePreloadHolder.defaultLocale = newLocale;
// Android-added: Keep ICU state in sync with java.util.
ICU.setDefaultLocale(newLocale.toLanguageTag());
}
@@ -2184,7 +2188,10 @@
*/
private transient volatile int hashCodeValue = 0;
- private volatile static Locale defaultLocale = initDefault();
+ // Android-changed: Add NoImagePreloadHolder to allow compile-time initialization.
+ private static class NoImagePreloadHolder {
+ public volatile static Locale defaultLocale = initDefault();
+ }
private volatile static Locale defaultDisplayLocale = null;
private volatile static Locale defaultFormatLocale = null;
diff --git a/ojluni/src/test/java/nio/file/TestUtil.java b/ojluni/src/test/java/nio/file/TestUtil.java
new file mode 100644
index 0000000..2d102fd
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/TestUtil.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+// Android-changed: Adapted from jdk/test/java/nio/file/TestUtil.java
+// Android-changed: Added package & made methods public
+package test.java.nio.file;
+
+import java.nio.file.*;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.Random;
+import java.io.IOException;
+
+public class TestUtil {
+ private TestUtil() {
+ }
+
+ static public Path createTemporaryDirectory(String where) throws IOException {
+ Path dir = FileSystems.getDefault().getPath(where);
+ return Files.createTempDirectory(dir, "name");
+ }
+
+ static public Path createTemporaryDirectory() throws IOException {
+ return Files.createTempDirectory("name");
+ }
+
+ static public void removeAll(Path dir) throws IOException {
+ Files.walkFileTree(dir, new FileVisitor<Path>() {
+ @Override
+ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) {
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
+ try {
+ Files.delete(file);
+ } catch (IOException x) {
+ System.err.format("Unable to delete %s: %s\n", file, x);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
+ try {
+ Files.delete(dir);
+ } catch (IOException x) {
+ System.err.format("Unable to delete %s: %s\n", dir, x);
+ }
+ return FileVisitResult.CONTINUE;
+ }
+ @Override
+ public FileVisitResult visitFileFailed(Path file, IOException exc) {
+ System.err.format("Unable to visit %s: %s\n", file, exc);
+ return FileVisitResult.CONTINUE;
+ }
+ });
+ }
+
+ static public void deleteUnchecked(Path file) {
+ try {
+ Files.delete(file);
+ } catch (IOException exc) {
+ System.err.format("Unable to delete %s: %s\n", file, exc);
+ }
+ }
+
+ /**
+ * Creates a directory tree in the given directory so that the total
+ * size of the path is more than 2k in size. This is used for long
+ * path tests on Windows.
+ */
+ static public Path createDirectoryWithLongPath(Path dir)
+ throws IOException
+ {
+ StringBuilder sb = new StringBuilder();
+ for (int i=0; i<240; i++) {
+ sb.append('A');
+ }
+ String name = sb.toString();
+ do {
+ dir = dir.resolve(name).resolve(".");
+ Files.createDirectory(dir);
+ } while (dir.toString().length() < 2048);
+ return dir;
+ }
+
+ /**
+ * Returns true if symbolic links are supported
+ */
+ static public boolean supportsLinks(Path dir) {
+ Path link = dir.resolve("testlink");
+ Path target = dir.resolve("testtarget");
+ try {
+ Files.createSymbolicLink(link, target);
+ Files.delete(link);
+ return true;
+ } catch (UnsupportedOperationException x) {
+ return false;
+ } catch (IOException x) {
+ return false;
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java b/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java
new file mode 100644
index 0000000..7f0c17b
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/AclEntryEmptySetTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 7076310
+ * @summary Test AclEntry.Builder setFlags and setPermissions with empty sets
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/AclEntry/EmptySet.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+
+import java.nio.file.attribute.*;
+import java.util.*;
+
+/*
+ * Test for bug 7076310 "(file) AclEntry.Builder setFlags throws
+ * IllegalArgumentException if set argument is empty"
+ * The bug is only applies when the given Set is NOT an instance of EnumSet.
+ *
+ * The setPermissions method also has the same problem.
+ */
+// Android-changed: Renamed from "EmptySet"
+public class AclEntryEmptySetTest {
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() {
+ Set<AclEntryFlag> flags = new HashSet<>();
+ AclEntry.newBuilder().setFlags(flags);
+
+ Set<AclEntryPermission> perms = new HashSet<>();
+ AclEntry.newBuilder().setPermissions(perms);
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java
new file mode 100644
index 0000000..262aa81
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/AclFileAttributeViewTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333 6891404
+ * @summary Unit test for java.nio.file.attribute.AclFileAttribueView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+import static java.nio.file.attribute.AclEntryType.*;
+import static java.nio.file.attribute.AclEntryPermission.*;
+import static java.nio.file.attribute.AclEntryFlag.*;
+
+// Android-changed: Renamed from "Basic"
+public class AclFileAttributeViewTest {
+
+ static void printAcl(List<AclEntry> acl) {
+ for (AclEntry entry: acl) {
+ System.out.format(" %s%n", entry);
+ }
+ }
+
+ // sanity check read and writing ACL
+ static void testReadWrite(Path dir) throws IOException {
+ Path file = dir.resolve("foo");
+ if (Files.notExists(file))
+ Files.createFile(file);
+
+ AclFileAttributeView view =
+ Files.getFileAttributeView(file, AclFileAttributeView.class);
+
+ // print existing ACL
+ List<AclEntry> acl = view.getAcl();
+ System.out.println(" -- current ACL --");
+ printAcl(acl);
+
+ // insert entry to grant owner read access
+ UserPrincipal owner = view.getOwner();
+ AclEntry entry = AclEntry.newBuilder()
+ .setType(ALLOW)
+ .setPrincipal(owner)
+ .setPermissions(READ_DATA, READ_ATTRIBUTES)
+ .build();
+ System.out.println(" -- insert (entry 0) --");
+ System.out.format(" %s%n", entry);
+ acl.add(0, entry);
+ view.setAcl(acl);
+
+ // re-ACL and check entry
+ List<AclEntry> newacl = view.getAcl();
+ System.out.println(" -- current ACL --");
+ printAcl(acl);
+ if (!newacl.get(0).equals(entry)) {
+ throw new RuntimeException("Entry 0 is not expected");
+ }
+
+ // if PosixFileAttributeView then repeat test with OWNER@
+ if (Files.getFileStore(file).supportsFileAttributeView("posix")) {
+ owner = file.getFileSystem().getUserPrincipalLookupService()
+ .lookupPrincipalByName("OWNER@");
+ entry = AclEntry.newBuilder(entry).setPrincipal(owner).build();
+
+ System.out.println(" -- replace (entry 0) --");
+ System.out.format(" %s%n", entry);
+
+ acl.set(0, entry);
+ view.setAcl(acl);
+ newacl = view.getAcl();
+ System.out.println(" -- current ACL --");
+ printAcl(acl);
+ if (!newacl.get(0).equals(entry)) {
+ throw new RuntimeException("Entry 0 is not expected");
+ }
+ }
+ }
+
+ static FileAttribute<List<AclEntry>> asAclAttribute(final List<AclEntry> acl) {
+ return new FileAttribute<List<AclEntry>>() {
+ public String name() { return "acl:acl"; }
+ public List<AclEntry> value() { return acl; }
+ };
+ }
+
+ static void assertEquals(List<AclEntry> actual, List<AclEntry> expected) {
+ if (!actual.equals(expected)) {
+ System.err.format("Actual: %s\n", actual);
+ System.err.format("Expected: %s\n", expected);
+ throw new RuntimeException("ACL not expected");
+ }
+ }
+
+ // sanity check create a file or directory with initial ACL
+ static void testCreateFile(Path dir) throws IOException {
+ UserPrincipal user = Files.getOwner(dir);
+ AclFileAttributeView view;
+
+ // create file with initial ACL
+ System.out.println("-- create file with initial ACL --");
+ Path file = dir.resolve("gus");
+ List<AclEntry> fileAcl = Arrays.asList(
+ AclEntry.newBuilder()
+ .setType(AclEntryType.ALLOW)
+ .setPrincipal(user)
+ .setPermissions(SYNCHRONIZE, READ_DATA, WRITE_DATA,
+ READ_ATTRIBUTES, READ_ACL, WRITE_ATTRIBUTES, DELETE)
+ .build());
+ Files.createFile(file, asAclAttribute(fileAcl));
+ view = Files.getFileAttributeView(file, AclFileAttributeView.class);
+ assertEquals(view.getAcl(), fileAcl);
+
+ // create directory with initial ACL
+ System.out.println("-- create directory with initial ACL --");
+ Path subdir = dir.resolve("stuff");
+ List<AclEntry> dirAcl = Arrays.asList(
+ AclEntry.newBuilder()
+ .setType(AclEntryType.ALLOW)
+ .setPrincipal(user)
+ .setPermissions(SYNCHRONIZE, ADD_FILE, DELETE)
+ .build(),
+ AclEntry.newBuilder(fileAcl.get(0))
+ .setFlags(FILE_INHERIT)
+ .build());
+ Files.createDirectory(subdir, asAclAttribute(dirAcl));
+ view = Files.getFileAttributeView(subdir, AclFileAttributeView.class);
+ assertEquals(view.getAcl(), dirAcl);
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ // use work directory rather than system temporary directory to
+ // improve chances that ACLs are supported
+ Path dir = Paths.get("./work" + new Random().nextInt());
+ Files.createDirectory(dir);
+ try {
+ if (!Files.getFileStore(dir).supportsFileAttributeView("acl")) {
+ System.out.println("ACLs not supported - test skipped!");
+ return;
+ }
+ testReadWrite(dir);
+
+ // only currently feasible on Windows
+ if (System.getProperty("os.name").startsWith("Windows"))
+ testCreateFile(dir);
+
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java
new file mode 100644
index 0000000..b393981
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewCreationTimeTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 8011536
+ * @summary Basic test for creationTime attribute on platforms/file systems
+ * that support it.
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/BasicFileAttributeView/CreationTime.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.Path;
+import java.nio.file.Files;
+import java.nio.file.attribute.*;
+import java.time.Instant;
+import java.io.IOException;
+
+// Android-changed: Renamed from "CreationTime"
+public class BasicFileAttributeViewCreationTimeTest {
+
+ private static final java.io.PrintStream err = System.err;
+
+ /**
+ * Reads the creationTime attribute
+ */
+ private static FileTime creationTime(Path file) throws IOException {
+ return Files.readAttributes(file, BasicFileAttributes.class).creationTime();
+ }
+
+ /**
+ * Sets the creationTime attribute
+ */
+ private static void setCreationTime(Path file, FileTime time) throws IOException {
+ BasicFileAttributeView view =
+ Files.getFileAttributeView(file, BasicFileAttributeView.class);
+ view.setTimes(null, null, time);
+ }
+
+ static void test(Path top) throws IOException {
+ Path file = Files.createFile(top.resolve("foo"));
+
+ /**
+ * Check that creationTime reported
+ */
+ FileTime creationTime = creationTime(file);
+ Instant now = Instant.now();
+ if (Math.abs(creationTime.toMillis()-now.toEpochMilli()) > 10000L) {
+ err.println("File creation time reported as: " + creationTime);
+ throw new RuntimeException("Expected to be close to: " + now);
+ }
+
+ /**
+ * Is the creationTime attribute supported here?
+ */
+ boolean supportsCreationTimeRead = false;
+ boolean supportsCreationTimeWrite = false;
+ String os = System.getProperty("os.name");
+ if (os.contains("OS X") && Files.getFileStore(file).type().equals("hfs")) {
+ supportsCreationTimeRead = true;
+ } else if (os.startsWith("Windows")) {
+ String type = Files.getFileStore(file).type();
+ if (type.equals("NTFS") || type.equals("FAT")) {
+ supportsCreationTimeRead = true;
+ supportsCreationTimeWrite = true;
+ }
+ }
+
+ /**
+ * If the creation-time attribute is supported then change the file's
+ * last modified and check that it doesn't change the creation-time.
+ */
+ if (supportsCreationTimeRead) {
+ // change modified time by +1 hour
+ Instant plusHour = Instant.now().plusSeconds(60L * 60L);
+ Files.setLastModifiedTime(file, FileTime.from(plusHour));
+ FileTime current = creationTime(file);
+ if (!current.equals(creationTime))
+ throw new RuntimeException("Creation time should not have changed");
+ }
+
+ /**
+ * If the creation-time attribute is supported and can be changed then
+ * check that the change is effective.
+ */
+ if (supportsCreationTimeWrite) {
+ // change creation time by -1 hour
+ Instant minusHour = Instant.now().minusSeconds(60L * 60L);
+ creationTime = FileTime.from(minusHour);
+ setCreationTime(file, creationTime);
+ FileTime current = creationTime(file);
+ if (Math.abs(creationTime.toMillis()-current.toMillis()) > 1000L)
+ throw new RuntimeException("Creation time not changed");
+ }
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ // create temporary directory to run tests
+ Path dir = TestUtil.createTemporaryDirectory();
+ try {
+ test(dir);
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java
new file mode 100644
index 0000000..82f4e0e
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/BasicFileAttributeViewTest.java
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.BasicFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/BasicFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.io.*;
+
+// Android-changed: Renamed from "Basic"
+public class BasicFileAttributeViewTest {
+
+ static void check(boolean okay, String msg) {
+ if (!okay)
+ throw new RuntimeException(msg);
+ }
+
+ static void checkAttributesOfDirectory(Path dir)
+ throws IOException
+ {
+ BasicFileAttributes attrs = Files.readAttributes(dir, BasicFileAttributes.class);
+ check(attrs.isDirectory(), "is a directory");
+ check(!attrs.isRegularFile(), "is not a regular file");
+ check(!attrs.isSymbolicLink(), "is not a link");
+ check(!attrs.isOther(), "is not other");
+
+ // last-modified-time should match java.io.File in seconds
+ File f = new File(dir.toString());
+ check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
+ "last-modified time should be the same");
+ }
+
+ static void checkAttributesOfFile(Path dir, Path file)
+ throws IOException
+ {
+ BasicFileAttributes attrs = Files.readAttributes(file, BasicFileAttributes.class);
+ check(attrs.isRegularFile(), "is a regular file");
+ check(!attrs.isDirectory(), "is not a directory");
+ check(!attrs.isSymbolicLink(), "is not a link");
+ check(!attrs.isOther(), "is not other");
+
+ // size and last-modified-time should match java.io.File in seconds
+ File f = new File(file.toString());
+ check(f.length() == attrs.size(), "size should be the same");
+ check(f.lastModified()/1000 == attrs.lastModifiedTime().to(TimeUnit.SECONDS),
+ "last-modified time should be the same");
+
+ // copy last-modified time from directory to file,
+ // re-read attribtues, and check they match
+ BasicFileAttributeView view =
+ Files.getFileAttributeView(file, BasicFileAttributeView.class);
+ BasicFileAttributes dirAttrs = Files.readAttributes(dir, BasicFileAttributes.class);
+ view.setTimes(dirAttrs.lastModifiedTime(), null, null);
+
+ attrs = view.readAttributes();
+ check(attrs.lastModifiedTime().equals(dirAttrs.lastModifiedTime()),
+ "last-modified time should be equal");
+
+ // security tests
+ check (!(attrs instanceof PosixFileAttributes),
+ "should not be able to cast to PosixFileAttributes");
+ }
+
+ static void checkAttributesOfLink(Path link)
+ throws IOException
+ {
+ BasicFileAttributes attrs =
+ Files.readAttributes(link, BasicFileAttributes.class, LinkOption.NOFOLLOW_LINKS);
+ check(attrs.isSymbolicLink(), "is a link");
+ check(!attrs.isDirectory(), "is a directory");
+ check(!attrs.isRegularFile(), "is not a regular file");
+ check(!attrs.isOther(), "is not other");
+ }
+
+ static void attributeReadWriteTests(Path dir)
+ throws IOException
+ {
+ // create file
+ Path file = dir.resolve("foo");
+ try (OutputStream out = Files.newOutputStream(file)) {
+ out.write("this is not an empty file".getBytes("UTF-8"));
+ }
+
+ // check attributes of directory and file
+ checkAttributesOfDirectory(dir);
+ checkAttributesOfFile(dir, file);
+
+ // symbolic links may be supported
+ Path link = dir.resolve("link");
+ try {
+ Files.createSymbolicLink(link, file);
+ } catch (UnsupportedOperationException x) {
+ return;
+ } catch (IOException x) {
+ return;
+ }
+ checkAttributesOfLink(link);
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ // create temporary directory to run tests
+ Path dir = TestUtil.createTemporaryDirectory();
+ try {
+ attributeReadWriteTests(dir);
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java
new file mode 100644
index 0000000..8386a31
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/DosFileAttributeViewTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.DosFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/DosFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+
+// Android-changed: Renamed from "Basic"
+public class DosFileAttributeViewTest {
+
+ static void check(boolean okay) {
+ if (!okay)
+ throw new RuntimeException("Test failed");
+ }
+
+ // exercise each setter/getter method, leaving all attributes unset
+ static void testAttributes(DosFileAttributeView view) throws IOException {
+ view.setReadOnly(true);
+ check(view.readAttributes().isReadOnly());
+ view.setReadOnly(false);
+ check(!view.readAttributes().isReadOnly());
+ view.setHidden(true);
+ check(view.readAttributes().isHidden());
+ view.setHidden(false);
+ check(!view.readAttributes().isHidden());
+ view.setArchive(true);
+ check(view.readAttributes().isArchive());
+ view.setArchive(false);
+ check(!view.readAttributes().isArchive());
+ view.setSystem(true);
+ check(view.readAttributes().isSystem());
+ view.setSystem(false);
+ check(!view.readAttributes().isSystem());
+ }
+
+ // set the value of all attributes
+ static void setAll(DosFileAttributeView view, boolean value)
+ throws IOException
+ {
+ view.setReadOnly(value);
+ view.setHidden(value);
+ view.setArchive(value);
+ view.setSystem(value);
+ }
+
+ // read and write FAT attributes
+ static void readWriteTests(Path dir) throws IOException {
+
+ // create "foo" and test that we can read/write each FAT attribute
+ Path file = Files.createFile(dir.resolve("foo"));
+ try {
+ testAttributes(Files.getFileAttributeView(file, DosFileAttributeView.class));
+
+ // Following tests use a symbolic link so skip if not supported
+ if (!TestUtil.supportsLinks(dir))
+ return;
+
+ Path link = dir.resolve("link");
+ Files.createSymbolicLink(link, file);
+
+ // test following links
+ testAttributes(Files.getFileAttributeView(link, DosFileAttributeView.class));
+
+ // test not following links
+ try {
+ try {
+ testAttributes(Files
+ .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS));
+ } catch (IOException x) {
+ // access to link attributes not supported
+ return;
+ }
+
+ // set all attributes on link
+ // run test on target of link (which leaves them all un-set)
+ // check that attributes of link remain all set
+ setAll(Files
+ .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), true);
+ testAttributes(Files
+ .getFileAttributeView(link, DosFileAttributeView.class));
+ DosFileAttributes attrs =
+ Files.getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS)
+ .readAttributes();
+ check(attrs.isReadOnly());
+ check(attrs.isHidden());
+ check(attrs.isArchive());
+ check(attrs.isSystem());
+ setAll(Files
+ .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS), false);
+
+ // set all attributes on target
+ // run test on link (which leaves them all un-set)
+ // check that attributes of target remain all set
+ setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), true);
+ testAttributes(Files
+ .getFileAttributeView(link, DosFileAttributeView.class, NOFOLLOW_LINKS));
+ attrs = Files.getFileAttributeView(link, DosFileAttributeView.class).readAttributes();
+ check(attrs.isReadOnly());
+ check(attrs.isHidden());
+ check(attrs.isArchive());
+ check(attrs.isSystem());
+ setAll(Files.getFileAttributeView(link, DosFileAttributeView.class), false);
+ } finally {
+ TestUtil.deleteUnchecked(link);
+ }
+ } finally {
+ TestUtil.deleteUnchecked(file);
+ }
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ // create temporary directory to run tests
+ Path dir = TestUtil.createTemporaryDirectory();
+
+ try {
+ // skip test if DOS file attributes not supported
+ if (!Files.getFileStore(dir).supportsFileAttributeView("dos")) {
+ System.out.println("DOS file attribute not supported.");
+ return;
+ }
+ readWriteTests(dir);
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java b/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java
new file mode 100644
index 0000000..43c5d61
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/FileTimeTest.java
@@ -0,0 +1,352 @@
+/*
+ * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 6844313 8011647
+ * @summary Unit test for java.nio.file.FileTime
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/FileTime/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+
+import java.nio.file.attribute.FileTime;
+import java.time.Instant;
+import java.util.concurrent.TimeUnit;
+import static java.util.concurrent.TimeUnit.*;
+import java.util.Random;
+import java.util.EnumSet;
+
+// Android-changed: Renamed from "Basic"
+public class FileTimeTest {
+
+ static final Random rand = new Random();
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() {
+ long now = System.currentTimeMillis();
+ long tomorrowInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) + 1;
+ long yesterdayInDays = TimeUnit.DAYS.convert(now, MILLISECONDS) - 1;
+
+ Instant nowInstant = Instant.ofEpochMilli(now);
+
+ // equals
+ eq(now, MILLISECONDS, now, MILLISECONDS);
+ eq(now, MILLISECONDS, now*1000L, MICROSECONDS);
+ neq(now, MILLISECONDS, 0, MILLISECONDS);
+ neq(now, MILLISECONDS, 0, MICROSECONDS);
+
+ eq(nowInstant, now, MILLISECONDS);
+ eq(nowInstant, now*1000L, MICROSECONDS);
+ neq(nowInstant, 0, MILLISECONDS);
+ neq(nowInstant, 0, MICROSECONDS);
+
+ // compareTo
+ cmp(now, MILLISECONDS, now, MILLISECONDS, 0);
+ cmp(now, MILLISECONDS, now*1000L, MICROSECONDS, 0);
+ cmp(now, MILLISECONDS, now-1234, MILLISECONDS, 1);
+ cmp(now, MILLISECONDS, now+1234, MILLISECONDS, -1);
+
+ cmp(tomorrowInDays, DAYS, now, MILLISECONDS, 1);
+ cmp(now, MILLISECONDS, tomorrowInDays, DAYS, -1);
+ cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1);
+ cmp(now, MILLISECONDS, yesterdayInDays, DAYS, 1);
+ cmp(yesterdayInDays, DAYS, now, MILLISECONDS, -1);
+
+ cmp(Long.MAX_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, 1);
+ cmp(Long.MAX_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, 1);
+ cmp(Long.MIN_VALUE, DAYS, Long.MIN_VALUE, NANOSECONDS, -1);
+ cmp(Long.MIN_VALUE, DAYS, Long.MAX_VALUE, NANOSECONDS, -1);
+
+ cmp(Instant.MIN, Long.MIN_VALUE, DAYS, 1);
+ cmp(Instant.MIN, Long.MIN_VALUE, HOURS, 1);
+ cmp(Instant.MIN, Long.MIN_VALUE, MINUTES, 1);
+ cmp(Instant.MIN, Long.MIN_VALUE, SECONDS, 1);
+ cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 1, SECONDS, 1);
+ cmp(Instant.MIN, Instant.MIN.getEpochSecond() - 100, SECONDS, 1);
+ cmp(Instant.MIN, Instant.MIN.getEpochSecond(), SECONDS, 0);
+
+ cmp(Instant.MAX, Long.MAX_VALUE, DAYS, -1);
+ cmp(Instant.MAX, Long.MAX_VALUE, HOURS, -1);
+ cmp(Instant.MAX, Long.MAX_VALUE, MINUTES, -1);
+ cmp(Instant.MAX, Long.MAX_VALUE, SECONDS, -1);
+ cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 1, SECONDS, -1);
+ cmp(Instant.MAX, Instant.MAX.getEpochSecond() + 100, SECONDS, -1);
+ cmp(Instant.MAX, Instant.MAX.getEpochSecond(), SECONDS, 0);
+
+ cmp(nowInstant, now, MILLISECONDS, 0);
+ cmp(nowInstant, now*1000L, MICROSECONDS, 0);
+ cmp(nowInstant, now-1234, MILLISECONDS, 1);
+ cmp(nowInstant, now+1234, MILLISECONDS, -1);
+ cmp(nowInstant, tomorrowInDays, DAYS, -1);
+ cmp(nowInstant, yesterdayInDays, DAYS, 1);
+
+ // to(TimeUnit)
+ to(MILLISECONDS.convert(1, DAYS) - 1, MILLISECONDS);
+ to(MILLISECONDS.convert(1, DAYS) + 0, MILLISECONDS);
+ to(MILLISECONDS.convert(1, DAYS) + 1, MILLISECONDS);
+ to(1, MILLISECONDS);
+ to(0, MILLISECONDS);
+ to(1, MILLISECONDS);
+ to(MILLISECONDS.convert(-1, DAYS) - 1, MILLISECONDS);
+ to(MILLISECONDS.convert(-1, DAYS) + 0, MILLISECONDS);
+ to(MILLISECONDS.convert(-1, DAYS) + 1, MILLISECONDS);
+ for (TimeUnit unit: TimeUnit.values()) {
+ for (int i=0; i<100; i++) { to(rand.nextLong(), unit); }
+ to(Long.MIN_VALUE, unit);
+ to(Long.MAX_VALUE, unit);
+ }
+
+ // toInstant()
+ int N = 1000;
+ for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) {
+ for (int i = 0; i < N; i++) {
+ long value = rand.nextLong();
+ FileTime ft = FileTime.from(value, unit);
+ Instant instant = ft.toInstant();
+ if (instant != Instant.MIN && instant != Instant.MAX) {
+ eqTime(value, unit, instant);
+ }
+ }
+ }
+ for (TimeUnit unit : EnumSet.allOf(TimeUnit.class)) {
+ long value = Long.MIN_VALUE;
+ FileTime ft = FileTime.from(value, unit);
+ Instant instant = ft.toInstant();
+ if (unit.compareTo(TimeUnit.SECONDS) < 0) {
+ eqTime(value, unit, instant);
+ } else if (!instant.equals(Instant.MIN)) {
+ throw new RuntimeException("should overflow to MIN");
+ }
+ value = Long.MAX_VALUE;
+ ft = FileTime.from(value, unit);
+ instant = ft.toInstant();
+ if (unit.compareTo(TimeUnit.SECONDS) < 0) {
+ eqTime(value, unit, instant);
+ } else if (!instant.equals(Instant.MAX)) {
+ throw new RuntimeException("should overflow to MAX");
+ }
+ }
+
+ // from(Instant)
+ final long MAX_SECOND = 31556889864403199L;
+ for (int i = 0; i < N; i++) {
+ long v = rand.nextLong();
+ long secs = v % MAX_SECOND;
+ Instant instant = Instant.ofEpochSecond(secs, rand.nextInt(1000_000_000));
+ FileTime ft = FileTime.from(instant);
+ if (!ft.toInstant().equals(instant) || ft.to(SECONDS) != secs) {
+ throw new RuntimeException("from(Instant) failed");
+ }
+ long millis = v;
+ instant = Instant.ofEpochMilli(millis);
+ ft = FileTime.from(instant);
+ if (!ft.toInstant().equals(instant) ||
+ ft.toMillis() != instant.toEpochMilli()) {
+ throw new RuntimeException("from(Instant) failed");
+ }
+ long nanos = v;
+ ft = FileTime.from(nanos, NANOSECONDS);
+ secs = nanos / 1000_000_000;
+ nanos = nanos % 1000_000_000;
+ instant = Instant.ofEpochSecond(secs, nanos);
+ if (!ft.equals(FileTime.from(instant))) {
+ throw new RuntimeException("from(Instant) failed");
+ }
+ }
+
+ // toString
+ ts(1L, DAYS, "1970-01-02T00:00:00Z");
+ ts(1L, HOURS, "1970-01-01T01:00:00Z");
+ ts(1L, MINUTES, "1970-01-01T00:01:00Z");
+ ts(1L, SECONDS, "1970-01-01T00:00:01Z");
+ ts(1L, MILLISECONDS, "1970-01-01T00:00:00.001Z");
+ ts(1L, MICROSECONDS, "1970-01-01T00:00:00.000001Z");
+ ts(1L, NANOSECONDS, "1970-01-01T00:00:00.000000001Z");
+ ts(999999999L, NANOSECONDS, "1970-01-01T00:00:00.999999999Z");
+ ts(9999999999L, NANOSECONDS, "1970-01-01T00:00:09.999999999Z");
+
+ ts(-1L, DAYS, "1969-12-31T00:00:00Z");
+ ts(-1L, HOURS, "1969-12-31T23:00:00Z");
+ ts(-1L, MINUTES, "1969-12-31T23:59:00Z");
+ ts(-1L, SECONDS, "1969-12-31T23:59:59Z");
+ ts(-1L, MILLISECONDS, "1969-12-31T23:59:59.999Z");
+ ts(-1L, MICROSECONDS, "1969-12-31T23:59:59.999999Z");
+ ts(-1L, NANOSECONDS, "1969-12-31T23:59:59.999999999Z");
+ ts(-999999999L, NANOSECONDS, "1969-12-31T23:59:59.000000001Z");
+ ts(-9999999999L, NANOSECONDS, "1969-12-31T23:59:50.000000001Z");
+
+ ts(-62135596799999L, MILLISECONDS, "0001-01-01T00:00:00.001Z");
+ ts(-62135596800000L, MILLISECONDS, "0001-01-01T00:00:00Z");
+ ts(-62135596800001L, MILLISECONDS, "-0001-12-31T23:59:59.999Z");
+
+ ts(253402300799999L, MILLISECONDS, "9999-12-31T23:59:59.999Z");
+ ts(-377642044800001L, MILLISECONDS, "-9999-12-31T23:59:59.999Z");
+
+ // NTFS epoch in usec.
+ ts(-11644473600000000L, MICROSECONDS, "1601-01-01T00:00:00Z");
+
+ ts(Instant.MIN, "-1000000001-01-01T00:00:00Z");
+ ts(Instant.MAX, "1000000000-12-31T23:59:59.999999999Z");
+
+ try {
+ FileTime.from(0L, null);
+ throw new RuntimeException("NullPointerException expected");
+ } catch (NullPointerException npe) { }
+ try {
+ FileTime.from(null);
+ throw new RuntimeException("NullPointerException expected");
+ } catch (NullPointerException npe) { }
+
+ FileTime time = FileTime.fromMillis(now);
+ if (time.equals(null))
+ throw new RuntimeException("should not be equal to null");
+ try {
+ time.compareTo(null);
+ throw new RuntimeException("NullPointerException expected");
+ } catch (NullPointerException npe) { }
+
+ // Instant + toMilli() overflow
+ overflow(Long.MAX_VALUE,
+ FileTime.from(Instant.MAX).toMillis());
+ overflow(Long.MAX_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1))
+ .toMillis());
+ overflow(Long.MIN_VALUE,
+ FileTime.from(Instant.MIN).toMillis());
+ overflow(Long.MIN_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1))
+ .toMillis());
+
+ // Instant + to(TimeUnit) overflow
+ overflow(Long.MAX_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000 + 1))
+ .to(MILLISECONDS));
+ overflow(Long.MAX_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MAX_VALUE / 1000,
+ MILLISECONDS.toNanos(1000)))
+ .to(MILLISECONDS));
+ overflow(Long.MIN_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1))
+ .to(MILLISECONDS));
+ overflow(Long.MIN_VALUE,
+ FileTime.from(Instant.ofEpochSecond(Long.MIN_VALUE / 1000,
+ -MILLISECONDS.toNanos(1)))
+ .to(MILLISECONDS));
+ }
+
+ static void overflow(long minmax, long v) {
+ if (v != minmax)
+ throw new RuntimeException("saturates to Long.MIN/MAX_VALUE expected");
+ }
+
+ static void cmp(long v1, TimeUnit u1, long v2, TimeUnit u2, int expected) {
+ int result = FileTime.from(v1, u1).compareTo(FileTime.from(v2, u2));
+ if (result != expected)
+ throw new RuntimeException("unexpected order");
+ }
+
+ static void cmp(Instant ins, long v2, TimeUnit u2, int expected) {
+ int result = FileTime.from(ins).compareTo(FileTime.from(v2, u2));
+ if (result != expected)
+ throw new RuntimeException("unexpected order");
+ }
+
+ static void eq(long v1, TimeUnit u1, long v2, TimeUnit u2) {
+ FileTime t1 = FileTime.from(v1, u1);
+ FileTime t2 = FileTime.from(v2, u2);
+ if (!t1.equals(t2))
+ throw new RuntimeException("not equal");
+ if (t1.hashCode() != t2.hashCode())
+ throw new RuntimeException("hashCodes should be equal");
+ }
+
+ static void eq(Instant ins, long v2, TimeUnit u2) {
+ FileTime t1 = FileTime.from(ins);
+ FileTime t2 = FileTime.from(v2, u2);
+ if (!t1.equals(t2))
+ throw new RuntimeException("not equal");
+ if (t1.hashCode() != t2.hashCode())
+ throw new RuntimeException("hashCodes should be equal");
+ }
+
+ static void eqTime(long value, TimeUnit unit, Instant instant) {
+ long secs = SECONDS.convert(value, unit);
+ long nanos = NANOSECONDS.convert(value - unit.convert(secs, SECONDS), unit);
+ if (nanos < 0) { // normalize nanoOfSecond to positive
+ secs -= 1;
+ nanos += 1000_000_000;
+ }
+ if (secs != instant.getEpochSecond() || (int)nanos != instant.getNano()) {
+ System.err.println(" ins=" + instant);
+ throw new RuntimeException("ft and instant are not the same time point");
+ }
+ }
+
+ static void neq(long v1, TimeUnit u1, long v2, TimeUnit u2) {
+ FileTime t1 = FileTime.from(v1, u1);
+ FileTime t2 = FileTime.from(v2, u2);
+ if (t1.equals(t2))
+ throw new RuntimeException("should not be equal");
+ }
+
+ static void neq(Instant ins, long v2, TimeUnit u2) {
+ FileTime t1 = FileTime.from(ins);
+ FileTime t2 = FileTime.from(v2, u2);
+ if (t1.equals(t2))
+ throw new RuntimeException("should not be equal");
+ }
+
+ static void to(long v, TimeUnit unit) {
+ FileTime t = FileTime.from(v, unit);
+ for (TimeUnit u: TimeUnit.values()) {
+ long result = t.to(u);
+ long expected = u.convert(v, unit);
+ if (result != expected) {
+ throw new RuntimeException("unexpected result");
+ }
+ }
+ }
+
+ static void ts(long v, TimeUnit unit, String expected) {
+ String result = FileTime.from(v, unit).toString();
+ if (!result.equals(expected)) {
+ System.err.format("FileTime.from(%d, %s).toString() failed\n", v, unit);
+ System.err.format("Expected: %s\n", expected);
+ System.err.format(" Got: %s\n", result);
+ throw new RuntimeException();
+ }
+ }
+
+ static void ts(Instant instant, String expected) {
+ String result = FileTime.from(instant).toString();
+ if (!result.equals(expected)) {
+ System.err.format("FileTime.from(%s).toString() failed\n", instant);
+ System.err.format("Expected: %s\n", expected);
+ System.err.format(" Got: %s\n", result);
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java
new file mode 100644
index 0000000..7825837
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/PosixFileAttributeViewTest.java
@@ -0,0 +1,406 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.PosixFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/PosixFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.io.IOException;
+import java.util.*;
+
+/**
+ * Unit test for PosixFileAttributeView, passing silently if this attribute
+ * view is not available.
+ */
+
+// Android-changed: Renamed from "Basic"
+public class PosixFileAttributeViewTest {
+
+ /**
+ * Use view to update permission to the given mode and check that the
+ * permissions have been updated.
+ */
+ static void testPermissions(Path file, String mode) throws IOException {
+ System.out.format("change mode: %s\n", mode);
+ Set<PosixFilePermission> perms = PosixFilePermissions.fromString(mode);
+
+ // change permissions and re-read them.
+ Files.setPosixFilePermissions(file, perms);
+ Set<PosixFilePermission> current = Files.getPosixFilePermissions(file);
+ if (!current.equals(perms)) {
+ throw new RuntimeException("Actual permissions: " +
+ PosixFilePermissions.toString(current) + ", expected: " +
+ PosixFilePermissions.toString(perms));
+ }
+
+ // repeat test using setAttribute/getAttribute
+ Files.setAttribute(file, "posix:permissions", perms);
+ current = (Set<PosixFilePermission>)Files.getAttribute(file, "posix:permissions");
+ if (!current.equals(perms)) {
+ throw new RuntimeException("Actual permissions: " +
+ PosixFilePermissions.toString(current) + ", expected: " +
+ PosixFilePermissions.toString(perms));
+ }
+ }
+
+ /**
+ * Check that the actual permissions of a file match or make it more
+ * secure than requested
+ */
+ static void checkSecure(Set<PosixFilePermission> requested,
+ Set<PosixFilePermission> actual)
+ {
+ for (PosixFilePermission perm: actual) {
+ if (!requested.contains(perm)) {
+ throw new RuntimeException("Actual permissions: " +
+ PosixFilePermissions.toString(actual) + ", requested: " +
+ PosixFilePermissions.toString(requested) +
+ " - file is less secure than requested");
+ }
+ }
+ }
+
+ /**
+ * Create file with given mode and check that the file is created with a
+ * mode that is not less secure
+ */
+ static void createWithPermissions(Path file,
+ String mode)
+ throws IOException
+ {
+ Set<PosixFilePermission> requested = PosixFilePermissions.fromString(mode);
+ FileAttribute<Set<PosixFilePermission>> attr =
+ PosixFilePermissions.asFileAttribute(requested);
+ System.out.format("create file with mode: %s\n", mode);
+ Files.createFile(file, attr);
+ try {
+ checkSecure(requested,
+ Files.getFileAttributeView(file, PosixFileAttributeView.class)
+ .readAttributes()
+ .permissions());
+ } finally {
+ Files.delete(file);
+ }
+
+ System.out.format("create directory with mode: %s\n", mode);
+ Files.createDirectory(file, attr);
+ try {
+ checkSecure(requested,
+ Files.getFileAttributeView(file, PosixFileAttributeView.class)
+ .readAttributes()
+ .permissions());
+ } finally {
+ Files.delete(file);
+ }
+ }
+
+ /**
+ * Test the setPermissions/permissions methods.
+ */
+ static void permissionTests(Path dir)
+ throws IOException
+ {
+ System.out.println("-- Permission Tests --");
+
+ // create file and test updating and reading its permissions
+ Path file = dir.resolve("foo");
+ System.out.format("create %s\n", file);
+ Files.createFile(file);
+ try {
+ // get initial permissions so that we can restore them later
+ PosixFileAttributeView view =
+ Files.getFileAttributeView(file, PosixFileAttributeView.class);
+ Set<PosixFilePermission> save = view.readAttributes()
+ .permissions();
+
+ // test various modes
+ try {
+ testPermissions(file, "---------");
+ testPermissions(file, "r--------");
+ testPermissions(file, "-w-------");
+ testPermissions(file, "--x------");
+ testPermissions(file, "rwx------");
+ testPermissions(file, "---r-----");
+ testPermissions(file, "----w----");
+ testPermissions(file, "-----x---");
+ testPermissions(file, "---rwx---");
+ testPermissions(file, "------r--");
+ testPermissions(file, "-------w-");
+ testPermissions(file, "--------x");
+ testPermissions(file, "------rwx");
+ testPermissions(file, "r--r-----");
+ testPermissions(file, "r--r--r--");
+ testPermissions(file, "rw-rw----");
+ testPermissions(file, "rwxrwx---");
+ testPermissions(file, "rw-rw-r--");
+ testPermissions(file, "r-xr-x---");
+ testPermissions(file, "r-xr-xr-x");
+ testPermissions(file, "rwxrwxrwx");
+ } finally {
+ view.setPermissions(save);
+ }
+ } finally {
+ Files.delete(file);
+ }
+
+ // create link (to file that doesn't exist) and test reading of
+ // permissions
+ if (TestUtil.supportsLinks(dir)) {
+ Path link = dir.resolve("link");
+ System.out.format("create link %s\n", link);
+ Files.createSymbolicLink(link, file);
+ try {
+ PosixFileAttributes attrs =
+ Files.getFileAttributeView(link,
+ PosixFileAttributeView.class,
+ NOFOLLOW_LINKS)
+ .readAttributes();
+ if (!attrs.isSymbolicLink()) {
+ throw new RuntimeException("not a link");
+ }
+ } finally {
+ Files.delete(link);
+ }
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Test creating a file and directory with initial permissios
+ */
+ static void createTests(Path dir)
+ throws IOException
+ {
+ System.out.println("-- Create Tests --");
+
+ Path file = dir.resolve("foo");
+
+ createWithPermissions(file, "---------");
+ createWithPermissions(file, "r--------");
+ createWithPermissions(file, "-w-------");
+ createWithPermissions(file, "--x------");
+ createWithPermissions(file, "rwx------");
+ createWithPermissions(file, "---r-----");
+ createWithPermissions(file, "----w----");
+ createWithPermissions(file, "-----x---");
+ createWithPermissions(file, "---rwx---");
+ createWithPermissions(file, "------r--");
+ createWithPermissions(file, "-------w-");
+ createWithPermissions(file, "--------x");
+ createWithPermissions(file, "------rwx");
+ createWithPermissions(file, "r--r-----");
+ createWithPermissions(file, "r--r--r--");
+ createWithPermissions(file, "rw-rw----");
+ createWithPermissions(file, "rwxrwx---");
+ createWithPermissions(file, "rw-rw-r--");
+ createWithPermissions(file, "r-xr-x---");
+ createWithPermissions(file, "r-xr-xr-x");
+ createWithPermissions(file, "rwxrwxrwx");
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Test setOwner/setGroup methods - this test simply exercises the
+ * methods to avoid configuration.
+ */
+ static void ownerTests(Path dir)
+ throws IOException
+ {
+ System.out.println("-- Owner Tests --");
+
+ Path file = dir.resolve("gus");
+ System.out.format("create %s\n", file);
+
+ Files.createFile(file);
+ try {
+
+ // read attributes of directory to get owner/group
+ PosixFileAttributeView view =
+ Files.getFileAttributeView(file, PosixFileAttributeView.class);
+ PosixFileAttributes attrs = view.readAttributes();
+
+ // set to existing owner/group
+ view.setOwner(attrs.owner());
+ view.setGroup(attrs.group());
+
+ // repeat test using set/getAttribute
+ UserPrincipal owner = (UserPrincipal)Files.getAttribute(file, "posix:owner");
+ Files.setAttribute(file, "posix:owner", owner);
+ UserPrincipal group = (UserPrincipal)Files.getAttribute(file, "posix:group");
+ Files.setAttribute(file, "posix:group", group);
+
+ } finally {
+ Files.delete(file);
+ }
+
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Test the lookupPrincipalByName/lookupPrincipalByGroupName methods
+ */
+ static void lookupPrincipalTests(Path dir)
+ throws IOException
+ {
+ System.out.println("-- Lookup UserPrincipal Tests --");
+
+ UserPrincipalLookupService lookupService = dir.getFileSystem()
+ .getUserPrincipalLookupService();
+
+ // read attributes of directory to get owner/group
+ PosixFileAttributes attrs = Files.readAttributes(dir, PosixFileAttributes.class);
+
+ // lookup owner and check it matches file's owner
+ System.out.format("lookup: %s\n", attrs.owner().getName());
+ try {
+ UserPrincipal owner = lookupService.lookupPrincipalByName(attrs.owner().getName());
+ if (owner instanceof GroupPrincipal)
+ throw new RuntimeException("owner is a group?");
+ if (!owner.equals(attrs.owner()))
+ throw new RuntimeException("owner different from file owner");
+ } catch (UserPrincipalNotFoundException x) {
+ System.out.println("user not found - test skipped");
+ }
+
+ // lookup group and check it matches file's group-owner
+ System.out.format("lookup group: %s\n", attrs.group().getName());
+ try {
+ GroupPrincipal group = lookupService.lookupPrincipalByGroupName(attrs.group().getName());
+ if (!group.equals(attrs.group()))
+ throw new RuntimeException("group different from file group-owner");
+ } catch (UserPrincipalNotFoundException x) {
+ System.out.println("group not found - test skipped");
+ }
+
+ // test that UserPrincipalNotFoundException is thrown
+ String invalidPrincipal = "scumbag99";
+ try {
+ System.out.format("lookup: %s\n", invalidPrincipal);
+ lookupService.lookupPrincipalByName(invalidPrincipal);
+ throw new RuntimeException("'" + invalidPrincipal + "' is a valid user?");
+ } catch (UserPrincipalNotFoundException x) {
+ }
+ try {
+ System.out.format("lookup group: %s\n", invalidPrincipal);
+ lookupService.lookupPrincipalByGroupName("idonotexist");
+ throw new RuntimeException("'" + invalidPrincipal + "' is a valid group?");
+ } catch (UserPrincipalNotFoundException x) {
+ }
+ System.out.println("OKAY");
+ }
+
+ /**
+ * Test various exceptions are thrown as expected
+ */
+ @SuppressWarnings("unchecked")
+ static void exceptionsTests(Path dir)
+ throws IOException
+ {
+ System.out.println("-- Exceptions --");
+
+ PosixFileAttributeView view =
+ Files.getFileAttributeView(dir,PosixFileAttributeView.class);
+
+ // NullPointerException
+ try {
+ view.setOwner(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ view.setGroup(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+
+ UserPrincipalLookupService lookupService = dir.getFileSystem()
+ .getUserPrincipalLookupService();
+ try {
+ lookupService.lookupPrincipalByName(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ lookupService.lookupPrincipalByGroupName(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ view.setPermissions(null);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+ try {
+ Set<PosixFilePermission> perms = new HashSet<>();
+ perms.add(null);
+ view.setPermissions(perms);
+ throw new RuntimeException("NullPointerException not thrown");
+ } catch (NullPointerException x) {
+ }
+
+ // ClassCastException
+ try {
+ Set perms = new HashSet(); // raw type
+ perms.add(new Object());
+ view.setPermissions(perms);
+ throw new RuntimeException("ClassCastException not thrown");
+ } catch (ClassCastException x) {
+ }
+
+ System.out.println("OKAY");
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ Path dir = TestUtil.createTemporaryDirectory();
+ try {
+ if (!Files.getFileStore(dir).supportsFileAttributeView("posix")) {
+ System.out.println("PosixFileAttributeView not supported");
+ return;
+ }
+
+ permissionTests(dir);
+ createTests(dir);
+ ownerTests(dir);
+ lookupPrincipalTests(dir);
+ exceptionsTests(dir);
+
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+}
diff --git a/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java b/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java
new file mode 100644
index 0000000..6fb3c78
--- /dev/null
+++ b/ojluni/src/test/java/nio/file/attribute/UserDefinedFileAttributeViewTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/* @test
+ * @bug 4313887 6838333
+ * @summary Unit test for java.nio.file.attribute.UserDefinedFileAttributeView
+ * @library ../..
+ */
+// Android-changed: Adapted from
+// jdk/test/java/nio/file/attribute/UserDefinedFileAttributeView/Basic.java
+// Android-changed: Added package & Test import
+package test.java.nio.file.attribute;
+import org.testng.annotations.Test;
+import test.java.nio.file.TestUtil;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.file.*;
+import static java.nio.file.LinkOption.*;
+import java.nio.file.attribute.*;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Random;
+import java.io.IOException;
+
+// Android-changed: Renamed from "Basic"
+public class UserDefinedFileAttributeViewTest {
+
+ private static Random rand = new Random();
+
+ private static final String ATTR_NAME = "mime_type";
+ private static final String ATTR_VALUE = "text/plain";
+ private static final String ATTR_VALUE2 = "text/html";
+
+ static interface Task {
+ void run() throws Exception;
+ }
+
+ static void tryCatch(Class<? extends Throwable> ex, Task task) {
+ boolean caught = false;
+ try {
+ task.run();
+ } catch (Throwable x) {
+ if (ex.isAssignableFrom(x.getClass())) {
+ caught = true;
+ } else {
+ throw new RuntimeException(x);
+ }
+ }
+ if (!caught)
+ throw new RuntimeException(ex.getName() + " expected");
+ }
+
+ static void expectNullPointerException(Task task) {
+ tryCatch(NullPointerException.class, task);
+ }
+
+ static boolean hasAttribute(UserDefinedFileAttributeView view, String attr)
+ throws IOException
+ {
+ for (String name: view.list()) {
+ if (name.equals(ATTR_NAME))
+ return true;
+ }
+ return false;
+ }
+
+ static void test(Path file, LinkOption... options) throws IOException {
+ final UserDefinedFileAttributeView view =
+ Files.getFileAttributeView(file, UserDefinedFileAttributeView.class, options);
+ ByteBuffer buf = rand.nextBoolean() ?
+ ByteBuffer.allocate(100) : ByteBuffer.allocateDirect(100);
+
+ // Test: write
+ buf.put(ATTR_VALUE.getBytes()).flip();
+ int size = buf.remaining();
+ int nwrote = view.write(ATTR_NAME, buf);
+ if (nwrote != size)
+ throw new RuntimeException("Unexpected number of bytes written");
+
+ // Test: size
+ if (view.size(ATTR_NAME) != size)
+ throw new RuntimeException("Unexpected size");
+
+ // Test: read
+ buf.clear();
+ int nread = view.read(ATTR_NAME, buf);
+ if (nread != size)
+ throw new RuntimeException("Unexpected number of bytes read");
+ buf.flip();
+ String value = Charset.defaultCharset().decode(buf).toString();
+ if (!value.equals(ATTR_VALUE))
+ throw new RuntimeException("Unexpected attribute value");
+
+ // Test: read with insufficient space
+ tryCatch(IOException.class, new Task() {
+ public void run() throws IOException {
+ view.read(ATTR_NAME, ByteBuffer.allocateDirect(1));
+ }});
+
+ // Test: replace value
+ buf.clear();
+ buf.put(ATTR_VALUE2.getBytes()).flip();
+ size = buf.remaining();
+ view.write(ATTR_NAME, buf);
+ if (view.size(ATTR_NAME) != size)
+ throw new RuntimeException("Unexpected size");
+
+ // Test: list
+ if (!hasAttribute(view, ATTR_NAME))
+ throw new RuntimeException("Attribute name not in list");
+
+ // Test: delete
+ view.delete(ATTR_NAME);
+ if (hasAttribute(view, ATTR_NAME))
+ throw new RuntimeException("Attribute name in list");
+
+ // Test: dynamic access
+ String name = "user:" + ATTR_NAME;
+ byte[] valueAsBytes = ATTR_VALUE.getBytes();
+ Files.setAttribute(file, name, valueAsBytes);
+ byte[] actualAsBytes = (byte[])Files.getAttribute(file, name);
+ if (!Arrays.equals(valueAsBytes, actualAsBytes))
+ throw new RuntimeException("Unexpected attribute value");
+ Map<String,?> map = Files.readAttributes(file, name);
+ if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+ throw new RuntimeException("Unexpected attribute value");
+ map = Files.readAttributes(file, "user:*");
+ if (!Arrays.equals(valueAsBytes, (byte[])map.get(ATTR_NAME)))
+ throw new RuntimeException("Unexpected attribute value");
+ }
+
+ static void miscTests(final Path file) throws IOException {
+ final UserDefinedFileAttributeView view =
+ Files.getFileAttributeView(file, UserDefinedFileAttributeView.class);
+ view.write(ATTR_NAME, ByteBuffer.wrap(ATTR_VALUE.getBytes()));
+
+ // NullPointerException
+ final ByteBuffer buf = ByteBuffer.allocate(100);
+
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.read(null, buf);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.read(ATTR_NAME, null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.write(null, buf);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.write(ATTR_NAME, null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.size(null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ view.delete(null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.getAttribute(file, null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.getAttribute(file, "user:" + ATTR_NAME, (LinkOption[])null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.setAttribute(file, "user:" + ATTR_NAME, null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.setAttribute(file, null, new byte[0]);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.setAttribute(file, "user: " + ATTR_NAME, new byte[0], (LinkOption[])null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.readAttributes(file, (String)null);
+ }});
+ expectNullPointerException(new Task() {
+ public void run() throws IOException {
+ Files.readAttributes(file, "*", (LinkOption[])null);
+ }});
+
+ // Read-only buffer
+ tryCatch(IllegalArgumentException.class, new Task() {
+ public void run() throws IOException {
+ ByteBuffer buf = ByteBuffer.wrap(ATTR_VALUE.getBytes()).asReadOnlyBuffer();
+ view.write(ATTR_NAME, buf);
+ buf.flip();
+ view.read(ATTR_NAME, buf);
+ }});
+
+ // Zero bytes remaining
+ tryCatch(IOException.class, new Task() {
+ public void run() throws IOException {
+ ByteBuffer buf = buf = ByteBuffer.allocateDirect(100);
+ buf.position(buf.capacity());
+ view.read(ATTR_NAME, buf);
+ }});
+ }
+
+ // Android-changed: Removed args & added @Test
+ @Test
+ public static void main() throws IOException {
+ // create temporary directory to run tests
+ Path dir = TestUtil.createTemporaryDirectory();
+ try {
+ if (!Files.getFileStore(dir).supportsFileAttributeView("user")) {
+ System.out.println("UserDefinedFileAttributeView not supported - skip test");
+ return;
+ }
+
+ // test access to user defined attributes of regular file
+ Path file = dir.resolve("foo.html");
+ Files.createFile(file);
+ try {
+ test(file);
+ } finally {
+ Files.delete(file);
+ }
+
+ // test access to user defined attributes of directory
+ Path subdir = dir.resolve("foo");
+ Files.createDirectory(subdir);
+ try {
+ test(subdir);
+ } finally {
+ Files.delete(subdir);
+ }
+
+ // test access to user defined attributes of sym link
+ if (TestUtil.supportsLinks(dir)) {
+ Path target = dir.resolve("doesnotexist");
+ Path link = dir.resolve("link");
+ Files.createSymbolicLink(link, target);
+ try {
+ test(link, NOFOLLOW_LINKS);
+ } catch (IOException x) {
+ // access to attributes of sym link may not be supported
+ } finally {
+ Files.delete(link);
+ }
+ }
+
+ // misc. tests
+ try {
+ file = dir.resolve("foo.txt");
+ Files.createFile(file);
+ miscTests(dir);
+ } finally {
+ Files.delete(file);
+ }
+
+ } finally {
+ TestUtil.removeAll(dir);
+ }
+ }
+ }
diff --git a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
index 3d89db5..1b8fea7 100644
--- a/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
+++ b/ojluni/src/test/java/time/tck/java/time/TCKInstant.java
@@ -1931,6 +1931,16 @@
Instant.ofEpochSecond(Long.MIN_VALUE / 1000 - 1).toEpochMilli();
}
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow() {
+ Instant.ofEpochSecond(Long.MAX_VALUE / 1000, 809_000_000).toEpochMilli();
+ }
+
+ @Test(expectedExceptions=ArithmeticException.class)
+ public void test_toEpochMillis_overflow2() {
+ Instant.ofEpochSecond(-9223372036854776L, 1).toEpochMilli();
+ }
+
//-----------------------------------------------------------------------
// compareTo()
//-----------------------------------------------------------------------
diff --git a/ojluni/src/test/java/time/test/java/time/TestInstant.java b/ojluni/src/test/java/time/test/java/time/TestInstant.java
index cf135a1..203bb57 100644
--- a/ojluni/src/test/java/time/test/java/time/TestInstant.java
+++ b/ojluni/src/test/java/time/test/java/time/TestInstant.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -62,6 +62,8 @@
import java.time.Instant;
import org.testng.annotations.Test;
+import org.testng.annotations.DataProvider;
+import static org.testng.Assert.assertEquals;
/**
* Test Instant.
@@ -74,4 +76,24 @@
assertImmutable(Instant.class);
}
+ @DataProvider(name="sampleEpochMillis")
+ private Object[][] provider_sampleEpochMillis() {
+ return new Object[][] {
+ {"Long.MAX_VALUE", Long.MAX_VALUE},
+ {"Long.MAX_VALUE-1", Long.MAX_VALUE - 1},
+ {"1", 1L},
+ {"0", 0L},
+ {"-1", -1L},
+ {"Long.MIN_VALUE+1", Long.MIN_VALUE + 1},
+ {"Long.MIN_VALUE", Long.MIN_VALUE}
+ };
+ }
+
+ @Test(dataProvider="sampleEpochMillis")
+ public void test_epochMillis(String name, long millis) {
+ Instant t1 = Instant.ofEpochMilli(millis);
+ long m = t1.toEpochMilli();
+ assertEquals(millis, m, name);
+ }
+
}
diff --git a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
index 1ef3a5b..23ef184 100644
--- a/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
+++ b/ojluni/src/test/java/time/test/java/time/chrono/TestJapaneseChronoImpl.java
@@ -99,7 +99,7 @@
assertEquals(locale.toString(), "ja_JP_#u-ca-japanese", "Unexpected locale");
// Android changed: Android doesn't return the Japanese Imperial Calendar from getInstance.
- Calendar cal = java.util.Calendar.getJapanesImperialInstance(TimeZone.getDefault(), locale);
+ Calendar cal = Calendar.getJapaneseImperialInstance(TimeZone.getDefault(), locale);
assertEquals(cal.getCalendarType(), "japanese", "Unexpected calendar type");
JapaneseDate jDate = JapaneseChronology.INSTANCE.date(isoStartDate);
diff --git a/ojluni/src/test/java/time/test/java/util/TestFormatter.java b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
index afd5fc4..05cb2e7 100644
--- a/ojluni/src/test/java/time/test/java/util/TestFormatter.java
+++ b/ojluni/src/test/java/time/test/java/util/TestFormatter.java
@@ -111,7 +111,7 @@
TimeZone tz = TimeZone.getTimeZone(zdt.getZone());
Calendar cal;
if (calLocale.getLanguage().equals("ja")) {
- cal = Calendar.getJapanesImperialInstance(tz, calLocale);
+ cal = Calendar.getJapaneseImperialInstance(tz, calLocale);
} else {
cal = Calendar.getInstance(tz, calLocale);
}
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index 50c4b84..4285911 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -114,6 +114,7 @@
ojluni/src/main/java/java/lang/AssertionError.java \
ojluni/src/main/java/java/lang/AutoCloseable.java \
ojluni/src/main/java/java/lang/Boolean.java \
+ ojluni/src/main/java/java/lang/BootstrapMethodError.java \
ojluni/src/main/java/java/lang/Byte.java \
ojluni/src/main/java/java/lang/Character.java \
ojluni/src/main/java/java/lang/CharSequence.java \
@@ -240,6 +241,8 @@
ojluni/src/main/java/java/lang/VirtualMachineError.java \
ojluni/src/main/java/java/lang/Void.java \
ojluni/src/main/java/java/lang/invoke/LambdaConversionException.java \
+ ojluni/src/main/java/java/lang/invoke/CallSite.java \
+ ojluni/src/main/java/java/lang/invoke/ConstantCallSite.java \
ojluni/src/main/java/java/lang/invoke/MethodHandle.java \
ojluni/src/main/java/java/lang/invoke/MethodHandles.java \
ojluni/src/main/java/java/lang/invoke/MethodHandleImpl.java \
@@ -247,8 +250,10 @@
ojluni/src/main/java/java/lang/invoke/MethodHandleStatics.java \
ojluni/src/main/java/java/lang/invoke/MethodType.java \
ojluni/src/main/java/java/lang/invoke/MethodTypeForm.java \
+ ojluni/src/main/java/java/lang/invoke/MutableCallSite.java \
ojluni/src/main/java/java/lang/invoke/Stable.java \
ojluni/src/main/java/java/lang/invoke/Transformers.java \
+ ojluni/src/main/java/java/lang/invoke/VolatileCallSite.java \
ojluni/src/main/java/java/lang/invoke/WrongMethodTypeException.java \
ojluni/src/main/java/java/net/AbstractPlainDatagramSocketImpl.java \
ojluni/src/main/java/java/net/AbstractPlainSocketImpl.java \
@@ -1744,10 +1749,10 @@
# On older platforms : Both sets of stub files are used and core-oj does not contain
# any of these classes.
openjdk_lambda_stub_files := \
- ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
ojluni/src/lambda/java/java/lang/invoke/LambdaMetafactory.java \
ojluni/src/lambda/java/java/lang/invoke/SerializedLambda.java
openjdk_lambda_duplicate_stub_files := \
+ ojluni/src/lambda/java/java/lang/invoke/CallSite.java \
ojluni/src/lambda/java/java/lang/invoke/MethodHandles.java \
ojluni/src/lambda/java/java/lang/invoke/LambdaConversionException.java \
ojluni/src/lambda/java/java/lang/invoke/MethodHandle.java \
diff --git a/support/src/test/java/libcore/java/security/StandardNames.java b/support/src/test/java/libcore/java/security/StandardNames.java
index 434473b..8bc9937 100644
--- a/support/src/test/java/libcore/java/security/StandardNames.java
+++ b/support/src/test/java/libcore/java/security/StandardNames.java
@@ -493,6 +493,16 @@
provide("Cipher", "PBEWITHSHAAND40BITRC2-CBC");
provide("Cipher", "PBEWITHSHAAND40BITRC4");
provide("Cipher", "PBEWITHSHAANDTWOFISH-CBC");
+ provide("Cipher", "PBEWithHmacSHA1AndAES_128");
+ provide("Cipher", "PBEWithHmacSHA224AndAES_128");
+ provide("Cipher", "PBEWithHmacSHA256AndAES_128");
+ provide("Cipher", "PBEWithHmacSHA384AndAES_128");
+ provide("Cipher", "PBEWithHmacSHA512AndAES_128");
+ provide("Cipher", "PBEWithHmacSHA1AndAES_256");
+ provide("Cipher", "PBEWithHmacSHA224AndAES_256");
+ provide("Cipher", "PBEWithHmacSHA256AndAES_256");
+ provide("Cipher", "PBEWithHmacSHA384AndAES_256");
+ provide("Cipher", "PBEWithHmacSHA512AndAES_256");
provide("Mac", "PBEWITHHMACSHA");
provide("Mac", "PBEWITHHMACSHA1");
provide("SecretKeyFactory", "PBEWITHHMACSHA1");
diff --git a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
similarity index 98%
rename from tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
rename to tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
index d08bb1d..1b56ebf 100644
--- a/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneBundleInstaller.java
+++ b/tzdata/update2/src/main/libcore/tzdata/update2/TimeZoneDistroInstaller.java
@@ -26,8 +26,7 @@
* A distro-validation / extraction class. Separate from the services code that uses it for easier
* testing. This class is not thread-safe: callers are expected to handle mutual exclusion.
*/
-// TODO(nfuller) Rename to TimeZoneDistroInstaller
-public final class TimeZoneBundleInstaller {
+public final class TimeZoneDistroInstaller {
/** {@link #installWithErrorCode(byte[])} result code: Success. */
public final static int INSTALL_SUCCESS = 0;
/** {@link #installWithErrorCode(byte[])} result code: Distro corrupt. */
@@ -49,7 +48,7 @@
private final File currentTzDataDir;
private final File workingDir;
- public TimeZoneBundleInstaller(String logTag, File systemTzDataFile, File installDir) {
+ public TimeZoneDistroInstaller(String logTag, File systemTzDataFile, File installDir) {
this.logTag = logTag;
this.systemTzDataFile = systemTzDataFile;
oldTzDataDir = new File(installDir, OLD_TZ_DATA_DIR_NAME);
diff --git a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
similarity index 92%
rename from tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
rename to tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
index 088e7cb..6ae0e56 100644
--- a/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneBundleInstallerTest.java
+++ b/tzdata/update2/src/test/libcore/tzdata/update2/TimeZoneDistroInstallerTest.java
@@ -34,9 +34,9 @@
import libcore.tzdata.update2.tools.TimeZoneDistroBuilder;
/**
- * Tests for {@link TimeZoneBundleInstaller}.
+ * Tests for {@link TimeZoneDistroInstaller}.
*/
-public class TimeZoneBundleInstallerTest extends TestCase {
+public class TimeZoneDistroInstallerTest extends TestCase {
// OLDER_RULES_VERSION < SYSTEM_RULES_VERSION < NEW_RULES_VERSION < NEWER_RULES_VERSION
private static final String OLDER_RULES_VERSION = "2030a";
@@ -44,7 +44,7 @@
private static final String NEW_RULES_VERSION = "2030c";
private static final String NEWER_RULES_VERSION = "2030d";
- private TimeZoneBundleInstaller installer;
+ private TimeZoneDistroInstaller installer;
private File tempDir;
private File testInstallDir;
private File testSystemTzDataDir;
@@ -61,8 +61,8 @@
byte[] systemTzDataBytes = createTzData(SYSTEM_RULES_VERSION);
createFile(testSystemTzDataFile, systemTzDataBytes);
- installer = new TimeZoneBundleInstaller(
- "TimeZoneBundleInstallerTest", testSystemTzDataFile, testInstallDir);
+ installer = new TimeZoneDistroInstaller(
+ "TimeZoneDistroInstallerTest", testSystemTzDataFile, testInstallDir);
}
private static File createDirectory(String prefix) throws Exception {
@@ -89,8 +89,8 @@
/** Tests the an update on a device will fail if the /system tzdata file cannot be found. */
public void testInstall_badSystemFile() throws Exception {
File doesNotExist = new File(testSystemTzDataDir, "doesNotExist");
- TimeZoneBundleInstaller brokenSystemInstaller = new TimeZoneBundleInstaller(
- "TimeZoneBundleInstallerTest", doesNotExist, testInstallDir);
+ TimeZoneDistroInstaller brokenSystemInstaller = new TimeZoneDistroInstaller(
+ "TimeZoneDistroInstallerTest", doesNotExist, testInstallDir);
TimeZoneDistro tzData = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
try {
@@ -106,7 +106,7 @@
TimeZoneDistro distro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro.getBytes()));
assertDistroInstalled(distro);
}
@@ -117,7 +117,7 @@
public void testInstall_successfulFirstUpdate_sameVersionAsSystem() throws Exception {
TimeZoneDistro distro = createValidTimeZoneDistro(SYSTEM_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro.getBytes()));
assertDistroInstalled(distro);
}
@@ -128,7 +128,7 @@
public void testInstall_unsuccessfulFirstUpdate_olderVersionThanSystem() throws Exception {
TimeZoneDistro distro = createValidTimeZoneDistro(OLDER_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+ TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}
@@ -139,19 +139,19 @@
public void testInstall_successfulFollowOnUpdate_newerVersion() throws Exception {
TimeZoneDistro distro1 = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro1.getBytes()));
assertDistroInstalled(distro1);
TimeZoneDistro distro2 = createValidTimeZoneDistro(NEW_RULES_VERSION, 2);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro2.getBytes()));
assertDistroInstalled(distro2);
TimeZoneDistro distro3 = createValidTimeZoneDistro(NEWER_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro3.getBytes()));
assertDistroInstalled(distro3);
}
@@ -163,13 +163,13 @@
public void testInstall_unsuccessfulFollowOnUpdate_olderVersion() throws Exception {
TimeZoneDistro distro1 = createValidTimeZoneDistro(NEW_RULES_VERSION, 2);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro1.getBytes()));
assertDistroInstalled(distro1);
TimeZoneDistro distro2 = createValidTimeZoneDistro(OLDER_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_RULES_TOO_OLD,
+ TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD,
installer.installWithErrorCode(distro2.getBytes()));
assertDistroInstalled(distro1);
}
@@ -178,7 +178,7 @@
public void testInstall_missingTzDataFile() throws Exception {
TimeZoneDistro installedDistro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(installedDistro.getBytes()));
assertDistroInstalled(installedDistro);
@@ -187,7 +187,7 @@
.clearTzDataForTests()
.buildUnvalidated();
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(incompleteDistro.getBytes()));
assertDistroInstalled(installedDistro);
}
@@ -196,7 +196,7 @@
public void testInstall_missingIcuFile() throws Exception {
TimeZoneDistro installedDistro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(installedDistro.getBytes()));
assertDistroInstalled(installedDistro);
@@ -205,7 +205,7 @@
.clearIcuDataForTests()
.buildUnvalidated();
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(incompleteDistro.getBytes()));
assertDistroInstalled(installedDistro);
}
@@ -220,7 +220,7 @@
TimeZoneDistro distro = createValidTimeZoneDistro(NEW_RULES_VERSION, 1);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_SUCCESS,
+ TimeZoneDistroInstaller.INSTALL_SUCCESS,
installer.installWithErrorCode(distro.getBytes()));
assertDistroInstalled(distro);
}
@@ -234,7 +234,7 @@
.clearVersionForTests()
.buildUnvalidated();
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}
@@ -248,7 +248,7 @@
.replaceFormatVersionForTests(2, 1)
.buildUnvalidated();
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}
@@ -265,7 +265,7 @@
TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidFormatVersionBytes);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}
@@ -281,7 +281,7 @@
TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRevisionBytes);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}
@@ -297,7 +297,7 @@
TimeZoneDistro distro = createTimeZoneDistroWithVersionBytes(invalidRulesVersionBytes);
assertEquals(
- TimeZoneBundleInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
+ TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE,
installer.installWithErrorCode(distro.getBytes()));
assertNoContentInstalled();
}