Merge "PathClassLoaderTest: add test about loading resources with tampered certificates"
diff --git a/JavaLibrary.mk b/JavaLibrary.mk
index 6b9e882..18ca800 100644
--- a/JavaLibrary.mk
+++ b/JavaLibrary.mk
@@ -121,6 +121,12 @@
LOCAL_MODULE := core-libart
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/JavaLibrary.mk
LOCAL_JAVA_LIBRARIES := core-all
+ifeq ($(EMMA_INSTRUMENT),true)
+ifneq ($(EMMA_INSTRUMENT_STATIC),true)
+ # For instrumented build, include Jacoco classes into core-libart.
+ LOCAL_STATIC_JAVA_LIBRARIES := jacocoagent
+endif # EMMA_INSTRUMENT_STATIC
+endif # EMMA_INSTRUMENT
LOCAL_CORE_LIBRARY := true
LOCAL_REQUIRED_MODULES := tzdata
include $(BUILD_JAVA_LIBRARY)
@@ -182,7 +188,7 @@
LOCAL_SRC_FILES := $(test_src_files)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs okhttp core-junit bouncycastle mockito-target
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs okhttp core-junit junit4-target bouncycastle mockito-target
LOCAL_STATIC_JAVA_LIBRARIES := core-tests-support sqlite-jdbc mockwebserver nist-pkix-tests
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -197,7 +203,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit bouncycastle
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-junit junit4-target bouncycastle
LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-bcpkix bouncycastle-ocsp
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := core-tests-support
@@ -211,7 +217,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under, jsr166-tests)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs core-junit
+LOCAL_JAVA_LIBRARIES := core-oj core-libart core-lambda-stubs core-junit junit4-target
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE := jsr166-tests
LOCAL_JAVA_LANGUAGE_VERSION := 1.8
@@ -294,7 +300,7 @@
LOCAL_SRC_FILES := $(test_src_files)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-lambda-stubs-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex core-tests-support-hostdex mockito-api-hostdex
+ LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-lambda-stubs-hostdex okhttp-hostdex bouncycastle-hostdex core-junit-hostdex junit4-target-hostdex core-tests-support-hostdex mockito-api-hostdex
LOCAL_STATIC_JAVA_LIBRARIES := sqlite-jdbc-host mockwebserver-host nist-pkix-tests-host
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
@@ -310,7 +316,7 @@
LOCAL_SRC_FILES := $(call all-test-java-files-under,support)
LOCAL_JAVA_RESOURCE_DIRS := $(test_resource_dirs)
LOCAL_NO_STANDARD_LIBRARIES := true
- LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-junit-hostdex bouncycastle-hostdex
+ LOCAL_JAVA_LIBRARIES := core-oj-hostdex core-libart-hostdex core-junit-hostdex junit4-target-hostdex bouncycastle-hostdex
LOCAL_STATIC_JAVA_LIBRARIES := bouncycastle-bcpkix-hostdex bouncycastle-ocsp-hostdex
LOCAL_JAVACFLAGS := $(local_javac_flags)
LOCAL_MODULE_TAGS := optional
diff --git a/NativeCode.mk b/NativeCode.mk
index 7ab8e4f..be02ff1 100644
--- a/NativeCode.mk
+++ b/NativeCode.mk
@@ -94,6 +94,7 @@
core_test_files := \
luni/src/test/native/dalvik_system_JniTest.cpp \
luni/src/test/native/libcore_java_io_FileTest.cpp \
+ luni/src/test/native/libcore_java_lang_ThreadTest.cpp \
luni/src/test/native/libcore_java_nio_BufferTest.cpp \
luni/src/test/native/libcore_util_NativeAllocationRegistryTest.cpp \
diff --git a/benchmarks/src/benchmarks/XmlSerializeBenchmark.java b/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
index 0ef2620..c542e87 100644
--- a/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
+++ b/benchmarks/src/benchmarks/XmlSerializeBenchmark.java
@@ -88,7 +88,7 @@
String[] splitted = datasetAsString.split(" ");
dataset = new double[splitted.length];
for (int i = 0; i < splitted.length; i++) {
- dataset[i] = Double.valueOf(splitted[i]);
+ dataset[i] = Double.parseDouble(splitted[i]);
}
}
diff --git a/benchmarks/src/benchmarks/regression/IntegerBenchmark.java b/benchmarks/src/benchmarks/regression/IntegerBenchmark.java
index f7f97c7..c9614d4 100644
--- a/benchmarks/src/benchmarks/regression/IntegerBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/IntegerBenchmark.java
@@ -133,4 +133,16 @@
}
return t;
}
+
+ public int timeIntegerValueOf(int reps) throws Exception {
+ String[] intStrings = new String[]{"0", "1", "12", "123", "1234", "12345",
+ "123456", "1234567", "12345678"};
+ int t = 0;
+ for (int i = 0; i < reps; ++i) {
+ for (int j = 0; j < intStrings.length; ++j) {
+ t += Integer.valueOf(intStrings[j]);
+ }
+ }
+ return t;
+ }
}
diff --git a/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java b/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
index 07a2305..ef54432 100644
--- a/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
+++ b/benchmarks/src/benchmarks/regression/StringBuilderBenchmark.java
@@ -63,6 +63,16 @@
}
}
+ public void timeAppendSubCharSequence(int reps) {
+ CharSequence cs = "chars";
+ for (int i = 0; i < reps; ++i) {
+ StringBuilder sb = new StringBuilder();
+ for (int j = 0; j < length; ++j) {
+ sb.append(cs);
+ }
+ }
+ }
+
public void timeAppendDouble(int reps) {
double d = 1.2;
for (int i = 0; i < reps; ++i) {
diff --git a/benchmarks/src/benchmarks/regression/StringReplaceBenchmark.java b/benchmarks/src/benchmarks/regression/StringReplaceBenchmark.java
new file mode 100644
index 0000000..a527633
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/StringReplaceBenchmark.java
@@ -0,0 +1,89 @@
+/*
+ * 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 benchmarks.regression;
+
+import com.google.caliper.Param;
+
+public class StringReplaceBenchmark {
+ static enum StringLengths {
+ EMPTY(""),
+ L_16(makeString(16)),
+ L_64(makeString(64)),
+ L_256(makeString(256)),
+ L_512(makeString(512));
+
+ private final String value;
+
+ private StringLengths(String s) {
+ this.value = s;
+ }
+ }
+
+ private static final String makeString(int length) {
+ final String sequence8 = "abcdefghijklmnop";
+ final int numAppends = (length / 16) - 1;
+ StringBuilder stringBuilder = new StringBuilder(length);
+
+ // (n-1) occurences of "abcdefghijklmnop"
+ for (int i = 0; i < numAppends; ++i) {
+ stringBuilder.append(sequence8);
+ }
+
+ // and one final occurence of qrstuvwx.
+ stringBuilder.append("qrstuvwx");
+
+ return stringBuilder.toString();
+ }
+
+ @Param private StringLengths s;
+
+ public void timeReplaceCharNonExistent(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace('z', '0');
+ }
+ }
+
+ public void timeReplaceCharRepeated(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace('a', '0');
+ }
+ }
+
+ public void timeReplaceSingleChar(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace('q', '0');
+ }
+ }
+
+ public void timeReplaceSequenceNonExistent(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace("fish", "0");
+ }
+ }
+
+ public void timeReplaceSequenceRepeated(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace("jklm", "0");
+ }
+ }
+
+ public void timeReplaceSingleSequence(int reps) {
+ for (int i = 0; i < reps; ++i) {
+ s.value.replace("qrst", "0");
+ }
+ }
+}
diff --git a/benchmarks/src/benchmarks/regression/StringToBytesBenchmark.java b/benchmarks/src/benchmarks/regression/StringToBytesBenchmark.java
new file mode 100644
index 0000000..8b2222472
--- /dev/null
+++ b/benchmarks/src/benchmarks/regression/StringToBytesBenchmark.java
@@ -0,0 +1,65 @@
+/*
+ * 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 benchmarks.regression;
+
+import com.google.caliper.Param;
+
+import java.nio.charset.StandardCharsets;
+
+public class StringToBytesBenchmark {
+ static enum StringLengths {
+ EMPTY(""),
+ L_16(makeString(16)),
+ L_64(makeString(64)),
+ L_256(makeString(256)),
+ L_512(makeString(512));
+
+ private final String value;
+
+ private StringLengths(String s) {
+ this.value = s;
+ }
+ }
+
+ private static final String makeString(int length) {
+ char[] chars = new char[length];
+ for (int i = 0; i < length; ++i) {
+ chars[i] = (char) i;
+ }
+ return new String(chars);
+ }
+
+ @Param StringLengths string;
+
+ public void timeGetBytesUtf8(int nreps) {
+ for (int i = 0; i < nreps; ++i) {
+ string.value.getBytes(StandardCharsets.UTF_8);
+ }
+ }
+
+ public void timeGetBytesIso88591(int nreps) {
+ for (int i = 0; i < nreps; ++i) {
+ string.value.getBytes(StandardCharsets.ISO_8859_1);
+ }
+ }
+
+ public void timeGetBytesAscii(int nreps) {
+ for (int i = 0; i < nreps; ++i) {
+ string.value.getBytes(StandardCharsets.US_ASCII);
+ }
+ }
+}
diff --git a/dalvik/src/main/java/dalvik/system/DexFile.java b/dalvik/src/main/java/dalvik/system/DexFile.java
index c30972b..3a12da2 100644
--- a/dalvik/src/main/java/dalvik/system/DexFile.java
+++ b/dalvik/src/main/java/dalvik/system/DexFile.java
@@ -322,13 +322,13 @@
/*
* Helper class.
*/
- private class DFEnum implements Enumeration<String> {
+ private static class DFEnum implements Enumeration<String> {
private int mIndex;
private String[] mNameList;
DFEnum(DexFile df) {
mIndex = 0;
- mNameList = getClassNameList(mCookie);
+ mNameList = getClassNameList(df.mCookie);
}
public boolean hasMoreElements() {
diff --git a/dalvik/src/main/java/dalvik/system/DexPathList.java b/dalvik/src/main/java/dalvik/system/DexPathList.java
index 7a3fa66..48cb792 100644
--- a/dalvik/src/main/java/dalvik/system/DexPathList.java
+++ b/dalvik/src/main/java/dalvik/system/DexPathList.java
@@ -311,8 +311,9 @@
// Raw dex file (not inside a zip/jar).
try {
dex = loadDexFile(file, optimizedDirectory, loader, elements);
- } catch (IOException ex) {
- System.logE("Unable to load dex file: " + file, ex);
+ } catch (IOException suppressed) {
+ System.logE("Unable to load dex file: " + file, suppressed);
+ suppressedExceptions.add(suppressed);
}
} else {
zip = file;
diff --git a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
index 48f1fe2..b29b895 100644
--- a/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
+++ b/dalvik/src/main/java/dalvik/system/ZygoteHooks.java
@@ -28,6 +28,18 @@
private long token;
/**
+ * Called by the zygote when starting up. It marks the point when any thread
+ * start should be an error, as only internal daemon threads are allowed there.
+ */
+ public static native void startZygoteNoThreadCreation();
+
+ /**
+ * Called by the zygote when startup is finished. It marks the point when it is
+ * conceivable that threads would be started again, e.g., restarting daemons.
+ */
+ public static native void stopZygoteNoThreadCreation();
+
+ /**
* Called by the zygote prior to every fork. Each call to {@code preFork}
* is followed by a matching call to {@link #postForkChild(int, String)} on the child
* process and {@link #postForkCommon()} on both the parent and the child
diff --git a/dex/src/main/java/com/android/dex/Dex.java b/dex/src/main/java/com/android/dex/Dex.java
index ea9b627b..d0434d6 100644
--- a/dex/src/main/java/com/android/dex/Dex.java
+++ b/dex/src/main/java/com/android/dex/Dex.java
@@ -93,7 +93,11 @@
* Creates a new dex buffer of the dex in {@code in}, and closes {@code in}.
*/
public Dex(InputStream in) throws IOException {
- loadFrom(in);
+ try {
+ loadFrom(in);
+ } finally {
+ in.close();
+ }
}
/**
@@ -104,13 +108,17 @@
ZipFile zipFile = new ZipFile(file);
ZipEntry entry = zipFile.getEntry(DexFormat.DEX_IN_JAR_NAME);
if (entry != null) {
- loadFrom(zipFile.getInputStream(entry));
+ try (InputStream inputStream = zipFile.getInputStream(entry)) {
+ loadFrom(inputStream);
+ }
zipFile.close();
} else {
throw new DexException("Expected " + DexFormat.DEX_IN_JAR_NAME + " in " + file);
}
} else if (file.getName().endsWith(".dex")) {
- loadFrom(new FileInputStream(file));
+ try (InputStream inputStream = new FileInputStream(file)) {
+ loadFrom(inputStream);
+ }
} else {
throw new DexException("unknown output extension: " + file);
}
@@ -141,6 +149,9 @@
return new Dex(data);
}
+ /**
+ * It is the caller's responsibility to close {@code in}.
+ */
private void loadFrom(InputStream in) throws IOException {
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
byte[] buffer = new byte[8192];
@@ -149,7 +160,6 @@
while ((count = in.read(buffer)) != -1) {
bytesOut.write(buffer, 0, count);
}
- in.close();
this.data = ByteBuffer.wrap(bytesOut.toByteArray());
this.data.order(ByteOrder.LITTLE_ENDIAN);
@@ -174,9 +184,9 @@
}
public void writeTo(File dexOut) throws IOException {
- OutputStream out = new FileOutputStream(dexOut);
- writeTo(out);
- out.close();
+ try (OutputStream out = new FileOutputStream(dexOut)) {
+ writeTo(out);
+ }
}
public TableOfContents getTableOfContents() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
index 1da9502..46559dc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/BufferedReaderTest.java
@@ -573,6 +573,16 @@
}
/**
+ * @tests java.io.BufferedReader#lines()
+ */
+ public void test_lines() {
+ // Test for method java.util.stream.Stream java.io.BufferedReader.lines()
+ br = new BufferedReader(new Support_StringReader(testString));
+ String[] r = br.lines().toArray(String[]::new);
+ assertEquals(107, r.length);
+ }
+
+ /**
* Sets up the fixture, for example, open a network connection. This method
* is called before a test is executed.
*/
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
index 3806492..1a490fa 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/io/ObjectStreamClassTest.java
@@ -25,6 +25,7 @@
import java.io.ObjectStreamClass;
import java.io.ObjectStreamField;
import java.io.Serializable;
+import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ObjectStreamClassTest extends TestCase {
@@ -216,8 +217,23 @@
osc = ObjectStreamClass.lookup(NonSerialzableClass.class);
assertNull(osc);
-
}
+ // http://b/28106822
+ public void testBug28106822() throws Exception {
+ Method getConstructorId = ObjectStreamClass.class.getDeclaredMethod(
+ "getConstructorId", Class.class);
+ getConstructorId.setAccessible(true);
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, Object.class));
+ assertEquals(1189998819991197253L, getConstructorId.invoke(null, String.class));
+
+ Method newInstance = ObjectStreamClass.class.getDeclaredMethod("newInstance",
+ Class.class, Long.TYPE);
+ newInstance.setAccessible(true);
+
+ Object obj = newInstance.invoke(null, String.class, 0 /* ignored */);
+ assertNotNull(obj);
+ assertTrue(obj instanceof String);
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
index f5bb134..37f5c0a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/MathTest.java
@@ -1057,6 +1057,68 @@
}
/**
+ * {@link java.lang.Math#nextDown(double)}
+ * @since 1.8
+ */
+ @SuppressWarnings("boxing")
+ public void test_nextDown_D() {
+ // This method is semantically equivalent to nextAfter(d,
+ // Double.NEGATIVE_INFINITY),
+ // so we use the data of test_nextAfter_DD
+ for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+ final double start = NEXTAFTER_DD_START_CASES[i][0];
+ final long nextDownBits = Double
+ .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][2]);
+ final long resultBits = Double.doubleToLongBits(Math.nextDown(start));
+ assertEquals("Result should be next down-number.", nextDownBits,
+ resultBits);
+ }
+
+ // test for cases with NaN
+ assertTrue("The result should be NaN.", Double.isNaN(Math
+ .nextDown(Double.NaN)));
+
+ // test for exception
+ try {
+ Math.nextDown((Double) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * {@link java.lang.Math#nextDown(float)}
+ * @since 1.8
+ */
+ @SuppressWarnings("boxing")
+ public void test_nextDown_F() {
+ // This method is semantically equivalent to nextAfter(f,
+ // Float.NEGATIVE_INFINITY),
+ // so we use the data of test_nextAfter_FD
+ for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+ final float start = NEXTAFTER_FD_START_CASES[i][0];
+ final int nextDownBits = Float
+ .floatToIntBits(NEXTAFTER_FD_START_CASES[i][2]);
+ final int resultBits = Float.floatToIntBits(Math.nextDown(start));
+ assertEquals("Result should be next down-number.", nextDownBits,
+ resultBits);
+ }
+
+ // test for cases with NaN
+ assertTrue("The result should be NaN.", Float.isNaN(Math
+ .nextDown(Float.NaN)));
+
+ // test for exception
+ try {
+ Math.nextDown((Float) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
* java.lang.Math#pow(double, double)
*/
public void test_powDD() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/StrictMathTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/StrictMathTest.java
index cce8935..055fbfe 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/StrictMathTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/lang/StrictMathTest.java
@@ -881,6 +881,70 @@
}
/**
+ * {@link java.lang.StrictMath#nextDown(double)}
+ * @since 1.8
+ */
+ @SuppressWarnings("boxing")
+ public void test_nextDown_D() {
+ // This method is semantically equivalent to nextAfter(d,
+ // Double.NEGATIVE_INFINITY),
+ // so we use the data of test_nextAfter_DD
+ for (int i = 0; i < NEXTAFTER_DD_START_CASES.length; i++) {
+ final double start = NEXTAFTER_DD_START_CASES[i][0];
+ final long nextDownBits = Double
+ .doubleToLongBits(NEXTAFTER_DD_START_CASES[i][2]);
+ final long resultBits = Double.doubleToLongBits(StrictMath
+ .nextDown(start));
+ assertEquals("Result should be next down-number.", nextDownBits,
+ resultBits);
+ }
+
+ // test for cases with NaN
+ assertTrue("The result should be NaN.", Double.isNaN(StrictMath
+ .nextDown(Double.NaN)));
+
+ // test for exception
+ try {
+ StrictMath.nextDown((Double) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
+ * {@link java.lang.StrictMath#nextDown(float)}
+ * @since 1.8
+ */
+ @SuppressWarnings("boxing")
+ public void test_nextDown_F() {
+ // This method is semantically equivalent to nextAfter(f,
+ // Float.NEGATIVE_INFINITY),
+ // so we use the data of test_nextAfter_FD
+ for (int i = 0; i < NEXTAFTER_FD_START_CASES.length; i++) {
+ final float start = NEXTAFTER_FD_START_CASES[i][0];
+ final int nextDownBits = Float
+ .floatToIntBits(NEXTAFTER_FD_START_CASES[i][2]);
+ final int resultBits = Float.floatToIntBits(StrictMath
+ .nextDown(start));
+ assertEquals("Result should be next down-number.", nextDownBits,
+ resultBits);
+ }
+
+ // test for cases with NaN
+ assertTrue("The result should be NaN.", Float.isNaN(StrictMath
+ .nextDown(Float.NaN)));
+
+ // test for exception
+ try {
+ StrictMath.nextDown((Float) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ // Expected
+ }
+ }
+
+ /**
* java.lang.StrictMath#pow(double, double)
*/
public void test_powDD() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
index e8f8e29..4998dc5 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/DatagramSocketTest.java
@@ -390,8 +390,11 @@
public void test_getSoTimeout() throws Exception {
DatagramSocket ds = new DatagramSocket();
- ds.setSoTimeout(100);
- assertEquals("Returned incorrect timeout", 100, ds.getSoTimeout());
+ final int timeoutSet = 100;
+ ds.setSoTimeout(timeoutSet);
+ int actualTimeout = ds.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Returned incorrect timeout", Math.abs(actualTimeout - timeoutSet) <= 10);
}
static final class TestDatagramSocketImpl extends DatagramSocketImpl {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
index 264e004..d0bb14a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/MulticastSocketTest.java
@@ -71,7 +71,7 @@
// Determine if the device is marked to support multicast or not. If this propery is not
// set we assume the device has an interface capable of supporting multicast.
- supportsMulticast = Boolean.valueOf(
+ supportsMulticast = Boolean.parseBoolean(
System.getProperty("android.cts.device.multicast", "true"));
if (!supportsMulticast) {
return;
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
index 1c1a544..5279464 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/ServerSocketTest.java
@@ -296,9 +296,12 @@
*/
public void test_getSoTimeout() throws IOException {
s = new ServerSocket(0);
+ final int timeoutSet = 100;
try {
- s.setSoTimeout(100);
- assertEquals("Returned incorrect sotimeout", 100, s.getSoTimeout());
+ s.setSoTimeout(timeoutSet);
+ int actualTimeout = s.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Returned incorrect sotimeout", Math.abs(timeoutSet - actualTimeout) <= 10);
} finally {
s.close();
}
@@ -348,12 +351,15 @@
*/
public void test_setSoTimeoutI() throws IOException {
// Timeout should trigger and throw InterruptedIOException
+ final int timeoutSet = 100;
try {
s = new ServerSocket(0);
- s.setSoTimeout(100);
+ s.setSoTimeout(timeoutSet);
s.accept();
} catch (InterruptedIOException e) {
- assertEquals("Set incorrect sotimeout", 100, s.getSoTimeout());
+ int actualSoTimeout = s.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Set incorrect sotimeout", Math.abs(timeoutSet - actualSoTimeout) <= 10);
return;
}
@@ -372,7 +378,7 @@
try {
int portNumber = s.getLocalPort();
// In IPv6, the all-zeros-address is written as "::"
- assertEquals("ServerSocket[addr=/::,localport="
+ assertEquals("ServerSocket[addr=::/::,localport="
+ portNumber + "]", s.toString());
} finally {
s.close();
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
index 4df92e2..0915a27 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/net/SocketTest.java
@@ -967,8 +967,11 @@
public void test_getSoTimeout() throws Exception {
ServerSocket server = new ServerSocket(0);
Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
- client.setSoTimeout(100);
- assertEquals("Returned incorrect sotimeout", 100, client.getSoTimeout());
+ final int timeoutSet = 100;
+ client.setSoTimeout(timeoutSet);
+ int actualTimeout = client.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Returned incorrect sotimeout", Math.abs(timeoutSet - actualTimeout) <= 10);
client.close();
server.close();
}
@@ -1492,8 +1495,11 @@
public void test_setSoTimeoutI() throws Exception {
ServerSocket server = new ServerSocket(0);
Socket client = new Socket(InetAddress.getLocalHost(), server.getLocalPort());
- client.setSoTimeout(100);
- assertEquals("Set incorrect sotimeout", 100, client.getSoTimeout());
+ final int timeoutSet = 100;
+ client.setSoTimeout(timeoutSet);
+ int actualTimeout = client.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("Set incorrect sotimeout", Math.abs(timeoutSet - actualTimeout) <= 10);
client.close();
server.close();
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
index f3b5f8b..d6dacb4 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/FileChannelTest.java
@@ -46,6 +46,8 @@
import junit.framework.TestCase;
+import libcore.io.IoUtils;
+
public class FileChannelTest extends TestCase {
private static final int CAPACITY = 100;
@@ -76,8 +78,12 @@
private FileChannel readOnlyFileChannel;
+ private FileChannel readOnlyFileChannel2;
+
private FileChannel writeOnlyFileChannel;
+ private FileChannel writeOnlyFileChannel2;
+
private FileChannel readWriteFileChannel;
private File fileOfReadOnlyFileChannel;
@@ -121,41 +127,23 @@
fileLock = null;
readOnlyFileChannel = new FileInputStream(fileOfReadOnlyFileChannel)
.getChannel();
+ readOnlyFileChannel2 = new FileInputStream(fileOfReadOnlyFileChannel)
+ .getChannel();
writeOnlyFileChannel = new FileOutputStream(fileOfWriteOnlyFileChannel)
.getChannel();
+ writeOnlyFileChannel2 = new FileOutputStream(fileOfWriteOnlyFileChannel)
+ .getChannel();
readWriteFileChannel = new RandomAccessFile(fileOfReadWriteFileChannel,
"rw").getChannel();
}
protected void tearDown() {
- if (null != readOnlyFileChannel) {
- try {
- readOnlyFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != writeOnlyFileChannel) {
- try {
- writeOnlyFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != readWriteFileChannel) {
- try {
- readWriteFileChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != fis) {
- try {
- fis.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ IoUtils.closeQuietly(readOnlyFileChannel);
+ IoUtils.closeQuietly(readOnlyFileChannel2);
+ IoUtils.closeQuietly(writeOnlyFileChannel);
+ IoUtils.closeQuietly(writeOnlyFileChannel2);
+ IoUtils.closeQuietly(readWriteFileChannel);
+ IoUtils.closeQuietly(fis);
if (null != fileLock) {
try {
@@ -174,56 +162,15 @@
if (null != fileOfReadWriteFileChannel) {
fileOfReadWriteFileChannel.delete();
}
- if (null != datagramChannelSender) {
- try {
- datagramChannelSender.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != datagramChannelReceiver) {
- try {
- datagramChannelReceiver.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != serverSocketChannel) {
- try {
- serverSocketChannel.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != socketChannelSender) {
- try {
- socketChannelSender.close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != socketChannelReceiver) {
- try {
- socketChannelReceiver.close();
- } catch (IOException e) {
- // do nothing
- }
- }
+
+ IoUtils.closeQuietly(datagramChannelSender);
+ IoUtils.closeQuietly(datagramChannelReceiver);
+ IoUtils.closeQuietly(serverSocketChannel);
+ IoUtils.closeQuietly(socketChannelSender);
+ IoUtils.closeQuietly(socketChannelReceiver);
if (null != pipe) {
- if (null != pipe.source()) {
- try {
- pipe.source().close();
- } catch (IOException e) {
- // do nothing
- }
- }
- if (null != pipe.sink()) {
- try {
- pipe.sink().close();
- } catch (IOException e) {
- // do nothing
- }
- }
+ IoUtils.closeQuietly(pipe.source());
+ IoUtils.closeQuietly(pipe.sink());
}
}
@@ -653,14 +600,81 @@
/**
* @tests java.nio.channels.FileChannel#lock()
*/
+ public void test_lock_Closed() throws Exception {
+ readOnlyFileChannel.close();
+ try {
+ readOnlyFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ writeOnlyFileChannel.close();
+ try {
+ writeOnlyFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ readWriteFileChannel.close();
+ try {
+ readWriteFileChannel.lock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_NonWritable() throws Exception {
+ try {
+ readOnlyFileChannel.lock();
+ fail("should throw NonWritableChannelException");
+ } catch (NonWritableChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
public void test_lock() throws Exception {
- MockFileChannel mockFileChannel = new MockFileChannel();
- // Verify that calling lock() leads to the method
- // lock(long, long, boolean) being called with a 0 for the
- // first parameter, Long.MAX_VALUE as the second parameter and false
- // as the third parameter.
- mockFileChannel.lock();
- assertTrue(mockFileChannel.isLockCalled);
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+ assertFalse(fileLock.isShared());
+ assertSame(writeOnlyFileChannel, fileLock.channel());
+ assertEquals(Long.MAX_VALUE, fileLock.size());
+ assertEquals(0, fileLock.position());
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_OverlappingException() throws Exception {
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+
+ // Test the same channel cannot be locked twice.
+ try {
+ writeOnlyFileChannel.lock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.lock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#lock()
+ */
+ public void test_lock_After_Release() throws Exception {
+ fileLock = writeOnlyFileChannel.lock();
+ fileLock.release();
+ // After release file lock can be obtained again.
+ fileLock = writeOnlyFileChannel.lock();
+ assertTrue(fileLock.isValid());
+
+ // A different channel should be able to obtain a lock after it has been released
+ fileLock.release();
+ assertTrue(writeOnlyFileChannel2.lock().isValid());
}
/**
@@ -826,12 +840,17 @@
fileLock = writeOnlyFileChannel.lock(POSITION, SIZE, false);
assertTrue(fileLock.isValid());
+ // Test the same channel cannot be locked twice.
try {
writeOnlyFileChannel.lock(POSITION + 1, SIZE, false);
fail("should throw OverlappingFileLockException");
- } catch (OverlappingFileLockException e) {
- // expected
- }
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.lock(POSITION + 1, SIZE, false);
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
}
/**
@@ -861,14 +880,88 @@
/**
* @tests java.nio.channels.FileChannel#tryLock()
*/
+ public void test_tryLock_Closed() throws Exception {
+ readOnlyFileChannel.close();
+ try {
+ readOnlyFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ writeOnlyFileChannel.close();
+ try {
+ writeOnlyFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+
+ readWriteFileChannel.close();
+ try {
+ readWriteFileChannel.tryLock();
+ fail("should throw ClosedChannelException");
+ } catch (ClosedChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_NonWritable() throws Exception {
+ try {
+ readOnlyFileChannel.tryLock();
+ fail("should throw NonWritableChannelException");
+ } catch (NonWritableChannelException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
public void test_tryLock() throws Exception {
- MockFileChannel mockFileChannel = new MockFileChannel();
- // Verify that calling tryLock() leads to the method
- // tryLock(long, long, boolean) being called with a 0 for the
- // first parameter, Long.MAX_VALUE as the second parameter and false
- // as the third parameter.
- mockFileChannel.tryLock();
- assertTrue(mockFileChannel.isTryLockCalled);
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+ assertFalse(fileLock.isShared());
+ assertSame(writeOnlyFileChannel, fileLock.channel());
+ assertEquals(0, fileLock.position());
+ assertEquals(Long.MAX_VALUE, fileLock.size());
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_Overlapping() throws Exception {
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test the same channel cannot be locked twice.
+ try {
+ writeOnlyFileChannel.tryLock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.tryLock();
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
+ }
+
+ /**
+ * @tests java.nio.channels.FileChannel#tryLock()
+ */
+ public void test_tryLock_After_Release() throws Exception {
+ fileLock = writeOnlyFileChannel.tryLock();
+ fileLock.release();
+
+ // After release file lock can be obtained again.
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test that the same channel can acquire the lock after it has been released
+ fileLock.release();
+ fileLock = writeOnlyFileChannel.tryLock();
+ assertTrue(fileLock.isValid());
+
+ // Test that a different channel can acquire the lock after it has been released
+ fileLock.release();
+ fileLock = writeOnlyFileChannel2.tryLock();
+ assertTrue(fileLock.isValid());
}
/**
@@ -1034,12 +1127,17 @@
fileLock = writeOnlyFileChannel.lock(POSITION, SIZE, false);
assertTrue(fileLock.isValid());
+ // Test the same channel cannot be locked twice.
try {
- writeOnlyFileChannel.lock(POSITION + 1, SIZE, false);
+ writeOnlyFileChannel.tryLock(POSITION + 1, SIZE, false);
fail("should throw OverlappingFileLockException");
- } catch (OverlappingFileLockException e) {
- // expected
- }
+ } catch (OverlappingFileLockException expected) {}
+
+ // Test that a different channel on the same file also cannot be locked.
+ try {
+ writeOnlyFileChannel2.tryLock(POSITION + 1, SIZE, false);
+ fail("should throw OverlappingFileLockException");
+ } catch (OverlappingFileLockException expected) {}
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
index 8b0f5b3..8978714 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/nio/channels/MockDatagramChannel.java
@@ -25,6 +25,7 @@
import java.net.SocketOption;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
+import java.nio.channels.MembershipKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Set;
@@ -111,13 +112,23 @@
return null;
}
- @Override
- public Set<SocketOption<?>> supportedOptions() {
+ public DatagramChannel bind(SocketAddress local) throws IOException {
return null;
}
@Override
- public DatagramChannel bind(SocketAddress local) throws IOException {
+ public MembershipKey join(InetAddress group, NetworkInterface interf) {
+ return null;
+ }
+
+ @Override
+ public MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+ throws IOException {
+ return null;
+ }
+
+ @Override
+ public Set<SocketOption<?>> supportedOptions() {
return null;
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
index d52e586..e7acfdf 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/ChoiceFormatTest.java
@@ -21,6 +21,7 @@
import java.text.FieldPosition;
import java.text.MessageFormat;
import java.text.ParsePosition;
+import java.util.Arrays;
import java.util.Locale;
import junit.framework.TestCase;
@@ -300,9 +301,11 @@
// java.text.ChoiceFormat.getFormats()
String[] orgFormats = (String[]) formats.clone();
String[] f = (String[]) f1.getFormats();
- assertTrue("Wrong formats", f.equals(formats));
+ // getFormats() documentation says "Get the formats passed in the constructor",
+ // which can be interpreted as object identity.
+ assertTrue("Wrong formats", f == formats);
f[0] = "Modified";
- assertTrue("Formats copied", !f.equals(orgFormats));
+ assertTrue("Formats copied", f != orgFormats);
}
/**
@@ -312,9 +315,11 @@
// Test for method double [] java.text.ChoiceFormat.getLimits()
double[] orgLimits = (double[]) limits.clone();
double[] l = f1.getLimits();
- assertTrue("Wrong limits", l.equals(limits));
+ // getLimits() documentation says "Get the limits passed in the constructor",
+ // which can be interpreted as object identity.
+ assertTrue("Wrong limits", l == limits);
l[0] = 3.14527;
- assertTrue("Limits copied", !l.equals(orgLimits));
+ assertTrue("Limits copied", l != orgLimits);
}
/**
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
index a61e343..3caf588 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/Arrays2Test.java
@@ -486,4 +486,21 @@
fail();
} catch(NullPointerException expected) {}
}
+
+ public void test_replaceAll() throws Exception {
+ List<Integer> list = Arrays.asList(0, 1, 2);
+ list.replaceAll(k -> k + 1);
+ assertEquals((Integer)1, list.get(0));
+ assertEquals((Integer)2, list.get(1));
+ assertEquals((Integer)3, list.get(2));
+ assertEquals(3, list.size());
+ }
+
+ public void test_replaceAll_NPE() throws Exception {
+ List<Integer> list = Arrays.asList(0, 1, 2);
+ try {
+ list.replaceAll(null);
+ fail();
+ } catch(NullPointerException expected) {}
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
index afec098..bbd8c50 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/GregorianCalendarTest.java
@@ -37,6 +37,8 @@
public void setUp() throws Exception {
super.setUp();
defaultLocale = Locale.getDefault();
+ // Most tests are locale independent, but locale does affect start-of-week.
+ Locale.setDefault(Locale.US);
}
@Override
@@ -537,8 +539,6 @@
* java.util.GregorianCalendar#roll(int, boolean)
*/
public void test_rollIZ() {
- Locale.setDefault(Locale.US);
-
// Test for method void java.util.GregorianCalendar.roll(int, boolean)
GregorianCalendar gc = new GregorianCalendar(1972, Calendar.OCTOBER,
13, 19, 9, 59);
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
index bf8db02..ee1a372 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/IdentityHashMapTest.java
@@ -36,6 +36,7 @@
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
+import java.util.function.BiFunction;
public class IdentityHashMapTest extends junit.framework.TestCase {
private static final String ID = "hello";
@@ -1054,6 +1055,34 @@
SpliteratorTester.testSpliteratorNPE(values.spliterator());
}
+ public void test_replaceAll() {
+ IdentityHashMap<String, String> map = new IdentityHashMap<>();
+ String key1 = "key1";
+ String key2 = "key2";
+ String key3 = "key3";
+
+ map.put(key1, "1");
+ map.put(key2, "2");
+ map.put(key3, "3");
+
+ map.replaceAll((k, v) -> k + v);
+
+ assertEquals("key11", map.get(key1));
+ assertEquals("key22", map.get(key2));
+ assertEquals("key33", map.get(key3));
+ assertEquals(3, map.size());
+
+ try {
+ map.replaceAll(new BiFunction<String, String, String>() {
+ @Override
+ public String apply(String s, String s2) {
+ map.put("key4", "4");
+ return "";
+ }
+ });
+ } catch (ConcurrentModificationException expected) {}
+ }
+
// comparator for IdentityHashMap objects
private static final SerializableAssert COMPARATOR = new SerializableAssert() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
index 11be2fe..db2ee7a 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/ResourceBundleTest.java
@@ -395,4 +395,12 @@
Locale.setDefault(defLocale);
}
+
+ // http://b/26879578
+ public void testBundleWithUtf8Values() {
+ ResourceBundle bundle = ResourceBundle.getBundle(
+ "org.apache.harmony.tests.java.util.TestUtf8ResourceBundle");
+ assertEquals("Страх мой удивительный UTF-8 синтаксического анализа",
+ bundle.getString("key"));
+ }
}
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
index 173e37e..958d9bc 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/util/jar/JarFileTest.java
@@ -300,27 +300,6 @@
assertEquals(6, i);
}
- public void test_entries2() throws Exception {
- Support_Resources.copyFile(resources, null, jarName);
- JarFile jarFile = new JarFile(new File(resources, jarName));
- Enumeration<JarEntry> enumeration = jarFile.entries();
- jarFile.close();
- try {
- enumeration.hasMoreElements();
- fail("hasMoreElements() did not detect a closed jar file");
- } catch (IllegalStateException e) {
- }
- Support_Resources.copyFile(resources, null, jarName);
- jarFile = new JarFile(new File(resources, jarName));
- enumeration = jarFile.entries();
- jarFile.close();
- try {
- enumeration.nextElement();
- fail("nextElement() did not detect closed jar file");
- } catch (IllegalStateException e) {
- }
- }
-
/**
* @throws IOException
* java.util.jar.JarFile#getJarEntry(java.lang.String)
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
index f2705ea..2b4b916 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/net/ssl/HttpsURLConnectionTest.java
@@ -97,16 +97,6 @@
}
/**
- * javax.net.ssl.HttpsURLConnection#getDefaultSSLSocketFactory()
- */
- public final void test_getDefaultSSLSocketFactory() {
- SSLSocketFactory sf = HttpsURLConnection.getDefaultSSLSocketFactory();
- if (!sf.equals(SSLSocketFactory.getDefault())) {
- fail("incorrect DefaultSSLSocketFactory");
- }
- }
-
- /**
* javax.net.ssl.HttpsURLConnection#getHostnameVerifier()
*/
public final void test_getHostnameVerifier()
@@ -186,17 +176,6 @@
}
/**
- * javax.net.ssl.HttpsURLConnection#getSSLSocketFactory()
- */
- public final void test_getSSLSocketFactory() {
- HttpsURLConnection con = new MyHttpsURLConnection(null);
- SSLSocketFactory sf = con.getSSLSocketFactory();
- if (!sf.equals(SSLSocketFactory.getDefault())) {
- fail("incorrect DefaultSSLSocketFactory");
- }
- }
-
- /**
* javax.net.ssl.HttpsURLConnection#setDefaultHostnameVerifier()
*/
public final void test_setDefaultHostnameVerifier() {
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
index 024c9e9..8682de7 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/javax/security/auth/callback/PasswordCallbackTest.java
@@ -93,7 +93,7 @@
}
pc.clearPassword();
res = pc.getPassword();
- if (res.equals(psw2)) {
+ if (Arrays.equals(res, psw2)) {
fail("Incorrect password was returned after clear");
}
pc.setPassword(psw1);
diff --git a/json/src/main/java/org/json/JSONObject.java b/json/src/main/java/org/json/JSONObject.java
index 9ea91a6..7902389 100644
--- a/json/src/main/java/org/json/JSONObject.java
+++ b/json/src/main/java/org/json/JSONObject.java
@@ -21,6 +21,7 @@
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
// Note: this class was written without inspecting the non-free org.json sourcecode.
@@ -100,6 +101,8 @@
@Override public boolean equals(Object o) {
return o == this || o == null; // API specifies this broken equals implementation
}
+ // at least make the broken equals(null) consistent with Objects.hashCode(null).
+ @Override public int hashCode() { return Objects.hashCode(null); }
@Override public String toString() {
return "null";
}
diff --git a/json/src/test/java/org/json/JSONObjectTest.java b/json/src/test/java/org/json/JSONObjectTest.java
index 9029ec6..07d1cf6 100644
--- a/json/src/test/java/org/json/JSONObjectTest.java
+++ b/json/src/test/java/org/json/JSONObjectTest.java
@@ -27,6 +27,7 @@
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import junit.framework.TestCase;
@@ -825,6 +826,12 @@
assertTrue(object.isNull("bar"));
}
+ public void testNullValue_equalsAndHashCode() {
+ assertTrue(JSONObject.NULL.equals(null)); // guaranteed by javadoc
+ // not guaranteed by javadoc, but seems like a good idea
+ assertEquals(Objects.hashCode(null), JSONObject.NULL.hashCode());
+ }
+
public void testHas() throws JSONException {
JSONObject object = new JSONObject();
object.put("foo", 5);
diff --git a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java
index 60de8b9..5949cbc 100644
--- a/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java
+++ b/jsr166-tests/src/test/java/jsr166/ConcurrentHashMap8Test.java
@@ -300,7 +300,7 @@
*/
public void testGetMappedValue() {
ConcurrentHashMap map = map5();
- assertNull(map.keySet().getMappedValue());
+ assertNull(((ConcurrentHashMap.KeySetView) map.keySet()).getMappedValue());
try {
map.keySet(null);
shouldThrow();
diff --git a/libart/src/main/java/dalvik/system/VMRuntime.java b/libart/src/main/java/dalvik/system/VMRuntime.java
index 9b7d24a..8b27ca2 100644
--- a/libart/src/main/java/dalvik/system/VMRuntime.java
+++ b/libart/src/main/java/dalvik/system/VMRuntime.java
@@ -39,7 +39,7 @@
// instruction set name should not exceed 7 characters. See installd
// and the package manager for the actual propeties.
private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP
- = new HashMap<String, String>();
+ = new HashMap<String, String>(16);
static {
ABI_TO_INSTRUCTION_SET_MAP.put("armeabi", "arm");
ABI_TO_INSTRUCTION_SET_MAP.put("armeabi-v7a", "arm");
@@ -396,4 +396,10 @@
* set.
*/
public static native boolean didPruneDalvikCache();
+
+ /**
+ * Register the current execution thread to the runtime as sensitive thread.
+ * Should be called just once. Subsequent calls are ignored.
+ */
+ public static native void registerSensitiveThread();
}
diff --git a/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
new file mode 100644
index 0000000..8d05711
--- /dev/null
+++ b/libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+/*
+ * 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 java.lang;
+
+import java.util.Properties;
+
+/**
+ * A class encoding all hardcoded system property values on Android. A compiler may
+ * take advantage of these properties. Changing them at load-time (-D) or runtime
+ * may not have any effect.
+ *
+ * @hide
+ */
+public final class AndroidHardcodedSystemProperties {
+
+ // This value is shared with sun.misc.Version. It is defined here so that the compiler
+ // can use it.
+ public final static String JAVA_VERSION = "0";
+
+ final static String[][] STATIC_PROPERTIES = {
+ // None of these four are meaningful on Android, but these keys are guaranteed
+ // to be present for System.getProperty. For java.class.version, we use the maximum
+ // class file version that dx currently supports.
+ { "java.class.version", "50.0" },
+ { "java.version", JAVA_VERSION },
+ { "java.compiler", "" },
+ { "java.ext.dirs", "" },
+
+ { "java.specification.name", "Dalvik Core Library" },
+ { "java.specification.vendor", "The Android Project" },
+ { "java.specification.version", "0.9" },
+
+ { "java.vendor", "The Android Project" },
+ { "java.vendor.url", "http://www.android.com/" },
+ { "java.vm.name", "Dalvik" },
+ { "java.vm.specification.name", "Dalvik Virtual Machine Specification" },
+ { "java.vm.specification.vendor", "The Android Project" },
+ { "java.vm.specification.version", "0.9" },
+ { "java.vm.vendor", "The Android Project" },
+
+ { "java.vm.vendor.url", "http://www.android.com/" },
+
+ { "java.net.preferIPv6Addresses", "false" },
+
+ { "file.encoding", "UTF-8" },
+
+ { "file.separator", "/" },
+ { "line.separator", "\n" },
+ { "path.separator", ":" },
+
+ // Turn off ICU debugging. This allows compile-time initialization of a range of
+ // classes. b/28039175
+ { "ICUDebug", null },
+
+ // Hardcode DecimalFormat parsing flag to be default. b/27265238
+ { "android.icu.text.DecimalFormat.SkipExtendedSeparatorParsing", null },
+ // Hardcode MessagePattern apostrophe mode to be default. b/27265238
+ { "android.icu.text.MessagePattern.ApostropheMode", null },
+
+ // Hardcode "sun.io.useCanonCaches" to use the default (on). b/28174137
+ { "sun.io.useCanonCaches", null },
+ { "sun.io.useCanonPrefixCache", null },
+
+ // Hardcode some http properties to use the default. b/28174137
+ { "http.keepAlive", null },
+ { "http.keepAliveDuration", null },
+ { "http.maxConnections", null },
+
+ // Hardcode "os.name" to "Linux." Aids compile-time initialization, checked in System.
+ // b/28174137
+ { "os.name", "Linux" },
+ };
+}
+
diff --git a/libart/src/main/java/java/lang/reflect/AbstractMethod.java b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
index 2b93f52..0126765 100644
--- a/libart/src/main/java/java/lang/reflect/AbstractMethod.java
+++ b/libart/src/main/java/java/lang/reflect/AbstractMethod.java
@@ -35,7 +35,6 @@
import com.android.dex.Dex;
import java.lang.annotation.Annotation;
import java.util.List;
-import libcore.reflect.AnnotationAccess;
import libcore.reflect.GenericSignatureParser;
import libcore.reflect.ListOfTypes;
import libcore.reflect.Types;
@@ -198,18 +197,17 @@
return Types.getTypeArray(getMethodOrConstructorGenericInfo().genericExceptionTypes, false);
}
- @Override public Annotation[] getDeclaredAnnotations() {
- List<Annotation> result = AnnotationAccess.getDeclaredAnnotations(this);
- return result.toArray(new Annotation[result.size()]);
- }
+ @Override public native Annotation[] getDeclaredAnnotations();
@Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
if (annotationType == null) {
throw new NullPointerException("annotationType == null");
}
- return AnnotationAccess.isDeclaredAnnotationPresent(this, annotationType);
+ return isAnnotationPresentNative(annotationType);
}
+ private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
+
public Annotation[] getAnnotations() {
return super.getAnnotations();
}
@@ -253,7 +251,7 @@
* Returns generic information associated with this method/constructor member.
*/
final GenericInfo getMethodOrConstructorGenericInfo() {
- String signatureAttribute = AnnotationAccess.getSignature(this);
+ String signatureAttribute = getSignatureAttribute();
Member member;
Class<?>[] exceptionTypes;
boolean method = this instanceof Method;
@@ -279,6 +277,20 @@
parser.returnType, parser.formalTypeParameters);
}
+ private String getSignatureAttribute() {
+ String[] annotation = getSignatureAnnotation();
+ if (annotation == null) {
+ return null;
+ }
+ StringBuilder result = new StringBuilder();
+ for (String s : annotation) {
+ result.append(s);
+ }
+ return result.toString();
+ }
+
+ private native String[] getSignatureAnnotation();
+
protected boolean equalMethodParameters(Class<?>[] params) {
Dex dex = declaringClassOfOverriddenMethod.getDex();
short[] types = dex.parameterTypeIndicesFromMethodIndex(dexMethodIndex);
diff --git a/luni/src/main/java/java/math/BigDecimal.java b/luni/src/main/java/java/math/BigDecimal.java
index 0e89762..0f49056 100644
--- a/luni/src/main/java/java/math/BigDecimal.java
+++ b/luni/src/main/java/java/math/BigDecimal.java
@@ -1035,10 +1035,13 @@
if(this.bitLength < 64 && divisor.bitLength < 64 ) {
if(diffScale == 0) {
- return dividePrimitiveLongs(this.smallValue,
- divisor.smallValue,
- scale,
- roundingMode );
+ // http://b/26105053 - corner case: Long.MIN_VALUE / (-1) overflows a long
+ if (this.smallValue != Long.MIN_VALUE || divisor.smallValue != -1) {
+ return dividePrimitiveLongs(this.smallValue,
+ divisor.smallValue,
+ scale,
+ roundingMode);
+ }
} else if(diffScale > 0) {
if(diffScale < MathUtils.LONG_POWERS_OF_TEN.length &&
divisor.bitLength + LONG_POWERS_OF_TEN_BIT_LENGTH[(int)diffScale] < 64) {
@@ -1085,7 +1088,7 @@
if(scaledDivisor.bitLength() < 63) { // 63 in order to avoid out of long after *2
long rem = remainder.longValue();
long divisor = scaledDivisor.longValue();
- compRem = longCompareTo(Math.abs(rem) * 2,Math.abs(divisor));
+ compRem = compareForRounding(rem, divisor);
// To look if there is a carry
compRem = roundingBehavior(quotient.testBit(0) ? 1 : 0,
sign * (5 + compRem), roundingMode);
@@ -1113,8 +1116,7 @@
int sign = Long.signum( scaledDividend ) * Long.signum( scaledDivisor );
if (remainder != 0) {
// Checking if: remainder * 2 >= scaledDivisor
- int compRem; // 'compare to remainder'
- compRem = longCompareTo(Math.abs(remainder) * 2,Math.abs(scaledDivisor));
+ int compRem = compareForRounding(remainder, scaledDivisor); // 'compare to remainder'
// To look if there is a carry
quotient += roundingBehavior(((int)quotient) & 1,
sign * (5 + compRem),
@@ -2700,9 +2702,36 @@
setUnscaledValue(integerAndFraction[0]);
}
- private static int longCompareTo(long value1, long value2) {
+ /**
+ * Returns -1, 0, and 1, respectively, if {@code value1 <, ==, > value2},
+ * respectively, when comparing without regard to the values' sign.
+ * This corresponds to the partial order where {@code 0L} is the smallest
+ * possible value and {@link Long#MIN_VALUE} is the largest because its
+ * absolute value is larger than any possible long value.
+ */
+ private static int compareAbsoluteValues(long value1, long value2) {
+ // Because Math.abs(Long.MIN_VALUE) == Long.MIN_VALUE,
+ // -1 <= Math.abs(v) - 1 <= Long.MAX_VALUE with correct ordering
+ // for v == Long.MIN_VALUE.
+ value1 = Math.abs(value1) - 1;
+ value2 = Math.abs(value2) - 1;
+ // Unlike Long.compare(), we guarantee to return specifically -1 and +1
return value1 > value2 ? 1 : (value1 < value2 ? -1 : 0);
}
+
+ /**
+ * Returns {@code -1, 0, +1} respectively for {@code abs(n/d) <, ==, > 0.5},
+ * respectively, using overflow and rounding safe arithmetics.
+ */
+ private static int compareForRounding(long n, long d) {
+ long halfD = d / 2;
+ if (n == halfD || n == -halfD) {
+ return (int) (d & 1);
+ } else {
+ return compareAbsoluteValues(n, halfD);
+ }
+ }
+
/**
* This method implements an efficient rounding for numbers which unscaled
* value fits in the type {@code long}.
@@ -2724,7 +2753,7 @@
// If the discarded fraction is non-zero perform rounding
if (fraction != 0) {
// To check if the discarded fraction >= 0.5
- compRem = longCompareTo(Math.abs(fraction) * 2, sizeOfFraction);
+ compRem = compareForRounding(fraction, sizeOfFraction);
// To look if there is a carry
integer += roundingBehavior( ((int)integer) & 1,
Long.signum(fraction) * (5 + compRem),
diff --git a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
index 38be0c2..0a73c9f 100644
--- a/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetDecoderICU.java
@@ -68,6 +68,7 @@
private CharsetDecoderICU(Charset cs, float averageCharsPerByte, long address) {
super(cs, averageCharsPerByte, MAX_CHARS_PER_BYTE);
this.converterHandle = address;
+ NativeConverter.registerConverter(this, converterHandle);
}
@Override protected void implReplaceWith(String newReplacement) {
@@ -155,14 +156,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- NativeConverter.closeConverter(converterHandle);
- converterHandle = 0;
- } finally {
- super.finalize();
- }
- }
private int getArray(CharBuffer out) {
if (out.hasArray()) {
diff --git a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
index 3583e19..a981c18 100644
--- a/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
+++ b/luni/src/main/java/java/nio/charset/CharsetEncoderICU.java
@@ -21,6 +21,7 @@
import libcore.icu.ICU;
import libcore.icu.NativeConverter;
import libcore.util.EmptyArray;
+import libcore.util.NativeAllocationRegistry;
final class CharsetEncoderICU extends CharsetEncoder {
private static final Map<String, byte[]> DEFAULT_REPLACEMENTS = new HashMap<String, byte[]>();
@@ -49,7 +50,7 @@
private int[] data = new int[3];
/* handle to the ICU converter that is opened */
- private long converterHandle=0;
+ private final long converterHandle;
private char[] input = null;
private byte[] output = null;
@@ -95,6 +96,7 @@
super(cs, averageBytesPerChar, maxBytesPerChar, replacement, true);
// Our native peer needs to know what just happened...
this.converterHandle = address;
+ NativeConverter.registerConverter(this, converterHandle);
updateCallback();
}
@@ -184,15 +186,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- NativeConverter.closeConverter(converterHandle);
- converterHandle=0;
- } finally {
- super.finalize();
- }
- }
-
private int getArray(ByteBuffer out) {
if (out.hasArray()) {
output = out.array();
diff --git a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
index 2581230..e4c6df0 100644
--- a/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
+++ b/luni/src/main/java/java/util/concurrent/ConcurrentHashMap.java
@@ -1201,6 +1201,9 @@
* operations. It does not support the {@code add} or
* {@code addAll} operations.
*
+ * <p> The set returned by this method is guaranteed to an instance of
+ * {@link KeySetView}.
+ *
* <p>The view's iterators and spliterators are
* <a href="package-summary.html#Weakly"><i>weakly consistent</i></a>.
*
@@ -1209,7 +1212,8 @@
*
* @return the set view
*/
- public KeySetView<K,V> keySet() {
+ // NOTE: The upstream version of this function returns KeySetView (See http://b/28099367).
+ public Set<K> keySet() {
KeySetView<K,V> ks;
return (ks = keySet) != null ? ks : (keySet = new KeySetView<K,V>(this, null));
}
@@ -4553,8 +4557,7 @@
* A view of a ConcurrentHashMap as a {@link Set} of keys, in
* which additions may optionally be enabled by mapping to a
* common value. This class cannot be directly instantiated.
- * See {@link #keySet() keySet()},
- * {@link #keySet(Object) keySet(V)},
+ * See {@link #keySet(Object) keySet(V)},
* {@link #newKeySet() newKeySet()},
* {@link #newKeySet(int) newKeySet(int)}.
*
diff --git a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
index 1fbca2f..c31bee3 100644
--- a/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
+++ b/luni/src/main/java/javax/xml/datatype/FactoryFinder.java
@@ -61,8 +61,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
index 0060612..50a644f 100644
--- a/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/validation/SchemaFactoryFinder.java
@@ -62,8 +62,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
index 5a7663c..7a4f6b3 100644
--- a/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
+++ b/luni/src/main/java/javax/xml/xpath/XPathFactoryFinder.java
@@ -69,8 +69,8 @@
File f = new File(configFile);
if (f.exists()) {
if (debug) debugPrintln("Read properties file " + f);
- try {
- cacheProps.load(new FileInputStream(f));
+ try (FileInputStream inputStream = new FileInputStream(f)) {
+ cacheProps.load(inputStream);
} catch (Exception ex) {
if (debug) {
ex.printStackTrace();
diff --git a/luni/src/main/java/libcore/icu/NativeConverter.java b/luni/src/main/java/libcore/icu/NativeConverter.java
index 17be458..a2b5798 100644
--- a/luni/src/main/java/libcore/icu/NativeConverter.java
+++ b/luni/src/main/java/libcore/icu/NativeConverter.java
@@ -9,12 +9,17 @@
package libcore.icu;
+import libcore.util.NativeAllocationRegistry;
+
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.CodingErrorAction;
public final class NativeConverter {
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), getNativeSize());
+
public static native int decode(long converterHandle, byte[] input, int inEnd,
char[] output, int outEnd, int[] data, boolean flush);
@@ -24,6 +29,10 @@
public static native long openConverter(String charsetName);
public static native void closeConverter(long converterHandle);
+ public static void registerConverter(Object referrent, long converterHandle) {
+ registry.registerNativeAllocation(referrent, converterHandle);
+ }
+
public static native void resetByteToChar(long converterHandle);
public static native void resetCharToByte(long converterHandle);
@@ -67,4 +76,7 @@
encoder.replacement());
}
private static native void setCallbackEncode(long converterHandle, int onMalformedInput, int onUnmappableInput, byte[] subBytes);
+
+ public static native long getNativeFinalizer();
+ public static native long getNativeSize();
}
diff --git a/luni/src/main/java/libcore/reflect/AnnotationAccess.java b/luni/src/main/java/libcore/reflect/AnnotationAccess.java
deleted file mode 100644
index 2a72c18..0000000
--- a/luni/src/main/java/libcore/reflect/AnnotationAccess.java
+++ /dev/null
@@ -1,727 +0,0 @@
-/*
- * Copyright (C) 2011 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.reflect;
-
-import com.android.dex.Dex;
-import com.android.dex.EncodedValueReader;
-import com.android.dex.FieldId;
-import com.android.dex.MethodId;
-import com.android.dex.ProtoId;
-import com.android.dex.TypeList;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Inherited;
-import java.lang.reflect.AccessibleObject;
-import java.lang.reflect.AnnotatedElement;
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Field;
-import java.lang.reflect.Member;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import libcore.util.EmptyArray;
-
-/**
- * Look up annotations from a dex file.
- */
-public final class AnnotationAccess {
- private AnnotationAccess() {
- }
-
- /*
- * Classes like arrays, primitives and proxies will not have a Dex file.
- * Such classes never have annotations.
- */
-
- private static final Class<?>[] NO_ARGUMENTS = null;
- @SuppressWarnings("unused")
- private static final byte VISIBILITY_BUILD = 0x00;
- private static final byte VISIBILITY_RUNTIME = 0x01;
- @SuppressWarnings("unused")
- private static final byte VISIBILITY_SYSTEM = 0x02;
-
- /*
- * Class annotations. This includes declared class annotations plus
- * annotations on the superclass that have @Inherited.
- */
-
- public static <A extends java.lang.annotation.Annotation> A getAnnotation(
- Class<?> c, Class<A> annotationType) {
- if (annotationType == null) {
- throw new NullPointerException("annotationType == null");
- }
-
- A annotation = getDeclaredAnnotation(c, annotationType);
- if (annotation != null) {
- return annotation;
- }
-
- if (isInherited(annotationType)) {
- for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) {
- annotation = getDeclaredAnnotation(sup, annotationType);
- if (annotation != null) {
- return annotation;
- }
- }
- }
-
- return null;
- }
-
- /**
- * Returns true if {@code annotationType} annotations on the superclass
- * apply to subclasses that don't have another annotation of the same
- * type.
- */
- private static boolean isInherited(Class<? extends Annotation> annotationType) {
- return isDeclaredAnnotationPresent(annotationType, Inherited.class);
- }
-
- public static Annotation[] getAnnotations(Class<?> c) {
- /*
- * We need to get the annotations declared on this class, plus the
- * annotations from superclasses that have the "@Inherited" annotation
- * set. We create a temporary map to use while we accumulate the
- * annotations and convert it to an array at the end.
- *
- * It's possible to have duplicates when annotations are inherited.
- * We use a Map to filter those out.
- *
- * HashMap might be overkill here.
- */
- HashMap<Class<?>, Annotation> map = new HashMap<Class<?>, Annotation>();
- for (Annotation declaredAnnotation : getDeclaredAnnotations(c)) {
- map.put(declaredAnnotation.annotationType(), declaredAnnotation);
- }
- for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) {
- for (Annotation declaredAnnotation : getDeclaredAnnotations(sup)) {
- Class<? extends Annotation> clazz = declaredAnnotation.annotationType();
- if (!map.containsKey(clazz) && isInherited(clazz)) {
- map.put(clazz, declaredAnnotation);
- }
- }
- }
-
- /* convert annotation values from HashMap to array */
- Collection<Annotation> coll = map.values();
- return coll.toArray(new Annotation[coll.size()]);
- }
-
- /**
- * Returns true if {@code c} is annotated by {@code annotationType}.
- */
- public static boolean isAnnotationPresent(
- Class<?> c, Class<? extends Annotation> annotationType) {
- if (annotationType == null) {
- throw new NullPointerException("annotationType == null");
- }
-
- if (isDeclaredAnnotationPresent(c, annotationType)) {
- return true;
- }
-
- if (isInherited(annotationType)) {
- for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) {
- if (isDeclaredAnnotationPresent(sup, annotationType)) {
- return true;
- }
- }
- }
-
- return false;
- }
-
- /*
- * Class, Field, Method, Constructor and Parameter annotations
- */
-
- /**
- * Returns the annotations on {@code element}.
- */
- public static List<Annotation> getDeclaredAnnotations(AnnotatedElement element) {
- int offset = getAnnotationSetOffset(element);
- return annotationSetToAnnotations(getDexClass(element), offset);
- }
-
- /**
- * Returns the annotation if it exists.
- */
- public static <A extends Annotation> A getDeclaredAnnotation(
- AnnotatedElement element, Class<A> annotationClass) {
- com.android.dex.Annotation a = getAnnotation(element, annotationClass);
- return a != null
- ? toAnnotationInstance(getDexClass(element), annotationClass, a)
- : null;
- }
-
- /**
- * Returns true if the annotation exists.
- */
- public static boolean isDeclaredAnnotationPresent(
- AnnotatedElement element, Class<? extends Annotation> annotationClass) {
- return getAnnotation(element, annotationClass) != null;
- }
-
- private static com.android.dex.Annotation getAnnotation(
- AnnotatedElement element, Class<? extends Annotation> annotationClass) {
- int annotationSetOffset = getAnnotationSetOffset(element);
- if (annotationSetOffset == 0) {
- return null; // no annotation
- }
-
- Class<?> dexClass = getDexClass(element);
- Dex dex = dexClass.getDex();
- Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item
- String annotationInternalName = InternalNames.getInternalName(annotationClass);
- for (int i = 0, size = setIn.readInt(); i < size; i++) {
- int annotationOffset = setIn.readInt();
- Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
- // The internal string name of the annotation is compared here and deliberately not
- // the value of annotationClass.getTypeIndex(). The annotationClass may have been
- // defined by a different dex file, which would make the indexes incomparable.
- com.android.dex.Annotation candidate = annotationIn.readAnnotation();
- String candidateInternalName = dex.typeNames().get(candidate.getTypeIndex());
- if (candidateInternalName.equals(annotationInternalName)) {
- return candidate;
- }
- }
-
- return null; // This set doesn't contain the annotation.
- }
-
- /**
- * @param element a class, a field, a method or a constructor.
- */
- private static int getAnnotationSetOffset(AnnotatedElement element) {
- Class<?> dexClass = getDexClass(element);
- int directoryOffset = dexClass.getDexAnnotationDirectoryOffset();
- if (directoryOffset == 0) {
- return 0; // nothing on this class has annotations
- }
-
- Dex.Section directoryIn = dexClass.getDex().open(directoryOffset);
- int classSetOffset = directoryIn.readInt();
- if (element instanceof Class) {
- return classSetOffset;
- }
-
- int fieldsSize = directoryIn.readInt();
- int methodsSize = directoryIn.readInt();
- directoryIn.readInt(); // parameters size
-
- if (element instanceof Field) {
- int fieldIndex = ((Field) element).getDexFieldIndex();
- for (int i = 0; i < fieldsSize; i++) {
- int candidateFieldIndex = directoryIn.readInt();
- int annotationSetOffset = directoryIn.readInt();
- if (candidateFieldIndex == fieldIndex) {
- return annotationSetOffset;
- }
- }
- // if we were searching for a field then we missed
- return 0;
- }
-
- // Skip through the fields without reading them and look for constructors or methods.
- directoryIn.skip(8 * fieldsSize);
-
- int methodIndex= element instanceof Method ? ((Method) element).getDexMethodIndex()
- : ((Constructor<?>) element).getDexMethodIndex();
- for (int i = 0; i < methodsSize; i++) {
- int candidateMethodIndex = directoryIn.readInt();
- int annotationSetOffset = directoryIn.readInt();
- if (candidateMethodIndex == methodIndex) {
- return annotationSetOffset;
- }
- }
-
- return 0;
- }
-
- /**
- * Returns {@code element} if it is a class; and the class declaring
- * {@code element} otherwise. The dex file of the returned class also
- * defines {@code element}.
- */
- private static Class<?> getDexClass(AnnotatedElement element) {
- return element instanceof Class
- ? ((Class<?>) element)
- : ((Member) element).getDeclaringClass();
- }
-
- /**
- * Returns the parameter annotations on {@code member}.
- */
- public static Annotation[][] getParameterAnnotations(Class<?> declaringClass,
- int methodDexIndex) {
- Dex dex = declaringClass.getDex();
- int protoIndex = dex.methodIds().get(methodDexIndex).getProtoIndex();
- ProtoId proto = dex.protoIds().get(protoIndex);
- TypeList parametersList = dex.readTypeList(proto.getParametersOffset());
- short[] types = parametersList.getTypes();
- int typesCount = types.length;
-
- int directoryOffset = declaringClass.getDexAnnotationDirectoryOffset();
- if (directoryOffset == 0) {
- return new Annotation[typesCount][0]; // nothing on this class has annotations
- }
-
- Dex.Section directoryIn = dex.open(directoryOffset);
- directoryIn.readInt(); // class annotations
- int fieldsSize = directoryIn.readInt();
- int methodsSize = directoryIn.readInt();
- int parametersSize = directoryIn.readInt();
-
- for (int i = 0; i < fieldsSize; i++) {
- directoryIn.readInt(); // field_index
- directoryIn.readInt(); // annotation_set
- }
-
- for (int i = 0; i < methodsSize; i++) {
- directoryIn.readInt(); // method_index
- directoryIn.readInt(); // annotation_set
- }
-
- for (int i = 0; i < parametersSize; i++) {
- int candidateMethodDexIndex = directoryIn.readInt();
- int annotationSetRefListOffset = directoryIn.readInt();
- if (candidateMethodDexIndex != methodDexIndex) {
- continue;
- }
-
- Dex.Section refList = dex.open(annotationSetRefListOffset);
- int parameterCount = refList.readInt();
- Annotation[][] result = new Annotation[parameterCount][];
- for (int p = 0; p < parameterCount; p++) {
- int annotationSetOffset = refList.readInt();
- List<Annotation> annotations
- = annotationSetToAnnotations(declaringClass, annotationSetOffset);
- result[p] = annotations.toArray(new Annotation[annotations.size()]);
- }
- return result;
- }
-
- return new Annotation[typesCount][0];
- }
-
- /*
- * System annotations.
- */
-
- public static Object getDefaultValue(Method method) {
- /*
- * Dex represents this with @AnnotationDefault on annotations that have
- * default values:
- *
- * @AnnotationDefault(value=@Foo(a=7))
- * public @interface Foo {
- * int a() default 7;
- * int b();
- * }
- */
-
- Class<?> annotationClass = method.getDeclaringClass();
- // All lookups of type and string indexes are within the Dex that declares the annotation so
- // the indexes can be compared directly.
- Dex dex = annotationClass.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, annotationClass, "Ldalvik/annotation/AnnotationDefault;");
- if (reader == null) {
- return null;
- }
-
- int fieldCount = reader.readAnnotation();
- if (reader.getAnnotationType() != annotationClass.getDexTypeIndex()) {
- throw new AssertionError("annotation value type != annotation class");
- }
-
- int methodNameIndex = dex.findStringIndex(method.getName());
- for (int i = 0; i < fieldCount; i++) {
- int candidateNameIndex = reader.readAnnotationName();
- if (candidateNameIndex == methodNameIndex) {
- Class<?> returnType = method.getReturnType();
- return decodeValue(annotationClass, returnType, dex, reader);
- } else {
- reader.skipValue();
- }
- }
-
- return null;
- }
-
- /**
- * Returns the class of which {@code c} is a direct member. If {@code c} is
- * defined in a method or constructor, this is not transitive.
- */
- public static Class<?> getEnclosingClass(Class<?> c) {
- /*
- * public class Bar {
- * @EnclosingClass(value=Bar)
- * public class Foo {}
- * }
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, c, "Ldalvik/annotation/EnclosingClass;");
- if (reader == null) {
- return null;
- }
- return c.getDexCacheType(dex, reader.readType());
- }
-
- public static AccessibleObject getEnclosingMethodOrConstructor(Class<?> c) {
- /*
- * public class Bar {
- * public void quux(String s, int i) {
- * @EnclosingMethod(value=Bar.quux(String,int))
- * class Foo {}
- * }
- * }
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, c, "Ldalvik/annotation/EnclosingMethod;");
- if (reader == null) {
- return null;
- }
- return indexToMethod(c, dex, reader.readMethod());
- }
-
- public static Class<?>[] getMemberClasses(Class<?> c) {
- /*
- * @MemberClasses(value=[Bar, Baz])
- * public class Foo {
- * class Bar {}
- * class Baz {}
- * }
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, c, "Ldalvik/annotation/MemberClasses;");
- if (reader == null) {
- return EmptyArray.CLASS;
- }
- return (Class[]) decodeValue(c, Class[].class, dex, reader);
- }
-
- /**
- * @param element a class, a field, a method or a constructor.
- */
- public static String getSignature(AnnotatedElement element) {
- /*
- * @Signature(value=["Ljava/util/List", "<", "Ljava/lang/String;", ">;"])
- * List<String> foo;
- */
- Class<?> dexClass = getDexClass(element);
- Dex dex = dexClass.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, element, "Ldalvik/annotation/Signature;");
- if (reader == null) {
- return null;
- }
- String[] array = (String[]) decodeValue(dexClass, String[].class, dex, reader);
- StringBuilder result = new StringBuilder();
- for (String s : array) {
- result.append(s);
- }
- return result.toString();
- }
-
- /**
- * @param element a method or a constructor.
- */
- public static Class<?>[] getExceptions(AnnotatedElement element) {
- /*
- * @Throws(value=[IOException.class])
- * void foo() throws IOException;
- */
- Class<?> dexClass = getDexClass(element);
- Dex dex = dexClass.getDex();
- EncodedValueReader reader = getOnlyAnnotationValue(
- dex, element, "Ldalvik/annotation/Throws;");
- if (reader == null) {
- return EmptyArray.CLASS;
- }
- return (Class<?>[]) decodeValue(dexClass, Class[].class, dex, reader);
- }
-
- public static int getInnerClassFlags(Class<?> c, int defaultValue) {
- /*
- * @InnerClass(accessFlags=0x01,name="Foo")
- * class Foo {};
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getAnnotationReader(
- dex, c, "Ldalvik/annotation/InnerClass;", 2);
- if (reader == null) {
- return defaultValue;
- }
- reader.readAnnotationName(); // accessFlags
- return reader.readInt();
- }
-
- public static String getInnerClassName(Class<?> c) {
- /*
- * @InnerClass(accessFlags=0x01,name="Foo")
- * class Foo {};
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getAnnotationReader(
- dex, c, "Ldalvik/annotation/InnerClass;", 2);
- if (reader == null) {
- return null;
- }
- reader.readAnnotationName(); // accessFlags
- reader.readInt();
- reader.readAnnotationName(); // name
- return reader.peek() == EncodedValueReader.ENCODED_NULL
- ? null
- : (String) decodeValue(c, String.class, dex, reader);
- }
-
- public static boolean isAnonymousClass(Class<?> c) {
- /*
- * @InnerClass(accessFlags=0x01,name="Foo")
- * class Foo {};
- */
- Dex dex = c.getDex();
- EncodedValueReader reader = getAnnotationReader(
- dex, c, "Ldalvik/annotation/InnerClass;", 2);
- if (reader == null) {
- return false;
- }
- reader.readAnnotationName(); // accessFlags
- reader.readInt();
- reader.readAnnotationName(); // name
- return reader.peek() == EncodedValueReader.ENCODED_NULL;
- }
-
- /*
- * Dex support.
- *
- * Different classes come from different Dex files. This class is careful
- * to guarantee that Dex-relative indices and encoded values are interpreted
- * using the Dex that they were read from. Methods that use Dex-relative
- * values accept that Dex as a parameter or the class from which that Dex
- * was derived.
- */
-
- private static EncodedValueReader getAnnotationReader(
- Dex dex, AnnotatedElement element, String annotationName, int expectedFieldCount) {
- int annotationSetOffset = getAnnotationSetOffset(element);
- if (annotationSetOffset == 0) {
- return null; // no annotations on the class
- }
-
- Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item
- com.android.dex.Annotation annotation = null;
- // TODO: is it better to compute the index of the annotation name in the dex file and check
- // indices below?
- for (int i = 0, size = setIn.readInt(); i < size; i++) {
- int annotationOffset = setIn.readInt();
- Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
- com.android.dex.Annotation candidate = annotationIn.readAnnotation();
- String candidateAnnotationName = dex.typeNames().get(candidate.getTypeIndex());
- if (annotationName.equals(candidateAnnotationName)) {
- annotation = candidate;
- break;
- }
- }
- if (annotation == null) {
- return null; // no annotation
- }
-
- EncodedValueReader reader = annotation.getReader();
- int fieldCount = reader.readAnnotation();
- String readerAnnotationName = dex.typeNames().get(reader.getAnnotationType());
- if (!readerAnnotationName.equals(annotationName)) {
- throw new AssertionError();
- }
- if (fieldCount != expectedFieldCount) {
- return null; // not the expected values on this annotation; give up
- }
-
- return reader;
- }
-
- /**
- * Returns a reader ready to read the only value of the annotation on
- * {@code element}, or null if that annotation doesn't exist.
- */
- private static EncodedValueReader getOnlyAnnotationValue(
- Dex dex, AnnotatedElement element, String annotationName) {
- EncodedValueReader reader = getAnnotationReader(dex, element, annotationName, 1);
- if (reader == null) {
- return null;
- }
- reader.readAnnotationName(); // skip the name
- return reader;
- }
-
- private static Class<? extends Annotation> getAnnotationClass(Class<?> context, Dex dex,
- int typeIndex) {
- try {
- @SuppressWarnings("unchecked") // we do a runtime check
- Class<? extends Annotation> result =
- (Class<? extends Annotation>) context.getDexCacheType(dex, typeIndex);
- if (!result.isAnnotation()) {
- throw new IncompatibleClassChangeError("Expected annotation: " + result.getName());
- }
- return result;
- } catch (NoClassDefFoundError ncdfe) {
- return null;
- }
- }
-
- private static AccessibleObject indexToMethod(Class<?> context, Dex dex, int methodIndex) {
- Class<?> declaringClass =
- context.getDexCacheType(dex, dex.declaringClassIndexFromMethodIndex(methodIndex));
- String name = context.getDexCacheString(dex, dex.nameIndexFromMethodIndex(methodIndex));
- short[] types = dex.parameterTypeIndicesFromMethodIndex(methodIndex);
- Class<?>[] parametersArray = new Class[types.length];
- for (int i = 0; i < types.length; i++) {
- parametersArray[i] = context.getDexCacheType(dex, types[i]);
- }
- try {
- return name.equals("<init>")
- ? declaringClass.getDeclaredConstructor(parametersArray)
- : declaringClass.getDeclaredMethod(name, parametersArray);
- } catch (NoSuchMethodException e) {
- throw new IncompatibleClassChangeError("Couldn't find " + declaringClass.getName()
- + "." + name + Arrays.toString(parametersArray));
- }
- }
-
- private static List<Annotation> annotationSetToAnnotations(Class<?> context, int offset) {
- if (offset == 0) {
- return Collections.emptyList(); // no annotations in the set
- }
-
- Dex dex = context.getDex();
- Dex.Section setIn = dex.open(offset); // annotation_set_item
- int size = setIn.readInt();
- List<Annotation> result = new ArrayList<Annotation>(size);
-
- for (int i = 0; i < size; i++) {
- int annotationOffset = setIn.readInt();
- Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item
- com.android.dex.Annotation annotation = annotationIn.readAnnotation();
- if (annotation.getVisibility() != VISIBILITY_RUNTIME) {
- continue;
- }
- Class<? extends Annotation> annotationClass =
- getAnnotationClass(context, dex, annotation.getTypeIndex());
- if (annotationClass != null) {
- result.add(toAnnotationInstance(context, dex, annotationClass, annotation.getReader()));
- }
- }
- return result;
- }
-
- private static <A extends Annotation> A toAnnotationInstance(Class<?> context,
- Class<A> annotationClass, com.android.dex.Annotation annotation) {
- return toAnnotationInstance(context, context.getDex(), annotationClass,
- annotation.getReader());
- }
-
- private static <A extends Annotation> A toAnnotationInstance(Class<?> context, Dex dex,
- Class<A> annotationClass, EncodedValueReader reader) {
- int fieldCount = reader.readAnnotation();
- if (annotationClass != context.getDexCacheType(dex, reader.getAnnotationType())) {
- throw new AssertionError("annotation value type != return type");
- }
- AnnotationMember[] members = new AnnotationMember[fieldCount];
- for (int i = 0; i < fieldCount; i++) {
- int name = reader.readAnnotationName();
- String nameString = dex.strings().get(name);
- Method method;
- try {
- method = annotationClass.getMethod(nameString, NO_ARGUMENTS);
- } catch (NoSuchMethodException e) {
- throw new IncompatibleClassChangeError(
- "Couldn't find " + annotationClass.getName() + "." + nameString);
- }
- Class<?> returnType = method.getReturnType();
- Object value = decodeValue(context, returnType, dex, reader);
- members[i] = new AnnotationMember(nameString, value, returnType, method);
- }
- return AnnotationFactory.createAnnotation(annotationClass, members);
- }
-
- private static Object decodeValue(Class<?> context, Class<?> type,
- Dex dex, EncodedValueReader reader) {
- if (type.isArray()) {
- int size = reader.readArray();
- Class<?> componentType = type.getComponentType();
- Object array = Array.newInstance(componentType, size);
- for (int i = 0; i < size; i++) {
- Array.set(array, i, decodeValue(context, componentType, dex, reader));
- }
- return array;
- } else if (type.isEnum()) {
- int fieldIndex = reader.readEnum();
- FieldId fieldId = dex.fieldIds().get(fieldIndex);
- String fieldName = dex.strings().get(fieldId.getNameIndex());
- Field field;
- try {
- field = type.getDeclaredField(fieldName);
- return field.get(null);
- } catch (NoSuchFieldException e) {
- NoSuchFieldError error = new NoSuchFieldError();
- error.initCause(e);
- throw error;
- } catch (IllegalAccessException e) {
- IllegalAccessError error = new IllegalAccessError();
- error.initCause(e);
- throw error;
- }
- } else if (type.isAnnotation()) {
- @SuppressWarnings("unchecked") // Class.isAnnotation is the runtime check
- Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) type;
- return toAnnotationInstance(context, dex, annotationClass, reader);
- } else if (type == String.class) {
- int index = reader.readString();
- return context.getDexCacheString(dex, index);
- } else if (type == Class.class) {
- int index = reader.readType();
- return context.getDexCacheType(dex, index);
- } else if (type == byte.class) {
- return reader.readByte();
- } else if (type == short.class) {
- return reader.readShort();
- } else if (type == int.class) {
- return reader.readInt();
- } else if (type == long.class) {
- return reader.readLong();
- } else if (type == float.class) {
- return reader.readFloat();
- } else if (type == double.class) {
- return reader.readDouble();
- } else if (type == char.class) {
- return reader.readChar();
- } else if (type == boolean.class) {
- return reader.readBoolean();
- } else {
- // is null legit?
- throw new AssertionError("Unexpected annotation value type: " + type);
- }
- }
-}
diff --git a/luni/src/main/java/libcore/reflect/TypeVariableImpl.java b/luni/src/main/java/libcore/reflect/TypeVariableImpl.java
index 2eb9827..6bf1881 100644
--- a/luni/src/main/java/libcore/reflect/TypeVariableImpl.java
+++ b/luni/src/main/java/libcore/reflect/TypeVariableImpl.java
@@ -84,7 +84,8 @@
if (decl instanceof Class) {
// FIXME: Is the following hierarchy correct?:
Class cl = (Class)decl;
- decl = (GenericDeclaration) AnnotationAccess.getEnclosingMethodOrConstructor(cl);
+ Method m = cl.getEnclosingMethod();
+ decl = (GenericDeclaration) m != null ? m : cl.getEnclosingConstructor();
if (decl != null) {
return decl;
}
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
index 6724776..0eda8f0 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/DOMConfigurationImpl.java
@@ -357,6 +357,10 @@
}
public DOMStringList getParameterNames() {
+ return internalGetParameterNames();
+ }
+
+ private static DOMStringList internalGetParameterNames() {
final String[] result = PARAMETERS.keySet().toArray(new String[PARAMETERS.size()]);
return new DOMStringList() {
public String item(int index) {
diff --git a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
index e1b62fa..e4002ea 100644
--- a/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/dom/DocumentImpl.java
@@ -56,7 +56,6 @@
*/
private String documentUri;
private String inputEncoding;
- private String xmlEncoding;
private String xmlVersion = "1.0";
private boolean xmlStandalone = false;
private boolean strictErrorChecking = true;
@@ -437,7 +436,7 @@
}
public String getXmlEncoding() {
- return xmlEncoding;
+ return null;
}
public boolean getXmlStandalone() {
diff --git a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
index 040a012..4f54fb5 100644
--- a/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
+++ b/luni/src/main/java/org/apache/harmony/xml/parsers/DocumentBuilderImpl.java
@@ -129,11 +129,12 @@
parser.require(XmlPullParser.END_DOCUMENT, null, null);
} catch (XmlPullParserException ex) {
- if (ex.getDetail() instanceof IOException) {
- throw (IOException) ex.getDetail();
+ Throwable detail = ex.getDetail();
+ if (detail instanceof IOException) {
+ throw (IOException) detail;
}
- if (ex.getDetail() instanceof RuntimeException) {
- throw (RuntimeException) ex.getDetail();
+ if (detail instanceof RuntimeException) {
+ throw (RuntimeException) detail;
}
LocatorImpl locator = new LocatorImpl();
diff --git a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
index c4ff069..39dd367 100644
--- a/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
+++ b/luni/src/main/java/org/xml/sax/helpers/XMLReaderFactory.java
@@ -126,9 +126,12 @@
in = loader.getResourceAsStream (service);
if (in != null) {
- reader = new BufferedReader (new InputStreamReader (in, StandardCharsets.UTF_8));
- className = reader.readLine ();
- in.close ();
+ try {
+ reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
+ className = reader.readLine();
+ } finally {
+ in.close(); // may throw IOException
+ }
}
} catch (Exception e) {
}
diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp
index 35d014c..3b25233 100644
--- a/luni/src/main/native/java_util_regex_Matcher.cpp
+++ b/luni/src/main/native/java_util_regex_Matcher.cpp
@@ -116,8 +116,18 @@
void operator=(const MatcherAccessor&);
};
-static void Matcher_closeImpl(JNIEnv*, jclass, jlong address) {
- delete toRegexMatcher(address);
+static void Matcher_free(void* address) {
+ delete reinterpret_cast<icu::RegexMatcher*>(address);
+}
+
+static jlong Matcher_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&Matcher_free);
+}
+
+// Return a guess of the amount of native memory to be deallocated by a typical call to
+// Matcher_free().
+static jint Matcher_nativeSize(JNIEnv*, jclass) {
+ return 200; // Very rough guess based on a quick look at the implementation.
}
static jint Matcher_findImpl(JNIEnv* env, jclass, jlong addr, jstring javaText, jint startIndex, jintArray offsets) {
@@ -198,13 +208,14 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Matcher, closeImpl, "(J)V"),
NATIVE_METHOD(Matcher, findImpl, "(JLjava/lang/String;I[I)Z"),
NATIVE_METHOD(Matcher, findNextImpl, "(JLjava/lang/String;[I)Z"),
+ NATIVE_METHOD(Matcher, getNativeFinalizer, "()J"),
NATIVE_METHOD(Matcher, groupCountImpl, "(J)I"),
NATIVE_METHOD(Matcher, hitEndImpl, "(J)Z"),
NATIVE_METHOD(Matcher, lookingAtImpl, "(JLjava/lang/String;[I)Z"),
NATIVE_METHOD(Matcher, matchesImpl, "(JLjava/lang/String;[I)Z"),
+ NATIVE_METHOD(Matcher, nativeSize, "()I"),
NATIVE_METHOD(Matcher, openImpl, "(J)J"),
NATIVE_METHOD(Matcher, requireEndImpl, "(J)Z"),
NATIVE_METHOD(Matcher, setInputImpl, "(JLjava/lang/String;II)V"),
diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp
index f2c07dc..4166da03 100644
--- a/luni/src/main/native/java_util_regex_Pattern.cpp
+++ b/luni/src/main/native/java_util_regex_Pattern.cpp
@@ -27,10 +27,6 @@
// ICU documentation: http://icu-project.org/apiref/icu4c/classRegexPattern.html
-static icu::RegexPattern* toRegexPattern(jlong addr) {
- return reinterpret_cast<icu::RegexPattern*>(static_cast<uintptr_t>(addr));
-}
-
static const char* regexDetailMessage(UErrorCode status) {
// These human-readable error messages were culled from "utypes.h", and then slightly tuned
// to make more sense in context.
@@ -71,8 +67,18 @@
env->Throw(reinterpret_cast<jthrowable>(exception));
}
-static void Pattern_closeImpl(JNIEnv*, jclass, jlong addr) {
- delete toRegexPattern(addr);
+static void Pattern_free(void* addr) {
+ delete reinterpret_cast<icu::RegexPattern*>(addr);
+}
+
+static jlong Pattern_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&Pattern_free);
+}
+
+// Return a guess of the amount of native memory to be deallocated by a typical call to
+// Pattern_free().
+static jint Pattern_nativeSize(JNIEnv*, jclass) {
+ return 500; // Very rough guess based on a quick look at the implementation.
}
static jlong Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint flags) {
@@ -95,9 +101,11 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Pattern, closeImpl, "(J)V"),
NATIVE_METHOD(Pattern, compileImpl, "(Ljava/lang/String;I)J"),
+ NATIVE_METHOD(Pattern, getNativeFinalizer, "()J"),
+ NATIVE_METHOD(Pattern, nativeSize, "()I"),
};
+
void register_java_util_regex_Pattern(JNIEnv* env) {
jniRegisterNativeMethods(env, "java/util/regex/Pattern", gMethods, NELEM(gMethods));
}
diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp
index 334f4c9..bf938d1 100644
--- a/luni/src/main/native/libcore_icu_NativeConverter.cpp
+++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp
@@ -611,6 +611,20 @@
javaCanonicalName, icuCanonicalNameStr, javaAliases);
}
+static void FreeNativeConverter(void *converter) {
+ ucnv_close(reinterpret_cast<UConverter*>(converter));
+}
+
+static jlong NativeConverter_getNativeFinalizer(JNIEnv*, jclass) {
+ return reinterpret_cast<jlong>(&FreeNativeConverter);
+}
+
+
+static jlong NativeConverter_getNativeSize(JNIEnv*, jclass, jstring) {
+ // TODO: Improve estimate.
+ return 200;
+}
+
static JNINativeMethod gMethods[] = {
NATIVE_METHOD(NativeConverter, charsetForName, "(Ljava/lang/String;)Ljava/nio/charset/Charset;"),
NATIVE_METHOD(NativeConverter, closeConverter, "(J)V"),
@@ -628,6 +642,8 @@
NATIVE_METHOD(NativeConverter, resetCharToByte, "(J)V"),
NATIVE_METHOD(NativeConverter, setCallbackDecode, "(JIILjava/lang/String;)V"),
NATIVE_METHOD(NativeConverter, setCallbackEncode, "(JII[B)V"),
+ NATIVE_METHOD(NativeConverter, getNativeFinalizer, "()J"),
+ NATIVE_METHOD(NativeConverter, getNativeSize, "()J")
};
void register_libcore_icu_NativeConverter(JNIEnv* env) {
jniRegisterNativeMethods(env, "libcore/icu/NativeConverter", gMethods, NELEM(gMethods));
diff --git a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
index 398adbc..74432e5 100644
--- a/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/FileInputStreamTest.java
@@ -223,6 +223,28 @@
assertTrue(getOpenFdsForPrefix("test_bug_25695227").isEmpty());
}
+ // http://b/28192631
+ public void testSkipOnLargeFiles() throws Exception {
+ File largeFile = File.createTempFile("FileInputStreamTest_testSkipOnLargeFiles", "");
+ FileOutputStream fos = new FileOutputStream(largeFile);
+ try {
+ byte[] buffer = new byte[1024 * 1024]; // 1 MB
+ for (int i = 0; i < 3 * 1024; i++) { // 3 GB
+ fos.write(buffer);
+ }
+ } finally {
+ fos.close();
+ }
+
+ FileInputStream fis = new FileInputStream(largeFile);
+ long lastByte = 3 * 1024 * 1024 * 1024L - 1;
+ assertEquals(0, Libcore.os.lseek(fis.getFD(), 0, OsConstants.SEEK_CUR));
+ assertEquals(lastByte, fis.skip(lastByte));
+
+ // Proactively cleanup - it's a pretty large file.
+ assertTrue(largeFile.delete());
+ }
+
private static List<Integer> getOpenFdsForPrefix(String path) throws Exception {
File[] fds = new File("/proc/self/fd").listFiles();
List<Integer> list = new ArrayList<>();
diff --git a/luni/src/test/java/libcore/java/io/FileTest.java b/luni/src/test/java/libcore/java/io/FileTest.java
index 93b6708..5d5317a 100644
--- a/luni/src/test/java/libcore/java/io/FileTest.java
+++ b/luni/src/test/java/libcore/java/io/FileTest.java
@@ -337,13 +337,14 @@
// http://b/27273930
public void testJavaIoTmpdirMutable() throws Exception {
final String oldTmpDir = System.getProperty("java.io.tmpdir");
- final String newTmpDir = oldTmpDir + "/newTemp";
- File subDir = new File(oldTmpDir, "newTemp");
+ final String directoryName = "/newTemp" + Integer.toString(Math.randomIntInternal());
+ final String newTmpDir = oldTmpDir + directoryName;
+ File subDir = new File(oldTmpDir, directoryName);
assertTrue(subDir.mkdir());
try {
System.setProperty("java.io.tmpdir", newTmpDir);
File tempFile = File.createTempFile("foo", ".bar");
- assertTrue(tempFile.getAbsolutePath().contains("/newTemp/"));
+ assertTrue(tempFile.getAbsolutePath().contains(directoryName));
} finally {
System.setProperty("java.io.tmpdir", oldTmpDir);
}
diff --git a/luni/src/test/java/libcore/java/io/ObjectOutputStreamTest.java b/luni/src/test/java/libcore/java/io/ObjectOutputStreamTest.java
index 9228162..3adc030 100644
--- a/luni/src/test/java/libcore/java/io/ObjectOutputStreamTest.java
+++ b/luni/src/test/java/libcore/java/io/ObjectOutputStreamTest.java
@@ -16,8 +16,14 @@
package libcore.java.io;
+import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Arrays;
+import java.util.List;
import junit.framework.TestCase;
public final class ObjectOutputStreamTest extends TestCase {
@@ -32,4 +38,74 @@
ObjectOutputStream os = new ObjectOutputStream(new ByteArrayOutputStream());
os.writeObject(s);
}
+
+ public static class CallsCloseInWriteObjectMethod implements Serializable {
+ private String message;
+
+ public CallsCloseInWriteObjectMethod(String message) {
+ this.message = message;
+ }
+
+ private void writeObject(ObjectOutputStream oos) throws IOException {
+ oos.writeObject(message);
+ oos.close();
+ }
+
+ private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
+ message = (String) ois.readObject();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ CallsCloseInWriteObjectMethod that = (CallsCloseInWriteObjectMethod) o;
+
+ return message.equals(that.message);
+ }
+
+ @Override
+ public int hashCode() {
+ return message.hashCode();
+ }
+ }
+
+ // http://b/28159133
+ public void testCloseInWriteObject() throws Exception {
+ String hello = "Hello";
+ CallsCloseInWriteObjectMethod object = new CallsCloseInWriteObjectMethod(hello);
+ // This reproduces the problem in http://b/28159133 as follows:
+ // the list class gets handle N
+ // the object closes the ObjectOutputStream and clears the handle table
+ // the hello gets handle N
+ // the reuse of hello has a reference to handle N
+ // When it is deserialized the list contains object, hello, Arrays.asList().getClass()
+ // instead of object, hello, hello.
+ List<Serializable> input = Arrays.asList(object, hello, hello);
+ @SuppressWarnings("unchecked")
+ List<CallsCloseInWriteObjectMethod> output = (List<CallsCloseInWriteObjectMethod>)
+ roundTrip(input);
+
+ assertEquals(input, output);
+ }
+
+ private Serializable roundTrip(Object object)
+ throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
+ oos.writeObject(object);
+ }
+
+ Serializable read;
+ ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
+ try (ObjectInputStream ois = new ObjectInputStream(bais)) {
+ read = (Serializable) ois.readObject();
+ }
+ return read;
+ }
}
diff --git a/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java b/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java
new file mode 100644
index 0000000..0d67277
--- /dev/null
+++ b/luni/src/test/java/libcore/java/io/UncheckedIOExceptionTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.io;
+
+import junit.framework.TestCase;
+
+import org.apache.harmony.testframework.serialization.SerializationTest;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+
+public class UncheckedIOExceptionTest extends TestCase {
+
+ /**
+ * java.lang.UncheckedIOException#UncheckedIOException(java.io.IOException)
+ */
+ public void test_ConstructorLjava_lang_IOException() {
+ IOException ioException = new IOException();
+ UncheckedIOException e = new UncheckedIOException(ioException);
+ assertEquals("java.io.IOException", e.getMessage());
+ assertSame(ioException, e.getCause());
+ }
+
+ /**
+ * java.lang.UncheckedIOException#UncheckedIOException(java.lang.String, java.io.IOException)
+ */
+ public void test_ConstructorLjava_lang_String_IOException() {
+ IOException ioException = new IOException();
+ UncheckedIOException e = new UncheckedIOException("errmsg", ioException);
+ assertEquals("errmsg", e.getMessage());
+ assertSame(ioException, e.getCause());
+ }
+
+ /**
+ * serialization/deserialization.
+ */
+ public void testSerializationSelf() throws Exception {
+ SerializationTest.verifySelf(new UncheckedIOException(new IOException()));
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/BooleanTest.java b/luni/src/test/java/libcore/java/lang/BooleanTest.java
index b1f536f..10dac92 100644
--- a/luni/src/test/java/libcore/java/lang/BooleanTest.java
+++ b/luni/src/test/java/libcore/java/lang/BooleanTest.java
@@ -38,4 +38,25 @@
assertEquals(Boolean.TRUE.hashCode(), Boolean.hashCode(true));
assertEquals(Boolean.FALSE.hashCode(), Boolean.hashCode(false));
}
+
+ public void testLogicalAnd() {
+ assertTrue(Boolean.logicalAnd(Boolean.TRUE, Boolean.TRUE));
+ assertFalse(Boolean.logicalAnd(Boolean.TRUE, Boolean.FALSE));
+ assertFalse(Boolean.logicalAnd(Boolean.FALSE, Boolean.TRUE));
+ assertFalse(Boolean.logicalAnd(Boolean.FALSE, Boolean.FALSE));
+ }
+
+ public void testLogicalOr() {
+ assertTrue(Boolean.logicalOr(Boolean.TRUE, Boolean.TRUE));
+ assertTrue(Boolean.logicalOr(Boolean.TRUE, Boolean.FALSE));
+ assertTrue(Boolean.logicalOr(Boolean.FALSE, Boolean.TRUE));
+ assertFalse(Boolean.logicalOr(Boolean.FALSE, Boolean.FALSE));
+ }
+
+ public void testLogicalXor() {
+ assertFalse(Boolean.logicalXor(Boolean.TRUE, Boolean.TRUE));
+ assertTrue(Boolean.logicalXor(Boolean.TRUE, Boolean.FALSE));
+ assertTrue(Boolean.logicalXor(Boolean.FALSE, Boolean.TRUE));
+ assertFalse(Boolean.logicalXor(Boolean.FALSE, Boolean.FALSE));
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/MathTest.java b/luni/src/test/java/libcore/java/lang/MathTest.java
new file mode 100644
index 0000000..f7ebaa6
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/MathTest.java
@@ -0,0 +1,303 @@
+/*
+ * 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.lang;
+
+import junit.framework.TestCase;
+
+import java.math.BigInteger;
+
+public class MathTest extends TestCase {
+
+ public void testIntExact() {
+ testIntExact(123, 456);
+ testIntExact(-456, 456);
+ testIntExact(0, 0);
+ testIntExact(Integer.MAX_VALUE, 1);
+ testIntExact(Integer.MAX_VALUE, -1);
+ testIntExact(Integer.MIN_VALUE, 1);
+ testIntExact(Integer.MIN_VALUE, -1);
+ testIntExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ testIntExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
+ }
+
+ private void testIntExact(int a, int b) {
+ testAddExactI(a, b);
+ testSubtractExactI(a, b);
+ testMultiplyExactI(a, b);
+ testIncrementExactI(a);
+ testDecrementExactI(a);
+ testNegateExactI(a);
+ }
+
+ private void testAddExactI(int a, int b) {
+ long expected = (long) a + (long) b;
+ try {
+ assertEquals(expected, Math.addExact(a, b));
+ } catch (ArithmeticException e) {
+ if (expected == a + b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testSubtractExactI(int a, int b) {
+ long expected = (long) a - (long) b;
+ try {
+ assertEquals(expected, Math.subtractExact(a, b));
+ } catch (ArithmeticException e) {
+ long result = (long) a - (long) b;
+ if (expected == a - b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testMultiplyExactI(int a, int b) {
+ long expected = (long) a * (long) b;
+ try {
+ assertEquals(expected, Math.multiplyExact(a, b));
+ } catch (ArithmeticException e) {
+ if (expected == a * b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testIncrementExactI(int a) {
+ long expected = (long) a + 1L;
+ try {
+ assertEquals(expected, Math.incrementExact(a));
+ } catch (ArithmeticException e) {
+ if (expected == a + 1) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testDecrementExactI(int a) {
+ long expected = (long) a - 1L;
+ try {
+ assertEquals(expected, Math.decrementExact(a));
+ } catch (ArithmeticException e) {
+ if (expected == a - 1) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testNegateExactI(int a) {
+ long expected = -((long) a);
+ try {
+ assertEquals(expected, Math.negateExact(a));
+ } catch (ArithmeticException e) {
+ if (expected == -a) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ public void testLongExact() {
+ testLongExact(123, 456);
+ testLongExact(-456, 456);
+ testLongExact(0, 0);
+ testLongExact(Long.MAX_VALUE, 1);
+ testLongExact(Long.MAX_VALUE, -1);
+ testLongExact(Long.MIN_VALUE, 1);
+ testLongExact(Long.MIN_VALUE, -1);
+ testLongExact(Long.MAX_VALUE, Long.MAX_VALUE);
+ testLongExact(Long.MIN_VALUE, Long.MIN_VALUE);
+ }
+
+ private void testLongExact(long a, long b) {
+ testAddExactL(a, b);
+ testSubtractExactL(a, b);
+ testMultiplyExactL(a, b);
+ testIncrementExactL(a);
+ testDecrementExactL(a);
+ testNegateExactL(a);
+ testToIntExactL(a);
+ }
+
+ private void testAddExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).add(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.addExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a + b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testSubtractExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).subtract(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.subtractExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a - b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testMultiplyExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).multiply(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.multiplyExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a * b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testIncrementExactL(long a) {
+ BigInteger expected = BigInteger.valueOf(a).add(BigInteger.ONE);
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.incrementExact(a)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a + 1L))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testDecrementExactL(long a) {
+ BigInteger expected = BigInteger.valueOf(a).subtract(BigInteger.ONE);
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.decrementExact(a)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a - 1L))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testNegateExactL(long a) {
+ BigInteger expected = BigInteger.valueOf(a).negate();
+ try {
+ assertEquals(expected, BigInteger.valueOf(Math.negateExact(a)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(-a))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testToIntExactL(long a) {
+ try {
+ assertEquals((int) a, Math.toIntExact(a));
+ assertEquals(a, Math.toIntExact(a)); // Is not exact, should throw AE.
+ } catch (ArithmeticException e) {
+ if (a <= Integer.MAX_VALUE && a >= Integer.MIN_VALUE) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ public void testIntFloorDivMod() {
+ testFloorDivModI(123, 456);
+ testFloorDivModI(456, 123);
+ testFloorDivModI(369, 123);
+ testFloorDivModI(1, 0);
+ testFloorDivModI(Integer.MAX_VALUE, 1);
+ testFloorDivModI(Integer.MAX_VALUE, -1);
+ testFloorDivModI(Integer.MIN_VALUE, 1);
+ testFloorDivModI(Integer.MIN_VALUE, -1);
+ }
+
+ private void testFloorDivModI(int a, int b) {
+ testFloorDivI(a, b);
+ testFloorModI(a, b);
+ }
+
+ private void testFloorDivI(int a, int b) {
+ try {
+ int floorDiv = Math.floorDiv(a, b);
+ int expected = a / b;
+ if (expected < 0 && a % b != 0) {
+ --expected;
+ }
+ assertEquals(expected, floorDiv);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ private void testFloorModI(int a, int b) {
+ try {
+ int floorMod = Math.floorMod(a, b);
+ int expected = a % b;
+ if ((a ^ b) < 0 && expected != 0) {
+ expected = b - expected;
+ }
+ assertEquals(expected, floorMod);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ public void testLongFloorDivMod() {
+ testFloorDivModL(123L, 456L);
+ testFloorDivModL(456L, 123L);
+ testFloorDivModL(369L, 123L);
+ testFloorDivModL(1L, 0L);
+ testFloorDivModL(Long.MAX_VALUE, 1L);
+ testFloorDivModL(Long.MAX_VALUE, -1L);
+ testFloorDivModL(Long.MIN_VALUE, 1L);
+ testFloorDivModL(Long.MIN_VALUE, -1L);
+ }
+
+ private void testFloorDivModL(long a, long b) {
+ testFloorDivL(a, b);
+ testFloorModL(a, b);
+ }
+
+ private void testFloorDivL(long a, long b) {
+ try {
+ long floorDiv = Math.floorDiv(a, b);
+ long expected = a / b;
+ if (expected < 0 && a % b != 0) {
+ --expected;
+ }
+ assertEquals(expected, floorDiv);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ private void testFloorModL(long a, long b) {
+ try {
+ long floorMod = Math.floorMod(a, b);
+ long expected = a % b;
+ if ((a ^ b) < 0 && expected != 0) {
+ expected = b - expected;
+ }
+ assertEquals(expected, floorMod);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/OldSystemTest.java b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
index f7a69a3..6c12250 100644
--- a/luni/src/test/java/libcore/java/lang/OldSystemTest.java
+++ b/luni/src/test/java/libcore/java/lang/OldSystemTest.java
@@ -258,8 +258,8 @@
public void test_gc() {
Runtime rt = Runtime.getRuntime();
Vector<StringBuffer> vec = new Vector<StringBuffer>();
- long beforeTest = rt.freeMemory();
- while(rt.freeMemory() < beforeTest * 2/3) {
+ long beforeTest = rt.totalMemory() - rt.freeMemory();
+ while (rt.totalMemory() - rt.freeMemory() < beforeTest * 2) {
vec.add(new StringBuffer(1000));
}
long beforeGC = rt.totalMemory() - rt.freeMemory();
diff --git a/luni/src/test/java/libcore/java/lang/PackageTest.java b/luni/src/test/java/libcore/java/lang/PackageTest.java
index c004e23..269831f 100644
--- a/luni/src/test/java/libcore/java/lang/PackageTest.java
+++ b/luni/src/test/java/libcore/java/lang/PackageTest.java
@@ -37,6 +37,12 @@
assertEquals(getClass().getPackage(), libcoreJavaLang);
}
+ // http://b/28057303
+ public void test_toString() throws Exception {
+ Package libcoreJavaLang = Package.getPackage("libcore.java.lang");
+ assertEquals("package libcore.java.lang", libcoreJavaLang.toString());
+ }
+
// http://b/5171136
public void testGetPackages() {
assertTrue(packages.contains(getClass().getPackage()));
diff --git a/luni/src/test/java/libcore/java/lang/StrictMathTest.java b/luni/src/test/java/libcore/java/lang/StrictMathTest.java
new file mode 100644
index 0000000..2509af8
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/StrictMathTest.java
@@ -0,0 +1,231 @@
+/*
+ * 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.lang;
+
+import junit.framework.TestCase;
+
+import java.math.BigInteger;
+
+public class StrictMathTest extends TestCase {
+
+ public void testIntExact() {
+ testIntExact(123, 456);
+ testIntExact(-456, 456);
+ testIntExact(0, 0);
+ testIntExact(Integer.MAX_VALUE, 1);
+ testIntExact(Integer.MAX_VALUE, -1);
+ testIntExact(Integer.MIN_VALUE, 1);
+ testIntExact(Integer.MIN_VALUE, -1);
+ testIntExact(Integer.MAX_VALUE, Integer.MAX_VALUE);
+ testIntExact(Integer.MIN_VALUE, Integer.MIN_VALUE);
+ }
+
+ private void testIntExact(int a, int b) {
+ testAddExactI(a, b);
+ testSubtractExactI(a, b);
+ testMultiplyExactI(a, b);
+ }
+
+ private void testAddExactI(int a, int b) {
+ long expected = (long) a + (long) b;
+ try {
+ assertEquals(expected, StrictMath.addExact(a, b));
+ } catch (ArithmeticException e) {
+ if (expected == a + b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testSubtractExactI(int a, int b) {
+ long expected = (long) a - (long) b;
+ try {
+ assertEquals(expected, StrictMath.subtractExact(a, b));
+ } catch (ArithmeticException e) {
+ long result = (long) a - (long) b;
+ if (expected == a - b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testMultiplyExactI(int a, int b) {
+ long expected = (long) a * (long) b;
+ try {
+ assertEquals(expected, StrictMath.multiplyExact(a, b));
+ } catch (ArithmeticException e) {
+ if (expected == a * b) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ public void testLongExact() {
+ testLongExact(123, 456);
+ testLongExact(-456, 456);
+ testLongExact(0, 0);
+ testLongExact(Long.MAX_VALUE, 1);
+ testLongExact(Long.MAX_VALUE, -1);
+ testLongExact(Long.MIN_VALUE, 1);
+ testLongExact(Long.MIN_VALUE, -1);
+ testLongExact(Long.MAX_VALUE, Long.MAX_VALUE);
+ testLongExact(Long.MIN_VALUE, Long.MIN_VALUE);
+ }
+
+ private void testLongExact(long a, long b) {
+ testAddExactL(a, b);
+ testSubtractExactL(a, b);
+ testMultiplyExactL(a, b);
+ testToIntExactL(a);
+ }
+
+ private void testAddExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).add(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(StrictMath.addExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a + b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testSubtractExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).subtract(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(StrictMath.subtractExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a - b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testMultiplyExactL(long a, long b) {
+ BigInteger expected = BigInteger.valueOf(a).multiply(BigInteger.valueOf(b));
+ try {
+ assertEquals(expected, BigInteger.valueOf(StrictMath.multiplyExact(a, b)));
+ } catch (ArithmeticException e) {
+ if (expected.equals(BigInteger.valueOf(a * b))) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ private void testToIntExactL(long a) {
+ try {
+ assertEquals((int) a, StrictMath.toIntExact(a));
+ assertEquals(a, StrictMath.toIntExact(a)); // Is not exact, should throw AE.
+ } catch (ArithmeticException e) {
+ if (a <= Integer.MAX_VALUE && a >= Integer.MIN_VALUE) {
+ fail(); // This is not an overflow
+ }
+ }
+ }
+
+ public void testIntFloorDivMod() {
+ testFloorDivModI(123, 456);
+ testFloorDivModI(456, 123);
+ testFloorDivModI(369, 123);
+ testFloorDivModI(1, 0);
+ testFloorDivModI(Integer.MAX_VALUE, 1);
+ testFloorDivModI(Integer.MAX_VALUE, -1);
+ testFloorDivModI(Integer.MIN_VALUE, 1);
+ testFloorDivModI(Integer.MIN_VALUE, -1);
+ }
+
+ private void testFloorDivModI(int a, int b) {
+ testFloorDivI(a, b);
+ testFloorModI(a, b);
+ }
+
+ private void testFloorDivI(int a, int b) {
+ try {
+ int floorDiv = StrictMath.floorDiv(a, b);
+ int expected = a / b;
+ if (expected < 0 && a % b != 0) {
+ --expected;
+ }
+ assertEquals(expected, floorDiv);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ private void testFloorModI(int a, int b) {
+ try {
+ int floorMod = StrictMath.floorMod(a, b);
+ int expected = a % b;
+ if ((a ^ b) < 0 && expected != 0) {
+ expected = b - expected;
+ }
+ assertEquals(expected, floorMod);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ public void testLongFloorDivMod() {
+ testFloorDivModL(123L, 456L);
+ testFloorDivModL(456L, 123L);
+ testFloorDivModL(369L, 123L);
+ testFloorDivModL(1L, 0L);
+ testFloorDivModL(Long.MAX_VALUE, 1L);
+ testFloorDivModL(Long.MAX_VALUE, -1L);
+ testFloorDivModL(Long.MIN_VALUE, 1L);
+ testFloorDivModL(Long.MIN_VALUE, -1L);
+ }
+
+ private void testFloorDivModL(long a, long b) {
+ testFloorDivL(a, b);
+ testFloorModL(a, b);
+ }
+
+ private void testFloorDivL(long a, long b) {
+ try {
+ long floorDiv = StrictMath.floorDiv(a, b);
+ long expected = a / b;
+ if (expected < 0 && a % b != 0) {
+ --expected;
+ }
+ assertEquals(expected, floorDiv);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+
+ private void testFloorModL(long a, long b) {
+ try {
+ long floorMod = StrictMath.floorMod(a, b);
+ long expected = a % b;
+ if ((a ^ b) < 0 && expected != 0) {
+ expected = b - expected;
+ }
+ assertEquals(expected, floorMod);
+ } catch (ArithmeticException e) {
+ if (b != 0) {
+ fail(); // Should only throw AE when b is zero.
+ }
+ }
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/StringBufferTest.java b/luni/src/test/java/libcore/java/lang/StringBufferTest.java
new file mode 100644
index 0000000..402bc36
--- /dev/null
+++ b/luni/src/test/java/libcore/java/lang/StringBufferTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.lang;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+
+public class StringBufferTest extends TestCase {
+
+ public void testChars() {
+ StringBuffer s = new StringBuffer("Hello\n\tworld");
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.chars().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ StringBuffer surrogateCP = new StringBuffer().append(new char[]{high, low, low});
+ assertTrue(Arrays.equals(new int[]{high, low, low}, surrogateCP.chars().toArray()));
+ }
+
+ public void testCodePoints() {
+ StringBuffer s = new StringBuffer("Hello\n\tworld");
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.codePoints().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ StringBuffer surrogateCP = new StringBuffer().append(new char[]{high, low, low, '0'});
+ assertEquals(Character.toCodePoint(high, low), surrogateCP.codePoints().toArray()[0]);
+ assertEquals((int) low, surrogateCP.codePoints().toArray()[1]); // Unmatched surrogate.
+ assertEquals((int) '0', surrogateCP.codePoints().toArray()[2]);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/lang/StringBuilderTest.java b/luni/src/test/java/libcore/java/lang/StringBuilderTest.java
index 1f9abbf..20d2974 100644
--- a/luni/src/test/java/libcore/java/lang/StringBuilderTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringBuilderTest.java
@@ -16,6 +16,8 @@
package libcore.java.lang;
+import java.util.Arrays;
+
public class StringBuilderTest extends junit.framework.TestCase {
// See https://code.google.com/p/android/issues/detail?id=60639
public void test_deleteChatAt_lastRange() {
@@ -129,4 +131,34 @@
sb.delete(sb.length() - 1, sb.length());
assertEquals("mogw", sb.toString());
}
+
+ public void testChars() {
+ StringBuilder s = new StringBuilder("Hello\n\tworld");
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.chars().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ StringBuilder surrogateCP = new StringBuilder().append(new char[]{high, low, low});
+ assertTrue(Arrays.equals(new int[]{high, low, low}, surrogateCP.chars().toArray()));
+ }
+
+ public void testCodePoints() {
+ StringBuilder s = new StringBuilder("Hello\n\tworld");
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.codePoints().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ StringBuilder surrogateCP = new StringBuilder().append(new char[]{high, low, low, '0'});
+ assertEquals(Character.toCodePoint(high, low), surrogateCP.codePoints().toArray()[0]);
+ assertEquals((int) low, surrogateCP.codePoints().toArray()[1]); // Unmatched surrogate.
+ assertEquals((int) '0', surrogateCP.codePoints().toArray()[2]);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/StringTest.java b/luni/src/test/java/libcore/java/lang/StringTest.java
index 63f991e..60c3467 100644
--- a/luni/src/test/java/libcore/java/lang/StringTest.java
+++ b/luni/src/test/java/libcore/java/lang/StringTest.java
@@ -16,8 +16,6 @@
package libcore.java.lang;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.ReadOnlyBufferException;
@@ -317,6 +315,24 @@
assertEquals("-h-e-l-l-o- -w-o-r-l-d-", "hello world".replace("", "-"));
assertEquals("-w-o-r-l-d-", "hello world".substring(6).replace("", "-"));
assertEquals("-*-w-*-o-*-r-*-l-*-d-*-", "hello world".substring(6).replace("", "-*-"));
+
+ // Replace on an empty string with an empty target should insert the pattern
+ // precisely once.
+ assertEquals("", "".replace("", ""));
+ assertEquals("food", "".replace("", "food"));
+ }
+
+ public void test_replace() {
+ // Replace on an empty string is a no-op.
+ assertEquals("", "".replace("foo", "bar"));
+ // Replace on a string which doesn't contain the target sequence is a no-op.
+ assertEquals("baz", "baz".replace("foo", "bar"));
+ // Test that we iterate forward on the string.
+ assertEquals("mmmba", "bababa".replace("baba", "mmm"));
+ // Test replacements at the end of the string.
+ assertEquals("foodie", "foolish".replace("lish", "die"));
+ // Test a string that has multiple replacements.
+ assertEquals("hahahaha", "kkkk".replace("k", "ha"));
}
public void test_String_getBytes() throws Exception {
@@ -437,4 +453,34 @@
} catch (StringIndexOutOfBoundsException expected) {
}
}
+
+ public void testChars() {
+ String s = "Hello\n\tworld";
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.chars().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ String surrogateCP = new String(new char[]{high, low, low});
+ assertTrue(Arrays.equals(new int[]{high, low, low}, surrogateCP.chars().toArray()));
+ }
+
+ public void testCodePoints() {
+ String s = "Hello\n\tworld";
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, s.codePoints().toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ String surrogateCP = new String(new char[]{high, low, low, '0'});
+ assertEquals(Character.toCodePoint(high, low), surrogateCP.codePoints().toArray()[0]);
+ assertEquals((int) low, surrogateCP.codePoints().toArray()[1]); // Unmatched surrogate.
+ assertEquals((int) '0', surrogateCP.codePoints().toArray()[2]);
+ }
}
diff --git a/luni/src/test/java/libcore/java/lang/ThreadTest.java b/luni/src/test/java/libcore/java/lang/ThreadTest.java
index 8545a20..10ca9a7 100644
--- a/luni/src/test/java/libcore/java/lang/ThreadTest.java
+++ b/luni/src/test/java/libcore/java/lang/ThreadTest.java
@@ -22,6 +22,9 @@
import libcore.java.lang.ref.FinalizationTester;
public final class ThreadTest extends TestCase {
+ static {
+ System.loadLibrary("javacoretests");
+ }
/**
* getContextClassLoader returned a non-application class loader.
@@ -167,6 +170,19 @@
assertTrue("Must have traces for all threads", visibleTraces.get() > 1);
}
+ // http://b/27748318
+ public void testNativeThreadNames() throws Exception {
+ String testResult = nativeTestNativeThreadNames();
+ // Not using assertNull here because this results in a better error message.
+ if (testResult != null) {
+ fail(testResult);
+ }
+ }
+
+ // This method returns {@code null} if all tests pass, or a non-null String containing
+ // failure details if an error occured.
+ private static native String nativeTestNativeThreadNames();
+
private Thread newThread(final AtomicInteger finalizedThreadsCount, final int size) {
return new Thread() {
long[] memoryPressure = new long[size];
diff --git a/luni/src/test/java/libcore/java/lang/reflect/AnnotationsTest.java b/luni/src/test/java/libcore/java/lang/reflect/AnnotationsTest.java
index a37806f..c9cd3d1 100644
--- a/luni/src/test/java/libcore/java/lang/reflect/AnnotationsTest.java
+++ b/luni/src/test/java/libcore/java/lang/reflect/AnnotationsTest.java
@@ -298,6 +298,12 @@
assertDeclared(true, aPackage, RepeatableAnnotations.class);
}
+ public void testRetentionPolicy() {
+ assertNull(RetentionAnnotations.class.getAnnotation(ClassRetentionAnnotation.class));
+ assertNotNull(RetentionAnnotations.class.getAnnotation(RuntimeRetentionAnnotation.class));
+ assertNull(RetentionAnnotations.class.getAnnotation(SourceRetentionAnnotation.class));
+ }
+
private static final Object staticAnonymous = new Object() {};
private static class Foo {
@@ -340,6 +346,15 @@
RepeatableAnnotation[] value();
}
+ @Retention(RetentionPolicy.CLASS)
+ public @interface ClassRetentionAnnotation {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ public @interface RuntimeRetentionAnnotation {}
+
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SourceRetentionAnnotation {}
+
@AnnotationA @AnnotationB @RepeatableAnnotation
public static class Type {
@AnnotationA @AnnotationC public Type() {}
@@ -358,6 +373,9 @@
@RepeatableAnnotations({ @RepeatableAnnotation, @RepeatableAnnotation})
public static class TypeWithExplicitRepeatableAnnotations {}
+ @ClassRetentionAnnotation @RuntimeRetentionAnnotation @SourceRetentionAnnotation
+ public static class RetentionAnnotations {}
+
static enum Breakfast { WAFFLES, PANCAKES }
@Retention(RetentionPolicy.RUNTIME)
diff --git a/luni/src/test/java/libcore/java/math/BigDecimalTest.java b/luni/src/test/java/libcore/java/math/BigDecimalTest.java
index cdfab6c..e2dae32 100644
--- a/luni/src/test/java/libcore/java/math/BigDecimalTest.java
+++ b/luni/src/test/java/libcore/java/math/BigDecimalTest.java
@@ -17,8 +17,11 @@
package libcore.java.math;
import java.math.BigDecimal;
+import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;
+import java.util.Locale;
+
import junit.framework.TestCase;
public final class BigDecimalTest extends TestCase {
@@ -67,26 +70,36 @@
// https://code.google.com/p/android/issues/detail?id=43480
public void testPrecisionFromString() {
- BigDecimal a = new BigDecimal("-0.011111111111111111111");
- BigDecimal b = a.multiply(BigDecimal.ONE);
+ BigDecimal a = new BigDecimal("-0.011111111111111111111");
+ BigDecimal b = a.multiply(BigDecimal.ONE);
- assertEquals("-0.011111111111111111111", a.toString());
- assertEquals("-0.011111111111111111111", b.toString());
+ assertEquals("-0.011111111111111111111", a.toString());
+ assertEquals("-0.011111111111111111111", b.toString());
- assertEquals(20, a.precision());
- assertEquals(20, b.precision());
+ assertEquals(20, a.precision());
+ assertEquals(20, b.precision());
- assertEquals(21, a.scale());
- assertEquals(21, b.scale());
+ assertEquals(21, a.scale());
+ assertEquals(21, b.scale());
- assertEquals("-11111111111111111111", a.unscaledValue().toString());
- assertEquals("-11111111111111111111", b.unscaledValue().toString());
+ assertEquals("-11111111111111111111", a.unscaledValue().toString());
+ assertEquals("-11111111111111111111", b.unscaledValue().toString());
- assertEquals(a, b);
- assertEquals(b, a);
+ assertEquals(a, b);
+ assertEquals(b, a);
- assertEquals(0, a.subtract(b).signum());
- assertEquals(0, a.compareTo(b));
+ assertEquals(0, a.subtract(b).signum());
+ assertEquals(0, a.compareTo(b));
+ }
+
+ public void testPrecisionFromString_simplePowersOfTen() {
+ assertEquals(new BigDecimal(BigInteger.valueOf(-10), 1), new BigDecimal("-1.0"));
+ assertEquals(new BigDecimal(BigInteger.valueOf(-1), 1), new BigDecimal("-0.1"));
+ assertEquals(new BigDecimal(BigInteger.valueOf(-1), -1), new BigDecimal("-1E+1"));
+
+ assertEquals(new BigDecimal(BigInteger.valueOf(10), 1), new BigDecimal("1.0"));
+ assertEquals(new BigDecimal(BigInteger.valueOf(1), 0), new BigDecimal("1"));
+ assertFalse(new BigDecimal("1.0").equals(new BigDecimal("1")));
}
// https://code.google.com/p/android/issues/detail?id=54580
@@ -108,4 +121,81 @@
assertFalse(zero.equals(other));
assertFalse(other.equals(zero));
}
+
+ private static void checkDivide(String expected, long n, long d, int scale, RoundingMode rm) {
+ assertEquals(String.format(Locale.US, "%d/%d [%d, %s]", n, d, scale, rm.name()),
+ new BigDecimal(expected),
+ new BigDecimal(n).divide(new BigDecimal(d), scale, rm));
+ }
+
+ public void testDivideRounding() {
+ checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.DOWN);
+ checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.UP);
+ checkDivide("-1", 1, Long.MIN_VALUE, 0, RoundingMode.FLOOR);
+ checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.CEILING);
+ checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_EVEN);
+ checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
+ checkDivide("0", 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
+
+ checkDivide("1", Long.MAX_VALUE, Long.MAX_VALUE / 2 + 1, 0, RoundingMode.DOWN);
+ checkDivide("2", Long.MAX_VALUE, Long.MAX_VALUE / 2, 0, RoundingMode.DOWN);
+ checkDivide("0.50", Long.MAX_VALUE / 2, Long.MAX_VALUE, 2, RoundingMode.HALF_UP);
+ checkDivide("0.50", Long.MIN_VALUE / 2, Long.MIN_VALUE, 2, RoundingMode.HALF_UP);
+ checkDivide("0.5000", Long.MIN_VALUE / 2, Long.MIN_VALUE, 4, RoundingMode.HALF_UP);
+ // (-2^62 + 1) / (-2^63) = (2^62 - 1) / 2^63 = 0.5 - 2^-63
+ checkDivide("0", Long.MIN_VALUE / 2 + 1, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
+ checkDivide("1", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_UP);
+ checkDivide("0", Long.MIN_VALUE / 2, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
+ // (-2^62 - 1) / (-2^63) = (2^62 + 1) / 2^63 = 0.5 + 2^-63
+ checkDivide("1", Long.MIN_VALUE / 2 - 1, Long.MIN_VALUE, 0, RoundingMode.HALF_DOWN);
+ }
+
+ /**
+ * Tests that Long.MIN_VALUE / -1 doesn't overflow back to Long.MIN_VALUE,
+ * like it would in long arithmetic.
+ */
+ // https://code.google.com/p/android/issues/detail?id=196555
+ public void testDivideAvoids64bitOverflow() throws Exception {
+ BigDecimal minLong = new BigDecimal("-9223372036854775808");
+ assertEquals("9223372036854775808/(-1)",
+ new BigDecimal("9223372036854775808"),
+ minLong.divide(new BigDecimal("-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
+
+ assertEquals("922337203685477580.8/(-0.1)",
+ new BigDecimal("9223372036854775808"),
+ new BigDecimal("-922337203685477580.8")
+ .divide(new BigDecimal("-0.1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
+
+ assertEquals("92233720368547758080/(-1E+1)",
+ new BigDecimal("9223372036854775808"),
+ new BigDecimal("-92233720368547758080")
+ .divide(new BigDecimal("-1E+1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
+
+ assertEquals("9223372036854775808/(-10) with one decimal of precision",
+ new BigDecimal("922337203685477580.8"),
+ minLong.divide(new BigDecimal("-1E+1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
+
+ // cases that request adjustment of the result scale, i.e. (diffScale != 0)
+ // i.e. result scale != (numerator.scale - divisor.scale)
+ assertEquals("9223372036854775808/(-1) with one decimal of precision",//
+ new BigDecimal("9223372036854775808.0"),
+ minLong.divide(new BigDecimal("-1"), /* scale = */ 1, RoundingMode.UNNECESSARY));
+
+ assertEquals("9223372036854775808/(-1.0)",//
+ new BigDecimal("9223372036854775808"),
+ minLong.divide(new BigDecimal("-1.0"), /* scale = */ 0, RoundingMode.UNNECESSARY));
+
+ assertEquals("9223372036854775808/(-1.0) with one decimal of precision",//
+ new BigDecimal("9223372036854775808.0"),
+ minLong.divide(new BigDecimal("-1.0"), /* scale = */ 1, RoundingMode.UNNECESSARY));
+
+ // another arbitrary calculation that results in Long.MAX_VALUE + 1
+ // via a different route
+ assertEquals("4611686018427387904/(-5E-1)",//
+ new BigDecimal("9223372036854775808"),
+ new BigDecimal("-4611686018427387904").divide(
+ new BigDecimal("-5E-1"), /* scale = */ 0, RoundingMode.UNNECESSARY));
+
+ }
+
}
diff --git a/luni/src/test/java/libcore/java/math/BigIntegerTest.java b/luni/src/test/java/libcore/java/math/BigIntegerTest.java
index 58c68a1..80041c2 100644
--- a/luni/src/test/java/libcore/java/math/BigIntegerTest.java
+++ b/luni/src/test/java/libcore/java/math/BigIntegerTest.java
@@ -184,4 +184,15 @@
assertEquals(trimmed, extraZeroes);
}
+
+ /**
+ * Tests that Long.MIN_VALUE / -1 doesn't overflow back to Long.MIN_VALUE,
+ * like it would in long arithmetic.
+ */
+ public void test_divide_avoids64bitOverflow() throws Exception {
+ BigInteger negV = BigInteger.valueOf(Long.MIN_VALUE);
+ BigInteger posV = negV.divide(BigInteger.valueOf(-1));
+ assertEquals("-9223372036854775808", negV.toString());
+ assertEquals( "9223372036854775808", posV.toString());
+ }
}
diff --git a/luni/src/test/java/libcore/java/net/OldServerSocketTest.java b/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
index 6518897..8588144 100644
--- a/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldServerSocketTest.java
@@ -238,11 +238,11 @@
public void test_getSoTimeout_setSoTimeout() throws Exception {
// TODO: a useful test would check that setSoTimeout actually causes timeouts!
ServerSocket s = new ServerSocket();
- s.setSoTimeout(1500);
- int ms = s.getSoTimeout();
- if (ms < 1500-10 || ms > 1500+10) {
- fail("suspicious timeout: " + ms);
- }
+ final int timeoutSet = 1500;
+ s.setSoTimeout(timeoutSet);
+ int actualTimeout = s.getSoTimeout();
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue("suspicious timeout: " + actualTimeout, Math.abs(actualTimeout - timeoutSet) <= 10);
s.close();
try {
s.getSoTimeout();
diff --git a/luni/src/test/java/libcore/java/net/OldSocketTest.java b/luni/src/test/java/libcore/java/net/OldSocketTest.java
index ded5802..4254516 100644
--- a/luni/src/test/java/libcore/java/net/OldSocketTest.java
+++ b/luni/src/test/java/libcore/java/net/OldSocketTest.java
@@ -389,9 +389,7 @@
Socket s = new Socket();
s.setSoTimeout(1500);
int ms = s.getSoTimeout();
- if (ms < 1500-10 || ms > 1500+10) {
- fail("suspicious timeout: " + ms);
- }
+ assertTrue("suspicious timeout: " + ms, Math.abs(ms - 1500) <= 10);
s.close();
try {
s.getSoTimeout();
@@ -1384,10 +1382,10 @@
connector.start();
theSocket.setSoTimeout(1000);
Thread.sleep(10);
- assertEquals("Socket option not set during connect: 10 ", 1000, theSocket.getSoTimeout());
+ assertTrue("Socket option not set during connect: 10 ", Math.abs(1000 - theSocket.getSoTimeout()) <= 10);
Thread.sleep(50);
theSocket.setSoTimeout(2000);
- assertEquals("Socket option not set during connect: 50 ", 2000, theSocket.getSoTimeout());
+ assertTrue("Socket option not set during connect: 50 ", Math.abs(2000 - theSocket.getSoTimeout()) <= 10);
Thread.sleep(5000);
theSocket.close();
diff --git a/luni/src/test/java/libcore/java/net/URLConnectionTest.java b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
index 383461e..468787f 100644
--- a/luni/src/test/java/libcore/java/net/URLConnectionTest.java
+++ b/luni/src/test/java/libcore/java/net/URLConnectionTest.java
@@ -1929,8 +1929,8 @@
assertEquals(Arrays.asList("verify " + hostName), hostnameVerifier.calls);
assertEquals(Arrays.asList("checkServerTrusted ["
- + "CN=" + hostName + " 1, "
- + "CN=Test Intermediate Certificate Authority 1, "
+ + "CN=" + hostName + " 3, "
+ + "CN=Test Intermediate Certificate Authority 2, "
+ "CN=Test Root Certificate Authority 1"
+ "] ECDHE_RSA"),
trustManager.calls);
diff --git a/luni/src/test/java/libcore/java/nio/CharBufferTest.java b/luni/src/test/java/libcore/java/nio/CharBufferTest.java
new file mode 100644
index 0000000..26e5778
--- /dev/null
+++ b/luni/src/test/java/libcore/java/nio/CharBufferTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.nio;
+
+import junit.framework.TestCase;
+
+import java.nio.CharBuffer;
+import java.util.Arrays;
+
+public class CharBufferTest extends TestCase {
+
+ public void testChars() {
+ char highSurrogate = '\uD83D', lowSurrogate = '\uDE02';
+ String s = "Hello\n\tworld" + highSurrogate + lowSurrogate;
+ CharBuffer cb = CharBuffer.allocate(32).append(s);
+ cb.rewind();
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);
+ }
+ assertTrue(Arrays.equals(expected, cb.chars().limit(s.length()).toArray()));
+ }
+
+ public void testCodePoints() {
+ String s = "Hello\n\tworld";
+ CharBuffer cb = CharBuffer.allocate(32).append(s);
+ cb.rewind();
+ int[] expected = new int[s.length()];
+ for (int i = 0; i < s.length(); ++i) {
+ expected[i] = (int) s.charAt(i);}
+ assertTrue(Arrays.equals(expected, cb.codePoints().limit(s.length()).toArray()));
+
+ // Surrogate code point
+ char high = '\uD83D', low = '\uDE02';
+ String surrogateCP = new String(new char[]{high, low, low, '0'});
+ cb = CharBuffer.allocate(32).append(surrogateCP);
+ cb.rewind();
+ assertEquals(Character.toCodePoint(high, low), cb.codePoints().toArray()[0]);
+ assertEquals((int) low, cb.codePoints().toArray()[1]); // Unmatched surrogate.
+ assertEquals((int) '0', cb.codePoints().toArray()[2]);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
index 609a990..f3bd7ff 100644
--- a/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/DatagramChannelTest.java
@@ -17,20 +17,23 @@
package libcore.java.nio.channels;
import java.io.IOException;
+import java.net.BindException;
import java.net.DatagramSocket;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
+import java.net.ProtocolFamily;
+import java.net.StandardProtocolFamily;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.nio.channels.spi.SelectorProvider;
import java.util.Enumeration;
-import java.util.Set;
public class DatagramChannelTest extends junit.framework.TestCase {
public void test_read_intoReadOnlyByteArrays() throws Exception {
@@ -181,6 +184,75 @@
assertNotNull(socket.getFileDescriptor$());
}
+ public void test_bind() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ DatagramChannel channel = DatagramChannel.open();
+ channel.bind(socketAddress);
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress)(channel.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress)(channel.getLocalAddress())).getPort() > 0);
+
+ try {
+ channel.bind(socketAddress);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
+ ((InetSocketAddress)(channel.getLocalAddress())).getPort());
+ try {
+ DatagramChannel.open().bind(socketAddress);
+ fail();
+ } catch (BindException expected) {}
+
+ channel.close();
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ try {
+ channel.bind(socketAddress);
+ } catch (ClosedChannelException expected) {}
+ }
+
+ public void test_getRemoteAddress() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ DatagramChannel clientChannel = DatagramChannel.open();
+ DatagramChannel serverChannel = DatagramChannel.open();
+ serverChannel.bind(socketAddress);
+
+ assertNull(clientChannel.getRemoteAddress());
+
+ clientChannel.connect(serverChannel.getLocalAddress());
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress)(clientChannel.getRemoteAddress())).getAddress());
+ assertEquals(((InetSocketAddress)(serverChannel.getLocalAddress())).getPort(),
+ ((InetSocketAddress)(clientChannel.getRemoteAddress())).getPort());
+ }
+
+ public void test_open$java_net_ProtocolFamily() throws IOException {
+ DatagramChannel channel = DatagramChannel.open(StandardProtocolFamily.INET);
+
+ channel.bind(new InetSocketAddress(Inet4Address.LOOPBACK, 0));
+ assertEquals(SelectorProvider.provider(), channel.provider());
+
+ try {
+ // Should not support IPv6 Address
+ // InetSocketAddress(int) returns IPv6 ANY address
+ DatagramChannel.open(StandardProtocolFamily.INET).bind(new InetSocketAddress(0));
+ fail();
+ } catch (UnsupportedAddressTypeException expected) {}
+
+ DatagramChannel.open(StandardProtocolFamily.INET6).bind(new InetSocketAddress(0));
+
+ try {
+ DatagramChannel.open(MockProtocolFamily.MOCK);
+ fail();
+ } catch (UnsupportedOperationException expected) {}
+
+ try {
+ DatagramChannel.open(null);
+ fail();
+ } catch (NullPointerException expected) {}
+ }
+
private static InetAddress getNonLoopbackNetworkInterfaceAddress(boolean ipv4) throws IOException {
Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
while (networkInterfaces.hasMoreElements()) {
@@ -199,4 +271,8 @@
}
return null;
}
+
+ enum MockProtocolFamily implements ProtocolFamily {
+ MOCK,
+ }
}
diff --git a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
index 1178b70..113779d 100644
--- a/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/ServerSocketChannelTest.java
@@ -22,10 +22,13 @@
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.SocketException;
+import java.net.StandardSocketOptions;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.channels.UnresolvedAddressException;
+import java.nio.channels.UnsupportedAddressTypeException;
import java.util.Enumeration;
import java.util.Set;
@@ -136,6 +139,58 @@
ssc.close();
}
+ public void test_bind$SocketAddress() throws IOException {
+ ServerSocketChannel ssc = ServerSocketChannel.open();
+ ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
+ assertEquals(InetAddress.getLoopbackAddress(),
+ ((InetSocketAddress)(ssc.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress)(ssc.getLocalAddress())).getPort() > 0);
+
+ try {
+ ssc.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(),
+ ((InetSocketAddress)(ssc.getLocalAddress())).getPort()));
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ try {
+ ServerSocketChannel ssc1 = ServerSocketChannel.open();
+ ssc1.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
+ fail();
+ } catch (UnresolvedAddressException expected) {
+ }
+
+ ssc.close();
+ try {
+ ssc.bind(new InetSocketAddress("1.1.1.1.1.1.1", 0));
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_setOption() throws Exception {
+ ServerSocketChannel sc = ServerSocketChannel.open();
+ sc.setOption(StandardSocketOptions.SO_REUSEADDR, true);
+
+ // Assert that we can read back the option from the channel...
+ assertTrue(sc.getOption(StandardSocketOptions.SO_REUSEADDR));
+
+ sc.setOption(StandardSocketOptions.SO_REUSEADDR, false);
+
+ // Assert that we can read back the option from the channel...
+ assertEquals(false, (boolean)sc.getOption(StandardSocketOptions.SO_REUSEADDR));
+
+ sc.setOption(StandardSocketOptions.SO_RCVBUF, 1100);
+ assertTrue(1100 <= sc.getOption(StandardSocketOptions.SO_RCVBUF));
+
+ sc.close();
+ try {
+ sc.setOption(StandardSocketOptions.SO_RCVBUF, 2000);
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
private static boolean canConnect(InetSocketAddress address) {
try {
SocketChannel socketChannel = SocketChannel.open(address);
diff --git a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
index d31b222..72609ee 100644
--- a/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
+++ b/luni/src/test/java/libcore/java/nio/channels/SocketChannelTest.java
@@ -20,278 +20,378 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
+import java.net.BindException;
import java.net.ConnectException;
-import java.net.Socket;
-import java.net.SocketImpl;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketImpl;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
+import java.nio.channels.AlreadyBoundException;
import java.nio.channels.ClosedChannelException;
-import java.nio.channels.SocketChannel;
-import java.nio.channels.Selector;
+import java.nio.channels.NotYetConnectedException;
import java.nio.channels.SelectionKey;
-import java.nio.channels.UnresolvedAddressException;
-import java.util.Set;
-
-import static android.system.OsConstants.*;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
public class SocketChannelTest extends junit.framework.TestCase {
- public void test_read_intoReadOnlyByteArrays() throws Exception {
- ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
- ServerSocket ss = new ServerSocket(0);
- ss.setReuseAddress(true);
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- try {
- sc.read(readOnly);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- sc.read(new ByteBuffer[] { readOnly });
- fail();
- } catch (IllegalArgumentException expected) {
- }
- try {
- sc.read(new ByteBuffer[] { readOnly }, 0, 1);
- fail();
- } catch (IllegalArgumentException expected) {
- }
- }
-
- // https://code.google.com/p/android/issues/detail?id=56684
- public void test_56684() throws Exception {
- SocketChannel sc = SocketChannel.open();
- sc.configureBlocking(false);
-
- Selector selector = Selector.open();
- SelectionKey selectionKey = sc.register(selector, SelectionKey.OP_CONNECT);
-
- try {
- // This test originally mocked the connect syscall to return ENETUNREACH.
- // This is not easily doable in openJdk libcore, but a connect to broadcast
- // address (255.255.255.255) for a TCP connection produces ENETUNREACH
- // Kernel code that does it is at
- // http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.18#L182
- sc.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[] {
- (byte) 255, (byte) 255, (byte)255, (byte)255 }), 0));
- fail();
- } catch (ConnectException ex) {
+ public void test_read_intoReadOnlyByteArrays() throws Exception {
+ ByteBuffer readOnly = ByteBuffer.allocate(1).asReadOnlyBuffer();
+ ServerSocket ss = new ServerSocket(0);
+ ss.setReuseAddress(true);
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ try {
+ sc.read(readOnly);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ sc.read(new ByteBuffer[] { readOnly });
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ try {
+ sc.read(new ByteBuffer[] { readOnly }, 0, 1);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
}
- try {
- sc.finishConnect();
- fail();
- } catch (ClosedChannelException expected) {
- }
- }
+ // https://code.google.com/p/android/issues/detail?id=56684
+ public void test_56684() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ sc.configureBlocking(false);
- /** Checks that closing a Socket's output stream also closes the Socket and SocketChannel. */
- public void test_channelSocketOutputStreamClosureState() throws Exception {
- ServerSocket ss = new ServerSocket(0);
+ Selector selector = Selector.open();
+ SelectionKey selectionKey = sc.register(selector, SelectionKey.OP_CONNECT);
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- sc.configureBlocking(true);
+ try {
+ // This test originally mocked the connect syscall to return ENETUNREACH.
+ // This is not easily doable in openJdk libcore, but a connect to broadcast
+ // address (255.255.255.255) for a TCP connection produces ENETUNREACH
+ // Kernel code that does it is at
+ // http://lxr.free-electrons.com/source/net/ipv4/tcp_ipv4.c?v=3.18#L182
+ sc.connect(new InetSocketAddress(InetAddress.getByAddress(new byte[] {
+ (byte) 255, (byte) 255, (byte) 255, (byte) 255 }), 0));
+ fail();
+ } catch (ConnectException ex) {
+ }
- Socket scSocket = sc.socket();
- OutputStream os = scSocket.getOutputStream();
-
- assertTrue(sc.isOpen());
- assertFalse(scSocket.isClosed());
-
- os.close();
-
- assertFalse(sc.isOpen());
- assertTrue(scSocket.isClosed());
-
- ss.close();
- }
-
- /** Checks that closing a Socket's input stream also closes the Socket and SocketChannel. */
- public void test_channelSocketInputStreamClosureState() throws Exception {
- ServerSocket ss = new ServerSocket(0);
-
- SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
- sc.configureBlocking(true);
-
- Socket scSocket = sc.socket();
- InputStream is = scSocket.getInputStream();
-
- assertTrue(sc.isOpen());
- assertFalse(scSocket.isClosed());
-
- is.close();
-
- assertFalse(sc.isOpen());
- assertTrue(scSocket.isClosed());
-
- ss.close();
- }
-
- /** Checks the state of the SocketChannel and associated Socket after open() */
- public void test_open_initialState() throws Exception {
- SocketChannel sc = SocketChannel.open();
- try {
- assertNull(sc.socket().getLocalSocketAddress());
-
- Socket socket = sc.socket();
- assertFalse(socket.isBound());
- assertFalse(socket.isClosed());
- assertFalse(socket.isConnected());
- assertEquals(-1, socket.getLocalPort());
- assertTrue(socket.getLocalAddress().isAnyLocalAddress());
- assertNull(socket.getLocalSocketAddress());
- assertNull(socket.getInetAddress());
- assertEquals(0, socket.getPort());
- assertNull(socket.getRemoteSocketAddress());
- assertFalse(socket.getReuseAddress());
-
- assertSame(sc, socket.getChannel());
- } finally {
- sc.close();
- }
- }
-
- public void test_bind_unresolvedAddress() throws IOException {
- SocketChannel sc = SocketChannel.open();
- try {
- sc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
- fail();
- } catch (IOException expected) {
+ try {
+ sc.finishConnect();
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
}
- assertNull(sc.socket().getLocalSocketAddress());
- assertTrue(sc.isOpen());
- assertFalse(sc.isConnected());
+ /** Checks that closing a Socket's output stream also closes the Socket and SocketChannel. */
+ public void test_channelSocketOutputStreamClosureState() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- sc.close();
- }
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ sc.configureBlocking(true);
- /** Checks that the SocketChannel and associated Socket agree on the socket state. */
- public void test_bind_socketStateSync() throws IOException {
- SocketChannel sc = SocketChannel.open();
- assertNull(sc.socket().getLocalSocketAddress());
+ Socket scSocket = sc.socket();
+ OutputStream os = scSocket.getOutputStream();
- Socket socket = sc.socket();
- assertNull(socket.getLocalSocketAddress());
- assertFalse(socket.isBound());
+ assertTrue(sc.isOpen());
+ assertFalse(scSocket.isClosed());
- InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
- sc.socket().bind(bindAddr);
+ os.close();
- InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
- assertEquals(actualAddr, socket.getLocalSocketAddress());
- assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
- assertTrue(socket.isBound());
- assertFalse(socket.isConnected());
- assertFalse(socket.isClosed());
+ assertFalse(sc.isOpen());
+ assertTrue(scSocket.isClosed());
- sc.close();
+ ss.close();
+ }
- assertFalse(sc.isOpen());
- assertTrue(socket.isClosed());
- }
+ /** Checks that closing a Socket's input stream also closes the Socket and SocketChannel. */
+ public void test_channelSocketInputStreamClosureState() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- /**
- * Checks that the SocketChannel and associated Socket agree on the socket state, even if
- * the Socket object is requested/created after bind().
- */
- public void test_bind_socketObjectCreationAfterBind() throws IOException {
- SocketChannel sc = SocketChannel.open();
- assertNull(sc.socket().getLocalSocketAddress());
+ SocketChannel sc = SocketChannel.open(ss.getLocalSocketAddress());
+ sc.configureBlocking(true);
- InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
- sc.socket().bind(bindAddr);
+ Socket scSocket = sc.socket();
+ InputStream is = scSocket.getInputStream();
- // Socket object creation after bind().
- Socket socket = sc.socket();
- InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
- assertEquals(actualAddr, socket.getLocalSocketAddress());
- assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
- assertTrue(socket.isBound());
- assertFalse(socket.isConnected());
- assertFalse(socket.isClosed());
+ assertTrue(sc.isOpen());
+ assertFalse(scSocket.isClosed());
- sc.close();
+ is.close();
- assertFalse(sc.isOpen());
- assertTrue(socket.isClosed());
- }
+ assertFalse(sc.isOpen());
+ assertTrue(scSocket.isClosed());
- /**
- * Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
- */
- public void test_connect_blocking() throws Exception {
- ServerSocket ss = new ServerSocket(0);
+ ss.close();
+ }
- SocketChannel sc = SocketChannel.open();
- assertTrue(sc.isBlocking());
+ /** Checks the state of the SocketChannel and associated Socket after open() */
+ public void test_open_initialState() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ try {
+ assertNull(sc.socket().getLocalSocketAddress());
- assertTrue(sc.connect(ss.getLocalSocketAddress()));
+ Socket socket = sc.socket();
+ assertFalse(socket.isBound());
+ assertFalse(socket.isClosed());
+ assertFalse(socket.isConnected());
+ assertEquals(-1, socket.getLocalPort());
+ assertTrue(socket.getLocalAddress().isAnyLocalAddress());
+ assertNull(socket.getLocalSocketAddress());
+ assertNull(socket.getInetAddress());
+ assertEquals(0, socket.getPort());
+ assertNull(socket.getRemoteSocketAddress());
+ assertFalse(socket.getReuseAddress());
- assertTrue(sc.socket().isBound());
- assertTrue(sc.isConnected());
- assertTrue(sc.socket().isConnected());
- assertFalse(sc.socket().isClosed());
- assertTrue(sc.isBlocking());
+ assertSame(sc, socket.getChannel());
+ } finally {
+ sc.close();
+ }
+ }
- ss.close();
- sc.close();
- }
+ public void test_bind_unresolvedAddress() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ try {
+ sc.socket().bind(new InetSocketAddress("unresolvedname", 31415));
+ fail();
+ } catch (IOException expected) {
+ }
- /** Tests connect() and object state for a non-blocking SocketChannel. */
- public void test_connect_nonBlocking() throws Exception {
- ServerSocket ss = new ServerSocket(0);
-
- SocketChannel sc = SocketChannel.open();
- assertTrue(sc.isBlocking());
- sc.configureBlocking(false);
- assertFalse(sc.isBlocking());
-
- if (!sc.connect(ss.getLocalSocketAddress())) {
- do {
- assertTrue(sc.socket().isBound());
+ assertNull(sc.socket().getLocalSocketAddress());
+ assertTrue(sc.isOpen());
assertFalse(sc.isConnected());
- assertFalse(sc.socket().isConnected());
+
+ sc.close();
+ }
+
+ /** Checks that the SocketChannel and associated Socket agree on the socket state. */
+ public void test_bind_socketStateSync() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.socket().getLocalSocketAddress());
+
+ Socket socket = sc.socket();
+ assertNull(socket.getLocalSocketAddress());
+ assertFalse(socket.isBound());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.socket().bind(bindAddr);
+
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Checks that the SocketChannel and associated Socket agree on the socket state, even if
+ * the Socket object is requested/created after bind().
+ */
+ public void test_bind_socketObjectCreationAfterBind() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ assertNull(sc.socket().getLocalSocketAddress());
+
+ InetSocketAddress bindAddr = new InetSocketAddress("localhost", 0);
+ sc.socket().bind(bindAddr);
+
+ // Socket object creation after bind().
+ Socket socket = sc.socket();
+ InetSocketAddress actualAddr = (InetSocketAddress) sc.socket().getLocalSocketAddress();
+ assertEquals(actualAddr, socket.getLocalSocketAddress());
+ assertEquals(bindAddr.getHostName(), actualAddr.getHostName());
+ assertTrue(socket.isBound());
+ assertFalse(socket.isConnected());
+ assertFalse(socket.isClosed());
+
+ sc.close();
+
+ assertFalse(sc.isOpen());
+ assertTrue(socket.isClosed());
+ }
+
+ /**
+ * Tests connect() and object state for a blocking SocketChannel. Blocking mode is the default.
+ */
+ public void test_connect_blocking() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
+
+ SocketChannel sc = SocketChannel.open();
+ assertTrue(sc.isBlocking());
+
+ assertTrue(sc.connect(ss.getLocalSocketAddress()));
+
+ assertTrue(sc.socket().isBound());
+ assertTrue(sc.isConnected());
+ assertTrue(sc.socket().isConnected());
assertFalse(sc.socket().isClosed());
- } while (!sc.finishConnect());
+ assertTrue(sc.isBlocking());
+
+ ss.close();
+ sc.close();
}
- assertTrue(sc.socket().isBound());
- assertTrue(sc.isConnected());
- assertTrue(sc.socket().isConnected());
- assertFalse(sc.socket().isClosed());
- assertFalse(sc.isBlocking());
- ss.close();
- sc.close();
- }
+ /** Tests connect() and object state for a non-blocking SocketChannel. */
+ public void test_connect_nonBlocking() throws Exception {
+ ServerSocket ss = new ServerSocket(0);
- public void test_Socket_impl_notNull() throws Exception {
- SocketChannel sc = SocketChannel.open();
- Socket socket = sc.socket();
- Field f_impl = Socket.class.getDeclaredField("impl");
- f_impl.setAccessible(true);
- Object implFieldValue = f_impl.get(socket);
- assertNotNull(implFieldValue);
- assertTrue(implFieldValue instanceof SocketImpl);
- }
+ SocketChannel sc = SocketChannel.open();
+ assertTrue(sc.isBlocking());
+ sc.configureBlocking(false);
+ assertFalse(sc.isBlocking());
- public void test_setOption() throws Exception {
- SocketChannel sc = SocketChannel.open();
- sc.setOption(StandardSocketOptions.SO_LINGER, 1000);
+ if (!sc.connect(ss.getLocalSocketAddress())) {
+ do {
+ assertTrue(sc.socket().isBound());
+ assertFalse(sc.isConnected());
+ assertFalse(sc.socket().isConnected());
+ assertFalse(sc.socket().isClosed());
+ } while (!sc.finishConnect());
+ }
+ assertTrue(sc.socket().isBound());
+ assertTrue(sc.isConnected());
+ assertTrue(sc.socket().isConnected());
+ assertFalse(sc.socket().isClosed());
+ assertFalse(sc.isBlocking());
- // Assert that we can read back the option from the channel...
- assertEquals(1000, (int) sc.<Integer>getOption(StandardSocketOptions.SO_LINGER));
- // ... and its socket adaptor.
- assertEquals(1000, sc.socket().getSoLinger());
-
- sc.close();
- try {
- sc.setOption(StandardSocketOptions.SO_LINGER, 2000);
- fail();
- } catch (ClosedChannelException expected) {
+ ss.close();
+ sc.close();
}
- }
+
+ public void test_Socket_impl_notNull() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ Socket socket = sc.socket();
+ Field f_impl = Socket.class.getDeclaredField("impl");
+ f_impl.setAccessible(true);
+ Object implFieldValue = f_impl.get(socket);
+ assertNotNull(implFieldValue);
+ assertTrue(implFieldValue instanceof SocketImpl);
+ }
+
+ public void test_setOption() throws Exception {
+ SocketChannel sc = SocketChannel.open();
+ sc.setOption(StandardSocketOptions.SO_LINGER, 1000);
+
+ // Assert that we can read back the option from the channel...
+ assertEquals(1000, (int) sc.<Integer>getOption(StandardSocketOptions.SO_LINGER));
+ // ... and its socket adaptor.
+ assertEquals(1000, sc.socket().getSoLinger());
+
+ sc.close();
+ try {
+ sc.setOption(StandardSocketOptions.SO_LINGER, 2000);
+ fail();
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_bind() throws IOException {
+ InetSocketAddress socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ SocketChannel sc = SocketChannel.open();
+ sc.bind(socketAddress);
+ assertEquals(socketAddress.getAddress(),
+ ((InetSocketAddress) (sc.getLocalAddress())).getAddress());
+ assertTrue(((InetSocketAddress) (sc.getLocalAddress())).getPort() > 0);
+
+ try {
+ sc.bind(socketAddress);
+ fail();
+ } catch (AlreadyBoundException expected) {
+ }
+
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK,
+ ((InetSocketAddress) (sc.getLocalAddress())).getPort());
+ try {
+ SocketChannel.open().bind(socketAddress);
+ fail();
+ } catch (BindException expected) {
+ }
+
+ sc.close();
+ socketAddress = new InetSocketAddress(Inet4Address.LOOPBACK, 0);
+ try {
+ sc.bind(socketAddress);
+ } catch (ClosedChannelException expected) {
+ }
+ }
+
+ public void test_getRemoteAddress() throws IOException {
+ SocketChannel sc = SocketChannel.open();
+ ServerSocket ss = new ServerSocket(0);
+
+ assertNull(sc.getRemoteAddress());
+
+ sc.connect(ss.getLocalSocketAddress());
+ assertEquals(sc.getRemoteAddress(), ss.getLocalSocketAddress());
+ }
+
+ public void test_shutdownInput() throws IOException {
+ SocketChannel channel1 = SocketChannel.open();
+ ServerSocket server1 = new ServerSocket(0);
+ InetSocketAddress localAddr1 = new InetSocketAddress("127.0.0.1", server1.getLocalPort());
+
+ // initialize write content
+ byte[] writeContent = new byte[10];
+ for (int i = 0; i < writeContent.length; i++) {
+ writeContent[i] = (byte) i;
+ }
+
+ // establish connection
+ channel1.connect(localAddr1);
+ Socket acceptedSocket = server1.accept();
+ // use OutputStream.write to write bytes data.
+ OutputStream out = acceptedSocket.getOutputStream();
+ out.write(writeContent);
+ // use close to guarantee all data is sent
+ acceptedSocket.close();
+
+ channel1.configureBlocking(false);
+ ByteBuffer readContent = ByteBuffer.allocate(10 + 1);
+ channel1.shutdownInput();
+ assertEquals(-1, channel1.read(readContent));
+ }
+
+ public void test_shutdownOutput() throws IOException {
+ SocketChannel channel1 = SocketChannel.open();
+ ServerSocket server1 = new ServerSocket(0);
+ InetSocketAddress localAddr1 = new InetSocketAddress("127.0.0.1", server1.getLocalPort());
+
+ // initialize write content
+ ByteBuffer writeContent = ByteBuffer.allocate(10);
+ for (int i = 0; i < 10; i++) {
+ writeContent.put((byte) i);
+ }
+ writeContent.flip();
+
+ try {
+ channel1.shutdownOutput();
+ fail();
+ } catch (NotYetConnectedException expected) {}
+
+ // establish connection
+ channel1.connect(localAddr1);
+ channel1.shutdownOutput();
+
+ try {
+ channel1.write(writeContent);
+ fail();
+ } catch (ClosedChannelException expected) {}
+
+ channel1.close();
+
+ try {
+ channel1.shutdownOutput();
+ fail();
+ } catch(ClosedChannelException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java b/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java
new file mode 100644
index 0000000..0c0ad0c
--- /dev/null
+++ b/luni/src/test/java/libcore/java/security/cert/CertPathValidatorTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 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.security.cert;
+
+import java.security.KeyStore.PrivateKeyEntry;
+import java.security.PrivateKey;
+import java.security.cert.CertPath;
+import java.security.cert.CertPathValidator;
+import java.security.cert.CertPathValidatorException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.PKIXParameters;
+import java.security.cert.PKIXRevocationChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.X509Certificate;
+import java.security.cert.PKIXRevocationChecker.Option;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import com.android.org.bouncycastle.asn1.x509.CRLReason;
+import com.android.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.android.org.bouncycastle.cert.X509CertificateHolder;
+import com.android.org.bouncycastle.cert.jcajce.JcaX509CertificateHolder;
+import com.android.org.bouncycastle.cert.ocsp.BasicOCSPResp;
+import com.android.org.bouncycastle.cert.ocsp.BasicOCSPRespBuilder;
+import com.android.org.bouncycastle.cert.ocsp.CertificateID;
+import com.android.org.bouncycastle.cert.ocsp.CertificateStatus;
+import com.android.org.bouncycastle.cert.ocsp.OCSPResp;
+import com.android.org.bouncycastle.cert.ocsp.OCSPRespBuilder;
+import com.android.org.bouncycastle.cert.ocsp.RevokedStatus;
+import com.android.org.bouncycastle.operator.DigestCalculatorProvider;
+import com.android.org.bouncycastle.operator.bc.BcDigestCalculatorProvider;
+import com.android.org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
+import junit.framework.TestCase;
+import libcore.java.security.TestKeyStore;
+
+public class CertPathValidatorTest extends TestCase {
+ private OCSPResp generateOCSPResponse(X509Certificate serverCertJca, X509Certificate caCertJca,
+ PrivateKey caKey, CertificateStatus status) throws Exception {
+ X509CertificateHolder caCert = new JcaX509CertificateHolder(caCertJca);
+
+ DigestCalculatorProvider digCalcProv = new BcDigestCalculatorProvider();
+ BasicOCSPRespBuilder basicBuilder = new BasicOCSPRespBuilder(
+ SubjectPublicKeyInfo.getInstance(caCertJca.getPublicKey().getEncoded()),
+ digCalcProv.get(CertificateID.HASH_SHA1));
+
+ CertificateID certId = new CertificateID(digCalcProv.get(CertificateID.HASH_SHA1),
+ caCert, serverCertJca.getSerialNumber());
+
+ basicBuilder.addResponse(certId, status);
+
+ BasicOCSPResp resp = basicBuilder.build(
+ new JcaContentSignerBuilder("SHA1withRSA").build(caKey), null, new Date());
+
+ OCSPRespBuilder builder = new OCSPRespBuilder();
+ return builder.build(OCSPRespBuilder.SUCCESSFUL, resp);
+ }
+
+ private void runOCSPStapledTest(CertificateStatus certStatus, final boolean goodStatus)
+ throws Exception {
+ PrivateKeyEntry serverEntry = TestKeyStore.getServer().getPrivateKey("RSA", "RSA");
+ PrivateKeyEntry caEntry = TestKeyStore.getIntermediateCa().getPrivateKey("RSA", "RSA");
+ PrivateKeyEntry rootCaEntry = TestKeyStore.getRootCa().getPrivateKey("RSA", "RSA");
+
+ X509Certificate serverCert = (X509Certificate) serverEntry.getCertificate();
+ OCSPResp ocspResponse = generateOCSPResponse(serverCert,
+ (X509Certificate) caEntry.getCertificate(), caEntry.getPrivateKey(), certStatus);
+
+ PKIXParameters params = new PKIXParameters(Collections
+ .singleton(new TrustAnchor((X509Certificate) rootCaEntry.getCertificate(), null)));
+
+ // By default we shouldn't have a PKIXRevocationChecker already.
+ for (PKIXCertPathChecker checker : params.getCertPathCheckers()) {
+ assertFalse(checker instanceof PKIXRevocationChecker);
+ }
+
+ CertPathValidator cpv = CertPathValidator.getInstance("PKIX");
+
+ PKIXRevocationChecker revChecker = (PKIXRevocationChecker) cpv.getRevocationChecker();
+ revChecker.setOptions(Collections.singleton(Option.ONLY_END_ENTITY));
+ revChecker.setOcspResponses(
+ Collections.singletonMap(serverCert, ocspResponse.getEncoded()));
+
+ List<PKIXCertPathChecker> checkers = new ArrayList<>(params.getCertPathCheckers());
+ checkers.add(revChecker);
+ params.setCertPathCheckers(checkers);
+
+ ArrayList<X509Certificate> chain = new ArrayList<>();
+ chain.add(serverCert);
+ chain.add((X509Certificate) caEntry.getCertificate());
+
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ CertPath certPath = cf.generateCertPath(chain);
+
+ try {
+ cpv.validate(certPath, params);
+ assertTrue("should fail with failure OCSP status", goodStatus);
+ } catch (CertPathValidatorException maybeExpected) {
+ assertFalse("should not fail with good OCSP status", goodStatus);
+ }
+ }
+
+ public void test_OCSP_EndEntity_KeyCompromise_Failure() throws Exception {
+ runOCSPStapledTest(new RevokedStatus(new Date(), CRLReason.keyCompromise), false);
+ }
+
+ public void test_OCSP_EndEntity_Good_Success() throws Exception {
+ runOCSPStapledTest(CertificateStatus.GOOD, true);
+ }
+}
diff --git a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
index 0eae20a..2b8b566 100644
--- a/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/DecimalFormatTest.java
@@ -283,6 +283,13 @@
assertEquals(expected, numberFormat.format(2.01));
}
+ // http://b/27855939
+ public void testBug27855939() {
+ DecimalFormat df = new DecimalFormat("00");
+ assertEquals("01", df.format(BigDecimal.ONE));
+ assertEquals("00", df.format(BigDecimal.ZERO));
+ }
+
// Confirm the currency symbol used by a format is determined by the locale of the format
// not the current default Locale.
public void testSetCurrency_symbolOrigin() {
diff --git a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
index 2150b50..24c8817 100644
--- a/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
+++ b/luni/src/test/java/libcore/java/text/SimpleDateFormatTest.java
@@ -31,6 +31,22 @@
private static final TimeZone AMERICA_LOS_ANGELES = TimeZone.getTimeZone("America/Los_Angeles");
private static final TimeZone AUSTRALIA_LORD_HOWE = TimeZone.getTimeZone("Australia/Lord_Howe");
+ private Locale defaultLocale;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ defaultLocale = Locale.getDefault();
+ // Locale affects timezone names / abbreviations so can affect formatting and parsing.
+ Locale.setDefault(Locale.US);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ Locale.setDefault(defaultLocale);
+ super.tearDown();
+ }
+
// The RI fails this test.
public void test2DigitYearStartIsCloned() throws Exception {
// Test that get2DigitYearStart returns a clone.
diff --git a/luni/src/test/java/libcore/java/util/ArraysTest.java b/luni/src/test/java/libcore/java/util/ArraysTest.java
index e79cb0d..2c9d5c5 100644
--- a/luni/src/test/java/libcore/java/util/ArraysTest.java
+++ b/luni/src/test/java/libcore/java/util/ArraysTest.java
@@ -17,6 +17,7 @@
package libcore.java.util;
import java.util.Arrays;
+import java.util.Random;
public class ArraysTest extends junit.framework.TestCase {
@@ -235,4 +236,302 @@
} catch (NullPointerException expected) {
}
}
+
+ /**
+ * java.util.Array#parallelPrefix(int[], java.util.function.IntBinaryOperator)
+ */
+ public void test_parallelPrefix$I() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ int[] list = new int[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextInt() % 1000; // Prevent overflow
+ }
+
+ int[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = 0; i < seqResult.length - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, (x, y) -> x + y);
+ assertTrue(Arrays.equals(seqResult, list));
+
+ try {
+ Arrays.parallelPrefix(list, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((int[]) null, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(int[], int, int, java.util.function.IntBinaryOperator)
+ */
+ public void test_parallelPrefix$III() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ int[] list = new int[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextInt() % 1000; // Prevent overflow
+ }
+
+ int begin = 100, end = 500;
+ int[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = begin; i < end - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
+ assertTrue(Arrays.equals(seqResult, list));
+
+ try {
+ Arrays.parallelPrefix(list, begin, end, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((int[]) null, begin, end, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix(list, end, begin, (x, y) -> x + y);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(long[], java.util.function.LongBinaryOperator)
+ */
+ public void test_parallelPrefix$L() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ long[] list = new long[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextLong() % 1000000; // Prevent overflow
+ }
+
+ long[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = 0; i < seqResult.length - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, (x, y) -> x + y);
+ assertTrue(Arrays.equals(seqResult, list));
+
+ try {
+ Arrays.parallelPrefix(list, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((long[]) null, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(long[], int, int, java.util.function.LongBinaryOperator)
+ */
+ public void test_parallelPrefix$LII() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ long[] list = new long[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextLong() % 1000000; // Prevent overflow
+ }
+
+ int begin = 100, end = 500;
+ long[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = begin; i < end - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
+ assertTrue(Arrays.equals(seqResult, list));
+
+ try {
+ Arrays.parallelPrefix(list, begin, end, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((long[]) null, begin, end, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix(list, end, begin, (x, y) -> x + y);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(double[], java.util.function.DoubleBinaryOperator)
+ */
+ public void test_parallelPrefix$D() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ double[] list = new double[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextDouble() * 1000;
+ }
+
+ double[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = 0; i < seqResult.length - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, (x, y) -> x + y);
+
+ // Parallel double arithmetic contains error, reduce to integer for comparison.
+ int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
+ int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
+ assertTrue(Arrays.equals(seqResultInInt, listInInt));
+
+ try {
+ Arrays.parallelPrefix(list, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((double[]) null, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(double[], int, int, java.util.function.DoubleBinaryOperator)
+ */
+ public void test_parallelPrefix$DII() {
+ // Get an arbitrary array of ints.
+ Random rand = new Random(0);
+ double[] list = new double[1000];
+ for(int i = 0; i < list.length; ++i) {
+ list[i] = rand.nextDouble() * 1000;
+ }
+
+ int begin = 100, end = 500;
+ double[] seqResult = list.clone();
+
+ // Sequential solution
+ for(int i = begin; i < end - 1; ++i) {
+ seqResult[i + 1] += seqResult[i];
+ }
+
+ Arrays.parallelPrefix(list, begin, end, (x, y) -> x + y);
+
+ // Parallel double arithmetic contains error, reduce to integer for comparison.
+ int[] listInInt = Arrays.stream(list).mapToInt(x -> (int) x).toArray();
+ int[] seqResultInInt = Arrays.stream(seqResult).mapToInt(x -> (int) x).toArray();
+ assertTrue(Arrays.equals(seqResultInInt, listInInt));
+
+ try {
+ Arrays.parallelPrefix(list, begin, end, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((double[]) null, begin, end, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix(list, end, begin, (x, y) -> x + y);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(T[], java.util.function.BinaryOperator<T>)
+ */
+ public void test_parallelPrefix$T() {
+ String[] strings = new String[3];
+ strings[0] = "a";
+ strings[1] = "b";
+ strings[2] = "c";
+
+ Arrays.parallelPrefix(strings, (x, y) -> x + y);
+ assertEquals("a", strings[0]);
+ assertEquals("ab", strings[1]);
+ assertEquals("abc", strings[2]);
+
+ try {
+ Arrays.parallelPrefix(strings, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((String[]) null, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+ }
+
+ /**
+ * java.util.Array#parallelPrefix(T[], int, int, java.util.function.BinaryOperator<T>)
+ */
+ public void test_parallelPrefix$TII() {
+ String[] strings = new String[5];
+ strings[0] = "a";
+ strings[1] = "b";
+ strings[2] = "c";
+ strings[3] = "d";
+ strings[4] = "e";
+ int begin = 1, end = 4;
+
+ Arrays.parallelPrefix(strings, begin, end, (x, y) -> x + y);
+ assertEquals("a", strings[0]);
+ assertEquals("b", strings[1]);
+ assertEquals("bc", strings[2]);
+ assertEquals("bcd", strings[3]);
+ assertEquals("e", strings[4]);
+
+ try {
+ Arrays.parallelPrefix(strings, begin, end, null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix((String[]) null, begin, end, (x, y) -> x + y);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ try {
+ Arrays.parallelPrefix(strings, end, begin, (x, y) -> x + y);
+ fail();
+ } catch (IllegalArgumentException expected) {
+ }
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/BitSetTest.java b/luni/src/test/java/libcore/java/util/BitSetTest.java
index 4998a07..c4e8ad3 100644
--- a/luni/src/test/java/libcore/java/util/BitSetTest.java
+++ b/luni/src/test/java/libcore/java/util/BitSetTest.java
@@ -20,6 +20,7 @@
import java.nio.LongBuffer;
import java.util.Arrays;
import java.util.BitSet;
+import java.util.Random;
public class BitSetTest extends junit.framework.TestCase {
public void test_toString() throws Exception {
@@ -231,4 +232,17 @@
result.xor(big());
assertEquals("{10, 1000}", result.toString());
}
+
+ public void test_stream() {
+ final int size = 128;
+
+ // Generate an arbitrary array of bytes.
+ byte[] bytes = new byte[size];
+ new Random(0).nextBytes(bytes);
+
+ BitSet bs = BitSet.valueOf(bytes);
+
+ assertEquals(bs.cardinality(), bs.stream().count());
+ bs.stream().forEach(x -> assertTrue(bs.get(x)));
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/CalendarWeekOfMonthTest.java b/luni/src/test/java/libcore/java/util/CalendarWeekOfMonthTest.java
new file mode 100644
index 0000000..66cd0e8
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/CalendarWeekOfMonthTest.java
@@ -0,0 +1,235 @@
+/*
+ * 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 java.util.Arrays;
+import java.util.Calendar;
+import java.util.Collection;
+import java.util.GregorianCalendar;
+import java.util.Locale;
+import java.util.TimeZone;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Test that Calendar.get(WEEK_OF_MONTH) works as expected.
+ */
+@RunWith(Parameterized.class)
+public class CalendarWeekOfMonthTest {
+
+ private final long timeInMillis;
+
+ private final String date;
+
+ private final int firstDayOfWeek;
+
+ private final int minimalDaysInFirstWeek;
+
+ private final int expectedWeekOfMonth;
+
+ @Parameterized.Parameters
+ public static Collection<Object[]> data() {
+ return Arrays.asList(new Object[][] {
+ // MinimalDaysInFirstWeek = 4, FirstDayOfWeek MONDAY
+ { 1462107600000L, "01 May 2016", Calendar.MONDAY, 4, 0 },
+ { 1462194000000L, "02 May 2016", Calendar.MONDAY, 4, 1 },
+ { 1462798800000L, "09 May 2016", Calendar.MONDAY, 4, 2 },
+ { 1463403600000L, "16 May 2016", Calendar.MONDAY, 4, 3 },
+ { 1464008400000L, "23 May 2016", Calendar.MONDAY, 4, 4 },
+ { 1464613200000L, "30 May 2016", Calendar.MONDAY, 4, 5 },
+ { 1464786000000L, "01 Jun 2016", Calendar.MONDAY, 4, 1 },
+ { 1465218000000L, "06 Jun 2016", Calendar.MONDAY, 4, 2 },
+ { 1465822800000L, "13 Jun 2016", Calendar.MONDAY, 4, 3 },
+ { 1466427600000L, "20 Jun 2016", Calendar.MONDAY, 4, 4 },
+ { 1467032400000L, "27 Jun 2016", Calendar.MONDAY, 4, 5 },
+ { 1467378000000L, "01 Jul 2016", Calendar.MONDAY, 4, 0 },
+ { 1467637200000L, "04 Jul 2016", Calendar.MONDAY, 4, 1 },
+ { 1468242000000L, "11 Jul 2016", Calendar.MONDAY, 4, 2 },
+ { 1468846800000L, "18 Jul 2016", Calendar.MONDAY, 4, 3 },
+ { 1469451600000L, "25 Jul 2016", Calendar.MONDAY, 4, 4 },
+ { 1470056400000L, "01 Aug 2016", Calendar.MONDAY, 4, 1 },
+ { 1470661200000L, "08 Aug 2016", Calendar.MONDAY, 4, 2 },
+ { 1471266000000L, "15 Aug 2016", Calendar.MONDAY, 4, 3 },
+ { 1471870800000L, "22 Aug 2016", Calendar.MONDAY, 4, 4 },
+ { 1472475600000L, "29 Aug 2016", Calendar.MONDAY, 4, 5 },
+ { 1472734800000L, "01 Sep 2016", Calendar.MONDAY, 4, 1 },
+ { 1473080400000L, "05 Sep 2016", Calendar.MONDAY, 4, 2 },
+ { 1473685200000L, "12 Sep 2016", Calendar.MONDAY, 4, 3 },
+ { 1474290000000L, "19 Sep 2016", Calendar.MONDAY, 4, 4 },
+ { 1474894800000L, "26 Sep 2016", Calendar.MONDAY, 4, 5 },
+ { 1475326800000L, "01 Oct 2016", Calendar.MONDAY, 4, 0 },
+ { 1475499600000L, "03 Oct 2016", Calendar.MONDAY, 4, 1 },
+ { 1476104400000L, "10 Oct 2016", Calendar.MONDAY, 4, 2 },
+ { 1476709200000L, "17 Oct 2016", Calendar.MONDAY, 4, 3 },
+ { 1477314000000L, "24 Oct 2016", Calendar.MONDAY, 4, 4 },
+ { 1477918800000L, "31 Oct 2016", Calendar.MONDAY, 4, 5 },
+ { 1478005200000L, "01 Nov 2016", Calendar.MONDAY, 4, 1 },
+ { 1478523600000L, "07 Nov 2016", Calendar.MONDAY, 4, 2 },
+ { 1479128400000L, "14 Nov 2016", Calendar.MONDAY, 4, 3 },
+ { 1479733200000L, "21 Nov 2016", Calendar.MONDAY, 4, 4 },
+ { 1480338000000L, "28 Nov 2016", Calendar.MONDAY, 4, 5 },
+
+ // MinimalDaysInFirstWeek = 1, FirstDayOfWeek MONDAY
+ { 1462107600000L, "01 May 2016", Calendar.MONDAY, 1, 1 },
+ { 1462194000000L, "02 May 2016", Calendar.MONDAY, 1, 2 },
+ { 1462798800000L, "09 May 2016", Calendar.MONDAY, 1, 3 },
+ { 1463403600000L, "16 May 2016", Calendar.MONDAY, 1, 4 },
+ { 1464008400000L, "23 May 2016", Calendar.MONDAY, 1, 5 },
+ { 1464613200000L, "30 May 2016", Calendar.MONDAY, 1, 6 },
+ { 1464786000000L, "01 Jun 2016", Calendar.MONDAY, 1, 1 },
+ { 1465218000000L, "06 Jun 2016", Calendar.MONDAY, 1, 2 },
+ { 1465822800000L, "13 Jun 2016", Calendar.MONDAY, 1, 3 },
+ { 1466427600000L, "20 Jun 2016", Calendar.MONDAY, 1, 4 },
+ { 1467032400000L, "27 Jun 2016", Calendar.MONDAY, 1, 5 },
+ { 1467378000000L, "01 Jul 2016", Calendar.MONDAY, 1, 1 },
+ { 1467637200000L, "04 Jul 2016", Calendar.MONDAY, 1, 2 },
+ { 1468242000000L, "11 Jul 2016", Calendar.MONDAY, 1, 3 },
+ { 1468846800000L, "18 Jul 2016", Calendar.MONDAY, 1, 4 },
+ { 1469451600000L, "25 Jul 2016", Calendar.MONDAY, 1, 5 },
+ { 1470056400000L, "01 Aug 2016", Calendar.MONDAY, 1, 1 },
+ { 1470661200000L, "08 Aug 2016", Calendar.MONDAY, 1, 2 },
+ { 1471266000000L, "15 Aug 2016", Calendar.MONDAY, 1, 3 },
+ { 1471870800000L, "22 Aug 2016", Calendar.MONDAY, 1, 4 },
+ { 1472475600000L, "29 Aug 2016", Calendar.MONDAY, 1, 5 },
+ { 1472734800000L, "01 Sep 2016", Calendar.MONDAY, 1, 1 },
+ { 1473080400000L, "05 Sep 2016", Calendar.MONDAY, 1, 2 },
+ { 1473685200000L, "12 Sep 2016", Calendar.MONDAY, 1, 3 },
+ { 1474290000000L, "19 Sep 2016", Calendar.MONDAY, 1, 4 },
+ { 1474894800000L, "26 Sep 2016", Calendar.MONDAY, 1, 5 },
+ { 1475326800000L, "01 Oct 2016", Calendar.MONDAY, 1, 1 },
+ { 1475499600000L, "03 Oct 2016", Calendar.MONDAY, 1, 2 },
+ { 1476104400000L, "10 Oct 2016", Calendar.MONDAY, 1, 3 },
+ { 1476709200000L, "17 Oct 2016", Calendar.MONDAY, 1, 4 },
+ { 1477314000000L, "24 Oct 2016", Calendar.MONDAY, 1, 5 },
+ { 1477918800000L, "31 Oct 2016", Calendar.MONDAY, 1, 6 },
+ { 1478005200000L, "01 Nov 2016", Calendar.MONDAY, 1, 1 },
+ { 1478523600000L, "07 Nov 2016", Calendar.MONDAY, 1, 2 },
+ { 1479128400000L, "14 Nov 2016", Calendar.MONDAY, 1, 3 },
+ { 1479733200000L, "21 Nov 2016", Calendar.MONDAY, 1, 4 },
+ { 1480338000000L, "28 Nov 2016", Calendar.MONDAY, 1, 5 },
+
+ // MinimalDaysInFirstWeek = 4, FirstDayOfWeek SUNDAY
+ { 1462107600000L, "01 May 2016", Calendar.SUNDAY, 4, 1 },
+ { 1462712400000L, "08 May 2016", Calendar.SUNDAY, 4, 2 },
+ { 1463317200000L, "15 May 2016", Calendar.SUNDAY, 4, 3 },
+ { 1463922000000L, "22 May 2016", Calendar.SUNDAY, 4, 4 },
+ { 1464526800000L, "29 May 2016", Calendar.SUNDAY, 4, 5 },
+ { 1464786000000L, "01 Jun 2016", Calendar.SUNDAY, 4, 1 },
+ { 1465131600000L, "05 Jun 2016", Calendar.SUNDAY, 4, 2 },
+ { 1465736400000L, "12 Jun 2016", Calendar.SUNDAY, 4, 3 },
+ { 1466341200000L, "19 Jun 2016", Calendar.SUNDAY, 4, 4 },
+ { 1466946000000L, "26 Jun 2016", Calendar.SUNDAY, 4, 5 },
+ { 1467378000000L, "01 Jul 2016", Calendar.SUNDAY, 4, 0 },
+ { 1467550800000L, "03 Jul 2016", Calendar.SUNDAY, 4, 1 },
+ { 1468155600000L, "10 Jul 2016", Calendar.SUNDAY, 4, 2 },
+ { 1468760400000L, "17 Jul 2016", Calendar.SUNDAY, 4, 3 },
+ { 1469365200000L, "24 Jul 2016", Calendar.SUNDAY, 4, 4 },
+ { 1469970000000L, "31 Jul 2016", Calendar.SUNDAY, 4, 5 },
+ { 1470056400000L, "01 Aug 2016", Calendar.SUNDAY, 4, 1 },
+ { 1470574800000L, "07 Aug 2016", Calendar.SUNDAY, 4, 2 },
+ { 1471179600000L, "14 Aug 2016", Calendar.SUNDAY, 4, 3 },
+ { 1471784400000L, "21 Aug 2016", Calendar.SUNDAY, 4, 4 },
+ { 1472389200000L, "28 Aug 2016", Calendar.SUNDAY, 4, 5 },
+ { 1472734800000L, "01 Sep 2016", Calendar.SUNDAY, 4, 0 },
+ { 1472994000000L, "04 Sep 2016", Calendar.SUNDAY, 4, 1 },
+ { 1473598800000L, "11 Sep 2016", Calendar.SUNDAY, 4, 2 },
+ { 1474203600000L, "18 Sep 2016", Calendar.SUNDAY, 4, 3 },
+ { 1474808400000L, "25 Sep 2016", Calendar.SUNDAY, 4, 4 },
+ { 1475326800000L, "01 Oct 2016", Calendar.SUNDAY, 4, 0 },
+ { 1475413200000L, "02 Oct 2016", Calendar.SUNDAY, 4, 1 },
+ { 1476018000000L, "09 Oct 2016", Calendar.SUNDAY, 4, 2 },
+ { 1476622800000L, "16 Oct 2016", Calendar.SUNDAY, 4, 3 },
+ { 1477227600000L, "23 Oct 2016", Calendar.SUNDAY, 4, 4 },
+ { 1477832400000L, "30 Oct 2016", Calendar.SUNDAY, 4, 5 },
+ { 1478005200000L, "01 Nov 2016", Calendar.SUNDAY, 4, 1 },
+ { 1478437200000L, "06 Nov 2016", Calendar.SUNDAY, 4, 2 },
+ { 1479042000000L, "13 Nov 2016", Calendar.SUNDAY, 4, 3 },
+ { 1479646800000L, "20 Nov 2016", Calendar.SUNDAY, 4, 4 },
+ { 1480251600000L, "27 Nov 2016", Calendar.SUNDAY, 4, 5 },
+
+ // MinimalDaysInFirstWeek = 1, FirstDayOfWeek SUNDAY
+ { 1462107600000L, "01 May 2016", Calendar.SUNDAY, 1, 1 },
+ { 1462712400000L, "08 May 2016", Calendar.SUNDAY, 1, 2 },
+ { 1463317200000L, "15 May 2016", Calendar.SUNDAY, 1, 3 },
+ { 1463922000000L, "22 May 2016", Calendar.SUNDAY, 1, 4 },
+ { 1464526800000L, "29 May 2016", Calendar.SUNDAY, 1, 5 },
+ { 1464786000000L, "01 Jun 2016", Calendar.SUNDAY, 1, 1 },
+ { 1465131600000L, "05 Jun 2016", Calendar.SUNDAY, 1, 2 },
+ { 1465736400000L, "12 Jun 2016", Calendar.SUNDAY, 1, 3 },
+ { 1466341200000L, "19 Jun 2016", Calendar.SUNDAY, 1, 4 },
+ { 1466946000000L, "26 Jun 2016", Calendar.SUNDAY, 1, 5 },
+ { 1467378000000L, "01 Jul 2016", Calendar.SUNDAY, 1, 1 },
+ { 1467550800000L, "03 Jul 2016", Calendar.SUNDAY, 1, 2 },
+ { 1468155600000L, "10 Jul 2016", Calendar.SUNDAY, 1, 3 },
+ { 1468760400000L, "17 Jul 2016", Calendar.SUNDAY, 1, 4 },
+ { 1469365200000L, "24 Jul 2016", Calendar.SUNDAY, 1, 5 },
+ { 1469970000000L, "31 Jul 2016", Calendar.SUNDAY, 1, 6 },
+ { 1470056400000L, "01 Aug 2016", Calendar.SUNDAY, 1, 1 },
+ { 1470574800000L, "07 Aug 2016", Calendar.SUNDAY, 1, 2 },
+ { 1471179600000L, "14 Aug 2016", Calendar.SUNDAY, 1, 3 },
+ { 1471784400000L, "21 Aug 2016", Calendar.SUNDAY, 1, 4 },
+ { 1472389200000L, "28 Aug 2016", Calendar.SUNDAY, 1, 5 },
+ { 1472734800000L, "01 Sep 2016", Calendar.SUNDAY, 1, 1 },
+ { 1472994000000L, "04 Sep 2016", Calendar.SUNDAY, 1, 2 },
+ { 1473598800000L, "11 Sep 2016", Calendar.SUNDAY, 1, 3 },
+ { 1474203600000L, "18 Sep 2016", Calendar.SUNDAY, 1, 4 },
+ { 1474808400000L, "25 Sep 2016", Calendar.SUNDAY, 1, 5 },
+ { 1475326800000L, "01 Oct 2016", Calendar.SUNDAY, 1, 1 },
+ { 1475413200000L, "02 Oct 2016", Calendar.SUNDAY, 1, 2 },
+ { 1476018000000L, "09 Oct 2016", Calendar.SUNDAY, 1, 3 },
+ { 1476622800000L, "16 Oct 2016", Calendar.SUNDAY, 1, 4 },
+ { 1477227600000L, "23 Oct 2016", Calendar.SUNDAY, 1, 5 },
+ { 1477832400000L, "30 Oct 2016", Calendar.SUNDAY, 1, 6 },
+ { 1478005200000L, "01 Nov 2016", Calendar.SUNDAY, 1, 1 },
+ { 1478437200000L, "06 Nov 2016", Calendar.SUNDAY, 1, 2 },
+ { 1479042000000L, "13 Nov 2016", Calendar.SUNDAY, 1, 3 },
+ { 1479646800000L, "20 Nov 2016", Calendar.SUNDAY, 1, 4 },
+ { 1480251600000L, "27 Nov 2016", Calendar.SUNDAY, 1, 5 },
+
+ });
+ }
+
+ public CalendarWeekOfMonthTest(long timeInMillis, String date, int firstDayOfWeek,
+ int minimalDaysInFirstWeek, int expectedWeekOfMonth) {
+ this.timeInMillis = timeInMillis;
+ this.date = date;
+ this.firstDayOfWeek = firstDayOfWeek;
+ this.minimalDaysInFirstWeek = minimalDaysInFirstWeek;
+ this.expectedWeekOfMonth = expectedWeekOfMonth;
+ }
+
+ @Test
+ public void test() {
+ Calendar calendar = new GregorianCalendar(
+ TimeZone.getTimeZone("America/Los_Angeles"), Locale.US);
+ calendar.setFirstDayOfWeek(firstDayOfWeek);
+ calendar.setMinimalDaysInFirstWeek(minimalDaysInFirstWeek);
+ calendar.setTimeInMillis(timeInMillis);
+
+ assertEquals(toString(), expectedWeekOfMonth, calendar.get(Calendar.WEEK_OF_MONTH));
+ }
+
+ @Override
+ public String toString() {
+ return "CalendarWeekOfMonthTest{" + "timeInMillis=" + timeInMillis
+ + ", date='" + date + '\'' + ", firstDayOfWeek=" + firstDayOfWeek
+ + ", minimalDaysInFirstWeek=" + minimalDaysInFirstWeek
+ + ", expectedWeekOfMonth=" + expectedWeekOfMonth + '}';
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/CollectionsTest.java b/luni/src/test/java/libcore/java/util/CollectionsTest.java
index c45b83e..f3284c0 100644
--- a/luni/src/test/java/libcore/java/util/CollectionsTest.java
+++ b/luni/src/test/java/libcore/java/util/CollectionsTest.java
@@ -32,6 +32,9 @@
public final class CollectionsTest extends TestCase {
+ private static final Object NOT_A_STRING = new Object();
+ private static final Object A_STRING = "string";
+
public void testEmptyEnumeration() {
Enumeration<Object> e = Collections.emptyEnumeration();
assertFalse(e instanceof Serializable);
@@ -599,4 +602,140 @@
public void test_SingletonList_sort() {
Collections.singletonList(1).sort((k1, k2) -> 2);
}
+
+ public void test_CheckedMap_replaceAll() {
+ Map<Integer, Integer> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Integer.class);
+ checkedMap.put(1, 10);
+ checkedMap.put(2, 20);
+ checkedMap.put(3, 30);
+ checkedMap.replaceAll((k, v) -> (Integer)k + (Integer)v);
+ assertEquals(11, checkedMap.get(1));
+ assertEquals(22, checkedMap.get(2));
+ assertEquals(33, checkedMap.get(3));
+ assertEquals(3, checkedMap.size());
+ }
+
+ public void test_CheckedMap_putIfAbsent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_putIfAbsent(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+
+ // When key is present
+ checkedMap2.putIfAbsent(1, A_STRING);
+ try {
+ checkedMap2.putIfAbsent(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+
+ // When key is absent
+ checkedMap2.clear();
+ try {
+ checkedMap2.putIfAbsent(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_remove() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_remove(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
+
+ public void test_CheckedMap_replace$K$V$V() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_replace$K$V$V(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.replace(1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_replace$K$V() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_replace$K$V(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.replace(1, 1, NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_computeIfAbsent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_computeIfAbsent(checkedMap, true /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 = Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ // When key is present
+ try {
+ checkedMap2.computeIfAbsent(1, k -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+
+ // When key is absent
+ checkedMap2.clear();
+ try {
+ checkedMap2.computeIfAbsent(1, k -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_computeIfPresent() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_computeIfPresent(checkedMap, true /* acceptsNullKey */);
+
+ // Without generics to check the typeCheck implementation
+ Map m = new HashMap();
+ Map checkedMap2 = Collections.checkedMap(m, Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.computeIfPresent(1, (k, v) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_compute() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_compute(checkedMap, true /* acceptsNullKey */);
+
+ Map checkedMap2 = Collections.checkedMap(new HashMap(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+ try {
+ checkedMap2.compute(1, (k, v) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
+
+ public void test_CheckedMap_merge() {
+ Map<Integer, Double> map = new HashMap<>();
+ Map checkedMap = Collections.checkedMap(map, Integer.class, Double.class);
+ MapDefaultMethodTester.test_merge(checkedMap, true /* acceptsNullKey */);
+
+ // Without generics to check the typeCheck implementation
+ Map checkedMap2 =
+ Collections.checkedMap(new HashMap<>(), Integer.class, String.class);
+ checkedMap2.put(1, A_STRING);
+
+ try {
+ checkedMap2.merge(1, A_STRING, (v1, v2) -> NOT_A_STRING);
+ } catch (ClassCastException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java b/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
index 8b417f2..3fa4dab 100644
--- a/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
+++ b/luni/src/test/java/libcore/java/util/GregorianCalendarTest.java
@@ -38,6 +38,22 @@
Calendar.NOVEMBER, 2, 0, hours(2),
hours(1));
+ private Locale defaultLocale;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ defaultLocale = Locale.getDefault();
+ // Most tests are locale independent, but locale does affect start-of-week.
+ Locale.setDefault(Locale.US);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ Locale.setDefault(defaultLocale);
+ super.tearDown();
+ }
+
// Documented a previous difference in behavior between this and the RI, see
// https://code.google.com/p/android/issues/detail?id=61993 for more details.
// Switching to OpenJDK has fixed that issue and so this test has been changed to reflect
diff --git a/luni/src/test/java/libcore/java/util/HashMapTest.java b/luni/src/test/java/libcore/java/util/HashMapTest.java
index 5aecbb3..12bf59b 100644
--- a/luni/src/test/java/libcore/java/util/HashMapTest.java
+++ b/luni/src/test/java/libcore/java/util/HashMapTest.java
@@ -16,6 +16,7 @@
package libcore.java.util;
+import java.util.ConcurrentModificationException;
import java.util.HashMap;
public class HashMapTest extends junit.framework.TestCase {
@@ -68,4 +69,33 @@
MapDefaultMethodTester
.test_merge(new HashMap<>(), true /*acceptsNullKey*/);
}
+
+ public void test_replaceAll() throws Exception {
+ HashMap<String, String> map = new HashMap<>();
+ map.put("one", "1");
+ map.put("two", "2");
+ map.put("three", "3");
+
+ map.replaceAll((k, v) -> k + v);
+ assertEquals("one1", map.get("one"));
+ assertEquals("two2", map.get("two"));
+ assertEquals("three3", map.get("three"));
+ assertEquals(3, map.size());
+
+ try {
+ map.replaceAll(new java.util.function.BiFunction<String, String, String>() {
+ @Override
+ public String apply(String k, String v) {
+ map.put("foo1", v);
+ return v;
+ }
+ });
+ fail();
+ } catch(ConcurrentModificationException expected) {}
+
+ try {
+ map.replaceAll(null);
+ fail();
+ } catch(NullPointerException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/HashtableTest.java b/luni/src/test/java/libcore/java/util/HashtableTest.java
index 28aa662..40fbf25 100644
--- a/luni/src/test/java/libcore/java/util/HashtableTest.java
+++ b/luni/src/test/java/libcore/java/util/HashtableTest.java
@@ -16,6 +16,7 @@
package libcore.java.util;
+import java.util.ConcurrentModificationException;
import java.util.Hashtable;
import java.util.Map;
@@ -68,4 +69,37 @@
public void test_merge() {
MapDefaultMethodTester.test_merge(new Hashtable<>(), false /*doesNotAcceptNullKey*/);
}
+
+ public void test_replaceAll() throws Exception {
+ Hashtable<String, String> ht = new Hashtable<>();
+ ht.put("one", "1");
+ ht.put("two", "2");
+ ht.put("three", "3");
+
+ ht.replaceAll((k, v) -> k + v);
+ assertEquals("one1", ht.get("one"));
+ assertEquals("two2", ht.get("two"));
+ assertEquals("three3", ht.get("three"));
+ assertEquals(3, ht.size());
+
+ try {
+ ht.replaceAll(new java.util.function.BiFunction<String, String, String>() {
+ @Override
+ public String apply(String k, String v) {
+ ht.put("foo", v);
+ return v;
+ }
+ });
+ fail();
+ } catch(ConcurrentModificationException expected) {}
+
+ try {
+ ht.replaceAll(null);
+ fail();
+ } catch(NullPointerException expected) {}
+
+ try {
+ ht.replaceAll((k, v) -> null);
+ } catch (NullPointerException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java b/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
index c7de1f6..fec95b1 100644
--- a/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
+++ b/luni/src/test/java/libcore/java/util/LinkedHashMapTest.java
@@ -16,8 +16,11 @@
package libcore.java.util;
+import java.util.ConcurrentModificationException;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
public class LinkedHashMapTest extends junit.framework.TestCase {
@@ -205,4 +208,60 @@
assertEquals("key1", newest.getKey());
assertEquals("value3", newest.getValue());
}
+
+ // http://b/27929722
+ // This tests the behaviour is consistent with earlier Android releases.
+ // This behaviour is NOT consistent with the RI. Future Android releases
+ // might change this.
+ public void test_removeEldestEntry() {
+ final AtomicBoolean removeEldestEntryReturnValue = new AtomicBoolean(false);
+ final AtomicInteger removeEldestEntryCallCount = new AtomicInteger(0);
+ LinkedHashMap<String, String> m = new LinkedHashMap<String, String>() {
+ @Override
+ protected boolean removeEldestEntry(Entry eldest) {
+ removeEldestEntryCallCount.incrementAndGet();
+ return removeEldestEntryReturnValue.get();
+ }
+ };
+
+ m.put("foo", "bar");
+ assertEquals(0, removeEldestEntryCallCount.get());
+ m.put("baz", "quux");
+ assertEquals(1, removeEldestEntryCallCount.get());
+
+ removeEldestEntryReturnValue.set(true);
+ m.put("foob", "faab");
+ assertEquals(2, removeEldestEntryCallCount.get());
+ assertEquals(2, m.size());
+ assertFalse(m.containsKey("foo"));
+ }
+
+ public void test_replaceAll() {
+ LinkedHashMap<String, String> map = new LinkedHashMap<>();
+ map.put("one", "1");
+ map.put("two", "2");
+ map.put("three", "3");
+
+ map.replaceAll((k, v) -> k + v);
+ assertEquals("one1", map.get("one"));
+ assertEquals("two2", map.get("two"));
+ assertEquals("three3", map.get("three"));
+ assertEquals(3, map.size());
+
+ try {
+ map.replaceAll(new java.util.function.BiFunction<String, String, String>() {
+ @Override
+ public String apply(String k, String v) {
+ map.put("foo1", v);
+ return v;
+ }
+ });
+ fail();
+ } catch(ConcurrentModificationException expected) {}
+
+ try {
+ map.replaceAll(null);
+ fail();
+ } catch(NullPointerException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/RandomTest.java b/luni/src/test/java/libcore/java/util/RandomTest.java
index 11bdc63..f72a9be 100644
--- a/luni/src/test/java/libcore/java/util/RandomTest.java
+++ b/luni/src/test/java/libcore/java/util/RandomTest.java
@@ -16,6 +16,7 @@
package libcore.java.util;
+import java.util.Arrays;
import java.util.Random;
public class RandomTest extends junit.framework.TestCase {
@@ -40,4 +41,237 @@
r2.nextInt();
assertNotNull(r2.state);
}
+
+ public void test_ints$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ int[] rands = new int[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextInt();
+ }
+
+ int[] streamRands = new Random(0).ints().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_ints$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ int[] rands = new int[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextInt();
+ }
+
+ int[] streamRands = new Random(0).ints(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).ints(size).count());
+
+ try {
+ new Random(0).ints(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_ints$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ int[] rands = new int[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextInt(bound - origin) + origin;
+ }
+
+ int[] streamRands = new Random(0).ints(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).ints(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_ints$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ int[] rands = new int[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextInt(bound - origin) + origin;
+ }
+
+ int[] streamRands = new Random(0).ints(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).ints(size, origin, bound).count());
+
+ try {
+ new Random(0).ints(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).ints(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ long[] rands = new long[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextLong();
+ }
+
+ long[] streamRands = new Random(0).longs().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_longs$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ long[] rands = new long[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextLong();
+ }
+
+ long[] streamRands = new Random(0).longs(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).longs(size).count());
+
+ try {
+ new Random(0).longs(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ long[] rands = new long[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = (rand.nextLong() & 127) + origin;
+ }
+
+ long[] streamRands = new Random(0).longs(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).longs(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_longs$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ long[] rands = new long[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = (rand.nextLong() & 127) + origin;
+ }
+
+ long[] streamRands = new Random(0).longs(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).longs(size, origin, bound).count());
+
+ try {
+ new Random(0).longs(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).longs(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+
+ Random rand = new Random(0);
+ double[] rands = new double[limit];
+ for(int i = 0; i < limit; ++i) {
+ rands[i] = rand.nextDouble();
+ }
+
+ double[] streamRands = new Random(0).doubles().limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ }
+
+ public void test_doubles$L() {
+ final int size = 32;
+
+ Random rand = new Random(0);
+ double[] rands = new double[size];
+ for(int i = 0; i < size; ++i) {
+ rands[i] = rand.nextDouble();
+ }
+
+ double[] streamRands = new Random(0).doubles(size).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).doubles(size).count());
+
+ try {
+ new Random(0).ints(-1);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$II() {
+ final int limit = 128; // We can't test for every element in an infinite stream.
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ double[] rands = new double[limit];
+ for(int i = 0; i < limit; ++i) {
+ double r = rand.nextDouble() * (bound - origin) + origin;
+ if (r >= bound) {
+ r = Math.nextDown(r);
+ }
+ rands[i] = r;
+ }
+
+ double[] streamRands = new Random(0).doubles(origin, bound).limit(limit).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+
+ try {
+ new Random(0).doubles(100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ public void test_doubles$LII() {
+ final int size = 32;
+ final int origin = 128, bound = 256;
+
+ Random rand = new Random(0);
+ double[] rands = new double[size];
+ for(int i = 0; i < size; ++i) {
+ double r = rand.nextDouble() * (bound - origin) + origin;
+ if (r >= bound) {
+ r = Math.nextDown(r);
+ }
+ rands[i] = r;
+ }
+
+ double[] streamRands = new Random(0).doubles(size, origin, bound).toArray();
+ assertTrue(Arrays.equals(rands, streamRands));
+ assertEquals(size, new Random(0).doubles(size, origin, bound).count());
+
+ try {
+ new Random(0).doubles(-1, 10, 20);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ new Random(0).doubles(10, 100, 0);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/TreeMapTest.java b/luni/src/test/java/libcore/java/util/TreeMapTest.java
index 05c5235..355d29d 100644
--- a/luni/src/test/java/libcore/java/util/TreeMapTest.java
+++ b/luni/src/test/java/libcore/java/util/TreeMapTest.java
@@ -567,4 +567,43 @@
SpliteratorTester.runSortedTests(values, (a, b) -> (a.getKey().compareTo(b.getKey())));
SpliteratorTester.runOrderedTests(values);
}
+
+ public void test_replaceAll() throws Exception {
+ TreeMap<String, String> map = new TreeMap<>();
+ map.put("one", "1");
+ map.put("two", "2");
+ map.put("three", "3");
+
+ TreeMap<String, String> output = new TreeMap<>();
+ map.replaceAll((k, v) -> k + v);
+ assertEquals("one1", map.get("one"));
+ assertEquals("two2", map.get("two"));
+ assertEquals("three3", map.get("three"));
+
+ try {
+ map.replaceAll(null);
+ fail();
+ } catch(NullPointerException expected) {}
+
+ try {
+ map.replaceAll(new java.util.function.BiFunction<String, String, String>() {
+ @Override
+ public String apply(String k, String v) {
+ map.put("foo", v);
+ return v;
+ }
+ });
+ fail();
+ } catch(ConcurrentModificationException expected) {}
+ }
+
+ public void test_replace$K$V$V() {
+ MapDefaultMethodTester.test_replace$K$V$V(new TreeMap<>(), false /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
+
+ public void test_replace$K$V() {
+ MapDefaultMethodTester.test_replace$K$V(new TreeMap<>(), false /* acceptsNullKey */,
+ true /* acceptsNullValue */);
+ }
}
diff --git a/luni/src/test/java/libcore/java/util/WeakHashMapTest.java b/luni/src/test/java/libcore/java/util/WeakHashMapTest.java
new file mode 100644
index 0000000..42a1d22
--- /dev/null
+++ b/luni/src/test/java/libcore/java/util/WeakHashMapTest.java
@@ -0,0 +1,81 @@
+/*
+ * 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 junit.framework.TestCase;
+
+import java.util.ConcurrentModificationException;
+import java.util.WeakHashMap;
+
+public class WeakHashMapTest extends TestCase {
+
+ static Data[] data = new Data[100];
+
+ public void test_replaceAll() {
+ initializeData();
+ WeakHashMap<Data, String> map = new WeakHashMap<>();
+ for(int i = 0; i < data.length; i++) {
+ map.put(data[i], "");
+ }
+ map.replaceAll((k, v) -> k.value);
+
+ for(int i = 0; i < data.length; i++) {
+ assertEquals(data[i].value, map.get(data[i]));
+ }
+
+ try {
+ map.replaceAll(new java.util.function.BiFunction<Data, String, String>() {
+ @Override
+ public String apply(Data k, String v) {
+ map.put(new Data(), "");
+ return v;
+ }
+ });
+ fail();
+ } catch (ConcurrentModificationException expected) {
+ }
+
+ try {
+ map.replaceAll(null);
+ fail();
+ } catch (NullPointerException expected) {
+ }
+
+ map.clear();
+ for(int i = 0; i < data.length; i++) {
+ map.put(data[i], data[i].value);
+ }
+
+ map.replaceAll((k, v) -> null);
+
+ for(int i = 0; i < data.length; i++) {
+ assertNull(map.get(data[i]));
+ }
+ assertEquals(data.length, map.size());
+ }
+
+ private void initializeData() {
+ for (int i = 0; i < data.length; i++) {
+ data[i] = new Data();
+ data[i].value = Integer.toString(i);
+ }
+ }
+
+ private static class Data {
+ public String value = "";
+ }
+}
diff --git a/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java b/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
index e5c3bdb..29cdffa 100644
--- a/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
+++ b/luni/src/test/java/libcore/java/util/jar/OldManifestTest.java
@@ -23,6 +23,8 @@
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
import java.util.jar.Attributes;
import java.util.jar.Manifest;
import junit.framework.TestCase;
@@ -176,9 +178,12 @@
// The Manifest-Version takes precedence,
// and the Signature-Version gets no special treatment.
- String[] lines = new String(os.toByteArray(), "UTF-8").split("\r\n");
- assertEquals("Manifest-Version: 1.0", lines[0]);
- assertEquals("Aardvark-Version: 3.0", lines[1]);
- assertEquals("Signature-Version: 2.0", lines[2]);
+ List<String> lines = Arrays.asList(new String(os.toByteArray(), "UTF-8").split("\r\n"));
+ // The first line must always contain the Manifest-Version (or the Signature-Version if
+ // the ManifestVersion is missing.
+ assertEquals("Manifest-Version: 1.0", lines.get(0));
+
+ assertTrue(lines.contains("Aardvark-Version: 3.0"));
+ assertTrue(lines.contains("Signature-Version: 2.0"));
}
}
diff --git a/luni/src/test/java/libcore/javax/crypto/CipherTest.java b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
index bad8a74..ad419ac 100644
--- a/luni/src/test/java/libcore/javax/crypto/CipherTest.java
+++ b/luni/src/test/java/libcore/javax/crypto/CipherTest.java
@@ -3683,4 +3683,72 @@
cipher.init(Cipher.ENCRYPT_MODE, keyGen.generateKeyPair().getPublic());
cipher.doFinal(new byte[] {1,2,3,4});
}
+
+ /**
+ * http://b/27224566
+ * http://b/27994930
+ * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a
+ * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so
+ * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture,
+ * assuming the IV was a 0 vector. Some apps still use this functionality. This
+ * compatibility is likely to be removed in later versions of Android.
+ * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow
+ * if an IV is passed in the parameters.
+ */
+ public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_noIV() throws Exception {
+ byte[] plaintext = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19 };
+ byte[] ciphertext = new byte[] { 92, -65, -128, 16, -102, -115, -44, 52, 16, 124, -34,
+ -45, 58, -70, -17, 127, 119, -67, 87, 91, 63, -13, -40, 9, 97, -17, -71, 97, 10,
+ -61, -19, -73 };
+ SecretKeyFactory skf =
+ SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1");
+ PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(),
+ "salt".getBytes(),
+ 100, 128);
+ SecretKey secretKey = skf.generateSecret(pbeks);
+
+ Cipher cipher =
+ Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+ PBEParameterSpec paramSpec = new PBEParameterSpec("salt".getBytes(), 100);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, paramSpec);
+ assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext)));
+
+ secretKey = skf.generateSecret(pbeks);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, paramSpec);
+ assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext)));
+ }
+
+ /**
+ * http://b/27224566
+ * http://b/27994930
+ * Check that a PBKDF2WITHHMACSHA1 secret key factory works well with a
+ * PBEWITHSHAAND128BITAES-CBC-BC cipher. The former is PKCS5 and the latter is PKCS12, and so
+ * mixing them is not recommended. However, until 1.52 BouncyCastle was accepting this mixture,
+ * assuming the IV was a 0 vector. Some apps still use this functionality. This
+ * compatibility is likely to be removed in later versions of Android.
+ * TODO(27995180): consider whether we keep this compatibility. Consider whether we only allow
+ * if an IV is passed in the parameters.
+ */
+ public void test_PBKDF2WITHHMACSHA1_SKFactory_and_PBEAESCBC_Cipher_withIV() throws Exception {
+ byte[] plaintext = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19 };
+ byte[] ciphertext = { 68, -87, 71, -6, 32, -77, 124, 3, 35, -26, 96, -16, 100, -17, 52, -32,
+ 110, 26, -117, 112, -25, -113, -58, -30, 19, -46, -21, 59, -126, -8, -70, -89 };
+ byte[] iv = new byte[] { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
+ SecretKeyFactory skf =
+ SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1");
+ PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(),
+ "salt".getBytes(),
+ 100, 128);
+ SecretKey secretKey = skf.generateSecret(pbeks);
+ Cipher cipher =
+ Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC");
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(iv));
+ assertEquals(Arrays.toString(ciphertext), Arrays.toString(cipher.doFinal(plaintext)));
+
+ secretKey = skf.generateSecret(pbeks);
+ cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv));
+ assertEquals(Arrays.toString(plaintext), Arrays.toString(cipher.doFinal(ciphertext)));
+ }
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/KeyManagerFactoryTest.java b/luni/src/test/java/libcore/javax/net/ssl/KeyManagerFactoryTest.java
index 0657f18..b99a3f1 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/KeyManagerFactoryTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/KeyManagerFactoryTest.java
@@ -26,6 +26,7 @@
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Arrays;
+import java.util.Locale;
import java.util.Set;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
@@ -39,17 +40,18 @@
public class KeyManagerFactoryTest extends TestCase {
- private static TestKeyStore TEST_KEY_STORE;
+ private TestKeyStore testKeyStore;
- // note the rare usage of DSA keys here in addition to RSA
- private static TestKeyStore getTestKeyStore() throws Exception {
- if (TEST_KEY_STORE == null) {
- TEST_KEY_STORE = new TestKeyStore.Builder()
- .keyAlgorithms("RSA", "DH_RSA", "DSA", "DH_DSA", "EC", "EC_RSA")
- .aliasPrefix("rsa-dsa-ec-dh")
- .build();
- }
- return TEST_KEY_STORE;
+ protected void setUp() throws Exception {
+ // note the rare usage of DSA keys here in addition to RSA
+ testKeyStore = new TestKeyStore.Builder()
+ .keyAlgorithms("RSA", "DH_RSA", "DSA", "DH_DSA", "EC", "EC_RSA")
+ .aliasPrefix("rsa-dsa-ec-dh")
+ .build();
+ }
+
+ private TestKeyStore getTestKeyStore() throws Exception {
+ return testKeyStore;
}
public void test_KeyManagerFactory_getDefaultAlgorithm() throws Exception {
@@ -230,34 +232,30 @@
X509Certificate[] certificateChain = km.getCertificateChain(alias);
PrivateKey privateKey = km.getPrivateKey(alias);
- String keyAlgName;
- String sigAlgName;
- if (keyType == null) {
- keyAlgName = privateKey.getAlgorithm();
- sigAlgName = keyAlgName;
- } else {
- // potentially handle EC_EC or EC_RSA
- keyAlgName = TestKeyStore.keyAlgorithm(keyType);
- sigAlgName = TestKeyStore.signatureAlgorithm(keyType);
- X509Certificate certificate = certificateChain[0];
- assertEquals(keyType, keyAlgName, certificate.getPublicKey().getAlgorithm());
- assertEquals(keyType, keyAlgName, privateKey.getAlgorithm());
- // skip this for EC which could return EC_RSA case instead of EC_EC
- if (!keyType.equals("EC")) {
- String expectedSigAlgName = sigAlgName.toUpperCase();
- String actualSigAlgName = certificate.getSigAlgName().toUpperCase();
- String expected = actualSigAlgName + " contains " + expectedSigAlgName;
- assertTrue(expected, actualSigAlgName.contains(expectedSigAlgName));
- }
- }
+ String keyAlgName = privateKey.getAlgorithm();
+
+ X509Certificate certificate = certificateChain[0];
+ assertEquals(keyType, keyAlgName, certificate.getPublicKey().getAlgorithm());
+
+ String sigAlgName = certificate.getSigAlgName();
PrivateKeyEntry privateKeyEntry = getTestKeyStore().getPrivateKey(keyAlgName, sigAlgName);
- if (!"EC".equals(keyAlgName)) {
- assertEquals(keyType,
- Arrays.<Certificate>asList(privateKeyEntry.getCertificateChain()),
- Arrays.<Certificate>asList(certificateChain));
- assertEquals(keyType,
- privateKeyEntry.getPrivateKey(), privateKey);
+
+ assertEquals(keyType,
+ Arrays.<Certificate>asList(privateKeyEntry.getCertificateChain()),
+ Arrays.<Certificate>asList(certificateChain));
+ assertEquals(keyType,
+ privateKeyEntry.getPrivateKey(), privateKey);
+
+ if (keyType != null) {
+ assertEquals(TestKeyStore.keyAlgorithm(keyType), keyAlgName);
+
+ // Skip this when we're given only "DH" or "EC" instead of "DH_DSA",
+ // "EC_RSA", etc. since we don't know what the expected
+ // algorithm was.
+ if (!keyType.equals("DH") && !keyType.equals("EC")) {
+ assertTrue(sigAlgName.contains(TestKeyStore.signatureAlgorithm(keyType)));
+ }
}
}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SNIHostNameTest.java b/luni/src/test/java/libcore/javax/net/ssl/SNIHostNameTest.java
new file mode 100644
index 0000000..0e4ed61
--- /dev/null
+++ b/luni/src/test/java/libcore/javax/net/ssl/SNIHostNameTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 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.javax.net.ssl;
+
+import java.util.Arrays;
+import javax.net.ssl.SNIHostName;
+import javax.net.ssl.StandardConstants;
+import junit.framework.TestCase;
+
+public class SNIHostNameTest extends TestCase {
+ public void test_byteArray_Constructor() throws Exception {
+ // From draft-josefsson-idn-test-vectors-00 section 5.2
+ byte[] idnEncoded = new byte[] {
+ (byte) 0xE4, (byte) 0xBB, (byte) 0x96, (byte) 0xE4, (byte) 0xBB, (byte) 0xAC,
+ (byte) 0xE4, (byte) 0xB8, (byte) 0xBA, (byte) 0xE4, (byte) 0xBB, (byte) 0x80,
+ (byte) 0xE4, (byte) 0xB9, (byte) 0x88, (byte) 0xE4, (byte) 0xB8, (byte) 0x8D,
+ (byte) 0xE8, (byte) 0xAF, (byte) 0xB4, (byte) 0xE4, (byte) 0xB8, (byte) 0xAD,
+ (byte) 0xE6, (byte) 0x96, (byte) 0x87,
+ };
+
+ SNIHostName hostName = new SNIHostName(idnEncoded);
+ assertEquals("xn--ihqwcrb4cv8a8dqg056pqjye", hostName.getAsciiName());
+ assertEquals(StandardConstants.SNI_HOST_NAME, hostName.getType());
+ assertEquals(Arrays.toString(idnEncoded), Arrays.toString(hostName.getEncoded()));
+ }
+}
diff --git a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
index 0ed4e88..d17e32b 100644
--- a/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
+++ b/luni/src/test/java/libcore/javax/net/ssl/SSLSocketTest.java
@@ -1305,8 +1305,9 @@
// setting wrapper sets underlying and ...
int expectedTimeoutMillis = 1000; // 10 was too small because it was affected by rounding
wrapping.setSoTimeout(expectedTimeoutMillis);
- assertEquals(expectedTimeoutMillis, wrapping.getSoTimeout());
- assertEquals(expectedTimeoutMillis, underlying.getSoTimeout());
+ // The kernel can round the requested value based on the HZ setting. We allow up to 10ms.
+ assertTrue(Math.abs(expectedTimeoutMillis - wrapping.getSoTimeout()) <= 10);
+ assertTrue(Math.abs(expectedTimeoutMillis - underlying.getSoTimeout()) <= 10);
// ... getting wrapper inspects underlying
underlying.setSoTimeout(0);
diff --git a/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java b/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
index a4f534b..41b9643 100644
--- a/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
+++ b/luni/src/test/java/org/apache/harmony/regex/tests/java/util/regex/PatternTest.java
@@ -1840,4 +1840,44 @@
mat = pat.matcher(testString);
assertTrue(mat.matches());
}
+
+ public void testAsPredicate() {
+ String[][] posSeq = {
+ { "abb", "ababb", "abababbababb", "abababbababbabababbbbbabb" },
+ { "213567", "12324567", "1234567", "213213567",
+ "21312312312567", "444444567" },
+ { "abcdaab", "aab", "abaab", "cdaab", "acbdadcbaab" },
+ { "213234567", "3458", "0987654", "7689546432", "0398576",
+ "98432", "5" },
+ {
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" },
+ { "ababbaAabababblice", "ababbaAliceababab", "ababbAabliceaaa",
+ "abbbAbbbliceaaa", "Alice" },
+ { "a123", "bnxnvgds156", "for", "while", "if", "struct" },
+ { "xy" }, { "xy" }, { "xcy" }
+ };
+
+ for (int i = 0; i < testPatterns.length; i++) {
+ Pattern p = Pattern.compile(testPatterns[i]);
+ for (int j = 0; j < posSeq[i].length; j++) {
+ assertTrue(p.asPredicate().test(posSeq[i][j]));
+ }
+ }
+ }
+
+ public void testSplitAsStream() {
+ String s[];
+ Pattern pat = Pattern.compile("b");
+ s = pat.splitAsStream("abccbadfebb").toArray(String[]::new);
+ assertEquals(s.length, 3);
+ s = pat.splitAsStream("").toArray(String[]::new);
+ assertEquals(s.length, 0);
+ pat = Pattern.compile("");
+ s = pat.splitAsStream("").toArray(String[]::new);
+ assertEquals(s.length, 0);
+ s = pat.splitAsStream("abccbadfe").toArray(String[]::new);
+ assertEquals(s.length, 9);
+ }
}
diff --git a/luni/src/test/java/tests/security/cert/CertPathBuilder2Test.java b/luni/src/test/java/tests/security/cert/CertPathBuilder2Test.java
index ffc5d08..5451e85 100644
--- a/luni/src/test/java/tests/security/cert/CertPathBuilder2Test.java
+++ b/luni/src/test/java/tests/security/cert/CertPathBuilder2Test.java
@@ -79,19 +79,6 @@
private void checkResult(CertPathBuilder certBuild)
throws InvalidAlgorithmParameterException,
CertPathBuilderException {
- String dt = CertPathBuilder.getDefaultType();
- String propName = CertPathBuilder1Test.DEFAULT_TYPE_PROPERTY;
- String dtN;
- for (int i = 0; i <invalidValues.length; i++) {
- Security.setProperty(propName, invalidValues[i]);
- dtN = CertPathBuilder.getDefaultType();
- if (!dtN.equals(invalidValues[i]) && !dtN.equals(dt)) {
- fail("Incorrect default type: ".concat(dtN));
- }
- }
- Security.setProperty(propName, dt);
- assertEquals("Incorrect default type", CertPathBuilder.getDefaultType(),
- dt);
try {
certBuild.build(null);
fail("CertPathBuilderException must be thrown");
@@ -161,10 +148,9 @@
} catch (NoSuchAlgorithmException e) {
}
}
- String prov = null;
for (int i = 0; i < validValues.length; i++) {
try {
- CertPathBuilder.getInstance(validValues[i], prov);
+ CertPathBuilder.getInstance(validValues[i], (Provider) null);
fail("IllegalArgumentException must be thrown when provider is null (type: "
.concat(validValues[i]).concat(")"));
} catch (IllegalArgumentException e) {
@@ -224,10 +210,9 @@
} catch (NoSuchAlgorithmException e) {
}
}
- Provider prov = null;
for (int i = 0; i < validValues.length; i++) {
try {
- CertPathBuilder.getInstance(validValues[i], prov);
+ CertPathBuilder.getInstance(validValues[i], (Provider) null);
fail("IllegalArgumentException must be thrown when provider is null (type: "
.concat(validValues[i]).concat(")"));
} catch (IllegalArgumentException e) {
diff --git a/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java b/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
index a6eaf05..1616efb 100644
--- a/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
+++ b/luni/src/test/java/tests/security/cert/X509CertSelectorTest.java
@@ -397,7 +397,8 @@
selector.setIssuer(iss1);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name1, selector.getIssuerAsBytes()));
- assertFalse("The returned issuer should differ", name2.equals(selector.getIssuerAsBytes()));
+ assertFalse("The returned issuer should differ",
+ Arrays.equals(name2, selector.getIssuerAsBytes()));
selector.setIssuer(iss2);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name2, selector.getIssuerAsBytes()));
@@ -682,7 +683,7 @@
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name1, selector.getSubjectAsBytes()));
assertFalse("The returned issuer should differ",
- name2.equals(selector.getSubjectAsBytes()));
+ Arrays.equals(name2, selector.getSubjectAsBytes()));
selector.setSubject(sub2);
assertTrue("The returned issuer should be equal to specified",
Arrays.equals(name2, selector.getSubjectAsBytes()));
diff --git a/luni/src/test/native/libcore_java_lang_ThreadTest.cpp b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
new file mode 100644
index 0000000..68e858a
--- /dev/null
+++ b/luni/src/test/native/libcore_java_lang_ThreadTest.cpp
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015 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.
+ */
+
+#include <memory>
+#include <string>
+
+#include <pthread.h>
+#include <sys/prctl.h>
+
+#include <jni.h>
+#include "JNIHelp.h"
+
+static JavaVM* javaVm = nullptr;
+
+static void* TestThreadNaming(void* arg) {
+ const bool attach_with_name = (reinterpret_cast<uint64_t>(arg) == 1);
+ const std::string native_thread_name = "foozball";
+ pthread_setname_np(pthread_self(), native_thread_name.c_str());
+
+ JNIEnv* env;
+ JavaVMAttachArgs args;
+ args.version = JNI_VERSION_1_6;
+ args.group = nullptr;
+ if (attach_with_name) {
+ args.name = native_thread_name.c_str();
+ } else {
+ args.name = nullptr;
+ }
+
+ if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
+ return new std::string("Attach failed");
+ }
+
+ std::string* exception_message = nullptr;
+ std::unique_ptr<char[]> thread_name(new char[32]);
+ if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(thread_name.get()), 0L, 0L, 0L) == 0) {
+ // If a thread is attached with a name, the native thread name must be set to
+ // the supplied name. In this test, the name we attach with == the
+ // native_thread_name.
+ if (attach_with_name && (thread_name.get() != native_thread_name)) {
+ exception_message = new std::string("expected_thread_name != thread_name: ");
+ exception_message->append("expected :");
+ exception_message->append(native_thread_name);
+ exception_message->append(" was :");
+ exception_message->append(thread_name.get());
+ }
+
+ // On the other hand, if the thread isn't attached with a name - the
+ // runtime assigns a name according to the usual thread naming scheme.
+ if (!attach_with_name && strncmp(thread_name.get(), "Thread", 6)) {
+ exception_message = new std::string("unexpected thread name : ");
+ exception_message->append(thread_name.get());
+ }
+ } else {
+ exception_message = new std::string("prctl(PR_GET_NAME) failed :");
+ exception_message->append(strerror(errno));
+ }
+
+
+ if (javaVm->DetachCurrentThread() != JNI_OK) {
+ exception_message = new std::string("Detach failed");
+ }
+
+ return exception_message;
+}
+
+extern "C" jstring Java_libcore_java_lang_ThreadTest_nativeTestNativeThreadNames(
+ JNIEnv* env, jobject /* object */) {
+ std::string result;
+
+ // TEST 1: Test that a thread attaching with a specified name (in the
+ // JavaVMAttachArgs) does not have its name changed.
+ pthread_t attacher;
+ if (pthread_create(&attacher, nullptr, TestThreadNaming,
+ reinterpret_cast<void*>(static_cast<uint64_t>(0))) != 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Attach failed");
+ }
+
+ std::string* result_test1;
+ if (pthread_join(attacher, reinterpret_cast<void**>(&result_test1)) != 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Join failed");
+ }
+
+ if (result_test1 != nullptr) {
+ result.append("test 1: ");
+ result.append(*result_test1);
+ }
+
+ // TEST 2: Test that a thread attaching without a specified name (in the
+ // JavaVMAttachArgs) has its native name changed as per the standard naming
+ // convention.
+ pthread_t attacher2;
+ if (pthread_create(&attacher2, nullptr, TestThreadNaming,
+ reinterpret_cast<void*>(static_cast<uint64_t>(1))) != 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Attach failed");
+ }
+
+ std::string* result_test2;
+ if (pthread_join(attacher2, reinterpret_cast<void**>(&result_test2)) != 0) {
+ jniThrowException(env, "java/lang/IllegalStateException", "Join failed");
+ }
+
+ if (result_test2 != nullptr) {
+ result.append("test 2: ");
+ result.append(*result_test2);
+ }
+
+ // Return test results.
+ jstring resultJString = nullptr;
+ if (result.size() > 0) {
+ resultJString = env->NewStringUTF(result.c_str());
+ }
+
+ delete result_test1;
+ delete result_test2;
+
+ return resultJString;
+}
+
+extern "C" int JNI_OnLoad(JavaVM* vm, void*) {
+ javaVm = vm;
+ return JNI_VERSION_1_6;
+}
diff --git a/luni/src/test/resources/org/apache/harmony/tests/java/util/TestUtf8ResourceBundle.properties b/luni/src/test/resources/org/apache/harmony/tests/java/util/TestUtf8ResourceBundle.properties
new file mode 100644
index 0000000..9d872b4
--- /dev/null
+++ b/luni/src/test/resources/org/apache/harmony/tests/java/util/TestUtf8ResourceBundle.properties
@@ -0,0 +1 @@
+key=Страх мой удивительный UTF-8 синтаксического анализа
diff --git a/non_openjdk_java_files.mk b/non_openjdk_java_files.mk
index 104a6f3..c50d5ad 100644
--- a/non_openjdk_java_files.mk
+++ b/non_openjdk_java_files.mk
@@ -56,6 +56,7 @@
libart/src/main/java/dalvik/system/VMStack.java \
libart/src/main/java/dalvik/system/TransactionAbortError.java \
dalvik/src/main/java/dalvik/system/ZygoteHooks.java \
+ libart/src/main/java/java/lang/AndroidHardcodedSystemProperties.java \
libart/src/main/java/java/lang/Daemons.java \
libart/src/main/java/java/lang/DexCache.java \
luni/src/main/java/java/lang/FindBugsSuppressWarnings.java \
@@ -391,7 +392,6 @@
luni/src/main/java/libcore/net/http/HttpDate.java \
luni/src/main/java/libcore/net/http/ResponseUtils.java \
luni/src/main/java/libcore/reflect/AnnotatedElements.java \
- luni/src/main/java/libcore/reflect/AnnotationAccess.java \
luni/src/main/java/libcore/reflect/AnnotationFactory.java \
luni/src/main/java/libcore/reflect/AnnotationMember.java \
luni/src/main/java/libcore/reflect/GenericArrayTypeImpl.java \
diff --git a/ojluni/src/main/java/java/io/BufferedReader.java b/ojluni/src/main/java/java/io/BufferedReader.java
index 4d2962c..5a45f4b 100755
--- a/ojluni/src/main/java/java/io/BufferedReader.java
+++ b/ojluni/src/main/java/java/io/BufferedReader.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
@@ -27,6 +27,13 @@
package java.io;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
/**
* Reads text from a character-input stream, buffering characters so as to
* provide for the efficient reading of characters, arrays, and lines.
@@ -530,4 +537,65 @@
cb = null;
}
}
+
+ /**
+ * Returns a {@code Stream}, the elements of which are lines read from
+ * this {@code BufferedReader}. The {@link Stream} is lazily populated,
+ * i.e., read only occurs during the
+ * <a href="../util/stream/package-summary.html#StreamOps">terminal
+ * stream operation</a>.
+ *
+ * <p> The reader must not be operated on during the execution of the
+ * terminal stream operation. Otherwise, the result of the terminal stream
+ * operation is undefined.
+ *
+ * <p> After execution of the terminal stream operation there are no
+ * guarantees that the reader will be at a specific position from which to
+ * read the next character or line.
+ *
+ * <p> If an {@link IOException} is thrown when accessing the underlying
+ * {@code BufferedReader}, it is wrapped in an {@link
+ * UncheckedIOException} which will be thrown from the {@code Stream}
+ * method that caused the read to take place. This method will return a
+ * Stream if invoked on a BufferedReader that is closed. Any operation on
+ * that stream that requires reading from the BufferedReader after it is
+ * closed, will cause an UncheckedIOException to be thrown.
+ *
+ * @return a {@code Stream<String>} providing the lines of text
+ * described by this {@code BufferedReader}
+ *
+ * @since 1.8
+ */
+ public Stream<String> lines() {
+ Iterator<String> iter = new Iterator<String>() {
+ String nextLine = null;
+
+ @Override
+ public boolean hasNext() {
+ if (nextLine != null) {
+ return true;
+ } else {
+ try {
+ nextLine = readLine();
+ return (nextLine != null);
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+
+ @Override
+ public String next() {
+ if (nextLine != null || hasNext()) {
+ String line = nextLine;
+ nextLine = null;
+ return line;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ };
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
}
diff --git a/ojluni/src/main/java/java/io/ObjectInputStream.java b/ojluni/src/main/java/java/io/ObjectInputStream.java
index 6ba4dc3..3352266 100755
--- a/ojluni/src/main/java/java/io/ObjectInputStream.java
+++ b/ojluni/src/main/java/java/io/ObjectInputStream.java
@@ -202,7 +202,7 @@
* @see java.io.DataInput
* @see java.io.ObjectOutputStream
* @see java.io.Serializable
- * @see <a href="../../../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
+ * @see <a href="{@docRoot}/../platform/serialization/spec/input.html"> Object Serialization Specification, Section 3, Object Input Classes</a>
* @since JDK1.1
*/
public class ObjectInputStream
diff --git a/ojluni/src/main/java/java/io/ObjectOutputStream.java b/ojluni/src/main/java/java/io/ObjectOutputStream.java
index 93ccd0c..5e5fbfa 100755
--- a/ojluni/src/main/java/java/io/ObjectOutputStream.java
+++ b/ojluni/src/main/java/java/io/ObjectOutputStream.java
@@ -37,6 +37,7 @@
import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue;
import java.io.SerialCallbackContext;
+
import sun.reflect.misc.ReflectUtil;
/**
@@ -157,7 +158,7 @@
* @see java.io.ObjectInputStream
* @see java.io.Serializable
* @see java.io.Externalizable
- * @see <a href="../../../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
+ * @see <a href="{@docRoot}/../platform/serialization/spec/output.html">Object Serialization Specification, Section 2, Object Output Classes</a>
* @since JDK1.1
*/
public class ObjectOutputStream
@@ -749,7 +750,8 @@
*/
public void close() throws IOException {
flush();
- clear();
+ // http://b/28159133
+ // clear();
bout.close();
}
@@ -1798,6 +1800,17 @@
private final DataOutputStream dout;
/**
+ * Indicates that this stream was closed and that a warning must be logged once if an
+ * attempt is made to write to it and the underlying stream does not throw an exception.
+ *
+ * <p>This will be set back to false when a warning is logged to ensure that the log is not
+ * flooded with warnings.
+ *
+ * http://b/28159133
+ */
+ private boolean warnOnceWhenWriting;
+
+ /**
* Creates new BlockDataOutputStream on top of given underlying stream.
* Block data mode is turned off by default.
*/
@@ -1830,6 +1843,25 @@
return blkmode;
}
+ /**
+ * Warns if the stream has been closed.
+ *
+ * <p>This is called after data has been written to the underlying stream in order to allow
+ * the underlying stream to detect and fail if an attempt is made to write to a closed
+ * stream. That ensures that this will only log a warning if the underlying stream does not
+ * so it will not log unnecessary warnings.
+ */
+ private void warnIfClosed() {
+ if (warnOnceWhenWriting) {
+ System.logW("The app is relying on undefined behavior. Attempting to write to a"
+ + " closed ObjectOutputStream could produce corrupt output in a future"
+ + " release of Android.", new IOException("Stream Closed"));
+ // Set back to false so no more messages are logged unless the stream is closed
+ // again.
+ warnOnceWhenWriting = false;
+ }
+ }
+
/* ----------------- generic output stream methods ----------------- */
/*
* The following methods are equivalent to their counterparts in
@@ -1860,6 +1892,7 @@
public void close() throws IOException {
flush();
out.close();
+ warnOnceWhenWriting = true;
}
/**
@@ -1874,6 +1907,7 @@
if (!(copy || blkmode)) { // write directly
drain();
out.write(b, off, len);
+ warnIfClosed();
return;
}
@@ -1895,6 +1929,7 @@
len -= wlen;
}
}
+ warnIfClosed();
}
/**
@@ -1910,6 +1945,7 @@
}
out.write(buf, 0, pos);
pos = 0;
+ warnIfClosed();
}
/**
@@ -1927,6 +1963,7 @@
Bits.putInt(hbuf, 1, len);
out.write(hbuf, 0, 5);
}
+ warnIfClosed();
}
diff --git a/ojluni/src/main/java/java/io/ObjectStreamClass.java b/ojluni/src/main/java/java/io/ObjectStreamClass.java
index 6167a9f..1c2df71 100755
--- a/ojluni/src/main/java/java/io/ObjectStreamClass.java
+++ b/ojluni/src/main/java/java/io/ObjectStreamClass.java
@@ -60,13 +60,13 @@
* loaded in this Java VM can be found/created using the lookup method.
*
* <p>The algorithm to compute the SerialVersionUID is described in
- * <a href="../../../platform/serialization/spec/class.html#4100">Object
+ * <a href="{@docRoot}/../platform/serialization/spec/class.html#4100">Object
* Serialization Specification, Section 4.6, Stream Unique Identifiers</a>.
*
* @author Mike Warres
* @author Roger Riggs
* @see ObjectStreamField
- * @see <a href="../../../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
+ * @see <a href="{@docRoot}/../platform/serialization/spec/class.html">Object Serialization Specification, Section 4, Class Descriptors</a>
* @since JDK1.1
*/
public class ObjectStreamClass implements Serializable {
@@ -2272,6 +2272,32 @@
return matches;
}
+ // NOTE: The following couple of methods are left here because frameworks such as objenesis
+ // use them.
+ //
+ // **** THESE METHODS WILL BE REMOVED IN A FUTURE ANDROID RELEASE ****.
+ //
+ private static long getConstructorId(Class<?> clazz) {
+ System.logE("WARNING: ObjectStreamClass.getConstructorId(Class<?>) is private API and" +
+ "will be removed in a future Android release.");
+ // NOTE: This method is a stub that returns a fixed value. It's meant to be used
+ // with newInstance(Class<?>, long) and our current implementation of that method ignores
+ // the "constructorId" argument. We return :
+ //
+ // oh one one eight nine nine nine
+ // eight eight one nine nine
+ // nine one one nine seven two five
+ // three
+ //
+ // in all cases.
+ return 1189998819991197253L;
+ }
+ private static Object newInstance(Class<?> clazz, long constructorId) {
+ System.logE("WARNING: ObjectStreamClass.newInstance(Class<?>, long) is private API and" +
+ "will be removed in a future Android release.");
+ return sun.misc.Unsafe.getUnsafe().allocateInstance(clazz);
+ }
+
/**
* Removes from the specified map any keys that have been enqueued
* on the specified reference queue.
diff --git a/ojluni/src/main/java/java/io/UncheckedIOException.java b/ojluni/src/main/java/java/io/UncheckedIOException.java
new file mode 100644
index 0000000..22c43e3
--- /dev/null
+++ b/ojluni/src/main/java/java/io/UncheckedIOException.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 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. 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.io;
+
+import java.util.Objects;
+
+/**
+ * Wraps an {@link IOException} with an unchecked exception.
+ *
+ * @since 1.8
+ */
+public class UncheckedIOException extends RuntimeException {
+ private static final long serialVersionUID = -8134305061645241065L;
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param message
+ * the detail message, can be null
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(String message, IOException cause) {
+ super(message, Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Constructs an instance of this class.
+ *
+ * @param cause
+ * the {@code IOException}
+ *
+ * @throws NullPointerException
+ * if the cause is {@code null}
+ */
+ public UncheckedIOException(IOException cause) {
+ super(Objects.requireNonNull(cause));
+ }
+
+ /**
+ * Returns the cause of this exception.
+ *
+ * @return the {@code IOException} which is the cause of this exception.
+ */
+ @Override
+ public IOException getCause() {
+ return (IOException) super.getCause();
+ }
+
+ /**
+ * Called to read the object from a stream.
+ *
+ * @throws InvalidObjectException
+ * if the object is invalid or has a cause that is not
+ * an {@code IOException}
+ */
+ private void readObject(ObjectInputStream s)
+ throws IOException, ClassNotFoundException
+ {
+ s.defaultReadObject();
+ Throwable cause = super.getCause();
+ if (!(cause instanceof IOException))
+ throw new InvalidObjectException("Cause must be an IOException");
+ }
+}
diff --git a/ojluni/src/main/java/java/io/package.html b/ojluni/src/main/java/java/io/package.html
index 1b909ad..72e458b 100755
--- a/ojluni/src/main/java/java/io/package.html
+++ b/ojluni/src/main/java/java/io/package.html
@@ -36,7 +36,7 @@
<h2>Package Specification</h2>
<ul>
- <li><a href="../../../platform/serialization/spec/serialTOC.html"> Java Object Serialization Specification </a>
+ <li><a href="{@docRoot}/../platform/serialization/spec/serialTOC.html"> Java Object Serialization Specification </a>
</ul>
<h2>Related Documentation</h2>
@@ -44,7 +44,7 @@
For overviews, tutorials, examples, guides, and tool documentation,
please see:
<ul>
- <li><a href="../../../technotes/guides/serialization">Serialization Enhancements</a>
+ <li><a href="{@docRoot}/../technotes/guides/serialization">Serialization Enhancements</a>
</ul>
@since JDK1.0
diff --git a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
index e11ae3c..63606b3 100755
--- a/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
+++ b/ojluni/src/main/java/java/lang/AbstractStringBuilder.java
@@ -413,7 +413,7 @@
if (str == null) str = "null";
int len = str.length();
ensureCapacityInternal(count + len);
- str.getChars(0, len, value, count);
+ str.getCharsNoCheck(0, len, value, count);
count += len;
return this;
}
@@ -478,8 +478,16 @@
+ s.length());
int len = end - start;
ensureCapacityInternal(count + len);
- for (int i = start, j = count; i < end; i++, j++)
- value[j] = s.charAt(i);
+ if (s instanceof String) {
+ ((String) s).getCharsNoCheck(start, end, value, count);
+ } else if (s instanceof AbstractStringBuilder) {
+ AbstractStringBuilder other = (AbstractStringBuilder) s;
+ System.arraycopy(other.value, start, value, count, len);
+ } else {
+ for (int i = start, j = count; i < end; i++, j++) {
+ value[j] = s.charAt(i);
+ }
+ }
count += len;
return this;
}
@@ -805,7 +813,7 @@
ensureCapacityInternal(newCount);
System.arraycopy(value, end, value, start + len, count - end);
- str.getChars(0, len, value, start);
+ str.getCharsNoCheck(0, len, value, start);
count = newCount;
return this;
}
@@ -978,7 +986,7 @@
int len = str.length();
ensureCapacityInternal(count + len);
System.arraycopy(value, offset, value, offset + len, count - offset);
- str.getChars(0, len, value, offset);
+ str.getCharsNoCheck(0, len, value, offset);
count += len;
return this;
}
diff --git a/ojluni/src/main/java/java/lang/Boolean.java b/ojluni/src/main/java/java/lang/Boolean.java
index cac469b..f71d666 100755
--- a/ojluni/src/main/java/java/lang/Boolean.java
+++ b/ojluni/src/main/java/java/lang/Boolean.java
@@ -292,4 +292,46 @@
private static boolean toBoolean(String name) {
return ((name != null) && name.equalsIgnoreCase("true"));
}
+
+ /**
+ * Returns the result of applying the logical AND operator to the
+ * specified {@code boolean} operands.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the logical AND of {@code a} and {@code b}
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static boolean logicalAnd(boolean a, boolean b) {
+ return a && b;
+ }
+
+ /**
+ * Returns the result of applying the logical OR operator to the
+ * specified {@code boolean} operands.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the logical OR of {@code a} and {@code b}
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static boolean logicalOr(boolean a, boolean b) {
+ return a || b;
+ }
+
+ /**
+ * Returns the result of applying the logical XOR operator to the
+ * specified {@code boolean} operands.
+ *
+ * @param a the first operand
+ * @param b the second operand
+ * @return the logical XOR of {@code a} and {@code b}
+ * @see java.util.function.BinaryOperator
+ * @since 1.8
+ */
+ public static boolean logicalXor(boolean a, boolean b) {
+ return a ^ b;
+ }
}
diff --git a/ojluni/src/main/java/java/lang/CharSequence.java b/ojluni/src/main/java/java/lang/CharSequence.java
index d9e65a0..7b50d74 100755
--- a/ojluni/src/main/java/java/lang/CharSequence.java
+++ b/ojluni/src/main/java/java/lang/CharSequence.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2003, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -25,6 +25,13 @@
package java.lang;
+import java.util.NoSuchElementException;
+import java.util.PrimitiveIterator;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.IntConsumer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* A <tt>CharSequence</tt> is a readable sequence of <code>char</code> values. This
@@ -108,4 +115,120 @@
*/
public String toString();
+ /**
+ * Returns a stream of {@code int} zero-extending the {@code char} values
+ * from this sequence. Any char which maps to a <a
+ * href="{@docRoot}/java/lang/Character.html#unicode">surrogate code
+ * point</a> is passed through uninterpreted.
+ *
+ * <p>If the sequence is mutated while the stream is being read, the
+ * result is undefined.
+ *
+ * @return an IntStream of char values from this sequence
+ * @since 1.8
+ */
+ public default IntStream chars() {
+ class CharIterator implements PrimitiveIterator.OfInt {
+ int cur = 0;
+
+ public boolean hasNext() {
+ return cur < length();
+ }
+
+ public int nextInt() {
+ if (hasNext()) {
+ return charAt(cur++);
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+
+ @Override
+ public void forEachRemaining(IntConsumer block) {
+ for (; cur < length(); cur++) {
+ block.accept(charAt(cur));
+ }
+ }
+ }
+
+ return StreamSupport.intStream(() ->
+ Spliterators.spliterator(
+ new CharIterator(),
+ length(),
+ Spliterator.ORDERED),
+ Spliterator.SUBSIZED | Spliterator.SIZED | Spliterator.ORDERED,
+ false);
+ }
+
+ /**
+ * Returns a stream of code point values from this sequence. Any surrogate
+ * pairs encountered in the sequence are combined as if by {@linkplain
+ * Character#toCodePoint Character.toCodePoint} and the result is passed
+ * to the stream. Any other code units, including ordinary BMP characters,
+ * unpaired surrogates, and undefined code units, are zero-extended to
+ * {@code int} values which are then passed to the stream.
+ *
+ * <p>If the sequence is mutated while the stream is being read, the result
+ * is undefined.
+ *
+ * @return an IntStream of Unicode code points from this sequence
+ * @since 1.8
+ */
+ public default IntStream codePoints() {
+ class CodePointIterator implements PrimitiveIterator.OfInt {
+ int cur = 0;
+
+ @Override
+ public void forEachRemaining(IntConsumer block) {
+ final int length = length();
+ int i = cur;
+ try {
+ while (i < length) {
+ char c1 = charAt(i++);
+ if (!Character.isHighSurrogate(c1) || i >= length) {
+ block.accept(c1);
+ } else {
+ char c2 = charAt(i);
+ if (Character.isLowSurrogate(c2)) {
+ i++;
+ block.accept(Character.toCodePoint(c1, c2));
+ } else {
+ block.accept(c1);
+ }
+ }
+ }
+ } finally {
+ cur = i;
+ }
+ }
+
+ public boolean hasNext() {
+ return cur < length();
+ }
+
+ public int nextInt() {
+ final int length = length();
+
+ if (cur >= length) {
+ throw new NoSuchElementException();
+ }
+ char c1 = charAt(cur++);
+ if (Character.isHighSurrogate(c1) && cur < length) {
+ char c2 = charAt(cur);
+ if (Character.isLowSurrogate(c2)) {
+ cur++;
+ return Character.toCodePoint(c1, c2);
+ }
+ }
+ return c1;
+ }
+ }
+
+ return StreamSupport.intStream(() ->
+ Spliterators.spliteratorUnknownSize(
+ new CodePointIterator(),
+ Spliterator.ORDERED),
+ Spliterator.ORDERED,
+ false);
+ }
}
diff --git a/ojluni/src/main/java/java/lang/Character.java b/ojluni/src/main/java/java/lang/Character.java
index bb69d91..5b9038a 100755
--- a/ojluni/src/main/java/java/lang/Character.java
+++ b/ojluni/src/main/java/java/lang/Character.java
@@ -6458,6 +6458,21 @@
* @since 1.5
*/
public static int digit(int codePoint, int radix) {
+ if (radix < MIN_RADIX || radix > MAX_RADIX) {
+ return -1;
+ }
+ if (codePoint < 128) {
+ // Optimized for ASCII
+ int result = -1;
+ if ('0' <= codePoint && codePoint <= '9') {
+ result = codePoint - '0';
+ } else if ('a' <= codePoint && codePoint <= 'z') {
+ result = 10 + (codePoint - 'a');
+ } else if ('A' <= codePoint && codePoint <= 'Z') {
+ result = 10 + (codePoint - 'A');
+ }
+ return result < radix ? result : -1;
+ }
return digitImpl(codePoint, radix);
}
diff --git a/ojluni/src/main/java/java/lang/Class.java b/ojluni/src/main/java/java/lang/Class.java
index a1c471a..09f949b 100755
--- a/ojluni/src/main/java/java/lang/Class.java
+++ b/ojluni/src/main/java/java/lang/Class.java
@@ -26,6 +26,7 @@
package java.lang;
+import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member;
@@ -65,8 +66,6 @@
import java.lang.reflect.AccessibleObject;
import com.android.dex.Dex;
import dalvik.system.VMStack;
-import libcore.reflect.AnnotatedElements;
-import libcore.reflect.AnnotationAccess;
import libcore.reflect.InternalNames;
import libcore.reflect.GenericSignatureParser;
import libcore.reflect.Types;
@@ -753,7 +752,7 @@
* @since 1.5
*/
@Override public synchronized TypeVariable<Class<T>>[] getTypeParameters() {
- String annotationSignature = AnnotationAccess.getSignature(this);
+ String annotationSignature = getSignatureAttribute();
if (annotationSignature == null) {
return EmptyArray.TYPE_VARIABLE;
}
@@ -820,7 +819,7 @@
return null;
}
- String annotationSignature = AnnotationAccess.getSignature(this);
+ String annotationSignature = getSignatureAttribute();
if (annotationSignature != null) {
GenericSignatureParser parser = new GenericSignatureParser(getClassLoader());
parser.parseForClass(this, annotationSignature);
@@ -981,7 +980,7 @@
synchronized (Caches.genericInterfaces) {
result = Caches.genericInterfaces.get(this);
if (result == null) {
- String annotationSignature = AnnotationAccess.getSignature(this);
+ String annotationSignature = getSignatureAttribute();
if (annotationSignature == null) {
result = getInterfaces();
} else {
@@ -1052,7 +1051,7 @@
return Modifier.ABSTRACT | Modifier.FINAL | componentModifiers;
}
int JAVA_FLAGS_MASK = 0xffff;
- int modifiers = AnnotationAccess.getInnerClassFlags(this, accessFlags & JAVA_FLAGS_MASK);
+ int modifiers = this.getInnerClassFlags(accessFlags & JAVA_FLAGS_MASK);
return modifiers & JAVA_FLAGS_MASK;
}
@@ -1242,8 +1241,7 @@
* @since 1.5
*/
public boolean isLocalClass() {
- return !classNameImpliesTopLevel()
- && AnnotationAccess.getEnclosingMethodOrConstructor(this) != null
+ return (getEnclosingMethod() != null || getEnclosingConstructor() != null)
&& !isAnonymousClass();
}
@@ -2421,7 +2419,6 @@
return false;
}
-
/**
* Returns an array containing all the annotations of this class. If there are no annotations
* then an empty array is returned.
@@ -2473,18 +2470,9 @@
* @since 1.8
*/
@Override
- public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
- return AnnotatedElements.getDeclaredAnnotationsByType(this, annotationClass);
- }
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
// Find any associated annotations [directly or repeatably (indirectly) present on this].
- T[] annotations = AnnotatedElements.getAnnotationsByType(this, annotationClass);
+ T[] annotations = AnnotatedElement.super.getAnnotationsByType(annotationClass);
if (annotations.length != 0) {
return annotations;
@@ -2534,6 +2522,20 @@
return annotationType;
}
+ private String getSignatureAttribute() {
+ String[] annotation = getSignatureAnnotation();
+ if (annotation == null) {
+ return null;
+ }
+ StringBuilder result = new StringBuilder();
+ for (String s : annotation) {
+ result.append(s);
+ }
+ return result.toString();
+ }
+
+ private native String[] getSignatureAnnotation();
+
/**
* Is this a runtime created proxy class?
*
diff --git a/ojluni/src/main/java/java/lang/ClassLoader.java b/ojluni/src/main/java/java/lang/ClassLoader.java
index 73ca551..332cbd9 100755
--- a/ojluni/src/main/java/java/lang/ClassLoader.java
+++ b/ojluni/src/main/java/java/lang/ClassLoader.java
@@ -205,6 +205,7 @@
*/
private static ClassLoader createSystemClassLoader() {
String classPath = System.getProperty("java.class.path", ".");
+ String librarySearchPath = System.getProperty("java.library.path", "");
// String[] paths = classPath.split(":");
// URL[] urls = new URL[paths.length];
@@ -220,7 +221,7 @@
// return new java.net.URLClassLoader(urls, null);
// TODO Make this a java.net.URLClassLoader once we have those?
- return new PathClassLoader(classPath, BootClassLoader.getInstance());
+ return new PathClassLoader(classPath, librarySearchPath, BootClassLoader.getInstance());
}
// The packages defined in this class loader. Each package name is mapped
diff --git a/ojluni/src/main/java/java/lang/Integer.java b/ojluni/src/main/java/java/lang/Integer.java
index fe36907..3dbc2d5 100755
--- a/ojluni/src/main/java/java/lang/Integer.java
+++ b/ojluni/src/main/java/java/lang/Integer.java
@@ -480,7 +480,7 @@
*/
if (s == null) {
- throw new NumberFormatException("null");
+ throw new NumberFormatException("s == null");
}
if (radix < Character.MIN_RADIX) {
diff --git a/ojluni/src/main/java/java/lang/JavaLangAccess.java b/ojluni/src/main/java/java/lang/JavaLangAccess.java
index 20d673e..2779c60 100644
--- a/ojluni/src/main/java/java/lang/JavaLangAccess.java
+++ b/ojluni/src/main/java/java/lang/JavaLangAccess.java
@@ -35,13 +35,6 @@
/**
* @hide
*/
- public static int getStringHash32(String string) {
- return string.hash32();
- }
-
- /**
- * @hide
- */
public static <E extends Enum<E>>
E[] getEnumConstantsShared(Class<E> klass) {
return klass.getEnumConstantsShared();
diff --git a/ojluni/src/main/java/java/lang/Math.java b/ojluni/src/main/java/java/lang/Math.java
index 0e36ab7..4c82331 100755
--- a/ojluni/src/main/java/java/lang/Math.java
+++ b/ojluni/src/main/java/java/lang/Math.java
@@ -737,6 +737,399 @@
}
/**
+ * Returns the sum of its arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int addExact(int x, int y) {
+ int r = x + y;
+ // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+ if (((x ^ r) & (y ^ r)) < 0) {
+ throw new ArithmeticException("integer overflow");
+ }
+ return r;
+ }
+
+ /**
+ * Returns the sum of its arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long addExact(long x, long y) {
+ long r = x + y;
+ // HD 2-12 Overflow iff both arguments have the opposite sign of the result
+ if (((x ^ r) & (y ^ r)) < 0) {
+ throw new ArithmeticException("long overflow");
+ }
+ return r;
+ }
+
+ /**
+ * Returns the difference of the arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value to subtract from the first
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int subtractExact(int x, int y) {
+ int r = x - y;
+ // HD 2-12 Overflow iff the arguments have different signs and
+ // the sign of the result is different than the sign of x
+ if (((x ^ y) & (x ^ r)) < 0) {
+ throw new ArithmeticException("integer overflow");
+ }
+ return r;
+ }
+
+ /**
+ * Returns the difference of the arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value to subtract from the first
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long subtractExact(long x, long y) {
+ long r = x - y;
+ // HD 2-12 Overflow iff the arguments have different signs and
+ // the sign of the result is different than the sign of x
+ if (((x ^ y) & (x ^ r)) < 0) {
+ throw new ArithmeticException("long overflow");
+ }
+ return r;
+ }
+
+ /**
+ * Returns the product of the arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int multiplyExact(int x, int y) {
+ long r = (long)x * (long)y;
+ if ((int)r != r) {
+ throw new ArithmeticException("integer overflow");
+ }
+ return (int)r;
+ }
+
+ /**
+ * Returns the product of the arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long multiplyExact(long x, long y) {
+ long r = x * y;
+ long ax = Math.abs(x);
+ long ay = Math.abs(y);
+ if (((ax | ay) >>> 31 != 0)) {
+ // Some bits greater than 2^31 that might cause overflow
+ // Check the result using the divide operator
+ // and check for the special case of Long.MIN_VALUE * -1
+ if (((y != 0) && (r / y != x)) ||
+ (x == Long.MIN_VALUE && y == -1)) {
+ throw new ArithmeticException("long overflow");
+ }
+ }
+ return r;
+ }
+
+ /**
+ * Returns the argument incremented by one, throwing an exception if the
+ * result overflows an {@code int}.
+ *
+ * @param a the value to increment
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int incrementExact(int a) {
+ if (a == Integer.MAX_VALUE) {
+ throw new ArithmeticException("integer overflow");
+ }
+
+ return a + 1;
+ }
+
+ /**
+ * Returns the argument incremented by one, throwing an exception if the
+ * result overflows a {@code long}.
+ *
+ * @param a the value to increment
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long incrementExact(long a) {
+ if (a == Long.MAX_VALUE) {
+ throw new ArithmeticException("long overflow");
+ }
+
+ return a + 1L;
+ }
+
+ /**
+ * Returns the argument decremented by one, throwing an exception if the
+ * result overflows an {@code int}.
+ *
+ * @param a the value to decrement
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int decrementExact(int a) {
+ if (a == Integer.MIN_VALUE) {
+ throw new ArithmeticException("integer overflow");
+ }
+
+ return a - 1;
+ }
+
+ /**
+ * Returns the argument decremented by one, throwing an exception if the
+ * result overflows a {@code long}.
+ *
+ * @param a the value to decrement
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long decrementExact(long a) {
+ if (a == Long.MIN_VALUE) {
+ throw new ArithmeticException("long overflow");
+ }
+
+ return a - 1L;
+ }
+
+ /**
+ * Returns the negation of the argument, throwing an exception if the
+ * result overflows an {@code int}.
+ *
+ * @param a the value to negate
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @since 1.8
+ */
+ public static int negateExact(int a) {
+ if (a == Integer.MIN_VALUE) {
+ throw new ArithmeticException("integer overflow");
+ }
+
+ return -a;
+ }
+
+ /**
+ * Returns the negation of the argument, throwing an exception if the
+ * result overflows a {@code long}.
+ *
+ * @param a the value to negate
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @since 1.8
+ */
+ public static long negateExact(long a) {
+ if (a == Long.MIN_VALUE) {
+ throw new ArithmeticException("long overflow");
+ }
+
+ return -a;
+ }
+
+ /**
+ * Returns the value of the {@code long} argument;
+ * throwing an exception if the value overflows an {@code int}.
+ *
+ * @param value the long value
+ * @return the argument as an int
+ * @throws ArithmeticException if the {@code argument} overflows an int
+ * @since 1.8
+ */
+ public static int toIntExact(long value) {
+ if ((int)value != value) {
+ throw new ArithmeticException("integer overflow");
+ }
+ return (int)value;
+ }
+
+ /**
+ * Returns the largest (closest to positive infinity)
+ * {@code int} value that is less than or equal to the algebraic quotient.
+ * There is one special case, if the dividend is the
+ * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
+ * then integer overflow occurs and
+ * the result is equal to the {@code Integer.MIN_VALUE}.
+ * <p>
+ * Normal integer division operates under the round to zero rounding mode
+ * (truncation). This operation instead acts under the round toward
+ * negative infinity (floor) rounding mode.
+ * The floor rounding mode gives different results than truncation
+ * when the exact result is negative.
+ * <ul>
+ * <li>If the signs of the arguments are the same, the results of
+ * {@code floorDiv} and the {@code /} operator are the same. <br>
+ * For example, {@code floorDiv(4, 3) == 1} and {@code (4 / 3) == 1}.</li>
+ * <li>If the signs of the arguments are different, the quotient is negative and
+ * {@code floorDiv} returns the integer less than or equal to the quotient
+ * and the {@code /} operator returns the integer closest to zero.<br>
+ * For example, {@code floorDiv(-4, 3) == -2},
+ * whereas {@code (-4 / 3) == -1}.
+ * </li>
+ * </ul>
+ * <p>
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the largest (closest to positive infinity)
+ * {@code int} value that is less than or equal to the algebraic quotient.
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see #floorMod(int, int)
+ * @see #floor(double)
+ * @since 1.8
+ */
+ public static int floorDiv(int x, int y) {
+ int r = x / y;
+ // if the signs are different and modulo not zero, round down
+ if ((x ^ y) < 0 && (r * y != x)) {
+ r--;
+ }
+ return r;
+ }
+
+ /**
+ * Returns the largest (closest to positive infinity)
+ * {@code long} value that is less than or equal to the algebraic quotient.
+ * There is one special case, if the dividend is the
+ * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
+ * then integer overflow occurs and
+ * the result is equal to the {@code Long.MIN_VALUE}.
+ * <p>
+ * Normal integer division operates under the round to zero rounding mode
+ * (truncation). This operation instead acts under the round toward
+ * negative infinity (floor) rounding mode.
+ * The floor rounding mode gives different results than truncation
+ * when the exact result is negative.
+ * <p>
+ * For examples, see {@link #floorDiv(int, int)}.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the largest (closest to positive infinity)
+ * {@code long} value that is less than or equal to the algebraic quotient.
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see #floorMod(long, long)
+ * @see #floor(double)
+ * @since 1.8
+ */
+ public static long floorDiv(long x, long y) {
+ long r = x / y;
+ // if the signs are different and modulo not zero, round down
+ if ((x ^ y) < 0 && (r * y != x)) {
+ r--;
+ }
+ return r;
+ }
+
+ /**
+ * Returns the floor modulus of the {@code int} arguments.
+ * <p>
+ * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+ * has the same sign as the divisor {@code y}, and
+ * is in the range of {@code -abs(y) < r < +abs(y)}.
+ *
+ * <p>
+ * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+ * <ul>
+ * <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+ * </ul>
+ * <p>
+ * The difference in values between {@code floorMod} and
+ * the {@code %} operator is due to the difference between
+ * {@code floorDiv} that returns the integer less than or equal to the quotient
+ * and the {@code /} operator that returns the integer closest to zero.
+ * <p>
+ * Examples:
+ * <ul>
+ * <li>If the signs of the arguments are the same, the results
+ * of {@code floorMod} and the {@code %} operator are the same. <br>
+ * <ul>
+ * <li>{@code floorMod(4, 3) == 1}; and {@code (4 % 3) == 1}</li>
+ * </ul>
+ * <li>If the signs of the arguments are different, the results differ from the {@code %} operator.<br>
+ * <ul>
+ * <li>{@code floorMod(+4, -3) == -2}; and {@code (+4 % -3) == +1} </li>
+ * <li>{@code floorMod(-4, +3) == +2}; and {@code (-4 % +3) == -1} </li>
+ * <li>{@code floorMod(-4, -3) == -1}; and {@code (-4 % -3) == -1 } </li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>
+ * If the signs of arguments are unknown and a positive modulus
+ * is needed it can be computed as {@code (floorMod(x, y) + abs(y)) % abs(y)}.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see #floorDiv(int, int)
+ * @since 1.8
+ */
+ public static int floorMod(int x, int y) {
+ int r = x - floorDiv(x, y) * y;
+ return r;
+ }
+
+ /**
+ * Returns the floor modulus of the {@code long} arguments.
+ * <p>
+ * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+ * has the same sign as the divisor {@code y}, and
+ * is in the range of {@code -abs(y) < r < +abs(y)}.
+ *
+ * <p>
+ * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+ * <ul>
+ * <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+ * </ul>
+ * <p>
+ * For examples, see {@link #floorMod(int, int)}.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see #floorDiv(long, long)
+ * @since 1.8
+ */
+ public static long floorMod(long x, long y) {
+ return x - floorDiv(x, y) * y;
+ }
+
+ /**
* Returns the absolute value of an {@code int} value.
* If the argument is not negative, the argument is returned.
* If the argument is negative, the negation of the argument is returned.
@@ -1462,7 +1855,79 @@
public static float nextUp(float f) {
return sun.misc.FpUtils.nextUp(f);
}
+ /**
+ * Returns the floating-point value adjacent to {@code d} in
+ * the direction of negative infinity. This method is
+ * semantically equivalent to {@code nextAfter(d,
+ * Double.NEGATIVE_INFINITY)}; however, a
+ * {@code nextDown} implementation may run faster than its
+ * equivalent {@code nextAfter} call.
+ *
+ * <p>Special Cases:
+ * <ul>
+ * <li> If the argument is NaN, the result is NaN.
+ *
+ * <li> If the argument is negative infinity, the result is
+ * negative infinity.
+ *
+ * <li> If the argument is zero, the result is
+ * {@code -Double.MIN_VALUE}
+ *
+ * </ul>
+ *
+ * @param d starting floating-point value
+ * @return The adjacent floating-point value closer to negative
+ * infinity.
+ * @since 1.8
+ */
+ public static double nextDown(double d) {
+ if (Double.isNaN(d) || d == Double.NEGATIVE_INFINITY)
+ return d;
+ else {
+ if (d == 0.0)
+ return -Double.MIN_VALUE;
+ else
+ return Double.longBitsToDouble(Double.doubleToRawLongBits(d) +
+ ((d > 0.0d)?-1L:+1L));
+ }
+ }
+ /**
+ * Returns the floating-point value adjacent to {@code f} in
+ * the direction of negative infinity. This method is
+ * semantically equivalent to {@code nextAfter(f,
+ * Float.NEGATIVE_INFINITY)}; however, a
+ * {@code nextDown} implementation may run faster than its
+ * equivalent {@code nextAfter} call.
+ *
+ * <p>Special Cases:
+ * <ul>
+ * <li> If the argument is NaN, the result is NaN.
+ *
+ * <li> If the argument is negative infinity, the result is
+ * negative infinity.
+ *
+ * <li> If the argument is zero, the result is
+ * {@code -Float.MIN_VALUE}
+ *
+ * </ul>
+ *
+ * @param f starting floating-point value
+ * @return The adjacent floating-point value closer to negative
+ * infinity.
+ * @since 1.8
+ */
+ public static float nextDown(float f) {
+ if (Float.isNaN(f) || f == Float.NEGATIVE_INFINITY)
+ return f;
+ else {
+ if (f == 0.0f)
+ return -Float.MIN_VALUE;
+ else
+ return Float.intBitsToFloat(Float.floatToRawIntBits(f) +
+ ((f > 0.0f)?-1:+1));
+ }
+ }
/**
* Return {@code d} ×
diff --git a/ojluni/src/main/java/java/lang/Package.java b/ojluni/src/main/java/java/lang/Package.java
index 984317b..a4777c5 100755
--- a/ojluni/src/main/java/java/lang/Package.java
+++ b/ojluni/src/main/java/java/lang/Package.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 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
@@ -26,6 +26,7 @@
package java.lang;
+import java.lang.reflect.AnnotatedElement;
import java.io.InputStream;
import java.util.Enumeration;
@@ -48,12 +49,11 @@
import java.util.HashMap;
import java.util.Iterator;
-import java.lang.annotation.Annotation;
import sun.net.www.ParseUtil;
import sun.reflect.CallerSensitive;
import dalvik.system.VMStack;
-import libcore.reflect.AnnotatedElements;
+import java.lang.annotation.Annotation;
/**
* {@code Package} objects contain version information
@@ -357,17 +357,25 @@
* @return the string representation of the package.
*/
public String toString() {
- String spec = specTitle;
- String ver = specVersion;
- if (spec != null && spec.length() > 0)
- spec = ", " + spec;
- else
- spec = "";
- if (ver != null && ver.length() > 0)
- ver = ", version " + ver;
- else
- ver = "";
- return "package " + pkgName + spec + ver;
+ // Android changed: Several apps try to parse the output of toString(). This is a really
+ // bad idea - especially when there's a Package.getName() function as well as a
+ // Class.getName() function that can be used instead.
+ //
+ // *** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ***
+ //
+ // String spec = specTitle;
+ // String ver = specVersion;
+ // if (spec != null && spec.length() > 0)
+ // spec = ", " + spec;
+ // else
+ // spec = "";
+ // if (ver != null && ver.length() > 0)
+ // ver = ", version " + ver;
+ // else
+ // ver = "";
+ // return "package " + pkgName + spec + ver;
+
+ return "package " + pkgName;
}
private Class<?> getPackageInfo() {
@@ -393,11 +401,11 @@
/**
* @throws NullPointerException {@inheritDoc}
- * @since 1.5
+ * @since 1.8
*/
- public boolean isAnnotationPresent(
- Class<? extends Annotation> annotationClass) {
- return getPackageInfo().isAnnotationPresent(annotationClass);
+ @Override
+ public <A extends Annotation> A[] getAnnotationsByType(Class<A> annotationClass) {
+ return getPackageInfo().getAnnotationsByType(annotationClass);
}
/**
@@ -408,6 +416,24 @@
}
/**
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass) {
+ return getPackageInfo().getDeclaredAnnotation(annotationClass);
+ }
+
+ /**
+ * @throws NullPointerException {@inheritDoc}
+ * @since 1.8
+ */
+ @Override
+ public <A extends Annotation> A[] getDeclaredAnnotationsByType(Class<A> annotationClass) {
+ return getPackageInfo().getDeclaredAnnotationsByType(annotationClass);
+ }
+
+ /**
* @since 1.5
*/
public Annotation[] getDeclaredAnnotations() {
@@ -415,32 +441,6 @@
}
/**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
- return AnnotatedElements.getDeclaredAnnotationsByType(this, annotationClass);
- }
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
- return AnnotatedElements.getAnnotationsByType(this, annotationClass);
- }
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> Annotation getDeclaredAnnotation(Class<T> annotationClass) {
- return AnnotatedElements.getDeclaredAnnotation(this, annotationClass);
- }
- /**
* Construct a package instance with the specified version
* information.
* @param pkgName the name of the package
diff --git a/ojluni/src/main/java/java/lang/StrictMath.java b/ojluni/src/main/java/java/lang/StrictMath.java
index 23978ea..3023fc0 100755
--- a/ojluni/src/main/java/java/lang/StrictMath.java
+++ b/ojluni/src/main/java/java/lang/StrictMath.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -696,6 +696,211 @@
}
/**
+ * Returns the sum of its arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#addExact(int,int)
+ * @since 1.8
+ */
+ public static int addExact(int x, int y) {
+ return Math.addExact(x, y);
+ }
+
+ /**
+ * Returns the sum of its arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#addExact(long,long)
+ * @since 1.8
+ */
+ public static long addExact(long x, long y) {
+ return Math.addExact(x, y);
+ }
+
+ /**
+ * Returns the difference of the arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value to subtract from the first
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#subtractExact(int,int)
+ * @since 1.8
+ */
+ public static int subtractExact(int x, int y) {
+ return Math.subtractExact(x, y);
+ }
+
+ /**
+ * Returns the difference of the arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value to subtract from the first
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#subtractExact(long,long)
+ * @since 1.8
+ */
+ public static long subtractExact(long x, long y) {
+ return Math.subtractExact(x, y);
+ }
+
+ /**
+ * Returns the product of the arguments,
+ * throwing an exception if the result overflows an {@code int}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows an int
+ * @see Math#multiplyExact(int,int)
+ * @since 1.8
+ */
+ public static int multiplyExact(int x, int y) {
+ return Math.multiplyExact(x, y);
+ }
+
+ /**
+ * Returns the product of the arguments,
+ * throwing an exception if the result overflows a {@code long}.
+ *
+ * @param x the first value
+ * @param y the second value
+ * @return the result
+ * @throws ArithmeticException if the result overflows a long
+ * @see Math#multiplyExact(long,long)
+ * @since 1.8
+ */
+ public static long multiplyExact(long x, long y) {
+ return Math.multiplyExact(x, y);
+ }
+
+ /**
+ * Returns the value of the {@code long} argument;
+ * throwing an exception if the value overflows an {@code int}.
+ *
+ * @param value the long value
+ * @return the argument as an int
+ * @throws ArithmeticException if the {@code argument} overflows an int
+ * @see Math#toIntExact(long)
+ * @since 1.8
+ */
+ public static int toIntExact(long value) {
+ return Math.toIntExact(value);
+ }
+
+ /**
+ * Returns the largest (closest to positive infinity)
+ * {@code int} value that is less than or equal to the algebraic quotient.
+ * There is one special case, if the dividend is the
+ * {@linkplain Integer#MIN_VALUE Integer.MIN_VALUE} and the divisor is {@code -1},
+ * then integer overflow occurs and
+ * the result is equal to the {@code Integer.MIN_VALUE}.
+ * <p>
+ * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
+ * a comparison to the integer division {@code /} operator.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the largest (closest to positive infinity)
+ * {@code int} value that is less than or equal to the algebraic quotient.
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see Math#floorDiv(int, int)
+ * @see Math#floor(double)
+ * @since 1.8
+ */
+ public static int floorDiv(int x, int y) {
+ return Math.floorDiv(x, y);
+ }
+
+ /**
+ * Returns the largest (closest to positive infinity)
+ * {@code long} value that is less than or equal to the algebraic quotient.
+ * There is one special case, if the dividend is the
+ * {@linkplain Long#MIN_VALUE Long.MIN_VALUE} and the divisor is {@code -1},
+ * then integer overflow occurs and
+ * the result is equal to the {@code Long.MIN_VALUE}.
+ * <p>
+ * See {@link Math#floorDiv(int, int) Math.floorDiv} for examples and
+ * a comparison to the integer division {@code /} operator.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the largest (closest to positive infinity)
+ * {@code long} value that is less than or equal to the algebraic quotient.
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see Math#floorDiv(long, long)
+ * @see Math#floor(double)
+ * @since 1.8
+ */
+ public static long floorDiv(long x, long y) {
+ return Math.floorDiv(x, y);
+ }
+
+ /**
+ * Returns the floor modulus of the {@code int} arguments.
+ * <p>
+ * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+ * has the same sign as the divisor {@code y}, and
+ * is in the range of {@code -abs(y) < r < +abs(y)}.
+ * <p>
+ * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+ * <ul>
+ * <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+ * </ul>
+ * <p>
+ * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
+ * a comparison to the {@code %} operator.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see Math#floorMod(int, int)
+ * @see StrictMath#floorDiv(int, int)
+ * @since 1.8
+ */
+ public static int floorMod(int x, int y) {
+ return Math.floorMod(x , y);
+ }
+ /**
+ * Returns the floor modulus of the {@code long} arguments.
+ * <p>
+ * The floor modulus is {@code x - (floorDiv(x, y) * y)},
+ * has the same sign as the divisor {@code y}, and
+ * is in the range of {@code -abs(y) < r < +abs(y)}.
+ * <p>
+ * The relationship between {@code floorDiv} and {@code floorMod} is such that:
+ * <ul>
+ * <li>{@code floorDiv(x, y) * y + floorMod(x, y) == x}
+ * </ul>
+ * <p>
+ * See {@link Math#floorMod(int, int) Math.floorMod} for examples and
+ * a comparison to the {@code %} operator.
+ *
+ * @param x the dividend
+ * @param y the divisor
+ * @return the floor modulus {@code x - (floorDiv(x, y) * y)}
+ * @throws ArithmeticException if the divisor {@code y} is zero
+ * @see Math#floorMod(long, long)
+ * @see StrictMath#floorDiv(long, long)
+ * @since 1.8
+ */
+ public static long floorMod(long x, long y) {
+ return Math.floorMod(x, y);
+ }
+
+ /**
* Returns the absolute value of an {@code int} value..
* If the argument is not negative, the argument is returned.
* If the argument is negative, the negation of the argument is returned.
@@ -1397,6 +1602,63 @@
return sun.misc.FpUtils.nextUp(f);
}
+ /**
+ * Returns the floating-point value adjacent to {@code d} in
+ * the direction of negative infinity. This method is
+ * semantically equivalent to {@code nextAfter(d,
+ * Double.NEGATIVE_INFINITY)}; however, a
+ * {@code nextDown} implementation may run faster than its
+ * equivalent {@code nextAfter} call.
+ *
+ * <p>Special Cases:
+ * <ul>
+ * <li> If the argument is NaN, the result is NaN.
+ *
+ * <li> If the argument is negative infinity, the result is
+ * negative infinity.
+ *
+ * <li> If the argument is zero, the result is
+ * {@code -Double.MIN_VALUE}
+ *
+ * </ul>
+ *
+ * @param d starting floating-point value
+ * @return The adjacent floating-point value closer to negative
+ * infinity.
+ * @since 1.8
+ */
+ public static double nextDown(double d) {
+ return Math.nextDown(d);
+ }
+
+ /**
+ * Returns the floating-point value adjacent to {@code f} in
+ * the direction of negative infinity. This method is
+ * semantically equivalent to {@code nextAfter(f,
+ * Float.NEGATIVE_INFINITY)}; however, a
+ * {@code nextDown} implementation may run faster than its
+ * equivalent {@code nextAfter} call.
+ *
+ * <p>Special Cases:
+ * <ul>
+ * <li> If the argument is NaN, the result is NaN.
+ *
+ * <li> If the argument is negative infinity, the result is
+ * negative infinity.
+ *
+ * <li> If the argument is zero, the result is
+ * {@code -Float.MIN_VALUE}
+ *
+ * </ul>
+ *
+ * @param f starting floating-point value
+ * @return The adjacent floating-point value closer to negative
+ * infinity.
+ * @since 1.8
+ */
+ public static float nextDown(float f) {
+ return Math.nextDown(f);
+ }
/**
* Return {@code d} ×
diff --git a/ojluni/src/main/java/java/lang/String.java b/ojluni/src/main/java/java/lang/String.java
index 5023da8..8a83df9 100755
--- a/ojluni/src/main/java/java/lang/String.java
+++ b/ojluni/src/main/java/java/lang/String.java
@@ -37,6 +37,8 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
+
+import libcore.util.CharsetUtils;
import libcore.util.EmptyArray;
/**
@@ -857,7 +859,21 @@
* @since 1.6
*/
public byte[] getBytes(Charset charset) {
- if (charset == null) throw new NullPointerException();
+ if (charset == null) {
+ throw new NullPointerException("charset == null");
+ }
+
+ final String name = charset.name();
+ if ("UTF-8".equals(name)) {
+ return CharsetUtils.toUtf8Bytes(this, 0, count);
+ } else if ("ISO-8859-1".equals(name)) {
+ return CharsetUtils.toIsoLatin1Bytes(this, 0, count);
+ } else if ("US-ASCII".equals(name)) {
+ return CharsetUtils.toAsciiBytes(this, 0, count);
+ } else if ("UTF-16BE".equals(name)) {
+ return CharsetUtils.toBigEndianUtf16Bytes(this, 0, count);
+ }
+
return StringCoding.encode(charset, this);
}
@@ -1595,11 +1611,7 @@
* is the string being searched for.
*
* @param source the characters being searched.
- * @param sourceOffset offset of the source string.
- * @param sourceCount count of the source string.
* @param target the characters being searched for.
- * @param targetOffset offset of the target string.
- * @param targetCount count of the target string.
* @param fromIndex the index to begin searching from.
*/
static int indexOf(String source,
@@ -1998,29 +2010,18 @@
* occurrence of <code>oldChar</code> with <code>newChar</code>.
*/
public String replace(char oldChar, char newChar) {
+ String replaced = this;
if (oldChar != newChar) {
- int len = count;
- int i = -1;
-
- while (++i < len) {
+ for (int i = 0; i < count; ++i) {
if (charAt(i) == oldChar) {
- break;
+ if (replaced == this) {
+ replaced = StringFactory.newStringFromString(this);
+ }
+ replaced.setCharAt(i, newChar);
}
}
- if (i < len) {
- char buf[] = new char[len];
- for (int j = 0; j < i; j++) {
- buf[j] = charAt(j);
- }
- while (i < len) {
- char c = charAt(i);
- buf[i] = (c == oldChar) ? newChar : c;
- i++;
- }
- return StringFactory.newStringFromChars(buf);
- }
}
- return this;
+ return replaced;
}
/**
@@ -2167,8 +2168,60 @@
* @since 1.5
*/
public String replace(CharSequence target, CharSequence replacement) {
- return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(
- this).replaceAll(Matcher.quoteReplacement(replacement.toString()));
+ if (target == null) {
+ throw new NullPointerException("target == null");
+ }
+
+ if (replacement == null) {
+ throw new NullPointerException("replacement == null");
+ }
+
+ String replacementStr = replacement.toString();
+ String targetStr = target.toString();
+
+ // Special case when target == "". This is a pretty nonsensical transformation and nobody
+ // should be hitting this.
+ //
+ // See commit 870b23b3febc85 and http://code.google.com/p/android/issues/detail?id=8807
+ // An empty target is inserted at the start of the string, the end of the string and
+ // between all characters.
+ if (targetStr.isEmpty()) {
+ // Note that overallocates by |replacement.size()| if |this| is the empty string, but
+ // that should be a rare case within an already nonsensical case.
+ StringBuilder sb = new StringBuilder(replacementStr.length() * (count + 2) + count);
+ sb.append(replacementStr);
+ for (int i = 0; i < count; ++i) {
+ sb.append(charAt(i));
+ sb.append(replacementStr);
+ }
+
+ return sb.toString();
+ }
+
+ // This is the "regular" case.
+ int lastMatch = 0;
+ StringBuilder sb = null;
+ for (;;) {
+ int currentMatch = indexOf(this, targetStr, lastMatch);
+ if (currentMatch == -1) {
+ break;
+ }
+
+ if (sb == null) {
+ sb = new StringBuilder(count);
+ }
+
+ sb.append(this, lastMatch, currentMatch);
+ sb.append(replacementStr);
+ lastMatch = currentMatch + targetStr.count;
+ }
+
+ if (sb != null) {
+ sb.append(this, lastMatch, count);
+ return sb.toString();
+ } else {
+ return this;
+ }
}
/**
@@ -2252,61 +2305,12 @@
* @spec JSR-51
*/
public String[] split(String regex, int limit) {
- /* fastpath if the regex is a
- (1)one-char String and this character is not one of the
- RegEx's meta characters ".$|()[{^?*+\\", or
- (2)two-char String and the first char is the backslash and
- the second is not the ascii digit or ascii letter.
- */
- char ch = 0;
- if (((regex.count == 1 &&
- ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
- (regex.length() == 2 &&
- regex.charAt(0) == '\\' &&
- (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&
- ((ch-'a')|('z'-ch)) < 0 &&
- ((ch-'A')|('Z'-ch)) < 0)) &&
- (ch < Character.MIN_HIGH_SURROGATE ||
- ch > Character.MAX_LOW_SURROGATE))
- {
- int off = 0;
- int next = 0;
-
- int sepCount = 0;
- while (sepCount != limit-1 && (next = indexOf(ch, off)) != -1) {
- sepCount += 1;
- off = next + 1;
- }
- // If no match was found, return this
- if (off == 0) {
- return new String[]{this};
- }
-
- int end = count;
-
- // Remove trailing separators
- if (limit == 0 && off == end) {
- if (sepCount == end) {
- return EmptyArray.STRING;
- }
- while (charAt(off - 1) == ch) {
- --off;
- }
- sepCount -= count - off;
- end = off;
- }
-
- off = 0;
- String[] result = new String[sepCount + 1];
- for (int i = 0;i < sepCount; i++) {
- next = indexOf(ch, off);
- result[i] = substring(off, next);
- off = next + 1;
- }
-
- result[sepCount] = substring(off, end);
- return result;
+ // Try fast splitting without allocating Pattern object
+ String[] fast = Pattern.fastSplit(regex, this, limit);
+ if (fast != null) {
+ return fast;
}
+
return Pattern.compile(regex).split(this, limit);
}
@@ -2838,74 +2842,4 @@
* guaranteed to be from a pool of unique strings.
*/
public native String intern();
-
- /**
- * Seed value used for each alternative hash calculated.
- */
- private static int HASHING_SEED;
-
- private static int getHashingSeed() {
- long nanos = System.nanoTime();
- long now = System.currentTimeMillis();
- int SEED_MATERIAL[] = {
- System.identityHashCode(String.class),
- System.identityHashCode(System.class),
- (int) (nanos >>> 32),
- (int) nanos,
- (int) (now >>> 32),
- (int) now,
- (int) (System.nanoTime() >>> 2)
- };
-
- // Use murmur3 to scramble the seeding material.
- // Inline implementation to avoid loading classes
- int h1 = 0;
-
- // body
- for (int k1 : SEED_MATERIAL) {
- k1 *= 0xcc9e2d51;
- k1 = (k1 << 15) | (k1 >>> 17);
- k1 *= 0x1b873593;
-
- h1 ^= k1;
- h1 = (h1 << 13) | (h1 >>> 19);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- // tail (always empty, as body is always 32-bit chunks)
-
- // finalization
-
- h1 ^= SEED_MATERIAL.length * 4;
-
- // finalization mix force all bits of a hash block to avalanche
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
-
- HASHING_SEED = h1;
- return HASHING_SEED;
- }
-
- /**
- * Cached value of the alternative hashing algorithm result
- */
- // TODO(narayan): This adds a 4 byte overhead to all string objects. Is it
- // worth the trouble ? hash32() below has been changed not to cache the calculated
- // hash. This is likely to be expensive and needs further analysis.
- //
- // private transient int hash32 = 0;
-
- /**
- * Calculates a 32-bit hash value for this string.
- *
- * @return a 32-bit hash value for this string.
- */
- int hash32() {
- char[] value = new char[count];
- getChars(0, count, value, 0);
- return sun.misc.Hashing.murmur3_32(getHashingSeed(), value, 0, count);
- }
}
diff --git a/ojluni/src/main/java/java/lang/System.java b/ojluni/src/main/java/java/lang/System.java
index bd00e50..03b6bd2 100755
--- a/ojluni/src/main/java/java/lang/System.java
+++ b/ojluni/src/main/java/java/lang/System.java
@@ -938,19 +938,10 @@
VMRuntime runtime = VMRuntime.getRuntime();
Properties p = new Properties();
- String projectUrl = "http://www.android.com/";
- String projectName = "The Android Project";
-
+ // Set non-static properties.
p.put("java.boot.class.path", runtime.bootClassPath());
p.put("java.class.path", runtime.classPath());
- // None of these four are meaningful on Android, but these keys are guaranteed
- // to be present for System.getProperty. For java.class.version, we use the maximum
- // class file version that dx currently supports.
- p.put("java.class.version", "50.0");
- p.put("java.compiler", "");
- p.put("java.ext.dirs", "");
-
// TODO: does this make any sense? Should we just leave java.home unset?
String javaHome = getenv("JAVA_HOME");
if (javaHome == null) {
@@ -958,25 +949,8 @@
}
p.put("java.home", javaHome);
- p.put("java.specification.name", "Dalvik Core Library");
- p.put("java.specification.vendor", projectName);
- p.put("java.specification.version", "0.9");
-
- p.put("java.vendor", projectName);
- p.put("java.vendor.url", projectUrl);
- p.put("java.vm.name", "Dalvik");
- p.put("java.vm.specification.name", "Dalvik Virtual Machine Specification");
- p.put("java.vm.specification.vendor", projectName);
- p.put("java.vm.specification.version", "0.9");
- p.put("java.vm.vendor", projectName);
p.put("java.vm.version", runtime.vmVersion());
- p.put("java.vm.vendor.url", projectUrl);
-
- p.put("java.net.preferIPv6Addresses", "false");
-
- p.put("file.encoding", "UTF-8");
-
try {
StructPasswd passwd = Libcore.os.getpwuid(Libcore.os.getuid());
p.put("user.name", passwd.pw_name);
@@ -986,7 +960,11 @@
StructUtsname info = Libcore.os.uname();
p.put("os.arch", info.machine);
- p.put("os.name", info.sysname);
+ if (p.get("os.name") != null && !p.get("os.name").equals(info.sysname)) {
+ logE("Wrong compile-time assumption for os.name: " + p.get("os.name") + " vs " +
+ info.sysname);
+ p.put("os.name", info.sysname);
+ }
p.put("os.version", info.release);
// Undocumented Android-only properties.
@@ -1003,24 +981,24 @@
parsePropertyAssignments(p, specialProperties());
// Override built-in properties with settings from the command line.
+ // Note: it is not possible to override hardcoded values.
parsePropertyAssignments(p, runtime.properties());
- if (p.containsKey("file.separator")) {
- logE("Ignoring command line argument: -Dfile.separator");
- }
- if (p.containsKey("line.separator")) {
- logE("Ignoring command line argument: -Dline.separator");
+ // Set static hardcoded properties.
+ // These come last, as they must be guaranteed to agree with what a backend compiler
+ // may assume when compiling the boot image on Android.
+ for (String[] pair : AndroidHardcodedSystemProperties.STATIC_PROPERTIES) {
+ if (p.containsKey(pair[0])) {
+ logE("Ignoring command line argument: -D" + pair[0]);
+ }
+ if (pair[1] == null) {
+ p.remove(pair[0]);
+ } else {
+ p.put(pair[0], pair[1]);
+ }
}
- if (p.containsKey("path.separator")) {
- logE("Ignoring command line argument: -Dpath.separator");
- }
-
- p.put("file.separator", "/");
- p.put("line.separator", "\n");
- p.put("path.separator", ":");
-
return p;
}
@@ -1094,92 +1072,54 @@
/**
* Determines the current system properties.
- * <p>
- * First, if there is a security manager, its
- * <code>checkPropertiesAccess</code> method is called with no
- * arguments. This may result in a security exception.
- * <p>
- * The current set of system properties for use by the
- * {@link #getProperty(String)} method is returned as a
- * <code>Properties</code> object. If there is no current set of
- * system properties, a set of system properties is first created and
- * initialized. This set of system properties always includes values
- * for the following keys:
- * <table summary="Shows property keys and associated values">
- * <tr><th>Key</th>
- * <th>Description of Associated Value</th></tr>
- * <tr><td><code>java.version</code></td>
- * <td>Java Runtime Environment version</td></tr>
- * <tr><td><code>java.vendor</code></td>
- * <td>Java Runtime Environment vendor</td></tr
- * <tr><td><code>java.vendor.url</code></td>
- * <td>Java vendor URL</td></tr>
- * <tr><td><code>java.home</code></td>
- * <td>Java installation directory</td></tr>
- * <tr><td><code>java.vm.specification.version</code></td>
- * <td>Java Virtual Machine specification version</td></tr>
- * <tr><td><code>java.vm.specification.vendor</code></td>
- * <td>Java Virtual Machine specification vendor</td></tr>
- * <tr><td><code>java.vm.specification.name</code></td>
- * <td>Java Virtual Machine specification name</td></tr>
- * <tr><td><code>java.vm.version</code></td>
- * <td>Java Virtual Machine implementation version</td></tr>
- * <tr><td><code>java.vm.vendor</code></td>
- * <td>Java Virtual Machine implementation vendor</td></tr>
- * <tr><td><code>java.vm.name</code></td>
- * <td>Java Virtual Machine implementation name</td></tr>
- * <tr><td><code>java.specification.version</code></td>
- * <td>Java Runtime Environment specification version</td></tr>
- * <tr><td><code>java.specification.vendor</code></td>
- * <td>Java Runtime Environment specification vendor</td></tr>
- * <tr><td><code>java.specification.name</code></td>
- * <td>Java Runtime Environment specification name</td></tr>
- * <tr><td><code>java.class.version</code></td>
- * <td>Java class format version number</td></tr>
- * <tr><td><code>java.class.path</code></td>
- * <td>Java class path</td></tr>
- * <tr><td><code>java.library.path</code></td>
- * <td>List of paths to search when loading libraries</td></tr>
- * <tr><td><code>java.io.tmpdir</code></td>
- * <td>Default temp file path</td></tr>
- * <tr><td><code>java.compiler</code></td>
- * <td>Name of JIT compiler to use</td></tr>
- * <tr><td><code>java.ext.dirs</code></td>
- * <td>Path of extension directory or directories</td></tr>
- * <tr><td><code>os.name</code></td>
- * <td>Operating system name</td></tr>
- * <tr><td><code>os.arch</code></td>
- * <td>Operating system architecture</td></tr>
- * <tr><td><code>os.version</code></td>
- * <td>Operating system version</td></tr>
- * <tr><td><code>file.separator</code></td>
- * <td>File separator ("/" on UNIX)</td></tr>
- * <tr><td><code>path.separator</code></td>
- * <td>Path separator (":" on UNIX)</td></tr>
- * <tr><td><code>line.separator</code></td>
- * <td>Line separator ("\n" on UNIX)</td></tr>
- * <tr><td><code>user.name</code></td>
- * <td>User's account name</td></tr>
- * <tr><td><code>user.home</code></td>
- * <td>User's home directory</td></tr>
- * <tr><td><code>user.dir</code></td>
- * <td>User's current working directory</td></tr>
+ *
+ *
+ * <p>The following properties are always provided by the Dalvik VM:</p>
+ * <p><table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+ * <tr BGCOLOR="#CCCCFF" CLASS="TableHeadingColor">
+ * <td><b>Name</b></td> <td><b>Meaning</b></td> <td><b>Example</b></td></tr>
+ * <tr><td>file.separator</td> <td>{@link java.io.File#separator}</td> <td>{@code /}</td></tr>
+ *
+ * <tr><td>java.class.path</td> <td>System class path</td> <td>{@code .}</td></tr>
+ * <tr><td>java.class.version</td> <td>(Not useful on Android)</td> <td>{@code 50.0}</td></tr>
+ * <tr><td>java.compiler</td> <td>(Not useful on Android)</td> <td>Empty</td></tr>
+ * <tr><td>java.ext.dirs</td> <td>(Not useful on Android)</td> <td>Empty</td></tr>
+ * <tr><td>java.home</td> <td>Location of the VM on the file system</td> <td>{@code /system}</td></tr>
+ * <tr><td>java.io.tmpdir</td> <td>See {@link java.io.File#createTempFile}</td> <td>{@code /sdcard}</td></tr>
+ * <tr><td>java.library.path</td> <td>Search path for JNI libraries</td> <td>{@code /vendor/lib:/system/lib}</td></tr>
+ * <tr><td>java.vendor</td> <td>Human-readable VM vendor</td> <td>{@code The Android Project}</td></tr>
+ * <tr><td>java.vendor.url</td> <td>URL for VM vendor's web site</td> <td>{@code http://www.android.com/}</td></tr>
+ * <tr><td>java.version</td> <td>(Not useful on Android)</td> <td>{@code 0}</td></tr>
+ *
+ * <tr><td>java.specification.version</td> <td>VM libraries version</td> <td>{@code 0.9}</td></tr>
+ * <tr><td>java.specification.vendor</td> <td>VM libraries vendor</td> <td>{@code The Android Project}</td></tr>
+ * <tr><td>java.specification.name</td> <td>VM libraries name</td> <td>{@code Dalvik Core Library}</td></tr>
+ * <tr><td>java.vm.version</td> <td>VM implementation version</td> <td>{@code 1.2.0}</td></tr>
+ * <tr><td>java.vm.vendor</td> <td>VM implementation vendor</td> <td>{@code The Android Project}</td></tr>
+ * <tr><td>java.vm.name</td> <td>VM implementation name</td> <td>{@code Dalvik}</td></tr>
+ * <tr><td>java.vm.specification.version</td> <td>VM specification version</td> <td>{@code 0.9}</td></tr>
+ * <tr><td>java.vm.specification.vendor</td> <td>VM specification vendor</td> <td>{@code The Android Project}</td></tr>
+ * <tr><td>java.vm.specification.name</td> <td>VM specification name</td> <td>{@code Dalvik Virtual Machine Specification}</td></tr>
+ *
+ * <tr><td>line.separator</td> <td>The system line separator</td> <td>{@code \n}</td></tr>
+ *
+ * <tr><td>os.arch</td> <td>OS architecture</td> <td>{@code armv7l}</td></tr>
+ * <tr><td>os.name</td> <td>OS (kernel) name</td> <td>{@code Linux}</td></tr>
+ * <tr><td>os.version</td> <td>OS (kernel) version</td> <td>{@code 2.6.32.9-g103d848}</td></tr>
+ *
+ * <tr><td>path.separator</td> <td>See {@link java.io.File#pathSeparator}</td> <td>{@code :}</td></tr>
+ *
+ * <tr><td>user.dir</td> <td>Base of non-absolute paths</td> <td>{@code /}</td></tr>
+ * <tr><td>user.home</td> <td>(Not useful on Android)</td> <td>Empty</td></tr>
+ * <tr><td>user.name</td> <td>(Not useful on Android)</td> <td>Empty</td></tr>
+ *
* </table>
* <p>
* Multiple paths in a system property value are separated by the path
* separator character of the platform.
- * <p>
- * Note that even if the security manager does not permit the
- * <code>getProperties</code> operation, it may choose to permit the
- * {@link #getProperty(String)} operation.
*
* @return the system properties
- * @exception SecurityException if a security manager exists and its
- * <code>checkPropertiesAccess</code> method doesn't allow access
- * to the system properties.
* @see #setProperties
- * @see java.lang.SecurityException
- * @see java.lang.SecurityManager#checkPropertiesAccess()
* @see java.util.Properties
*/
public static Properties getProperties() {
@@ -1220,11 +1160,7 @@
/**
* Gets the system property indicated by the specified key.
- * <p>
- * First, if there is a security manager, its
- * <code>checkPropertyAccess</code> method is called with the key as
- * its argument. This may result in a SecurityException.
- * <p>
+ *
* If there is no current set of system properties, a set of system
* properties is first created and initialized in the same manner as
* for the <code>getProperties</code> method.
@@ -1233,15 +1169,10 @@
* @return the string value of the system property,
* or <code>null</code> if there is no property with that key.
*
- * @exception SecurityException if a security manager exists and its
- * <code>checkPropertyAccess</code> method doesn't allow
- * access to the specified system property.
* @exception NullPointerException if <code>key</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #setProperty
- * @see java.lang.SecurityException
- * @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperties()
*/
public static String getProperty(String key) {
@@ -1266,14 +1197,10 @@
* @return the string value of the system property,
* or the default value if there is no property with that key.
*
- * @exception SecurityException if a security manager exists and its
- * <code>checkPropertyAccess</code> method doesn't allow
- * access to the specified system property.
* @exception NullPointerException if <code>key</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #setProperty
- * @see java.lang.SecurityManager#checkPropertyAccess(java.lang.String)
* @see java.lang.System#getProperties()
*/
public static String getProperty(String key, String def) {
@@ -1284,31 +1211,18 @@
/**
* Sets the system property indicated by the specified key.
- * <p>
- * First, if a security manager exists, its
- * <code>SecurityManager.checkPermission</code> method
- * is called with a <code>PropertyPermission(key, "write")</code>
- * permission. This may result in a SecurityException being thrown.
- * If no exception is thrown, the specified property is set to the given
- * value.
- * <p>
*
* @param key the name of the system property.
* @param value the value of the system property.
* @return the previous value of the system property,
* or <code>null</code> if it did not have one.
*
- * @exception SecurityException if a security manager exists and its
- * <code>checkPermission</code> method doesn't allow
- * setting of the specified property.
* @exception NullPointerException if <code>key</code> or
* <code>value</code> is <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #getProperty
* @see java.lang.System#getProperty(java.lang.String)
* @see java.lang.System#getProperty(java.lang.String, java.lang.String)
- * @see java.util.PropertyPermission
- * @see SecurityManager#checkPermission
* @since 1.2
*/
public static String setProperty(String key, String value) {
@@ -1319,29 +1233,17 @@
/**
* Removes the system property indicated by the specified key.
- * <p>
- * First, if a security manager exists, its
- * <code>SecurityManager.checkPermission</code> method
- * is called with a <code>PropertyPermission(key, "write")</code>
- * permission. This may result in a SecurityException being thrown.
- * If no exception is thrown, the specified property is removed.
- * <p>
*
* @param key the name of the system property to be removed.
* @return the previous string value of the system property,
* or <code>null</code> if there was no property with that key.
*
- * @exception SecurityException if a security manager exists and its
- * <code>checkPropertyAccess</code> method doesn't allow
- * access to the specified system property.
* @exception NullPointerException if <code>key</code> is
* <code>null</code>.
* @exception IllegalArgumentException if <code>key</code> is empty.
* @see #getProperty
* @see #setProperty
* @see java.util.Properties
- * @see java.lang.SecurityException
- * @see java.lang.SecurityManager#checkPropertiesAccess()
* @since 1.5
*/
public static String clearProperty(String key) {
diff --git a/ojluni/src/main/java/java/lang/Thread.java b/ojluni/src/main/java/java/lang/Thread.java
index c14022b..1436dd4 100755
--- a/ojluni/src/main/java/java/lang/Thread.java
+++ b/ojluni/src/main/java/java/lang/Thread.java
@@ -395,53 +395,6 @@
* zero to indicate that this parameter is to be ignored.
*/
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
- // Android changed : Reimplemented.
- /*
- if (name == null) {
- throw new NullPointerException("name cannot be null");
- }
-
- Thread parent = currentThread();
- SecurityManager security = System.getSecurityManager();
- if (g == null) {
- // Determine if it's an applet or not
-
- // If there is a security manager, ask the security manager what to do.
- if (security != null) {
- g = security.getThreadGroup();
- }
-
- // If the security doesn't have a strong opinion of the matter
- // use the parent thread group.
- if (g == null) {
- g = parent.getThreadGroup();
- }
- }
-
- // checkAccess regardless of whether or not threadgroup is explicitly passed in.
- g.checkAccess();
-
- // Do we have the required permissions?
- if (security != null) {
- if (isCCLOverridden(getClass())) {
- security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
- }
- }
- if (g == null) {
- g = parent.getThreadGroup();
- }
- g.checkAccess();
- this.daemon = parent.isDaemon();
- this.priority = parent.getPriority();
- this.name = name.toCharArray();
- if (security == null || isCCLOverridden(parent.getClass()))
- this.contextClassLoader = parent.getContextClassLoader();
- else
- this.contextClassLoader = parent.contextClassLoader;
- tid = nextThreadID();
- */
- // ----- END android -----
-
Thread parent = currentThread();
if (g == null) {
g = parent.getThreadGroup();
@@ -574,7 +527,12 @@
if (name == null) {
name = "Thread-" + nextThreadNum();
}
- setName(name);
+
+ // NOTE: Resist the temptation to call setName() here. This constructor is only called
+ // by the runtime to construct peers for threads that have attached via JNI and it's
+ // undesirable to clobber their natively set name.
+ this.name = name;
+
this.priority = priority;
this.daemon = daemon;
init2(currentThread());
diff --git a/ojluni/src/main/java/java/lang/reflect/AccessibleObject.java b/ojluni/src/main/java/java/lang/reflect/AccessibleObject.java
index 7295c6f..1fbf178 100755
--- a/ojluni/src/main/java/java/lang/reflect/AccessibleObject.java
+++ b/ojluni/src/main/java/java/lang/reflect/AccessibleObject.java
@@ -174,15 +174,6 @@
}
/**
- * @throws NullPointerException {@inheritDoc}
- * @since 1.5
- */
- public boolean isAnnotationPresent(
- Class<? extends Annotation> annotationClass) {
- return getAnnotation(annotationClass) != null;
- }
-
- /**
* @since 1.5
*/
public Annotation[] getAnnotations() {
@@ -195,31 +186,4 @@
public Annotation[] getDeclaredAnnotations() {
throw new AssertionError("All subclasses should override this method");
}
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
- return AnnotatedElements.getDeclaredAnnotationsByType(this, annotationClass);
- }
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
- return AnnotatedElements.getAnnotationsByType(this, annotationClass);
- }
-
- /**
- * {@inheritDoc}
- * @since 1.8
- */
- @Override
- public <T extends Annotation> Annotation getDeclaredAnnotation(Class<T> annotationClass) {
- return AnnotatedElements.getDeclaredAnnotation(this, annotationClass);
- }
}
diff --git a/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java b/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
index 724b70b..9d2158c 100755
--- a/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
+++ b/ojluni/src/main/java/java/lang/reflect/AnnotatedElement.java
@@ -27,7 +27,7 @@
package java.lang.reflect;
import java.lang.annotation.Annotation;
-// import libcore.reflect.AnnotatedElements;
+import libcore.reflect.AnnotatedElements;
/**
* Represents an annotated element of the program currently running in this
@@ -73,8 +73,9 @@
* @throws NullPointerException if the given annotation class is null
* @since 1.5
*/
- /*default*/ boolean isAnnotationPresent(Class<? extends Annotation> annotationClass);
- // { return getAnnotation(annotationClass) != null; }
+ default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
+ return getAnnotation(annotationClass) != null;
+ }
/**
* Returns this element's annotation for the specified type if
@@ -119,8 +120,9 @@
*
* @since 1.8
*/
- /*default*/ <T extends Annotation> Annotation getDeclaredAnnotation(Class<T> annotationClass);
- // { return AnnotatedElements.getDeclaredAnnotation(this, annotationClass); }
+ default <T extends Annotation> Annotation getDeclaredAnnotation(Class<T> annotationClass) {
+ return AnnotatedElements.getDeclaredAnnotation(this, annotationClass);
+ }
/**
* Returns a directly or indirectly present list of annotations on {@code this} element,
@@ -128,8 +130,9 @@
*
* @since 1.8
*/
- /*default*/ <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass);
- // { return AnnotatedElements.getDeclaredAnnotationsByType(this, annotationClass); }
+ default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
+ return AnnotatedElements.getDeclaredAnnotationsByType(this, annotationClass);
+ }
/**
* Returns an associated list of annotations on {@code this} element,
@@ -137,6 +140,7 @@
*
* @since 1.8
*/
- /*default*/ <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass);
- // { return AnnotatedElements.getAnnotationsByType(this, annotationClass); }
+ default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
+ return AnnotatedElements.getAnnotationsByType(this, annotationClass);
+ }
}
diff --git a/ojluni/src/main/java/java/lang/reflect/Constructor.java b/ojluni/src/main/java/java/lang/reflect/Constructor.java
index 9632f54..9742f0c 100755
--- a/ojluni/src/main/java/java/lang/reflect/Constructor.java
+++ b/ojluni/src/main/java/java/lang/reflect/Constructor.java
@@ -29,7 +29,6 @@
import sun.reflect.CallerSensitive;
import java.util.Comparator;
import java.util.List;
-import libcore.reflect.AnnotationAccess;
import libcore.reflect.Types;
import java.lang.annotation.Annotation;
diff --git a/ojluni/src/main/java/java/lang/reflect/Field.java b/ojluni/src/main/java/java/lang/reflect/Field.java
index 28cc6d8..315b1ed 100755
--- a/ojluni/src/main/java/java/lang/reflect/Field.java
+++ b/ojluni/src/main/java/java/lang/reflect/Field.java
@@ -31,7 +31,6 @@
import java.lang.annotation.Annotation;
import java.util.Map;
import com.android.dex.Dex;
-import libcore.reflect.AnnotationAccess;
import libcore.reflect.GenericSignatureParser;
import java.util.List;
@@ -181,7 +180,7 @@
}
StringBuilder result = new StringBuilder();
for (String s : annotation) {
- result.append(s);
+ result.append(s);
}
return result.toString();
}
diff --git a/ojluni/src/main/java/java/lang/reflect/Method.java b/ojluni/src/main/java/java/lang/reflect/Method.java
index d29e3e8..8ee7bd5 100755
--- a/ojluni/src/main/java/java/lang/reflect/Method.java
+++ b/ojluni/src/main/java/java/lang/reflect/Method.java
@@ -32,7 +32,6 @@
import com.android.dex.Dex;
import java.util.Comparator;
import java.util.List;
-import libcore.reflect.AnnotationAccess;
import libcore.reflect.Types;
/**
@@ -194,14 +193,6 @@
return super.getParameterTypes();
}
- @Override public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
- if (annotationType == null) {
- throw new NullPointerException("annotationType == null");
- }
- return isAnnotationPresentNative(annotationType);
- }
- private native boolean isAnnotationPresentNative(Class<? extends Annotation> annotationType);
-
/**
* Returns an array of {@code Type} objects that represent the formal
* parameter types, in declaration order, of the method represented by
@@ -556,11 +547,6 @@
}
/**
- * @since 1.5
- */
- @Override public native Annotation[] getDeclaredAnnotations();
-
- /**
* @throws NullPointerException {@inheritDoc}
* @since 1.5
*/
diff --git a/ojluni/src/main/java/java/net/HttpURLConnection.java b/ojluni/src/main/java/java/net/HttpURLConnection.java
index f88e9ef..9217aff 100755
--- a/ojluni/src/main/java/java/net/HttpURLConnection.java
+++ b/ojluni/src/main/java/java/net/HttpURLConnection.java
@@ -36,22 +36,241 @@
* details.
* <p>
*
- * Each HttpURLConnection instance is used to make a single request
- * but the underlying network connection to the HTTP server may be
- * transparently shared by other instances. Calling the close() methods
- * on the InputStream or OutputStream of an HttpURLConnection
- * after a request may free network resources associated with this
- * instance but has no effect on any shared persistent connection.
- * Calling the disconnect() method may close the underlying socket
- * if a persistent connection is otherwise idle at that time.
+ * <p>Uses of this class follow a pattern:
+ * <ol>
+ * <li>Obtain a new {@code HttpURLConnection} by calling {@link
+ * URL#openConnection() URL.openConnection()} and casting the result to
+ * {@code HttpURLConnection}.
+ * <li>Prepare the request. The primary property of a request is its URI.
+ * Request headers may also include metadata such as credentials, preferred
+ * content types, and session cookies.
+ * <li>Optionally upload a request body. Instances must be configured with
+ * {@link #setDoOutput(boolean) setDoOutput(true)} if they include a
+ * request body. Transmit data by writing to the stream returned by {@link
+ * #getOutputStream()}.
+ * <li>Read the response. Response headers typically include metadata such as
+ * the response body's content type and length, modified dates and session
+ * cookies. The response body may be read from the stream returned by {@link
+ * #getInputStream()}. If the response has no body, that method returns an
+ * empty stream.
+ * <li>Disconnect. Once the response body has been read, the {@code
+ * HttpURLConnection} should be closed by calling {@link #disconnect()}.
+ * Disconnecting releases the resources held by a connection so they may
+ * be closed or reused.
+ * </ol>
*
- * <P>The HTTP protocol handler has a few settings that can be accessed through
- * System Properties. This covers
- * <a href="doc-files/net-properties.html#Proxies">Proxy settings</a> as well as
- * <a href="doc-files/net-properties.html#MiscHTTP"> various other settings</a>.
- * </P>
+ * <p>For example, to retrieve the webpage at {@code http://www.android.com/}:
+ * <pre> {@code
+ * URL url = new URL("http://www.android.com/");
+ * HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ * try {
+ * InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ * readStream(in);
+ * } finally {
+ * urlConnection.disconnect();
+ * }
+ * }</pre>
*
- * @see java.net.HttpURLConnection#disconnect()
+ * <h3>Secure Communication with HTTPS</h3>
+ * Calling {@link URL#openConnection()} on a URL with the "https"
+ * scheme will return an {@code HttpsURLConnection}, which allows for
+ * overriding the default {@link javax.net.ssl.HostnameVerifier
+ * HostnameVerifier} and {@link javax.net.ssl.SSLSocketFactory
+ * SSLSocketFactory}. An application-supplied {@code SSLSocketFactory}
+ * created from an {@link javax.net.ssl.SSLContext SSLContext} can
+ * provide a custom {@link javax.net.ssl.X509TrustManager
+ * X509TrustManager} for verifying certificate chains and a custom
+ * {@link javax.net.ssl.X509KeyManager X509KeyManager} for supplying
+ * client certificates. See {@link javax.net.ssl.HttpsURLConnection
+ * HttpsURLConnection} for more details.
+ *
+ * <h3>Response Handling</h3>
+ * {@code HttpURLConnection} will follow up to five HTTP redirects. It will
+ * follow redirects from one origin server to another. This implementation
+ * doesn't follow redirects from HTTPS to HTTP or vice versa.
+ *
+ * <p>If the HTTP response indicates that an error occurred, {@link
+ * #getInputStream()} will throw an {@link IOException}. Use {@link
+ * #getErrorStream()} to read the error response. The headers can be read in
+ * the normal way using {@link #getHeaderFields()},
+ *
+ * <h3>Posting Content</h3>
+ * To upload data to a web server, configure the connection for output using
+ * {@link #setDoOutput(boolean) setDoOutput(true)}.
+ *
+ * <p>For best performance, you should call either {@link
+ * #setFixedLengthStreamingMode(int)} when the body length is known in advance,
+ * or {@link #setChunkedStreamingMode(int)} when it is not. Otherwise {@code
+ * HttpURLConnection} will be forced to buffer the complete request body in
+ * memory before it is transmitted, wasting (and possibly exhausting) heap and
+ * increasing latency.
+ *
+ * <p>For example, to perform an upload: <pre> {@code
+ * HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ * try {
+ * urlConnection.setDoOutput(true);
+ * urlConnection.setChunkedStreamingMode(0);
+ *
+ * OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
+ * writeStream(out);
+ *
+ * InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ * readStream(in);
+ * } finally {
+ * urlConnection.disconnect();
+ * }
+ * }</pre>
+ *
+ * <h3>Performance</h3>
+ * The input and output streams returned by this class are <strong>not
+ * buffered</strong>. Most callers should wrap the returned streams with {@link
+ * java.io.BufferedInputStream BufferedInputStream} or {@link
+ * java.io.BufferedOutputStream BufferedOutputStream}. Callers that do only bulk
+ * reads or writes may omit buffering.
+ *
+ * <p>When transferring large amounts of data to or from a server, use streams
+ * to limit how much data is in memory at once. Unless you need the entire
+ * body to be in memory at once, process it as a stream (rather than storing
+ * the complete body as a single byte array or string).
+ *
+ * <p>To reduce latency, this class may reuse the same underlying {@code Socket}
+ * for multiple request/response pairs. As a result, HTTP connections may be
+ * held open longer than necessary. Calls to {@link #disconnect()} may return
+ * the socket to a pool of connected sockets. This behavior can be disabled by
+ * setting the {@code http.keepAlive} system property to {@code false} before
+ * issuing any HTTP requests. The {@code http.maxConnections} property may be
+ * used to control how many idle connections to each server will be held.
+ *
+ * <p>By default, this implementation of {@code HttpURLConnection} requests that
+ * servers use gzip compression and it automatically decompresses the data for
+ * callers of {@link #getInputStream()}. The Content-Encoding and Content-Length
+ * response headers are cleared in this case. Gzip compression can be disabled by
+ * setting the acceptable encodings in the request header: <pre> {@code
+ * urlConnection.setRequestProperty("Accept-Encoding", "identity");
+ * }</pre>
+ *
+ * <p>Setting the Accept-Encoding request header explicitly disables automatic
+ * decompression and leaves the response headers intact; callers must handle
+ * decompression as needed, according to the Content-Encoding header of the
+ * response.
+ *
+ * <p>{@link #getContentLength()} returns the number of bytes transmitted and
+ * cannot be used to predict how many bytes can be read from
+ * {@link #getInputStream()} for compressed streams. Instead, read that stream
+ * until it is exhausted, i.e. when {@link InputStream#read} returns -1.
+ *
+ * <h3>Handling Network Sign-On</h3>
+ * Some Wi-Fi networks block Internet access until the user clicks through a
+ * sign-on page. Such sign-on pages are typically presented by using HTTP
+ * redirects. You can use {@link #getURL()} to test if your connection has been
+ * unexpectedly redirected. This check is not valid until <strong>after</strong>
+ * the response headers have been received, which you can trigger by calling
+ * {@link #getHeaderFields()} or {@link #getInputStream()}. For example, to
+ * check that a response was not redirected to an unexpected host:
+ * <pre> {@code
+ * HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ * try {
+ * InputStream in = new BufferedInputStream(urlConnection.getInputStream());
+ * if (!url.getHost().equals(urlConnection.getURL().getHost())) {
+ * // we were redirected! Kick the user out to the browser to sign on?
+ * }
+ * ...
+ * } finally {
+ * urlConnection.disconnect();
+ * }
+ * }</pre>
+ *
+ * <h3>HTTP Authentication</h3>
+ * {@code HttpURLConnection} supports <a
+ * href="http://www.ietf.org/rfc/rfc2617">HTTP basic authentication</a>. Use
+ * {@link Authenticator} to set the VM-wide authentication handler:
+ * <pre> {@code
+ * Authenticator.setDefault(new Authenticator() {
+ * protected PasswordAuthentication getPasswordAuthentication() {
+ * return new PasswordAuthentication(username, password.toCharArray());
+ * }
+ * });
+ * }</pre>
+ * Unless paired with HTTPS, this is <strong>not</strong> a secure mechanism for
+ * user authentication. In particular, the username, password, request and
+ * response are all transmitted over the network without encryption.
+ *
+ * <h3>Sessions with Cookies</h3>
+ * To establish and maintain a potentially long-lived session between client
+ * and server, {@code HttpURLConnection} includes an extensible cookie manager.
+ * Enable VM-wide cookie management using {@link CookieHandler} and {@link
+ * CookieManager}: <pre> {@code
+ * CookieManager cookieManager = new CookieManager();
+ * CookieHandler.setDefault(cookieManager);
+ * }</pre>
+ * By default, {@code CookieManager} accepts cookies from the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a> only. Two other policies are included: {@link
+ * CookiePolicy#ACCEPT_ALL} and {@link CookiePolicy#ACCEPT_NONE}. Implement
+ * {@link CookiePolicy} to define a custom policy.
+ *
+ * <p>The default {@code CookieManager} keeps all accepted cookies in memory. It
+ * will forget these cookies when the VM exits. Implement {@link CookieStore} to
+ * define a custom cookie store.
+ *
+ * <p>In addition to the cookies set by HTTP responses, you may set cookies
+ * programmatically. To be included in HTTP request headers, cookies must have
+ * the domain and path properties set.
+ *
+ * <p>By default, new instances of {@code HttpCookie} work only with servers
+ * that support <a href="http://www.ietf.org/rfc/rfc2965.txt">RFC 2965</a>
+ * cookies. Many web servers support only the older specification, <a
+ * href="http://www.ietf.org/rfc/rfc2109.txt">RFC 2109</a>. For compatibility
+ * with the most web servers, set the cookie version to 0.
+ *
+ * <p>For example, to receive {@code www.twitter.com} in French: <pre> {@code
+ * HttpCookie cookie = new HttpCookie("lang", "fr");
+ * cookie.setDomain("twitter.com");
+ * cookie.setPath("/");
+ * cookie.setVersion(0);
+ * cookieManager.getCookieStore().add(new URI("http://twitter.com/"), cookie);
+ * }</pre>
+ *
+ * <h3>HTTP Methods</h3>
+ * <p>{@code HttpURLConnection} uses the {@code GET} method by default. It will
+ * use {@code POST} if {@link #setDoOutput setDoOutput(true)} has been called.
+ * Other HTTP methods ({@code OPTIONS}, {@code HEAD}, {@code PUT}, {@code
+ * DELETE} and {@code TRACE}) can be used with {@link #setRequestMethod}.
+ *
+ * <h3>Proxies</h3>
+ * By default, this class will connect directly to the <a
+ * href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec1.html">origin
+ * server</a>. It can also connect via an {@link Proxy.Type#HTTP HTTP} or {@link
+ * Proxy.Type#SOCKS SOCKS} proxy. To use a proxy, use {@link
+ * URL#openConnection(Proxy) URL.openConnection(Proxy)} when creating the
+ * connection.
+ *
+ * <h3>IPv6 Support</h3>
+ * <p>This class includes transparent support for IPv6. For hosts with both IPv4
+ * and IPv6 addresses, it will attempt to connect to each of a host's addresses
+ * until a connection is established.
+ *
+ * <h3>Response Caching</h3>
+ * Android 4.0 (Ice Cream Sandwich, API level 15) includes a response cache. See
+ * {@code android.net.http.HttpResponseCache} for instructions on enabling HTTP
+ * caching in your application.
+ *
+ * <h3>Avoiding Bugs In Earlier Releases</h3>
+ * Prior to Android 2.2 (Froyo), this class had some frustrating bugs. In
+ * particular, calling {@code close()} on a readable {@code InputStream} could
+ * <a href="http://code.google.com/p/android/issues/detail?id=2939">poison the
+ * connection pool</a>. Work around this by disabling connection pooling:
+ * <pre> {@code
+ * private void disableConnectionReuseIfNecessary() {
+ * // Work around pre-Froyo bugs in HTTP connection reuse.
+ * if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) {
+ * System.setProperty("http.keepAlive", "false");
+ * }
+ * }}</pre>
+ *
+ * <p>Each instance of {@code HttpURLConnection} may be used for one
+ * request/response pair. Instances of this class are not thread safe.
+ *
* @since JDK1.1
*/
abstract public class HttpURLConnection extends URLConnection {
diff --git a/ojluni/src/main/java/java/net/Inet6Address.java b/ojluni/src/main/java/java/net/Inet6Address.java
index a46223d..f66b68d 100755
--- a/ojluni/src/main/java/java/net/Inet6Address.java
+++ b/ojluni/src/main/java/java/net/Inet6Address.java
@@ -171,7 +171,7 @@
/** @hide */
public static final InetAddress ANY =
- new Inet6Address(null, new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
+ new Inet6Address("::", new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0);
/** @hide */
public static final InetAddress LOOPBACK = new Inet6Address("localhost",
diff --git a/ojluni/src/main/java/java/nio/Buffer.java b/ojluni/src/main/java/java/nio/Buffer.java
index 48b46dc..a7416ba 100755
--- a/ojluni/src/main/java/java/nio/Buffer.java
+++ b/ojluni/src/main/java/java/nio/Buffer.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -26,6 +26,7 @@
package java.nio;
+import java.util.Spliterator;
/**
* A container for data of a specific primitive type.
@@ -173,6 +174,13 @@
public abstract class Buffer {
+ /**
+ * The characteristics of Spliterators that traverse and split elements
+ * maintained in Buffers.
+ */
+ static final int SPLITERATOR_CHARACTERISTICS =
+ Spliterator.SIZED | Spliterator.SUBSIZED | Spliterator.ORDERED;
+
// Invariants: mark <= position <= limit <= capacity
private int mark = -1;
int position = 0;
diff --git a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
index 0defd57..1e30eb4 100644
--- a/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
+++ b/ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -110,6 +110,10 @@
return this;
}
+ char getUnchecked(int i) {
+ return bb.getCharUnchecked(ix(i));
+ }
+
public CharBuffer put(char x) {
put(nextPutIndex(), x);
return this;
diff --git a/ojluni/src/main/java/java/nio/CharBuffer.java b/ojluni/src/main/java/java/nio/CharBuffer.java
index 68685ce..8a5c64f 100644
--- a/ojluni/src/main/java/java/nio/CharBuffer.java
+++ b/ojluni/src/main/java/java/nio/CharBuffer.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -30,6 +30,9 @@
import java.io.IOException;
+import java.util.Spliterator;
+import java.util.stream.StreamSupport;
+import java.util.stream.IntStream;
/**
@@ -377,6 +380,17 @@
public abstract char get(int index);
/**
+ * Absolute <i>get</i> method. Reads the char at the given
+ * index without any validation of the index.
+ *
+ * @param index
+ * The index from which the char will be read
+ *
+ * @return The char at the given index
+ */
+ abstract char getUnchecked(int index); // package-private
+
+ /**
* Absolute <i>put</i> method <i>(optional operation)</i>.
*
* <p> Writes the given char into this buffer at the given
@@ -1049,5 +1063,10 @@
*/
public abstract ByteOrder order();
-
+ @Override
+ public IntStream chars() {
+ CharBuffer self = this;
+ return StreamSupport.intStream(() -> new CharBufferSpliterator(self),
+ Buffer.SPLITERATOR_CHARACTERISTICS, false);
+ }
}
diff --git a/ojluni/src/main/java/java/nio/CharBufferSpliterator.java b/ojluni/src/main/java/java/nio/CharBufferSpliterator.java
new file mode 100644
index 0000000..5b3977a
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/CharBufferSpliterator.java
@@ -0,0 +1,96 @@
+/*
+ * 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. 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.nio;
+
+import java.util.Comparator;
+import java.util.Spliterator;
+import java.util.function.IntConsumer;
+
+/**
+ * A Spliterator.OfInt for sources that traverse and split elements
+ * maintained in a CharBuffer.
+ *
+ * @implNote
+ * The implementation is based on the code for the Array-based spliterators.
+ */
+class CharBufferSpliterator implements Spliterator.OfInt {
+ private final CharBuffer buffer;
+ private int index; // current index, modified on advance/split
+ private final int limit;
+
+ CharBufferSpliterator(CharBuffer buffer) {
+ this(buffer, buffer.position(), buffer.limit());
+ }
+
+ CharBufferSpliterator(CharBuffer buffer, int origin, int limit) {
+ assert origin <= limit;
+ this.buffer = buffer;
+ this.index = (origin <= limit) ? origin : limit;
+ this.limit = limit;
+ }
+
+ @Override
+ public OfInt trySplit() {
+ int lo = index, mid = (lo + limit) >>> 1;
+ return (lo >= mid)
+ ? null
+ : new CharBufferSpliterator(buffer, lo, index = mid);
+ }
+
+ @Override
+ public void forEachRemaining(IntConsumer action) {
+ if (action == null)
+ throw new NullPointerException();
+ CharBuffer cb = buffer;
+ int i = index;
+ int hi = limit;
+ index = hi;
+ while (i < hi) {
+ action.accept(cb.getUnchecked(i++));
+ }
+ }
+
+ @Override
+ public boolean tryAdvance(IntConsumer action) {
+ if (action == null)
+ throw new NullPointerException();
+ if (index >= 0 && index < limit) {
+ action.accept(buffer.getUnchecked(index++));
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public long estimateSize() {
+ return (long)(limit - index);
+ }
+
+ @Override
+ public int characteristics() {
+ return Buffer.SPLITERATOR_CHARACTERISTICS;
+ }
+}
diff --git a/ojluni/src/main/java/java/nio/HeapCharBuffer.java b/ojluni/src/main/java/java/nio/HeapCharBuffer.java
index 7957e70..f67c91f 100644
--- a/ojluni/src/main/java/java/nio/HeapCharBuffer.java
+++ b/ojluni/src/main/java/java/nio/HeapCharBuffer.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -115,6 +115,10 @@
return hb[ix(checkIndex(i))];
}
+ char getUnchecked(int i) {
+ return hb[ix(i)];
+ }
+
public CharBuffer get(char[] dst, int offset, int length) {
checkBounds(offset, length, dst.length);
if (length > remaining())
diff --git a/ojluni/src/main/java/java/nio/StringCharBuffer.java b/ojluni/src/main/java/java/nio/StringCharBuffer.java
index 8dbd53b..6654c18 100755
--- a/ojluni/src/main/java/java/nio/StringCharBuffer.java
+++ b/ojluni/src/main/java/java/nio/StringCharBuffer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -76,6 +76,10 @@
return str.charAt(checkIndex(index) + offset);
}
+ char getUnchecked(int index) {
+ return str.charAt(index + offset);
+ }
+
// ## Override bulk get methods for better performance
public final CharBuffer put(char c) {
diff --git a/ojluni/src/main/java/java/nio/channels/AcceptPendingException.java b/ojluni/src/main/java/java/nio/channels/AcceptPendingException.java
new file mode 100644
index 0000000..dc357f0
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AcceptPendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to initiate an accept
+ * operation on a channel and a previous accept operation has not completed.
+ *
+ * @since 1.7
+ */
+
+public class AcceptPendingException
+ extends IllegalStateException
+{
+
+ private static final long serialVersionUID = 2721339977965416421L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public AcceptPendingException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/AsynchronousByteChannel.java b/ojluni/src/main/java/java/nio/channels/AsynchronousByteChannel.java
new file mode 100755
index 0000000..9fdf753
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AsynchronousByteChannel.java
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.Future;
+
+/**
+ * An asynchronous channel that can read and write bytes.
+ *
+ * <p> Some channels may not allow more than one read or write to be outstanding
+ * at any given time. If a thread invokes a read method before a previous read
+ * operation has completed then a {@link ReadPendingException} will be thrown.
+ * Similarly, if a write method is invoked before a previous write has completed
+ * then {@link WritePendingException} is thrown. Whether or not other kinds of
+ * I/O operations may proceed concurrently with a read operation depends upon
+ * the type of the channel.
+ *
+ * <p> Note that {@link java.nio.ByteBuffer ByteBuffers} are not safe for use by
+ * multiple concurrent threads. When a read or write operation is initiated then
+ * care must be taken to ensure that the buffer is not accessed until the
+ * operation completes.
+ *
+ * @see Channels#newInputStream(AsynchronousByteChannel)
+ * @see Channels#newOutputStream(AsynchronousByteChannel)
+ *
+ * @since 1.7
+ */
+
+public interface AsynchronousByteChannel
+ extends AsynchronousChannel
+{
+ /**
+ * Reads a sequence of bytes from this channel into the given buffer.
+ *
+ * <p> This method initiates an asynchronous read operation to read a
+ * sequence of bytes from this channel into the given buffer. The {@code
+ * handler} parameter is a completion handler that is invoked when the read
+ * operation completes (or fails). The result passed to the completion
+ * handler is the number of bytes read or {@code -1} if no bytes could be
+ * read because the channel has reached end-of-stream.
+ *
+ * <p> The read operation may read up to <i>r</i> bytes from the channel,
+ * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+ * {@code dst.remaining()} at the time that the read is attempted. Where
+ * <i>r</i> is 0, the read operation completes immediately with a result of
+ * {@code 0} without initiating an I/O operation.
+ *
+ * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+ * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>.
+ * This byte sequence will be transferred into the buffer so that the first
+ * byte in the sequence is at index <i>p</i> and the last byte is at index
+ * <i>p</i> <tt>+</tt> <i>n</i> <tt>-</tt> <tt>1</tt>,
+ * where <i>p</i> is the buffer's position at the moment the read is
+ * performed. Upon completion the buffer's position will be equal to
+ * <i>p</i> <tt>+</tt> <i>n</i>; its limit will not have changed.
+ *
+ * <p> Buffers are not safe for use by multiple concurrent threads so care
+ * should be taken to not access the buffer until the operation has
+ * completed.
+ *
+ * <p> This method may be invoked at any time. Some channel types may not
+ * allow more than one read to be outstanding at any given time. If a thread
+ * initiates a read operation before a previous read operation has
+ * completed then a {@link ReadPendingException} will be thrown.
+ *
+ * @param dst
+ * The buffer into which bytes are to be transferred
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The completion handler
+ *
+ * @throws IllegalArgumentException
+ * If the buffer is read-only
+ * @throws ReadPendingException
+ * If the channel does not allow more than one read to be outstanding
+ * and a previous read has not completed
+ * @throws ShutdownChannelGroupException
+ * If the channel is associated with a {@link AsynchronousChannelGroup
+ * group} that has terminated
+ */
+ <A> void read(ByteBuffer dst,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler);
+
+ /**
+ * Reads a sequence of bytes from this channel into the given buffer.
+ *
+ * <p> This method initiates an asynchronous read operation to read a
+ * sequence of bytes from this channel into the given buffer. The method
+ * behaves in exactly the same manner as the {@link
+ * #read(ByteBuffer,Object,CompletionHandler)
+ * read(ByteBuffer,Object,CompletionHandler)} method except that instead
+ * of specifying a completion handler, this method returns a {@code Future}
+ * representing the pending result. The {@code Future}'s {@link Future#get()
+ * get} method returns the number of bytes read or {@code -1} if no bytes
+ * could be read because the channel has reached end-of-stream.
+ *
+ * @param dst
+ * The buffer into which bytes are to be transferred
+ *
+ * @return A Future representing the result of the operation
+ *
+ * @throws IllegalArgumentException
+ * If the buffer is read-only
+ * @throws ReadPendingException
+ * If the channel does not allow more than one read to be outstanding
+ * and a previous read has not completed
+ */
+ Future<Integer> read(ByteBuffer dst);
+
+ /**
+ * Writes a sequence of bytes to this channel from the given buffer.
+ *
+ * <p> This method initiates an asynchronous write operation to write a
+ * sequence of bytes to this channel from the given buffer. The {@code
+ * handler} parameter is a completion handler that is invoked when the write
+ * operation completes (or fails). The result passed to the completion
+ * handler is the number of bytes written.
+ *
+ * <p> The write operation may write up to <i>r</i> bytes to the channel,
+ * where <i>r</i> is the number of bytes remaining in the buffer, that is,
+ * {@code src.remaining()} at the time that the write is attempted. Where
+ * <i>r</i> is 0, the write operation completes immediately with a result of
+ * {@code 0} without initiating an I/O operation.
+ *
+ * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+ * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>.
+ * This byte sequence will be transferred from the buffer starting at index
+ * <i>p</i>, where <i>p</i> is the buffer's position at the moment the
+ * write is performed; the index of the last byte written will be
+ * <i>p</i> <tt>+</tt> <i>n</i> <tt>-</tt> <tt>1</tt>.
+ * Upon completion the buffer's position will be equal to
+ * <i>p</i> <tt>+</tt> <i>n</i>; its limit will not have changed.
+ *
+ * <p> Buffers are not safe for use by multiple concurrent threads so care
+ * should be taken to not access the buffer until the operation has
+ * completed.
+ *
+ * <p> This method may be invoked at any time. Some channel types may not
+ * allow more than one write to be outstanding at any given time. If a thread
+ * initiates a write operation before a previous write operation has
+ * completed then a {@link WritePendingException} will be thrown.
+ *
+ * @param src
+ * The buffer from which bytes are to be retrieved
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The completion handler object
+ *
+ * @throws WritePendingException
+ * If the channel does not allow more than one write to be outstanding
+ * and a previous write has not completed
+ * @throws ShutdownChannelGroupException
+ * If the channel is associated with a {@link AsynchronousChannelGroup
+ * group} that has terminated
+ */
+ <A> void write(ByteBuffer src,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler);
+
+ /**
+ * Writes a sequence of bytes to this channel from the given buffer.
+ *
+ * <p> This method initiates an asynchronous write operation to write a
+ * sequence of bytes to this channel from the given buffer. The method
+ * behaves in exactly the same manner as the {@link
+ * #write(ByteBuffer,Object,CompletionHandler)
+ * write(ByteBuffer,Object,CompletionHandler)} method except that instead
+ * of specifying a completion handler, this method returns a {@code Future}
+ * representing the pending result. The {@code Future}'s {@link Future#get()
+ * get} method returns the number of bytes written.
+ *
+ * @param src
+ * The buffer from which bytes are to be retrieved
+ *
+ * @return A Future representing the result of the operation
+ *
+ * @throws WritePendingException
+ * If the channel does not allow more than one write to be outstanding
+ * and a previous write has not completed
+ */
+ Future<Integer> write(ByteBuffer src);
+}
diff --git a/ojluni/src/main/java/java/nio/channels/AsynchronousChannel.java b/ojluni/src/main/java/java/nio/channels/AsynchronousChannel.java
new file mode 100755
index 0000000..5aa9fe2
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AsynchronousChannel.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.io.IOException;
+import java.util.concurrent.Future; // javadoc
+
+/**
+ * A channel that supports asynchronous I/O operations. Asynchronous I/O
+ * operations will usually take one of two forms:
+ *
+ * <ol>
+ * <li><pre>{@link Future}<V> <em>operation</em>(<em>...</em>)</pre></li>
+ * <li><pre>void <em>operation</em>(<em>...</em> A attachment, {@link
+ * CompletionHandler}<V,? super A> handler)</pre></li>
+ * </ol>
+ *
+ * where <i>operation</i> is the name of the I/O operation (read or write for
+ * example), <i>V</i> is the result type of the I/O operation, and <i>A</i> is
+ * the type of an object attached to the I/O operation to provide context when
+ * consuming the result. The attachment is important for cases where a
+ * <em>state-less</em> {@code CompletionHandler} is used to consume the result
+ * of many I/O operations.
+ *
+ * <p> In the first form, the methods defined by the {@link Future Future}
+ * interface may be used to check if the operation has completed, wait for its
+ * completion, and to retrieve the result. In the second form, a {@link
+ * CompletionHandler} is invoked to consume the result of the I/O operation when
+ * it completes or fails.
+ *
+ * <p> A channel that implements this interface is <em>asynchronously
+ * closeable</em>: If an I/O operation is outstanding on the channel and the
+ * channel's {@link #close close} method is invoked, then the I/O operation
+ * fails with the exception {@link AsynchronousCloseException}.
+ *
+ * <p> Asynchronous channels are safe for use by multiple concurrent threads.
+ * Some channel implementations may support concurrent reading and writing, but
+ * may not allow more than one read and one write operation to be outstanding at
+ * any given time.
+ *
+ * <h4>Cancellation</h4>
+ *
+ * <p> The {@code Future} interface defines the {@link Future#cancel cancel}
+ * method to cancel execution. This causes all threads waiting on the result of
+ * the I/O operation to throw {@link java.util.concurrent.CancellationException}.
+ * Whether the underlying I/O operation can be cancelled is highly implementation
+ * specific and therefore not specified. Where cancellation leaves the channel,
+ * or the entity to which it is connected, in an inconsistent state, then the
+ * channel is put into an implementation specific <em>error state</em> that
+ * prevents further attempts to initiate I/O operations that are <i>similar</i>
+ * to the operation that was cancelled. For example, if a read operation is
+ * cancelled but the implementation cannot guarantee that bytes have not been
+ * read from the channel then it puts the channel into an error state; further
+ * attempts to initiate a {@code read} operation cause an unspecified runtime
+ * exception to be thrown. Similarly, if a write operation is cancelled but the
+ * implementation cannot guarantee that bytes have not been written to the
+ * channel then subsequent attempts to initiate a {@code write} will fail with
+ * an unspecified runtime exception.
+ *
+ * <p> Where the {@link Future#cancel cancel} method is invoked with the {@code
+ * mayInterruptIfRunning} parameter set to {@code true} then the I/O operation
+ * may be interrupted by closing the channel. In that case all threads waiting
+ * on the result of the I/O operation throw {@code CancellationException} and
+ * any other I/O operations outstanding on the channel complete with the
+ * exception {@link AsynchronousCloseException}.
+ *
+ * <p> Where the {@code cancel} method is invoked to cancel read or write
+ * operations then it is recommended that all buffers used in the I/O operations
+ * be discarded or care taken to ensure that the buffers are not accessed while
+ * the channel remains open.
+ *
+ * @since 1.7
+ */
+
+public interface AsynchronousChannel
+ extends Channel
+{
+ /**
+ * Closes this channel.
+ *
+ * <p> Any outstanding asynchronous operations upon this channel will
+ * complete with the exception {@link AsynchronousCloseException}. After a
+ * channel is closed, further attempts to initiate asynchronous I/O
+ * operations complete immediately with cause {@link ClosedChannelException}.
+ *
+ * <p> This method otherwise behaves exactly as specified by the {@link
+ * Channel} interface.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ @Override
+ void close() throws IOException;
+}
diff --git a/ojluni/src/main/java/java/nio/channels/AsynchronousChannelGroup.java b/ojluni/src/main/java/java/nio/channels/AsynchronousChannelGroup.java
new file mode 100755
index 0000000..2eb4b52
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AsynchronousChannelGroup.java
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A grouping of asynchronous channels for the purpose of resource sharing.
+ *
+ * <p> An asynchronous channel group encapsulates the mechanics required to
+ * handle the completion of I/O operations initiated by {@link AsynchronousChannel
+ * asynchronous channels} that are bound to the group. A group has an associated
+ * thread pool to which tasks are submitted to handle I/O events and dispatch to
+ * {@link CompletionHandler completion-handlers} that consume the result of
+ * asynchronous operations performed on channels in the group. In addition to
+ * handling I/O events, the pooled threads may also execute other tasks required
+ * to support the execution of asynchronous I/O operations.
+ *
+ * <p> An asynchronous channel group is created by invoking the {@link
+ * #withFixedThreadPool withFixedThreadPool} or {@link #withCachedThreadPool
+ * withCachedThreadPool} methods defined here. Channels are bound to a group by
+ * specifying the group when constructing the channel. The associated thread
+ * pool is <em>owned</em> by the group; termination of the group results in the
+ * shutdown of the associated thread pool.
+ *
+ * <p> In addition to groups created explicitly, the Java virtual machine
+ * maintains a system-wide <em>default group</em> that is constructed
+ * automatically. Asynchronous channels that do not specify a group at
+ * construction time are bound to the default group. The default group has an
+ * associated thread pool that creates new threads as needed. The default group
+ * may be configured by means of system properties defined in the table below.
+ * Where the {@link java.util.concurrent.ThreadFactory ThreadFactory} for the
+ * default group is not configured then the pooled threads of the default group
+ * are {@link Thread#isDaemon daemon} threads.
+ *
+ * <table border>
+ * <tr>
+ * <th>System property</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <tr>
+ * <td> {@code java.nio.channels.DefaultThreadPool.threadFactory} </td>
+ * <td> The value of this property is taken to be the fully-qualified name
+ * of a concrete {@link java.util.concurrent.ThreadFactory ThreadFactory}
+ * class. The class is loaded using the system class loader and instantiated.
+ * The factory's {@link java.util.concurrent.ThreadFactory#newThread
+ * newThread} method is invoked to create each thread for the default
+ * group's thread pool. If the process to load and instantiate the value
+ * of the property fails then an unspecified error is thrown during the
+ * construction of the default group. </td>
+ * </tr>
+ * <tr>
+ * <td> {@code java.nio.channels.DefaultThreadPool.initialSize} </td>
+ * <td> The value of the {@code initialSize} parameter for the default
+ * group (see {@link #withCachedThreadPool withCachedThreadPool}).
+ * The value of the property is taken to be the {@code String}
+ * representation of an {@code Integer} that is the initial size parameter.
+ * If the value cannot be parsed as an {@code Integer} it causes an
+ * unspecified error to be thrown during the construction of the default
+ * group. </td>
+ * </tr>
+ * </table>
+ *
+ * <a name="threading"><h4>Threading</h4></a>
+ *
+ * <p> The completion handler for an I/O operation initiated on a channel bound
+ * to a group is guaranteed to be invoked by one of the pooled threads in the
+ * group. This ensures that the completion handler is run by a thread with the
+ * expected <em>identity</em>.
+ *
+ * <p> Where an I/O operation completes immediately, and the initiating thread
+ * is one of the pooled threads in the group then the completion handler may
+ * be invoked directly by the initiating thread. To avoid stack overflow, an
+ * implementation may impose a limit as to the number of activations on the
+ * thread stack. Some I/O operations may prohibit invoking the completion
+ * handler directly by the initiating thread (see {@link
+ * AsynchronousServerSocketChannel#accept(Object,CompletionHandler) accept}).
+ *
+ * <a name="shutdown"><h4>Shutdown and Termination</h4></a>
+ *
+ * <p> The {@link #shutdown() shutdown} method is used to initiate an <em>orderly
+ * shutdown</em> of a group. An orderly shutdown marks the group as shutdown;
+ * further attempts to construct a channel that binds to the group will throw
+ * {@link ShutdownChannelGroupException}. Whether or not a group is shutdown can
+ * be tested using the {@link #isShutdown() isShutdown} method. Once shutdown,
+ * the group <em>terminates</em> when all asynchronous channels that are bound to
+ * the group are closed, all actively executing completion handlers have run to
+ * completion, and resources used by the group are released. No attempt is made
+ * to stop or interrupt threads that are executing completion handlers. The
+ * {@link #isTerminated() isTerminated} method is used to test if the group has
+ * terminated, and the {@link #awaitTermination awaitTermination} method can be
+ * used to block until the group has terminated.
+ *
+ * <p> The {@link #shutdownNow() shutdownNow} method can be used to initiate a
+ * <em>forceful shutdown</em> of the group. In addition to the actions performed
+ * by an orderly shutdown, the {@code shutdownNow} method closes all open channels
+ * in the group as if by invoking the {@link AsynchronousChannel#close close}
+ * method.
+ *
+ * @since 1.7
+ *
+ * @see AsynchronousSocketChannel#open(AsynchronousChannelGroup)
+ * @see AsynchronousServerSocketChannel#open(AsynchronousChannelGroup)
+ */
+
+public abstract class AsynchronousChannelGroup {
+ private final AsynchronousChannelProvider provider;
+
+ /**
+ * Initialize a new instance of this class.
+ *
+ * @param provider
+ * The asynchronous channel provider for this group
+ */
+ protected AsynchronousChannelGroup(AsynchronousChannelProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * Returns the provider that created this channel group.
+ *
+ * @return The provider that created this channel group
+ */
+ public final AsynchronousChannelProvider provider() {
+ return provider;
+ }
+
+ /**
+ * Creates an asynchronous channel group with a fixed thread pool.
+ *
+ * <p> The resulting asynchronous channel group reuses a fixed number of
+ * threads. At any point, at most {@code nThreads} threads will be active
+ * processing tasks that are submitted to handle I/O events and dispatch
+ * completion results for operations initiated on asynchronous channels in
+ * the group.
+ *
+ * <p> The group is created by invoking the {@link
+ * AsynchronousChannelProvider#openAsynchronousChannelGroup(int,ThreadFactory)
+ * openAsynchronousChannelGroup(int,ThreadFactory)} method of the system-wide
+ * default {@link AsynchronousChannelProvider} object.
+ *
+ * @param nThreads
+ * The number of threads in the pool
+ * @param threadFactory
+ * The factory to use when creating new threads
+ *
+ * @return A new asynchronous channel group
+ *
+ * @throws IllegalArgumentException
+ * If {@code nThreads <= 0}
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousChannelGroup withFixedThreadPool(int nThreads,
+ ThreadFactory threadFactory)
+ throws IOException
+ {
+ return AsynchronousChannelProvider.provider()
+ .openAsynchronousChannelGroup(nThreads, threadFactory);
+ }
+
+ /**
+ * Creates an asynchronous channel group with a given thread pool that
+ * creates new threads as needed.
+ *
+ * <p> The {@code executor} parameter is an {@code ExecutorService} that
+ * creates new threads as needed to execute tasks that are submitted to
+ * handle I/O events and dispatch completion results for operations initiated
+ * on asynchronous channels in the group. It may reuse previously constructed
+ * threads when they are available.
+ *
+ * <p> The {@code initialSize} parameter may be used by the implementation
+ * as a <em>hint</em> as to the initial number of tasks it may submit. For
+ * example, it may be used to indictae the initial number of threads that
+ * wait on I/O events.
+ *
+ * <p> The executor is intended to be used exclusively by the resulting
+ * asynchronous channel group. Termination of the group results in the
+ * orderly {@link ExecutorService#shutdown shutdown} of the executor
+ * service. Shutting down the executor service by other means results in
+ * unspecified behavior.
+ *
+ * <p> The group is created by invoking the {@link
+ * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+ * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+ * default {@link AsynchronousChannelProvider} object.
+ *
+ * @param executor
+ * The thread pool for the resulting group
+ * @param initialSize
+ * A value {@code >=0} or a negative value for implementation
+ * specific default
+ *
+ * @return A new asynchronous channel group
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see java.util.concurrent.Executors#newCachedThreadPool
+ */
+ public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor,
+ int initialSize)
+ throws IOException
+ {
+ return AsynchronousChannelProvider.provider()
+ .openAsynchronousChannelGroup(executor, initialSize);
+ }
+
+ /**
+ * Creates an asynchronous channel group with a given thread pool.
+ *
+ * <p> The {@code executor} parameter is an {@code ExecutorService} that
+ * executes tasks submitted to dispatch completion results for operations
+ * initiated on asynchronous channels in the group.
+ *
+ * <p> Care should be taken when configuring the executor service. It
+ * should support <em>direct handoff</em> or <em>unbounded queuing</em> of
+ * submitted tasks, and the thread that invokes the {@link
+ * ExecutorService#execute execute} method should never invoke the task
+ * directly. An implementation may mandate additional constraints.
+ *
+ * <p> The executor is intended to be used exclusively by the resulting
+ * asynchronous channel group. Termination of the group results in the
+ * orderly {@link ExecutorService#shutdown shutdown} of the executor
+ * service. Shutting down the executor service by other means results in
+ * unspecified behavior.
+ *
+ * <p> The group is created by invoking the {@link
+ * AsynchronousChannelProvider#openAsynchronousChannelGroup(ExecutorService,int)
+ * openAsynchronousChannelGroup(ExecutorService,int)} method of the system-wide
+ * default {@link AsynchronousChannelProvider} object with an {@code
+ * initialSize} of {@code 0}.
+ *
+ * @param executor
+ * The thread pool for the resulting group
+ *
+ * @return A new asynchronous channel group
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousChannelGroup withThreadPool(ExecutorService executor)
+ throws IOException
+ {
+ return AsynchronousChannelProvider.provider()
+ .openAsynchronousChannelGroup(executor, 0);
+ }
+
+ /**
+ * Tells whether or not this asynchronous channel group is shutdown.
+ *
+ * @return {@code true} if this asynchronous channel group is shutdown or
+ * has been marked for shutdown.
+ */
+ public abstract boolean isShutdown();
+
+ /**
+ * Tells whether or not this group has terminated.
+ *
+ * <p> Where this method returns {@code true}, then the associated thread
+ * pool has also {@link ExecutorService#isTerminated terminated}.
+ *
+ * @return {@code true} if this group has terminated
+ */
+ public abstract boolean isTerminated();
+
+ /**
+ * Initiates an orderly shutdown of the group.
+ *
+ * <p> This method marks the group as shutdown. Further attempts to construct
+ * channel that binds to this group will throw {@link ShutdownChannelGroupException}.
+ * The group terminates when all asynchronous channels in the group are
+ * closed, all actively executing completion handlers have run to completion,
+ * and all resources have been released. This method has no effect if the
+ * group is already shutdown.
+ */
+ public abstract void shutdown();
+
+ /**
+ * Shuts down the group and closes all open channels in the group.
+ *
+ * <p> In addition to the actions performed by the {@link #shutdown() shutdown}
+ * method, this method invokes the {@link AsynchronousChannel#close close}
+ * method on all open channels in the group. This method does not attempt to
+ * stop or interrupt threads that are executing completion handlers. The
+ * group terminates when all actively executing completion handlers have run
+ * to completion and all resources have been released. This method may be
+ * invoked at any time. If some other thread has already invoked it, then
+ * another invocation will block until the first invocation is complete,
+ * after which it will return without effect.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract void shutdownNow() throws IOException;
+
+ /**
+ * Awaits termination of the group.
+
+ * <p> This method blocks until the group has terminated, or the timeout
+ * occurs, or the current thread is interrupted, whichever happens first.
+ *
+ * @param timeout
+ * The maximum time to wait, or zero or less to not wait
+ * @param unit
+ * The time unit of the timeout argument
+ *
+ * @return {@code true} if the group has terminated; {@code false} if the
+ * timeout elapsed before termination
+ *
+ * @throws InterruptedException
+ * If interrupted while waiting
+ */
+ public abstract boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException;
+}
diff --git a/ojluni/src/main/java/java/nio/channels/AsynchronousServerSocketChannel.java b/ojluni/src/main/java/java/nio/channels/AsynchronousServerSocketChannel.java
new file mode 100755
index 0000000..1b5a67f
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AsynchronousServerSocketChannel.java
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.util.concurrent.Future;
+import java.io.IOException;
+
+/**
+ * An asynchronous channel for stream-oriented listening sockets.
+ *
+ * <p> An asynchronous server-socket channel is created by invoking the
+ * {@link #open open} method of this class.
+ * A newly-created asynchronous server-socket channel is open but not yet bound.
+ * It can be bound to a local address and configured to listen for connections
+ * by invoking the {@link #bind(SocketAddress,int) bind} method. Once bound,
+ * the {@link #accept(Object,CompletionHandler) accept} method
+ * is used to initiate the accepting of connections to the channel's socket.
+ * An attempt to invoke the <tt>accept</tt> method on an unbound channel will
+ * cause a {@link NotYetBoundException} to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads
+ * though at most one accept operation can be outstanding at any time.
+ * If a thread initiates an accept operation before a previous accept operation
+ * has completed then an {@link AcceptPendingException} will be thrown.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Channels of this type support the following options:
+ * <blockquote>
+ * <table border>
+ * <tr>
+ * <th>Option Name</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ * <td> The size of the socket receive buffer </td>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ * <td> Re-use address </td>
+ * </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ * final AsynchronousServerSocketChannel listener =
+ * AsynchronousServerSocketChannel.open().bind(new InetSocketAddress(5000));
+ *
+ * listener.accept(null, new CompletionHandler<AsynchronousSocketChannel,Void>() {
+ * public void completed(AsynchronousSocketChannel ch, Void att) {
+ * // accept the next connection
+ * listener.accept(null, this);
+ *
+ * // handle this connection
+ * handle(ch);
+ * }
+ * public void failed(Throwable exc, Void att) {
+ * ...
+ * }
+ * });
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousServerSocketChannel
+ implements AsynchronousChannel, NetworkChannel
+{
+ private final AsynchronousChannelProvider provider;
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected AsynchronousServerSocketChannel(AsynchronousChannelProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * Returns the provider that created this channel.
+ */
+ public final AsynchronousChannelProvider provider() {
+ return provider;
+ }
+
+ /**
+ * Opens an asynchronous server-socket channel.
+ *
+ * <p> The new channel is created by invoking the {@link
+ * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousServerSocketChannel
+ * openAsynchronousServerSocketChannel} method on the {@link
+ * java.nio.channels.spi.AsynchronousChannelProvider} object that created
+ * the given group. If the group parameter is <tt>null</tt> then the
+ * resulting channel is created by the system-wide default provider, and
+ * bound to the <em>default group</em>.
+ *
+ * @param group
+ * The group to which the newly constructed channel should be bound,
+ * or <tt>null</tt> for the default group
+ *
+ * @return A new asynchronous server socket channel
+ *
+ * @throws ShutdownChannelGroupException
+ * If the channel group is shutdown
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousServerSocketChannel open(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ AsynchronousChannelProvider provider = (group == null) ?
+ AsynchronousChannelProvider.provider() : group.provider();
+ return provider.openAsynchronousServerSocketChannel(group);
+ }
+
+ /**
+ * Opens an asynchronous server-socket channel.
+ *
+ * <p> This method returns an asynchronous server socket channel that is
+ * bound to the <em>default group</em>. This method is equivalent to evaluating
+ * the expression:
+ * <blockquote><pre>
+ * open((AsynchronousChannelGroup)null);
+ * </pre></blockquote>
+ *
+ * @return A new asynchronous server socket channel
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousServerSocketChannel open()
+ throws IOException
+ {
+ return open(null);
+ }
+
+ /**
+ * Binds the channel's socket to a local address and configures the socket to
+ * listen for connections.
+ *
+ * <p> An invocation of this method is equivalent to the following:
+ * <blockquote><pre>
+ * bind(local, 0);
+ * </pre></blockquote>
+ *
+ * @param local
+ * The local address to bind the socket, or <tt>null</tt> to bind
+ * to an automatically assigned socket address
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException {@inheritDoc}
+ * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws SecurityException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ */
+ public final AsynchronousServerSocketChannel bind(SocketAddress local)
+ throws IOException
+ {
+ return bind(local, 0);
+ }
+
+ /**
+ * Binds the channel's socket to a local address and configures the socket to
+ * listen for connections.
+ *
+ * <p> This method is used to establish an association between the socket and
+ * a local address. Once an association is established then the socket remains
+ * bound until the associated channel is closed.
+ *
+ * <p> The {@code backlog} parameter is the maximum number of pending
+ * connections on the socket. Its exact semantics are implementation specific.
+ * In particular, an implementation may impose a maximum length or may choose
+ * to ignore the parameter altogther. If the {@code backlog} parameter has
+ * the value {@code 0}, or a negative value, then an implementation specific
+ * default is used.
+ *
+ * @param local
+ * The local address to bind the socket, or {@code null} to bind
+ * to an automatically assigned socket address
+ * @param backlog
+ * The maximum number of pending connections
+ *
+ * @return This channel
+ *
+ * @throws AlreadyBoundException
+ * If the socket is already bound
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given address is not supported
+ * @throws SecurityException
+ * If a security manager has been installed and its {@link
+ * SecurityManager#checkListen checkListen} method denies the operation
+ * @throws ClosedChannelException
+ * If the channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ */
+ public abstract AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
+ throws IOException;
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ */
+ public abstract <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name, T value)
+ throws IOException;
+
+ /**
+ * Accepts a connection.
+ *
+ * <p> This method initiates an asynchronous operation to accept a
+ * connection made to this channel's socket. The {@code handler} parameter is
+ * a completion handler that is invoked when a connection is accepted (or
+ * the operation fails). The result passed to the completion handler is
+ * the {@link AsynchronousSocketChannel} to the new connection.
+ *
+ * <p> When a new connection is accepted then the resulting {@code
+ * AsynchronousSocketChannel} will be bound to the same {@link
+ * AsynchronousChannelGroup} as this channel. If the group is {@link
+ * AsynchronousChannelGroup#isShutdown shutdown} and a connection is accepted,
+ * then the connection is closed, and the operation completes with an {@code
+ * IOException} and cause {@link ShutdownChannelGroupException}.
+ *
+ * <p> To allow for concurrent handling of new connections, the completion
+ * handler is not invoked directly by the initiating thread when a new
+ * connection is accepted immediately (see <a
+ * href="AsynchronousChannelGroup.html#threading">Threading<a>).
+ *
+ * <p> If a security manager has been installed then it verifies that the
+ * address and port number of the connection's remote endpoint are permitted
+ * by the security manager's {@link SecurityManager#checkAccept checkAccept}
+ * method. The permission check is performed with privileges that are restricted
+ * by the calling context of this method. If the permission check fails then
+ * the connection is closed and the operation completes with a {@link
+ * SecurityException}.
+ *
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws AcceptPendingException
+ * If an accept operation is already in progress on this channel
+ * @throws NotYetBoundException
+ * If this channel's socket has not yet been bound
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ public abstract <A> void accept(A attachment,
+ CompletionHandler<AsynchronousSocketChannel,? super A> handler);
+
+ /**
+ * Accepts a connection.
+ *
+ * <p> This method initiates an asynchronous operation to accept a
+ * connection made to this channel's socket. The method behaves in exactly
+ * the same manner as the {@link #accept(Object, CompletionHandler)} method
+ * except that instead of specifying a completion handler, this method
+ * returns a {@code Future} representing the pending result. The {@code
+ * Future}'s {@link Future#get() get} method returns the {@link
+ * AsynchronousSocketChannel} to the new connection on successful completion.
+ *
+ * @return a {@code Future} object representing the pending result
+ *
+ * @throws AcceptPendingException
+ * If an accept operation is already in progress on this channel
+ * @throws NotYetBoundException
+ * If this channel's socket has not yet been bound
+ */
+ public abstract Future<AsynchronousSocketChannel> accept();
+}
diff --git a/ojluni/src/main/java/java/nio/channels/AsynchronousSocketChannel.java b/ojluni/src/main/java/java/nio/channels/AsynchronousSocketChannel.java
new file mode 100755
index 0000000..d78800b
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/AsynchronousSocketChannel.java
@@ -0,0 +1,648 @@
+/*
+ * Copyright (c) 2007, 2010, 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.nio.channels;
+
+import java.nio.channels.spi.*;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.Future;
+import java.io.IOException;
+import java.net.SocketOption;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+/**
+ * An asynchronous channel for stream-oriented connecting sockets.
+ *
+ * <p> Asynchronous socket channels are created in one of two ways. A newly-created
+ * {@code AsynchronousSocketChannel} is created by invoking one of the {@link
+ * #open open} methods defined by this class. A newly-created channel is open but
+ * not yet connected. A connected {@code AsynchronousSocketChannel} is created
+ * when a connection is made to the socket of an {@link AsynchronousServerSocketChannel}.
+ * It is not possible to create an asynchronous socket channel for an arbitrary,
+ * pre-existing {@link java.net.Socket socket}.
+ *
+ * <p> A newly-created channel is connected by invoking its {@link #connect connect}
+ * method; once connected, a channel remains connected until it is closed. Whether
+ * or not a socket channel is connected may be determined by invoking its {@link
+ * #getRemoteAddress getRemoteAddress} method. An attempt to invoke an I/O
+ * operation upon an unconnected channel will cause a {@link NotYetConnectedException}
+ * to be thrown.
+ *
+ * <p> Channels of this type are safe for use by multiple concurrent threads.
+ * They support concurrent reading and writing, though at most one read operation
+ * and one write operation can be outstanding at any time.
+ * If a thread initiates a read operation before a previous read operation has
+ * completed then a {@link ReadPendingException} will be thrown. Similarly, an
+ * attempt to initiate a write operation before a previous write has completed
+ * will throw a {@link WritePendingException}.
+ *
+ * <p> Socket options are configured using the {@link #setOption(SocketOption,Object)
+ * setOption} method. Asynchronous socket channels support the following options:
+ * <blockquote>
+ * <table border>
+ * <tr>
+ * <th>Option Name</th>
+ * <th>Description</th>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_SNDBUF SO_SNDBUF} </td>
+ * <td> The size of the socket send buffer </td>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_RCVBUF SO_RCVBUF} </td>
+ * <td> The size of the socket receive buffer </td>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} </td>
+ * <td> Keep connection alive </td>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} </td>
+ * <td> Re-use address </td>
+ * </tr>
+ * <tr>
+ * <td> {@link java.net.StandardSocketOptions#TCP_NODELAY TCP_NODELAY} </td>
+ * <td> Disable the Nagle algorithm </td>
+ * </tr>
+ * </table>
+ * </blockquote>
+ * Additional (implementation specific) options may also be supported.
+ *
+ * <h4>Timeouts</h4>
+ *
+ * <p> The {@link #read(ByteBuffer,long,TimeUnit,Object,CompletionHandler) read}
+ * and {@link #write(ByteBuffer,long,TimeUnit,Object,CompletionHandler) write}
+ * methods defined by this class allow a timeout to be specified when initiating
+ * a read or write operation. If the timeout elapses before an operation completes
+ * then the operation completes with the exception {@link
+ * InterruptedByTimeoutException}. A timeout may leave the channel, or the
+ * underlying connection, in an inconsistent state. Where the implementation
+ * cannot guarantee that bytes have not been read from the channel then it puts
+ * the channel into an implementation specific <em>error state</em>. A subsequent
+ * attempt to initiate a {@code read} operation causes an unspecified runtime
+ * exception to be thrown. Similarly if a {@code write} operation times out and
+ * the implementation cannot guarantee bytes have not been written to the
+ * channel then further attempts to {@code write} to the channel cause an
+ * unspecified runtime exception to be thrown. When a timeout elapses then the
+ * state of the {@link ByteBuffer}, or the sequence of buffers, for the I/O
+ * operation is not defined. Buffers should be discarded or at least care must
+ * be taken to ensure that the buffers are not accessed while the channel remains
+ * open. All methods that accept timeout parameters treat values less than or
+ * equal to zero to mean that the I/O operation does not timeout.
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousSocketChannel
+ implements AsynchronousByteChannel, NetworkChannel
+{
+ private final AsynchronousChannelProvider provider;
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected AsynchronousSocketChannel(AsynchronousChannelProvider provider) {
+ this.provider = provider;
+ }
+
+ /**
+ * Returns the provider that created this channel.
+ */
+ public final AsynchronousChannelProvider provider() {
+ return provider;
+ }
+
+ /**
+ * Opens an asynchronous socket channel.
+ *
+ * <p> The new channel is created by invoking the {@link
+ * AsynchronousChannelProvider#openAsynchronousSocketChannel
+ * openAsynchronousSocketChannel} method on the {@link
+ * AsynchronousChannelProvider} that created the group. If the group parameter
+ * is {@code null} then the resulting channel is created by the system-wide
+ * default provider, and bound to the <em>default group</em>.
+ *
+ * @param group
+ * The group to which the newly constructed channel should be bound,
+ * or {@code null} for the default group
+ *
+ * @return A new asynchronous socket channel
+ *
+ * @throws ShutdownChannelGroupException
+ * If the channel group is shutdown
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousSocketChannel open(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ AsynchronousChannelProvider provider = (group == null) ?
+ AsynchronousChannelProvider.provider() : group.provider();
+ return provider.openAsynchronousSocketChannel(group);
+ }
+
+ /**
+ * Opens an asynchronous socket channel.
+ *
+ * <p> This method returns an asynchronous socket channel that is bound to
+ * the <em>default group</em>.This method is equivalent to evaluating the
+ * expression:
+ * <blockquote><pre>
+ * open((AsynchronousChannelGroup)null);
+ * </pre></blockquote>
+ *
+ * @return A new asynchronous socket channel
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public static AsynchronousSocketChannel open()
+ throws IOException
+ {
+ return open(null);
+ }
+
+
+ // -- socket options and related --
+
+ /**
+ * @throws ConnectionPendingException
+ * If a connection operation is already in progress on this channel
+ * @throws AlreadyBoundException {@inheritDoc}
+ * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ */
+ @Override
+ public abstract AsynchronousSocketChannel bind(SocketAddress local)
+ throws IOException;
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ClosedChannelException {@inheritDoc}
+ * @throws IOException {@inheritDoc}
+ */
+ @Override
+ public abstract <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
+ throws IOException;
+
+ /**
+ * Shutdown the connection for reading without closing the channel.
+ *
+ * <p> Once shutdown for reading then further reads on the channel will
+ * return {@code -1}, the end-of-stream indication. If the input side of the
+ * connection is already shutdown then invoking this method has no effect.
+ * The effect on an outstanding read operation is system dependent and
+ * therefore not specified. The effect, if any, when there is data in the
+ * socket receive buffer that has not been read, or data arrives subsequently,
+ * is also system dependent.
+ *
+ * @return The channel
+ *
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ */
+ public abstract AsynchronousSocketChannel shutdownInput() throws IOException;
+
+ /**
+ * Shutdown the connection for writing without closing the channel.
+ *
+ * <p> Once shutdown for writing then further attempts to write to the
+ * channel will throw {@link ClosedChannelException}. If the output side of
+ * the connection is already shutdown then invoking this method has no
+ * effect. The effect on an outstanding write operation is system dependent
+ * and therefore not specified.
+ *
+ * @return The channel
+ *
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If some other I/O error occurs
+ */
+ public abstract AsynchronousSocketChannel shutdownOutput() throws IOException;
+
+ // -- state --
+
+ /**
+ * Returns the remote address to which this channel's socket is connected.
+ *
+ * <p> Where the channel is bound and connected to an Internet Protocol
+ * socket address then the return value from this method is of type {@link
+ * java.net.InetSocketAddress}.
+ *
+ * @return The remote address; {@code null} if the channel's socket is not
+ * connected
+ *
+ * @throws ClosedChannelException
+ * If the channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract SocketAddress getRemoteAddress() throws IOException;
+
+ // -- asynchronous operations --
+
+ /**
+ * Connects this channel.
+ *
+ * <p> This method initiates an operation to connect this channel. The
+ * {@code handler} parameter is a completion handler that is invoked when
+ * the connection is successfully established or connection cannot be
+ * established. If the connection cannot be established then the channel is
+ * closed.
+ *
+ * <p> This method performs exactly the same security checks as the {@link
+ * java.net.Socket} class. That is, if a security manager has been
+ * installed then this method verifies that its {@link
+ * java.lang.SecurityManager#checkConnect checkConnect} method permits
+ * connecting to the address and port number of the given remote endpoint.
+ *
+ * @param remote
+ * The remote address to which this channel is to be connected
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws UnresolvedAddressException
+ * If the given remote address is not fully resolved
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given remote address is not supported
+ * @throws AlreadyConnectedException
+ * If this channel is already connected
+ * @throws ConnectionPendingException
+ * If a connection operation is already in progress on this channel
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ * @throws SecurityException
+ * If a security manager has been installed
+ * and it does not permit access to the given remote endpoint
+ *
+ * @see #getRemoteAddress
+ */
+ public abstract <A> void connect(SocketAddress remote,
+ A attachment,
+ CompletionHandler<Void,? super A> handler);
+
+ /**
+ * Connects this channel.
+ *
+ * <p> This method initiates an operation to connect this channel. This
+ * method behaves in exactly the same manner as the {@link
+ * #connect(SocketAddress, Object, CompletionHandler)} method except that
+ * instead of specifying a completion handler, this method returns a {@code
+ * Future} representing the pending result. The {@code Future}'s {@link
+ * Future#get() get} method returns {@code null} on successful completion.
+ *
+ * @param remote
+ * The remote address to which this channel is to be connected
+ *
+ * @return A {@code Future} object representing the pending result
+ *
+ * @throws UnresolvedAddressException
+ * If the given remote address is not fully resolved
+ * @throws UnsupportedAddressTypeException
+ * If the type of the given remote address is not supported
+ * @throws AlreadyConnectedException
+ * If this channel is already connected
+ * @throws ConnectionPendingException
+ * If a connection operation is already in progress on this channel
+ * @throws SecurityException
+ * If a security manager has been installed
+ * and it does not permit access to the given remote endpoint
+ */
+ public abstract Future<Void> connect(SocketAddress remote);
+
+ /**
+ * Reads a sequence of bytes from this channel into the given buffer.
+ *
+ * <p> This method initiates an asynchronous read operation to read a
+ * sequence of bytes from this channel into the given buffer. The {@code
+ * handler} parameter is a completion handler that is invoked when the read
+ * operation completes (or fails). The result passed to the completion
+ * handler is the number of bytes read or {@code -1} if no bytes could be
+ * read because the channel has reached end-of-stream.
+ *
+ * <p> If a timeout is specified and the timeout elapses before the operation
+ * completes then the operation completes with the exception {@link
+ * InterruptedByTimeoutException}. Where a timeout occurs, and the
+ * implementation cannot guarantee that bytes have not been read, or will not
+ * be read from the channel into the given buffer, then further attempts to
+ * read from the channel will cause an unspecific runtime exception to be
+ * thrown.
+ *
+ * <p> Otherwise this method works in the same manner as the {@link
+ * AsynchronousByteChannel#read(ByteBuffer,Object,CompletionHandler)}
+ * method.
+ *
+ * @param dst
+ * The buffer into which bytes are to be transferred
+ * @param timeout
+ * The maximum time for the I/O operation to complete
+ * @param unit
+ * The time unit of the {@code timeout} argument
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws IllegalArgumentException
+ * If the buffer is read-only
+ * @throws ReadPendingException
+ * If a read operation is already in progress on this channel
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ public abstract <A> void read(ByteBuffer dst,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler);
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ReadPendingException {@inheritDoc}
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ @Override
+ public final <A> void read(ByteBuffer dst,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler)
+ {
+ read(dst, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+ }
+
+ /**
+ * @throws IllegalArgumentException {@inheritDoc}
+ * @throws ReadPendingException {@inheritDoc}
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ */
+ @Override
+ public abstract Future<Integer> read(ByteBuffer dst);
+
+ /**
+ * Reads a sequence of bytes from this channel into a subsequence of the
+ * given buffers. This operation, sometimes called a <em>scattering read</em>,
+ * is often useful when implementing network protocols that group data into
+ * segments consisting of one or more fixed-length headers followed by a
+ * variable-length body. The {@code handler} parameter is a completion
+ * handler that is invoked when the read operation completes (or fails). The
+ * result passed to the completion handler is the number of bytes read or
+ * {@code -1} if no bytes could be read because the channel has reached
+ * end-of-stream.
+ *
+ * <p> This method initiates a read of up to <i>r</i> bytes from this channel,
+ * where <i>r</i> is the total number of bytes remaining in the specified
+ * subsequence of the given buffer array, that is,
+ *
+ * <blockquote><pre>
+ * dsts[offset].remaining()
+ * + dsts[offset+1].remaining()
+ * + ... + dsts[offset+length-1].remaining()</pre></blockquote>
+ *
+ * at the moment that the read is attempted.
+ *
+ * <p> Suppose that a byte sequence of length <i>n</i> is read, where
+ * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>.
+ * Up to the first <tt>dsts[offset].remaining()</tt> bytes of this sequence
+ * are transferred into buffer <tt>dsts[offset]</tt>, up to the next
+ * <tt>dsts[offset+1].remaining()</tt> bytes are transferred into buffer
+ * <tt>dsts[offset+1]</tt>, and so forth, until the entire byte sequence
+ * is transferred into the given buffers. As many bytes as possible are
+ * transferred into each buffer, hence the final position of each updated
+ * buffer, except the last updated buffer, is guaranteed to be equal to
+ * that buffer's limit. The underlying operating system may impose a limit
+ * on the number of buffers that may be used in an I/O operation. Where the
+ * number of buffers (with bytes remaining), exceeds this limit, then the
+ * I/O operation is performed with the maximum number of buffers allowed by
+ * the operating system.
+ *
+ * <p> If a timeout is specified and the timeout elapses before the operation
+ * completes then it completes with the exception {@link
+ * InterruptedByTimeoutException}. Where a timeout occurs, and the
+ * implementation cannot guarantee that bytes have not been read, or will not
+ * be read from the channel into the given buffers, then further attempts to
+ * read from the channel will cause an unspecific runtime exception to be
+ * thrown.
+ *
+ * @param dsts
+ * The buffers into which bytes are to be transferred
+ * @param offset
+ * The offset within the buffer array of the first buffer into which
+ * bytes are to be transferred; must be non-negative and no larger than
+ * {@code dsts.length}
+ * @param length
+ * The maximum number of buffers to be accessed; must be non-negative
+ * and no larger than {@code dsts.length - offset}
+ * @param timeout
+ * The maximum time for the I/O operation to complete
+ * @param unit
+ * The time unit of the {@code timeout} argument
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws IndexOutOfBoundsException
+ * If the pre-conditions for the {@code offset} and {@code length}
+ * parameter aren't met
+ * @throws IllegalArgumentException
+ * If the buffer is read-only
+ * @throws ReadPendingException
+ * If a read operation is already in progress on this channel
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ public abstract <A> void read(ByteBuffer[] dsts,
+ int offset,
+ int length,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Long,? super A> handler);
+
+ /**
+ * Writes a sequence of bytes to this channel from the given buffer.
+ *
+ * <p> This method initiates an asynchronous write operation to write a
+ * sequence of bytes to this channel from the given buffer. The {@code
+ * handler} parameter is a completion handler that is invoked when the write
+ * operation completes (or fails). The result passed to the completion
+ * handler is the number of bytes written.
+ *
+ * <p> If a timeout is specified and the timeout elapses before the operation
+ * completes then it completes with the exception {@link
+ * InterruptedByTimeoutException}. Where a timeout occurs, and the
+ * implementation cannot guarantee that bytes have not been written, or will
+ * not be written to the channel from the given buffer, then further attempts
+ * to write to the channel will cause an unspecific runtime exception to be
+ * thrown.
+ *
+ * <p> Otherwise this method works in the same manner as the {@link
+ * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
+ * method.
+ *
+ * @param src
+ * The buffer from which bytes are to be retrieved
+ * @param timeout
+ * The maximum time for the I/O operation to complete
+ * @param unit
+ * The time unit of the {@code timeout} argument
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws WritePendingException
+ * If a write operation is already in progress on this channel
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ public abstract <A> void write(ByteBuffer src,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler);
+
+ /**
+ * @throws WritePendingException {@inheritDoc}
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ @Override
+ public final <A> void write(ByteBuffer src,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler)
+
+ {
+ write(src, 0L, TimeUnit.MILLISECONDS, attachment, handler);
+ }
+
+ /**
+ * @throws WritePendingException {@inheritDoc}
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ */
+ @Override
+ public abstract Future<Integer> write(ByteBuffer src);
+
+ /**
+ * Writes a sequence of bytes to this channel from a subsequence of the given
+ * buffers. This operation, sometimes called a <em>gathering write</em>, is
+ * often useful when implementing network protocols that group data into
+ * segments consisting of one or more fixed-length headers followed by a
+ * variable-length body. The {@code handler} parameter is a completion
+ * handler that is invoked when the write operation completes (or fails).
+ * The result passed to the completion handler is the number of bytes written.
+ *
+ * <p> This method initiates a write of up to <i>r</i> bytes to this channel,
+ * where <i>r</i> is the total number of bytes remaining in the specified
+ * subsequence of the given buffer array, that is,
+ *
+ * <blockquote><pre>
+ * srcs[offset].remaining()
+ * + srcs[offset+1].remaining()
+ * + ... + srcs[offset+length-1].remaining()</pre></blockquote>
+ *
+ * at the moment that the write is attempted.
+ *
+ * <p> Suppose that a byte sequence of length <i>n</i> is written, where
+ * <tt>0</tt> <tt><</tt> <i>n</i> <tt><=</tt> <i>r</i>.
+ * Up to the first <tt>srcs[offset].remaining()</tt> bytes of this sequence
+ * are written from buffer <tt>srcs[offset]</tt>, up to the next
+ * <tt>srcs[offset+1].remaining()</tt> bytes are written from buffer
+ * <tt>srcs[offset+1]</tt>, and so forth, until the entire byte sequence is
+ * written. As many bytes as possible are written from each buffer, hence
+ * the final position of each updated buffer, except the last updated
+ * buffer, is guaranteed to be equal to that buffer's limit. The underlying
+ * operating system may impose a limit on the number of buffers that may be
+ * used in an I/O operation. Where the number of buffers (with bytes
+ * remaining), exceeds this limit, then the I/O operation is performed with
+ * the maximum number of buffers allowed by the operating system.
+ *
+ * <p> If a timeout is specified and the timeout elapses before the operation
+ * completes then it completes with the exception {@link
+ * InterruptedByTimeoutException}. Where a timeout occurs, and the
+ * implementation cannot guarantee that bytes have not been written, or will
+ * not be written to the channel from the given buffers, then further attempts
+ * to write to the channel will cause an unspecific runtime exception to be
+ * thrown.
+ *
+ * @param srcs
+ * The buffers from which bytes are to be retrieved
+ * @param offset
+ * The offset within the buffer array of the first buffer from which
+ * bytes are to be retrieved; must be non-negative and no larger
+ * than {@code srcs.length}
+ * @param length
+ * The maximum number of buffers to be accessed; must be non-negative
+ * and no larger than {@code srcs.length - offset}
+ * @param timeout
+ * The maximum time for the I/O operation to complete
+ * @param unit
+ * The time unit of the {@code timeout} argument
+ * @param attachment
+ * The object to attach to the I/O operation; can be {@code null}
+ * @param handler
+ * The handler for consuming the result
+ *
+ * @throws IndexOutOfBoundsException
+ * If the pre-conditions for the {@code offset} and {@code length}
+ * parameter aren't met
+ * @throws WritePendingException
+ * If a write operation is already in progress on this channel
+ * @throws NotYetConnectedException
+ * If this channel is not yet connected
+ * @throws ShutdownChannelGroupException
+ * If the channel group has terminated
+ */
+ public abstract <A> void write(ByteBuffer[] srcs,
+ int offset,
+ int length,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Long,? super A> handler);
+}
diff --git a/ojluni/src/main/java/java/nio/channels/Channels.java b/ojluni/src/main/java/java/nio/channels/Channels.java
index 204eafd..f27f0ab 100755
--- a/ojluni/src/main/java/java/nio/channels/Channels.java
+++ b/ojluni/src/main/java/java/nio/channels/Channels.java
@@ -181,6 +181,155 @@
};
}
+
+ /**
+ * Constructs a stream that reads bytes from the given channel.
+ *
+ * <p> The stream will not be buffered, and it will not support the {@link
+ * InputStream#mark mark} or {@link InputStream#reset reset} methods. The
+ * stream will be safe for access by multiple concurrent threads. Closing
+ * the stream will in turn cause the channel to be closed. </p>
+ *
+ * @param ch
+ * The channel from which bytes will be read
+ *
+ * @return A new input stream
+ *
+ * @since 1.7
+ */
+ public static InputStream newInputStream(final AsynchronousByteChannel ch) {
+ checkNotNull(ch, "ch");
+ return new InputStream() {
+
+ private ByteBuffer bb = null;
+ private byte[] bs = null; // Invoker's previous array
+ private byte[] b1 = null;
+
+ @Override
+ public synchronized int read() throws IOException {
+ if (b1 == null)
+ b1 = new byte[1];
+ int n = this.read(b1);
+ if (n == 1)
+ return b1[0] & 0xff;
+ return -1;
+ }
+
+ @Override
+ public synchronized int read(byte[] bs, int off, int len)
+ throws IOException
+ {
+ if ((off < 0) || (off > bs.length) || (len < 0) ||
+ ((off + len) > bs.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0)
+ return 0;
+
+ ByteBuffer bb = ((this.bs == bs)
+ ? this.bb
+ : ByteBuffer.wrap(bs));
+ bb.position(off);
+ bb.limit(Math.min(off + len, bb.capacity()));
+ this.bb = bb;
+ this.bs = bs;
+
+ boolean interrupted = false;
+ try {
+ for (;;) {
+ try {
+ return ch.read(bb).get();
+ } catch (ExecutionException ee) {
+ throw new IOException(ee.getCause());
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ ch.close();
+ }
+ };
+ }
+
+ /**
+ * Constructs a stream that writes bytes to the given channel.
+ *
+ * <p> The stream will not be buffered. The stream will be safe for access
+ * by multiple concurrent threads. Closing the stream will in turn cause
+ * the channel to be closed. </p>
+ *
+ * @param ch
+ * The channel to which bytes will be written
+ *
+ * @return A new output stream
+ *
+ * @since 1.7
+ */
+ public static OutputStream newOutputStream(final AsynchronousByteChannel ch) {
+ checkNotNull(ch, "ch");
+ return new OutputStream() {
+
+ private ByteBuffer bb = null;
+ private byte[] bs = null; // Invoker's previous array
+ private byte[] b1 = null;
+
+ @Override
+ public synchronized void write(int b) throws IOException {
+ if (b1 == null)
+ b1 = new byte[1];
+ b1[0] = (byte)b;
+ this.write(b1);
+ }
+
+ @Override
+ public synchronized void write(byte[] bs, int off, int len)
+ throws IOException
+ {
+ if ((off < 0) || (off > bs.length) || (len < 0) ||
+ ((off + len) > bs.length) || ((off + len) < 0)) {
+ throw new IndexOutOfBoundsException();
+ } else if (len == 0) {
+ return;
+ }
+ ByteBuffer bb = ((this.bs == bs)
+ ? this.bb
+ : ByteBuffer.wrap(bs));
+ bb.limit(Math.min(off + len, bb.capacity()));
+ bb.position(off);
+ this.bb = bb;
+ this.bs = bs;
+
+ boolean interrupted = false;
+ try {
+ while (bb.remaining() > 0) {
+ try {
+ ch.write(bb).get();
+ } catch (ExecutionException ee) {
+ throw new IOException(ee.getCause());
+ } catch (InterruptedException ie) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted)
+ Thread.currentThread().interrupt();
+ }
+ }
+
+ @Override
+ public void close() throws IOException {
+ ch.close();
+ }
+ };
+ }
+
+
// -- Channels from streams --
/**
diff --git a/ojluni/src/main/java/java/nio/channels/CompletionHandler.java b/ojluni/src/main/java/java/nio/channels/CompletionHandler.java
new file mode 100755
index 0000000..2574dbf
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/CompletionHandler.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+/**
+ * A handler for consuming the result of an asynchronous I/O operation.
+ *
+ * <p> The asynchronous channels defined in this package allow a completion
+ * handler to be specified to consume the result of an asynchronous operation.
+ * The {@link #completed completed} method is invoked when the I/O operation
+ * completes successfully. The {@link #failed failed} method is invoked if the
+ * I/O operations fails. The implementations of these methods should complete
+ * in a timely manner so as to avoid keeping the invoking thread from dispatching
+ * to other completion handlers.
+ *
+ * @param <V> The result type of the I/O operation
+ * @param <A> The type of the object attached to the I/O operation
+ *
+ * @since 1.7
+ */
+
+public interface CompletionHandler<V,A> {
+
+ /**
+ * Invoked when an operation has completed.
+ *
+ * @param result
+ * The result of the I/O operation.
+ * @param attachment
+ * The object attached to the I/O operation when it was initiated.
+ */
+ void completed(V result, A attachment);
+
+ /**
+ * Invoked when an operation fails.
+ *
+ * @param exc
+ * The exception to indicate why the I/O operation failed
+ * @param attachment
+ * The object attached to the I/O operation when it was initiated.
+ */
+ void failed(Throwable exc, A attachment);
+}
diff --git a/ojluni/src/main/java/java/nio/channels/DatagramChannel.java b/ojluni/src/main/java/java/nio/channels/DatagramChannel.java
index 3e49074..f4a6110 100755
--- a/ojluni/src/main/java/java/nio/channels/DatagramChannel.java
+++ b/ojluni/src/main/java/java/nio/channels/DatagramChannel.java
@@ -112,7 +112,7 @@
public abstract class DatagramChannel
extends AbstractSelectableChannel
- implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, NetworkChannel
+ implements ByteChannel, ScatteringByteChannel, GatheringByteChannel, MulticastChannel
{
/**
diff --git a/ojluni/src/main/java/java/nio/channels/IllegalChannelGroupException.java b/ojluni/src/main/java/java/nio/channels/IllegalChannelGroupException.java
new file mode 100644
index 0000000..dd47105
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/IllegalChannelGroupException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to open a channel
+ * in a group that was not created by the same provider.
+ *
+ * @since 1.7
+ */
+
+public class IllegalChannelGroupException
+ extends IllegalArgumentException
+{
+
+ private static final long serialVersionUID = -2495041211157744253L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public IllegalChannelGroupException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/InterruptedByTimeoutException.java b/ojluni/src/main/java/java/nio/channels/InterruptedByTimeoutException.java
new file mode 100644
index 0000000..ae2018d
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/InterruptedByTimeoutException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Checked exception received by a thread when a timeout elapses before an
+ * asynchronous operation completes.
+ *
+ * @since 1.7
+ */
+
+public class InterruptedByTimeoutException
+ extends java.io.IOException
+{
+
+ private static final long serialVersionUID = -4268008601014042947L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public InterruptedByTimeoutException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/MembershipKey.java b/ojluni/src/main/java/java/nio/channels/MembershipKey.java
new file mode 100755
index 0000000..ea7536a
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/MembershipKey.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+
+/**
+ * A token representing the membership of an Internet Protocol (IP) multicast
+ * group.
+ *
+ * <p> A membership key may represent a membership to receive all datagrams sent
+ * to the group, or it may be <em>source-specific</em>, meaning that it
+ * represents a membership that receives only datagrams from a specific source
+ * address. Whether or not a membership key is source-specific may be determined
+ * by invoking its {@link #sourceAddress() sourceAddress} method.
+ *
+ * <p> A membership key is valid upon creation and remains valid until the
+ * membership is dropped by invoking the {@link #drop() drop} method, or
+ * the channel is closed. The validity of the membership key may be tested
+ * by invoking its {@link #isValid() isValid} method.
+ *
+ * <p> Where a membership key is not source-specific and the underlying operation
+ * system supports source filtering, then the {@link #block block} and {@link
+ * #unblock unblock} methods can be used to block or unblock multicast datagrams
+ * from particular source addresses.
+ *
+ * @see MulticastChannel
+ *
+ * @since 1.7
+ */
+public abstract class MembershipKey {
+
+ /**
+ * Initializes a new instance of this class.
+ */
+ protected MembershipKey() {
+ }
+
+ /**
+ * Tells whether or not this membership is valid.
+ *
+ * <p> A multicast group membership is valid upon creation and remains
+ * valid until the membership is dropped by invoking the {@link #drop() drop}
+ * method, or the channel is closed.
+ *
+ * @return {@code true} if this membership key is valid, {@code false}
+ * otherwise
+ */
+ public abstract boolean isValid();
+
+ /**
+ * Drop membership.
+ *
+ * <p> If the membership key represents a membership to receive all datagrams
+ * then the membership is dropped and the channel will no longer receive any
+ * datagrams sent to the group. If the membership key is source-specific
+ * then the channel will no longer receive datagrams sent to the group from
+ * that source address.
+ *
+ * <p> After membership is dropped it may still be possible to receive
+ * datagrams sent to the group. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer. After membership is dropped
+ * then the channel may {@link MulticastChannel#join join} the group again
+ * in which case a new membership key is returned.
+ *
+ * <p> Upon return, this membership object will be {@link #isValid() invalid}.
+ * If the multicast group membership is already invalid then invoking this
+ * method has no effect. Once a multicast group membership is invalid,
+ * it remains invalid forever.
+ */
+ public abstract void drop();
+
+ /**
+ * Block multicast datagrams from the given source address.
+ *
+ * <p> If this membership key is not source-specific, and the underlying
+ * operating system supports source filtering, then this method blocks
+ * multicast datagrams from the given source address. If the given source
+ * address is already blocked then this method has no effect.
+ * After a source address is blocked it may still be possible to receive
+ * datagams from that source. This can arise when datagrams are waiting to
+ * be received in the socket's receive buffer.
+ *
+ * @param source
+ * The source address to block
+ *
+ * @return This membership key
+ *
+ * @throws IllegalArgumentException
+ * If the {@code source} parameter is not a unicast address or
+ * is not the same address type as the multicast group
+ * @throws IllegalStateException
+ * If this membership key is source-specific or is no longer valid
+ * @throws UnsupportedOperationException
+ * If the underlying operating system does not support source
+ * filtering
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract MembershipKey block(InetAddress source) throws IOException;
+
+ /**
+ * Unblock multicast datagrams from the given source address that was
+ * previously blocked using the {@link #block(InetAddress) block} method.
+ *
+ * @param source
+ * The source address to unblock
+ *
+ * @return This membership key
+ *
+ * @throws IllegalStateException
+ * If the given source address is not currently blocked or the
+ * membership key is no longer valid
+ */
+ public abstract MembershipKey unblock(InetAddress source);
+
+ /**
+ * Returns the channel for which this membership key was created. This
+ * method will continue to return the channel even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the channel
+ */
+ public abstract MulticastChannel channel();
+
+ /**
+ * Returns the multicast group for which this membership key was created.
+ * This method will continue to return the group even after the membership
+ * becomes {@link #isValid invalid}.
+ *
+ * @return the multicast group
+ */
+ public abstract InetAddress group();
+
+ /**
+ * Returns the network interface for which this membership key was created.
+ * This method will continue to return the network interface even after the
+ * membership becomes {@link #isValid invalid}.
+ *
+ * @return the network interface
+ */
+ public abstract NetworkInterface networkInterface();
+
+ /**
+ * Returns the source address if this membership key is source-specific,
+ * or {@code null} if this membership is not source-specific.
+ *
+ * @return The source address if this membership key is source-specific,
+ * otherwise {@code null}
+ */
+ public abstract InetAddress sourceAddress();
+}
diff --git a/ojluni/src/main/java/java/nio/channels/MulticastChannel.java b/ojluni/src/main/java/java/nio/channels/MulticastChannel.java
new file mode 100755
index 0000000..5b61f77
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/MulticastChannel.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2007, 2009, 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.nio.channels;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.net.ProtocolFamily; // javadoc
+import java.net.StandardProtocolFamily; // javadoc
+import java.net.StandardSocketOptions; // javadoc
+
+/**
+ * A network channel that supports Internet Protocol (IP) multicasting.
+ *
+ * <p> IP multicasting is the transmission of IP datagrams to members of
+ * a <em>group</em> that is zero or more hosts identified by a single destination
+ * address.
+ *
+ * <p> In the case of a channel to an {@link StandardProtocolFamily#INET IPv4} socket,
+ * the underlying operating system supports <a href="http://www.ietf.org/rfc/rfc2236.txt">
+ * <i>RFC 2236: Internet Group Management Protocol, Version 2 (IGMPv2)</i></a>.
+ * It may optionally support source filtering as specified by <a
+ * href="http://www.ietf.org/rfc/rfc3376.txt"> <i>RFC 3376: Internet Group
+ * Management Protocol, Version 3 (IGMPv3)</i></a>.
+ * For channels to an {@link StandardProtocolFamily#INET6 IPv6} socket, the equivalent
+ * standards are <a href="http://www.ietf.org/rfc/rfc2710.txt"> <i>RFC 2710:
+ * Multicast Listener Discovery (MLD) for IPv6</i></a> and <a
+ * href="http://www.ietf.org/rfc/rfc3810.txt"> <i>RFC 3810: Multicast Listener
+ * Discovery Version 2 (MLDv2) for IPv6</i></a>.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface)} method is used to
+ * join a group and receive all multicast datagrams sent to the group. A channel
+ * may join several multicast groups and may join the same group on several
+ * {@link NetworkInterface interfaces}. Membership is dropped by invoking the {@link
+ * MembershipKey#drop drop} method on the returned {@link MembershipKey}. If the
+ * underlying platform supports source filtering then the {@link MembershipKey#block
+ * block} and {@link MembershipKey#unblock unblock} methods can be used to block or
+ * unblock multicast datagrams from particular source addresses.
+ *
+ * <p> The {@link #join(InetAddress,NetworkInterface,InetAddress)} method
+ * is used to begin receiving datagrams sent to a group whose source address matches
+ * a given source address. This method throws {@link UnsupportedOperationException}
+ * if the underlying platform does not support source filtering. Membership is
+ * <em>cumulative</em> and this method may be invoked again with the same group
+ * and interface to allow receiving datagrams from other source addresses. The
+ * method returns a {@link MembershipKey} that represents membership to receive
+ * datagrams from the given source address. Invoking the key's {@link
+ * MembershipKey#drop drop} method drops membership so that datagrams from the
+ * source address can no longer be received.
+ *
+ * <h4>Platform dependencies</h4>
+ *
+ * The multicast implementation is intended to map directly to the native
+ * multicasting facility. Consequently, the following items should be considered
+ * when developing an application that receives IP multicast datagrams:
+ *
+ * <ol>
+ *
+ * <li><p> The creation of the channel should specify the {@link ProtocolFamily}
+ * that corresponds to the address type of the multicast groups that the channel
+ * will join. There is no guarantee that a channel to a socket in one protocol
+ * family can join and receive multicast datagrams when the address of the
+ * multicast group corresponds to another protocol family. For example, it is
+ * implementation specific if a channel to an {@link StandardProtocolFamily#INET6 IPv6}
+ * socket can join an {@link StandardProtocolFamily#INET IPv4} multicast group and receive
+ * multicast datagrams sent to the group. </p></li>
+ *
+ * <li><p> The channel's socket should be bound to the {@link
+ * InetAddress#isAnyLocalAddress wildcard} address. If the socket is bound to
+ * a specific address, rather than the wildcard address then it is implementation
+ * specific if multicast datagrams are received by the socket. </p></li>
+ *
+ * <li><p> The {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} option should be
+ * enabled prior to {@link NetworkChannel#bind binding} the socket. This is
+ * required to allow multiple members of the group to bind to the same
+ * address. </p></li>
+ *
+ * </ol>
+ *
+ * <p> <b>Usage Example:</b>
+ * <pre>
+ * // join multicast group on this interface, and also use this
+ * // interface for outgoing multicast datagrams
+ * NetworkInterface ni = NetworkInterface.getByName("hme0");
+ *
+ * DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)
+ * .setOption(StandardSocketOptions.SO_REUSEADDR, true)
+ * .bind(new InetSocketAddress(5000))
+ * .setOption(StandardSocketOptions.IP_MULTICAST_IF, ni);
+ *
+ * InetAddress group = InetAddress.getByName("225.4.5.6");
+ *
+ * MembershipKey key = dc.join(group, ni);
+ * </pre>
+ *
+ * @since 1.7
+ */
+
+public interface MulticastChannel
+ extends NetworkChannel
+{
+ /**
+ * Closes this channel.
+ *
+ * <p> If the channel is a member of a multicast group then the membership
+ * is {@link MembershipKey#drop dropped}. Upon return, the {@link
+ * MembershipKey membership-key} will be {@link MembershipKey#isValid
+ * invalid}.
+ *
+ * <p> This method otherwise behaves exactly as specified by the {@link
+ * Channel} interface.
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ @Override void close() throws IOException;
+
+ /**
+ * Joins a multicast group to begin receiving all datagrams sent to the group,
+ * returning a membership key.
+ *
+ * <p> If this channel is currently a member of the group on the given
+ * interface to receive all datagrams then the membership key, representing
+ * that membership, is returned. Otherwise this channel joins the group and
+ * the resulting new membership key is returned. The resulting membership key
+ * is not {@link MembershipKey#sourceAddress source-specific}.
+ *
+ * <p> A multicast channel may join several multicast groups, including
+ * the same group on more than one interface. An implementation may impose a
+ * limit on the number of groups that may be joined at the same time.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link InetAddress#isMulticastAddress
+ * multicast} address, or the group parameter is an address type
+ * that is not supported by this channel
+ * @throws IllegalStateException
+ * If the channel already has source-specific membership of the
+ * group on the interface
+ * @throws UnsupportedOperationException
+ * If the channel's socket is not an Internet Protocol socket
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf)
+ throws IOException;
+
+ /**
+ * Joins a multicast group to begin receiving datagrams sent to the group
+ * from a given source address.
+ *
+ * <p> If this channel is currently a member of the group on the given
+ * interface to receive datagrams from the given source address then the
+ * membership key, representing that membership, is returned. Otherwise this
+ * channel joins the group and the resulting new membership key is returned.
+ * The resulting membership key is {@link MembershipKey#sourceAddress
+ * source-specific}.
+ *
+ * <p> Membership is <em>cumulative</em> and this method may be invoked
+ * again with the same group and interface to allow receiving datagrams sent
+ * by other source addresses to the group.
+ *
+ * @param group
+ * The multicast address to join
+ * @param interf
+ * The network interface on which to join the group
+ * @param source
+ * The source address
+ *
+ * @return The membership key
+ *
+ * @throws IllegalArgumentException
+ * If the group parameter is not a {@link
+ * InetAddress#isMulticastAddress multicast} address, the
+ * source parameter is not a unicast address, the group
+ * parameter is an address type that is not supported by this channel,
+ * or the source parameter is not the same address type as the group
+ * @throws IllegalStateException
+ * If the channel is currently a member of the group on the given
+ * interface to receive all datagrams
+ * @throws UnsupportedOperationException
+ * If the channel's socket is not an Internet Protocol socket or
+ * source filtering is not supported
+ * @throws ClosedChannelException
+ * If this channel is closed
+ * @throws IOException
+ * If an I/O error occurs
+ * @throws SecurityException
+ * If a security manager is set, and its
+ * {@link SecurityManager#checkMulticast(InetAddress) checkMulticast}
+ * method denies access to the multiast group
+ */
+ MembershipKey join(InetAddress group, NetworkInterface interf, InetAddress source)
+ throws IOException;
+}
diff --git a/ojluni/src/main/java/java/nio/channels/ReadPendingException.java b/ojluni/src/main/java/java/nio/channels/ReadPendingException.java
new file mode 100644
index 0000000..770c9de
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/ReadPendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to read from an
+ * asynchronous socket channel and a previous read has not completed.
+ *
+ * @since 1.7
+ */
+
+public class ReadPendingException
+ extends IllegalStateException
+{
+
+ private static final long serialVersionUID = 1986315242191227217L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public ReadPendingException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java b/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
index 127fb5b..63ed42f 100755
--- a/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
+++ b/ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java
@@ -138,7 +138,7 @@
* @return This channel
*
* @throws AlreadyBoundException {@inheritDoc}
- * @throws UnsupportedAddressTypeException {@inheritDoc}
+ * @throws UnresolvedAddressException
* @throws ClosedChannelException {@inheritDoc}
* @throws IOException {@inheritDoc}
* @throws SecurityException
diff --git a/ojluni/src/main/java/java/nio/channels/ShutdownChannelGroupException.java b/ojluni/src/main/java/java/nio/channels/ShutdownChannelGroupException.java
new file mode 100644
index 0000000..b4e4b7d
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/ShutdownChannelGroupException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to construct a channel in
+ * a group that is shutdown or the completion handler for an I/O operation
+ * cannot be invoked because the channel group has terminated.
+ *
+ * @since 1.7
+ */
+
+public class ShutdownChannelGroupException
+ extends IllegalStateException
+{
+
+ private static final long serialVersionUID = -3903801676350154157L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public ShutdownChannelGroupException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/WritePendingException.java b/ojluni/src/main/java/java/nio/channels/WritePendingException.java
new file mode 100644
index 0000000..8957702
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/WritePendingException.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2000, 2007, 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.
+ *
+ */
+
+// -- This file was mechanically generated: Do not edit! -- //
+
+package java.nio.channels;
+
+
+/**
+ * Unchecked exception thrown when an attempt is made to write to an
+ * asynchronous socket channel and a previous write has not completed.
+ *
+ * @since 1.7
+ */
+
+public class WritePendingException
+ extends IllegalStateException
+{
+
+ private static final long serialVersionUID = 7031871839266032276L;
+
+ /**
+ * Constructs an instance of this class.
+ */
+ public WritePendingException() { }
+
+}
diff --git a/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
new file mode 100755
index 0000000..827a2c5
--- /dev/null
+++ b/ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2007, 2010, 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.nio.channels.spi;
+
+import java.nio.channels.*;
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.ServiceLoader;
+import java.util.ServiceConfigurationError;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Service-provider class for asynchronous channels.
+ *
+ * <p> An asynchronous channel provider is a concrete subclass of this class that
+ * has a zero-argument constructor and implements the abstract methods specified
+ * below. A given invocation of the Java virtual machine maintains a single
+ * system-wide default provider instance, which is returned by the {@link
+ * #provider() provider} method. The first invocation of that method will locate
+ * the default provider as specified below.
+ *
+ * <p> All of the methods in this class are safe for use by multiple concurrent
+ * threads. </p>
+ *
+ * @since 1.7
+ */
+
+public abstract class AsynchronousChannelProvider {
+ private static Void checkPermission() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkPermission(new RuntimePermission("asynchronousChannelProvider"));
+ return null;
+ }
+ private AsynchronousChannelProvider(Void ignore) { }
+
+ /**
+ * Initializes a new instance of this class.
+ *
+ * @throws SecurityException
+ * If a security manager has been installed and it denies
+ * {@link RuntimePermission}<tt>("asynchronousChannelProvider")</tt>
+ */
+ protected AsynchronousChannelProvider() {
+ this(checkPermission());
+ }
+
+ // lazy initialization of default provider
+ private static class ProviderHolder {
+ static final AsynchronousChannelProvider provider = load();
+
+ private static AsynchronousChannelProvider load() {
+ return AccessController
+ .doPrivileged(new PrivilegedAction<AsynchronousChannelProvider>() {
+ public AsynchronousChannelProvider run() {
+ AsynchronousChannelProvider p;
+ p = loadProviderFromProperty();
+ if (p != null)
+ return p;
+ p = loadProviderAsService();
+ if (p != null)
+ return p;
+ return sun.nio.ch.DefaultAsynchronousChannelProvider.create();
+ }});
+ }
+
+ private static AsynchronousChannelProvider loadProviderFromProperty() {
+ String cn = System.getProperty("java.nio.channels.spi.AsynchronousChannelProvider");
+ if (cn == null)
+ return null;
+ try {
+ Class<?> c = Class.forName(cn, true,
+ ClassLoader.getSystemClassLoader());
+ return (AsynchronousChannelProvider)c.newInstance();
+ } catch (ClassNotFoundException x) {
+ throw new ServiceConfigurationError(null, x);
+ } catch (IllegalAccessException x) {
+ throw new ServiceConfigurationError(null, x);
+ } catch (InstantiationException x) {
+ throw new ServiceConfigurationError(null, x);
+ } catch (SecurityException x) {
+ throw new ServiceConfigurationError(null, x);
+ }
+ }
+
+ private static AsynchronousChannelProvider loadProviderAsService() {
+ ServiceLoader<AsynchronousChannelProvider> sl =
+ ServiceLoader.load(AsynchronousChannelProvider.class,
+ ClassLoader.getSystemClassLoader());
+ Iterator<AsynchronousChannelProvider> i = sl.iterator();
+ for (;;) {
+ try {
+ return (i.hasNext()) ? i.next() : null;
+ } catch (ServiceConfigurationError sce) {
+ if (sce.getCause() instanceof SecurityException) {
+ // Ignore the security exception, try the next provider
+ continue;
+ }
+ throw sce;
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the system-wide default asynchronous channel provider for this
+ * invocation of the Java virtual machine.
+ *
+ * <p> The first invocation of this method locates the default provider
+ * object as follows: </p>
+ *
+ * <ol>
+ *
+ * <li><p> If the system property
+ * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> is defined
+ * then it is taken to be the fully-qualified name of a concrete provider class.
+ * The class is loaded and instantiated; if this process fails then an
+ * unspecified error is thrown. </p></li>
+ *
+ * <li><p> If a provider class has been installed in a jar file that is
+ * visible to the system class loader, and that jar file contains a
+ * provider-configuration file named
+ * <tt>java.nio.channels.spi.AsynchronousChannelProvider</tt> in the resource
+ * directory <tt>META-INF/services</tt>, then the first class name
+ * specified in that file is taken. The class is loaded and
+ * instantiated; if this process fails then an unspecified error is
+ * thrown. </p></li>
+ *
+ * <li><p> Finally, if no provider has been specified by any of the above
+ * means then the system-default provider class is instantiated and the
+ * result is returned. </p></li>
+ *
+ * </ol>
+ *
+ * <p> Subsequent invocations of this method return the provider that was
+ * returned by the first invocation. </p>
+ *
+ * @return The system-wide default AsynchronousChannel provider
+ */
+ public static AsynchronousChannelProvider provider() {
+ return ProviderHolder.provider;
+ }
+
+ /**
+ * Constructs a new asynchronous channel group with a fixed thread pool.
+ *
+ * @param nThreads
+ * The number of threads in the pool
+ * @param threadFactory
+ * The factory to use when creating new threads
+ *
+ * @throws IllegalArgumentException
+ * If {@code nThreads <= 0}
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see AsynchronousChannelGroup#withFixedThreadPool
+ */
+ public abstract AsynchronousChannelGroup
+ openAsynchronousChannelGroup(int nThreads, ThreadFactory threadFactory) throws IOException;
+
+ /**
+ * Constructs a new asynchronous channel group with the given thread pool.
+ *
+ * @param executor
+ * The thread pool
+ * @param initialSize
+ * A value {@code >=0} or a negative value for implementation
+ * specific default
+ *
+ * @throws IOException
+ * If an I/O error occurs
+ *
+ * @see AsynchronousChannelGroup#withCachedThreadPool
+ */
+ public abstract AsynchronousChannelGroup
+ openAsynchronousChannelGroup(ExecutorService executor, int initialSize) throws IOException;
+
+ /**
+ * Opens an asynchronous server-socket channel.
+ *
+ * @param group
+ * The group to which the channel is bound, or {@code null} to
+ * bind to the default group
+ *
+ * @return The new channel
+ *
+ * @throws IllegalChannelGroupException
+ * If the provider that created the group differs from this provider
+ * @throws ShutdownChannelGroupException
+ * The group is shutdown
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract AsynchronousServerSocketChannel openAsynchronousServerSocketChannel
+ (AsynchronousChannelGroup group) throws IOException;
+
+ /**
+ * Opens an asynchronous socket channel.
+ *
+ * @param group
+ * The group to which the channel is bound, or {@code null} to
+ * bind to the default group
+ *
+ * @return The new channel
+ *
+ * @throws IllegalChannelGroupException
+ * If the provider that created the group differs from this provider
+ * @throws ShutdownChannelGroupException
+ * The group is shutdown
+ * @throws IOException
+ * If an I/O error occurs
+ */
+ public abstract AsynchronousSocketChannel openAsynchronousSocketChannel
+ (AsynchronousChannelGroup group) throws IOException;
+}
diff --git a/ojluni/src/main/java/java/security/Key.java b/ojluni/src/main/java/java/security/Key.java
index 2df0f3e..9322710 100755
--- a/ojluni/src/main/java/java/security/Key.java
+++ b/ojluni/src/main/java/java/security/Key.java
@@ -83,7 +83,7 @@
* <p> A Key should use KeyRep as its serialized representation.
* Note that a serialized Key may contain sensitive information
* which should not be exposed in untrusted environments. See the
- * <a href="../../../platform/serialization/spec/security.html">
+ * <a href="{@docRoot}/../platform/serialization/spec/security.html">
* Security Appendix</a>
* of the Serialization Specification for more information.
*
diff --git a/ojluni/src/main/java/java/security/KeyRep.java b/ojluni/src/main/java/java/security/KeyRep.java
index b7d94f1..20e3e2f 100755
--- a/ojluni/src/main/java/java/security/KeyRep.java
+++ b/ojluni/src/main/java/java/security/KeyRep.java
@@ -41,7 +41,7 @@
*
* Note that a serialized Key may contain sensitive information
* which should not be exposed in untrusted environments. See the
- * <a href="../../../platform/serialization/spec/security.html">
+ * <a href="{@docRoot}/../platform/serialization/spec/security.html">
* Security Appendix</a>
* of the Serialization Specification for more information.
*
diff --git a/ojluni/src/main/java/java/security/Provider.java b/ojluni/src/main/java/java/security/Provider.java
index 6493f29..75cbeb8 100755
--- a/ojluni/src/main/java/java/security/Provider.java
+++ b/ojluni/src/main/java/java/security/Provider.java
@@ -627,7 +627,7 @@
if (typeAndAlg == null) {
return;
}
- String type = getEngineName(typeAndAlg[0]);
+ String type = typeAndAlg[0];
String aliasAlg = typeAndAlg[1].intern();
ServiceKey key = new ServiceKey(type, stdAlg, true);
Service s = legacyMap.get(key);
@@ -647,7 +647,7 @@
int i = typeAndAlg[1].indexOf(' ');
if (i == -1) {
// e.g. put("MessageDigest.SHA-1", "sun.security.provider.SHA");
- String type = getEngineName(typeAndAlg[0]);
+ String type = typeAndAlg[0];
String stdAlg = typeAndAlg[1].intern();
String className = value;
ServiceKey key = new ServiceKey(type, stdAlg, true);
@@ -662,7 +662,7 @@
} else { // attribute
// e.g. put("MessageDigest.SHA-1 ImplementedIn", "Software");
String attributeValue = value;
- String type = getEngineName(typeAndAlg[0]);
+ String type = typeAndAlg[0];
String attributeString = typeAndAlg[1];
String stdAlg = attributeString.substring(0, i).intern();
String attributeName = attributeString.substring(i + 1);
@@ -766,7 +766,7 @@
* it is replaced by the new service.
* This method also places information about this service
* in the provider's Hashtable values in the format described in the
- * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+ * <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
* Java Cryptography Architecture API Specification & Reference </a>.
*
* <p>Also, if there is a security manager, its
@@ -974,8 +974,10 @@
private static void addEngine(String name, boolean sp, String paramName) {
EngineDescription ed = new EngineDescription(name, sp, paramName);
- // also index by canonical name to avoid toLowerCase() for some lookups
- knownEngines.put(name.toLowerCase(ENGLISH), ed);
+ // NOTE: The original OpenJDK code supported case-insensitive lookups on the list
+ // of known engines.
+ //
+ // knownEngines.put(name.toLowerCase(ENGLISH), ed);
knownEngines.put(name, ed);
}
@@ -1026,17 +1028,6 @@
"java.lang.Object");
}
- // get the "standard" (mixed-case) engine name for arbitary case engine name
- // if there is no known engine by that name, return s
- private static String getEngineName(String s) {
- // try original case first, usually correct
- EngineDescription e = knownEngines.get(s);
- if (e == null) {
- e = knownEngines.get(s.toLowerCase(ENGLISH));
- }
- return (e == null) ? s : e.name;
- }
-
/**
* The description of a security service. It encapsulates the properties
* of a service and contains a factory method to obtain new implementation
@@ -1054,7 +1045,7 @@
* suitable services and instantes them. The valid arguments to those
* methods depend on the type of service. For the service types defined
* within Java SE, see the
- * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+ * <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
* Java Cryptography Architecture API Specification & Reference </a>
* for the valid values.
* Note that components outside of Java SE can define additional types of
@@ -1140,7 +1131,8 @@
throw new NullPointerException();
}
this.provider = provider;
- this.type = getEngineName(type);
+ // Android-changed.
+ this.type = type;
this.algorithm = algorithm;
this.className = className;
if (aliases == null) {
@@ -1230,7 +1222,7 @@
* instantiation in a different way.
* For details and the values of constructorParameter that are
* valid for the various types of services see the
- * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+ * <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
* Java Cryptography Architecture API Specification &
* Reference</a>.
*
@@ -1367,7 +1359,7 @@
*
* <p>For details and the values of parameter that are valid for the
* various types of services see the top of this class and the
- * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">
+ * <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">
* Java Cryptography Architecture API Specification &
* Reference</a>.
* Security providers can override it to implement their own test.
@@ -1530,5 +1522,4 @@
public boolean isRegistered() {
return registered;
}
-
}
diff --git a/ojluni/src/main/java/java/security/Security.java b/ojluni/src/main/java/java/security/Security.java
index 9b8cba9..b7f7ca9 100755
--- a/ojluni/src/main/java/java/security/Security.java
+++ b/ojluni/src/main/java/java/security/Security.java
@@ -59,19 +59,26 @@
static {
props = new Properties();
boolean loadedProps = false;
- Reader input = null;
+ InputStream is = null;
try {
- input = getSecurityPropertiesReader();
- props.load(input);
- loadedProps = true;
- } catch (Exception ex) {
+ /*
+ * Android keeps the property file in a jar resource.
+ */
+ InputStream propStream = Security.class.getResourceAsStream("security.properties");
+ if (propStream == null) {
+ System.logE("Could not find 'security.properties'.");
+ } else {
+ is = new BufferedInputStream(propStream);
+ props.load(is);
+ loadedProps = true;
+ }
+ } catch (IOException ex) {
System.logE("Could not load 'security.properties'", ex);
} finally {
- if (input != null) {
+ if (is != null) {
try {
- input.close();
- } catch (IOException ignored) {
- }
+ is.close();
+ } catch (IOException ignored) {}
}
}
@@ -80,13 +87,6 @@
}
}
- // Do not refactor or change this name. The runtime provides a cutout for this method
- // to let this class be compile time initializable.
- private static Reader getSecurityPropertiesReader() throws Exception {
- InputStream configStream = Security.class.getResourceAsStream("security.properties");
- return new InputStreamReader(new BufferedInputStream(configStream), "ISO-8859-1");
- }
-
/*
* Initialize to default values, if <java.home>/lib/java.security
* is not found.
@@ -953,7 +953,7 @@
* an empty Set if there is no provider that supports the
* specified service or if serviceName is null. For a complete list
* of Java cryptographic services, please see the
- * <a href="../../../technotes/guides/security/crypto/CryptoSpec.html">Java
+ * <a href="{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html">Java
* Cryptography Architecture API Specification & Reference</a>.
* Note: the returned set is immutable.
*
diff --git a/ojluni/src/main/java/java/sql/DriverManager.java b/ojluni/src/main/java/java/sql/DriverManager.java
index 0968db9..d1a9054 100755
--- a/ojluni/src/main/java/java/sql/DriverManager.java
+++ b/ojluni/src/main/java/java/sql/DriverManager.java
@@ -53,7 +53,7 @@
* </pre>
*<P> The <code>DriverManager</code> methods <code>getConnection</code> and
* <code>getDrivers</code> have been enhanced to support the Java Standard Edition
- * <a href="../../../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
+ * <a href="{@docRoot}/../technotes/guides/jar/jar.html#Service%20Provider">Service Provider</a> mechanism. JDBC 4.0 Drivers must
* include the file <code>META-INF/services/java.sql.Driver</code>. This file contains the name of the JDBC drivers
* implementation of <code>java.sql.Driver</code>. For example, to load the <code>my.sql.Driver</code> class,
* the <code>META-INF/services/java.sql.Driver</code> file would contain the entry:
diff --git a/ojluni/src/main/java/java/sql/package.html b/ojluni/src/main/java/java/sql/package.html
index 65d906b..673aa07 100755
--- a/ojluni/src/main/java/java/sql/package.html
+++ b/ojluni/src/main/java/java/sql/package.html
@@ -310,7 +310,7 @@
<h2>Related Documentation</h2>
<ul>
- <li><a href="../../../technotes/guides/jdbc/getstart/GettingStartedTOC.fm.html">Getting Started</a>--overviews of the major interfaces
+ <li><a href="{@docRoot}/../technotes/guides/jdbc/getstart/GettingStartedTOC.fm.html">Getting Started</a>--overviews of the major interfaces
<P>
<li><a href="http://java.sun.com/docs/books/tutorial/jdbc">Chapters on the JDBC
API</a>--from the online version of <i>The Java Tutorial Continued</i>
diff --git a/ojluni/src/main/java/java/text/ChoiceFormat.java b/ojluni/src/main/java/java/text/ChoiceFormat.java
index f513cd9..ccbd24f 100755
--- a/ojluni/src/main/java/java/text/ChoiceFormat.java
+++ b/ojluni/src/main/java/java/text/ChoiceFormat.java
@@ -208,7 +208,7 @@
} else if (tempBuffer.equals("-\u221E")) {
startValue = Double.NEGATIVE_INFINITY;
} else {
- startValue = Double.valueOf(segments[0].toString()).doubleValue();
+ startValue = Double.parseDouble(segments[0].toString());
}
} catch (Exception e) {
throw new IllegalArgumentException();
diff --git a/ojluni/src/main/java/java/text/DecimalFormat.java b/ojluni/src/main/java/java/text/DecimalFormat.java
index b8eade3..bcc9e8b 100755
--- a/ojluni/src/main/java/java/text/DecimalFormat.java
+++ b/ojluni/src/main/java/java/text/DecimalFormat.java
@@ -465,10 +465,7 @@
private void init(String pattern) {
this.icuDecimalFormat = new android.icu.text.DecimalFormat(pattern,
symbols.getIcuDecimalFormatSymbols());
- maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits();
- minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits();
- maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits();
- minimumFractionDigits = icuDecimalFormat.getMinimumFractionDigits();
+ updateFieldsFromIcu();
}
/**
@@ -1169,6 +1166,12 @@
}
private void updateFieldsFromIcu() {
+ // Imitate behaviour of ICU4C NumberFormat that Android used up to M.
+ // If the pattern doesn't enforce a different value (some exponential
+ // patterns do), then set the maximum integer digits to 2 billion.
+ if (icuDecimalFormat.getMaximumIntegerDigits() == DOUBLE_INTEGER_DIGITS) {
+ icuDecimalFormat.setMaximumIntegerDigits(2000000000);
+ }
maximumIntegerDigits = icuDecimalFormat.getMaximumIntegerDigits();
minimumIntegerDigits = icuDecimalFormat.getMinimumIntegerDigits();
maximumFractionDigits = icuDecimalFormat.getMaximumFractionDigits();
diff --git a/ojluni/src/main/java/java/util/Arrays.java b/ojluni/src/main/java/java/util/Arrays.java
index 6274b45..1fbe710 100755
--- a/ojluni/src/main/java/java/util/Arrays.java
+++ b/ojluni/src/main/java/java/util/Arrays.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2014, 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
@@ -28,11 +28,16 @@
import java.lang.reflect.*;
import java.util.concurrent.ForkJoinPool;
+import java.util.function.BinaryOperator;
import java.util.function.Consumer;
+import java.util.function.DoubleBinaryOperator;
+import java.util.function.IntBinaryOperator;
import java.util.function.IntFunction;
import java.util.function.IntToDoubleFunction;
import java.util.function.IntToLongFunction;
import java.util.function.IntUnaryOperator;
+import java.util.function.LongBinaryOperator;
+import java.util.function.UnaryOperator;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
@@ -1594,6 +1599,194 @@
}
}
+
+ // Parallel prefix
+
+ /**
+ * Cumulates, in parallel, each element of the given array in place,
+ * using the supplied function. For example if the array initially
+ * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+ * then upon return the array holds {@code [2, 3, 3, 6]}.
+ * Parallel prefix computation is usually more efficient than
+ * sequential loops for large arrays.
+ *
+ * @param <T> the class of the objects in the array
+ * @param array the array, which is modified in-place by this method
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static <T> void parallelPrefix(T[] array, BinaryOperator<T> op) {
+ Objects.requireNonNull(op);
+ if (array.length > 0)
+ new ArrayPrefixHelpers.CumulateTask<>
+ (null, op, array, 0, array.length).invoke();
+ }
+
+ /**
+ * Performs {@link #parallelPrefix(Object[], BinaryOperator)}
+ * for the given subrange of the array.
+ *
+ * @param <T> the class of the objects in the array
+ * @param array the array
+ * @param fromIndex the index of the first element, inclusive
+ * @param toIndex the index of the last element, exclusive
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > array.length}
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static <T> void parallelPrefix(T[] array, int fromIndex,
+ int toIndex, BinaryOperator<T> op) {
+ Objects.requireNonNull(op);
+ rangeCheck(array.length, fromIndex, toIndex);
+ if (fromIndex < toIndex)
+ new ArrayPrefixHelpers.CumulateTask<>
+ (null, op, array, fromIndex, toIndex).invoke();
+ }
+
+ /**
+ * Cumulates, in parallel, each element of the given array in place,
+ * using the supplied function. For example if the array initially
+ * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+ * then upon return the array holds {@code [2, 3, 3, 6]}.
+ * Parallel prefix computation is usually more efficient than
+ * sequential loops for large arrays.
+ *
+ * @param array the array, which is modified in-place by this method
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(long[] array, LongBinaryOperator op) {
+ Objects.requireNonNull(op);
+ if (array.length > 0)
+ new ArrayPrefixHelpers.LongCumulateTask
+ (null, op, array, 0, array.length).invoke();
+ }
+
+ /**
+ * Performs {@link #parallelPrefix(long[], LongBinaryOperator)}
+ * for the given subrange of the array.
+ *
+ * @param array the array
+ * @param fromIndex the index of the first element, inclusive
+ * @param toIndex the index of the last element, exclusive
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > array.length}
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(long[] array, int fromIndex,
+ int toIndex, LongBinaryOperator op) {
+ Objects.requireNonNull(op);
+ rangeCheck(array.length, fromIndex, toIndex);
+ if (fromIndex < toIndex)
+ new ArrayPrefixHelpers.LongCumulateTask
+ (null, op, array, fromIndex, toIndex).invoke();
+ }
+
+ /**
+ * Cumulates, in parallel, each element of the given array in place,
+ * using the supplied function. For example if the array initially
+ * holds {@code [2.0, 1.0, 0.0, 3.0]} and the operation performs addition,
+ * then upon return the array holds {@code [2.0, 3.0, 3.0, 6.0]}.
+ * Parallel prefix computation is usually more efficient than
+ * sequential loops for large arrays.
+ *
+ * <p> Because floating-point operations may not be strictly associative,
+ * the returned result may not be identical to the value that would be
+ * obtained if the operation was performed sequentially.
+ *
+ * @param array the array, which is modified in-place by this method
+ * @param op a side-effect-free function to perform the cumulation
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(double[] array, DoubleBinaryOperator op) {
+ Objects.requireNonNull(op);
+ if (array.length > 0)
+ new ArrayPrefixHelpers.DoubleCumulateTask
+ (null, op, array, 0, array.length).invoke();
+ }
+
+ /**
+ * Performs {@link #parallelPrefix(double[], DoubleBinaryOperator)}
+ * for the given subrange of the array.
+ *
+ * @param array the array
+ * @param fromIndex the index of the first element, inclusive
+ * @param toIndex the index of the last element, exclusive
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > array.length}
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(double[] array, int fromIndex,
+ int toIndex, DoubleBinaryOperator op) {
+ Objects.requireNonNull(op);
+ rangeCheck(array.length, fromIndex, toIndex);
+ if (fromIndex < toIndex)
+ new ArrayPrefixHelpers.DoubleCumulateTask
+ (null, op, array, fromIndex, toIndex).invoke();
+ }
+
+ /**
+ * Cumulates, in parallel, each element of the given array in place,
+ * using the supplied function. For example if the array initially
+ * holds {@code [2, 1, 0, 3]} and the operation performs addition,
+ * then upon return the array holds {@code [2, 3, 3, 6]}.
+ * Parallel prefix computation is usually more efficient than
+ * sequential loops for large arrays.
+ *
+ * @param array the array, which is modified in-place by this method
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(int[] array, IntBinaryOperator op) {
+ Objects.requireNonNull(op);
+ if (array.length > 0)
+ new ArrayPrefixHelpers.IntCumulateTask
+ (null, op, array, 0, array.length).invoke();
+ }
+
+ /**
+ * Performs {@link #parallelPrefix(int[], IntBinaryOperator)}
+ * for the given subrange of the array.
+ *
+ * @param array the array
+ * @param fromIndex the index of the first element, inclusive
+ * @param toIndex the index of the last element, exclusive
+ * @param op a side-effect-free, associative function to perform the
+ * cumulation
+ * @throws IllegalArgumentException if {@code fromIndex > toIndex}
+ * @throws ArrayIndexOutOfBoundsException
+ * if {@code fromIndex < 0} or {@code toIndex > array.length}
+ * @throws NullPointerException if the specified array or function is null
+ * @since 1.8
+ */
+ public static void parallelPrefix(int[] array, int fromIndex,
+ int toIndex, IntBinaryOperator op) {
+ Objects.requireNonNull(op);
+ rangeCheck(array.length, fromIndex, toIndex);
+ if (fromIndex < toIndex)
+ new ArrayPrefixHelpers.IntCumulateTask
+ (null, op, array, fromIndex, toIndex).invoke();
+ }
+
// Searching
/**
@@ -3696,6 +3889,15 @@
}
@Override
+ public void replaceAll(UnaryOperator<E> operator) {
+ Objects.requireNonNull(operator);
+ E[] a = this.a;
+ for (int i = 0; i < a.length; i++) {
+ a[i] = operator.apply(a[i]);
+ }
+ }
+
+ @Override
public Spliterator<E> spliterator() {
return Spliterators.spliterator(a, Spliterator.ORDERED);
}
diff --git a/ojluni/src/main/java/java/util/BitSet.java b/ojluni/src/main/java/java/util/BitSet.java
index fa0be57..3620cee 100755
--- a/ojluni/src/main/java/java/util/BitSet.java
+++ b/ojluni/src/main/java/java/util/BitSet.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2014, 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
@@ -29,6 +29,8 @@
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.LongBuffer;
+import java.util.stream.IntStream;
+import java.util.stream.StreamSupport;
/**
* This class implements a vector of bits that grows as needed. Each
@@ -1188,4 +1190,48 @@
b.append('}');
return b.toString();
}
+
+ /**
+ * Returns a stream of indices for which this {@code BitSet}
+ * contains a bit in the set state. The indices are returned
+ * in order, from lowest to highest. The size of the stream
+ * is the number of bits in the set state, equal to the value
+ * returned by the {@link #cardinality()} method.
+ *
+ * <p>The bit set must remain constant during the execution of the
+ * terminal stream operation. Otherwise, the result of the terminal
+ * stream operation is undefined.
+ *
+ * @return a stream of integers representing set indices
+ * @since 1.8
+ */
+ public IntStream stream() {
+ class BitSetIterator implements PrimitiveIterator.OfInt {
+ int next = nextSetBit(0);
+
+ @Override
+ public boolean hasNext() {
+ return next != -1;
+ }
+
+ @Override
+ public int nextInt() {
+ if (next != -1) {
+ int ret = next;
+ next = nextSetBit(next+1);
+ return ret;
+ } else {
+ throw new NoSuchElementException();
+ }
+ }
+ }
+
+ return StreamSupport.intStream(
+ () -> Spliterators.spliterator(
+ new BitSetIterator(), cardinality(),
+ Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED),
+ Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.ORDERED | Spliterator.DISTINCT | Spliterator.SORTED,
+ false);
+ }
}
diff --git a/ojluni/src/main/java/java/util/Collections.java b/ojluni/src/main/java/java/util/Collections.java
index 6b19738..1a9f83a 100644
--- a/ojluni/src/main/java/java/util/Collections.java
+++ b/ojluni/src/main/java/java/util/Collections.java
@@ -1796,7 +1796,6 @@
// Synch Wrappers
- // TODO: Replace {@code stream} with {@link Stream} once we have them.
/**
* Returns a synchronized (thread-safe) collection backed by the specified
* collection. In order to guarantee serial access, it is critical that
@@ -1805,7 +1804,7 @@
*
* It is imperative that the user manually synchronize on the returned
* collection when traversing it via {@link Iterator}, {@link Spliterator}
- * or {@code Stream}:
+ * or {@link Stream}:
* <pre>
* Collection c = Collections.synchronizedCollection(myCollection);
* ...
@@ -2884,14 +2883,6 @@
public boolean addAll(int index, Collection<? extends E> c) {
return list.addAll(index, checkedCopyOf(c));
}
- @Override
- public void replaceAll(UnaryOperator<E> operator) {
- list.replaceAll(operator);
- }
- @Override
- public void sort(Comparator<? super E> c) {
- list.sort(c);
- }
public ListIterator<E> listIterator() { return listIterator(0); }
public ListIterator<E> listIterator(final int index) {
@@ -2926,6 +2917,32 @@
public List<E> subList(int fromIndex, int toIndex) {
return new CheckedList<>(list.subList(fromIndex, toIndex), type);
}
+
+ /**
+ * {@inheritDoc}
+ *
+ * @throws ClassCastException if the class of an element returned by the
+ * operator prevents it from being added to this collection. The
+ * exception may be thrown after some elements of the list have
+ * already been replaced.
+ */
+ @Override
+ public void replaceAll(UnaryOperator<E> operator) {
+ Objects.requireNonNull(operator);
+
+ // Android-changed: Modified from OpenJDK 8 code because typeCheck returns void in
+ // OpenJDK 7.
+ list.replaceAll(e -> {
+ E newValue = operator.apply(e);
+ typeCheck(newValue);
+ return newValue;
+ });
+ }
+
+ @Override
+ public void sort(Comparator<? super E> c) {
+ list.sort(c);
+ }
}
/**
@@ -3088,6 +3105,68 @@
m.forEach(action);
}
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ m.replaceAll(typeCheck(function));
+ }
+
+ @Override
+ public V putIfAbsent(K key, V value) {
+ typeCheck(key, value);
+ return m.putIfAbsent(key, value);
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ return m.remove(key, value);
+ }
+
+ @Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ typeCheck(key, newValue);
+ return m.replace(key, oldValue, newValue);
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ typeCheck(key, value);
+ return m.replace(key, value);
+ }
+
+ @Override
+ public V computeIfAbsent(K key,
+ Function<? super K, ? extends V> mappingFunction) {
+ Objects.requireNonNull(mappingFunction);
+ return m.computeIfAbsent(key, k -> {
+ V value = mappingFunction.apply(k);
+ typeCheck(k, value);
+ return value;
+ });
+ }
+
+ @Override
+ public V computeIfPresent(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ return m.computeIfPresent(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V compute(K key,
+ BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
+ return m.compute(key, typeCheck(remappingFunction));
+ }
+
+ @Override
+ public V merge(K key, V value,
+ BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
+ Objects.requireNonNull(remappingFunction);
+ return m.merge(key, value, (v1, v2) -> {
+ V newValue = remappingFunction.apply(v1, v2);
+ typeCheck(null, newValue);
+ return newValue;
+ });
+ }
+
/**
* We need this class in addition to CheckedSet as Map.Entry permits
* modification of the backing Map via the setValue operation. This
diff --git a/ojluni/src/main/java/java/util/ComparableTimSort.java b/ojluni/src/main/java/java/util/ComparableTimSort.java
index e7c7ac0..36c8d90 100755
--- a/ojluni/src/main/java/java/util/ComparableTimSort.java
+++ b/ojluni/src/main/java/java/util/ComparableTimSort.java
@@ -144,10 +144,14 @@
* large) stack lengths for smaller arrays. The "magic numbers" in the
* computation below must be changed if MIN_MERGE is decreased. See
* the MIN_MERGE declaration above for more information.
+ * The maximum value of 49 allows for an array up to length
+ * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+ * increasing scenario. More explanations are given in section 4 of:
+ * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
*/
int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 :
- len < 119151 ? 24 : 40);
+ len < 119151 ? 24 : 49);
runBase = new int[stackLen];
runLen = new int[stackLen];
}
diff --git a/ojluni/src/main/java/java/util/HashMap.java b/ojluni/src/main/java/java/util/HashMap.java
index 547cb05..9403225 100755
--- a/ojluni/src/main/java/java/util/HashMap.java
+++ b/ojluni/src/main/java/java/util/HashMap.java
@@ -27,6 +27,7 @@
package java.util;
import java.io.*;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
@@ -133,7 +134,7 @@
/**
* The default initial capacity - MUST be a power of two.
*/
- static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
+ static final int DEFAULT_INITIAL_CAPACITY = 4;
/**
* The maximum capacity, used if a higher value is implicitly specified
@@ -175,7 +176,9 @@
*
* @serial
*/
- final float loadFactor;
+ // Android-Note: We always use a load factor of 0.75 and ignore any explicitly
+ // selected values.
+ final float loadFactor = DEFAULT_LOAD_FACTOR;
/**
* The number of times this HashMap has been structurally modified
@@ -187,62 +190,6 @@
transient int modCount;
/**
- * The default threshold of map capacity above which alternative hashing is
- * used for String keys. Alternative hashing reduces the incidence of
- * collisions due to weak hash code calculation for String keys.
- * <p/>
- * This value may be overridden by defining the system property
- * {@code jdk.map.althashing.threshold}. A property value of {@code 1}
- * forces alternative hashing to be used at all times whereas
- * {@code -1} value ensures that alternative hashing is never used.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
-
- /**
- * holds values which can't be initialized until after VM is booted.
- */
- private static class Holder {
-
- /**
- * Table capacity above which to switch to use alternative hashing.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD;
-
- static {
- String altThreshold = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.althashing.threshold"));
-
- int threshold;
- try {
- threshold = (null != altThreshold)
- ? Integer.parseInt(altThreshold)
- : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
-
- // disable alternative hashing if -1
- if (threshold == -1) {
- threshold = Integer.MAX_VALUE;
- }
-
- if (threshold < 0) {
- throw new IllegalArgumentException("value must be positive integer.");
- }
- } catch(IllegalArgumentException failed) {
- throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
- }
-
- ALTERNATIVE_HASHING_THRESHOLD = threshold;
- }
- }
-
- /**
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find. If 0 then
- * alternative hashing is disabled.
- */
- transient int hashSeed = 0;
-
- /**
* Constructs an empty <tt>HashMap</tt> with the specified initial
* capacity and load factor.
*
@@ -255,13 +202,21 @@
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal initial capacity: " +
initialCapacity);
- if (initialCapacity > MAXIMUM_CAPACITY)
+ if (initialCapacity > MAXIMUM_CAPACITY) {
initialCapacity = MAXIMUM_CAPACITY;
+ } else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) {
+ initialCapacity = DEFAULT_INITIAL_CAPACITY;
+ }
+
if (loadFactor <= 0 || Float.isNaN(loadFactor))
throw new IllegalArgumentException("Illegal load factor: " +
loadFactor);
+ // Android-Note: We always use the default load factor of 0.75f.
- this.loadFactor = loadFactor;
+ // This might appear wrong but it's just awkward design. We always call
+ // inflateTable() when table == EMPTY_TABLE. That method will take "threshold"
+ // to mean "capacity" and then replace it with the real threshold (i.e, multiplied with
+ // the load factor).
threshold = initialCapacity;
init();
}
@@ -330,7 +285,6 @@
threshold = (int) thresholdFloat;
table = new HashMapEntry[capacity];
- initHashSeedAsNeeded(capacity);
}
// internal utilities
@@ -346,45 +300,6 @@
}
/**
- * Initialize the hashing mask value. We defer initialization until we
- * really need it.
- */
- final boolean initHashSeedAsNeeded(int capacity) {
- boolean currentAltHashing = hashSeed != 0;
- boolean useAltHashing = sun.misc.VM.isBooted() &&
- (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
- boolean switching = currentAltHashing ^ useAltHashing;
- if (switching) {
- hashSeed = useAltHashing
- ? sun.misc.Hashing.randomHashSeed(this)
- : 0;
- }
- return switching;
- }
-
- /**
- * Retrieve object hash code and applies a supplemental hash function to the
- * result hash, which defends against poor quality hash functions. This is
- * critical because HashMap uses power-of-two length hash tables, that
- * otherwise encounter collisions for hashCodes that do not differ
- * in lower bits. Note: Null keys always map to hash 0, thus index 0.
- */
- final int hash(Object k) {
- int h = hashSeed;
- if (0 != h && k instanceof String) {
- return sun.misc.Hashing.stringHash32((String) k);
- }
-
- h ^= k.hashCode();
-
- // This function ensures that hashCodes that differ only by
- // constant multiples at each bit position have a bounded
- // number of collisions (approximately 8 at default load factor).
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
-
- /**
* Returns index for hash code h.
*/
static int indexFor(int h, int length) {
@@ -475,7 +390,7 @@
return null;
}
- int hash = (key == null) ? 0 : hash(key);
+ int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
for (HashMapEntry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
@@ -505,7 +420,7 @@
}
if (key == null)
return putForNullKey(value);
- int hash = hash(key);
+ int hash = sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);
for (HashMapEntry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
@@ -546,7 +461,7 @@
* addEntry.
*/
private void putForCreate(K key, V value) {
- int hash = null == key ? 0 : hash(key);
+ int hash = null == key ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);
/**
@@ -594,7 +509,7 @@
}
HashMapEntry[] newTable = new HashMapEntry[newCapacity];
- transfer(newTable, initHashSeedAsNeeded(newCapacity));
+ transfer(newTable);
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}
@@ -602,14 +517,11 @@
/**
* Transfers all entries from current table to newTable.
*/
- void transfer(HashMapEntry[] newTable, boolean rehash) {
+ void transfer(HashMapEntry[] newTable) {
int newCapacity = newTable.length;
for (HashMapEntry<K,V> e : table) {
while(null != e) {
HashMapEntry<K,V> next = e.next;
- if (rehash) {
- e.hash = null == e.key ? 0 : hash(e.key);
- }
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
@@ -682,7 +594,7 @@
if (size == 0) {
return null;
}
- int hash = (key == null) ? 0 : hash(key);
+ int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);
HashMapEntry<K,V> prev = table[i];
HashMapEntry<K,V> e = prev;
@@ -718,7 +630,7 @@
Map.Entry<K,V> entry = (Map.Entry<K,V>) o;
Object key = entry.getKey();
- int hash = (key == null) ? 0 : hash(key);
+ int hash = (key == null) ? 0 : sun.misc.Hashing.singleWordWangJenkinsHash(key);
int i = indexFor(hash, table.length);
HashMapEntry<K,V> prev = table[i];
HashMapEntry<K,V> e = prev;
@@ -894,7 +806,7 @@
void addEntry(int hash, K key, V value, int bucketIndex) {
if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
- hash = (null != key) ? hash(key) : 0;
+ hash = (null != key) ? sun.misc.Hashing.singleWordWangJenkinsHash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}
@@ -1455,6 +1367,23 @@
}
}
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ HashMapEntry<K,V>[] tab;
+ if (function == null)
+ throw new NullPointerException();
+ if (size > 0 && (tab = table) != null) {
+ int mc = modCount;
+ for (int i = 0; i < tab.length; ++i) {
+ for (HashMapEntry<K,V> e = tab[i]; e != null; e = e.next) {
+ e.value = function.apply(e.key, e.value);
+ }
+ }
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
+ }
+
/**
* Save the state of the <tt>HashMap</tt> instance to a stream (i.e.,
* serialize it).
diff --git a/ojluni/src/main/java/java/util/Hashtable.java b/ojluni/src/main/java/java/util/Hashtable.java
index 8a21511..783d17b 100755
--- a/ojluni/src/main/java/java/util/Hashtable.java
+++ b/ojluni/src/main/java/java/util/Hashtable.java
@@ -168,80 +168,8 @@
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = 1421746759512286392L;
- /**
- * The default threshold of map capacity above which alternative hashing is
- * used for String keys. Alternative hashing reduces the incidence of
- * collisions due to weak hash code calculation for String keys.
- * <p>
- * This value may be overridden by defining the system property
- * {@code jdk.map.althashing.threshold}. A property value of {@code 1}
- * forces alternative hashing to be used at all times whereas
- * {@code -1} value ensures that alternative hashing is never used.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
-
- /**
- * holds values which can't be initialized until after VM is booted.
- */
- private static class Holder {
-
- /**
- * Table capacity above which to switch to use alternative hashing.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD;
-
- static {
- String altThreshold = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.althashing.threshold"));
-
- int threshold;
- try {
- threshold = (null != altThreshold)
- ? Integer.parseInt(altThreshold)
- : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
-
- // disable alternative hashing if -1
- if (threshold == -1) {
- threshold = Integer.MAX_VALUE;
- }
-
- if (threshold < 0) {
- throw new IllegalArgumentException("value must be positive integer.");
- }
- } catch(IllegalArgumentException failed) {
- throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
- }
-
- ALTERNATIVE_HASHING_THRESHOLD = threshold;
- }
- }
-
- /**
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find.
- */
- transient int hashSeed;
-
- /**
- * Initialize the hashing mask value.
- */
- final boolean initHashSeedAsNeeded(int capacity) {
- boolean currentAltHashing = hashSeed != 0;
- boolean useAltHashing = sun.misc.VM.isBooted() &&
- (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
- boolean switching = currentAltHashing ^ useAltHashing;
- if (switching) {
- hashSeed = useAltHashing
- ? sun.misc.Hashing.randomHashSeed(this)
- : 0;
- }
- return switching;
- }
-
- private int hash(Object k) {
- // hashSeed will be zero if alternative hashing is disabled.
- return hashSeed ^ k.hashCode();
+ private static int hash(Object k) {
+ return k.hashCode();
}
/**
@@ -265,7 +193,6 @@
this.loadFactor = loadFactor;
table = new HashtableEntry[initialCapacity];
threshold = (initialCapacity <= MAX_ARRAY_SIZE + 1) ? initialCapacity : MAX_ARRAY_SIZE + 1;
- initHashSeedAsNeeded(initialCapacity);
}
/**
@@ -477,7 +404,6 @@
modCount++;
threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
- boolean rehash = initHashSeedAsNeeded(newCapacity);
table = newMap;
@@ -486,9 +412,6 @@
HashtableEntry<K,V> e = old;
old = old.next;
- if (rehash) {
- e.hash = hash(e.key);
- }
int index = (e.hash & 0x7FFFFFFF) % newCapacity;
e.next = newMap[index];
newMap[index] = e;
@@ -944,6 +867,27 @@
}
}
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public synchronized void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function); // explicit check required in case
+ // table is empty.
+ final int expectedModCount = modCount;
+
+ HashtableEntry<K, V>[] tab = table;
+ for (HashtableEntry<K, V> entry : tab) {
+ while (entry != null) {
+ entry.value = Objects.requireNonNull(
+ function.apply(entry.key, entry.value));
+ entry = entry.next;
+
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+ }
+
// Overrides Java8 default methods(added method synchronization)
@@ -1065,7 +1009,6 @@
HashtableEntry<K,V>[] newTable = new HashtableEntry[length];
threshold = (int) Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
count = 0;
- initHashSeedAsNeeded(length);
// Read the number of elements and then all the key/value objects
for (; elements > 0; elements--) {
diff --git a/ojluni/src/main/java/java/util/IdentityHashMap.java b/ojluni/src/main/java/java/util/IdentityHashMap.java
index ea1948d..b860cca 100755
--- a/ojluni/src/main/java/java/util/IdentityHashMap.java
+++ b/ojluni/src/main/java/java/util/IdentityHashMap.java
@@ -28,6 +28,7 @@
import java.io.*;
import java.lang.reflect.Array;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
/**
@@ -1359,6 +1360,25 @@
}
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ int expectedModCount = modCount;
+
+ Object[] t = table;
+ for (int index = 0; index < t.length; index += 2) {
+ Object k = t[index];
+ if (k != null) {
+ t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
+ }
+
+ if (modCount != expectedModCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+
/**
* Similar form as array-based Spliterators, but skips blank elements,
* and guestimates size as decreasing by half per split.
diff --git a/ojluni/src/main/java/java/util/LinkedHashMap.java b/ojluni/src/main/java/java/util/LinkedHashMap.java
index 81b8a7a..5a35728 100755
--- a/ojluni/src/main/java/java/util/LinkedHashMap.java
+++ b/ojluni/src/main/java/java/util/LinkedHashMap.java
@@ -26,7 +26,10 @@
package java.util;
+import sun.misc.Hashing;
+
import java.io.*;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
@@ -264,11 +267,9 @@
* faster to iterate using our linked list.
*/
@Override
- void transfer(HashMapEntry[] newTable, boolean rehash) {
+ void transfer(HashMapEntry[] newTable) {
int newCapacity = newTable.length;
for (LinkedHashMapEntry<K,V> e = header.after; e != header; e = e.after) {
- if (rehash)
- e.hash = (e.key == null) ? 0 : hash(e.key);
int index = indexFor(e.hash, newCapacity);
e.next = newTable[index];
newTable[index] = e;
@@ -440,13 +441,27 @@
* removes the eldest entry if appropriate.
*/
void addEntry(int hash, K key, V value, int bucketIndex) {
- super.addEntry(hash, key, value, bucketIndex);
+ // Previous Android releases called removeEldestEntry() before actually
+ // inserting a value but after increasing the size.
+ // The RI is documented to call it afterwards.
+ // **** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ****
// Remove eldest entry if instructed
LinkedHashMapEntry<K,V> eldest = header.after;
- if (removeEldestEntry(eldest)) {
- removeEntryForKey(eldest.key);
+ if (eldest != header) {
+ boolean removeEldest;
+ size++;
+ try {
+ removeEldest = removeEldestEntry(eldest);
+ } finally {
+ size--;
+ }
+ if (removeEldest) {
+ removeEntryForKey(eldest.key);
+ }
}
+
+ super.addEntry(hash, key, value, bucketIndex);
}
/**
@@ -473,7 +488,12 @@
size++;
}
- /**
+ // Intentionally make this not JavaDoc, as the we don't conform to
+ // the behaviour documented here (we call removeEldestEntry before
+ // inserting the new value to be consistent with previous Android
+ // releases).
+ // **** THIS CHANGE WILL BE REVERTED IN A FUTURE ANDROID RELEASE ****
+ /*
* Returns <tt>true</tt> if this map should remove its eldest entry.
* This method is invoked by <tt>put</tt> and <tt>putAll</tt> after
* inserting a new entry into the map. It provides the implementor
@@ -529,4 +549,15 @@
if (modCount != mc)
throw new ConcurrentModificationException();
}
+
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ if (function == null)
+ throw new NullPointerException();
+ int mc = modCount;
+ // Android modified - breaks from the loop when modCount != mc
+ for (LinkedHashMapEntry<K,V> e = header.after; modCount == mc && e != header; e = e.after)
+ e.value = function.apply(e.key, e.value);
+ if (modCount != mc)
+ throw new ConcurrentModificationException();
+ }
}
diff --git a/ojluni/src/main/java/java/util/Locale.java b/ojluni/src/main/java/java/util/Locale.java
index 21576b7..5d1a775 100755
--- a/ojluni/src/main/java/java/util/Locale.java
+++ b/ojluni/src/main/java/java/util/Locale.java
@@ -82,7 +82,7 @@
* described below.
*
* <dl>
- * <dt><a name="def_language"/><b>language</b></dt>
+ * <dt><a name="def_language"></a><b>language</b></dt>
*
* <dd>ISO 639 alpha-2 or alpha-3 language code, or registered
* language subtags up to 8 alpha letters (for future enhancements).
@@ -100,7 +100,7 @@
*
* <dd>Example: "en" (English), "ja" (Japanese), "kok" (Konkani)</dd><br>
*
- * <dt><a name="def_script"/><b>script</b></dt>
+ * <dt><a name="def_script"/></a><b>script</b></dt>
*
* <dd>ISO 15924 alpha-4 script code. You can find a full list of
* valid script codes in the IANA Language Subtag Registry (search
@@ -114,7 +114,7 @@
*
* <dd>Example: "Latn" (Latin), "Cyrl" (Cyrillic)</dd><br>
*
- * <dt><a name="def_region"/><b>country (region)</b></dt>
+ * <dt><a name="def_region"></a><b>country (region)</b></dt>
*
* <dd>ISO 3166 alpha-2 country code or UN M.49 numeric-3 area code.
* You can find a full list of valid country and region codes in the
@@ -128,7 +128,7 @@
* <dd>Example: "US" (United States), "FR" (France), "029"
* (Caribbean)</dd><br>
*
- * <dt><a name="def_variant"/><b>variant</b></dt>
+ * <dt><a name="def_variant"></a><b>variant</b></dt>
*
* <dd>Any arbitrary value used to indicate a variation of a
* <code>Locale</code>. Where there are two or more variant values
@@ -159,7 +159,7 @@
*
* <dd>Example: "polyton" (Polytonic Greek), "POSIX"</dd><br>
*
- * <dt><a name="def_extensions"/><b>extensions</b></dt>
+ * <dt><a name="def_extensions"></a><b>extensions</b></dt>
*
* <dd>A map from single character keys to string values, indicating
* extensions apart from language identification. The extensions in
@@ -187,7 +187,7 @@
* requirement (is well-formed), but does not validate the value
* itself. See {@link Builder} for details.
*
- * <h4><a name="def_locale_extension">Unicode locale/language extension</h4>
+ * <h4><a name="def_locale_extension"></a>Unicode locale/language extension</h4>
*
* <p>UTS#35, "Unicode Locale Data Markup Language" defines optional
* attributes and keywords to override or refine the default behavior
@@ -334,7 +334,7 @@
* Clients desiring a string representation of the complete locale can
* then always rely on <code>toLanguageTag</code> for this purpose.
*
- * <h5><a name="special_cases_constructor"/>Special cases</h5>
+ * <h5><a name="special_cases_constructor"></a>Special cases</h5>
*
* <p>For compatibility reasons, two
* non-conforming locales are treated as special cases. These are
@@ -398,6 +398,80 @@
* compatibility, the implementation still does not impose a length
* constraint.
*
+ * <a name="locale_data"></a><h4>Locale data</h4>
+ * <p>Note that locale data comes solely from ICU. User-supplied locale service providers (using
+ * the {@code java.text.spi} or {@code java.util.spi} mechanisms) are not supported.
+ *
+ * <p>Here are the versions of ICU (and the corresponding CLDR and Unicode versions) used in
+ * various Android releases:
+ * <table BORDER="1" WIDTH="100%" CELLPADDING="3" CELLSPACING="0" SUMMARY="">
+ * <tr><td>Android 1.5 (Cupcake)/Android 1.6 (Donut)/Android 2.0 (Eclair)</td>
+ * <td>ICU 3.8</td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-5">CLDR 1.5</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode5.0.0/">Unicode 5.0</a></td></tr>
+ * <tr><td>Android 2.2 (Froyo)</td>
+ * <td>ICU 4.2</td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-7">CLDR 1.7</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode5.1.0/">Unicode 5.1</a></td></tr>
+ * <tr><td>Android 2.3 (Gingerbread)/Android 3.0 (Honeycomb)</td>
+ * <td>ICU 4.4</td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-8">CLDR 1.8</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode5.2.0/">Unicode 5.2</a></td></tr>
+ * <tr><td>Android 4.0 (Ice Cream Sandwich)</td>
+ * <td><a href="http://site.icu-project.org/download/46">ICU 4.6</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-1-9">CLDR 1.9</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.1 (Jelly Bean)</td>
+ * <td><a href="http://site.icu-project.org/download/48">ICU 4.8</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-2-0">CLDR 2.0</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode6.0.0/">Unicode 6.0</a></td></tr>
+ * <tr><td>Android 4.3 (Jelly Bean MR2)</td>
+ * <td><a href="http://site.icu-project.org/download/50">ICU 50</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-22-1">CLDR 22.1</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 4.4 (KitKat)</td>
+ * <td><a href="http://site.icu-project.org/download/51">ICU 51</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-23">CLDR 23</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode6.2.0/">Unicode 6.2</a></td></tr>
+ * <tr><td>Android 5.0 (Lollipop)</td>
+ * <td><a href="http://site.icu-project.org/download/53">ICU 53</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-25">CLDR 25</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode 6.3</a></td></tr>
+ * <tr><td>Android 6.0 (Marshmallow)</td>
+ * <td><a href="http://site.icu-project.org/download/55">ICU 55.1</a></td>
+ * <td><a href="http://cldr.unicode.org/index/downloads/cldr-27">CLDR 27.0.1</a></td>
+ * <td><a href="http://www.unicode.org/versions/Unicode7.0.0/">Unicode 7.0</a></td></tr>
+ * </table>
+ *
+ * <a name="default_locale"></a><h4>Be wary of the default locale</h3>
+ * <p>Note that there are many convenience methods that automatically use the default locale, but
+ * using them may lead to subtle bugs.
+ *
+ * <p>The default locale is appropriate for tasks that involve presenting data to the user. In
+ * this case, you want to use the user's date/time formats, number
+ * formats, rules for conversion to lowercase, and so on. In this case, it's safe to use the
+ * convenience methods.
+ *
+ * <p>The default locale is <i>not</i> appropriate for machine-readable output. The best choice
+ * there is usually {@code Locale.US} – this locale is guaranteed to be available on all
+ * devices, and the fact that it has no surprising special cases and is frequently used (especially
+ * for computer-computer communication) means that it tends to be the most efficient choice too.
+ *
+ * <p>A common mistake is to implicitly use the default locale when producing output meant to be
+ * machine-readable. This tends to work on the developer's test devices (especially because so many
+ * developers use en_US), but fails when run on a device whose user is in a more complex locale.
+ *
+ * <p>For example, if you're formatting integers some locales will use non-ASCII decimal
+ * digits. As another example, if you're formatting floating-point numbers some locales will use
+ * {@code ','} as the decimal point and {@code '.'} for digit grouping. That's correct for
+ * human-readable output, but likely to cause problems if presented to another
+ * computer ({@link Double#parseDouble} can't parse such a number, for example).
+ * You should also be wary of the {@link String#toLowerCase} and
+ * {@link String#toUpperCase} overloads that don't take a {@code Locale}: in Turkey, for example,
+ * the characters {@code 'i'} and {@code 'I'} won't be converted to {@code 'I'} and {@code 'i'}.
+ * This is the correct behavior for Turkish text (such as user input), but inappropriate for, say,
+ * HTTP headers.
+ *
* @see Builder
* @see ResourceBundle
* @see java.text.Format
diff --git a/ojluni/src/main/java/java/util/Properties.java b/ojluni/src/main/java/java/util/Properties.java
index 112562f..d0470b2 100755
--- a/ojluni/src/main/java/java/util/Properties.java
+++ b/ojluni/src/main/java/java/util/Properties.java
@@ -106,8 +106,8 @@
* <p>This class is thread-safe: multiple threads can share a single
* <tt>Properties</tt> object without the need for external synchronization.
*
- * @see <a href="../../../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
- * @see <a href="../../../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
+ * @see <a href="{@docRoot}/../technotes/tools/solaris/native2ascii.html">native2ascii tool for Solaris</a>
+ * @see <a href="{@docRoot}/../technotes/tools/windows/native2ascii.html">native2ascii tool for Windows</a>
*
* @author Arthur van Hoff
* @author Michael McCloskey
diff --git a/ojluni/src/main/java/java/util/Random.java b/ojluni/src/main/java/java/util/Random.java
index e56051c..fb4ecfd 100755
--- a/ojluni/src/main/java/java/util/Random.java
+++ b/ojluni/src/main/java/java/util/Random.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 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
@@ -26,6 +26,14 @@
package java.util;
import java.io.*;
import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.DoubleConsumer;
+import java.util.function.IntConsumer;
+import java.util.function.LongConsumer;
+import java.util.stream.DoubleStream;
+import java.util.stream.IntStream;
+import java.util.stream.LongStream;
+import java.util.stream.StreamSupport;
+
import sun.misc.Unsafe;
/**
@@ -81,6 +89,13 @@
private static final long addend = 0xBL;
private static final long mask = (1L << 48) - 1;
+ private static final double DOUBLE_UNIT = 0x1.0p-53; // 1.0 / (1L << 53)
+
+ // IllegalArgumentException messages
+ static final String BadBound = "bound must be positive";
+ static final String BadRange = "bound must be greater than origin";
+ static final String BadSize = "size must be non-negative";
+
/**
* Creates a new random number generator. This constructor sets
* the seed of the random number generator to a value very likely
@@ -218,6 +233,82 @@
}
/**
+ * The form of nextLong used by LongStream Spliterators. If
+ * origin is greater than bound, acts as unbounded form of
+ * nextLong, else as bounded form.
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final long internalNextLong(long origin, long bound) {
+ long r = nextLong();
+ if (origin < bound) {
+ long n = bound - origin, m = n - 1;
+ if ((n & m) == 0L) // power of two
+ r = (r & m) + origin;
+ else if (n > 0L) { // reject over-represented candidates
+ for (long u = r >>> 1; // ensure nonnegative
+ u + m - (r = u % n) < 0L; // rejection check
+ u = nextLong() >>> 1) // retry
+ ;
+ r += origin;
+ }
+ else { // range not representable as long
+ while (r < origin || r >= bound)
+ r = nextLong();
+ }
+ }
+ return r;
+ }
+
+ /**
+ * The form of nextInt used by IntStream Spliterators.
+ * For the unbounded case: uses nextInt().
+ * For the bounded case with representable range: uses nextInt(int bound)
+ * For the bounded case with unrepresentable range: uses nextInt()
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final int internalNextInt(int origin, int bound) {
+ if (origin < bound) {
+ int n = bound - origin;
+ if (n > 0) {
+ return nextInt(n) + origin;
+ }
+ else { // range not representable as int
+ int r;
+ do {
+ r = nextInt();
+ } while (r < origin || r >= bound);
+ return r;
+ }
+ }
+ else {
+ return nextInt();
+ }
+ }
+
+ /**
+ * The form of nextDouble used by DoubleStream Spliterators.
+ *
+ * @param origin the least value, unless greater than bound
+ * @param bound the upper bound (exclusive), must not equal origin
+ * @return a pseudorandom value
+ */
+ final double internalNextDouble(double origin, double bound) {
+ double r = nextDouble();
+ if (origin < bound) {
+ r = r * (bound - origin) + origin;
+ if (r >= bound) // correct for rounding
+ r = Double.longBitsToDouble(Double.doubleToLongBits(bound) - 1);
+ }
+ return r;
+ }
+
+ /**
* Returns the next pseudorandom, uniformly distributed {@code int}
* value from this random number generator's sequence. The general
* contract of {@code nextInt} is that one {@code int} value is
@@ -512,6 +603,565 @@
}
}
+ // stream methods, coded in a way intended to better isolate for
+ // maintenance purposes the small differences across forms.
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code int} values.
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the method {@link #nextInt()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of pseudorandom {@code int} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public IntStream ints(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, streamSize, Integer.MAX_VALUE, 0),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code int}
+ * values.
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the method {@link #nextInt()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * ints(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code int} values
+ * @since 1.8
+ */
+ public IntStream ints() {
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, Long.MAX_VALUE, Integer.MAX_VALUE, 0),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number
+ * of pseudorandom {@code int} values, each conforming to the given
+ * origin (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the following method with the origin and bound:
+ * <pre> {@code
+ * int nextInt(int origin, int bound) {
+ * int n = bound - origin;
+ * if (n > 0) {
+ * return nextInt(n) + origin;
+ * }
+ * else { // range not representable as int
+ * int r;
+ * do {
+ * r = nextInt();
+ * } while (r < origin || r >= bound);
+ * return r;
+ * }
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code int} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero, or {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public IntStream ints(long streamSize, int randomNumberOrigin,
+ int randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * int} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code int} value is generated as if it's the result of
+ * calling the following method with the origin and bound:
+ * <pre> {@code
+ * int nextInt(int origin, int bound) {
+ * int n = bound - origin;
+ * if (n > 0) {
+ * return nextInt(n) + origin;
+ * }
+ * else { // range not representable as int
+ * int r;
+ * do {
+ * r = nextInt();
+ * } while (r < origin || r >= bound);
+ * return r;
+ * }
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * ints(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code int} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public IntStream ints(int randomNumberOrigin, int randomNumberBound) {
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.intStream
+ (new RandomIntsSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code long} values.
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the method {@link #nextLong()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of pseudorandom {@code long} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public LongStream longs(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, streamSize, Long.MAX_VALUE, 0L),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code long}
+ * values.
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the method {@link #nextLong()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * longs(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code long} values
+ * @since 1.8
+ */
+ public LongStream longs() {
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, Long.MAX_VALUE, Long.MAX_VALUE, 0L),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code long}, each conforming to the given origin
+ * (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * long nextLong(long origin, long bound) {
+ * long r = nextLong();
+ * long n = bound - origin, m = n - 1;
+ * if ((n & m) == 0L) // power of two
+ * r = (r & m) + origin;
+ * else if (n > 0L) { // reject over-represented candidates
+ * for (long u = r >>> 1; // ensure nonnegative
+ * u + m - (r = u % n) < 0L; // rejection check
+ * u = nextLong() >>> 1) // retry
+ * ;
+ * r += origin;
+ * }
+ * else { // range not representable as long
+ * while (r < origin || r >= bound)
+ * r = nextLong();
+ * }
+ * return r;
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code long} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero, or {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public LongStream longs(long streamSize, long randomNumberOrigin,
+ long randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * long} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code long} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * long nextLong(long origin, long bound) {
+ * long r = nextLong();
+ * long n = bound - origin, m = n - 1;
+ * if ((n & m) == 0L) // power of two
+ * r = (r & m) + origin;
+ * else if (n > 0L) { // reject over-represented candidates
+ * for (long u = r >>> 1; // ensure nonnegative
+ * u + m - (r = u % n) < 0L; // rejection check
+ * u = nextLong() >>> 1) // retry
+ * ;
+ * r += origin;
+ * }
+ * else { // range not representable as long
+ * while (r < origin || r >= bound)
+ * r = nextLong();
+ * }
+ * return r;
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * longs(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code long} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public LongStream longs(long randomNumberOrigin, long randomNumberBound) {
+ if (randomNumberOrigin >= randomNumberBound)
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.longStream
+ (new RandomLongsSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code double} values, each between zero
+ * (inclusive) and one (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the method {@link #nextDouble()}.
+ *
+ * @param streamSize the number of values to generate
+ * @return a stream of {@code double} values
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @since 1.8
+ */
+ public DoubleStream doubles(long streamSize) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, streamSize, Double.MAX_VALUE, 0.0),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * double} values, each between zero (inclusive) and one
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the method {@link #nextDouble()}.
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * doubles(Long.MAX_VALUE)}.
+ *
+ * @return a stream of pseudorandom {@code double} values
+ * @since 1.8
+ */
+ public DoubleStream doubles() {
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, Long.MAX_VALUE, Double.MAX_VALUE, 0.0),
+ false);
+ }
+
+ /**
+ * Returns a stream producing the given {@code streamSize} number of
+ * pseudorandom {@code double} values, each conforming to the given origin
+ * (inclusive) and bound (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * double nextDouble(double origin, double bound) {
+ * double r = nextDouble();
+ * r = r * (bound - origin) + origin;
+ * if (r >= bound) // correct for rounding
+ * r = Math.nextDown(bound);
+ * return r;
+ * }}</pre>
+ *
+ * @param streamSize the number of values to generate
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code double} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code streamSize} is
+ * less than zero
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public DoubleStream doubles(long streamSize, double randomNumberOrigin,
+ double randomNumberBound) {
+ if (streamSize < 0L)
+ throw new IllegalArgumentException(BadSize);
+ if (!(randomNumberOrigin < randomNumberBound))
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, streamSize, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Returns an effectively unlimited stream of pseudorandom {@code
+ * double} values, each conforming to the given origin (inclusive) and bound
+ * (exclusive).
+ *
+ * <p>A pseudorandom {@code double} value is generated as if it's the result
+ * of calling the following method with the origin and bound:
+ * <pre> {@code
+ * double nextDouble(double origin, double bound) {
+ * double r = nextDouble();
+ * r = r * (bound - origin) + origin;
+ * if (r >= bound) // correct for rounding
+ * r = Math.nextDown(bound);
+ * return r;
+ * }}</pre>
+ *
+ * @implNote This method is implemented to be equivalent to {@code
+ * doubles(Long.MAX_VALUE, randomNumberOrigin, randomNumberBound)}.
+ *
+ * @param randomNumberOrigin the origin (inclusive) of each random value
+ * @param randomNumberBound the bound (exclusive) of each random value
+ * @return a stream of pseudorandom {@code double} values,
+ * each with the given origin (inclusive) and bound (exclusive)
+ * @throws IllegalArgumentException if {@code randomNumberOrigin}
+ * is greater than or equal to {@code randomNumberBound}
+ * @since 1.8
+ */
+ public DoubleStream doubles(double randomNumberOrigin, double randomNumberBound) {
+ if (!(randomNumberOrigin < randomNumberBound))
+ throw new IllegalArgumentException(BadRange);
+ return StreamSupport.doubleStream
+ (new RandomDoublesSpliterator
+ (this, 0L, Long.MAX_VALUE, randomNumberOrigin, randomNumberBound),
+ false);
+ }
+
+ /**
+ * Spliterator for int streams. We multiplex the four int
+ * versions into one class by treating a bound less than origin as
+ * unbounded, and also by treating "infinite" as equivalent to
+ * Long.MAX_VALUE. For splits, it uses the standard divide-by-two
+ * approach. The long and double versions of this class are
+ * identical except for types.
+ */
+ static final class RandomIntsSpliterator implements Spliterator.OfInt {
+ final Random rng;
+ long index;
+ final long fence;
+ final int origin;
+ final int bound;
+ RandomIntsSpliterator(Random rng, long index, long fence,
+ int origin, int bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomIntsSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomIntsSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(IntConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextInt(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(IntConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ int o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextInt(o, b));
+ } while (++i < f);
+ }
+ }
+ }
+
+ /**
+ * Spliterator for long streams.
+ */
+ static final class RandomLongsSpliterator implements Spliterator.OfLong {
+ final Random rng;
+ long index;
+ final long fence;
+ final long origin;
+ final long bound;
+ RandomLongsSpliterator(Random rng, long index, long fence,
+ long origin, long bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomLongsSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomLongsSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(LongConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextLong(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(LongConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ long o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextLong(o, b));
+ } while (++i < f);
+ }
+ }
+
+ }
+
+ /**
+ * Spliterator for double streams.
+ */
+ static final class RandomDoublesSpliterator implements Spliterator.OfDouble {
+ final Random rng;
+ long index;
+ final long fence;
+ final double origin;
+ final double bound;
+ RandomDoublesSpliterator(Random rng, long index, long fence,
+ double origin, double bound) {
+ this.rng = rng; this.index = index; this.fence = fence;
+ this.origin = origin; this.bound = bound;
+ }
+
+ public RandomDoublesSpliterator trySplit() {
+ long i = index, m = (i + fence) >>> 1;
+ return (m <= i) ? null :
+ new RandomDoublesSpliterator(rng, i, index = m, origin, bound);
+ }
+
+ public long estimateSize() {
+ return fence - index;
+ }
+
+ public int characteristics() {
+ return (Spliterator.SIZED | Spliterator.SUBSIZED |
+ Spliterator.NONNULL | Spliterator.IMMUTABLE);
+ }
+
+ public boolean tryAdvance(DoubleConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ consumer.accept(rng.internalNextDouble(origin, bound));
+ index = i + 1;
+ return true;
+ }
+ return false;
+ }
+
+ public void forEachRemaining(DoubleConsumer consumer) {
+ if (consumer == null) throw new NullPointerException();
+ long i = index, f = fence;
+ if (i < f) {
+ index = f;
+ Random r = rng;
+ double o = origin, b = bound;
+ do {
+ consumer.accept(r.internalNextDouble(o, b));
+ } while (++i < f);
+ }
+ }
+ }
+
/**
* Serializable fields for Random.
*
diff --git a/ojluni/src/main/java/java/util/ResourceBundle.java b/ojluni/src/main/java/java/util/ResourceBundle.java
index 1df01f5..f604089 100755
--- a/ojluni/src/main/java/java/util/ResourceBundle.java
+++ b/ojluni/src/main/java/java/util/ResourceBundle.java
@@ -44,12 +44,14 @@
import dalvik.system.VMStack;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
+import java.nio.charset.StandardCharsets;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException;
@@ -848,7 +850,7 @@
* Gets a resource bundle using the specified base name, locale, and class
* loader.
*
- * <p><a name="default_behavior"/>This method behaves the same as calling
+ * <p><a name="default_behavior"></a>This method behaves the same as calling
* {@link #getBundle(String, Locale, ClassLoader, Control)} passing a
* default instance of {@link Control}. The following describes this behavior.
*
@@ -945,7 +947,7 @@
* <p>If still no result bundle is found, the base name alone is looked up. If
* this still fails, a <code>MissingResourceException</code> is thrown.
*
- * <p><a name="parent_chain"/> Once a result resource bundle has been found,
+ * <p><a name="parent_chain"></a> Once a result resource bundle has been found,
* its <em>parent chain</em> is instantiated. If the result bundle already
* has a parent (perhaps because it was returned from a cache) the chain is
* complete.
@@ -975,7 +977,7 @@
* path name (using "/") instead of a fully qualified class name (using
* ".").
*
- * <p><a name="default_behavior_example"/>
+ * <p><a name="default_behavior_example"></a>
* <strong>Example:</strong>
* <p>
* The following class and property files are provided:
@@ -2608,7 +2610,8 @@
}
if (stream != null) {
try {
- bundle = new PropertyResourceBundle(stream);
+ bundle = new PropertyResourceBundle(
+ new InputStreamReader(stream, StandardCharsets.UTF_8));
} finally {
stream.close();
}
diff --git a/ojluni/src/main/java/java/util/Spliterators.java b/ojluni/src/main/java/java/util/Spliterators.java
index 3f97a83..79c0ef3 100644
--- a/ojluni/src/main/java/java/util/Spliterators.java
+++ b/ojluni/src/main/java/java/util/Spliterators.java
@@ -384,7 +384,7 @@
*/
private static void checkFromToBounds(int arrayLength, int origin, int fence) {
if (origin > fence) {
- throw new IllegalArgumentException(
+ throw new ArrayIndexOutOfBoundsException(
"origin(" + origin + ") > fence(" + fence + ")");
}
if (origin < 0) {
diff --git a/ojluni/src/main/java/java/util/TimSort.java b/ojluni/src/main/java/java/util/TimSort.java
index 9966f74..ea0d58f 100755
--- a/ojluni/src/main/java/java/util/TimSort.java
+++ b/ojluni/src/main/java/java/util/TimSort.java
@@ -174,10 +174,14 @@
* large) stack lengths for smaller arrays. The "magic numbers" in the
* computation below must be changed if MIN_MERGE is decreased. See
* the MIN_MERGE declaration above for more information.
+ * The maximum value of 49 allows for an array up to length
+ * Integer.MAX_VALUE-4, if array is filled by the worst case stack size
+ * increasing scenario. More explanations are given in section 4 of:
+ * http://envisage-project.eu/wp-content/uploads/2015/02/sorting.pdf
*/
int stackLen = (len < 120 ? 5 :
len < 1542 ? 10 :
- len < 119151 ? 24 : 40);
+ len < 119151 ? 24 : 49);
runBase = new int[stackLen];
runLen = new int[stackLen];
}
diff --git a/ojluni/src/main/java/java/util/TreeMap.java b/ojluni/src/main/java/java/util/TreeMap.java
index 76e9b00..5e26f0f 100755
--- a/ojluni/src/main/java/java/util/TreeMap.java
+++ b/ojluni/src/main/java/java/util/TreeMap.java
@@ -998,6 +998,27 @@
}
@Override
+ public boolean replace(K key, V oldValue, V newValue) {
+ TreeMapEntry<K,V> p = getEntry(key);
+ if (p!=null && Objects.equals(oldValue, p.value)) {
+ p.value = newValue;
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public V replace(K key, V value) {
+ TreeMapEntry<K,V> p = getEntry(key);
+ if (p!=null) {
+ V oldValue = p.value;
+ p.value = value;
+ return oldValue;
+ }
+ return null;
+ }
+
+ @Override
public void forEach(BiConsumer<? super K, ? super V> action) {
Objects.requireNonNull(action);
int expectedModCount = modCount;
@@ -1010,6 +1031,20 @@
}
}
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ int expectedModCount = modCount;
+
+ for (TreeMapEntry<K, V> e = getFirstEntry(); e != null; e = successor(e)) {
+ e.value = function.apply(e.key, e.value);
+
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+
// View class support
class Values extends AbstractCollection<V> {
diff --git a/ojluni/src/main/java/java/util/WeakHashMap.java b/ojluni/src/main/java/java/util/WeakHashMap.java
index 9edf7b7..7785e05 100755
--- a/ojluni/src/main/java/java/util/WeakHashMap.java
+++ b/ojluni/src/main/java/java/util/WeakHashMap.java
@@ -28,6 +28,7 @@
import java.lang.ref.WeakReference;
import java.lang.ref.ReferenceQueue;
import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -188,68 +189,6 @@
*/
int modCount;
- /**
- * The default threshold of map capacity above which alternative hashing is
- * used for String keys. Alternative hashing reduces the incidence of
- * collisions due to weak hash code calculation for String keys.
- * <p/>
- * This value may be overridden by defining the system property
- * {@code jdk.map.althashing.threshold}. A property value of {@code 1}
- * forces alternative hashing to be used at all times whereas
- * {@code -1} value ensures that alternative hashing is never used.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD_DEFAULT = Integer.MAX_VALUE;
-
- /**
- * holds values which can't be initialized until after VM is booted.
- */
- private static class Holder {
-
- /**
- * Table capacity above which to switch to use alternative hashing.
- */
- static final int ALTERNATIVE_HASHING_THRESHOLD;
-
- static {
- String altThreshold = java.security.AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "jdk.map.althashing.threshold"));
-
- int threshold;
- try {
- threshold = (null != altThreshold)
- ? Integer.parseInt(altThreshold)
- : ALTERNATIVE_HASHING_THRESHOLD_DEFAULT;
-
- // disable alternative hashing if -1
- if (threshold == -1) {
- threshold = Integer.MAX_VALUE;
- }
-
- if (threshold < 0) {
- throw new IllegalArgumentException("value must be positive integer.");
- }
- } catch(IllegalArgumentException failed) {
- throw new Error("Illegal value for 'jdk.map.althashing.threshold'", failed);
- }
- ALTERNATIVE_HASHING_THRESHOLD = threshold;
- }
- }
-
- /**
- * If {@code true} then perform alternate hashing to reduce the incidence of
- * collisions due to weak hash code calculation.
- */
- transient boolean useAltHashing;
-
- /**
- * A randomizing value associated with this instance that is applied to
- * hash code of keys to make hash collisions harder to find.
- *
- * This hash seed is only used if {@code useAltHashing} is true.
- */
- transient int hashSeed;
-
@SuppressWarnings("unchecked")
private Entry<K,V>[] newTable(int n) {
return (Entry<K,V>[]) new Entry[n];
@@ -280,13 +219,6 @@
table = newTable(capacity);
this.loadFactor = loadFactor;
threshold = (int)(capacity * loadFactor);
- useAltHashing = sun.misc.VM.isBooted() &&
- (capacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
- if (useAltHashing) {
- hashSeed = sun.misc.Hashing.randomHashSeed(this);
- } else {
- hashSeed = 0;
- }
}
/**
@@ -355,34 +287,6 @@
}
/**
- * Retrieve object hash code and applies a supplemental hash function to the
- * result hash, which defends against poor quality hash functions. This is
- * critical because HashMap uses power-of-two length hash tables, that
- * otherwise encounter collisions for hashCodes that do not differ
- * in lower bits.
- */
- int hash(Object k) {
-
- int h;
- if (useAltHashing) {
- h = hashSeed;
- if (k instanceof String) {
- return sun.misc.Hashing.stringHash32((String) k);
- } else {
- h ^= k.hashCode();
- }
- } else {
- h = k.hashCode();
- }
-
- // This function ensures that hashCodes that differ only by
- // constant multiples at each bit position have a bounded
- // number of collisions (approximately 8 at default load factor).
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
-
- /**
* Returns index for hash code h.
*/
private static int indexFor(int h, int length) {
@@ -471,7 +375,7 @@
*/
public V get(Object key) {
Object k = maskNull(key);
- int h = hash(k);
+ int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
Entry<K,V>[] tab = getTable();
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
@@ -501,7 +405,7 @@
*/
Entry<K,V> getEntry(Object key) {
Object k = maskNull(key);
- int h = hash(k);
+ int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
Entry<K,V>[] tab = getTable();
int index = indexFor(h, tab.length);
Entry<K,V> e = tab[index];
@@ -524,7 +428,7 @@
*/
public V put(K key, V value) {
Object k = maskNull(key);
- int h = hash(k);
+ int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
Entry<K,V>[] tab = getTable();
int i = indexFor(h, tab.length);
@@ -568,14 +472,7 @@
}
Entry<K,V>[] newTable = newTable(newCapacity);
- boolean oldAltHashing = useAltHashing;
- useAltHashing |= sun.misc.VM.isBooted() &&
- (newCapacity >= Holder.ALTERNATIVE_HASHING_THRESHOLD);
- boolean rehash = oldAltHashing ^ useAltHashing;
- if (rehash) {
- hashSeed = sun.misc.Hashing.randomHashSeed(this);
- }
- transfer(oldTable, newTable, rehash);
+ transfer(oldTable, newTable);
table = newTable;
/*
@@ -587,13 +484,13 @@
threshold = (int)(newCapacity * loadFactor);
} else {
expungeStaleEntries();
- transfer(newTable, oldTable, false);
+ transfer(newTable, oldTable);
table = oldTable;
}
}
/** Transfers all entries from src to dest tables */
- private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest, boolean rehash) {
+ private void transfer(Entry<K,V>[] src, Entry<K,V>[] dest) {
for (int j = 0; j < src.length; ++j) {
Entry<K,V> e = src[j];
src[j] = null;
@@ -605,9 +502,6 @@
e.value = null; // " "
size--;
} else {
- if (rehash) {
- e.hash = hash(key);
- }
int i = indexFor(e.hash, dest.length);
e.next = dest[i];
dest[i] = e;
@@ -676,7 +570,7 @@
*/
public V remove(Object key) {
Object k = maskNull(key);
- int h = hash(k);
+ int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
Entry<K,V>[] tab = getTable();
int i = indexFor(h, tab.length);
Entry<K,V> prev = tab[i];
@@ -707,7 +601,7 @@
Entry<K,V>[] tab = getTable();
Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
Object k = maskNull(entry.getKey());
- int h = hash(k);
+ int h = sun.misc.Hashing.singleWordWangJenkinsHash(k);
int i = indexFor(h, tab.length);
Entry<K,V> prev = tab[i];
Entry<K,V> e = prev;
@@ -1114,6 +1008,29 @@
}
}
+ @SuppressWarnings("unchecked")
+ @Override
+ public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+ Objects.requireNonNull(function);
+ int expectedModCount = modCount;
+
+ Entry<K, V>[] tab = getTable();
+ for (Entry<K, V> entry : tab) {
+ while (entry != null) {
+ Object key = entry.get();
+ if (key != null) {
+ entry.value = function.apply((K)WeakHashMap.unmaskNull(key), entry.value);
+ }
+ entry = entry.next;
+
+ if (expectedModCount != modCount) {
+ throw new ConcurrentModificationException();
+ }
+ }
+ }
+ }
+
+
/**
* Similar form as other hash Spliterators, but skips dead
* elements.
diff --git a/ojluni/src/main/java/java/util/jar/Attributes.java b/ojluni/src/main/java/java/util/jar/Attributes.java
index 5fc1c91..d7f68a0 100755
--- a/ojluni/src/main/java/java/util/jar/Attributes.java
+++ b/ojluni/src/main/java/java/util/jar/Attributes.java
@@ -45,7 +45,7 @@
* the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed 70
* characters in length. Attribute values can contain any characters and
* will be UTF8-encoded when written to the output stream. See the
- * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+ * <a href="{@docRoot}/../technotes/guides/jar/jar.html">JAR File Specification</a>
* for more information about valid attribute names and values.
*
* @author David Connelly
@@ -442,7 +442,7 @@
* to the ASCII characters in the set [0-9a-zA-Z_-], and cannot exceed
* 70 characters in length. Attribute values can contain any characters
* and will be UTF8-encoded when written to the output stream. See the
- * <a href="../../../../technotes/guides/jar/jar.html">JAR File Specification</a>
+ * <a href="{@docRoot}/../technotes/guides/jar/jar.html">JAR File Specification</a>
* for more information about valid attribute names and values.
*/
public static class Name {
@@ -528,7 +528,7 @@
* <code>Name</code> object for <code>Manifest-Version</code>
* manifest attribute. This attribute indicates the version number
* of the manifest standard to which a JAR file's manifest conforms.
- * @see <a href="../../../../technotes/guides/jar/jar.html#JAR Manifest">
+ * @see <a href="{@docRoot}/../technotes/guides/jar/jar.html#JAR Manifest">
* Manifest and Signature Specification</a>
*/
public static final Name MANIFEST_VERSION = new Name("Manifest-Version");
@@ -536,7 +536,7 @@
/**
* <code>Name</code> object for <code>Signature-Version</code>
* manifest attribute used when signing JAR files.
- * @see <a href="../../../../technotes/guides/jar/jar.html#JAR Manifest">
+ * @see <a href="{@docRoot}/../technotes/guides/jar/jar.html#JAR Manifest">
* Manifest and Signature Specification</a>
*/
public static final Name SIGNATURE_VERSION = new Name("Signature-Version");
@@ -551,7 +551,7 @@
* <code>Name</code> object for <code>Class-Path</code>
* manifest attribute. Bundled extensions can use this attribute
* to find other JAR files containing needed classes.
- * @see <a href="../../../../technotes/guides/extensions/spec.html#bundled">
+ * @see <a href="{@docRoot}/../technotes/guides/extensions/spec.html#bundled">
* Extensions Specification</a>
*/
public static final Name CLASS_PATH = new Name("Class-Path");
@@ -568,7 +568,7 @@
/**
* <code>Name</code> object for <code>Sealed</code> manifest attribute
* used for sealing.
- * @see <a href="../../../../technotes/guides/extensions/spec.html#sealing">
+ * @see <a href="{@docRoot}/../technotes/guides/extensions/spec.html#sealing">
* Extension Sealing</a>
*/
public static final Name SEALED = new Name("Sealed");
@@ -576,7 +576,7 @@
/**
* <code>Name</code> object for <code>Extension-List</code> manifest attribute
* used for declaring dependencies on installed extensions.
- * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+ * @see <a href="{@docRoot}/../technotes/guides/extensions/spec.html#dependency">
* Installed extension dependency</a>
*/
public static final Name EXTENSION_LIST = new Name("Extension-List");
@@ -584,7 +584,7 @@
/**
* <code>Name</code> object for <code>Extension-Name</code> manifest attribute
* used for declaring dependencies on installed extensions.
- * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+ * @see <a href="{@docRoot}/../technotes/guides/extensions/spec.html#dependency">
* Installed extension dependency</a>
*/
public static final Name EXTENSION_NAME = new Name("Extension-Name");
@@ -592,7 +592,7 @@
/**
* <code>Name</code> object for <code>Extension-Name</code> manifest attribute
* used for declaring dependencies on installed extensions.
- * @see <a href="../../../../technotes/guides/extensions/spec.html#dependency">
+ * @see <a href="{@docRoot}/../technotes/guides/extensions/spec.html#dependency">
* Installed extension dependency</a>
*/
public static final Name EXTENSION_INSTALLATION = new Name("Extension-Installation");
@@ -600,7 +600,7 @@
/**
* <code>Name</code> object for <code>Implementation-Title</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name IMPLEMENTATION_TITLE = new Name("Implementation-Title");
@@ -608,7 +608,7 @@
/**
* <code>Name</code> object for <code>Implementation-Version</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name IMPLEMENTATION_VERSION = new Name("Implementation-Version");
@@ -616,7 +616,7 @@
/**
* <code>Name</code> object for <code>Implementation-Vendor</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name IMPLEMENTATION_VENDOR = new Name("Implementation-Vendor");
@@ -624,7 +624,7 @@
/**
* <code>Name</code> object for <code>Implementation-Vendor-Id</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name IMPLEMENTATION_VENDOR_ID = new Name("Implementation-Vendor-Id");
@@ -632,7 +632,7 @@
/**
* <code>Name</code> object for <code>Implementation-Vendor-URL</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name IMPLEMENTATION_URL = new Name("Implementation-URL");
@@ -640,7 +640,7 @@
/**
* <code>Name</code> object for <code>Specification-Title</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name SPECIFICATION_TITLE = new Name("Specification-Title");
@@ -648,7 +648,7 @@
/**
* <code>Name</code> object for <code>Specification-Version</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name SPECIFICATION_VERSION = new Name("Specification-Version");
@@ -656,7 +656,7 @@
/**
* <code>Name</code> object for <code>Specification-Vendor</code>
* manifest attribute used for package versioning.
- * @see <a href="../../../../technotes/guides/versioning/spec/versioning2.html#wp90779">
+ * @see <a href="{@docRoot}/../technotes/guides/versioning/spec/versioning2.html#wp90779">
* Java Product Versioning Specification</a>
*/
public static final Name SPECIFICATION_VENDOR = new Name("Specification-Vendor");
diff --git a/ojluni/src/main/java/java/util/jar/JarFile.java b/ojluni/src/main/java/java/util/jar/JarFile.java
index a0d0de9..f219505 100755
--- a/ojluni/src/main/java/java/util/jar/JarFile.java
+++ b/ojluni/src/main/java/java/util/jar/JarFile.java
@@ -174,7 +174,7 @@
return getManifestFromReference();
}
- private Manifest getManifestFromReference() throws IOException {
+ private synchronized Manifest getManifestFromReference() throws IOException {
Manifest man = manRef != null ? manRef.get() : null;
if (man == null) {
@@ -474,7 +474,7 @@
optoSft[9]=1;
}
- private JarEntry getManEntry() {
+ private synchronized JarEntry getManEntry() {
if (manEntry == null) {
// First look up manifest entry using standard name
manEntry = getJarEntry(MANIFEST_NAME);
@@ -591,100 +591,6 @@
return new JarFileEntry(ze);
}
- Enumeration<String> entryNames(CodeSource[] cs) {
- ensureInitialization();
- if (jv != null) {
- return jv.entryNames(this, cs);
- }
-
- /*
- * JAR file has no signed content. Is there a non-signing
- * code source?
- */
- boolean includeUnsigned = false;
- for (int i = 0; i < cs.length; i++) {
- if (cs[i].getCodeSigners() == null) {
- includeUnsigned = true;
- break;
- }
- }
- if (includeUnsigned) {
- return unsignedEntryNames();
- } else {
- return new Enumeration<String>() {
-
- public boolean hasMoreElements() {
- return false;
- }
-
- public String nextElement() {
- throw new NoSuchElementException();
- }
- };
- }
- }
-
- /**
- * Returns an enumeration of the zip file entries
- * excluding internal JAR mechanism entries and including
- * signed entries missing from the ZIP directory.
- */
- Enumeration<JarEntry> entries2() {
- ensureInitialization();
- if (jv != null) {
- return jv.entries2(this, super.entries());
- }
-
- // screen out entries which are never signed
- final Enumeration enum_ = super.entries();
- return new Enumeration<JarEntry>() {
-
- ZipEntry entry;
-
- public boolean hasMoreElements() {
- if (entry != null) {
- return true;
- }
- while (enum_.hasMoreElements()) {
- ZipEntry ze = (ZipEntry) enum_.nextElement();
- if (JarVerifier.isSigningRelated(ze.getName())) {
- continue;
- }
- entry = ze;
- return true;
- }
- return false;
- }
-
- public JarFileEntry nextElement() {
- if (hasMoreElements()) {
- ZipEntry ze = entry;
- entry = null;
- return new JarFileEntry(ze);
- }
- throw new NoSuchElementException();
- }
- };
- }
-
- CodeSource[] getCodeSources(URL url) {
- ensureInitialization();
- if (jv != null) {
- return jv.getCodeSources(this, url);
- }
-
- /*
- * JAR file has no signed content. Is there a non-signing
- * code source?
- */
- Enumeration unsigned = unsignedEntryNames();
- if (unsigned.hasMoreElements()) {
- return new CodeSource[]{JarVerifier.getUnsignedCS(url)};
- } else {
- return null;
- }
- }
-
private Enumeration<String> unsignedEntryNames() {
final Enumeration entries = entries();
return new Enumeration<String>() {
@@ -722,43 +628,4 @@
}
};
}
-
- CodeSource getCodeSource(URL url, String name) {
- ensureInitialization();
- if (jv != null) {
- if (jv.eagerValidation) {
- CodeSource cs = null;
- JarEntry je = getJarEntry(name);
- if (je != null) {
- cs = jv.getCodeSource(url, this, je);
- } else {
- cs = jv.getCodeSource(url, name);
- }
- return cs;
- } else {
- return jv.getCodeSource(url, name);
- }
- }
-
- return JarVerifier.getUnsignedCS(url);
- }
-
- void setEagerValidation(boolean eager) {
- try {
- maybeInstantiateVerifier();
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- if (jv != null) {
- jv.setEagerValidation(eager);
- }
- }
-
- List getManifestDigests() {
- ensureInitialization();
- if (jv != null) {
- return jv.getManifestDigests();
- }
- return new ArrayList();
- }
}
diff --git a/ojluni/src/main/java/java/util/jar/Manifest.java b/ojluni/src/main/java/java/util/jar/Manifest.java
index b6c7c3b..092926b 100755
--- a/ojluni/src/main/java/java/util/jar/Manifest.java
+++ b/ojluni/src/main/java/java/util/jar/Manifest.java
@@ -39,7 +39,7 @@
* associated Attributes. There are main Manifest Attributes as well as
* per-entry Attributes. For information on the Manifest format, please
* see the
- * <a href="../../../../technotes/guides/jar/jar.html">
+ * <a href="{@docRoot}/../technotes/guides/jar/jar.html">
* Manifest format specification</a>.
*
* @author David Connelly
diff --git a/ojluni/src/main/java/java/util/jar/package.html b/ojluni/src/main/java/java/util/jar/package.html
index dd9ad73..f485e63 100755
--- a/ojluni/src/main/java/java/util/jar/package.html
+++ b/ojluni/src/main/java/java/util/jar/package.html
@@ -45,7 +45,7 @@
package description.</a> <p>
In JAR files, all file names must be encoded in the UTF-8 encoding.
<p>
- <li><a href="../../../../technotes/guides/jar/jar.html">
+ <li><a href="{@docRoot}/../technotes/guides/jar/jar.html">
Manifest and Signature Specification</a> - The manifest format specification.
</ul>
diff --git a/ojluni/src/main/java/java/util/logging/Logger.java b/ojluni/src/main/java/java/util/logging/Logger.java
index e9728de..3652914 100755
--- a/ojluni/src/main/java/java/util/logging/Logger.java
+++ b/ojluni/src/main/java/java/util/logging/Logger.java
@@ -329,7 +329,7 @@
return System.getProperty(key);
}
});
- return Boolean.valueOf(s);
+ return Boolean.parseBoolean(s);
}
}
diff --git a/ojluni/src/main/java/java/util/logging/package.html b/ojluni/src/main/java/java/util/logging/package.html
index cafcdad..0dd7882 100755
--- a/ojluni/src/main/java/java/util/logging/package.html
+++ b/ojluni/src/main/java/java/util/logging/package.html
@@ -116,7 +116,7 @@
<P>
For an overview of control flow,
please refer to the
-<a href="../../../../technotes/guides/logging/overview.html">
+<a href="{@docRoot}/../technotes/guides/logging/overview.html">
Java Logging Overview</a>.
</P>
diff --git a/ojluni/src/main/java/java/util/package.html b/ojluni/src/main/java/java/util/package.html
index a655934..d062b97 100755
--- a/ojluni/src/main/java/java/util/package.html
+++ b/ojluni/src/main/java/java/util/package.html
@@ -35,8 +35,8 @@
<h2>Package Specification</h2>
<ul>
- <li><a href="../../../technotes/guides/collections/overview.html"><b>Collections Framework Overview</b></a>
- <li><a href="../../../technotes/guides/collections/reference.html"><b>
+ <li><a href="{@docRoot}/../technotes/guides/collections/overview.html"><b>Collections Framework Overview</b></a>
+ <li><a href="{@docRoot}/../technotes/guides/collections/reference.html"><b>
Collections Framework Annotated Outline</b></a>
</ul>
@@ -46,7 +46,7 @@
<li><a href="http://www.java.sun.com/docs/books/tutorial/collections/">
<b>Collections Framework Tutorial</b></a>
<li><a
- href="../../../technotes/guides/collections/designfaq.html"><b>Collections
+ href="{@docRoot}/../technotes/guides/collections/designfaq.html"><b>Collections
Framework Design FAQ</b></a>
</ul>
diff --git a/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java b/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
index c655ea1..a9c0962 100755
--- a/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
+++ b/ojluni/src/main/java/java/util/prefs/FileSystemPreferences.java
@@ -53,15 +53,6 @@
// Android changed: @hide.
public class FileSystemPreferences extends AbstractPreferences {
/**
- * Sync interval in seconds.
- */
- private static final int SYNC_INTERVAL = Math.max(1,
- Integer.parseInt(
- AccessController.doPrivileged(
- new sun.security.action.GetPropertyAction(
- "java.util.prefs.syncInterval", "30"))));
-
- /**
* Returns logger for error messages. Backing store exceptions are logged at
* WARNING level.
*/
@@ -427,27 +418,12 @@
changeLog.get(i).replay();
}
- private static Timer syncTimer = new Timer(true); // Daemon Thread
-
static {
- // Add periodic timer task to periodically sync cached prefs
- syncTimer.schedule(new TimerTask() {
+ // Add shutdown hook to flush cached prefs on normal termination
+ Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
syncWorld();
}
- }, SYNC_INTERVAL*1000, SYNC_INTERVAL*1000);
-
- // Add shutdown hook to flush cached prefs on normal termination
- AccessController.doPrivileged(new PrivilegedAction<Void>() {
- public Void run() {
- Runtime.getRuntime().addShutdownHook(new Thread() {
- public void run() {
- syncTimer.cancel();
- syncWorld();
- }
- });
- return null;
- }
});
}
diff --git a/ojluni/src/main/java/java/util/regex/Matcher.java b/ojluni/src/main/java/java/util/regex/Matcher.java
index 47062d7..dc37946 100755
--- a/ojluni/src/main/java/java/util/regex/Matcher.java
+++ b/ojluni/src/main/java/java/util/regex/Matcher.java
@@ -26,6 +26,7 @@
package java.util.regex;
+import libcore.util.NativeAllocationRegistry;
/**
* An engine that performs match operations on a {@link java.lang.CharSequence
@@ -115,6 +116,14 @@
private long address;
/**
+ * If non-null, a Runnable that can be used to explicitly deallocate address.
+ */
+ private Runnable nativeFinalizer;
+
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), nativeSize());
+
+ /**
* Holds the input text.
*/
private String input;
@@ -211,11 +220,13 @@
this.pattern = newPattern;
synchronized (this) {
- if (address != 0) {
- closeImpl(address);
+ if (nativeFinalizer != null) {
+ nativeFinalizer.run();
address = 0; // In case openImpl throws.
+ nativeFinalizer = null;
}
address = openImpl(pattern.address);
+ nativeFinalizer = registry.registerNativeAllocation(this, address);
}
if (input != null) {
@@ -1041,16 +1052,6 @@
}
}
- @Override protected void finalize() throws Throwable {
- try {
- synchronized (this) {
- closeImpl(address);
- }
- } finally {
- super.finalize();
- }
- }
-
/**
* Returns the start index of the previous match. </p>
*
@@ -1093,13 +1094,14 @@
return matchOffsets[group * 2];
}
- private static native void closeImpl(long addr);
private static native boolean findImpl(long addr, String s, int startIndex, int[] offsets);
private static native boolean findNextImpl(long addr, String s, int[] offsets);
+ private static native long getNativeFinalizer();
private static native int groupCountImpl(long addr);
private static native boolean hitEndImpl(long addr);
private static native boolean lookingAtImpl(long addr, String s, int[] offsets);
private static native boolean matchesImpl(long addr, String s, int[] offsets);
+ private static native int nativeSize();
private static native long openImpl(long patternAddr);
private static native boolean requireEndImpl(long addr);
private static native void setInputImpl(long addr, String s, int start, int end);
diff --git a/ojluni/src/main/java/java/util/regex/Pattern.java b/ojluni/src/main/java/java/util/regex/Pattern.java
index 8f6fe1f..1d772d9 100755
--- a/ojluni/src/main/java/java/util/regex/Pattern.java
+++ b/ojluni/src/main/java/java/util/regex/Pattern.java
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2014 The Android Open Source Project
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 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
@@ -26,8 +26,18 @@
package java.util.regex;
-import java.util.ArrayList;
+import libcore.util.NativeAllocationRegistry;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.NoSuchElementException;
+import java.util.Spliterator;
+import java.util.Spliterators;
+import java.util.function.Predicate;
+import java.util.stream.Stream;
+import java.util.stream.StreamSupport;
+
+import libcore.util.EmptyArray;
/**
* A compiled representation of a regular expression.
@@ -919,6 +929,9 @@
transient long address;
+ private static final NativeAllocationRegistry registry = new NativeAllocationRegistry(
+ getNativeFinalizer(), nativeSize());
+
/**
* Compiles the given regular expression into a pattern. </p>
@@ -1096,6 +1109,11 @@
* around matches of this pattern
*/
public String[] split(CharSequence input, int limit) {
+ String[] fast = fastSplit(pattern, input.toString(), limit);
+ if (fast != null) {
+ return fast;
+ }
+
int index = 0;
boolean matchLimited = limit > 0;
ArrayList<String> matchList = new ArrayList<>();
@@ -1132,6 +1150,85 @@
return matchList.subList(0, resultSize).toArray(result);
}
+ private static final String FASTSPLIT_METACHARACTERS = "\\?*+[](){}^$.|";
+
+ /**
+ * Returns a result equivalent to {@code s.split(separator, limit)} if it's able
+ * to compute it more cheaply than native impl, or null if the caller should fall back to
+ * using native impl.
+ *
+ * fastpath will work if the regex is a
+ * (1)one-char String and this character is not one of the
+ * RegEx's meta characters ".$|()[{^?*+\\", or
+ * (2)two-char String and the first char is the backslash and
+ * the second is one of regEx's meta characters ".$|()[{^?*+\\".
+ * @hide
+ */
+ public static String[] fastSplit(String re, String input, int limit) {
+ // Can we do it cheaply?
+ int len = re.length();
+ if (len == 0) {
+ return null;
+ }
+ char ch = re.charAt(0);
+ if (len == 1 && FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+ // We're looking for a single non-metacharacter. Easy.
+ } else if (len == 2 && ch == '\\') {
+ // We're looking for a quoted character.
+ // Quoted metacharacters are effectively single non-metacharacters.
+ ch = re.charAt(1);
+ if (FASTSPLIT_METACHARACTERS.indexOf(ch) == -1) {
+ return null;
+ }
+ } else {
+ return null;
+ }
+
+ // We can do this cheaply...
+
+ // Unlike Perl, which considers the result of splitting the empty string to be the empty
+ // array, Java returns an array containing the empty string.
+ if (input.isEmpty()) {
+ return new String[] { "" };
+ }
+
+ // Count separators
+ int separatorCount = 0;
+ int begin = 0;
+ int end;
+ while (separatorCount + 1 != limit && (end = input.indexOf(ch, begin)) != -1) {
+ ++separatorCount;
+ begin = end + 1;
+ }
+ int lastPartEnd = input.length();
+ if (limit == 0 && begin == lastPartEnd) {
+ // Last part is empty for limit == 0, remove all trailing empty matches.
+ if (separatorCount == lastPartEnd) {
+ // Input contains only separators.
+ return EmptyArray.STRING;
+ }
+ // Find the beginning of trailing separators.
+ do {
+ --begin;
+ } while (input.charAt(begin - 1) == ch);
+ // Reduce separatorCount and fix lastPartEnd.
+ separatorCount -= input.length() - begin;
+ lastPartEnd = begin;
+ }
+
+ // Collect the result parts.
+ String[] result = new String[separatorCount + 1];
+ begin = 0;
+ for (int i = 0; i != separatorCount; ++i) {
+ end = input.indexOf(ch, begin);
+ result[i] = input.substring(begin, end);
+ begin = end + 1;
+ }
+ // Add last part.
+ result[separatorCount] = input.substring(begin, lastPartEnd);
+ return result;
+ }
+
/**
* Splits the given input sequence around matches of this pattern.
*
@@ -1241,18 +1338,118 @@
// They even have the same value in native code.
int icuFlags = flags & (CASE_INSENSITIVE | COMMENTS | MULTILINE | DOTALL | UNIX_LINES);
address = compileImpl(icuPattern, icuFlags);
+ registry.registerNativeAllocation(this, address);
}
-
- @Override
- protected void finalize() throws Throwable {
- try {
- closeImpl(address);
- } finally {
- super.finalize();
- }
- }
-
- private static native void closeImpl(long addr);
private static native long compileImpl(String regex, int flags);
+ private static native long getNativeFinalizer();
+ private static native int nativeSize();
+
+ /**
+ * Creates a predicate which can be used to match a string.
+ *
+ * @return The predicate which can be used for matching on a string
+ * @since 1.8
+ */
+ public Predicate<String> asPredicate() {
+ return s -> matcher(s).find();
+ }
+
+ /**
+ * Creates a stream from the given input sequence around matches of this
+ * pattern.
+ *
+ * <p> The stream returned by this method contains each substring of the
+ * input sequence that is terminated by another subsequence that matches
+ * this pattern or is terminated by the end of the input sequence. The
+ * substrings in the stream are in the order in which they occur in the
+ * input. Trailing empty strings will be discarded and not encountered in
+ * the stream.
+ *
+ * <p> If this pattern does not match any subsequence of the input then
+ * the resulting stream has just one element, namely the input sequence in
+ * string form.
+ *
+ * <p> When there is a positive-width match at the beginning of the input
+ * sequence then an empty leading substring is included at the beginning
+ * of the stream. A zero-width match at the beginning however never produces
+ * such empty leading substring.
+ *
+ * <p> If the input sequence is mutable, it must remain constant during the
+ * execution of the terminal stream operation. Otherwise, the result of the
+ * terminal stream operation is undefined.
+ *
+ * @param input
+ * The character sequence to be split
+ *
+ * @return The stream of strings computed by splitting the input
+ * around matches of this pattern
+ * @see #split(CharSequence)
+ * @since 1.8
+ */
+ public Stream<String> splitAsStream(final CharSequence input) {
+ class MatcherIterator implements Iterator<String> {
+ private final Matcher matcher;
+ // The start position of the next sub-sequence of input
+ // when current == input.length there are no more elements
+ private int current;
+ // null if the next element, if any, needs to obtained
+ private String nextElement;
+ // > 0 if there are N next empty elements
+ private int emptyElementCount;
+
+ MatcherIterator() {
+ this.matcher = matcher(input);
+ }
+
+ public String next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+
+ if (emptyElementCount == 0) {
+ String n = nextElement;
+ nextElement = null;
+ return n;
+ } else {
+ emptyElementCount--;
+ return "";
+ }
+ }
+
+ public boolean hasNext() {
+ if (nextElement != null || emptyElementCount > 0)
+ return true;
+
+ if (current == input.length())
+ return false;
+
+ // Consume the next matching element
+ // Count sequence of matching empty elements
+ while (matcher.find()) {
+ nextElement = input.subSequence(current, matcher.start()).toString();
+ current = matcher.end();
+ if (!nextElement.isEmpty()) {
+ return true;
+ } else if (current > 0) { // no empty leading substring for zero-width
+ // match at the beginning of the input
+ emptyElementCount++;
+ }
+ }
+
+ // Consume last matching element
+ nextElement = input.subSequence(current, input.length()).toString();
+ current = input.length();
+ if (!nextElement.isEmpty()) {
+ return true;
+ } else {
+ // Ignore a terminal sequence of matching empty elements
+ emptyElementCount = 0;
+ nextElement = null;
+ return false;
+ }
+ }
+ }
+ return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
+ new MatcherIterator(), Spliterator.ORDERED | Spliterator.NONNULL), false);
+ }
}
diff --git a/ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java b/ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java
index 7abb25b..5308d812 100755
--- a/ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java
+++ b/ojluni/src/main/java/java/util/spi/LocaleServiceProvider.java
@@ -44,7 +44,7 @@
* <p>
* <h4>Packaging of Locale Sensitive Service Provider Implementations</h4>
* Implementations of these locale sensitive services are packaged using the
- * <a href="../../../../technotes/guides/extensions/index.html">Java Extension Mechanism</a>
+ * <a href="{@docRoot}/../technotes/guides/extensions/index.html">Java Extension Mechanism</a>
* as installed extensions. A provider identifies itself with a
* provider-configuration file in the resource directory META-INF/services,
* using the fully qualified provider interface class name as the file name.
diff --git a/ojluni/src/main/java/java/util/stream/LongStream.java b/ojluni/src/main/java/java/util/stream/LongStream.java
index 33d74ec..84189ef 100644
--- a/ojluni/src/main/java/java/util/stream/LongStream.java
+++ b/ojluni/src/main/java/java/util/stream/LongStream.java
@@ -24,6 +24,7 @@
*/
package java.util.stream;
+import java.math.BigInteger;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.Collection;
@@ -790,8 +791,11 @@
// Split the range in two and concatenate
// Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE) then
// the lower range, [Long.MIN_VALUE, 0) will be further split in two
- // Android-changed: no divideUnsigned support yet
- long m = startInclusive + ((endExclusive - startInclusive) / 2) + 1;
+ // Android-changed: no divideUnsigned support yet, use BigInteger instead.
+ long m = startInclusive +
+ BigInteger.valueOf(endExclusive).subtract(BigInteger.valueOf(startInclusive))
+ .divide(BigInteger.valueOf(2)).longValue() + 1;
+
return concat(range(startInclusive, m), range(m, endExclusive));
} else {
return StreamSupport.longStream(
@@ -825,8 +829,11 @@
// Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then
// the lower range, [Long.MIN_VALUE, 0), and upper range,
// [0, Long.MAX_VALUE], will both be further split in two
- // Android-changed: no divideUnsigned support yet
- long m = startInclusive + ((endInclusive - startInclusive) / 2) + 1;
+ // Android-changed: no divideUnsigned support yet, use BigInteger instead.
+ long m = startInclusive +
+ BigInteger.valueOf(endInclusive).subtract(BigInteger.valueOf(startInclusive))
+ .divide(BigInteger.valueOf(2)).longValue() + 1;
+
return concat(range(startInclusive, m), rangeClosed(m, endInclusive));
} else {
return StreamSupport.longStream(
diff --git a/ojluni/src/main/java/javax/security/sasl/package.html b/ojluni/src/main/java/javax/security/sasl/package.html
index cf497eb..7d9ba43 100755
--- a/ojluni/src/main/java/javax/security/sasl/package.html
+++ b/ojluni/src/main/java/javax/security/sasl/package.html
@@ -102,7 +102,7 @@
<h2>Related Documentation</h2>
Please refer to the
-<a href="../../../../technotes/guides/security/sasl/sasl-refguide.html">Java
+<a href="{@docRoot}/../technotes/guides/security/sasl/sasl-refguide.html">Java
SASL Programming Guide</a> for information on how to use this API.
diff --git a/ojluni/src/main/java/sun/misc/Hashing.java b/ojluni/src/main/java/sun/misc/Hashing.java
index 50e55ab..2b3b144 100755
--- a/ojluni/src/main/java/sun/misc/Hashing.java
+++ b/ojluni/src/main/java/sun/misc/Hashing.java
@@ -25,9 +25,6 @@
package sun.misc;
import java.util.concurrent.ThreadLocalRandom;
-// ----- BEGIN android -----
-import java.lang.JavaLangAccess;
-// ----- END android -----
/**
* Hashing utilities.
@@ -43,212 +40,18 @@
throw new Error("No instances");
}
- public static int murmur3_32(byte[] data) {
- return murmur3_32(0, data, 0, data.length);
- }
+ // Spread bits to regularize both segment and index locations,
+ // using variant of single-word Wang/Jenkins hash.
+ //
+ // Based on commit 1424a2a1a9fc53dc8b859a77c02c924.
+ public static int singleWordWangJenkinsHash(Object k) {
+ int h = k.hashCode();
- public static int murmur3_32(int seed, byte[] data) {
- return murmur3_32(seed, data, 0, data.length);
- }
-
- @SuppressWarnings("fallthrough")
- public static int murmur3_32(int seed, byte[] data, int offset, int len) {
- int h1 = seed;
- int count = len;
-
- // body
- while (count >= 4) {
- int k1 = (data[offset] & 0x0FF)
- | (data[offset + 1] & 0x0FF) << 8
- | (data[offset + 2] & 0x0FF) << 16
- | data[offset + 3] << 24;
-
- count -= 4;
- offset += 4;
-
- k1 *= 0xcc9e2d51;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= 0x1b873593;
-
- h1 ^= k1;
- h1 = Integer.rotateLeft(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- // tail
-
- if (count > 0) {
- int k1 = 0;
-
- switch (count) {
- case 3:
- k1 ^= (data[offset + 2] & 0xff) << 16;
- // fall through
- case 2:
- k1 ^= (data[offset + 1] & 0xff) << 8;
- // fall through
- case 1:
- k1 ^= (data[offset] & 0xff);
- // fall through
- default:
- k1 *= 0xcc9e2d51;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= 0x1b873593;
- h1 ^= k1;
- }
- }
-
- // finalization
-
- h1 ^= len;
-
- // finalization mix force all bits of a hash block to avalanche
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
-
- return h1;
- }
-
- public static int murmur3_32(char[] data) {
- return murmur3_32(0, data, 0, data.length);
- }
-
- public static int murmur3_32(int seed, char[] data) {
- return murmur3_32(seed, data, 0, data.length);
- }
-
- public static int murmur3_32(int seed, char[] data, int offset, int len) {
- int h1 = seed;
-
- int off = offset;
- int count = len;
-
- // body
- while (count >= 2) {
- int k1 = (data[off++] & 0xFFFF) | (data[off++] << 16);
-
- count -= 2;
-
- k1 *= 0xcc9e2d51;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= 0x1b873593;
-
- h1 ^= k1;
- h1 = Integer.rotateLeft(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- // tail
-
- if (count > 0) {
- int k1 = data[off];
-
- k1 *= 0xcc9e2d51;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= 0x1b873593;
- h1 ^= k1;
- }
-
- // finalization
-
- h1 ^= len * (Character.SIZE / Byte.SIZE);
-
- // finalization mix force all bits of a hash block to avalanche
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
-
- return h1;
- }
-
- public static int murmur3_32(int[] data) {
- return murmur3_32(0, data, 0, data.length);
- }
-
- public static int murmur3_32(int seed, int[] data) {
- return murmur3_32(seed, data, 0, data.length);
- }
-
- public static int murmur3_32(int seed, int[] data, int offset, int len) {
- int h1 = seed;
-
- int off = offset;
- int end = offset + len;
-
- // body
- while (off < end) {
- int k1 = data[off++];
-
- k1 *= 0xcc9e2d51;
- k1 = Integer.rotateLeft(k1, 15);
- k1 *= 0x1b873593;
-
- h1 ^= k1;
- h1 = Integer.rotateLeft(h1, 13);
- h1 = h1 * 5 + 0xe6546b64;
- }
-
- // tail (always empty, as body is always 32-bit chunks)
-
- // finalization
-
- h1 ^= len * (Integer.SIZE / Byte.SIZE);
-
- // finalization mix force all bits of a hash block to avalanche
- h1 ^= h1 >>> 16;
- h1 *= 0x85ebca6b;
- h1 ^= h1 >>> 13;
- h1 *= 0xc2b2ae35;
- h1 ^= h1 >>> 16;
-
- return h1;
- }
-
- /**
- * Return a 32 bit hash value for the specified string. The algorithm is
- * unspecified but will be consistent within a VM instance.
- *
- * @param string String to be hashed.
- * @return hash value of the string.
- */
- public static int stringHash32(String string) {
- // Android-changed: Access JavaLangAccess directly.
- return JavaLangAccess.getStringHash32(string);
- }
-
- /**
- * Return a non-zero 32-bit pseudo random value. The {@code instance} object
- * may be used as part of the value.
- *
- * @param instance an object to use if desired in choosing value.
- * @return a non-zero 32-bit pseudo random value.
- */
- public static int randomHashSeed(Object instance) {
- int seed;
- if (sun.misc.VM.isBooted()) {
- seed = ThreadLocalRandom.current().nextInt();
- } else {
- // lower quality "random" seed value--still better than zero and not
- // not practically reversible.
- int hashing_seed[] = {
- System.identityHashCode(Hashing.class),
- System.identityHashCode(instance),
- System.identityHashCode(Thread.currentThread()),
- (int) Thread.currentThread().getId(),
- (int) (System.currentTimeMillis() >>> 2), // resolution is poor
- (int) (System.nanoTime() >>> 5), // resolution is poor
- (int) (Runtime.getRuntime().freeMemory() >>> 4) // alloc min
- };
-
- seed = murmur3_32(hashing_seed);
- }
-
- // force to non-zero.
- return (0 != seed) ? seed : 1;
+ h += (h << 15) ^ 0xffffcd7d;
+ h ^= (h >>> 10);
+ h += (h << 3);
+ h ^= (h >>> 6);
+ h += (h << 2) + (h << 14);
+ return h ^ (h >>> 16);
}
}
diff --git a/ojluni/src/main/java/sun/misc/VM.java b/ojluni/src/main/java/sun/misc/VM.java
index e8af1d1..b57eb4a 100755
--- a/ojluni/src/main/java/sun/misc/VM.java
+++ b/ojluni/src/main/java/sun/misc/VM.java
@@ -295,7 +295,7 @@
allowGetCallerClass = (s != null
? (s.isEmpty() || Boolean.parseBoolean(s))
: true) ||
- Boolean.valueOf(props.getProperty("jdk.logging.allowStackWalkSearch"));
+ Boolean.parseBoolean(props.getProperty("jdk.logging.allowStackWalkSearch"));
// Remove other private system properties
// used by java.lang.Integer.IntegerCache
diff --git a/ojluni/src/main/java/sun/misc/Version.java b/ojluni/src/main/java/sun/misc/Version.java
index 319180c..2908005 100644
--- a/ojluni/src/main/java/sun/misc/Version.java
+++ b/ojluni/src/main/java/sun/misc/Version.java
@@ -31,7 +31,7 @@
// Android-changed : launcher_name, java_version,
// java_runtime_name and java_runtime_version.
private static final String launcher_name = "";
- private static final String java_version = "0";
+ private static final String java_version = AndroidHardcodedSystemProperties.JAVA_VERSION;
private static final String java_runtime_name = "Android Runtime";
private static final String java_runtime_version = "0.9";
@@ -280,7 +280,7 @@
int nextChar = 3;
try {
String uu = cs.subSequence(1, 3).toString();
- jvm_update_version = Integer.valueOf(uu).intValue();
+ jvm_update_version = Integer.parseInt(uu);
if (cs.length() >= 4) {
char c = cs.charAt(3);
if (c >= 'a' && c <= 'z') {
@@ -305,7 +305,7 @@
Character.isDigit(s.charAt(1)) &&
Character.isDigit(s.charAt(2))) {
jvm_build_number =
- Integer.valueOf(s.substring(1, 3)).intValue();
+ Integer.parseInt(s.substring(1, 3));
break;
}
}
diff --git a/ojluni/src/main/java/sun/net/www/http/HttpClient.java b/ojluni/src/main/java/sun/net/www/http/HttpClient.java
index b5a4329..09e0dbb 100755
--- a/ojluni/src/main/java/sun/net/www/http/HttpClient.java
+++ b/ojluni/src/main/java/sun/net/www/http/HttpClient.java
@@ -150,13 +150,13 @@
new sun.security.action.GetPropertyAction("sun.net.http.retryPost"));
if (keepAlive != null) {
- keepAliveProp = Boolean.valueOf(keepAlive).booleanValue();
+ keepAliveProp = Boolean.parseBoolean(keepAlive);
} else {
keepAliveProp = true;
}
if (retryPost != null) {
- retryPostProp = Boolean.valueOf(retryPost).booleanValue();
+ retryPostProp = Boolean.parseBoolean(retryPost);
} else
retryPostProp = true;
diff --git a/ojluni/src/main/java/sun/nio/ch/AsynchronousChannelGroupImpl.java b/ojluni/src/main/java/sun/nio/ch/AsynchronousChannelGroupImpl.java
new file mode 100755
index 0000000..a584ce9
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/AsynchronousChannelGroupImpl.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.Channel;
+import java.nio.channels.AsynchronousChannelGroup;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Queue;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.AccessControlContext;
+import sun.security.action.GetIntegerAction;
+
+/**
+ * Base implementation of AsynchronousChannelGroup
+ */
+
+abstract class AsynchronousChannelGroupImpl
+ extends AsynchronousChannelGroup implements Executor
+{
+ // number of internal threads handling I/O events when using an unbounded
+ // thread pool. Internal threads do not dispatch to completion handlers.
+ private static final int internalThreadCount = AccessController.doPrivileged(
+ new GetIntegerAction("sun.nio.ch.internalThreadPoolSize", 1));
+
+ // associated thread pool
+ private final ThreadPool pool;
+
+ // number of tasks running (including internal)
+ private final AtomicInteger threadCount = new AtomicInteger();
+
+ // associated Executor for timeouts
+ private ScheduledThreadPoolExecutor timeoutExecutor;
+
+ // task queue for when using a fixed thread pool. In that case, thread
+ // waiting on I/O events must be awokon to poll tasks from this queue.
+ private final Queue<Runnable> taskQueue;
+
+ // group shutdown
+ private final AtomicBoolean shutdown = new AtomicBoolean();
+ private final Object shutdownNowLock = new Object();
+ private volatile boolean terminateInitiated;
+
+ AsynchronousChannelGroupImpl(AsynchronousChannelProvider provider,
+ ThreadPool pool)
+ {
+ super(provider);
+ this.pool = pool;
+
+ if (pool.isFixedThreadPool()) {
+ taskQueue = new ConcurrentLinkedQueue<Runnable>();
+ } else {
+ taskQueue = null; // not used
+ }
+
+ // use default thread factory as thread should not be visible to
+ // application (it doesn't execute completion handlers).
+ this.timeoutExecutor = (ScheduledThreadPoolExecutor)
+ Executors.newScheduledThreadPool(1, ThreadPool.defaultThreadFactory());
+ this.timeoutExecutor.setRemoveOnCancelPolicy(true);
+ }
+
+ final ExecutorService executor() {
+ return pool.executor();
+ }
+
+ final boolean isFixedThreadPool() {
+ return pool.isFixedThreadPool();
+ }
+
+ final int fixedThreadCount() {
+ if (isFixedThreadPool()) {
+ return pool.poolSize();
+ } else {
+ return pool.poolSize() + internalThreadCount;
+ }
+ }
+
+ private Runnable bindToGroup(final Runnable task) {
+ final AsynchronousChannelGroupImpl thisGroup = this;
+ return new Runnable() {
+ public void run() {
+ Invoker.bindToGroup(thisGroup);
+ task.run();
+ }
+ };
+ }
+
+ private void startInternalThread(final Runnable task) {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ // internal threads should not be visible to application so
+ // cannot use user-supplied thread factory
+ ThreadPool.defaultThreadFactory().newThread(task).start();
+ return null;
+ }
+ });
+ }
+
+ protected final void startThreads(Runnable task) {
+ if (!isFixedThreadPool()) {
+ for (int i=0; i<internalThreadCount; i++) {
+ startInternalThread(task);
+ threadCount.incrementAndGet();
+ }
+ }
+ if (pool.poolSize() > 0) {
+ task = bindToGroup(task);
+ try {
+ for (int i=0; i<pool.poolSize(); i++) {
+ pool.executor().execute(task);
+ threadCount.incrementAndGet();
+ }
+ } catch (RejectedExecutionException x) {
+ // nothing we can do
+ }
+ }
+ }
+
+ final int threadCount() {
+ return threadCount.get();
+ }
+
+ /**
+ * Invoked by tasks as they terminate
+ */
+ final int threadExit(Runnable task, boolean replaceMe) {
+ if (replaceMe) {
+ try {
+ if (Invoker.isBoundToAnyGroup()) {
+ // submit new task to replace this thread
+ pool.executor().execute(bindToGroup(task));
+ } else {
+ // replace internal thread
+ startInternalThread(task);
+ }
+ return threadCount.get();
+ } catch (RejectedExecutionException x) {
+ // unable to replace
+ }
+ }
+ return threadCount.decrementAndGet();
+ }
+
+ /**
+ * Wakes up a thread waiting for I/O events to execute the given task.
+ */
+ abstract void executeOnHandlerTask(Runnable task);
+
+ /**
+ * For a fixed thread pool the task is queued to a thread waiting on I/O
+ * events. For other thread pools we simply submit the task to the thread
+ * pool.
+ */
+ final void executeOnPooledThread(Runnable task) {
+ if (isFixedThreadPool()) {
+ executeOnHandlerTask(task);
+ } else {
+ pool.executor().execute(bindToGroup(task));
+ }
+ }
+
+ final void offerTask(Runnable task) {
+ taskQueue.offer(task);
+ }
+
+ final Runnable pollTask() {
+ return (taskQueue == null) ? null : taskQueue.poll();
+ }
+
+ final Future<?> schedule(Runnable task, long timeout, TimeUnit unit) {
+ try {
+ return timeoutExecutor.schedule(task, timeout, unit);
+ } catch (RejectedExecutionException rej) {
+ if (terminateInitiated) {
+ // no timeout scheduled as group is terminating
+ return null;
+ }
+ throw new AssertionError(rej);
+ }
+ }
+
+ @Override
+ public final boolean isShutdown() {
+ return shutdown.get();
+ }
+
+ @Override
+ public final boolean isTerminated() {
+ return pool.executor().isTerminated();
+ }
+
+ /**
+ * Returns true if there are no channels in the group
+ */
+ abstract boolean isEmpty();
+
+ /**
+ * Attaches a foreign channel to this group.
+ */
+ abstract Object attachForeignChannel(Channel channel, FileDescriptor fdo)
+ throws IOException;
+
+ /**
+ * Detaches a foreign channel from this group.
+ */
+ abstract void detachForeignChannel(Object key);
+
+ /**
+ * Closes all channels in the group
+ */
+ abstract void closeAllChannels() throws IOException;
+
+ /**
+ * Shutdown all tasks waiting for I/O events.
+ */
+ abstract void shutdownHandlerTasks();
+
+ private void shutdownExecutors() {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ pool.executor().shutdown();
+ timeoutExecutor.shutdown();
+ return null;
+ }
+ });
+ }
+
+ @Override
+ public final void shutdown() {
+ if (shutdown.getAndSet(true)) {
+ // already shutdown
+ return;
+ }
+ // if there are channels in the group then shutdown will continue
+ // when the last channel is closed
+ if (!isEmpty()) {
+ return;
+ }
+ // initiate termination (acquire shutdownNowLock to ensure that other
+ // threads invoking shutdownNow will block).
+ synchronized (shutdownNowLock) {
+ if (!terminateInitiated) {
+ terminateInitiated = true;
+ shutdownHandlerTasks();
+ shutdownExecutors();
+ }
+ }
+ }
+
+ @Override
+ public final void shutdownNow() throws IOException {
+ shutdown.set(true);
+ synchronized (shutdownNowLock) {
+ if (!terminateInitiated) {
+ terminateInitiated = true;
+ closeAllChannels();
+ shutdownHandlerTasks();
+ shutdownExecutors();
+ }
+ }
+ }
+
+ /**
+ * For use by AsynchronousFileChannel to release resources without shutting
+ * down the thread pool.
+ */
+ final void detachFromThreadPool() {
+ if (shutdown.getAndSet(true))
+ throw new AssertionError("Already shutdown");
+ if (!isEmpty())
+ throw new AssertionError("Group not empty");
+ shutdownHandlerTasks();
+ }
+
+ @Override
+ public final boolean awaitTermination(long timeout, TimeUnit unit)
+ throws InterruptedException
+ {
+ return pool.executor().awaitTermination(timeout, unit);
+ }
+
+ /**
+ * Executes the given command on one of the channel group's pooled threads.
+ */
+ @Override
+ public final void execute(Runnable task) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ // when a security manager is installed then the user's task
+ // must be run with the current calling context
+ final AccessControlContext acc = AccessController.getContext();
+ final Runnable delegate = task;
+ task = new Runnable() {
+ @Override
+ public void run() {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ @Override
+ public Void run() {
+ delegate.run();
+ return null;
+ }
+ }, acc);
+ }
+ };
+ }
+ executeOnPooledThread(task);
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
new file mode 100755
index 0000000..d852b36
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/AsynchronousServerSocketChannelImpl.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.net.SocketAddress;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.net.InetSocketAddress;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.concurrent.Future;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import sun.net.NetHooks;
+
+/**
+ * Base implementation of AsynchronousServerSocketChannel.
+ */
+
+abstract class AsynchronousServerSocketChannelImpl
+ extends AsynchronousServerSocketChannel
+ implements Cancellable, Groupable
+{
+ protected final FileDescriptor fd;
+
+ // the local address to which the channel's socket is bound
+ protected volatile InetSocketAddress localAddress = null;
+
+ // need this lock to set local address
+ private final Object stateLock = new Object();
+
+ // close support
+ private ReadWriteLock closeLock = new ReentrantReadWriteLock();
+ private volatile boolean open = true;
+
+ // set true when accept operation is cancelled
+ private volatile boolean acceptKilled;
+
+ // set true when exclusive binding is on and SO_REUSEADDR is emulated
+ private boolean isReuseAddress;
+
+ AsynchronousServerSocketChannelImpl(AsynchronousChannelGroupImpl group) {
+ super(group.provider());
+ this.fd = Net.serverSocket(true);
+ }
+
+ @Override
+ public final boolean isOpen() {
+ return open;
+ }
+
+ /**
+ * Marks beginning of access to file descriptor/handle
+ */
+ final void begin() throws IOException {
+ closeLock.readLock().lock();
+ if (!isOpen())
+ throw new ClosedChannelException();
+ }
+
+ /**
+ * Marks end of access to file descriptor/handle
+ */
+ final void end() {
+ closeLock.readLock().unlock();
+ }
+
+ /**
+ * Invoked to close file descriptor/handle.
+ */
+ abstract void implClose() throws IOException;
+
+ @Override
+ public final void close() throws IOException {
+ // synchronize with any threads using file descriptor/handle
+ closeLock.writeLock().lock();
+ try {
+ if (!open)
+ return; // already closed
+ open = false;
+ } finally {
+ closeLock.writeLock().unlock();
+ }
+ implClose();
+ }
+
+ /**
+ * Invoked by accept to accept connection
+ */
+ abstract Future<AsynchronousSocketChannel>
+ implAccept(Object attachment,
+ CompletionHandler<AsynchronousSocketChannel,Object> handler);
+
+
+ @Override
+ public final Future<AsynchronousSocketChannel> accept() {
+ return implAccept(null, null);
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final <A> void accept(A attachment,
+ CompletionHandler<AsynchronousSocketChannel,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ implAccept(attachment, (CompletionHandler<AsynchronousSocketChannel,Object>)handler);
+ }
+
+ final boolean isAcceptKilled() {
+ return acceptKilled;
+ }
+
+ @Override
+ public final void onCancel(PendingFuture<?,?> task) {
+ acceptKilled = true;
+ }
+
+ @Override
+ public final AsynchronousServerSocketChannel bind(SocketAddress local, int backlog)
+ throws IOException
+ {
+ InetSocketAddress isa = (local == null) ? new InetSocketAddress(0) :
+ Net.checkAddress(local);
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkListen(isa.getPort());
+
+ try {
+ begin();
+ synchronized (stateLock) {
+ if (localAddress != null)
+ throw new AlreadyBoundException();
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
+ Net.bind(fd, isa.getAddress(), isa.getPort());
+ Net.listen(fd, backlog < 1 ? 50 : backlog);
+ localAddress = Net.localAddress(fd);
+ }
+ } finally {
+ end();
+ }
+ return this;
+ }
+
+ @Override
+ public final SocketAddress getLocalAddress() throws IOException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ return Net.getRevealedLocalAddress(localAddress);
+ }
+
+ @Override
+ public final <T> AsynchronousServerSocketChannel setOption(SocketOption<T> name,
+ T value)
+ throws IOException
+ {
+ if (name == null)
+ throw new NullPointerException();
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ try {
+ begin();
+ if (name == StandardSocketOptions.SO_REUSEADDR &&
+ Net.useExclusiveBind())
+ {
+ // SO_REUSEADDR emulated when using exclusive bind
+ isReuseAddress = (Boolean)value;
+ } else {
+ Net.setSocketOption(fd, Net.UNSPEC, name, value);
+ }
+ return this;
+ } finally {
+ end();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final <T> T getOption(SocketOption<T> name) throws IOException {
+ if (name == null)
+ throw new NullPointerException();
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ try {
+ begin();
+ if (name == StandardSocketOptions.SO_REUSEADDR &&
+ Net.useExclusiveBind())
+ {
+ // SO_REUSEADDR emulated when using exclusive bind
+ return (T)Boolean.valueOf(isReuseAddress);
+ }
+ return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+ } finally {
+ end();
+ }
+ }
+
+ private static class DefaultOptionsHolder {
+ static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+ private static Set<SocketOption<?>> defaultOptions() {
+ HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(2);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ @Override
+ public final Set<SocketOption<?>> supportedOptions() {
+ return DefaultOptionsHolder.defaultOptions;
+ }
+
+ @Override
+ public final String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getName());
+ sb.append('[');
+ if (!isOpen())
+ sb.append("closed");
+ else {
+ if (localAddress == null) {
+ sb.append("unbound");
+ } else {
+ sb.append(Net.getRevealedLocalAddressAsString(localAddress));
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java
new file mode 100755
index 0000000..af20709
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java
@@ -0,0 +1,597 @@
+/*
+ * Copyright (c) 2008, 2010, 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 sun.nio.ch;
+
+import java.nio.ByteBuffer;
+import java.nio.channels.*;
+import java.net.SocketOption;
+import java.net.StandardSocketOptions;
+import java.net.SocketAddress;
+import java.net.InetSocketAddress;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Collections;
+import java.util.concurrent.*;
+import java.util.concurrent.locks.*;
+import sun.net.NetHooks;
+
+/**
+ * Base implementation of AsynchronousSocketChannel
+ */
+
+abstract class AsynchronousSocketChannelImpl
+ extends AsynchronousSocketChannel
+ implements Cancellable, Groupable
+{
+ protected final FileDescriptor fd;
+
+ // protects state, localAddress, and remoteAddress
+ protected final Object stateLock = new Object();
+
+ protected volatile InetSocketAddress localAddress = null;
+ protected volatile InetSocketAddress remoteAddress = null;
+
+ // State, increases monotonically
+ static final int ST_UNINITIALIZED = -1;
+ static final int ST_UNCONNECTED = 0;
+ static final int ST_PENDING = 1;
+ static final int ST_CONNECTED = 2;
+ protected volatile int state = ST_UNINITIALIZED;
+
+ // reading state
+ private final Object readLock = new Object();
+ private boolean reading;
+ private boolean readShutdown;
+ private boolean readKilled; // further reading disallowed due to timeout
+
+ // writing state
+ private final Object writeLock = new Object();
+ private boolean writing;
+ private boolean writeShutdown;
+ private boolean writeKilled; // further writing disallowed due to timeout
+
+ // close support
+ private final ReadWriteLock closeLock = new ReentrantReadWriteLock();
+ private volatile boolean open = true;
+
+ // set true when exclusive binding is on and SO_REUSEADDR is emulated
+ private boolean isReuseAddress;
+
+ AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group)
+ throws IOException
+ {
+ super(group.provider());
+ this.fd = Net.socket(true);
+ this.state = ST_UNCONNECTED;
+ }
+
+ // Constructor for sockets obtained from AsynchronousServerSocketChannelImpl
+ AsynchronousSocketChannelImpl(AsynchronousChannelGroupImpl group,
+ FileDescriptor fd,
+ InetSocketAddress remote)
+ throws IOException
+ {
+ super(group.provider());
+ this.fd = fd;
+ this.state = ST_CONNECTED;
+ this.localAddress = Net.localAddress(fd);
+ this.remoteAddress = remote;
+ }
+
+ @Override
+ public final boolean isOpen() {
+ return open;
+ }
+
+ /**
+ * Marks beginning of access to file descriptor/handle
+ */
+ final void begin() throws IOException {
+ closeLock.readLock().lock();
+ if (!isOpen())
+ throw new ClosedChannelException();
+ }
+
+ /**
+ * Marks end of access to file descriptor/handle
+ */
+ final void end() {
+ closeLock.readLock().unlock();
+ }
+
+ /**
+ * Invoked to close socket and release other resources.
+ */
+ abstract void implClose() throws IOException;
+
+ @Override
+ public final void close() throws IOException {
+ // synchronize with any threads initiating asynchronous operations
+ closeLock.writeLock().lock();
+ try {
+ if (!open)
+ return; // already closed
+ open = false;
+ } finally {
+ closeLock.writeLock().unlock();
+ }
+ implClose();
+ }
+
+ final void enableReading(boolean killed) {
+ synchronized (readLock) {
+ reading = false;
+ if (killed)
+ readKilled = true;
+ }
+ }
+
+ final void enableReading() {
+ enableReading(false);
+ }
+
+ final void enableWriting(boolean killed) {
+ synchronized (writeLock) {
+ writing = false;
+ if (killed)
+ writeKilled = true;
+ }
+ }
+
+ final void enableWriting() {
+ enableWriting(false);
+ }
+
+ final void killReading() {
+ synchronized (readLock) {
+ readKilled = true;
+ }
+ }
+
+ final void killWriting() {
+ synchronized (writeLock) {
+ writeKilled = true;
+ }
+ }
+
+ final void killConnect() {
+ // when a connect is cancelled then the connection may have been
+ // established so prevent reading or writing.
+ killReading();
+ killWriting();
+ }
+
+ /**
+ * Invoked by connect to initiate the connect operation.
+ */
+ abstract <A> Future<Void> implConnect(SocketAddress remote,
+ A attachment,
+ CompletionHandler<Void,? super A> handler);
+
+ @Override
+ public final Future<Void> connect(SocketAddress remote) {
+ return implConnect(remote, null, null);
+ }
+
+ @Override
+ public final <A> void connect(SocketAddress remote,
+ A attachment,
+ CompletionHandler<Void,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ implConnect(remote, attachment, handler);
+ }
+
+ /**
+ * Invoked by read to initiate the I/O operation.
+ */
+ abstract <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
+ ByteBuffer dst,
+ ByteBuffer[] dsts,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<V,? super A> handler);
+
+ @SuppressWarnings("unchecked")
+ private <V extends Number,A> Future<V> read(boolean isScatteringRead,
+ ByteBuffer dst,
+ ByteBuffer[] dsts,
+ long timeout,
+ TimeUnit unit,
+ A att,
+ CompletionHandler<V,? super A> handler)
+ {
+ if (!isOpen()) {
+ Throwable e = new ClosedChannelException();
+ if (handler == null)
+ return CompletedFuture.withFailure(e);
+ Invoker.invoke(this, handler, att, null, e);
+ return null;
+ }
+
+ if (remoteAddress == null)
+ throw new NotYetConnectedException();
+
+ boolean hasSpaceToRead = isScatteringRead || dst.hasRemaining();
+ boolean shutdown = false;
+
+ // check and update state
+ synchronized (readLock) {
+ if (readKilled)
+ throw new IllegalStateException("Reading not allowed due to timeout or cancellation");
+ if (reading)
+ throw new ReadPendingException();
+ if (readShutdown) {
+ shutdown = true;
+ } else {
+ if (hasSpaceToRead) {
+ reading = true;
+ }
+ }
+ }
+
+ // immediately complete with -1 if shutdown for read
+ // immediately complete with 0 if no space remaining
+ if (shutdown || !hasSpaceToRead) {
+ Number result;
+ if (isScatteringRead) {
+ result = (shutdown) ? Long.valueOf(-1L) : Long.valueOf(0L);
+ } else {
+ result = (shutdown) ? -1 : 0;
+ }
+ if (handler == null)
+ return CompletedFuture.withResult((V)result);
+ Invoker.invoke(this, handler, att, (V)result, null);
+ return null;
+ }
+
+ return implRead(isScatteringRead, dst, dsts, timeout, unit, att, handler);
+ }
+
+ @Override
+ public final Future<Integer> read(ByteBuffer dst) {
+ if (dst.isReadOnly())
+ throw new IllegalArgumentException("Read-only buffer");
+ return read(false, dst, null, 0L, TimeUnit.MILLISECONDS, null, null);
+ }
+
+ @Override
+ public final <A> void read(ByteBuffer dst,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ if (dst.isReadOnly())
+ throw new IllegalArgumentException("Read-only buffer");
+ read(false, dst, null, timeout, unit, attachment, handler);
+ }
+
+ @Override
+ public final <A> void read(ByteBuffer[] dsts,
+ int offset,
+ int length,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Long,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ if ((offset < 0) || (length < 0) || (offset > dsts.length - length))
+ throw new IndexOutOfBoundsException();
+ ByteBuffer[] bufs = Util.subsequence(dsts, offset, length);
+ for (int i=0; i<bufs.length; i++) {
+ if (bufs[i].isReadOnly())
+ throw new IllegalArgumentException("Read-only buffer");
+ }
+ read(true, null, bufs, timeout, unit, attachment, handler);
+ }
+
+ /**
+ * Invoked by write to initiate the I/O operation.
+ */
+ abstract <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
+ ByteBuffer src,
+ ByteBuffer[] srcs,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<V,? super A> handler);
+
+ @SuppressWarnings("unchecked")
+ private <V extends Number,A> Future<V> write(boolean isGatheringWrite,
+ ByteBuffer src,
+ ByteBuffer[] srcs,
+ long timeout,
+ TimeUnit unit,
+ A att,
+ CompletionHandler<V,? super A> handler)
+ {
+ boolean hasDataToWrite = isGatheringWrite || src.hasRemaining();
+
+ boolean closed = false;
+ if (isOpen()) {
+ if (remoteAddress == null)
+ throw new NotYetConnectedException();
+ // check and update state
+ synchronized (writeLock) {
+ if (writeKilled)
+ throw new IllegalStateException("Writing not allowed due to timeout or cancellation");
+ if (writing)
+ throw new WritePendingException();
+ if (writeShutdown) {
+ closed = true;
+ } else {
+ if (hasDataToWrite)
+ writing = true;
+ }
+ }
+ } else {
+ closed = true;
+ }
+
+ // channel is closed or shutdown for write
+ if (closed) {
+ Throwable e = new ClosedChannelException();
+ if (handler == null)
+ return CompletedFuture.withFailure(e);
+ Invoker.invoke(this, handler, att, null, e);
+ return null;
+ }
+
+ // nothing to write so complete immediately
+ if (!hasDataToWrite) {
+ Number result = (isGatheringWrite) ? (Number)0L : (Number)0;
+ if (handler == null)
+ return CompletedFuture.withResult((V)result);
+ Invoker.invoke(this, handler, att, (V)result, null);
+ return null;
+ }
+
+ return implWrite(isGatheringWrite, src, srcs, timeout, unit, att, handler);
+ }
+
+ @Override
+ public final Future<Integer> write(ByteBuffer src) {
+ return write(false, src, null, 0L, TimeUnit.MILLISECONDS, null, null);
+ }
+
+ @Override
+ public final <A> void write(ByteBuffer src,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Integer,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ write(false, src, null, timeout, unit, attachment, handler);
+ }
+
+ @Override
+ public final <A> void write(ByteBuffer[] srcs,
+ int offset,
+ int length,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<Long,? super A> handler)
+ {
+ if (handler == null)
+ throw new NullPointerException("'handler' is null");
+ if ((offset < 0) || (length < 0) || (offset > srcs.length - length))
+ throw new IndexOutOfBoundsException();
+ srcs = Util.subsequence(srcs, offset, length);
+ write(true, null, srcs, timeout, unit, attachment, handler);
+ }
+
+ @Override
+ public final AsynchronousSocketChannel bind(SocketAddress local)
+ throws IOException
+ {
+ try {
+ begin();
+ synchronized (stateLock) {
+ if (state == ST_PENDING)
+ throw new ConnectionPendingException();
+ if (localAddress != null)
+ throw new AlreadyBoundException();
+ InetSocketAddress isa = (local == null) ?
+ new InetSocketAddress(0) : Net.checkAddress(local);
+ NetHooks.beforeTcpBind(fd, isa.getAddress(), isa.getPort());
+ Net.bind(fd, isa.getAddress(), isa.getPort());
+ localAddress = Net.localAddress(fd);
+ }
+ } finally {
+ end();
+ }
+ return this;
+ }
+
+ @Override
+ public final SocketAddress getLocalAddress() throws IOException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ return Net.getRevealedLocalAddress(localAddress);
+ }
+
+ @Override
+ public final <T> AsynchronousSocketChannel setOption(SocketOption<T> name, T value)
+ throws IOException
+ {
+ if (name == null)
+ throw new NullPointerException();
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ try {
+ begin();
+ if (writeShutdown)
+ throw new IOException("Connection has been shutdown for writing");
+ if (name == StandardSocketOptions.SO_REUSEADDR &&
+ Net.useExclusiveBind())
+ {
+ // SO_REUSEADDR emulated when using exclusive bind
+ isReuseAddress = (Boolean)value;
+ } else {
+ Net.setSocketOption(fd, Net.UNSPEC, name, value);
+ }
+ return this;
+ } finally {
+ end();
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public final <T> T getOption(SocketOption<T> name) throws IOException {
+ if (name == null)
+ throw new NullPointerException();
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ try {
+ begin();
+ if (name == StandardSocketOptions.SO_REUSEADDR &&
+ Net.useExclusiveBind())
+ {
+ // SO_REUSEADDR emulated when using exclusive bind
+ return (T)Boolean.valueOf(isReuseAddress);
+ }
+ return (T) Net.getSocketOption(fd, Net.UNSPEC, name);
+ } finally {
+ end();
+ }
+ }
+
+ private static class DefaultOptionsHolder {
+ static final Set<SocketOption<?>> defaultOptions = defaultOptions();
+
+ private static Set<SocketOption<?>> defaultOptions() {
+ HashSet<SocketOption<?>> set = new HashSet<SocketOption<?>>(5);
+ set.add(StandardSocketOptions.SO_SNDBUF);
+ set.add(StandardSocketOptions.SO_RCVBUF);
+ set.add(StandardSocketOptions.SO_KEEPALIVE);
+ set.add(StandardSocketOptions.SO_REUSEADDR);
+ set.add(StandardSocketOptions.TCP_NODELAY);
+ return Collections.unmodifiableSet(set);
+ }
+ }
+
+ @Override
+ public final Set<SocketOption<?>> supportedOptions() {
+ return DefaultOptionsHolder.defaultOptions;
+ }
+
+ @Override
+ public final SocketAddress getRemoteAddress() throws IOException {
+ if (!isOpen())
+ throw new ClosedChannelException();
+ return remoteAddress;
+ }
+
+ @Override
+ public final AsynchronousSocketChannel shutdownInput() throws IOException {
+ try {
+ begin();
+ if (remoteAddress == null)
+ throw new NotYetConnectedException();
+ synchronized (readLock) {
+ if (!readShutdown) {
+ Net.shutdown(fd, Net.SHUT_RD);
+ readShutdown = true;
+ }
+ }
+ } finally {
+ end();
+ }
+ return this;
+ }
+
+ @Override
+ public final AsynchronousSocketChannel shutdownOutput() throws IOException {
+ try {
+ begin();
+ if (remoteAddress == null)
+ throw new NotYetConnectedException();
+ synchronized (writeLock) {
+ if (!writeShutdown) {
+ Net.shutdown(fd, Net.SHUT_WR);
+ writeShutdown = true;
+ }
+ }
+ } finally {
+ end();
+ }
+ return this;
+ }
+
+ @Override
+ public final String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(this.getClass().getName());
+ sb.append('[');
+ synchronized (stateLock) {
+ if (!isOpen()) {
+ sb.append("closed");
+ } else {
+ switch (state) {
+ case ST_UNCONNECTED:
+ sb.append("unconnected");
+ break;
+ case ST_PENDING:
+ sb.append("connection-pending");
+ break;
+ case ST_CONNECTED:
+ sb.append("connected");
+ if (readShutdown)
+ sb.append(" ishut");
+ if (writeShutdown)
+ sb.append(" oshut");
+ break;
+ }
+ if (localAddress != null) {
+ sb.append(" local=");
+ sb.append(
+ Net.getRevealedLocalAddressAsString(localAddress));
+ }
+ if (remoteAddress != null) {
+ sb.append(" remote=");
+ sb.append(remoteAddress.toString());
+ }
+ }
+ }
+ sb.append(']');
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/BsdAsynchronousChannelProvider.java b/ojluni/src/main/java/sun/nio/ch/BsdAsynchronousChannelProvider.java
new file mode 100755
index 0000000..a732c11
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/BsdAsynchronousChannelProvider.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2012, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.io.IOException;
+
+public class BsdAsynchronousChannelProvider
+ extends AsynchronousChannelProvider
+{
+ private static volatile KQueuePort defaultPort;
+
+ private KQueuePort defaultEventPort() throws IOException {
+ if (defaultPort == null) {
+ synchronized (BsdAsynchronousChannelProvider.class) {
+ if (defaultPort == null) {
+ defaultPort = new KQueuePort(this, ThreadPool.getDefault()).start();
+ }
+ }
+ }
+ return defaultPort;
+ }
+
+ public BsdAsynchronousChannelProvider() {
+ }
+
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+ throws IOException
+ {
+ return new KQueuePort(this, ThreadPool.create(nThreads, factory)).start();
+ }
+
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+ throws IOException
+ {
+ return new KQueuePort(this, ThreadPool.wrap(executor, initialSize)).start();
+ }
+
+ private Port toPort(AsynchronousChannelGroup group) throws IOException {
+ if (group == null) {
+ return defaultEventPort();
+ } else {
+ if (!(group instanceof KQueuePort))
+ throw new IllegalChannelGroupException();
+ return (Port)group;
+ }
+ }
+
+ @Override
+ public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
+ }
+
+ @Override
+ public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ return new UnixAsynchronousSocketChannelImpl(toPort(group));
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/Cancellable.java b/ojluni/src/main/java/sun/nio/ch/Cancellable.java
new file mode 100755
index 0000000..9a84a63
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/Cancellable.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+/**
+ * Implemented by asynchronous channels that require notification when an I/O
+ * operation is cancelled.
+ */
+
+interface Cancellable {
+ /**
+ * Invoked to notify channel that cancel has been invoked while holding
+ * the Future's lock.
+ */
+ void onCancel(PendingFuture<?,?> task);
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
index 7da4bc86..e4d24a5 100755
--- a/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java
@@ -96,6 +96,9 @@
// Our socket adaptor, if any
private DatagramSocket socket;
+ // Multicast support
+ private MembershipRegistry registry;
+
// set true when socket is bound and SO_REUSEADDRESS is emulated
private boolean reuseAddressEmulated;
@@ -165,6 +168,7 @@
}
}
+ @Override
public SocketAddress getLocalAddress() throws IOException {
synchronized (stateLock) {
if (!isOpen())
@@ -242,6 +246,7 @@
}
}
+ @Override
@SuppressWarnings("unchecked")
public <T> T getOption(SocketOption<T> name)
throws IOException
@@ -320,6 +325,7 @@
}
}
+ @Override
public final Set<SocketOption<?>> supportedOptions() {
return DefaultOptionsHolder.defaultOptions;
}
@@ -787,12 +793,228 @@
return this;
}
+ /**
+ * Joins channel's socket to the given group/interface and
+ * optional source address.
+ */
+ private MembershipKey innerJoin(InetAddress group,
+ NetworkInterface interf,
+ InetAddress source)
+ throws IOException
+ {
+ if (!group.isMulticastAddress())
+ throw new IllegalArgumentException("Group not a multicast address");
+
+ // check multicast address is compatible with this socket
+ if (group instanceof Inet4Address) {
+ if (family == StandardProtocolFamily.INET6 && !Net.canIPv6SocketJoinIPv4Group())
+ throw new IllegalArgumentException("IPv6 socket cannot join IPv4 multicast group");
+ } else if (group instanceof Inet6Address) {
+ if (family != StandardProtocolFamily.INET6)
+ throw new IllegalArgumentException("Only IPv6 sockets can join IPv6 multicast group");
+ } else {
+ throw new IllegalArgumentException("Address type not supported");
+ }
+
+ // check source address
+ if (source != null) {
+ if (source.isAnyLocalAddress())
+ throw new IllegalArgumentException("Source address is a wildcard address");
+ if (source.isMulticastAddress())
+ throw new IllegalArgumentException("Source address is multicast address");
+ if (source.getClass() != group.getClass())
+ throw new IllegalArgumentException("Source address is different type to group");
+ }
+
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkMulticast(group);
+
+ synchronized (stateLock) {
+ if (!isOpen())
+ throw new ClosedChannelException();
+
+ // check the registry to see if we are already a member of the group
+ if (registry == null) {
+ registry = new MembershipRegistry();
+ } else {
+ // return existing membership key
+ MembershipKey key = registry.checkMembership(group, interf, source);
+ if (key != null)
+ return key;
+ }
+
+ MembershipKeyImpl key;
+ if ((family == StandardProtocolFamily.INET6) &&
+ ((group instanceof Inet6Address) || Net.canJoin6WithIPv4Group()))
+ {
+ int index = interf.getIndex();
+ if (index == -1)
+ throw new IOException("Network interface cannot be identified");
+
+ // need multicast and source address as byte arrays
+ byte[] groupAddress = Net.inet6AsByteArray(group);
+ byte[] sourceAddress = (source == null) ? null :
+ Net.inet6AsByteArray(source);
+
+ // join the group
+ int n = Net.join6(fd, groupAddress, index, sourceAddress);
+ if (n == IOStatus.UNAVAILABLE)
+ throw new UnsupportedOperationException();
+
+ key = new MembershipKeyImpl.Type6(this, group, interf, source,
+ groupAddress, index, sourceAddress);
+
+ } else {
+ // need IPv4 address to identify interface
+ Inet4Address target = Net.anyInet4Address(interf);
+ if (target == null)
+ throw new IOException("Network interface not configured for IPv4");
+
+ int groupAddress = Net.inet4AsInt(group);
+ int targetAddress = Net.inet4AsInt(target);
+ int sourceAddress = (source == null) ? 0 : Net.inet4AsInt(source);
+
+ // join the group
+ int n = Net.join4(fd, groupAddress, targetAddress, sourceAddress);
+ if (n == IOStatus.UNAVAILABLE)
+ throw new UnsupportedOperationException();
+
+ key = new MembershipKeyImpl.Type4(this, group, interf, source,
+ groupAddress, targetAddress, sourceAddress);
+ }
+
+ registry.add(key);
+ return key;
+ }
+ }
+
+ @Override
+ public MembershipKey join(InetAddress group,
+ NetworkInterface interf)
+ throws IOException
+ {
+ return innerJoin(group, interf, null);
+ }
+
+ @Override
+ public MembershipKey join(InetAddress group,
+ NetworkInterface interf,
+ InetAddress source)
+ throws IOException
+ {
+ if (source == null)
+ throw new NullPointerException("source address is null");
+ return innerJoin(group, interf, source);
+ }
+
+ // package-private
+ void drop(MembershipKeyImpl key) {
+ assert key.channel() == this;
+
+ synchronized (stateLock) {
+ if (!key.isValid())
+ return;
+
+ try {
+ if (key instanceof MembershipKeyImpl.Type6) {
+ MembershipKeyImpl.Type6 key6 =
+ (MembershipKeyImpl.Type6)key;
+ Net.drop6(fd, key6.groupAddress(), key6.index(), key6.source());
+ } else {
+ MembershipKeyImpl.Type4 key4 = (MembershipKeyImpl.Type4)key;
+ Net.drop4(fd, key4.groupAddress(), key4.interfaceAddress(),
+ key4.source());
+ }
+ } catch (IOException ioe) {
+ // should not happen
+ throw new AssertionError(ioe);
+ }
+
+ key.invalidate();
+ registry.remove(key);
+ }
+ }
+
+ /**
+ * Block datagrams from given source if a memory to receive all
+ * datagrams.
+ */
+ void block(MembershipKeyImpl key, InetAddress source)
+ throws IOException
+ {
+ assert key.channel() == this;
+ assert key.sourceAddress() == null;
+
+ synchronized (stateLock) {
+ if (!key.isValid())
+ throw new IllegalStateException("key is no longer valid");
+ if (source.isAnyLocalAddress())
+ throw new IllegalArgumentException("Source address is a wildcard address");
+ if (source.isMulticastAddress())
+ throw new IllegalArgumentException("Source address is multicast address");
+ if (source.getClass() != key.group().getClass())
+ throw new IllegalArgumentException("Source address is different type to group");
+
+ int n;
+ if (key instanceof MembershipKeyImpl.Type6) {
+ MembershipKeyImpl.Type6 key6 =
+ (MembershipKeyImpl.Type6)key;
+ n = Net.block6(fd, key6.groupAddress(), key6.index(),
+ Net.inet6AsByteArray(source));
+ } else {
+ MembershipKeyImpl.Type4 key4 =
+ (MembershipKeyImpl.Type4)key;
+ n = Net.block4(fd, key4.groupAddress(), key4.interfaceAddress(),
+ Net.inet4AsInt(source));
+ }
+ if (n == IOStatus.UNAVAILABLE) {
+ // ancient kernel
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+
+ /**
+ * Unblock given source.
+ */
+ void unblock(MembershipKeyImpl key, InetAddress source) {
+ assert key.channel() == this;
+ assert key.sourceAddress() == null;
+
+ synchronized (stateLock) {
+ if (!key.isValid())
+ throw new IllegalStateException("key is no longer valid");
+
+ try {
+ if (key instanceof MembershipKeyImpl.Type6) {
+ MembershipKeyImpl.Type6 key6 =
+ (MembershipKeyImpl.Type6)key;
+ Net.unblock6(fd, key6.groupAddress(), key6.index(),
+ Net.inet6AsByteArray(source));
+ } else {
+ MembershipKeyImpl.Type4 key4 =
+ (MembershipKeyImpl.Type4)key;
+ Net.unblock4(fd, key4.groupAddress(), key4.interfaceAddress(),
+ Net.inet4AsInt(source));
+ }
+ } catch (IOException ioe) {
+ // should not happen
+ throw new AssertionError(ioe);
+ }
+ }
+ }
+
protected void implCloseSelectableChannel() throws IOException {
synchronized (stateLock) {
if (state != ST_KILLED)
nd.preClose(fd);
ResourceManager.afterUdpClose();
+ // if member of mulitcast group then invalidate all keys
+ if (registry != null)
+ registry.invalidateAll();
+
long th;
if ((th = readerThread) != 0)
NativeThread.signal(th);
diff --git a/ojluni/src/main/java/sun/nio/ch/DefaultAsynchronousChannelProvider.java b/ojluni/src/main/java/sun/nio/ch/DefaultAsynchronousChannelProvider.java
new file mode 100755
index 0000000..38dd74f
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/DefaultAsynchronousChannelProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2008, 2012, 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 sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.security.AccessController;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Creates this platform's default asynchronous channel provider
+ */
+
+public class DefaultAsynchronousChannelProvider {
+
+ /**
+ * Prevent instantiation.
+ */
+ private DefaultAsynchronousChannelProvider() { }
+
+ /**
+ * Returns the default AsynchronousChannelProvider.
+ */
+ public static AsynchronousChannelProvider create() {
+ String osname = AccessController
+ .doPrivileged(new GetPropertyAction("os.name"));
+ // Android-changed: We don't compile SolarisAsynchronousChannelProvider.
+ //
+ // if (osname.equals("SunOS"))
+ // return new SolarisAsynchronousChannelProvider();
+ if (osname.equals("Linux"))
+ return new LinuxAsynchronousChannelProvider();
+ if (osname.contains("OS X"))
+ return new BsdAsynchronousChannelProvider();
+ throw new InternalError("platform not recognized");
+ }
+
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/EPollPort.java b/ojluni/src/main/java/sun/nio/ch/EPollPort.java
new file mode 100755
index 0000000..6b496ca
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/EPollPort.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+import static sun.nio.ch.EPoll.*;
+
+/**
+ * AsynchronousChannelGroup implementation based on the Linux epoll facility.
+ */
+
+final class EPollPort
+ extends Port
+{
+ // maximum number of events to poll at a time
+ private static final int MAX_EPOLL_EVENTS = 512;
+
+ // errors
+ private static final int ENOENT = 2;
+
+ // epoll file descriptor
+ private final int epfd;
+
+ // true if epoll closed
+ private boolean closed;
+
+ // socket pair used for wakeup
+ private final int sp[];
+
+ // number of wakeups pending
+ private final AtomicInteger wakeupCount = new AtomicInteger();
+
+ // address of the poll array passed to epoll_wait
+ private final long address;
+
+ // encapsulates an event for a channel
+ static class Event {
+ final PollableChannel channel;
+ final int events;
+
+ Event(PollableChannel channel, int events) {
+ this.channel = channel;
+ this.events = events;
+ }
+
+ PollableChannel channel() { return channel; }
+ int events() { return events; }
+ }
+
+ // queue of events for cases that a polling thread dequeues more than one
+ // event
+ private final ArrayBlockingQueue<Event> queue;
+ private final Event NEED_TO_POLL = new Event(null, 0);
+ private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
+
+ EPollPort(AsynchronousChannelProvider provider, ThreadPool pool)
+ throws IOException
+ {
+ super(provider, pool);
+
+ // open epoll
+ this.epfd = epollCreate();
+
+ // create socket pair for wakeup mechanism
+ int[] sv = new int[2];
+ try {
+ socketpair(sv);
+ // register one end with epoll
+ epollCtl(epfd, EPOLL_CTL_ADD, sv[0], POLLIN);
+ } catch (IOException x) {
+ close0(epfd);
+ throw x;
+ }
+ this.sp = sv;
+
+ // allocate the poll array
+ this.address = allocatePollArray(MAX_EPOLL_EVENTS);
+
+ // create the queue and offer the special event to ensure that the first
+ // threads polls
+ this.queue = new ArrayBlockingQueue<Event>(MAX_EPOLL_EVENTS);
+ this.queue.offer(NEED_TO_POLL);
+ }
+
+ EPollPort start() {
+ startThreads(new EventHandlerTask());
+ return this;
+ }
+
+ /**
+ * Release all resources
+ */
+ private void implClose() {
+ synchronized (this) {
+ if (closed)
+ return;
+ closed = true;
+ }
+ freePollArray(address);
+ close0(sp[0]);
+ close0(sp[1]);
+ close0(epfd);
+ }
+
+ private void wakeup() {
+ if (wakeupCount.incrementAndGet() == 1) {
+ // write byte to socketpair to force wakeup
+ try {
+ interrupt(sp[1]);
+ } catch (IOException x) {
+ throw new AssertionError(x);
+ }
+ }
+ }
+
+ @Override
+ void executeOnHandlerTask(Runnable task) {
+ synchronized (this) {
+ if (closed)
+ throw new RejectedExecutionException();
+ offerTask(task);
+ wakeup();
+ }
+ }
+
+ @Override
+ void shutdownHandlerTasks() {
+ /*
+ * If no tasks are running then just release resources; otherwise
+ * write to the one end of the socketpair to wakeup any polling threads.
+ */
+ int nThreads = threadCount();
+ if (nThreads == 0) {
+ implClose();
+ } else {
+ // send interrupt to each thread
+ while (nThreads-- > 0) {
+ wakeup();
+ }
+ }
+ }
+
+ // invoke by clients to register a file descriptor
+ @Override
+ void startPoll(int fd, int events) {
+ // update events (or add to epoll on first usage)
+ int err = epollCtl(epfd, EPOLL_CTL_MOD, fd, (events | EPOLLONESHOT));
+ if (err == ENOENT)
+ err = epollCtl(epfd, EPOLL_CTL_ADD, fd, (events | EPOLLONESHOT));
+ if (err != 0)
+ throw new AssertionError(); // should not happen
+ }
+
+ /*
+ * Task to process events from epoll and dispatch to the channel's
+ * onEvent handler.
+ *
+ * Events are retreived from epoll in batch and offered to a BlockingQueue
+ * where they are consumed by handler threads. A special "NEED_TO_POLL"
+ * event is used to signal one consumer to re-poll when all events have
+ * been consumed.
+ */
+ private class EventHandlerTask implements Runnable {
+ private Event poll() throws IOException {
+ try {
+ for (;;) {
+ int n = epollWait(epfd, address, MAX_EPOLL_EVENTS);
+ /*
+ * 'n' events have been read. Here we map them to their
+ * corresponding channel in batch and queue n-1 so that
+ * they can be handled by other handler threads. The last
+ * event is handled by this thread (and so is not queued).
+ */
+ fdToChannelLock.readLock().lock();
+ try {
+ while (n-- > 0) {
+ long eventAddress = getEvent(address, n);
+ int fd = getDescriptor(eventAddress);
+
+ // wakeup
+ if (fd == sp[0]) {
+ if (wakeupCount.decrementAndGet() == 0) {
+ // no more wakeups so drain pipe
+ drain1(sp[0]);
+ }
+
+ // queue special event if there are more events
+ // to handle.
+ if (n > 0) {
+ queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
+ continue;
+ }
+ return EXECUTE_TASK_OR_SHUTDOWN;
+ }
+
+ PollableChannel channel = fdToChannel.get(fd);
+ if (channel != null) {
+ int events = getEvents(eventAddress);
+ Event ev = new Event(channel, events);
+
+ // n-1 events are queued; This thread handles
+ // the last one except for the wakeup
+ if (n > 0) {
+ queue.offer(ev);
+ } else {
+ return ev;
+ }
+ }
+ }
+ } finally {
+ fdToChannelLock.readLock().unlock();
+ }
+ }
+ } finally {
+ // to ensure that some thread will poll when all events have
+ // been consumed
+ queue.offer(NEED_TO_POLL);
+ }
+ }
+
+ public void run() {
+ Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+ Invoker.getGroupAndInvokeCount();
+ final boolean isPooledThread = (myGroupAndInvokeCount != null);
+ boolean replaceMe = false;
+ Event ev;
+ try {
+ for (;;) {
+ // reset invoke count
+ if (isPooledThread)
+ myGroupAndInvokeCount.resetInvokeCount();
+
+ try {
+ replaceMe = false;
+ ev = queue.take();
+
+ // no events and this thread has been "selected" to
+ // poll for more.
+ if (ev == NEED_TO_POLL) {
+ try {
+ ev = poll();
+ } catch (IOException x) {
+ x.printStackTrace();
+ return;
+ }
+ }
+ } catch (InterruptedException x) {
+ continue;
+ }
+
+ // handle wakeup to execute task or shutdown
+ if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
+ Runnable task = pollTask();
+ if (task == null) {
+ // shutdown request
+ return;
+ }
+ // run task (may throw error/exception)
+ replaceMe = true;
+ task.run();
+ continue;
+ }
+
+ // process event
+ try {
+ ev.channel().onEvent(ev.events(), isPooledThread);
+ } catch (Error x) {
+ replaceMe = true; throw x;
+ } catch (RuntimeException x) {
+ replaceMe = true; throw x;
+ }
+ }
+ } finally {
+ // last handler to exit when shutdown releases resources
+ int remaining = threadExit(this, replaceMe);
+ if (remaining == 0 && isShutdown()) {
+ implClose();
+ }
+ }
+ }
+ }
+
+ // -- Native methods --
+
+ private static native void socketpair(int[] sv) throws IOException;
+
+ private static native void interrupt(int fd) throws IOException;
+
+ private static native void drain1(int fd) throws IOException;
+
+ private static native void close0(int fd);
+
+ static {
+ Util.load();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java b/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
index aac539b..113f84b 100755
--- a/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
+++ b/ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java
@@ -159,7 +159,7 @@
if (closed)
throw new ClosedSelectorException();
SelChImpl ch = ski.channel;
- int fd = Integer.valueOf(ch.getFDVal());
+ Integer fd = Integer.valueOf(ch.getFDVal());
fdToKey.put(fd, ski);
pollWrapper.add(fd);
keys.add(ski);
diff --git a/ojluni/src/main/java/sun/nio/ch/Groupable.java b/ojluni/src/main/java/sun/nio/ch/Groupable.java
new file mode 100755
index 0000000..64d8958
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/Groupable.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+/**
+ * Implemented by asynchronous channels that can be associated with an
+ * asynchronous channel group.
+ */
+
+interface Groupable {
+ AsynchronousChannelGroupImpl group();
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/Invoker.java b/ojluni/src/main/java/sun/nio/ch/Invoker.java
new file mode 100755
index 0000000..e55db54
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/Invoker.java
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.security.AccessController;
+import sun.security.action.GetIntegerAction;
+
+/**
+ * Defines static methods to invoke a completion handler or arbitrary task.
+ */
+
+class Invoker {
+ private Invoker() { }
+
+ // maximum number of completion handlers that may be invoked on the current
+ // thread before it re-directs invocations to the thread pool. This helps
+ // avoid stack overflow and lessens the risk of starvation.
+ private static final int maxHandlerInvokeCount = AccessController.doPrivileged(
+ new GetIntegerAction("sun.nio.ch.maxCompletionHandlersOnStack", 16));
+
+ // Per-thread object with reference to channel group and a counter for
+ // the number of completion handlers invoked. This should be reset to 0
+ // when all completion handlers have completed.
+ static class GroupAndInvokeCount {
+ private final AsynchronousChannelGroupImpl group;
+ private int handlerInvokeCount;
+ GroupAndInvokeCount(AsynchronousChannelGroupImpl group) {
+ this.group = group;
+ }
+ AsynchronousChannelGroupImpl group() {
+ return group;
+ }
+ int invokeCount() {
+ return handlerInvokeCount;
+ }
+ void setInvokeCount(int value) {
+ handlerInvokeCount = value;
+ }
+ void resetInvokeCount() {
+ handlerInvokeCount = 0;
+ }
+ void incrementInvokeCount() {
+ handlerInvokeCount++;
+ }
+ }
+ private static final ThreadLocal<GroupAndInvokeCount> myGroupAndInvokeCount =
+ new ThreadLocal<GroupAndInvokeCount>() {
+ @Override protected GroupAndInvokeCount initialValue() {
+ return null;
+ }
+ };
+
+ /**
+ * Binds this thread to the given group
+ */
+ static void bindToGroup(AsynchronousChannelGroupImpl group) {
+ myGroupAndInvokeCount.set(new GroupAndInvokeCount(group));
+ }
+
+ /**
+ * Returns the GroupAndInvokeCount object for this thread.
+ */
+ static GroupAndInvokeCount getGroupAndInvokeCount() {
+ return myGroupAndInvokeCount.get();
+ }
+
+ /**
+ * Returns true if the current thread is in a channel group's thread pool
+ */
+ static boolean isBoundToAnyGroup() {
+ return myGroupAndInvokeCount.get() != null;
+ }
+
+ /**
+ * Returns true if the current thread is in the given channel's thread
+ * pool and we haven't exceeded the maximum number of handler frames on
+ * the stack.
+ */
+ static boolean mayInvokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
+ AsynchronousChannelGroupImpl group)
+ {
+ if ((myGroupAndInvokeCount != null) &&
+ (myGroupAndInvokeCount.group() == group) &&
+ (myGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Invoke handler without checking the thread identity or number of handlers
+ * on the thread stack.
+ */
+ static <V,A> void invokeUnchecked(CompletionHandler<V,? super A> handler,
+ A attachment,
+ V value,
+ Throwable exc)
+ {
+ if (exc == null) {
+ handler.completed(value, attachment);
+ } else {
+ handler.failed(exc, attachment);
+ }
+
+ // clear interrupt
+ Thread.interrupted();
+ }
+
+ /**
+ * Invoke handler assuming thread identity already checked
+ */
+ static <V,A> void invokeDirect(GroupAndInvokeCount myGroupAndInvokeCount,
+ CompletionHandler<V,? super A> handler,
+ A attachment,
+ V result,
+ Throwable exc)
+ {
+ myGroupAndInvokeCount.incrementInvokeCount();
+ Invoker.invokeUnchecked(handler, attachment, result, exc);
+ }
+
+ /**
+ * Invokes the handler. If the current thread is in the channel group's
+ * thread pool then the handler is invoked directly, otherwise it is
+ * invoked indirectly.
+ */
+ static <V,A> void invoke(AsynchronousChannel channel,
+ CompletionHandler<V,? super A> handler,
+ A attachment,
+ V result,
+ Throwable exc)
+ {
+ boolean invokeDirect = false;
+ boolean identityOkay = false;
+ GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
+ if (thisGroupAndInvokeCount != null) {
+ if ((thisGroupAndInvokeCount.group() == ((Groupable)channel).group()))
+ identityOkay = true;
+ if (identityOkay &&
+ (thisGroupAndInvokeCount.invokeCount() < maxHandlerInvokeCount))
+ {
+ // group match
+ invokeDirect = true;
+ }
+ }
+ if (invokeDirect) {
+ invokeDirect(thisGroupAndInvokeCount, handler, attachment, result, exc);
+ } else {
+ try {
+ invokeIndirectly(channel, handler, attachment, result, exc);
+ } catch (RejectedExecutionException ree) {
+ // channel group shutdown; fallback to invoking directly
+ // if the current thread has the right identity.
+ if (identityOkay) {
+ invokeDirect(thisGroupAndInvokeCount,
+ handler, attachment, result, exc);
+ } else {
+ throw new ShutdownChannelGroupException();
+ }
+ }
+ }
+ }
+
+ /**
+ * Invokes the handler indirectly via the channel group's thread pool.
+ */
+ static <V,A> void invokeIndirectly(AsynchronousChannel channel,
+ final CompletionHandler<V,? super A> handler,
+ final A attachment,
+ final V result,
+ final Throwable exc)
+ {
+ try {
+ ((Groupable)channel).group().executeOnPooledThread(new Runnable() {
+ public void run() {
+ GroupAndInvokeCount thisGroupAndInvokeCount =
+ myGroupAndInvokeCount.get();
+ if (thisGroupAndInvokeCount != null)
+ thisGroupAndInvokeCount.setInvokeCount(1);
+ invokeUnchecked(handler, attachment, result, exc);
+ }
+ });
+ } catch (RejectedExecutionException ree) {
+ throw new ShutdownChannelGroupException();
+ }
+ }
+
+ /**
+ * Invokes the handler "indirectly" in the given Executor
+ */
+ static <V,A> void invokeIndirectly(final CompletionHandler<V,? super A> handler,
+ final A attachment,
+ final V value,
+ final Throwable exc,
+ Executor executor)
+ {
+ try {
+ executor.execute(new Runnable() {
+ public void run() {
+ invokeUnchecked(handler, attachment, value, exc);
+ }
+ });
+ } catch (RejectedExecutionException ree) {
+ throw new ShutdownChannelGroupException();
+ }
+ }
+
+ /**
+ * Invokes the given task on the thread pool associated with the given
+ * channel. If the current thread is in the thread pool then the task is
+ * invoked directly.
+ */
+ static void invokeOnThreadInThreadPool(Groupable channel,
+ Runnable task)
+ {
+ boolean invokeDirect;
+ GroupAndInvokeCount thisGroupAndInvokeCount = myGroupAndInvokeCount.get();
+ AsynchronousChannelGroupImpl targetGroup = channel.group();
+ if (thisGroupAndInvokeCount == null) {
+ invokeDirect = false;
+ } else {
+ invokeDirect = (thisGroupAndInvokeCount.group == targetGroup);
+ }
+ try {
+ if (invokeDirect) {
+ task.run();
+ } else {
+ targetGroup.executeOnPooledThread(task);
+ }
+ } catch (RejectedExecutionException ree) {
+ throw new ShutdownChannelGroupException();
+ }
+ }
+
+ /**
+ * Invoke handler with completed result. This method does not check the
+ * thread identity or the number of handlers on the thread stack.
+ */
+ static <V,A> void invokeUnchecked(PendingFuture<V,A> future) {
+ assert future.isDone();
+ CompletionHandler<V,? super A> handler = future.handler();
+ if (handler != null) {
+ invokeUnchecked(handler,
+ future.attachment(),
+ future.value(),
+ future.exception());
+ }
+ }
+
+ /**
+ * Invoke handler with completed result. If the current thread is in the
+ * channel group's thread pool then the handler is invoked directly,
+ * otherwise it is invoked indirectly.
+ */
+ static <V,A> void invoke(PendingFuture<V,A> future) {
+ assert future.isDone();
+ CompletionHandler<V,? super A> handler = future.handler();
+ if (handler != null) {
+ invoke(future.channel(),
+ handler,
+ future.attachment(),
+ future.value(),
+ future.exception());
+ }
+ }
+
+ /**
+ * Invoke handler with completed result. The handler is invoked indirectly,
+ * via the channel group's thread pool.
+ */
+ static <V,A> void invokeIndirectly(PendingFuture<V,A> future) {
+ assert future.isDone();
+ CompletionHandler<V,? super A> handler = future.handler();
+ if (handler != null) {
+ invokeIndirectly(future.channel(),
+ handler,
+ future.attachment(),
+ future.value(),
+ future.exception());
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/KQueue.java b/ojluni/src/main/java/sun/nio/ch/KQueue.java
new file mode 100755
index 0000000..e3466e3
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/KQueue.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2012, 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 sun.nio.ch;
+
+import java.io.IOException;
+import sun.misc.Unsafe;
+
+/**
+ * Provides access to the BSD kqueue facility.
+ */
+
+class KQueue {
+ private KQueue() { }
+
+ private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+ /**
+ * struct kevent {
+ * uintptr_t ident; // identifier for this event, usually the fd
+ * int16_t filter; // filter for event
+ * uint16_t flags; // general flags
+ * uint32_t fflags; // filter-specific flags
+ * intptr_t data; // filter-specific data
+ * void *udata; // opaque user data identifier
+ * };
+ */
+ private static final int SIZEOF_KQUEUEEVENT = keventSize();
+ private static final int OFFSET_IDENT = identOffset();
+ private static final int OFFSET_FILTER = filterOffset();
+ private static final int OFFSET_FLAGS = flagsOffset();
+
+ // filters
+ static final int EVFILT_READ = -1;
+ static final int EVFILT_WRITE = -2;
+
+ // flags
+ static final int EV_ADD = 0x0001;
+ static final int EV_ONESHOT = 0x0010;
+ static final int EV_CLEAR = 0x0020;
+
+ /**
+ * Allocates a poll array to handle up to {@code count} events.
+ */
+ static long allocatePollArray(int count) {
+ return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT);
+ }
+
+ /**
+ * Free a poll array
+ */
+ static void freePollArray(long address) {
+ unsafe.freeMemory(address);
+ }
+
+ /**
+ * Returns kevent[i].
+ */
+ static long getEvent(long address, int i) {
+ return address + (SIZEOF_KQUEUEEVENT*i);
+ }
+
+ /**
+ * Returns the file descriptor from a kevent (assuming to be in ident field)
+ */
+ static int getDescriptor(long address) {
+ return unsafe.getInt(address + OFFSET_IDENT);
+ }
+
+ static int getFilter(long address) {
+ return unsafe.getShort(address + OFFSET_FILTER);
+ }
+
+ static int getFlags(long address) {
+ return unsafe.getShort(address + OFFSET_FLAGS);
+ }
+
+ // -- Native methods --
+
+ private static native int keventSize();
+
+ private static native int identOffset();
+
+ private static native int filterOffset();
+
+ private static native int flagsOffset();
+
+ static native int kqueue() throws IOException;
+
+ static native int keventRegister(int kqpfd, int fd, int filter, int flags);
+
+ static native int keventPoll(int kqpfd, long pollAddress, int nevents)
+ throws IOException;
+
+ static {
+ Util.load();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/KQueuePort.java b/ojluni/src/main/java/sun/nio/ch/KQueuePort.java
new file mode 100755
index 0000000..cd16e2e
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/KQueuePort.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2012, 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 sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.io.IOException;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicInteger;
+import static sun.nio.ch.KQueue.*;
+
+/**
+ * AsynchronousChannelGroup implementation based on the BSD kqueue facility.
+ */
+
+final class KQueuePort
+ extends Port
+{
+ // maximum number of events to poll at a time
+ private static final int MAX_KEVENTS_TO_POLL = 512;
+
+ // kqueue file descriptor
+ private final int kqfd;
+
+ // true if kqueue closed
+ private boolean closed;
+
+ // socket pair used for wakeup
+ private final int sp[];
+
+ // number of wakeups pending
+ private final AtomicInteger wakeupCount = new AtomicInteger();
+
+ // address of the poll array passed to kqueue_wait
+ private final long address;
+
+ // encapsulates an event for a channel
+ static class Event {
+ final PollableChannel channel;
+ final int events;
+
+ Event(PollableChannel channel, int events) {
+ this.channel = channel;
+ this.events = events;
+ }
+
+ PollableChannel channel() { return channel; }
+ int events() { return events; }
+ }
+
+ // queue of events for cases that a polling thread dequeues more than one
+ // event
+ private final ArrayBlockingQueue<Event> queue;
+ private final Event NEED_TO_POLL = new Event(null, 0);
+ private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0);
+
+ KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool)
+ throws IOException
+ {
+ super(provider, pool);
+
+ // open kqueue
+ this.kqfd = kqueue();
+
+ // create socket pair for wakeup mechanism
+ int[] sv = new int[2];
+ try {
+ socketpair(sv);
+
+ // register one end with kqueue
+ keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD);
+ } catch (IOException x) {
+ close0(kqfd);
+ throw x;
+ }
+ this.sp = sv;
+
+ // allocate the poll array
+ this.address = allocatePollArray(MAX_KEVENTS_TO_POLL);
+
+ // create the queue and offer the special event to ensure that the first
+ // threads polls
+ this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL);
+ this.queue.offer(NEED_TO_POLL);
+ }
+
+ KQueuePort start() {
+ startThreads(new EventHandlerTask());
+ return this;
+ }
+
+ /**
+ * Release all resources
+ */
+ private void implClose() {
+ synchronized (this) {
+ if (closed)
+ return;
+ closed = true;
+ }
+ freePollArray(address);
+ close0(sp[0]);
+ close0(sp[1]);
+ close0(kqfd);
+ }
+
+ private void wakeup() {
+ if (wakeupCount.incrementAndGet() == 1) {
+ // write byte to socketpair to force wakeup
+ try {
+ interrupt(sp[1]);
+ } catch (IOException x) {
+ throw new AssertionError(x);
+ }
+ }
+ }
+
+ @Override
+ void executeOnHandlerTask(Runnable task) {
+ synchronized (this) {
+ if (closed)
+ throw new RejectedExecutionException();
+ offerTask(task);
+ wakeup();
+ }
+ }
+
+ @Override
+ void shutdownHandlerTasks() {
+ /*
+ * If no tasks are running then just release resources; otherwise
+ * write to the one end of the socketpair to wakeup any polling threads.
+ */
+ int nThreads = threadCount();
+ if (nThreads == 0) {
+ implClose();
+ } else {
+ // send interrupt to each thread
+ while (nThreads-- > 0) {
+ wakeup();
+ }
+ }
+ }
+
+ // invoked by clients to register a file descriptor
+ @Override
+ void startPoll(int fd, int events) {
+ // We use a separate filter for read and write events.
+ // TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here.
+ int err = 0;
+ int flags = (EV_ADD|EV_ONESHOT);
+ if ((events & Port.POLLIN) > 0)
+ err = keventRegister(kqfd, fd, EVFILT_READ, flags);
+ if (err == 0 && (events & Port.POLLOUT) > 0)
+ err = keventRegister(kqfd, fd, EVFILT_WRITE, flags);
+ if (err != 0)
+ throw new InternalError("kevent failed: " + err); // should not happen
+ }
+
+ /*
+ * Task to process events from kqueue and dispatch to the channel's
+ * onEvent handler.
+ *
+ * Events are retreived from kqueue in batch and offered to a BlockingQueue
+ * where they are consumed by handler threads. A special "NEED_TO_POLL"
+ * event is used to signal one consumer to re-poll when all events have
+ * been consumed.
+ */
+ private class EventHandlerTask implements Runnable {
+ private Event poll() throws IOException {
+ try {
+ for (;;) {
+ int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL);
+ /*
+ * 'n' events have been read. Here we map them to their
+ * corresponding channel in batch and queue n-1 so that
+ * they can be handled by other handler threads. The last
+ * event is handled by this thread (and so is not queued).
+ */
+ fdToChannelLock.readLock().lock();
+ try {
+ while (n-- > 0) {
+ long keventAddress = getEvent(address, n);
+ int fd = getDescriptor(keventAddress);
+
+ // wakeup
+ if (fd == sp[0]) {
+ if (wakeupCount.decrementAndGet() == 0) {
+ // no more wakeups so drain pipe
+ drain1(sp[0]);
+ }
+
+ // queue special event if there are more events
+ // to handle.
+ if (n > 0) {
+ queue.offer(EXECUTE_TASK_OR_SHUTDOWN);
+ continue;
+ }
+ return EXECUTE_TASK_OR_SHUTDOWN;
+ }
+
+ PollableChannel channel = fdToChannel.get(fd);
+ if (channel != null) {
+ int filter = getFilter(keventAddress);
+ int events = 0;
+ if (filter == EVFILT_READ)
+ events = Port.POLLIN;
+ else if (filter == EVFILT_WRITE)
+ events = Port.POLLOUT;
+
+ Event ev = new Event(channel, events);
+
+ // n-1 events are queued; This thread handles
+ // the last one except for the wakeup
+ if (n > 0) {
+ queue.offer(ev);
+ } else {
+ return ev;
+ }
+ }
+ }
+ } finally {
+ fdToChannelLock.readLock().unlock();
+ }
+ }
+ } finally {
+ // to ensure that some thread will poll when all events have
+ // been consumed
+ queue.offer(NEED_TO_POLL);
+ }
+ }
+
+ public void run() {
+ Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+ Invoker.getGroupAndInvokeCount();
+ final boolean isPooledThread = (myGroupAndInvokeCount != null);
+ boolean replaceMe = false;
+ Event ev;
+ try {
+ for (;;) {
+ // reset invoke count
+ if (isPooledThread)
+ myGroupAndInvokeCount.resetInvokeCount();
+
+ try {
+ replaceMe = false;
+ ev = queue.take();
+
+ // no events and this thread has been "selected" to
+ // poll for more.
+ if (ev == NEED_TO_POLL) {
+ try {
+ ev = poll();
+ } catch (IOException x) {
+ x.printStackTrace();
+ return;
+ }
+ }
+ } catch (InterruptedException x) {
+ continue;
+ }
+
+ // handle wakeup to execute task or shutdown
+ if (ev == EXECUTE_TASK_OR_SHUTDOWN) {
+ Runnable task = pollTask();
+ if (task == null) {
+ // shutdown request
+ return;
+ }
+ // run task (may throw error/exception)
+ replaceMe = true;
+ task.run();
+ continue;
+ }
+
+ // process event
+ try {
+ ev.channel().onEvent(ev.events(), isPooledThread);
+ } catch (Error x) {
+ replaceMe = true; throw x;
+ } catch (RuntimeException x) {
+ replaceMe = true; throw x;
+ }
+ }
+ } finally {
+ // last handler to exit when shutdown releases resources
+ int remaining = threadExit(this, replaceMe);
+ if (remaining == 0 && isShutdown()) {
+ implClose();
+ }
+ }
+ }
+ }
+
+ // -- Native methods --
+
+ private static native void socketpair(int[] sv) throws IOException;
+
+ private static native void interrupt(int fd) throws IOException;
+
+ private static native void drain1(int fd) throws IOException;
+
+ private static native void close0(int fd);
+
+ static {
+ Util.load();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/LinuxAsynchronousChannelProvider.java b/ojluni/src/main/java/sun/nio/ch/LinuxAsynchronousChannelProvider.java
new file mode 100755
index 0000000..2fbe896
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/LinuxAsynchronousChannelProvider.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2008, 2010, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.io.IOException;
+
+public class LinuxAsynchronousChannelProvider
+ extends AsynchronousChannelProvider
+{
+ private static volatile EPollPort defaultPort;
+
+ private EPollPort defaultEventPort() throws IOException {
+ if (defaultPort == null) {
+ synchronized (LinuxAsynchronousChannelProvider.class) {
+ if (defaultPort == null) {
+ defaultPort = new EPollPort(this, ThreadPool.getDefault()).start();
+ }
+ }
+ }
+ return defaultPort;
+ }
+
+ public LinuxAsynchronousChannelProvider() {
+ }
+
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+ throws IOException
+ {
+ return new EPollPort(this, ThreadPool.create(nThreads, factory)).start();
+ }
+
+ @Override
+ public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+ throws IOException
+ {
+ return new EPollPort(this, ThreadPool.wrap(executor, initialSize)).start();
+ }
+
+ private Port toPort(AsynchronousChannelGroup group) throws IOException {
+ if (group == null) {
+ return defaultEventPort();
+ } else {
+ if (!(group instanceof EPollPort))
+ throw new IllegalChannelGroupException();
+ return (Port)group;
+ }
+ }
+
+ @Override
+ public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ return new UnixAsynchronousServerSocketChannelImpl(toPort(group));
+ }
+
+ @Override
+ public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+ throws IOException
+ {
+ return new UnixAsynchronousSocketChannelImpl(toPort(group));
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/MembershipKeyImpl.java b/ojluni/src/main/java/sun/nio/ch/MembershipKeyImpl.java
new file mode 100755
index 0000000..5ecc396
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/MembershipKeyImpl.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.io.IOException;
+import java.util.HashSet;
+
+/**
+ * MembershipKey implementation.
+ */
+
+class MembershipKeyImpl
+ extends MembershipKey
+{
+ private final MulticastChannel ch;
+ private final InetAddress group;
+ private final NetworkInterface interf;
+ private final InetAddress source;
+
+ // true when key is valid
+ private volatile boolean valid = true;
+
+ // lock used when creating or accessing blockedSet
+ private Object stateLock = new Object();
+
+ // set of source addresses that are blocked
+ private HashSet<InetAddress> blockedSet;
+
+ private MembershipKeyImpl(MulticastChannel ch,
+ InetAddress group,
+ NetworkInterface interf,
+ InetAddress source)
+ {
+ this.ch = ch;
+ this.group = group;
+ this.interf = interf;
+ this.source = source;
+ }
+
+ /**
+ * MembershipKey will additional context for IPv4 membership
+ */
+ static class Type4 extends MembershipKeyImpl {
+ private final int groupAddress;
+ private final int interfAddress;
+ private final int sourceAddress;
+
+ Type4(MulticastChannel ch,
+ InetAddress group,
+ NetworkInterface interf,
+ InetAddress source,
+ int groupAddress,
+ int interfAddress,
+ int sourceAddress)
+ {
+ super(ch, group, interf, source);
+ this.groupAddress = groupAddress;
+ this.interfAddress = interfAddress;
+ this.sourceAddress = sourceAddress;
+ }
+
+ int groupAddress() {
+ return groupAddress;
+ }
+
+ int interfaceAddress() {
+ return interfAddress;
+ }
+
+ int source() {
+ return sourceAddress;
+ }
+ }
+
+ /**
+ * MembershipKey will additional context for IPv6 membership
+ */
+ static class Type6 extends MembershipKeyImpl {
+ private final byte[] groupAddress;
+ private final int index;
+ private final byte[] sourceAddress;
+
+ Type6(MulticastChannel ch,
+ InetAddress group,
+ NetworkInterface interf,
+ InetAddress source,
+ byte[] groupAddress,
+ int index,
+ byte[] sourceAddress)
+ {
+ super(ch, group, interf, source);
+ this.groupAddress = groupAddress;
+ this.index = index;
+ this.sourceAddress = sourceAddress;
+ }
+
+ byte[] groupAddress() {
+ return groupAddress;
+ }
+
+ int index() {
+ return index;
+ }
+
+ byte[] source() {
+ return sourceAddress;
+ }
+ }
+
+ public boolean isValid() {
+ return valid;
+ }
+
+ // package-private
+ void invalidate() {
+ valid = false;
+ }
+
+ public void drop() {
+ // delegate to channel
+ ((DatagramChannelImpl)ch).drop(this);
+ }
+
+ @Override
+ public MulticastChannel channel() {
+ return ch;
+ }
+
+ @Override
+ public InetAddress group() {
+ return group;
+ }
+
+ @Override
+ public NetworkInterface networkInterface() {
+ return interf;
+ }
+
+ @Override
+ public InetAddress sourceAddress() {
+ return source;
+ }
+
+ @Override
+ public MembershipKey block(InetAddress toBlock)
+ throws IOException
+ {
+ if (source != null)
+ throw new IllegalStateException("key is source-specific");
+
+ synchronized (stateLock) {
+ if ((blockedSet != null) && blockedSet.contains(toBlock)) {
+ // already blocked, nothing to do
+ return this;
+ }
+
+ ((DatagramChannelImpl)ch).block(this, toBlock);
+
+ // created blocked set if required and add source address
+ if (blockedSet == null)
+ blockedSet = new HashSet<InetAddress>();
+ blockedSet.add(toBlock);
+ }
+ return this;
+ }
+
+ @Override
+ public MembershipKey unblock(InetAddress toUnblock) {
+ synchronized (stateLock) {
+ if ((blockedSet == null) || !blockedSet.contains(toUnblock))
+ throw new IllegalStateException("not blocked");
+
+ ((DatagramChannelImpl)ch).unblock(this, toUnblock);
+
+ blockedSet.remove(toUnblock);
+ }
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(64);
+ sb.append('<');
+ sb.append(group.getHostAddress());
+ sb.append(',');
+ sb.append(interf.getName());
+ if (source != null) {
+ sb.append(',');
+ sb.append(source.getHostAddress());
+ }
+ sb.append('>');
+ return sb.toString();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/MembershipRegistry.java b/ojluni/src/main/java/sun/nio/ch/MembershipRegistry.java
new file mode 100755
index 0000000..6607fc8
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/MembershipRegistry.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.util.*;
+
+/**
+ * Simple registry of membership keys for a MulticastChannel.
+ *
+ * Instances of this object are not safe by multiple concurrent threads.
+ */
+
+class MembershipRegistry {
+
+ // map multicast group to keys
+ private Map<InetAddress,List<MembershipKeyImpl>> groups = null;
+
+ MembershipRegistry() {
+ }
+
+ /**
+ * Checks registry for membership of the group on the given
+ * network interface.
+ */
+ MembershipKey checkMembership(InetAddress group, NetworkInterface interf,
+ InetAddress source)
+ {
+ if (groups != null) {
+ List<MembershipKeyImpl> keys = groups.get(group);
+ if (keys != null) {
+ for (MembershipKeyImpl key: keys) {
+ if (key.networkInterface().equals(interf)) {
+ // already a member to receive all packets so return
+ // existing key or detect conflict
+ if (source == null) {
+ if (key.sourceAddress() == null)
+ return key;
+ throw new IllegalStateException("Already a member to receive all packets");
+ }
+
+ // already have source-specific membership so return key
+ // or detect conflict
+ if (key.sourceAddress() == null)
+ throw new IllegalStateException("Already have source-specific membership");
+ if (source.equals(key.sourceAddress()))
+ return key;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Add membership to the registry, returning a new membership key.
+ */
+ void add(MembershipKeyImpl key) {
+ InetAddress group = key.group();
+ List<MembershipKeyImpl> keys;
+ if (groups == null) {
+ groups = new HashMap<InetAddress,List<MembershipKeyImpl>>();
+ keys = null;
+ } else {
+ keys = groups.get(group);
+ }
+ if (keys == null) {
+ keys = new LinkedList<MembershipKeyImpl>();
+ groups.put(group, keys);
+ }
+ keys.add(key);
+ }
+
+ /**
+ * Remove a key from the registry
+ */
+ void remove(MembershipKeyImpl key) {
+ InetAddress group = key.group();
+ List<MembershipKeyImpl> keys = groups.get(group);
+ if (keys != null) {
+ Iterator<MembershipKeyImpl> i = keys.iterator();
+ while (i.hasNext()) {
+ if (i.next() == key) {
+ i.remove();
+ break;
+ }
+ }
+ if (keys.isEmpty()) {
+ groups.remove(group);
+ }
+ }
+ }
+
+ /**
+ * Invalidate all keys in the registry
+ */
+ void invalidateAll() {
+ if (groups != null) {
+ for (InetAddress group: groups.keySet()) {
+ for (MembershipKeyImpl key: groups.get(group)) {
+ key.invalidate();
+ }
+ }
+ }
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/PendingFuture.java b/ojluni/src/main/java/sun/nio/ch/PendingFuture.java
new file mode 100755
index 0000000..863b0f0
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/PendingFuture.java
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+
+/**
+ * A Future for a pending I/O operation. A PendingFuture allows for the
+ * attachment of an additional arbitrary context object and a timer task.
+ */
+
+final class PendingFuture<V,A> implements Future<V> {
+ private static final CancellationException CANCELLED =
+ new CancellationException();
+
+ private final AsynchronousChannel channel;
+ private final CompletionHandler<V,? super A> handler;
+ private final A attachment;
+
+ // true if result (or exception) is available
+ private volatile boolean haveResult;
+ private volatile V result;
+ private volatile Throwable exc;
+
+ // latch for waiting (created lazily if needed)
+ private CountDownLatch latch;
+
+ // optional timer task that is cancelled when result becomes available
+ private Future<?> timeoutTask;
+
+ // optional context object
+ private volatile Object context;
+
+ PendingFuture(AsynchronousChannel channel,
+ CompletionHandler<V,? super A> handler,
+ A attachment,
+ Object context)
+ {
+ this.channel = channel;
+ this.handler = handler;
+ this.attachment = attachment;
+ this.context = context;
+ }
+
+ PendingFuture(AsynchronousChannel channel,
+ CompletionHandler<V,? super A> handler,
+ A attachment)
+ {
+ this.channel = channel;
+ this.handler = handler;
+ this.attachment = attachment;
+ }
+
+ PendingFuture(AsynchronousChannel channel) {
+ this(channel, null, null);
+ }
+
+ PendingFuture(AsynchronousChannel channel, Object context) {
+ this(channel, null, null, context);
+ }
+
+ AsynchronousChannel channel() {
+ return channel;
+ }
+
+ CompletionHandler<V,? super A> handler() {
+ return handler;
+ }
+
+ A attachment() {
+ return attachment;
+ }
+
+ void setContext(Object context) {
+ this.context = context;
+ }
+
+ Object getContext() {
+ return context;
+ }
+
+ void setTimeoutTask(Future<?> task) {
+ synchronized (this) {
+ if (haveResult) {
+ task.cancel(false);
+ } else {
+ this.timeoutTask = task;
+ }
+ }
+ }
+
+ // creates latch if required; return true if caller needs to wait
+ private boolean prepareForWait() {
+ synchronized (this) {
+ if (haveResult) {
+ return false;
+ } else {
+ if (latch == null)
+ latch = new CountDownLatch(1);
+ return true;
+ }
+ }
+ }
+
+ /**
+ * Sets the result, or a no-op if the result or exception is already set.
+ */
+ void setResult(V res) {
+ synchronized (this) {
+ if (haveResult)
+ return;
+ result = res;
+ haveResult = true;
+ if (timeoutTask != null)
+ timeoutTask.cancel(false);
+ if (latch != null)
+ latch.countDown();
+ }
+ }
+
+ /**
+ * Sets the result, or a no-op if the result or exception is already set.
+ */
+ void setFailure(Throwable x) {
+ if (!(x instanceof IOException) && !(x instanceof SecurityException))
+ x = new IOException(x);
+ synchronized (this) {
+ if (haveResult)
+ return;
+ exc = x;
+ haveResult = true;
+ if (timeoutTask != null)
+ timeoutTask.cancel(false);
+ if (latch != null)
+ latch.countDown();
+ }
+ }
+
+ /**
+ * Sets the result
+ */
+ void setResult(V res, Throwable x) {
+ if (x == null) {
+ setResult(res);
+ } else {
+ setFailure(x);
+ }
+ }
+
+ @Override
+ public V get() throws ExecutionException, InterruptedException {
+ if (!haveResult) {
+ boolean needToWait = prepareForWait();
+ if (needToWait)
+ latch.await();
+ }
+ if (exc != null) {
+ if (exc == CANCELLED)
+ throw new CancellationException();
+ throw new ExecutionException(exc);
+ }
+ return result;
+ }
+
+ @Override
+ public V get(long timeout, TimeUnit unit)
+ throws ExecutionException, InterruptedException, TimeoutException
+ {
+ if (!haveResult) {
+ boolean needToWait = prepareForWait();
+ if (needToWait)
+ if (!latch.await(timeout, unit)) throw new TimeoutException();
+ }
+ if (exc != null) {
+ if (exc == CANCELLED)
+ throw new CancellationException();
+ throw new ExecutionException(exc);
+ }
+ return result;
+ }
+
+ Throwable exception() {
+ return (exc != CANCELLED) ? exc : null;
+ }
+
+ V value() {
+ return result;
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return (exc == CANCELLED);
+ }
+
+ @Override
+ public boolean isDone() {
+ return haveResult;
+ }
+
+ @Override
+ public boolean cancel(boolean mayInterruptIfRunning) {
+ synchronized (this) {
+ if (haveResult)
+ return false; // already completed
+
+ // notify channel
+ if (channel() instanceof Cancellable)
+ ((Cancellable)channel()).onCancel(this);
+
+ // set result and cancel timer
+ exc = CANCELLED;
+ haveResult = true;
+ if (timeoutTask != null)
+ timeoutTask.cancel(false);
+ }
+
+ // close channel if forceful cancel
+ if (mayInterruptIfRunning) {
+ try {
+ channel().close();
+ } catch (IOException ignore) { }
+ }
+
+ // release waiters
+ if (latch != null)
+ latch.countDown();
+ return true;
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/Port.java b/ojluni/src/main/java/sun/nio/ch/Port.java
new file mode 100755
index 0000000..9402508
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/Port.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2008, 2009, 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 sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.nio.channels.*;
+import java.io.IOException;
+import java.io.Closeable;
+import java.io.FileDescriptor;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Base implementation of AsynchronousChannelGroupImpl for Unix systems.
+ */
+
+abstract class Port extends AsynchronousChannelGroupImpl {
+ static final short POLLIN = 0x0001;
+ static final short POLLOUT = 0x0004;
+ static final short POLLERR = 0x0008;
+ static final short POLLHUP = 0x0010;
+
+ /**
+ * Implemented by clients registered with this port.
+ */
+ interface PollableChannel extends Closeable {
+ void onEvent(int events, boolean mayInvokeDirect);
+ }
+
+ // maps fd to "pollable" channel
+ protected final ReadWriteLock fdToChannelLock = new ReentrantReadWriteLock();
+ protected final Map<Integer,PollableChannel> fdToChannel =
+ new HashMap<Integer,PollableChannel>();
+
+
+ Port(AsynchronousChannelProvider provider, ThreadPool pool) {
+ super(provider, pool);
+ }
+
+ /**
+ * Register channel identified by its file descriptor
+ */
+ final void register(int fd, PollableChannel ch) {
+ fdToChannelLock.writeLock().lock();
+ try {
+ if (isShutdown())
+ throw new ShutdownChannelGroupException();
+ fdToChannel.put(Integer.valueOf(fd), ch);
+ } finally {
+ fdToChannelLock.writeLock().unlock();
+ }
+ }
+
+ /**
+ * Unregister channel identified by its file descriptor
+ */
+ final void unregister(int fd) {
+ boolean checkForShutdown = false;
+
+ fdToChannelLock.writeLock().lock();
+ try {
+ fdToChannel.remove(Integer.valueOf(fd));
+
+ // last key to be removed so check if group is shutdown
+ if (fdToChannel.isEmpty())
+ checkForShutdown = true;
+
+ } finally {
+ fdToChannelLock.writeLock().unlock();
+ }
+
+ // continue shutdown
+ if (checkForShutdown && isShutdown()) {
+ try {
+ shutdownNow();
+ } catch (IOException ignore) { }
+ }
+ }
+ /**
+ * Register file descriptor with polling mechanism for given events.
+ * The implementation should translate the events as required.
+ */
+ abstract void startPoll(int fd, int events);
+
+ @Override
+ final boolean isEmpty() {
+ fdToChannelLock.writeLock().lock();
+ try {
+ return fdToChannel.isEmpty();
+ } finally {
+ fdToChannelLock.writeLock().unlock();
+ }
+ }
+
+ @Override
+ final Object attachForeignChannel(final Channel channel, FileDescriptor fd) {
+ int fdVal = IOUtil.fdVal(fd);
+ register(fdVal, new PollableChannel() {
+ public void onEvent(int events, boolean mayInvokeDirect) { }
+ public void close() throws IOException {
+ channel.close();
+ }
+ });
+ return Integer.valueOf(fdVal);
+ }
+
+ @Override
+ final void detachForeignChannel(Object key) {
+ unregister((Integer)key);
+ }
+
+ @Override
+ final void closeAllChannels() {
+ /**
+ * Close channels in batches of up to 128 channels. This allows close
+ * to remove the channel from the map without interference.
+ */
+ final int MAX_BATCH_SIZE = 128;
+ PollableChannel channels[] = new PollableChannel[MAX_BATCH_SIZE];
+ int count;
+ do {
+ // grab a batch of up to 128 channels
+ fdToChannelLock.writeLock().lock();
+ count = 0;
+ try {
+ for (Integer fd: fdToChannel.keySet()) {
+ channels[count++] = fdToChannel.get(fd);
+ if (count >= MAX_BATCH_SIZE)
+ break;
+ }
+ } finally {
+ fdToChannelLock.writeLock().unlock();
+ }
+
+ // close them
+ for (int i=0; i<count; i++) {
+ try {
+ channels[i].close();
+ } catch (IOException ignore) { }
+ }
+ } while (count > 0);
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java
new file mode 100755
index 0000000..3b431e7
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java
@@ -0,0 +1,351 @@
+/*
+ * 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.net.InetSocketAddress;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Unix implementation of AsynchronousServerSocketChannel
+ */
+
+class UnixAsynchronousServerSocketChannelImpl
+ extends AsynchronousServerSocketChannelImpl
+ implements Port.PollableChannel
+{
+ private final static NativeDispatcher nd = new SocketDispatcher();
+
+ private final Port port;
+ private final int fdVal;
+
+ // flag to indicate an accept is outstanding
+ private final AtomicBoolean accepting = new AtomicBoolean();
+ private void enableAccept() {
+ accepting.set(false);
+ }
+
+ // used to ensure that the context for an asynchronous accept is visible
+ // the pooled thread that handles the I/O event
+ private final Object updateLock = new Object();
+
+ // pending accept
+ private boolean acceptPending;
+ private CompletionHandler<AsynchronousSocketChannel,Object> acceptHandler;
+ private Object acceptAttachment;
+ private PendingFuture<AsynchronousSocketChannel,Object> acceptFuture;
+
+ // context for permission check when security manager set
+ private AccessControlContext acceptAcc;
+
+
+ UnixAsynchronousServerSocketChannelImpl(Port port)
+ throws IOException
+ {
+ super(port);
+
+ try {
+ IOUtil.configureBlocking(fd, false);
+ } catch (IOException x) {
+ nd.close(fd); // prevent leak
+ throw x;
+ }
+ this.port = port;
+ this.fdVal = IOUtil.fdVal(fd);
+
+ // add mapping from file descriptor to this channel
+ port.register(fdVal, this);
+ }
+
+ @Override
+ void implClose() throws IOException {
+ // remove the mapping
+ port.unregister(fdVal);
+
+ // close file descriptor
+ nd.close(fd);
+
+ // if there is a pending accept then complete it
+ CompletionHandler<AsynchronousSocketChannel,Object> handler;
+ Object att;
+ PendingFuture<AsynchronousSocketChannel,Object> future;
+ synchronized (updateLock) {
+ if (!acceptPending)
+ return; // no pending accept
+ acceptPending = false;
+ handler = acceptHandler;
+ att = acceptAttachment;
+ future = acceptFuture;
+ }
+
+ // discard the stack trace as otherwise it may appear that implClose
+ // has thrown the exception.
+ AsynchronousCloseException x = new AsynchronousCloseException();
+ x.setStackTrace(new StackTraceElement[0]);
+ if (handler == null) {
+ future.setFailure(x);
+ } else {
+ // invoke by submitting task rather than directly
+ Invoker.invokeIndirectly(this, handler, att, null, x);
+ }
+ }
+
+ @Override
+ public AsynchronousChannelGroupImpl group() {
+ return port;
+ }
+
+ /**
+ * Invoked by event handling thread when listener socket is polled
+ */
+ @Override
+ public void onEvent(int events, boolean mayInvokeDirect) {
+ synchronized (updateLock) {
+ if (!acceptPending)
+ return; // may have been grabbed by asynchronous close
+ acceptPending = false;
+ }
+
+ // attempt to accept connection
+ FileDescriptor newfd = new FileDescriptor();
+ InetSocketAddress[] isaa = new InetSocketAddress[1];
+ Throwable exc = null;
+ try {
+ begin();
+ int n = accept0(this.fd, newfd, isaa);
+
+ // spurious wakeup, is this possible?
+ if (n == IOStatus.UNAVAILABLE) {
+ synchronized (updateLock) {
+ acceptPending = true;
+ }
+ port.startPoll(fdVal, Port.POLLIN);
+ return;
+ }
+
+ } catch (Throwable x) {
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ end();
+ }
+
+ // Connection accepted so finish it when not holding locks.
+ AsynchronousSocketChannel child = null;
+ if (exc == null) {
+ try {
+ child = finishAccept(newfd, isaa[0], acceptAcc);
+ } catch (Throwable x) {
+ if (!(x instanceof IOException) && !(x instanceof SecurityException))
+ x = new IOException(x);
+ exc = x;
+ }
+ }
+
+ // copy field befores accept is re-renabled
+ CompletionHandler<AsynchronousSocketChannel,Object> handler = acceptHandler;
+ Object att = acceptAttachment;
+ PendingFuture<AsynchronousSocketChannel,Object> future = acceptFuture;
+
+ // re-enable accepting and invoke handler
+ enableAccept();
+
+ if (handler == null) {
+ future.setResult(child, exc);
+ // if an async cancel has already cancelled the operation then
+ // close the new channel so as to free resources
+ if (child != null && future.isCancelled()) {
+ try {
+ child.close();
+ } catch (IOException ignore) { }
+ }
+ } else {
+ Invoker.invoke(this, handler, att, child, exc);
+ }
+ }
+
+ /**
+ * Completes the accept by creating the AsynchronousSocketChannel for
+ * the given file descriptor and remote address. If this method completes
+ * with an IOException or SecurityException then the channel/file descriptor
+ * will be closed.
+ */
+ private AsynchronousSocketChannel finishAccept(FileDescriptor newfd,
+ final InetSocketAddress remote,
+ AccessControlContext acc)
+ throws IOException, SecurityException
+ {
+ AsynchronousSocketChannel ch = null;
+ try {
+ ch = new UnixAsynchronousSocketChannelImpl(port, newfd, remote);
+ } catch (IOException x) {
+ nd.close(newfd);
+ throw x;
+ }
+
+ // permission check must always be in initiator's context
+ try {
+ if (acc != null) {
+ AccessController.doPrivileged(new PrivilegedAction<Void>() {
+ public Void run() {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkAccept(remote.getAddress().getHostAddress(),
+ remote.getPort());
+ }
+ return null;
+ }
+ }, acc);
+ } else {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ sm.checkAccept(remote.getAddress().getHostAddress(),
+ remote.getPort());
+ }
+ }
+ } catch (SecurityException x) {
+ try {
+ ch.close();
+ } catch (Throwable suppressed) {
+ x.addSuppressed(suppressed);
+ }
+ throw x;
+ }
+ return ch;
+ }
+
+ @Override
+ Future<AsynchronousSocketChannel> implAccept(Object att,
+ CompletionHandler<AsynchronousSocketChannel,Object> handler)
+ {
+ // complete immediately if channel is closed
+ if (!isOpen()) {
+ Throwable e = new ClosedChannelException();
+ if (handler == null) {
+ return CompletedFuture.withFailure(e);
+ } else {
+ Invoker.invoke(this, handler, att, null, e);
+ return null;
+ }
+ }
+ if (localAddress == null)
+ throw new NotYetBoundException();
+
+ // cancel was invoked with pending accept so connection may have been
+ // dropped.
+ if (isAcceptKilled())
+ throw new RuntimeException("Accept not allowed due cancellation");
+
+ // check and set flag to prevent concurrent accepting
+ if (!accepting.compareAndSet(false, true))
+ throw new AcceptPendingException();
+
+ // attempt accept
+ FileDescriptor newfd = new FileDescriptor();
+ InetSocketAddress[] isaa = new InetSocketAddress[1];
+ Throwable exc = null;
+ try {
+ begin();
+
+ int n = accept0(this.fd, newfd, isaa);
+ if (n == IOStatus.UNAVAILABLE) {
+
+ // need calling context when there is security manager as
+ // permission check may be done in a different thread without
+ // any application call frames on the stack
+ PendingFuture<AsynchronousSocketChannel,Object> result = null;
+ synchronized (updateLock) {
+ if (handler == null) {
+ this.acceptHandler = null;
+ result = new PendingFuture<AsynchronousSocketChannel,Object>(this);
+ this.acceptFuture = result;
+ } else {
+ this.acceptHandler = handler;
+ this.acceptAttachment = att;
+ }
+ this.acceptAcc = (System.getSecurityManager() == null) ?
+ null : AccessController.getContext();
+ this.acceptPending = true;
+ }
+
+ // register for connections
+ port.startPoll(fdVal, Port.POLLIN);
+ return result;
+ }
+ } catch (Throwable x) {
+ // accept failed
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ end();
+ }
+
+ AsynchronousSocketChannel child = null;
+ if (exc == null) {
+ // connection accepted immediately
+ try {
+ child = finishAccept(newfd, isaa[0], null);
+ } catch (Throwable x) {
+ exc = x;
+ }
+ }
+
+ // re-enable accepting before invoking handler
+ enableAccept();
+
+ if (handler == null) {
+ return CompletedFuture.withResult(child, exc);
+ } else {
+ Invoker.invokeIndirectly(this, handler, att, child, exc);
+ return null;
+ }
+ }
+
+ // -- Native methods --
+
+ private static native void initIDs();
+
+ // Accepts a new connection, setting the given file descriptor to refer to
+ // the new socket and setting isaa[0] to the socket's remote address.
+ // Returns 1 on success, or IOStatus.UNAVAILABLE.
+ //
+ private native int accept0(FileDescriptor ssfd, FileDescriptor newfd,
+ InetSocketAddress[] isaa)
+ throws IOException;
+
+ static {
+ Util.load();
+ initIDs();
+ }
+}
diff --git a/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java b/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
new file mode 100755
index 0000000..8b74488
--- /dev/null
+++ b/ojluni/src/main/java/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java
@@ -0,0 +1,753 @@
+/*
+ * 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 sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.ByteBuffer;
+import java.net.*;
+import java.util.concurrent.*;
+import java.io.IOException;
+import java.io.FileDescriptor;
+import java.security.AccessController;
+import sun.net.NetHooks;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Unix implementation of AsynchronousSocketChannel
+ */
+
+class UnixAsynchronousSocketChannelImpl
+ extends AsynchronousSocketChannelImpl implements Port.PollableChannel
+{
+ private final static NativeDispatcher nd = new SocketDispatcher();
+ private static enum OpType { CONNECT, READ, WRITE };
+
+ private static final boolean disableSynchronousRead;
+ static {
+ String propValue = AccessController.doPrivileged(
+ new GetPropertyAction("sun.nio.ch.disableSynchronousRead", "false"));
+ disableSynchronousRead = (propValue.length() == 0) ?
+ true : Boolean.valueOf(propValue);
+ }
+
+ private final Port port;
+ private final int fdVal;
+
+ // used to ensure that the context for I/O operations that complete
+ // ascynrhonously is visible to the pooled threads handling I/O events.
+ private final Object updateLock = new Object();
+
+ // pending connect (updateLock)
+ private boolean connectPending;
+ private CompletionHandler<Void,Object> connectHandler;
+ private Object connectAttachment;
+ private PendingFuture<Void,Object> connectFuture;
+
+ // pending remote address (stateLock)
+ private SocketAddress pendingRemote;
+
+ // pending read (updateLock)
+ private boolean readPending;
+ private boolean isScatteringRead;
+ private ByteBuffer readBuffer;
+ private ByteBuffer[] readBuffers;
+ private CompletionHandler<Number,Object> readHandler;
+ private Object readAttachment;
+ private PendingFuture<Number,Object> readFuture;
+ private Future<?> readTimer;
+
+ // pending write (updateLock)
+ private boolean writePending;
+ private boolean isGatheringWrite;
+ private ByteBuffer writeBuffer;
+ private ByteBuffer[] writeBuffers;
+ private CompletionHandler<Number,Object> writeHandler;
+ private Object writeAttachment;
+ private PendingFuture<Number,Object> writeFuture;
+ private Future<?> writeTimer;
+
+
+ UnixAsynchronousSocketChannelImpl(Port port)
+ throws IOException
+ {
+ super(port);
+
+ // set non-blocking
+ try {
+ IOUtil.configureBlocking(fd, false);
+ } catch (IOException x) {
+ nd.close(fd);
+ throw x;
+ }
+
+ this.port = port;
+ this.fdVal = IOUtil.fdVal(fd);
+
+ // add mapping from file descriptor to this channel
+ port.register(fdVal, this);
+ }
+
+ // Constructor for sockets created by UnixAsynchronousServerSocketChannelImpl
+ UnixAsynchronousSocketChannelImpl(Port port,
+ FileDescriptor fd,
+ InetSocketAddress remote)
+ throws IOException
+ {
+ super(port, fd, remote);
+
+ this.fdVal = IOUtil.fdVal(fd);
+ IOUtil.configureBlocking(fd, false);
+
+ try {
+ port.register(fdVal, this);
+ } catch (ShutdownChannelGroupException x) {
+ // ShutdownChannelGroupException thrown if we attempt to register a
+ // new channel after the group is shutdown
+ throw new IOException(x);
+ }
+
+ this.port = port;
+ }
+
+ @Override
+ public AsynchronousChannelGroupImpl group() {
+ return port;
+ }
+
+ // register events for outstanding I/O operations, caller already owns updateLock
+ private void updateEvents() {
+ assert Thread.holdsLock(updateLock);
+ int events = 0;
+ if (readPending)
+ events |= Port.POLLIN;
+ if (connectPending || writePending)
+ events |= Port.POLLOUT;
+ if (events != 0)
+ port.startPoll(fdVal, events);
+ }
+
+ // register events for outstanding I/O operations
+ private void lockAndUpdateEvents() {
+ synchronized (updateLock) {
+ updateEvents();
+ }
+ }
+
+ // invoke to finish read and/or write operations
+ private void finish(boolean mayInvokeDirect,
+ boolean readable,
+ boolean writable)
+ {
+ boolean finishRead = false;
+ boolean finishWrite = false;
+ boolean finishConnect = false;
+
+ // map event to pending result
+ synchronized (updateLock) {
+ if (readable && this.readPending) {
+ this.readPending = false;
+ finishRead = true;
+ }
+ if (writable) {
+ if (this.writePending) {
+ this.writePending = false;
+ finishWrite = true;
+ } else if (this.connectPending) {
+ this.connectPending = false;
+ finishConnect = true;
+ }
+ }
+ }
+
+ // complete the I/O operation. Special case for when channel is
+ // ready for both reading and writing. In that case, submit task to
+ // complete write if write operation has a completion handler.
+ if (finishRead) {
+ if (finishWrite)
+ finishWrite(false);
+ finishRead(mayInvokeDirect);
+ return;
+ }
+ if (finishWrite) {
+ finishWrite(mayInvokeDirect);
+ }
+ if (finishConnect) {
+ finishConnect(mayInvokeDirect);
+ }
+ }
+
+ /**
+ * Invoked by event handler thread when file descriptor is polled
+ */
+ @Override
+ public void onEvent(int events, boolean mayInvokeDirect) {
+ boolean readable = (events & Port.POLLIN) > 0;
+ boolean writable = (events & Port.POLLOUT) > 0;
+ if ((events & (Port.POLLERR | Port.POLLHUP)) > 0) {
+ readable = true;
+ writable = true;
+ }
+ finish(mayInvokeDirect, readable, writable);
+ }
+
+ @Override
+ void implClose() throws IOException {
+ // remove the mapping
+ port.unregister(fdVal);
+
+ // close file descriptor
+ nd.close(fd);
+
+ // All outstanding I/O operations are required to fail
+ finish(false, true, true);
+ }
+
+ @Override
+ public void onCancel(PendingFuture<?,?> task) {
+ if (task.getContext() == OpType.CONNECT)
+ killConnect();
+ if (task.getContext() == OpType.READ)
+ killReading();
+ if (task.getContext() == OpType.WRITE)
+ killWriting();
+ }
+
+ // -- connect --
+
+ private void setConnected() throws IOException {
+ synchronized (stateLock) {
+ state = ST_CONNECTED;
+ localAddress = Net.localAddress(fd);
+ remoteAddress = (InetSocketAddress)pendingRemote;
+ }
+ }
+
+ private void finishConnect(boolean mayInvokeDirect) {
+ Throwable e = null;
+ try {
+ begin();
+ checkConnect(fdVal);
+ setConnected();
+ } catch (Throwable x) {
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ e = x;
+ } finally {
+ end();
+ }
+ if (e != null) {
+ // close channel if connection cannot be established
+ try {
+ close();
+ } catch (Throwable suppressed) {
+ e.addSuppressed(suppressed);
+ }
+ }
+
+ // invoke handler and set result
+ CompletionHandler<Void,Object> handler = connectHandler;
+ Object att = connectAttachment;
+ PendingFuture<Void,Object> future = connectFuture;
+ if (handler == null) {
+ future.setResult(null, e);
+ } else {
+ if (mayInvokeDirect) {
+ Invoker.invokeUnchecked(handler, att, null, e);
+ } else {
+ Invoker.invokeIndirectly(this, handler, att, null, e);
+ }
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ <A> Future<Void> implConnect(SocketAddress remote,
+ A attachment,
+ CompletionHandler<Void,? super A> handler)
+ {
+ if (!isOpen()) {
+ Throwable e = new ClosedChannelException();
+ if (handler == null) {
+ return CompletedFuture.withFailure(e);
+ } else {
+ Invoker.invoke(this, handler, attachment, null, e);
+ return null;
+ }
+ }
+
+ InetSocketAddress isa = Net.checkAddress(remote);
+
+ // permission check
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null)
+ sm.checkConnect(isa.getAddress().getHostAddress(), isa.getPort());
+
+ // check and set state
+ boolean notifyBeforeTcpConnect;
+ synchronized (stateLock) {
+ if (state == ST_CONNECTED)
+ throw new AlreadyConnectedException();
+ if (state == ST_PENDING)
+ throw new ConnectionPendingException();
+ state = ST_PENDING;
+ pendingRemote = remote;
+ notifyBeforeTcpConnect = (localAddress == null);
+ }
+
+ Throwable e = null;
+ try {
+ begin();
+ // notify hook if unbound
+ if (notifyBeforeTcpConnect)
+ NetHooks.beforeTcpConnect(fd, isa.getAddress(), isa.getPort());
+ int n = Net.connect(fd, isa.getAddress(), isa.getPort());
+ if (n == IOStatus.UNAVAILABLE) {
+ // connection could not be established immediately
+ PendingFuture<Void,A> result = null;
+ synchronized (updateLock) {
+ if (handler == null) {
+ result = new PendingFuture<Void,A>(this, OpType.CONNECT);
+ this.connectFuture = (PendingFuture<Void,Object>)result;
+ } else {
+ this.connectHandler = (CompletionHandler<Void,Object>)handler;
+ this.connectAttachment = attachment;
+ }
+ this.connectPending = true;
+ updateEvents();
+ }
+ return result;
+ }
+ setConnected();
+ } catch (Throwable x) {
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ e = x;
+ } finally {
+ end();
+ }
+
+ // close channel if connect fails
+ if (e != null) {
+ try {
+ close();
+ } catch (Throwable suppressed) {
+ e.addSuppressed(suppressed);
+ }
+ }
+ if (handler == null) {
+ return CompletedFuture.withResult(null, e);
+ } else {
+ Invoker.invoke(this, handler, attachment, null, e);
+ return null;
+ }
+ }
+
+ // -- read --
+
+ private void finishRead(boolean mayInvokeDirect) {
+ int n = -1;
+ Throwable exc = null;
+
+ // copy fields as we can't access them after reading is re-enabled.
+ boolean scattering = isScatteringRead;
+ CompletionHandler<Number,Object> handler = readHandler;
+ Object att = readAttachment;
+ PendingFuture<Number,Object> future = readFuture;
+ Future<?> timeout = readTimer;
+
+ try {
+ begin();
+
+ if (scattering) {
+ n = (int)IOUtil.read(fd, readBuffers, nd);
+ } else {
+ n = IOUtil.read(fd, readBuffer, -1, nd);
+ }
+ if (n == IOStatus.UNAVAILABLE) {
+ // spurious wakeup, is this possible?
+ synchronized (updateLock) {
+ readPending = true;
+ }
+ return;
+ }
+
+ // allow objects to be GC'ed.
+ this.readBuffer = null;
+ this.readBuffers = null;
+ this.readAttachment = null;
+
+ // allow another read to be initiated
+ enableReading();
+
+ } catch (Throwable x) {
+ enableReading();
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ // restart poll in case of concurrent write
+ if (!(exc instanceof AsynchronousCloseException))
+ lockAndUpdateEvents();
+ end();
+ }
+
+ // cancel the associated timer
+ if (timeout != null)
+ timeout.cancel(false);
+
+ // create result
+ Number result = (exc != null) ? null : (scattering) ?
+ (Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
+
+ // invoke handler or set result
+ if (handler == null) {
+ future.setResult(result, exc);
+ } else {
+ if (mayInvokeDirect) {
+ Invoker.invokeUnchecked(handler, att, result, exc);
+ } else {
+ Invoker.invokeIndirectly(this, handler, att, result, exc);
+ }
+ }
+ }
+
+ private Runnable readTimeoutTask = new Runnable() {
+ public void run() {
+ CompletionHandler<Number,Object> handler = null;
+ Object att = null;
+ PendingFuture<Number,Object> future = null;
+
+ synchronized (updateLock) {
+ if (!readPending)
+ return;
+ readPending = false;
+ handler = readHandler;
+ att = readAttachment;
+ future = readFuture;
+ }
+
+ // kill further reading before releasing waiters
+ enableReading(true);
+
+ // invoke handler or set result
+ Exception exc = new InterruptedByTimeoutException();
+ if (handler == null) {
+ future.setFailure(exc);
+ } else {
+ AsynchronousChannel ch = UnixAsynchronousSocketChannelImpl.this;
+ Invoker.invokeIndirectly(ch, handler, att, null, exc);
+ }
+ }
+ };
+
+ /**
+ * Initiates a read or scattering read operation
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ <V extends Number,A> Future<V> implRead(boolean isScatteringRead,
+ ByteBuffer dst,
+ ByteBuffer[] dsts,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<V,? super A> handler)
+ {
+ // A synchronous read is not attempted if disallowed by system property
+ // or, we are using a fixed thread pool and the completion handler may
+ // not be invoked directly (because the thread is not a pooled thread or
+ // there are too many handlers on the stack).
+ Invoker.GroupAndInvokeCount myGroupAndInvokeCount = null;
+ boolean invokeDirect = false;
+ boolean attemptRead = false;
+ if (!disableSynchronousRead) {
+ if (handler == null) {
+ attemptRead = true;
+ } else {
+ myGroupAndInvokeCount = Invoker.getGroupAndInvokeCount();
+ invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
+ // okay to attempt read with user thread pool
+ attemptRead = invokeDirect || !port.isFixedThreadPool();
+ }
+ }
+
+ int n = IOStatus.UNAVAILABLE;
+ Throwable exc = null;
+ boolean pending = false;
+
+ try {
+ begin();
+
+ if (attemptRead) {
+ if (isScatteringRead) {
+ n = (int)IOUtil.read(fd, dsts, nd);
+ } else {
+ n = IOUtil.read(fd, dst, -1, nd);
+ }
+ }
+
+ if (n == IOStatus.UNAVAILABLE) {
+ PendingFuture<V,A> result = null;
+ synchronized (updateLock) {
+ this.isScatteringRead = isScatteringRead;
+ this.readBuffer = dst;
+ this.readBuffers = dsts;
+ if (handler == null) {
+ this.readHandler = null;
+ result = new PendingFuture<V,A>(this, OpType.READ);
+ this.readFuture = (PendingFuture<Number,Object>)result;
+ this.readAttachment = null;
+ } else {
+ this.readHandler = (CompletionHandler<Number,Object>)handler;
+ this.readAttachment = attachment;
+ this.readFuture = null;
+ }
+ if (timeout > 0L) {
+ this.readTimer = port.schedule(readTimeoutTask, timeout, unit);
+ }
+ this.readPending = true;
+ updateEvents();
+ }
+ pending = true;
+ return result;
+ }
+ } catch (Throwable x) {
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ if (!pending)
+ enableReading();
+ end();
+ }
+
+ Number result = (exc != null) ? null : (isScatteringRead) ?
+ (Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
+
+ // read completed immediately
+ if (handler != null) {
+ if (invokeDirect) {
+ Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);
+ } else {
+ Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);
+ }
+ return null;
+ } else {
+ return CompletedFuture.withResult((V)result, exc);
+ }
+ }
+
+ // -- write --
+
+ private void finishWrite(boolean mayInvokeDirect) {
+ int n = -1;
+ Throwable exc = null;
+
+ // copy fields as we can't access them after reading is re-enabled.
+ boolean gathering = this.isGatheringWrite;
+ CompletionHandler<Number,Object> handler = this.writeHandler;
+ Object att = this.writeAttachment;
+ PendingFuture<Number,Object> future = this.writeFuture;
+ Future<?> timer = this.writeTimer;
+
+ try {
+ begin();
+
+ if (gathering) {
+ n = (int)IOUtil.write(fd, writeBuffers, nd);
+ } else {
+ n = IOUtil.write(fd, writeBuffer, -1, nd);
+ }
+ if (n == IOStatus.UNAVAILABLE) {
+ // spurious wakeup, is this possible?
+ synchronized (updateLock) {
+ writePending = true;
+ }
+ return;
+ }
+
+ // allow objects to be GC'ed.
+ this.writeBuffer = null;
+ this.writeBuffers = null;
+ this.writeAttachment = null;
+
+ // allow another write to be initiated
+ enableWriting();
+
+ } catch (Throwable x) {
+ enableWriting();
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ // restart poll in case of concurrent write
+ if (!(exc instanceof AsynchronousCloseException))
+ lockAndUpdateEvents();
+ end();
+ }
+
+ // cancel the associated timer
+ if (timer != null)
+ timer.cancel(false);
+
+ // create result
+ Number result = (exc != null) ? null : (gathering) ?
+ (Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
+
+ // invoke handler or set result
+ if (handler == null) {
+ future.setResult(result, exc);
+ } else {
+ if (mayInvokeDirect) {
+ Invoker.invokeUnchecked(handler, att, result, exc);
+ } else {
+ Invoker.invokeIndirectly(this, handler, att, result, exc);
+ }
+ }
+ }
+
+ private Runnable writeTimeoutTask = new Runnable() {
+ public void run() {
+ CompletionHandler<Number,Object> handler = null;
+ Object att = null;
+ PendingFuture<Number,Object> future = null;
+
+ synchronized (updateLock) {
+ if (!writePending)
+ return;
+ writePending = false;
+ handler = writeHandler;
+ att = writeAttachment;
+ future = writeFuture;
+ }
+
+ // kill further writing before releasing waiters
+ enableWriting(true);
+
+ // invoke handler or set result
+ Exception exc = new InterruptedByTimeoutException();
+ if (handler != null) {
+ Invoker.invokeIndirectly(UnixAsynchronousSocketChannelImpl.this,
+ handler, att, null, exc);
+ } else {
+ future.setFailure(exc);
+ }
+ }
+ };
+
+ /**
+ * Initiates a read or scattering read operation
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ <V extends Number,A> Future<V> implWrite(boolean isGatheringWrite,
+ ByteBuffer src,
+ ByteBuffer[] srcs,
+ long timeout,
+ TimeUnit unit,
+ A attachment,
+ CompletionHandler<V,? super A> handler)
+ {
+ Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+ Invoker.getGroupAndInvokeCount();
+ boolean invokeDirect = Invoker.mayInvokeDirect(myGroupAndInvokeCount, port);
+ boolean attemptWrite = (handler == null) || invokeDirect ||
+ !port.isFixedThreadPool(); // okay to attempt write with user thread pool
+
+ int n = IOStatus.UNAVAILABLE;
+ Throwable exc = null;
+ boolean pending = false;
+
+ try {
+ begin();
+
+ if (attemptWrite) {
+ if (isGatheringWrite) {
+ n = (int)IOUtil.write(fd, srcs, nd);
+ } else {
+ n = IOUtil.write(fd, src, -1, nd);
+ }
+ }
+
+ if (n == IOStatus.UNAVAILABLE) {
+ PendingFuture<V,A> result = null;
+ synchronized (updateLock) {
+ this.isGatheringWrite = isGatheringWrite;
+ this.writeBuffer = src;
+ this.writeBuffers = srcs;
+ if (handler == null) {
+ this.writeHandler = null;
+ result = new PendingFuture<V,A>(this, OpType.WRITE);
+ this.writeFuture = (PendingFuture<Number,Object>)result;
+ this.writeAttachment = null;
+ } else {
+ this.writeHandler = (CompletionHandler<Number,Object>)handler;
+ this.writeAttachment = attachment;
+ this.writeFuture = null;
+ }
+ if (timeout > 0L) {
+ this.writeTimer = port.schedule(writeTimeoutTask, timeout, unit);
+ }
+ this.writePending = true;
+ updateEvents();
+ }
+ pending = true;
+ return result;
+ }
+ } catch (Throwable x) {
+ if (x instanceof ClosedChannelException)
+ x = new AsynchronousCloseException();
+ exc = x;
+ } finally {
+ if (!pending)
+ enableWriting();
+ end();
+ }
+
+ Number result = (exc != null) ? null : (isGatheringWrite) ?
+ (Number)Long.valueOf(n) : (Number)Integer.valueOf(n);
+
+ // write completed immediately
+ if (handler != null) {
+ if (invokeDirect) {
+ Invoker.invokeDirect(myGroupAndInvokeCount, handler, attachment, (V)result, exc);
+ } else {
+ Invoker.invokeIndirectly(this, handler, attachment, (V)result, exc);
+ }
+ return null;
+ } else {
+ return CompletedFuture.withResult((V)result, exc);
+ }
+ }
+
+ // -- Native methods --
+
+ private static native void checkConnect(int fdVal) throws IOException;
+
+ static {
+ Util.load();
+ }
+}
diff --git a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
index 62f8bdd..fc4ee76 100755
--- a/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
+++ b/ojluni/src/main/java/sun/security/jca/ProviderConfig.java
@@ -208,58 +208,68 @@
if (debug != null) {
debug.println("Loading provider: " + ProviderConfig.this);
}
+
try {
- ClassLoader cl = ClassLoader.getSystemClassLoader();
- Class<?> provClass;
- if (cl != null) {
- provClass = cl.loadClass(className);
- } else {
- provClass = Class.forName(className);
- }
- Object obj;
- if (hasArgument() == false) {
- obj = provClass.newInstance();
- } else {
- Constructor<?> cons = provClass.getConstructor(CL_STRING);
- obj = cons.newInstance(argument);
- }
- if (obj instanceof Provider) {
- if (debug != null) {
- debug.println("Loaded provider " + obj);
+ // First try with the boot classloader.
+ return initProvider(className, Object.class.getClassLoader());
+ } catch (Exception e1) {
+ // If that fails, try with the system classloader.
+ try {
+ return initProvider(className, ClassLoader.getSystemClassLoader());
+ } catch (Exception e) {
+ Throwable t;
+ if (e instanceof InvocationTargetException) {
+ t = ((InvocationTargetException)e).getCause();
+ } else {
+ t = e;
}
- return (Provider)obj;
- } else {
if (debug != null) {
- debug.println(className + " is not a provider");
+ debug.println("Error loading provider " + ProviderConfig.this);
+ t.printStackTrace();
}
- disableLoad();
+ // provider indicates fatal error, pass through exception
+ if (t instanceof ProviderException) {
+ throw (ProviderException)t;
+ }
+ // provider indicates that loading should not be retried
+ if (t instanceof UnsupportedOperationException) {
+ disableLoad();
+ }
return null;
}
- } catch (Exception e) {
- Throwable t;
- if (e instanceof InvocationTargetException) {
- t = ((InvocationTargetException)e).getCause();
- } else {
- t = e;
- }
- if (debug != null) {
- debug.println("Error loading provider " + ProviderConfig.this);
- t.printStackTrace();
- }
- // provider indicates fatal error, pass through exception
- if (t instanceof ProviderException) {
- throw (ProviderException)t;
- }
- // provider indicates that loading should not be retried
- if (t instanceof UnsupportedOperationException) {
- disableLoad();
- }
- return null;
}
}
});
}
+ private Provider initProvider(String className, ClassLoader cl) throws Exception {
+ Class<?> provClass;
+ if (cl != null) {
+ provClass = cl.loadClass(className);
+ } else {
+ provClass = Class.forName(className);
+ }
+ Object obj;
+ if (hasArgument() == false) {
+ obj = provClass.newInstance();
+ } else {
+ Constructor<?> cons = provClass.getConstructor(CL_STRING);
+ obj = cons.newInstance(argument);
+ }
+ if (obj instanceof Provider) {
+ if (debug != null) {
+ debug.println("Loaded provider " + obj);
+ }
+ return (Provider)obj;
+ } else {
+ if (debug != null) {
+ debug.println(className + " is not a provider");
+ }
+ disableLoad();
+ return null;
+ }
+ }
+
/**
* Perform property expansion of the provider value.
*
diff --git a/ojluni/src/main/java/sun/security/jca/Providers.java b/ojluni/src/main/java/sun/security/jca/Providers.java
index d66d4f8..2212dc2 100755
--- a/ojluni/src/main/java/sun/security/jca/Providers.java
+++ b/ojluni/src/main/java/sun/security/jca/Providers.java
@@ -56,6 +56,15 @@
// triggers a getInstance() call (although that should not happen)
providerList = ProviderList.EMPTY;
providerList = ProviderList.fromSecurityProperties();
+
+ // removeInvalid is specified to try initializing all configured providers
+ // and removing those that aren't instantiable. This has the side effect
+ // of eagerly initializing all providers.
+ final int numConfiguredProviders = providerList.size();
+ providerList = providerList.removeInvalid();
+ if (numConfiguredProviders != providerList.size()) {
+ throw new AssertionError("Unable to configure default providers");
+ }
}
private Providers() {
diff --git a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
index 51fac9b..756a48e 100755
--- a/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
+++ b/ojluni/src/main/java/sun/security/ssl/SSLSessionContextImpl.java
@@ -207,7 +207,7 @@
"javax.net.ssl.sessionCacheSize");
}
});
- cacheLimit = (s != null) ? Integer.valueOf(s).intValue() : 0;
+ cacheLimit = (s != null) ? Integer.parseInt(s) : 0;
} catch (Exception e) {
}
diff --git a/ojluni/src/main/native/DatagramChannelImpl.c b/ojluni/src/main/native/DatagramChannelImpl.c
index 471c62b..4307743 100644
--- a/ojluni/src/main/native/DatagramChannelImpl.c
+++ b/ojluni/src/main/native/DatagramChannelImpl.c
@@ -145,6 +145,8 @@
len = MAX_PACKET_LEN;
}
+ memset(&sa, 0, sa_len);
+
do {
retry = JNI_FALSE;
n = recvfrom(fd, buf, len, 0, (struct sockaddr *)&sa, &sa_len);
@@ -171,7 +173,7 @@
// Peer (or other thread) has performed an orderly shutdown, sockaddr will be
// invalid.
- if (n == 0) {
+ if (n == 0 && ((struct sockaddr *)&sa)->sa_family == 0) {
// zero the sender field, so receive() returns null and not
// random garbage
(*env)->SetObjectField(env, this, dci_senderID, NULL);
diff --git a/openjdk_java_files.mk b/openjdk_java_files.mk
index e065270..66ae35b 100644
--- a/openjdk_java_files.mk
+++ b/openjdk_java_files.mk
@@ -85,6 +85,7 @@
ojluni/src/main/java/java/io/StringReader.java \
ojluni/src/main/java/java/io/StringWriter.java \
ojluni/src/main/java/java/io/SyncFailedException.java \
+ ojluni/src/main/java/java/io/UncheckedIOException.java \
ojluni/src/main/java/java/io/UnixFileSystem.java \
ojluni/src/main/java/java/io/UnsupportedEncodingException.java \
ojluni/src/main/java/java/io/UTFDataFormatException.java \
@@ -309,15 +310,87 @@
ojluni/src/main/java/java/nio/Buffer.java \
ojluni/src/main/java/java/nio/BufferOverflowException.java \
ojluni/src/main/java/java/nio/BufferUnderflowException.java \
- ojluni/src/main/java/java/nio/ByteBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsCharBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsDoubleBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsFloatBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsIntBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsLongBuffer.java \
ojluni/src/main/java/java/nio/ByteBufferAsShortBuffer.java \
+ ojluni/src/main/java/java/nio/ByteBuffer.java \
ojluni/src/main/java/java/nio/ByteOrder.java \
+ ojluni/src/main/java/java/nio/channels/AcceptPendingException.java \
+ ojluni/src/main/java/java/nio/channels/AlreadyBoundException.java \
+ ojluni/src/main/java/java/nio/channels/AlreadyConnectedException.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousChannelGroup.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousChannel.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousCloseException.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousServerSocketChannel.java \
+ ojluni/src/main/java/java/nio/channels/AsynchronousSocketChannel.java \
+ ojluni/src/main/java/java/nio/channels/ByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/CancelledKeyException.java \
+ ojluni/src/main/java/java/nio/channels/Channel.java \
+ ojluni/src/main/java/java/nio/channels/Channels.java \
+ ojluni/src/main/java/java/nio/channels/ClosedByInterruptException.java \
+ ojluni/src/main/java/java/nio/channels/ClosedChannelException.java \
+ ojluni/src/main/java/java/nio/channels/ClosedSelectorException.java \
+ ojluni/src/main/java/java/nio/channels/CompletionHandler.java \
+ ojluni/src/main/java/java/nio/channels/ConnectionPendingException.java \
+ ojluni/src/main/java/java/nio/channels/DatagramChannel.java \
+ ojluni/src/main/java/java/nio/channels/FileChannel.java \
+ ojluni/src/main/java/java/nio/channels/FileLockInterruptionException.java \
+ ojluni/src/main/java/java/nio/channels/FileLock.java \
+ ojluni/src/main/java/java/nio/channels/GatheringByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/IllegalBlockingModeException.java \
+ ojluni/src/main/java/java/nio/channels/IllegalChannelGroupException.java \
+ ojluni/src/main/java/java/nio/channels/IllegalSelectorException.java \
+ ojluni/src/main/java/java/nio/channels/InterruptedByTimeoutException.java \
+ ojluni/src/main/java/java/nio/channels/InterruptibleChannel.java \
+ ojluni/src/main/java/java/nio/channels/MembershipKey.java \
+ ojluni/src/main/java/java/nio/channels/MulticastChannel.java \
+ ojluni/src/main/java/java/nio/channels/NetworkChannel.java \
+ ojluni/src/main/java/java/nio/channels/NoConnectionPendingException.java \
+ ojluni/src/main/java/java/nio/channels/NonReadableChannelException.java \
+ ojluni/src/main/java/java/nio/channels/NonWritableChannelException.java \
+ ojluni/src/main/java/java/nio/channels/NotYetBoundException.java \
+ ojluni/src/main/java/java/nio/channels/NotYetConnectedException.java \
+ ojluni/src/main/java/java/nio/channels/OverlappingFileLockException.java \
+ ojluni/src/main/java/java/nio/channels/Pipe.java \
+ ojluni/src/main/java/java/nio/channels/ReadableByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/ReadPendingException.java \
+ ojluni/src/main/java/java/nio/channels/ScatteringByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/SeekableByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/SelectableChannel.java \
+ ojluni/src/main/java/java/nio/channels/SelectionKey.java \
+ ojluni/src/main/java/java/nio/channels/Selector.java \
+ ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java \
+ ojluni/src/main/java/java/nio/channels/ShutdownChannelGroupException.java \
+ ojluni/src/main/java/java/nio/channels/SocketChannel.java \
+ ojluni/src/main/java/java/nio/channels/spi/AbstractInterruptibleChannel.java \
+ ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java \
+ ojluni/src/main/java/java/nio/channels/spi/AbstractSelectionKey.java \
+ ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java \
+ ojluni/src/main/java/java/nio/channels/spi/AsynchronousChannelProvider.java \
+ ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java \
+ ojluni/src/main/java/java/nio/channels/UnresolvedAddressException.java \
+ ojluni/src/main/java/java/nio/channels/UnsupportedAddressTypeException.java \
+ ojluni/src/main/java/java/nio/channels/WritableByteChannel.java \
+ ojluni/src/main/java/java/nio/channels/WritePendingException.java \
ojluni/src/main/java/java/nio/CharBuffer.java \
+ ojluni/src/main/java/java/nio/CharBufferSpliterator.java \
+ ojluni/src/main/java/java/nio/charset/CharacterCodingException.java \
+ ojluni/src/main/java/java/nio/charset/CharsetDecoder.java \
+ ojluni/src/main/java/java/nio/charset/CharsetEncoder.java \
+ ojluni/src/main/java/java/nio/charset/Charset.java \
+ ojluni/src/main/java/java/nio/charset/CoderMalfunctionError.java \
+ ojluni/src/main/java/java/nio/charset/CoderResult.java \
+ ojluni/src/main/java/java/nio/charset/CodingErrorAction.java \
+ ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java \
+ ojluni/src/main/java/java/nio/charset/MalformedInputException.java \
+ ojluni/src/main/java/java/nio/charset/spi/CharsetProvider.java \
+ ojluni/src/main/java/java/nio/charset/StandardCharsets.java \
+ ojluni/src/main/java/java/nio/charset/UnmappableCharacterException.java \
+ ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java \
ojluni/src/main/java/java/nio/DirectByteBuffer.java \
ojluni/src/main/java/java/nio/DoubleBuffer.java \
ojluni/src/main/java/java/nio/FloatBuffer.java \
@@ -335,62 +408,6 @@
ojluni/src/main/java/java/nio/ReadOnlyBufferException.java \
ojluni/src/main/java/java/nio/ShortBuffer.java \
ojluni/src/main/java/java/nio/StringCharBuffer.java \
- ojluni/src/main/java/java/nio/channels/AlreadyBoundException.java \
- ojluni/src/main/java/java/nio/channels/AlreadyConnectedException.java \
- ojluni/src/main/java/java/nio/channels/AsynchronousCloseException.java \
- ojluni/src/main/java/java/nio/channels/ByteChannel.java \
- ojluni/src/main/java/java/nio/channels/CancelledKeyException.java \
- ojluni/src/main/java/java/nio/channels/Channel.java \
- ojluni/src/main/java/java/nio/channels/Channels.java \
- ojluni/src/main/java/java/nio/channels/ClosedByInterruptException.java \
- ojluni/src/main/java/java/nio/channels/ClosedChannelException.java \
- ojluni/src/main/java/java/nio/channels/ClosedSelectorException.java \
- ojluni/src/main/java/java/nio/channels/ConnectionPendingException.java \
- ojluni/src/main/java/java/nio/channels/DatagramChannel.java \
- ojluni/src/main/java/java/nio/channels/FileChannel.java \
- ojluni/src/main/java/java/nio/channels/FileLock.java \
- ojluni/src/main/java/java/nio/channels/FileLockInterruptionException.java \
- ojluni/src/main/java/java/nio/channels/GatheringByteChannel.java \
- ojluni/src/main/java/java/nio/channels/IllegalBlockingModeException.java \
- ojluni/src/main/java/java/nio/channels/IllegalSelectorException.java \
- ojluni/src/main/java/java/nio/channels/InterruptibleChannel.java \
- ojluni/src/main/java/java/nio/channels/NetworkChannel.java \
- ojluni/src/main/java/java/nio/channels/NoConnectionPendingException.java \
- ojluni/src/main/java/java/nio/channels/NonReadableChannelException.java \
- ojluni/src/main/java/java/nio/channels/NonWritableChannelException.java \
- ojluni/src/main/java/java/nio/channels/NotYetBoundException.java \
- ojluni/src/main/java/java/nio/channels/NotYetConnectedException.java \
- ojluni/src/main/java/java/nio/channels/OverlappingFileLockException.java \
- ojluni/src/main/java/java/nio/channels/Pipe.java \
- ojluni/src/main/java/java/nio/channels/ReadableByteChannel.java \
- ojluni/src/main/java/java/nio/channels/ScatteringByteChannel.java \
- ojluni/src/main/java/java/nio/channels/SeekableByteChannel.java \
- ojluni/src/main/java/java/nio/channels/SelectableChannel.java \
- ojluni/src/main/java/java/nio/channels/SelectionKey.java \
- ojluni/src/main/java/java/nio/channels/Selector.java \
- ojluni/src/main/java/java/nio/channels/ServerSocketChannel.java \
- ojluni/src/main/java/java/nio/channels/SocketChannel.java \
- ojluni/src/main/java/java/nio/channels/UnresolvedAddressException.java \
- ojluni/src/main/java/java/nio/channels/UnsupportedAddressTypeException.java \
- ojluni/src/main/java/java/nio/channels/WritableByteChannel.java \
- ojluni/src/main/java/java/nio/channels/spi/AbstractInterruptibleChannel.java \
- ojluni/src/main/java/java/nio/channels/spi/AbstractSelectableChannel.java \
- ojluni/src/main/java/java/nio/channels/spi/AbstractSelectionKey.java \
- ojluni/src/main/java/java/nio/channels/spi/AbstractSelector.java \
- ojluni/src/main/java/java/nio/channels/spi/SelectorProvider.java \
- ojluni/src/main/java/java/nio/charset/CharacterCodingException.java \
- ojluni/src/main/java/java/nio/charset/Charset.java \
- ojluni/src/main/java/java/nio/charset/CharsetDecoder.java \
- ojluni/src/main/java/java/nio/charset/CharsetEncoder.java \
- ojluni/src/main/java/java/nio/charset/CoderMalfunctionError.java \
- ojluni/src/main/java/java/nio/charset/CoderResult.java \
- ojluni/src/main/java/java/nio/charset/CodingErrorAction.java \
- ojluni/src/main/java/java/nio/charset/IllegalCharsetNameException.java \
- ojluni/src/main/java/java/nio/charset/MalformedInputException.java \
- ojluni/src/main/java/java/nio/charset/StandardCharsets.java \
- ojluni/src/main/java/java/nio/charset/UnmappableCharacterException.java \
- ojluni/src/main/java/java/nio/charset/UnsupportedCharsetException.java \
- ojluni/src/main/java/java/nio/charset/spi/CharsetProvider.java \
ojluni/src/main/java/java/security/AccessControlContext.java \
ojluni/src/main/java/java/security/AccessControlException.java \
ojluni/src/main/java/java/security/AccessController.java \
@@ -648,6 +665,7 @@
ojluni/src/main/java/java/util/AbstractSet.java \
ojluni/src/main/java/java/util/ArrayDeque.java \
ojluni/src/main/java/java/util/ArrayList.java \
+ ojluni/src/main/java/java/util/ArrayPrefixHelpers.java \
ojluni/src/main/java/java/util/Arrays.java \
ojluni/src/main/java/java/util/ArraysParallelSortHelpers.java \
ojluni/src/main/java/java/util/BitSet.java \
@@ -1176,11 +1194,17 @@
ojluni/src/main/java/sun/nio/ch/AbstractPollArrayWrapper.java \
ojluni/src/main/java/sun/nio/ch/AbstractPollSelectorImpl.java \
ojluni/src/main/java/sun/nio/ch/AllocatedNativeObject.java \
+ ojluni/src/main/java/sun/nio/ch/AsynchronousChannelGroupImpl.java \
+ ojluni/src/main/java/sun/nio/ch/AsynchronousServerSocketChannelImpl.java \
+ ojluni/src/main/java/sun/nio/ch/AsynchronousSocketChannelImpl.java \
+ ojluni/src/main/java/sun/nio/ch/BsdAsynchronousChannelProvider.java \
+ ojluni/src/main/java/sun/nio/ch/Cancellable.java \
ojluni/src/main/java/sun/nio/ch/ChannelInputStream.java \
ojluni/src/main/java/sun/nio/ch/CompletedFuture.java \
ojluni/src/main/java/sun/nio/ch/DatagramChannelImpl.java \
ojluni/src/main/java/sun/nio/ch/DatagramDispatcher.java \
ojluni/src/main/java/sun/nio/ch/DatagramSocketAdaptor.java \
+ ojluni/src/main/java/sun/nio/ch/DefaultAsynchronousChannelProvider.java \
ojluni/src/main/java/sun/nio/ch/DefaultSelectorProvider.java \
ojluni/src/main/java/sun/nio/ch/DevPollArrayWrapper.java \
ojluni/src/main/java/sun/nio/ch/DevPollSelectorImpl.java \
@@ -1188,6 +1212,7 @@
ojluni/src/main/java/sun/nio/ch/DirectBuffer.java \
ojluni/src/main/java/sun/nio/ch/EPollArrayWrapper.java \
ojluni/src/main/java/sun/nio/ch/EPoll.java \
+ ojluni/src/main/java/sun/nio/ch/EPollPort.java \
ojluni/src/main/java/sun/nio/ch/EPollSelectorImpl.java \
ojluni/src/main/java/sun/nio/ch/EPollSelectorProvider.java \
ojluni/src/main/java/sun/nio/ch/ExtendedSocketOption.java \
@@ -1198,21 +1223,30 @@
ojluni/src/main/java/sun/nio/ch/FileKey.java \
ojluni/src/main/java/sun/nio/ch/FileLockImpl.java \
ojluni/src/main/java/sun/nio/ch/FileLockTable.java \
+ ojluni/src/main/java/sun/nio/ch/Groupable.java \
ojluni/src/main/java/sun/nio/ch/InheritedChannel.java \
ojluni/src/main/java/sun/nio/ch/Interruptible.java \
+ ojluni/src/main/java/sun/nio/ch/Invoker.java \
ojluni/src/main/java/sun/nio/ch/IOStatus.java \
ojluni/src/main/java/sun/nio/ch/IOUtil.java \
ojluni/src/main/java/sun/nio/ch/IOVecWrapper.java \
+ ojluni/src/main/java/sun/nio/ch/KQueue.java \
+ ojluni/src/main/java/sun/nio/ch/KQueuePort.java \
+ ojluni/src/main/java/sun/nio/ch/LinuxAsynchronousChannelProvider.java \
+ ojluni/src/main/java/sun/nio/ch/MembershipKeyImpl.java \
+ ojluni/src/main/java/sun/nio/ch/MembershipRegistry.java \
ojluni/src/main/java/sun/nio/ch/NativeDispatcher.java \
ojluni/src/main/java/sun/nio/ch/NativeObject.java \
ojluni/src/main/java/sun/nio/ch/NativeThread.java \
ojluni/src/main/java/sun/nio/ch/NativeThreadSet.java \
ojluni/src/main/java/sun/nio/ch/Net.java \
ojluni/src/main/java/sun/nio/ch/OptionKey.java \
+ ojluni/src/main/java/sun/nio/ch/PendingFuture.java \
ojluni/src/main/java/sun/nio/ch/PipeImpl.java \
ojluni/src/main/java/sun/nio/ch/PollArrayWrapper.java \
ojluni/src/main/java/sun/nio/ch/PollSelectorImpl.java \
ojluni/src/main/java/sun/nio/ch/PollSelectorProvider.java \
+ ojluni/src/main/java/sun/nio/ch/Port.java \
ojluni/src/main/java/sun/nio/ch/Reflect.java \
ojluni/src/main/java/sun/nio/ch/SelChImpl.java \
ojluni/src/main/java/sun/nio/ch/SelectionKeyImpl.java \
@@ -1227,6 +1261,8 @@
ojluni/src/main/java/sun/nio/ch/SocketOptionRegistry.java \
ojluni/src/main/java/sun/nio/ch/SourceChannelImpl.java \
ojluni/src/main/java/sun/nio/ch/ThreadPool.java \
+ ojluni/src/main/java/sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \
+ ojluni/src/main/java/sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
ojluni/src/main/java/sun/nio/ch/Util.java \
ojluni/src/main/java/sun/nio/cs/ArrayDecoder.java \
ojluni/src/main/java/sun/nio/cs/ArrayEncoder.java \
diff --git a/run-libcore-tests b/run-libcore-tests
index 90a2e41..996030a 100755
--- a/run-libcore-tests
+++ b/run-libcore-tests
@@ -21,9 +21,9 @@
$VOGAR \
--vm-arg -Xmx32M \
- --classpath out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/javalib.jar \
- --classpath out/target/common/obj/JAVA_LIBRARIES/sqlite-jdbc_intermediates/classes.jar \
- --classpath out/target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates/classes.jar \
- --classpath out/target/common/obj/JAVA_LIBRARIES/okhttp_intermediates/classes.jar \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/core-tests_intermediates/classes.jack \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/sqlite-jdbc_intermediates/classes.jack \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/bouncycastle_intermediates/classes.jack \
+ --classpath out/target/common/obj/JAVA_LIBRARIES/okhttp_intermediates/classes.jack \
$test_packages \
|| true
diff --git a/support/src/test/java/libcore/java/security/CpuFeatures.java b/support/src/test/java/libcore/java/security/CpuFeatures.java
index 30ca868..319056a 100644
--- a/support/src/test/java/libcore/java/security/CpuFeatures.java
+++ b/support/src/test/java/libcore/java/security/CpuFeatures.java
@@ -19,6 +19,8 @@
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
@@ -39,6 +41,19 @@
return true;
}
+ // If we're in an emulated ABI, Conscrypt's NativeCrypto might bridge to
+ // a library that has accelerated AES instructions. See if Conscrypt
+ // detects that condition.
+ try {
+ Class<?> nativeCrypto = Class.forName("com.android.org.conscrypt.NativeCrypto");
+ Method EVP_has_aes_hardware = nativeCrypto.getDeclaredMethod("EVP_has_aes_hardware");
+ return ((Integer) EVP_has_aes_hardware.invoke(null)) == 1;
+ } catch (ClassNotFoundException | NoSuchMethodException | SecurityException
+ | IllegalAccessException | IllegalArgumentException ignored) {
+ } catch (InvocationTargetException e) {
+ throw new IllegalArgumentException(e);
+ }
+
return false;
}
diff --git a/support/src/test/java/libcore/java/security/TestKeyStore.java b/support/src/test/java/libcore/java/security/TestKeyStore.java
index d6e6c91..2313a74 100644
--- a/support/src/test/java/libcore/java/security/TestKeyStore.java
+++ b/support/src/test/java/libcore/java/security/TestKeyStore.java
@@ -68,10 +68,12 @@
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.spec.AlgorithmParameterSpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
+import javax.crypto.spec.DHParameterSpec;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManager;
@@ -89,9 +91,6 @@
* accessible via TestKeyStore.get().
*/
public final class TestKeyStore extends Assert {
- /** Size of DH keys to generate for testing. */
- private static final int DH_KEY_SIZE_BITS = 1024;
-
/** Size of DSA keys to generate for testing. */
private static final int DSA_KEY_SIZE_BITS = 1024;
@@ -101,6 +100,35 @@
/** Size of RSA keys to generate for testing. */
private static final int RSA_KEY_SIZE_BITS = 1024;
+ // Generated with: openssl dhparam -C 1024
+ private static final BigInteger DH_PARAMS_P = new BigInteger(1, new byte[] {
+ (byte) 0xA2, (byte) 0x31, (byte) 0xB4, (byte) 0xB3, (byte) 0x6D, (byte) 0x9B,
+ (byte) 0x7E, (byte) 0xF4, (byte) 0xE7, (byte) 0x21, (byte) 0x51, (byte) 0x40,
+ (byte) 0xEB, (byte) 0xC6, (byte) 0xB6, (byte) 0xD6, (byte) 0x54, (byte) 0x56,
+ (byte) 0x72, (byte) 0xBE, (byte) 0x43, (byte) 0x18, (byte) 0x30, (byte) 0x5C,
+ (byte) 0x15, (byte) 0x5A, (byte) 0xF9, (byte) 0x19, (byte) 0x62, (byte) 0xAD,
+ (byte) 0xF4, (byte) 0x29, (byte) 0xCB, (byte) 0xC6, (byte) 0xF6, (byte) 0x64,
+ (byte) 0x0B, (byte) 0x9D, (byte) 0x23, (byte) 0x80, (byte) 0xF9, (byte) 0x5B,
+ (byte) 0x1C, (byte) 0x1C, (byte) 0x6A, (byte) 0xB4, (byte) 0xEA, (byte) 0xB9,
+ (byte) 0x80, (byte) 0x98, (byte) 0x8B, (byte) 0xAF, (byte) 0x15, (byte) 0xA8,
+ (byte) 0x5C, (byte) 0xC4, (byte) 0xB0, (byte) 0x41, (byte) 0x29, (byte) 0x66,
+ (byte) 0x9F, (byte) 0x9F, (byte) 0x1F, (byte) 0x88, (byte) 0x50, (byte) 0x97,
+ (byte) 0x38, (byte) 0x0B, (byte) 0x01, (byte) 0x16, (byte) 0xD6, (byte) 0x84,
+ (byte) 0x1D, (byte) 0x48, (byte) 0x6F, (byte) 0x7C, (byte) 0x06, (byte) 0x8C,
+ (byte) 0x6E, (byte) 0x68, (byte) 0xCD, (byte) 0x38, (byte) 0xE6, (byte) 0x22,
+ (byte) 0x30, (byte) 0x61, (byte) 0x37, (byte) 0x02, (byte) 0x3D, (byte) 0x47,
+ (byte) 0x62, (byte) 0xCE, (byte) 0xB9, (byte) 0x1A, (byte) 0x69, (byte) 0x9D,
+ (byte) 0xA1, (byte) 0x9F, (byte) 0x10, (byte) 0xA1, (byte) 0xAA, (byte) 0x70,
+ (byte) 0xF7, (byte) 0x27, (byte) 0x9C, (byte) 0xD4, (byte) 0xA5, (byte) 0x15,
+ (byte) 0xE2, (byte) 0x15, (byte) 0x0C, (byte) 0x20, (byte) 0x90, (byte) 0x08,
+ (byte) 0xB6, (byte) 0xF5, (byte) 0xDF, (byte) 0x1C, (byte) 0xCB, (byte) 0x82,
+ (byte) 0x6D, (byte) 0xC0, (byte) 0xE1, (byte) 0xBD, (byte) 0xCC, (byte) 0x4A,
+ (byte) 0x76, (byte) 0xE3,
+ });
+
+ // generator of 2
+ private static final BigInteger DH_PARAMS_G = BigInteger.valueOf(2);
+
private static TestKeyStore ROOT_CA;
private static TestKeyStore INTERMEDIATE_CA;
private static TestKeyStore INTERMEDIATE_CA_2;
@@ -174,6 +202,7 @@
.aliasPrefix("RootCA")
.subject("CN=Test Root Certificate Authority")
.ca(true)
+ .certificateSerialNumber(BigInteger.valueOf(1))
.build();
INTERMEDIATE_CA = new Builder()
.aliasPrefix("IntermediateCA")
@@ -181,12 +210,14 @@
.ca(true)
.signer(ROOT_CA.getPrivateKey("RSA", "RSA"))
.rootCa(ROOT_CA.getRootCertificate("RSA"))
+ .certificateSerialNumber(BigInteger.valueOf(2))
.build();
SERVER = new Builder()
.aliasPrefix("server")
.signer(INTERMEDIATE_CA.getPrivateKey("RSA", "RSA"))
.rootCa(INTERMEDIATE_CA.getRootCertificate("RSA"))
.addSubjectAltNameIpAddress(LOCAL_HOST_ADDRESS)
+ .certificateSerialNumber(BigInteger.valueOf(3))
.build();
CLIENT = new TestKeyStore(createClient(INTERMEDIATE_CA.keyStore), null, null);
CLIENT_CERTIFICATE = new Builder()
@@ -293,6 +324,8 @@
= new ArrayList<GeneralSubtree>();
private final List<GeneralSubtree> excludedNameConstraints
= new ArrayList<GeneralSubtree>();
+ // Generated randomly if not set
+ private BigInteger certificateSerialNumber = null;
public Builder() {
subject = localhost();
@@ -386,6 +419,11 @@
new GeneralName(GeneralName.iPAddress, new DEROctetString(ipAddress)));
}
+ public Builder certificateSerialNumber(BigInteger certificateSerialNumber) {
+ this.certificateSerialNumber = certificateSerialNumber;
+ return this;
+ }
+
public TestKeyStore build() {
try {
if (StandardNames.IS_RI) {
@@ -483,16 +521,17 @@
} else {
if (privateEntry == null) {
// 1a.) we make the keys
- int keySize;
+ int keySize = -1;
+ AlgorithmParameterSpec spec = null;
if (keyAlgorithm.equals("RSA")) {
keySize = RSA_KEY_SIZE_BITS;
} else if (keyAlgorithm.equals("DH_RSA")) {
- keySize = DH_KEY_SIZE_BITS;
+ spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G);
keyAlgorithm = "DH";
} else if (keyAlgorithm.equals("DSA")) {
keySize = DSA_KEY_SIZE_BITS;
} else if (keyAlgorithm.equals("DH_DSA")) {
- keySize = DH_KEY_SIZE_BITS;
+ spec = new DHParameterSpec(DH_PARAMS_P, DH_PARAMS_G);
keyAlgorithm = "DH";
} else if (keyAlgorithm.equals("EC")) {
keySize = EC_KEY_SIZE_BITS;
@@ -504,7 +543,13 @@
}
KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyAlgorithm);
- kpg.initialize(keySize, new SecureRandom());
+ if (spec != null) {
+ kpg.initialize(spec);
+ } else if (keySize != -1) {
+ kpg.initialize(keySize);
+ } else {
+ throw new AssertionError("Must either have set algorithm parameters or key size!");
+ }
KeyPair kp = kpg.generateKeyPair();
privateKey = kp.getPrivate();
@@ -523,7 +568,8 @@
x509c = createCertificate(publicKey, signingKey, subject, issuer, keyUsage, ca,
extendedKeyUsages, criticalExtendedKeyUsages,
subjectAltNames,
- permittedNameConstraints, excludedNameConstraints);
+ permittedNameConstraints, excludedNameConstraints,
+ certificateSerialNumber);
}
X509Certificate[] x509cc;
@@ -565,7 +611,8 @@
new ArrayList<Boolean>(),
new ArrayList<GeneralName>(),
new ArrayList<GeneralSubtree>(),
- new ArrayList<GeneralSubtree>());
+ new ArrayList<GeneralSubtree>(),
+ null /* serialNumber, generated randomly */);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -582,7 +629,8 @@
List<Boolean> criticalExtendedKeyUsages,
List<GeneralName> subjectAltNames,
List<GeneralSubtree> permittedNameConstraints,
- List<GeneralSubtree> excludedNameConstraints) throws Exception {
+ List<GeneralSubtree> excludedNameConstraints,
+ BigInteger serialNumber) throws Exception {
// Note that there is no way to programmatically make a
// Certificate using java.* or javax.* APIs. The
// CertificateFactory interface assumes you want to read
@@ -596,11 +644,6 @@
Date start = new Date(now - millisPerDay);
Date end = new Date(now + millisPerDay);
- // Generate a random serial number.
- byte[] serialBytes = new byte[16];
- new SecureRandom().nextBytes(serialBytes);
- BigInteger serial = new BigInteger(1, serialBytes);
-
String keyAlgorithm = privateKey.getAlgorithm();
String signatureAlgorithm;
if (keyAlgorithm.equals("RSA")) {
@@ -622,7 +665,12 @@
x509cg.setNotAfter(end);
x509cg.setPublicKey(publicKey);
x509cg.setSignatureAlgorithm(signatureAlgorithm);
- x509cg.setSerialNumber(serial);
+ if (serialNumber == null) {
+ byte[] serialBytes = new byte[16];
+ new SecureRandom().nextBytes(serialBytes);
+ serialNumber = new BigInteger(1, serialBytes);
+ }
+ x509cg.setSerialNumber(serialNumber);
if (keyUsage != 0) {
x509cg.addExtension(X509Extensions.KeyUsage,
true,