diff options
119 files changed, 4532 insertions, 4078 deletions
diff --git a/archive/src/main/java/java/util/jar/JarFile.java b/archive/src/main/java/java/util/jar/JarFile.java index d6e8339..6f4eb83 100644 --- a/archive/src/main/java/java/util/jar/JarFile.java +++ b/archive/src/main/java/java/util/jar/JarFile.java @@ -68,6 +68,10 @@ public class JarFile extends ZipFile { private JarVerifier.VerifierEntry entry; + // BEGIN android-added + private boolean done = false; + // END android-added + JarFileInputStream(InputStream is, ZipEntry ze, JarVerifier.VerifierEntry e) { super(is); @@ -78,6 +82,10 @@ public class JarFile extends ZipFile { @Override public int read() throws IOException { + // BEGIN android-changed + if (done) { + return -1; + } if (count > 0) { int r = super.read(); if (r != -1) { @@ -87,16 +95,24 @@ public class JarFile extends ZipFile { count = 0; } if (count == 0) { + done = true; entry.verify(); } return r; } else { + done = true; + entry.verify(); return -1; } + // END android-changed } @Override public int read(byte[] buf, int off, int nbytes) throws IOException { + // BEGIN android-changed + if (done) { + return -1; + } if (count > 0) { int r = super.read(buf, off, nbytes); if (r != -1) { @@ -110,22 +126,25 @@ public class JarFile extends ZipFile { count = 0; } if (count == 0) { + done = true; entry.verify(); } return r; } else { + done = true; + entry.verify(); return -1; } + // END android-changed } // BEGIN android-added @Override public int available() throws IOException { - if (count > 0) { - return super.available(); - } else { + if (done) { return 0; } + return super.available(); } // END android-added diff --git a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java index 96321a4..d2a5110 100644 --- a/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java +++ b/archive/src/test/java/org/apache/harmony/archive/tests/java/util/jar/JarFileTest.java @@ -18,10 +18,15 @@ package org.apache.harmony.archive.tests.java.util.jar; import dalvik.annotation.AndroidOnly; -import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; +import junit.framework.TestCase; + +import tests.support.Support_PlatformFile; +import tests.support.resource.Support_Resources; + import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -41,10 +46,6 @@ import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; -import junit.framework.TestCase; -import tests.support.Support_PlatformFile; -import tests.support.resource.Support_Resources; - @TestTargetClass(JarFile.class) public class JarFileTest extends TestCase { @@ -74,14 +75,22 @@ public class JarFileTest extends TestCase { private final String jarName5 = "hyts_signed_inc.jar"; - private final String integrateJar = "Integrate.jar"; - private final String entryName = "foo/bar/A.class"; private final String entryName3 = "coucou/FileAccess.class"; + private final String integrateJar = "Integrate.jar"; + private final String integrateJarEntry = "Test.class"; + private final String emptyEntryJar = "EmptyEntries_signed.jar"; + + private final String emptyEntry1 = "subfolder/internalSubset01.js"; + + private final String emptyEntry2 = "svgtest.js"; + + private final String emptyEntry3 = "svgunit.js"; + private File resources; // custom security manager @@ -1061,4 +1070,33 @@ public class JarFileTest extends TestCase { // expected } } + + /** + * The jar is intact, but the entry object is modified. + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Regression test for issue introduced by HAROMNY-4569. " + + "signed archives containing files with size 0 could not get verified", + method = "getInputStream", + args = {ZipEntry.class} + ) + public void testJarVerificationEmptyEntry() throws IOException { + Support_Resources.copyFile(resources, null, emptyEntryJar); + File f = new File(resources, emptyEntryJar); + + JarFile jarFile = new JarFile(f); + + ZipEntry zipEntry = jarFile.getJarEntry(emptyEntry1); + int res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); + assertEquals("Wrong length of empty jar entry", -1, res); + + zipEntry = jarFile.getJarEntry(emptyEntry2); + res = jarFile.getInputStream(zipEntry).read(new byte[100], 0, 100); + assertEquals("Wrong length of empty jar entry", -1, res); + + zipEntry = jarFile.getJarEntry(emptyEntry3); + res = jarFile.getInputStream(zipEntry).read(); + assertEquals("Wrong length of empty jar entry", -1, res); + } } diff --git a/crypto/src/main/java/javax/crypto/BadPaddingException.java b/crypto/src/main/java/javax/crypto/BadPaddingException.java index 19fdaa8..5e2dd38 100644 --- a/crypto/src/main/java/javax/crypto/BadPaddingException.java +++ b/crypto/src/main/java/javax/crypto/BadPaddingException.java @@ -22,8 +22,6 @@ import java.security.GeneralSecurityException; /** * The exception that is thrown when a padding mechanism is expected for the * input data, but the input data does not have the proper padding bytes. - * - * @since Android 1.0 */ public class BadPaddingException extends GeneralSecurityException { @@ -37,7 +35,6 @@ public class BadPaddingException extends GeneralSecurityException { * * @param msg * the message - * @since Android 1.0 */ public BadPaddingException(String msg) { super(msg); @@ -45,8 +42,6 @@ public class BadPaddingException extends GeneralSecurityException { /** * Creates a new instance of {@code BadPaddingException} with no message. - * - * @since Android 1.0 */ public BadPaddingException() { } diff --git a/crypto/src/main/java/javax/crypto/Cipher.java b/crypto/src/main/java/javax/crypto/Cipher.java index ae72226..8e084ae 100644 --- a/crypto/src/main/java/javax/crypto/Cipher.java +++ b/crypto/src/main/java/javax/crypto/Cipher.java @@ -61,58 +61,41 @@ import org.apache.harmony.security.fortress.Engine; * to be processed at a time can be optionally specified by appending it to the * mode name. e.g. <i>"AES/CFB8/NoPadding"</i>. If no number is specified, a * provider specific default value is used. - * </p> - * - * @since Android 1.0 */ public class Cipher { /** * Constant for decryption operation mode. - * - * @since Android 1.0 */ public static final int DECRYPT_MODE = 2; /** * Constant for encryption operation mode. - * - * @since Android 1.0 */ public static final int ENCRYPT_MODE = 1; /** * Constant indicating that the key to be unwrapped is a private key. - * - * @since Android 1.0 */ public static final int PRIVATE_KEY = 2; /** * Constant indicating that the key to be unwrapped is a public key. - * - * @since Android 1.0 */ public static final int PUBLIC_KEY = 1; /** * Constant indicating that the key to be unwrapped is a secret key. - * - * @since Android 1.0 */ public static final int SECRET_KEY = 3; /** * Constant for key unwrapping operation mode. - * - * @since Android 1.0 */ public static final int UNWRAP_MODE = 4; /** * Constant for key wrapping operation mode. - * - * @since Android 1.0 */ public static final int WRAP_MODE = 3; @@ -147,7 +130,7 @@ public class Cipher { /** * Creates a new Cipher instance. - * + * * @param cipherSpi * the implementation delegate of the cipher. * @param provider @@ -157,7 +140,6 @@ public class Cipher { * @throws NullPointerException * if either cipherSpi is {@code null} or provider is {@code * null} and {@code cipherSpi} is a {@code NullCipherSpi}. - * @since Android 1.0 */ protected Cipher(CipherSpi cipherSpi, Provider provider, String transformation) { @@ -178,7 +160,7 @@ public class Cipher { * transformation. The first found provider providing the transformation is * used to create the cipher. If no provider is found an exception is * thrown. - * + * * @param transformation * the name of the transformation to create a cipher for. * @return a cipher for the requested transformation. @@ -189,7 +171,6 @@ public class Cipher { * @throws NoSuchPaddingException * if no installed provider can provide the padding scheme in * the <i>transformation</i>. - * @since Android 1.0 */ public static final Cipher getInstance(String transformation) throws NoSuchAlgorithmException, NoSuchPaddingException { @@ -199,7 +180,7 @@ public class Cipher { /** * Creates a new cipher for the specified transformation provided by the * specified provider. - * + * * @param transformation * the name of the transformation to create a cipher for. * @param provider @@ -216,7 +197,6 @@ public class Cipher { * is not available. * @throws IllegalArgumentException * if the specified provider is {@code null}. - * @since Android 1.0 */ public static final Cipher getInstance(String transformation, String provider) throws NoSuchAlgorithmException, @@ -235,7 +215,7 @@ public class Cipher { /** * Creates a new cipher for the specified transformation. - * + * * @param transformation * the name of the transformation to create a cipher for. * @param provider @@ -250,7 +230,6 @@ public class Cipher { * is not available. * @throws IllegalArgumentException * if the provider is {@code null}. - * @since Android 1.0 */ public static final Cipher getInstance(String transformation, Provider provider) throws NoSuchAlgorithmException, @@ -373,9 +352,8 @@ public class Cipher { /** * Returns the provider of this cipher instance. - * + * * @return the provider of this cipher instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -386,10 +364,8 @@ public class Cipher { * <p> * This is the name of the <i>transformation</i> argument used in the * {@code getInstance} call creating this object. - * </p> - * + * * @return the name of the algorithm of this cipher instance. - * @since Android 1.0. */ public final String getAlgorithm() { return transformation; @@ -397,9 +373,8 @@ public class Cipher { /** * Returns this ciphers block size (in bytes). - * + * * @return this ciphers block size. - * @since Android 1.0 */ public final int getBlockSize() { return spiImpl.engineGetBlockSize(); @@ -408,13 +383,12 @@ public class Cipher { /** * Returns the length in bytes an output buffer needs to be when this cipher * is updated with {@code inputLen} bytes. - * + * * @param inputLen * the number of bytes of the input. * @return the output buffer length for the input length. * @throws IllegalStateException * if this cipher instance is in an invalid state. - * @since Android 1.0 */ public final int getOutputSize(int inputLen) { if (mode == 0) { @@ -426,9 +400,8 @@ public class Cipher { /** * Returns the <i>initialization vector</i> for this cipher instance. - * + * * @return the <i>initialization vector</i> for this cipher instance. - * @since Android 1.0 */ public final byte[] getIV() { return spiImpl.engineGetIV(); @@ -440,11 +413,10 @@ public class Cipher { * These may be a the same parameters that were used to create this cipher * instance, or may be a combination of default and random parameters, * depending on the underlying cipher implementation. - * + * * @return the parameters that where used to create this cipher instance, or * {@code null} if this cipher instance does not have any * parameters. - * @since Android 1.0 */ public final AlgorithmParameters getParameters() { return spiImpl.engineGetParameters(); @@ -452,9 +424,8 @@ public class Cipher { /** * Returns the exemption mechanism associated with this cipher. - * + * * @return currently {@code null} - * @since Android 1.0 */ public final ExemptionMechanism getExemptionMechanism() { //FIXME implement getExemptionMechanism @@ -473,7 +444,7 @@ public class Cipher { * The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters or random values * that the specified key can not provide, the underlying implementation of * this cipher is supposed to generate the required parameters (using its @@ -483,8 +454,7 @@ public class Cipher { * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling its {@code init} * method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -494,7 +464,6 @@ public class Cipher { * @throws InvalidKeyException * if the specified key can not be used to initialize this * cipher instance. - * @since Android 1.0 */ public final void init(int opmode, Key key) throws InvalidKeyException { if (sec_rand == null) { @@ -513,7 +482,7 @@ public class Cipher { * The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters or random values * that the specified key can not provide, the underlying implementation of * this cipher is supposed to generate the required parameters (using its @@ -523,8 +492,7 @@ public class Cipher { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -538,7 +506,6 @@ public class Cipher { * cipher instance. * @throws InvalidParameterException * if the specified opmode is invalid. - * @since Android 1.0 */ public final void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException { @@ -559,7 +526,7 @@ public class Cipher { * <p> * The cipher is initialized for the specified operational mode (one of: * encryption, decryption, key wrapping or key unwrapping). - * </p> + * <p> * If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random @@ -568,8 +535,7 @@ public class Cipher { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -584,7 +550,6 @@ public class Cipher { * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. - * @since Android 1.0 */ public final void init(int opmode, Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { @@ -611,7 +576,7 @@ public class Cipher { * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling it {@code init} * method. - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -630,7 +595,6 @@ public class Cipher { * cipher. * @throws InvalidParameterException * if the specified {@code opmode} is invalid. - * @since Android 1.0 */ public final void init(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, @@ -656,7 +620,7 @@ public class Cipher { * The cipher is initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random @@ -666,8 +630,7 @@ public class Cipher { * init} methods, the state of the instance is overridden, meaning that it * is equivalent to creating a new instance and calling it {@code init} * method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -682,7 +645,6 @@ public class Cipher { * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. - * @since Android 1.0 */ public final void init(int opmode, Key key, AlgorithmParameters params) throws InvalidKeyException, InvalidAlgorithmParameterException { @@ -699,7 +661,7 @@ public class Cipher { * The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random @@ -708,8 +670,7 @@ public class Cipher { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -728,7 +689,6 @@ public class Cipher { * cipher. * @throws InvalidParameterException * if the specified {@code opmode} is invalid. - * @since Android 1.0 */ public final void init(int opmode, Key key, AlgorithmParameters params, SecureRandom random) throws InvalidKeyException, @@ -768,7 +728,7 @@ public class Cipher { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -778,7 +738,6 @@ public class Cipher { * @throws InvalidKeyException * if the public key in the certificate can not be used to * initialize this cipher instance. - * @since Android 1.0 */ public final void init(int opmode, Certificate certificate) throws InvalidKeyException { @@ -795,7 +754,7 @@ public class Cipher { * The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * It the type of the certificate is X.509 and the certificate has a <i>key * usage</i> extension field marked as critical, the specified {@code * opmode} has the be enabled for this key, otherwise an {@code @@ -806,11 +765,11 @@ public class Cipher { * cipher is supposed to generate the required parameters (using its * provider or random values). Random values are generated using {@code * random}. - * </p> + * <p> * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -822,7 +781,6 @@ public class Cipher { * @throws InvalidKeyException * if the public key in the certificate can not be used to * initialize this cipher instance. - * @since Android 1.0 */ public final void init(int opmode, Certificate certificate, SecureRandom random) throws InvalidKeyException { @@ -874,7 +832,7 @@ public class Cipher { /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are returned. - * + * * @param input * the input bytes to transform. * @return the transformed bytes in a new buffer, or {@code null} if the @@ -884,7 +842,6 @@ public class Cipher { * decryption. * @throws IllegalArgumentException * if the input is {@code null}. - * @since Android 1.0 */ public final byte[] update(byte[] input) { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { @@ -903,7 +860,7 @@ public class Cipher { /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are returned. - * + * * @param input * the input bytes to transform. * @param inputOffset @@ -919,7 +876,6 @@ public class Cipher { * if the input is {@code null}, or if {@code inputOffset} and * {@code inputLen} do not specify a valid chunk in the input * buffer. - * @since Android 1.0 */ public final byte[] update(byte[] input, int inputOffset, int inputLen) { if (mode != ENCRYPT_MODE && mode != DECRYPT_MODE) { @@ -949,8 +905,7 @@ public class Cipher { * a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. - * </p> - * + * * @param input * the input bytes to transform. * @param inputOffset @@ -969,7 +924,6 @@ public class Cipher { * if the input is {@code null}, the output is {@code null}, or * if {@code inputOffset} and {@code inputLen} do not specify a * valid chunk in the input buffer. - * @since Android 1.0 */ public final int update(byte[] input, int inputOffset, int inputLen, byte[] output) throws ShortBufferException { @@ -984,8 +938,7 @@ public class Cipher { * a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. - * </p> - * + * * @param input * the input bytes to transform. * @param inputOffset @@ -1006,7 +959,6 @@ public class Cipher { * if the input is {@code null}, the output is {@code null}, or * if {@code inputOffset} and {@code inputLen} do not specify a * valid chunk in the input buffer. - * @since Android 1.0 */ public final int update(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { @@ -1046,8 +998,7 @@ public class Cipher { * bytes a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. - * </p> - * + * * @param input * the input buffer to transform. * @param output @@ -1061,7 +1012,6 @@ public class Cipher { * @throws IllegalArgumentException * if the input buffer and the output buffer are the identical * object. - * @since Android 1.0 */ public final int update(ByteBuffer input, ByteBuffer output) throws ShortBufferException { @@ -1081,8 +1031,7 @@ public class Cipher { * <p> * Processes any bytes that may have been buffered in previous {@code * update} calls. - * </p> - * + * * @return the final bytes from the transformation. * @throws IllegalBlockSizeException * if the size of the resulting bytes is not a multiple of the @@ -1092,7 +1041,6 @@ public class Cipher { * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. - * @since Android 1.0 */ public final byte[] doFinal() throws IllegalBlockSizeException, BadPaddingException { @@ -1108,9 +1056,9 @@ public class Cipher { * <p> * Processes any bytes that may have been buffered in previous {@code * update} calls. - * </p> + * <p> * The final transformed bytes are stored in the {@code output} buffer. - * + * * @param output * the output buffer. * @param outputOffset @@ -1126,7 +1074,6 @@ public class Cipher { * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. - * @since Android 1.0 */ public final int doFinal(byte[] output, int outputOffset) throws IllegalBlockSizeException, ShortBufferException, @@ -1147,8 +1094,7 @@ public class Cipher { * <p> * Processes the bytes in {@code input} buffer, and any bytes that have been * buffered in previous {@code update} calls. - * </p> - * + * * @param input * the input buffer. * @return the final bytes from the transformation. @@ -1160,7 +1106,6 @@ public class Cipher { * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. - * @since Android 1.0 */ public final byte[] doFinal(byte[] input) throws IllegalBlockSizeException, BadPaddingException { @@ -1177,7 +1122,7 @@ public class Cipher { * Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. - * + * * @param input * the input buffer. * @param inputOffset @@ -1196,7 +1141,6 @@ public class Cipher { * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. - * @since Android 1.0 */ public final byte[] doFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException { @@ -1218,7 +1162,7 @@ public class Cipher { * Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. - * + * * @param input * the input buffer. * @param inputOffset @@ -1241,7 +1185,6 @@ public class Cipher { * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. - * @since Android 1.0 */ public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output) throws ShortBufferException, @@ -1255,8 +1198,7 @@ public class Cipher { * Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. - * </p> - * + * * @param input * the input buffer. * @param inputOffset @@ -1281,7 +1223,6 @@ public class Cipher { * @throws IllegalArgumentException * if {@code inputOffset} and {@code inputLen} do not specify an * valid chunk in the input buffer. - * @since Android 1.0 */ public final int doFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException, @@ -1306,8 +1247,7 @@ public class Cipher { * {@code input.position()}, and any bytes that have been buffered in * previous {@code update} calls. The transformed bytes are placed into * {@code output} buffer. - * </p> - * + * * @param input * the input buffer. * @param output @@ -1326,7 +1266,6 @@ public class Cipher { * @throws IllegalStateException * if this cipher instance is not initialized for encryption or * decryption. - * @since Android 1.0 */ public final int doFinal(ByteBuffer input, ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, @@ -1344,7 +1283,7 @@ public class Cipher { /** * Wraps a key using this cipher instance. - * + * * @param key * the key to wrap. * @return the wrapped key. @@ -1355,7 +1294,6 @@ public class Cipher { * if this cipher instance can not wrap this key. * @throws IllegalStateException * if this cipher instance is not initialized for wrapping. - * @since Android 1.0 */ public final byte[] wrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { @@ -1368,7 +1306,7 @@ public class Cipher { /** * Unwraps a key using this cipher instance. - * + * * @param wrappedKey * the wrapped key to unwrap. * @param wrappedKeyAlgorithm @@ -1386,7 +1324,6 @@ public class Cipher { * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. * @throws IllegalStateException * if this cipher instance is not initialized for unwrapping. - * @since Android 1.0 */ public final Key unwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) throws InvalidKeyException, @@ -1401,7 +1338,7 @@ public class Cipher { /** * Returns the maximum key length for the specified transformation. - * + * * @param transformation * the transformation name. * @return the maximum key length, currently {@code Integer.MAX_VALUE}. @@ -1410,7 +1347,6 @@ public class Cipher { * be found. * @throws NullPointerException * if {@code transformation} is {@code null}. - * @since Android 1.0 */ public static final int getMaxAllowedKeyLength(String transformation) throws NoSuchAlgorithmException { @@ -1425,7 +1361,7 @@ public class Cipher { /** * Returns the maximum cipher parameter value for the specified * transformation. If there is no maximum limit, {@code null} is returned. - * + * * @param transformation * the transformation name. * @return a parameter spec holding the maximum value or {@code null}. @@ -1435,7 +1371,6 @@ public class Cipher { * be found. * @throws NullPointerException * if {@code transformation} is {@code null}. - * @since Android 1.0 */ public static final AlgorithmParameterSpec getMaxAllowedParameterSpec( String transformation) throws NoSuchAlgorithmException { diff --git a/crypto/src/main/java/javax/crypto/CipherInputStream.java b/crypto/src/main/java/javax/crypto/CipherInputStream.java index ca64c49..b2c626d 100644 --- a/crypto/src/main/java/javax/crypto/CipherInputStream.java +++ b/crypto/src/main/java/javax/crypto/CipherInputStream.java @@ -32,9 +32,6 @@ import java.security.GeneralSecurityException; * by a {@code CipherInputStream}. For example, if a cipher initialized for * decryption is used with a {@code CipherInputStream}, the {@code * CipherInputStream} tries to read the data an decrypt them before returning. - * </p> - * - * @since Android 1.0 */ public class CipherInputStream extends FilterInputStream { @@ -48,12 +45,11 @@ public class CipherInputStream extends FilterInputStream { /** * Creates a new {@code CipherInputStream} instance for an {@code * InputStream} and a cipher. - * + * * @param is * the input stream to read data from. * @param c * the cipher to process the data with. - * @since Android 1.0 */ public CipherInputStream(InputStream is, Cipher c) { super(is); @@ -65,11 +61,9 @@ public class CipherInputStream extends FilterInputStream { * InputStream} without a cipher. * <p> * A {@code NullCipher} is created and used to process the data. - * </p> - * + * * @param is * the input stream to read data from. - * @since Android 1.0 */ protected CipherInputStream(InputStream is) { this(is, new NullCipher()); @@ -77,11 +71,10 @@ public class CipherInputStream extends FilterInputStream { /** * Reads the next byte from this cipher input stream. - * + * * @return the next byte, or {@code -1} if the end of the stream is reached. * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public int read() throws IOException { @@ -114,14 +107,13 @@ public class CipherInputStream extends FilterInputStream { /** * Reads the next {@code b.length} bytes from this input stream into buffer * {@code b}. - * + * * @param b * the buffer to be filled with data. * @return the number of bytes filled into buffer {@code b}, or {@code -1} * if the end of the stream is reached. * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public int read(byte[] b) throws IOException { @@ -134,8 +126,7 @@ public class CipherInputStream extends FilterInputStream { * <p> * if {@code b} is {@code null}, the next {@code len} bytes are read and * discarded. - * </p> - * + * * @param b * the buffer to be filled with data. * @param off @@ -148,7 +139,6 @@ public class CipherInputStream extends FilterInputStream { * if an error occurs. * @throws NullPointerException * if the underlying input stream is {@code null}. - * @since Android 1.0 */ @Override public int read(byte[] b, int off, int len) throws IOException { @@ -175,15 +165,12 @@ public class CipherInputStream extends FilterInputStream { * The number of bytes skipped depends on the result of a call to * {@link CipherInputStream#available() available}. The smaller of n and the * result are the number of bytes being skipped. - * </p> - * Skipping is (currently) not supported in Android. - * + * * @param n * the number of bytes that should be skipped. * @return the number of bytes actually skipped. * @throws IOException * if an error occurs - * @since Android 1.0 */ @Override public long skip(long n) throws IOException { @@ -199,13 +186,11 @@ public class CipherInputStream extends FilterInputStream { } /** - * Returns the number of bytes available without blocking. It (currently) - * always returns {@code 0} in Android. - * + * Returns the number of bytes available without blocking. + * * @return the number of bytes available, currently zero. * @throws IOException * if an error occurs - * @since Android 1.0 */ @Override public int available() throws IOException { @@ -215,10 +200,9 @@ public class CipherInputStream extends FilterInputStream { /** * Closes this {@code CipherInputStream}, also closes the underlying input * stream and call {@code doFinal} on the cipher object. - * + * * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public void close() throws IOException { @@ -232,15 +216,15 @@ public class CipherInputStream extends FilterInputStream { } /** - * Returns whether this input stream supports {@code mark} and {@code reset} - * , which it does not. - * + * Returns whether this input stream supports {@code mark} and + * {@code reset}, which it does not. + * * @return false, since this input stream does not support {@code mark} and * {@code reset}. - * @since Android 1.0 */ @Override public boolean markSupported() { return false; } } + diff --git a/crypto/src/main/java/javax/crypto/CipherOutputStream.java b/crypto/src/main/java/javax/crypto/CipherOutputStream.java index 8bce42b..1f95b99 100644 --- a/crypto/src/main/java/javax/crypto/CipherOutputStream.java +++ b/crypto/src/main/java/javax/crypto/CipherOutputStream.java @@ -31,9 +31,6 @@ import javax.crypto.NullCipher; * by a {@code CipherOutputStream}. For example, if a cipher initialized for * encryption is used with a {@code CipherOutputStream}, the {@code * CipherOutputStream} tries to encrypt the data writing it out. - * </p> - * - * @since Android 1.0 */ public class CipherOutputStream extends FilterOutputStream { @@ -43,12 +40,11 @@ public class CipherOutputStream extends FilterOutputStream { /** * Creates a new {@code CipherOutputStream} instance for an {@code * OutputStream} and a {@code Cipher}. - * + * * @param os * the output stream to write data to. * @param c * the cipher to process the data with. - * @since Android 1.0 */ public CipherOutputStream(OutputStream os, Cipher c) { super(os); @@ -60,11 +56,9 @@ public class CipherOutputStream extends FilterOutputStream { * OutputStream} without a cipher. * <p> * A {@code NullCipher} is created to process the data. - * </p> - * + * * @param os * the output stream to write the data to. - * @since Android 1.0 */ protected CipherOutputStream(OutputStream os) { this(os, new NullCipher()); @@ -72,12 +66,11 @@ public class CipherOutputStream extends FilterOutputStream { /** * Writes the single byte to this cipher output stream. - * + * * @param b * the byte to write. * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public void write(int b) throws IOException { @@ -91,12 +84,11 @@ public class CipherOutputStream extends FilterOutputStream { /** * Writes the buffer of bytes to this cipher output stream. - * + * * @param b * the buffer of bytes. * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public void write(byte[] b) throws IOException { @@ -106,7 +98,7 @@ public class CipherOutputStream extends FilterOutputStream { /** * Writes the {@code len} bytes from buffer {@code b} starting at offset * {@code off} to this cipher output stream. - * + * * @param b * the buffer. * @param off @@ -115,7 +107,6 @@ public class CipherOutputStream extends FilterOutputStream { * the number of bytes. * @throws IOException * if an error occurs. - * @since Android 1.0 */ @Override public void write(byte[] b, int off, int len) throws IOException { @@ -130,7 +121,7 @@ public class CipherOutputStream extends FilterOutputStream { /** * Flushes this cipher output stream. - * + * * @throws IOException * if an error occurs */ @@ -145,7 +136,7 @@ public class CipherOutputStream extends FilterOutputStream { * On the underlying cipher {@code doFinal} will be invoked, and any * buffered bytes from the cipher are also written out, and the cipher is * reset to its initial state. The underlying output stream is also closed. - * + * * @throws IOException * if an error occurs. */ @@ -173,3 +164,4 @@ public class CipherOutputStream extends FilterOutputStream { } } } + diff --git a/crypto/src/main/java/javax/crypto/CipherSpi.java b/crypto/src/main/java/javax/crypto/CipherSpi.java index f6da929..50fdd49 100644 --- a/crypto/src/main/java/javax/crypto/CipherSpi.java +++ b/crypto/src/main/java/javax/crypto/CipherSpi.java @@ -44,7 +44,7 @@ import org.apache.harmony.crypto.internal.nls.Messages; * </ul> * The following behavior should be implemented for obtaining {@code Cipher} * instances. - * </p> + * <p> * When one of the {@link Cipher#getInstance} factory methods is called with a * <i>transformation</i> that is only an <i>algorithm</i>, check if the provider * defines a {@code CipherSpi} for "algorithm", if so: return it, otherwise @@ -76,53 +76,46 @@ import org.apache.harmony.crypto.internal.nls.Messages; * padding name and return it, otherwise throw a * {@link NoSuchAlgorithmException}. * </ul> - * </p> - * + * * @see Cipher - * @since Android 1.0 */ public abstract class CipherSpi { /** * Creates a new {@code CipherSpi} instance. - * - * @since Android 1.0 */ public CipherSpi() { } /** * Sets the mode for this cipher. - * + * * @param mode * the name of the cipher mode. * @throws NoSuchAlgorithmException * if the specified cipher mode is not supported by this * provider. - * @since Android 1.0 */ protected abstract void engineSetMode(String mode) throws NoSuchAlgorithmException; /** * Sets the padding method for this cipher. - * + * * @param padding * the name of the padding method. * @throws NoSuchPaddingException * if the specified padding method is not supported by this * cipher. - * @since Android 1.0 */ protected abstract void engineSetPadding(String padding) throws NoSuchPaddingException; /** * Returns the block size of this cipher (in bytes) - * + * * @return the block size of this cipher, or zero if this cipher is not a * block cipher. - * @since Android 1.0 */ protected abstract int engineGetBlockSize(); @@ -133,21 +126,18 @@ public abstract class CipherSpi { * <p> * The actual output length of the next call to {@code update} or {@code * doFinal} may be smaller than the length returned by this method. - * </p> - * + * * @param inputLen * the length of the input (in bytes). * @return the size for a buffer (in bytes). - * @since Android 1.0 */ protected abstract int engineGetOutputSize(int inputLen); /** * Returns the Initialization Vector (IV) that was used to initialize this * cipher or {@code null} if none was used. - * + * * @return the Initialization Vector (IV), or {@code null} if none was used. - * @since Android 1.0 */ protected abstract byte[] engineGetIV(); @@ -157,12 +147,10 @@ public abstract class CipherSpi { * These may be a the same parameters that were used to create this cipher * instance, or may be a combination of default and random parameters, * depending on the underlying cipher implementation. - * </p> - * + * * @return the parameters that where used to create this cipher instance, or * {@code null} if this cipher instance does not have any parameters * at all. - * @since Android 1.0 */ protected abstract AlgorithmParameters engineGetParameters(); @@ -173,7 +161,7 @@ public abstract class CipherSpi { * The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters or random values * that the specified key cannot provide, the underlying implementation of * this cipher is supposed to generate the required parameters (using its @@ -183,8 +171,7 @@ public abstract class CipherSpi { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -196,7 +183,6 @@ public abstract class CipherSpi { * @throws InvalidKeyException * if the specified key cannot be used to initialize this cipher * instance. - * @since Android 1.0 */ protected abstract void engineInit(int opmode, Key key, SecureRandom random) throws InvalidKeyException; @@ -208,7 +194,7 @@ public abstract class CipherSpi { * The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random @@ -217,8 +203,7 @@ public abstract class CipherSpi { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -235,7 +220,6 @@ public abstract class CipherSpi { * @throws InvalidAlgorithmParameterException * it the specified parameters are inappropriate for this * cipher. - * @since Android 1.0 */ protected abstract void engineInit(int opmode, Key key, AlgorithmParameterSpec params, SecureRandom random) @@ -248,7 +232,7 @@ public abstract class CipherSpi { * The cipher will be initialized for the specified operation (one of: * encryption, decryption, key wrapping or key unwrapping) depending on * {@code opmode}. - * </p> + * <p> * If this cipher instance needs any algorithm parameters and {@code params} * is {@code null}, the underlying implementation of this cipher is supposed * to generate the required parameters (using its provider or random @@ -257,8 +241,7 @@ public abstract class CipherSpi { * When a cipher instance is initialized by a call to any of the {@code * init} methods, the state of the instance is overridden, means it is * equivalent to creating a new instance and calling it {@code init} method. - * </p> - * + * * @param opmode * the operation this cipher instance should be initialized for * (one of: {@code ENCRYPT_MODE}, {@code DECRYPT_MODE}, {@code @@ -275,7 +258,6 @@ public abstract class CipherSpi { * @throws InvalidAlgorithmParameterException * if the specified parameters are inappropriate for this * cipher. - * @since Android 1.0 */ protected abstract void engineInit(int opmode, Key key, AlgorithmParameters params, SecureRandom random) @@ -284,7 +266,7 @@ public abstract class CipherSpi { /** * Continues a multi-part transformation (encryption or decryption). The * transformed bytes are returned. - * + * * @param input * the input bytes to transform. * @param inputOffset @@ -299,7 +281,6 @@ public abstract class CipherSpi { * @throws IllegalArgumentException * if the input is null, or if {@code inputOffset} and {@code * inputLen} do not specify a valid chunk in the input buffer. - * @since Android 1.0 */ protected abstract byte[] engineUpdate(byte[] input, int inputOffset, int inputLen); @@ -312,8 +293,7 @@ public abstract class CipherSpi { * a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. - * </p> - * + * * @param input * the input bytes to transform. * @param inputOffset @@ -327,7 +307,6 @@ public abstract class CipherSpi { * @return the number of bytes placed in output. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. - * @since Android 1.0 */ protected abstract int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) @@ -342,8 +321,7 @@ public abstract class CipherSpi { * bytes a {@code ShortBufferException} is thrown. Use * {@link Cipher#getOutputSize getOutputSize} to check for the size of the * output buffer. - * </p> - * + * * @param input * the input buffer to transform. * @param output @@ -351,7 +329,6 @@ public abstract class CipherSpi { * @return the number of bytes stored in the output buffer. * @throws ShortBufferException * if the size of the {@code output} buffer is too small. - * @since Android 1.0 */ protected int engineUpdate(ByteBuffer input, ByteBuffer output) throws ShortBufferException { @@ -395,8 +372,7 @@ public abstract class CipherSpi { * Processes the {@code inputLen} bytes in {@code input} buffer at {@code * inputOffset}, and any bytes that have been buffered in previous {@code * update} calls. - * </p> - * + * * @param input * the input buffer. * @param inputOffset @@ -409,7 +385,6 @@ public abstract class CipherSpi { * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. - * @since Android 1.0 */ protected abstract byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen) throws IllegalBlockSizeException, BadPaddingException; @@ -418,10 +393,9 @@ public abstract class CipherSpi { * Finishes a multi-part transformation (encryption or decryption). * <p> * Processes the {@code inputLen} bytes in {@code input} buffer at - * {@code inputOffset}, and any bytes that have been buffered in previous + * {@code inputOffset}, and any bytes that have been buffered in previous * {@code update} calls. - * </p> - * + * * @param input * the input buffer. * @param inputOffset @@ -440,7 +414,6 @@ public abstract class CipherSpi { * cipher block size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. - * @since Android 1.0 */ protected abstract int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) @@ -454,8 +427,7 @@ public abstract class CipherSpi { * {@code input.position()}, and any bytes that have been buffered in * previous {@code update} calls. The transformed bytes are placed into * {@code output} buffer. - * </p> - * + * * @param input * the input buffer. * @param output @@ -519,7 +491,7 @@ public abstract class CipherSpi { * this class (for backwards compatibility, it cannot be abstract). If this * method is not overridden, it throws an {@code * UnsupportedOperationException}. - * + * * @param key * the key to wrap. * @return the wrapped key @@ -528,7 +500,6 @@ public abstract class CipherSpi { * cipher block size. * @throws InvalidKeyException * if this cipher instance cannot wrap this key. - * @since Android 1.0 */ protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException { @@ -542,8 +513,7 @@ public abstract class CipherSpi { * This method has been added to this class (for backwards compatibility, it * cannot be abstract). If this method is not overridden, it throws an * {@code UnsupportedOperationException}. - * </p> - * + * * @param wrappedKey * the wrapped key to unwrap. * @param wrappedKeyAlgorithm @@ -559,7 +529,6 @@ public abstract class CipherSpi { * @throws NoSuchAlgorithmException * if no provider can be found that can create a key of type * {@code wrappedKeyType} for the {@code wrappedKeyAlgorithm}. - * @since Android 1.0 */ protected Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm, int wrappedKeyType) throws InvalidKeyException, @@ -573,17 +542,16 @@ public abstract class CipherSpi { * added to this class (for backwards compatibility, it cannot be abstract). * If this method is not overridden, it throws an {@code * UnsupportedOperationException}. - * + * * @param key * the key to get the size for. * @return the size of a specified key object in bits. * @throws InvalidKeyException * if the size of the key cannot be determined by this * implementation. - * @since Android 1.0 */ protected int engineGetKeySize(Key key) throws InvalidKeyException { throw new UnsupportedOperationException( Messages.getString("crypto.12")); //$NON-NLS-1$ } -} +}
\ No newline at end of file diff --git a/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java b/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java index 301cd49..2d0fd25 100644 --- a/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java +++ b/crypto/src/main/java/javax/crypto/EncryptedPrivateKeyInfo.java @@ -46,7 +46,6 @@ import org.apache.harmony.security.x509.AlgorithmIdentifier; * #8 - Private-Key Information Syntax Standard</a>. * <p> * The definition of ASN.1 is as follows: - * </p> * <dl> * EncryptedPrivateKeyInfo ::= SEQUENCE { * <dd>encryptionAlgorithm AlgorithmIdentifier,</dd> @@ -57,8 +56,6 @@ import org.apache.harmony.security.x509.AlgorithmIdentifier; * <dd>algorithm OBJECT IDENTIFIER,</dd> * <dd>parameters ANY DEFINED BY algorithm OPTIONAL }</dd> * </dl> - * - * @since Android 1.0 */ public class EncryptedPrivateKeyInfo { // Encryption algorithm name @@ -75,14 +72,13 @@ public class EncryptedPrivateKeyInfo { /** * Creates an {@code EncryptedPrivateKeyInfo} instance from its encoded * representation by parsing it. - * + * * @param encoded * the encoded representation of this object * @throws IOException * if parsing the encoded representation fails. * @throws NullPointerException * if {@code encoded} is {@code null}. - * @since Android 1.0 */ public EncryptedPrivateKeyInfo(byte[] encoded) throws IOException { @@ -127,7 +123,7 @@ public class EncryptedPrivateKeyInfo { /** * Creates an {@code EncryptedPrivateKeyInfo} instance from an algorithm * name and its encrypted data. - * + * * @param encrAlgName * the name of an algorithm. * @param encryptedData @@ -139,7 +135,6 @@ public class EncryptedPrivateKeyInfo { * null}. * @throws IllegalArgumentException * if {@code encryptedData} is empty. - * @since Android 1.0 */ public EncryptedPrivateKeyInfo(String encrAlgName, byte[] encryptedData) throws NoSuchAlgorithmException { @@ -166,7 +161,7 @@ public class EncryptedPrivateKeyInfo { /** * Creates an {@code EncryptedPrivateKeyInfo} instance from the * encryption algorithm parameters an its encrypted data. - * + * * @param algParams * the encryption algorithm parameters. * @param encryptedData @@ -177,7 +172,6 @@ public class EncryptedPrivateKeyInfo { * @throws NullPointerException * if {@code algParams} or {@code encryptedData} is * {@code null}. - * @since Android 1.0 */ public EncryptedPrivateKeyInfo(AlgorithmParameters algParams, byte[] encryptedData) @@ -204,9 +198,8 @@ public class EncryptedPrivateKeyInfo { /** * Returns the name of the encryption algorithm. - * + * * @return the name of the encryption algorithm. - * @since Android 1.0 */ public String getAlgName() { return algName; @@ -214,9 +207,8 @@ public class EncryptedPrivateKeyInfo { /** * Returns the parameters used by the encryption algorithm. - * + * * @return the parameters used by the encryption algorithm. - * @since Android 1.0 */ public AlgorithmParameters getAlgParameters() { return algParameters; @@ -224,10 +216,9 @@ public class EncryptedPrivateKeyInfo { /** * Returns the encrypted data of this key. - * + * * @return the encrypted data of this key, each time this method is called a * new array is returned. - * @since Android 1.0 */ public byte[] getEncryptedData() { byte[] ret = new byte[encryptedData.length]; @@ -242,8 +233,7 @@ public class EncryptedPrivateKeyInfo { * The cipher must be initialize in either {@code Cipher.DECRYPT_MODE} or * {@code Cipher.UNWRAP_MODE} with the same parameters and key used for * encrypting this. - * </p> - * + * * @param cipher * the cipher initialized for decrypting the encrypted data. * @return the extracted {@code PKCS8EncodedKeySpec}. @@ -252,7 +242,6 @@ public class EncryptedPrivateKeyInfo { * encrypted data. * @throws NullPointerException * if {@code cipher} is {@code null}. - * @since Android 1.0 */ public PKCS8EncodedKeySpec getKeySpec(Cipher cipher) throws InvalidKeySpecException { @@ -280,7 +269,7 @@ public class EncryptedPrivateKeyInfo { /** * Returns the {@code PKCS8EncodedKeySpec} object extracted from the * encrypted data. - * + * * @param decryptKey * the key to decrypt the encrypted data with. * @return the extracted {@code PKCS8EncodedKeySpec}. @@ -292,7 +281,6 @@ public class EncryptedPrivateKeyInfo { * data. * @throws NullPointerException * if {@code decryptKey} is {@code null}. - * @since Android 1.0 */ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey) throws NoSuchAlgorithmException, @@ -331,7 +319,7 @@ public class EncryptedPrivateKeyInfo { /** * Returns the {@code PKCS8EncodedKeySpec} object extracted from the * encrypted data. - * + * * @param decryptKey * the key to decrypt the encrypted data with. * @param providerName @@ -349,7 +337,6 @@ public class EncryptedPrivateKeyInfo { * @throws NullPointerException * if {@code decryptKey} or {@code providerName} is {@code null} * . - * @since Android 1.0 */ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, String providerName) throws NoSuchProviderException, @@ -393,7 +380,7 @@ public class EncryptedPrivateKeyInfo { /** * Returns the {@code PKCS8EncodedKeySpec} object extracted from the * encrypted data. - * + * * @param decryptKey * the key to decrypt the encrypted data with. * @param provider @@ -407,7 +394,6 @@ public class EncryptedPrivateKeyInfo { * data. * @throws NullPointerException * if {@code decryptKey} or {@code provider} is {@code null}. - * @since Android 1.0 */ public PKCS8EncodedKeySpec getKeySpec(Key decryptKey, Provider provider) throws NoSuchAlgorithmException, @@ -448,11 +434,10 @@ public class EncryptedPrivateKeyInfo { /** * Returns the ASN.1 encoded representation of this object. - * + * * @return the ASN.1 encoded representation of this object. * @throws IOException * if encoding this object fails. - * @since Android 1.0 */ public byte[] getEncoded() throws IOException { if (encoded == null) { diff --git a/crypto/src/main/java/javax/crypto/ExemptionMechanism.java b/crypto/src/main/java/javax/crypto/ExemptionMechanism.java index 7c68d28..76c88cb 100644 --- a/crypto/src/main/java/javax/crypto/ExemptionMechanism.java +++ b/crypto/src/main/java/javax/crypto/ExemptionMechanism.java @@ -34,8 +34,6 @@ import org.apache.harmony.security.fortress.Engine; /** * This class implements the functionality of an exemption mechanism such as * <i>key recovery</i>, <i>key weakening</i>, or <i>key escrow</i>. - * - * @since Android 1.0 */ public class ExemptionMechanism { @@ -62,14 +60,13 @@ public class ExemptionMechanism { /** * Creates a {@code ExemptionMechanism} instance. - * + * * @param exmechSpi * the implementation delegate. * @param provider * the associated provider. * @param mechanism * the name of the mechanism. - * @since Android 1.0 */ protected ExemptionMechanism(ExemptionMechanismSpi exmechSpi, Provider provider, String mechanism) { @@ -81,9 +78,8 @@ public class ExemptionMechanism { /** * Returns the name of this {@code ExemptionMechanism}. - * + * * @return the name of this {@code ExemptionMechanism}. - * @since Android 1.0 */ public final String getName() { return mechanism; @@ -92,7 +88,7 @@ public class ExemptionMechanism { /** * Returns a new {@code ExemptionMechanism} instance that provides the * specified exemption mechanism algorithm. - * + * * @param algorithm * the name of the requested exemption mechanism. * @return the new {@code ExemptionMechanism} instance. @@ -100,7 +96,6 @@ public class ExemptionMechanism { * if the specified algorithm is not available by any provider. * @throws NullPointerException * if the algorithm parameter is {@code null}. - * @since Android 1.0 */ public static final ExemptionMechanism getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -117,7 +112,7 @@ public class ExemptionMechanism { /** * Returns a new {@code ExemptionMechansm} instance that provides the * specified exemption mechanism algorithm from the specified provider. - * + * * @param algorithm * the name of the requested exemption mechanism. * @param provider @@ -132,7 +127,6 @@ public class ExemptionMechanism { * if the algorithm parameter is {@code null}. * @throws IllegalArgumentException * if the provider parameter is {@code null}. - * @since Android 1.0 */ public static final ExemptionMechanism getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, @@ -153,7 +147,7 @@ public class ExemptionMechanism { /** * Returns a new {@code ExemptionMechanism} instance that provides the * specified exemption mechanism algorithm from the specified provider. - * + * * @param algorithm * the name of the requested exemption mechanism. * @param provider @@ -166,7 +160,6 @@ public class ExemptionMechanism { * if the algorithm parameter is {@code null}. * @throws IllegalArgumentException * if the provider parameter is {@code null}. - * @since Android 1.0 */ public static final ExemptionMechanism getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { @@ -185,9 +178,8 @@ public class ExemptionMechanism { /** * Returns the provider of this {@code ExemptionMechanism} instance. - * + * * @return the provider of this {@code ExemptionMechanism} instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -197,7 +189,7 @@ public class ExemptionMechanism { * Returns whether the result blob for this {@code ExemptionMechanism} * instance has been generated successfully and that the specified key is * the same as the one that was used to initialize and generate. - * + * * @param key * the key to verify. * @return whether the result blob for this {@code ExemptionMechanism} @@ -205,7 +197,6 @@ public class ExemptionMechanism { * @throws ExemptionMechanismException * if an error occurs while determining whether the result blob * has been generated successfully. - * @since Android 1.0 */ public final boolean isCryptoAllowed(Key key) throws ExemptionMechanismException { @@ -222,14 +213,13 @@ public class ExemptionMechanism { * Returns the size in bytes for the output buffer needed to hold the output * of the next {@link #genExemptionBlob} call, given the specified {@code * inputLen} (in bytes). - * + * * @param inputLen * the specified input length (in bytes). * @return the size in bytes for the output buffer. * @throws IllegalStateException * if this {@code ExemptionMechanism} instance is not * initialized. - * @since Android 1.0 */ public final int getOutputSize(int inputLen) throws IllegalStateException { if (!isInit) { @@ -241,14 +231,13 @@ public class ExemptionMechanism { /** * Initializes this {@code ExemptionMechanism} instance with the * specified key. - * + * * @param key * the key to initialize this instance with. * @throws InvalidKeyException * if the key cannot be used to initialize this mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ public final void init(Key key) throws InvalidKeyException, ExemptionMechanismException { @@ -261,7 +250,7 @@ public class ExemptionMechanism { /** * Initializes this {@code ExemptionMechanism} instance with the * specified key and algorithm parameters. - * + * * @param key * the key to initialize this instance with. * @param param @@ -273,7 +262,6 @@ public class ExemptionMechanism { * mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ public final void init(Key key, AlgorithmParameters param) throws InvalidKeyException, InvalidAlgorithmParameterException, @@ -287,7 +275,7 @@ public class ExemptionMechanism { /** * Initializes this {@code ExemptionMechanism} instance with the * specified key and algorithm parameters. - * + * * @param key * the key to initialize this instance with. * @param param @@ -299,7 +287,6 @@ public class ExemptionMechanism { * mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ public final void init(Key key, AlgorithmParameterSpec param) throws InvalidKeyException, InvalidAlgorithmParameterException, @@ -312,14 +299,13 @@ public class ExemptionMechanism { /** * Generates the result key blob for this exemption mechanism. - * + * * @return the result key blob for this exemption mechanism. * @throws IllegalStateException * if this {@code ExemptionMechanism} instance is not * initialized. * @throws ExemptionMechanismException * if error(s) occur during generation. - * @since Android 1.0 */ public final byte[] genExemptionBlob() throws IllegalStateException, ExemptionMechanismException { @@ -335,7 +321,7 @@ public class ExemptionMechanism { /** * Generates the result key blob for this exemption mechanism and stores it * into the {@code output} buffer. - * + * * @param output * the output buffer for the result key blob. * @return the number of bytes written to the {@code output} buffer. @@ -346,7 +332,6 @@ public class ExemptionMechanism { * if the provided buffer is too small for the result key blob. * @throws ExemptionMechanismException * if error(s) occur during generation. - * @since Android 1.0 */ public final int genExemptionBlob(byte[] output) throws IllegalStateException, ShortBufferException, @@ -357,7 +342,7 @@ public class ExemptionMechanism { /** * Generates the result key blob for this exemption mechanism and stores it * into the {@code output} buffer at offset {@code outputOffset}. - * + * * @param output * the output buffer for the result key blob. * @param outputOffset @@ -370,7 +355,6 @@ public class ExemptionMechanism { * if the provided buffer is too small for the result key blob. * @throws ExemptionMechanismException * if error(s) occur during generation. - * @since Android 1.0 */ public final int genExemptionBlob(byte[] output, int outputOffset) throws IllegalStateException, ShortBufferException, @@ -386,8 +370,6 @@ public class ExemptionMechanism { /** * Frees the references to the key used to initialize this instance. - * - * @since Android 1.0 */ @Override protected void finalize() { diff --git a/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java b/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java index 3af498b..d094ac3 100644 --- a/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java +++ b/crypto/src/main/java/javax/crypto/ExemptionMechanismException.java @@ -21,8 +21,6 @@ import java.security.GeneralSecurityException; /** * This is the base class for {@code ExemptionMechanismException}. - * - * @since Android 1.0 */ public class ExemptionMechanismException extends GeneralSecurityException { @@ -37,7 +35,6 @@ public class ExemptionMechanismException extends GeneralSecurityException { * * @param msg * the exception message. - * @since Android 1.0 */ public ExemptionMechanismException(String msg) { super(msg); @@ -45,8 +42,6 @@ public class ExemptionMechanismException extends GeneralSecurityException { /** * Creates a new {@code ExemptionMechanismException} with no message. - * - * @since Android 1.0 */ public ExemptionMechanismException() { } diff --git a/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java b/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java index cef1516..39a27f6 100644 --- a/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java +++ b/crypto/src/main/java/javax/crypto/ExemptionMechanismSpi.java @@ -26,26 +26,21 @@ import java.security.spec.AlgorithmParameterSpec; /** * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the {@code * ExemptionMechanism} class. - * - * @since Android 1.0 */ public abstract class ExemptionMechanismSpi { /** * Creates a new {@code ExemptionMechanismSpi} instance. - * - * @since Android 1.0 */ public ExemptionMechanismSpi() { } /** * Generates the result key blob for this exemption mechanism. - * + * * @return the result key blob for this exemption mechanism. * @throws ExemptionMechanismException * if error(s) occur during generation. - * @since Android 1.0 */ protected abstract byte[] engineGenExemptionBlob() throws ExemptionMechanismException; @@ -53,7 +48,7 @@ public abstract class ExemptionMechanismSpi { /** * Generates the result key blob for this exemption mechanism and stores it * into the {@code output} buffer at offset {@code outputOffset}. - * + * * @param output * the output buffer for the result key blob. * @param outputOffset @@ -63,7 +58,6 @@ public abstract class ExemptionMechanismSpi { * if the provided buffer is too small for the result key blob. * @throws ExemptionMechanismException * if error(s) occur during generation. - * @since Android 1.0 */ protected abstract int engineGenExemptionBlob(byte[] output, int outputOffset) throws ShortBufferException, @@ -73,7 +67,7 @@ public abstract class ExemptionMechanismSpi { * Returns the size in bytes for the output buffer needed to hold the output * of the next {@link #engineGenExemptionBlob} call, given the specified * {@code inputLen} (in bytes). - * + * * @param inputLen * the specified input length (in bytes). * @return the size in bytes for the output buffer. @@ -83,14 +77,13 @@ public abstract class ExemptionMechanismSpi { /** * Initializes this {@code ExemptionMechanism} instance with the specified * key. - * + * * @param key * the key to initialize this instance with. * @throws InvalidKeyException * if the key cannot be used to initialize this mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ protected abstract void engineInit(Key key) throws InvalidKeyException, ExemptionMechanismException; @@ -98,7 +91,7 @@ public abstract class ExemptionMechanismSpi { /** * Initializes this {@code ExemptionMechanism} instance with the specified * key and algorithm parameters. - * + * * @param key * the key to initialize this instance with. * @param params @@ -110,7 +103,6 @@ public abstract class ExemptionMechanismSpi { * mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ protected abstract void engineInit(Key key, AlgorithmParameters params) throws InvalidKeyException, InvalidAlgorithmParameterException, @@ -119,7 +111,7 @@ public abstract class ExemptionMechanismSpi { /** * Initializes this {@code ExemptionMechanism} instance with the specified * key and algorithm parameters. - * + * * @param key * the key to initialize this instance with. * @param params @@ -131,7 +123,6 @@ public abstract class ExemptionMechanismSpi { * mechanism. * @throws ExemptionMechanismException * if error(s) occur during initialization. - * @since Android 1.0 */ protected abstract void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException, diff --git a/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java b/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java index e376b85..0766b7c 100644 --- a/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java +++ b/crypto/src/main/java/javax/crypto/IllegalBlockSizeException.java @@ -22,8 +22,6 @@ import java.security.GeneralSecurityException; /** * The exception, that is thrown when the data length provided to a block cipher * does not match the block size of the cipher. - * - * @since Android 1.0 */ public class IllegalBlockSizeException extends GeneralSecurityException { @@ -38,7 +36,6 @@ public class IllegalBlockSizeException extends GeneralSecurityException { * * @param msg * the message - * @since Android 1.0 */ public IllegalBlockSizeException(String msg) { super(msg); @@ -46,8 +43,6 @@ public class IllegalBlockSizeException extends GeneralSecurityException { /** * Creates a new {@code IllegalBlockSizeException}. - * - * @since Android 1.0 */ public IllegalBlockSizeException() { } diff --git a/crypto/src/main/java/javax/crypto/KeyAgreement.java b/crypto/src/main/java/javax/crypto/KeyAgreement.java index ee1f195..593aa37 100644 --- a/crypto/src/main/java/javax/crypto/KeyAgreement.java +++ b/crypto/src/main/java/javax/crypto/KeyAgreement.java @@ -34,8 +34,6 @@ import org.apache.harmony.security.fortress.Engine; * This class provides the functionality for a key exchange protocol. This * enables two or more parties to agree on a secret key for symmetric * cryptography. - * - * @since Android 1.0 */ public class KeyAgreement { @@ -56,14 +54,13 @@ public class KeyAgreement { /** * Creates a new {@code KeyAgreement} instance. - * + * * @param keyAgreeSpi * the <b>SPI</b> delegate. * @param provider * the provider providing this KeyAgreement. * @param algorithm * the name of the key agreement algorithm. - * @since Android 1.0 */ protected KeyAgreement(KeyAgreementSpi keyAgreeSpi, Provider provider, String algorithm) { @@ -74,9 +71,8 @@ public class KeyAgreement { /** * Returns the name of the key agreement algorithm. - * + * * @return the name of the key agreement algorithm. - * @since Android 1.0 */ public final String getAlgorithm() { return algorithm; @@ -84,9 +80,8 @@ public class KeyAgreement { /** * Returns the provider for this {@code KeyAgreement} instance. - * + * * @return the provider for this {@code KeyAgreement} instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -94,7 +89,7 @@ public class KeyAgreement { /** * Creates a new {@code KeyAgreement} for the specified algorithm. - * + * * @param algorithm * the name of the key agreement algorithm to create. * @return a key agreement for the specified algorithm. @@ -102,7 +97,6 @@ public class KeyAgreement { * if no installed provider can provide the requested algorithm. * @throws NullPointerException * if the specified algorithm is {@code null}. - * @since Android 1.0 */ public static final KeyAgreement getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -119,7 +113,7 @@ public class KeyAgreement { /** * Creates a new {@code KeyAgreement} for the specified algorithm from the * specified provider. - * + * * @param algorithm * the name of the key agreement algorithm to create. * @param provider @@ -134,7 +128,6 @@ public class KeyAgreement { * if the specified provider does not exist. * @throws IllegalArgumentException * if the specified provider name is {@code null} or empty. - * @since Android 1.0 */ public static final KeyAgreement getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, @@ -152,7 +145,7 @@ public class KeyAgreement { /** * Create a new {@code KeyAgreement} for the specified algorithm from the * specified provider. - * + * * @param algorithm * the name of the key agreement algorithm to create. * @param provider @@ -184,13 +177,12 @@ public class KeyAgreement { /** * Initializes this {@code KeyAgreement} with the specified key. - * + * * @param key * the key to initialize this key agreement. * @throws InvalidKeyException * if the specified key cannot be used to initialize this key * agreement. - * @since Android 1.0 */ public final void init(Key key) throws InvalidKeyException { spiImpl.engineInit(key, rndm);//new SecureRandom()); @@ -199,7 +191,7 @@ public class KeyAgreement { /** * Initializes this {@code KeyAgreement} with the specified key and the * specified randomness source. - * + * * @param key * the key to initialize this key agreement. * @param random @@ -207,7 +199,6 @@ public class KeyAgreement { * @throws InvalidKeyException * if the specified key cannot be used to initialize this key * agreement. - * @since Android 1.0 */ public final void init(Key key, SecureRandom random) throws InvalidKeyException { @@ -217,7 +208,7 @@ public class KeyAgreement { /** * Initializes this {@code KeyAgreement} with the specified key and the * algorithm parameters. - * + * * @param key * the key to initialize this key agreement. * @param params @@ -228,7 +219,6 @@ public class KeyAgreement { * @throws InvalidAlgorithmParameterException * if the specified parameters are invalid for this key * agreement algorithm. - * @since Android 1.0 */ public final void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { @@ -238,7 +228,7 @@ public class KeyAgreement { /** * Initializes this {@code KeyAgreement} with the specified key, algorithm * parameters and randomness source. - * + * * @param key * the key to initialize this key agreement. * @param params @@ -251,7 +241,6 @@ public class KeyAgreement { * @throws InvalidAlgorithmParameterException * if the specified parameters are invalid for this key * agreement algorithm. - * @since Android 1.0 */ public final void init(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, @@ -262,7 +251,7 @@ public class KeyAgreement { /** * Does the next (or the last) phase of the key agreement, using the * specified key. - * + * * @param key * the key received from the other party for this phase. * @param lastPhase @@ -275,7 +264,6 @@ public class KeyAgreement { * this phase, * @throws IllegalStateException * if this instance has not been initialized. - * @since Android 1.0 */ public final Key doPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException { @@ -284,11 +272,10 @@ public class KeyAgreement { /** * Generates the shared secret. - * + * * @return the generated shared secret. * @throws IllegalStateException * if this key agreement is not complete. - * @since Android 1.0 */ public final byte[] generateSecret() throws IllegalStateException { return spiImpl.engineGenerateSecret(); @@ -297,7 +284,7 @@ public class KeyAgreement { /** * Generates the shared secret and stores it into the buffer {@code * sharedSecred} at {@code offset}. - * + * * @param sharedSecret * the buffer to store the shared secret. * @param offset @@ -307,7 +294,6 @@ public class KeyAgreement { * if this key agreement is not complete. * @throws ShortBufferException * if the specified buffer is too small for the shared secret. - * @since Android 1.0 */ public final int generateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException { @@ -316,7 +302,7 @@ public class KeyAgreement { /** * Generates the shared secret. - * + * * @param algorithm * the algorithm to for the {@code SecretKey} * @return the shared secret as a {@code SecretKey} of the specified @@ -329,7 +315,6 @@ public class KeyAgreement { * @throws InvalidKeyException * if a {@code SecretKey} with the specified algorithm cannot be * created using the generated shared secret. - * @since Android 1.0 */ public final SecretKey generateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, diff --git a/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java b/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java index fa9f377..5011183 100644 --- a/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java +++ b/crypto/src/main/java/javax/crypto/KeyAgreementSpi.java @@ -27,15 +27,11 @@ import java.security.spec.AlgorithmParameterSpec; /** * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the * {@code KeyAgreement} class. - * - * @since Android 1.0 */ public abstract class KeyAgreementSpi { - + /** * Creates a new {@code KeyAgreementSpi} instance. - * - * @since Android 1.0 */ public KeyAgreementSpi() { } @@ -43,7 +39,7 @@ public abstract class KeyAgreementSpi { /** * Does the next (or the last) phase of the key agreement, using the * specified key. - * + * * @param key * the key received from the other party for this phase. * @param lastPhase @@ -56,18 +52,16 @@ public abstract class KeyAgreementSpi { * this phase, * @throws IllegalStateException * if this instance has not been initialized. - * @since Android 1.0 */ protected abstract Key engineDoPhase(Key key, boolean lastPhase) throws InvalidKeyException, IllegalStateException; /** * Generates the shared secret. - * + * * @return the generated shared secret. * @throws IllegalStateException * if this key agreement is not complete. - * @since Android 1.0 */ protected abstract byte[] engineGenerateSecret() throws IllegalStateException; @@ -75,7 +69,7 @@ public abstract class KeyAgreementSpi { /** * Generates the shared secret and stores it into the buffer {@code * sharedSecred} at {@code offset}. - * + * * @param sharedSecret * the buffer to store the shared secret. * @param offset @@ -85,14 +79,13 @@ public abstract class KeyAgreementSpi { * if this key agreement is not complete. * @throws ShortBufferException * if the specified buffer is too small for the shared secret. - * @since Android 1.0 */ protected abstract int engineGenerateSecret(byte[] sharedSecret, int offset) throws IllegalStateException, ShortBufferException; /** * Generates the shared secret. - * + * * @param algorithm * the algorithm to for the {@code SecretKey} * @return the shared secret as a {@code SecretKey} of the specified @@ -105,7 +98,6 @@ public abstract class KeyAgreementSpi { * @throws InvalidKeyException * if a {@code SecretKey} with the specified algorithm cannot be * created using the generated shared secret. - * @since Android 1.0 */ protected abstract SecretKey engineGenerateSecret(String algorithm) throws IllegalStateException, NoSuchAlgorithmException, @@ -114,7 +106,7 @@ public abstract class KeyAgreementSpi { /** * Initializes this {@code KeyAgreementSpi} with the specified key and the * specified randomness source. - * + * * @param key * the key to initialize this key agreement. * @param random @@ -122,7 +114,6 @@ public abstract class KeyAgreementSpi { * @throws InvalidKeyException * if the specified key cannot be used to initialize this key * agreement. - * @since Android 1.0 */ protected abstract void engineInit(Key key, SecureRandom random) throws InvalidKeyException; @@ -130,7 +121,7 @@ public abstract class KeyAgreementSpi { /** * Initializes this {@code KeyAgreementSpi} with the specified key, * algorithm parameters and randomness source. - * + * * @param key * the key to initialize this key agreement. * @param params @@ -143,7 +134,6 @@ public abstract class KeyAgreementSpi { * @throws InvalidAlgorithmParameterException * if the specified parameters are invalid for this key * agreement algorithm. - * @since Android 1.0 */ protected abstract void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom random) throws InvalidKeyException, diff --git a/crypto/src/main/java/javax/crypto/KeyGenerator.java b/crypto/src/main/java/javax/crypto/KeyGenerator.java index 3243b39..f1dd3b2 100644 --- a/crypto/src/main/java/javax/crypto/KeyGenerator.java +++ b/crypto/src/main/java/javax/crypto/KeyGenerator.java @@ -32,8 +32,6 @@ import org.apache.harmony.security.fortress.Engine; /** * This class provides the public API for generating symmetric cryptographic * keys. - * - * @since Android 1.0 */ public class KeyGenerator { @@ -54,14 +52,13 @@ public class KeyGenerator { /** * Creates a new {@code KeyGenerator} instance. - * + * * @param keyGenSpi * the implementation delegate. * @param provider * the implementation provider. * @param algorithm * the name of the algorithm. - * @since Android 1.0 */ protected KeyGenerator(KeyGeneratorSpi keyGenSpi, Provider provider, String algorithm) { @@ -72,9 +69,8 @@ public class KeyGenerator { /** * Returns the name of the key generation algorithm. - * + * * @return the name of the key generation algorithm. - * @since Android 1.0 */ public final String getAlgorithm() { return algorithm; @@ -82,9 +78,8 @@ public class KeyGenerator { /** * Returns the provider of this {@code KeyGenerator} instance. - * + * * @return the provider of this {@code KeyGenerator} instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -93,7 +88,7 @@ public class KeyGenerator { /** * Creates a new {@code KeyGenerator} instance that provides the specified * key algorithm, - * + * * @param algorithm * the name of the requested key algorithm * @return the new {@code KeyGenerator} instance. @@ -101,7 +96,6 @@ public class KeyGenerator { * if the specified algorithm is not available by any provider. * @throws NullPointerException * if {@code algorithm} is {@code null}. - * @since Android 1.0 */ public static final KeyGenerator getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -118,7 +112,7 @@ public class KeyGenerator { /** * Creates a new {@code KeyGenerator} instance that provides the specified * key algorithm from the specified provider. - * + * * @param algorithm * the name of the requested key algorithm. * @param provider @@ -133,7 +127,6 @@ public class KeyGenerator { * if the specified provider is name is {@code null} or empty. * @throws NullPointerException * if the specified algorithm name is {@code null}. - * @since Android 1.0 */ public static final KeyGenerator getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, @@ -151,7 +144,7 @@ public class KeyGenerator { /** * Creates a new {@code KeyGenerator} instance that provides the specified * key algorithm from the specified provider. - * + * * @param algorithm * the name of the requested key algorithm. * @param provider @@ -164,7 +157,6 @@ public class KeyGenerator { * if the specified provider is {@code null}. * @throws NullPointerException * if the specified algorithm name is {@code null}. - * @since Android 1.0 */ public static final KeyGenerator getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { @@ -183,9 +175,8 @@ public class KeyGenerator { /** * Generates a secret key. - * + * * @return the generated secret key. - * @since Android 1.0 */ public final SecretKey generateKey() { return spiImpl.engineGenerateKey(); @@ -194,13 +185,12 @@ public class KeyGenerator { /** * Initializes this {@code KeyGenerator} instance with the specified * algorithm parameters. - * + * * @param params * the parameters for the key generation algorithm. * @throws InvalidAlgorithmParameterException * if the parameters cannot be used to initialize this key * generator algorithm. - * @since Android 1.0 */ public final void init(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { @@ -210,7 +200,7 @@ public class KeyGenerator { /** * Initializes this {@code KeyGenerator} instance with the specified * algorithm parameters and randomness source. - * + * * @param params * the parameters for the key generation algorithm. * @param random @@ -218,7 +208,6 @@ public class KeyGenerator { * @throws InvalidAlgorithmParameterException * if the parameters cannot be uses to initialize this key * generator algorithm. - * @since Android 1.0 */ public final void init(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { @@ -228,10 +217,9 @@ public class KeyGenerator { /** * Initializes this {@code KeyGenerator} instance for the specified key size * (in bits). - * + * * @param keysize * the size of the key (in bits). - * @since Android 1.0 */ public final void init(int keysize) { spiImpl.engineInit(keysize, rndm);//new SecureRandom()); @@ -240,12 +228,11 @@ public class KeyGenerator { /** * Initializes this {@code KeyGenerator} instance for the specified key size * (in bits) using the specified randomness source. - * + * * @param keysize * the size of the key (in bits). * @param random * the randomness source for any random bytes. - * @since Android 1.0 */ public final void init(int keysize, SecureRandom random) { spiImpl.engineInit(keysize, random); @@ -254,10 +241,9 @@ public class KeyGenerator { /** * Initializes this {@code KeyGenerator} with the specified randomness * source. - * + * * @param random * the randomness source for any random bytes. - * @since Android 1.0 */ public final void init(SecureRandom random) { spiImpl.engineInit(random); diff --git a/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java b/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java index 165db69..edbbe43 100644 --- a/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java +++ b/crypto/src/main/java/javax/crypto/KeyGeneratorSpi.java @@ -26,30 +26,26 @@ import java.security.spec.AlgorithmParameterSpec; * {@code KeyGenerator} class. * * @see KeyGenerator - * @since Android 1.0 */ public abstract class KeyGeneratorSpi { /** * Creates a new {@code KeyGeneratorSpi} instance. - * - * @since Android 1.0 */ public KeyGeneratorSpi() { } /** * Generates a secret key. - * + * * @return the generated secret key. - * @since Android 1.0 */ protected abstract SecretKey engineGenerateKey(); /** * Initializes this {@code KeyGeneratorSpi} instance with the specified * algorithm parameters and randomness source. - * + * * @param params * the parameters for the key generation algorithm. * @param random @@ -57,7 +53,6 @@ public abstract class KeyGeneratorSpi { * @throws InvalidAlgorithmParameterException * if the parameters cannot be uses to initialize this key * generator algorithm. - * @since Android 1.0 */ protected abstract void engineInit(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException; @@ -65,22 +60,20 @@ public abstract class KeyGeneratorSpi { /** * Initializes this {@code KeyGenerator} instance for the specified key * size (in bits) using the specified randomness source. - * + * * @param keysize * the size of the key (in bits). * @param random * the randomness source for any random bytes. - * @since Android 1.0 */ protected abstract void engineInit(int keysize, SecureRandom random); /** * Initializes this {@code KeyGenerator} with the specified randomness * source. - * + * * @param random * the randomness source for any random bytes. - * @since Android 1.0 */ protected abstract void engineInit(SecureRandom random); }
\ No newline at end of file diff --git a/crypto/src/main/java/javax/crypto/Mac.java b/crypto/src/main/java/javax/crypto/Mac.java index 95f4539..94ea20e 100644 --- a/crypto/src/main/java/javax/crypto/Mac.java +++ b/crypto/src/main/java/javax/crypto/Mac.java @@ -34,8 +34,6 @@ import org.apache.harmony.security.fortress.Engine; /** * This class provides the public API for <i>Message Authentication Code</i> * (MAC) algorithms. - * - * @since Android 1.0 */ public class Mac implements Cloneable { @@ -56,14 +54,13 @@ public class Mac implements Cloneable { /** * Creates a new {@code Mac} instance. - * + * * @param macSpi * the implementation delegate. * @param provider * the implementation provider. * @param algorithm * the name of the MAC algorithm. - * @since Android 1.0 */ protected Mac(MacSpi macSpi, Provider provider, String algorithm) { this.provider = provider; @@ -76,7 +73,6 @@ public class Mac implements Cloneable { * Returns the name of the MAC algorithm. * * @return the name of the MAC algorithm. - * @since Android 1.0 */ public final String getAlgorithm() { return algorithm; @@ -84,9 +80,8 @@ public class Mac implements Cloneable { /** * Returns the provider of this {@code Mac} instance. - * + * * @return the provider of this {@code Mac} instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -102,8 +97,8 @@ public class Mac implements Cloneable { * @throws NoSuchAlgorithmException * if the specified algorithm is not available by any provider. * @throws NullPointerException - * if {@code algorithm} is {@code null}. - * @since Android 1.0 + * if {@code algorithm} is {@code null} (instead of + * NoSuchAlgorithmException as in 1.4 release). */ public static final Mac getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -133,8 +128,8 @@ public class Mac implements Cloneable { * @throws IllegalArgumentException * if the specified provider name is {@code null} or empty. * @throws NullPointerException - * if {@code algorithm} is {@code null} - * @since Android 1.0. + * if {@code algorithm} is {@code null} (instead of + * NoSuchAlgorithmException as in 1.4 release). */ public static final Mac getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, NoSuchProviderException { @@ -163,8 +158,8 @@ public class Mac implements Cloneable { * @throws IllegalArgumentException * if {@code provider} is {@code null}. * @throws NullPointerException - * if {@code algorithm} is {@code null}. - * @since Android 1.0 + * if {@code algorithm} is {@code null} (instead of + * NoSuchAlgorithmException as in 1.4 release). */ public static final Mac getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { @@ -182,7 +177,7 @@ public class Mac implements Cloneable { /** * Returns the length of this MAC (in bytes). - * + * * @return the length of this MAC (in bytes). */ public final int getMacLength() { @@ -192,7 +187,7 @@ public class Mac implements Cloneable { /** * Initializes this {@code Mac} instance with the specified key and * algorithm parameters. - * + * * @param key * the key to initialize this algorithm. * @param params @@ -203,7 +198,6 @@ public class Mac implements Cloneable { * @throws InvalidAlgorithmParameterException * if the specified parameters cannot be used to initialize this * algorithm. - * @since Android 1.0 */ public final void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException { @@ -216,7 +210,7 @@ public class Mac implements Cloneable { /** * Initializes this {@code Mac} instance with the specified key. - * + * * @param key * the key to initialize this algorithm. * @throws InvalidKeyException @@ -225,7 +219,6 @@ public class Mac implements Cloneable { * @throws RuntimeException * if the specified key cannot be used to initialize this * algorithm. - * @since Android 1.0 */ public final void init(Key key) throws InvalidKeyException { if (key == null) { @@ -241,12 +234,11 @@ public class Mac implements Cloneable { /** * Updates this {@code Mac} instance with the specified byte. - * + * * @param input * the byte * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final void update(byte input) throws IllegalStateException { if (!isInitMac) { @@ -258,7 +250,7 @@ public class Mac implements Cloneable { /** * Updates this {@code Mac} instance with the data from the specified buffer * {@code input} from the specified {@code offset} and length {@code len}. - * + * * @param input * the buffer. * @param offset @@ -270,7 +262,6 @@ public class Mac implements Cloneable { * @throws IllegalArgumentException * if {@code offset} and {@code len} do not specified a valid * chunk in {@code input} buffer. - * @since Android 1.0 */ public final void update(byte[] input, int offset, int len) throws IllegalStateException { @@ -288,12 +279,11 @@ public class Mac implements Cloneable { /** * Copies the buffer provided as input for further processing. - * + * * @param input * the buffer. * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final void update(byte[] input) throws IllegalStateException { if (!isInitMac) { @@ -308,12 +298,11 @@ public class Mac implements Cloneable { * Updates this {@code Mac} instance with the data from the specified * buffer, starting at {@link ByteBuffer#position()}, including the next * {@link ByteBuffer#remaining()} bytes. - * + * * @param input * the buffer. * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final void update(ByteBuffer input) { if (!isInitMac) { @@ -333,12 +322,10 @@ public class Mac implements Cloneable { * This {@code Mac} instance is reverted to its initial state and can be * used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * + * * @return the generated digest. * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final byte[] doFinal() throws IllegalStateException { if (!isInitMac) { @@ -355,8 +342,7 @@ public class Mac implements Cloneable { * This {@code Mac} instance is reverted to its initial state and can be * used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * + * * @param output * the output buffer * @param outOffset @@ -368,7 +354,6 @@ public class Mac implements Cloneable { * of the output buffer. * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final void doFinal(byte[] output, int outOffset) throws ShortBufferException, IllegalStateException { @@ -401,14 +386,12 @@ public class Mac implements Cloneable { * This {@code Mac} instance is reverted to its initial state and can be * used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * + * * @param input * the final bytes. * @return the generated digest. * @throws IllegalStateException * if this MAC is not initialized. - * @since Android 1.0 */ public final byte[] doFinal(byte[] input) throws IllegalStateException { if (!isInitMac) { @@ -426,9 +409,6 @@ public class Mac implements Cloneable { * This {@code Mac} instance is reverted to its initial state and can be * used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * - * @since Android 1.0 */ public final void reset() { spiImpl.engineReset(); @@ -436,11 +416,10 @@ public class Mac implements Cloneable { /** * Clones this {@code Mac} instance and the underlying implementation. - * + * * @return the cloned instance. * @throws CloneNotSupportedException * if the underlying implementation does not support cloning. - * @since Android 1.0 */ @Override public final Object clone() throws CloneNotSupportedException { @@ -449,4 +428,4 @@ public class Mac implements Cloneable { mac.isInitMac = this.isInitMac; return mac; } -} +}
\ No newline at end of file diff --git a/crypto/src/main/java/javax/crypto/MacSpi.java b/crypto/src/main/java/javax/crypto/MacSpi.java index 4756184..b2683d2 100644 --- a/crypto/src/main/java/javax/crypto/MacSpi.java +++ b/crypto/src/main/java/javax/crypto/MacSpi.java @@ -28,30 +28,26 @@ import java.nio.ByteBuffer; * Mac} class. * * @see Mac - * @since Android 1.0 */ public abstract class MacSpi { - + /** * Creates a new {@code MacSpi} instance. - * - * @since Android 1.0 */ public MacSpi() { } /** * Returns the length of this MAC (in bytes). - * + * * @return the length of this MAC (in bytes). - * @since Android 1.0 */ protected abstract int engineGetMacLength(); /** * Initializes this {@code MacSpi} instance with the specified key and * algorithm parameters. - * + * * @param key * the key to initialize this algorithm. * @param params @@ -62,17 +58,15 @@ public abstract class MacSpi { * @throws InvalidAlgorithmParameterException * if the specified parameters cannot be used to initialize this * algorithm. - * @since Android 1.0 */ protected abstract void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException, InvalidAlgorithmParameterException; /** * Updates this {@code MacSpi} instance with the specified byte. - * + * * @param input * the byte. - * @since Android 1.0 */ protected abstract void engineUpdate(byte input); @@ -80,14 +74,13 @@ public abstract class MacSpi { * Updates this {@code MacSpi} instance with the data from the specified * buffer {@code input} from the specified {@code offset} and length {@code * len}. - * + * * @param input * the buffer. * @param offset * the offset in the buffer. * @param len * the length of the data in the buffer. - * @since Android 1.0 */ protected abstract void engineUpdate(byte[] input, int offset, int len); @@ -95,10 +88,9 @@ public abstract class MacSpi { * Updates this {@code MacSpi} instance with the data from the specified * buffer, starting at {@link ByteBuffer#position()}, including the next * {@link ByteBuffer#remaining()} bytes. - * + * * @param input * the buffer. - * @since Android 1.0 */ protected void engineUpdate(ByteBuffer input) { if (!input.hasRemaining()) { @@ -126,10 +118,8 @@ public abstract class MacSpi { * This {@code MacSpi} instance is reverted to its initial state and * can be used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * + * * @return the generated digest. - * @since Android 1.0 */ protected abstract byte[] engineDoFinal(); @@ -139,19 +129,15 @@ public abstract class MacSpi { * This {@code MacSpi} instance is reverted to its initial state and can be * used to start the next MAC computation with the same parameters or * initialized with different parameters. - * </p> - * - * @since Android 1.0 */ protected abstract void engineReset(); /** * Clones this {@code MacSpi} instance. - * + * * @return the cloned instance. * @throws CloneNotSupportedException * if cloning is not supported. - * @since Android 1.0 */ @Override public Object clone() throws CloneNotSupportedException { diff --git a/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java b/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java index 4afb8ab..55e1f1e 100644 --- a/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java +++ b/crypto/src/main/java/javax/crypto/NoSuchPaddingException.java @@ -22,8 +22,6 @@ import java.security.GeneralSecurityException; /** * The exception that is thrown when the requested padding mechanism is not * supported. - * - * @since Android 1.0 */ public class NoSuchPaddingException extends GeneralSecurityException { @@ -38,7 +36,6 @@ public class NoSuchPaddingException extends GeneralSecurityException { * * @param msg * the message. - * @since Android 1.0 */ public NoSuchPaddingException(String msg) { super(msg); @@ -46,8 +43,6 @@ public class NoSuchPaddingException extends GeneralSecurityException { /** * Creates a new {@code NoSuchPaddingException}. - * - * @since Android 1.0 */ public NoSuchPaddingException() { } diff --git a/crypto/src/main/java/javax/crypto/NullCipher.java b/crypto/src/main/java/javax/crypto/NullCipher.java index 49f96c2..fadf3ae 100644 --- a/crypto/src/main/java/javax/crypto/NullCipher.java +++ b/crypto/src/main/java/javax/crypto/NullCipher.java @@ -32,8 +32,6 @@ import org.apache.harmony.crypto.internal.NullCipherSpi; /** * This class provides an identity cipher that does not transform the input data * in any way. The <i>encrypted</i> data is identical to the <i>plain text</i>. - * - * @since Android 1.0 */ public class NullCipher extends Cipher { diff --git a/crypto/src/main/java/javax/crypto/SealedObject.java b/crypto/src/main/java/javax/crypto/SealedObject.java index 4e71453..bf453db 100644 --- a/crypto/src/main/java/javax/crypto/SealedObject.java +++ b/crypto/src/main/java/javax/crypto/SealedObject.java @@ -40,19 +40,13 @@ import org.apache.harmony.crypto.internal.nls.Messages; * <p> * Since a {@code SealedObject} instance is a serializable object itself it can * either be stored or transmitted over an insecure channel. - * </p> + * <p> * The wrapped object can later be decrypted (unsealed) using the corresponding * key and then be deserialized to retrieve the original object.The sealed * object itself keeps track of the cipher and corresponding parameters. - * - * @since Android 1.0 */ public class SealedObject implements Serializable { - // the value of this field was derived by using serialver utility - /** - * @com.intel.drl.spec_ref - */ private static final long serialVersionUID = 4482838265551344752L; /** @@ -76,8 +70,7 @@ public class SealedObject implements Serializable { * and sealing it using the specified cipher. * <p> * The cipher must be fully initialized. - * </p> - * + * * @param object * the object to seal, can be {@code null}. * @param c @@ -90,7 +83,6 @@ public class SealedObject implements Serializable { * size. * @throws NullPointerException * if the cipher is {@code null}. - * @since Android 1.0 */ public SealedObject(Serializable object, Cipher c) throws IOException, IllegalBlockSizeException { @@ -117,10 +109,9 @@ public class SealedObject implements Serializable { /** * Creates a new {@code SealedObject} instance by copying the data from * the specified object. - * + * * @param so * the object to copy. - * @since Android 1.0 */ protected SealedObject(SealedObject so) { if (so == null) { @@ -134,9 +125,8 @@ public class SealedObject implements Serializable { /** * Returns the algorithm this object was sealed with. - * + * * @return the algorithm this object was sealed with. - * @since Android 1.0 */ public final String getAlgorithm() { return sealAlg; @@ -144,7 +134,7 @@ public class SealedObject implements Serializable { /** * Returns the wrapped object, decrypting it using the specified key. - * + * * @param key * the key to decrypt the data with. * @return the encapsulated object. @@ -156,7 +146,6 @@ public class SealedObject implements Serializable { * if the algorithm to decrypt the data is not available. * @throws InvalidKeyException * if the specified key cannot be used to decrypt the data. - * @since Android 1.0 */ public final Object getObject(Key key) throws IOException, ClassNotFoundException, @@ -207,7 +196,7 @@ public class SealedObject implements Serializable { /** * Returns the wrapped object, decrypting it using the specified * cipher. - * + * * @param c * the cipher to decrypt the data. * @return the encapsulated object. @@ -221,7 +210,6 @@ public class SealedObject implements Serializable { * size. * @throws BadPaddingException * if the padding of the data does not match the padding scheme. - * @since Android 1.0 */ public final Object getObject(Cipher c) throws IOException, ClassNotFoundException, @@ -239,7 +227,7 @@ public class SealedObject implements Serializable { /** * Returns the wrapped object, decrypting it using the specified key. The * specified provider is used to retrieve the cipher algorithm. - * + * * @param key * the key to decrypt the data. * @param provider @@ -255,7 +243,6 @@ public class SealedObject implements Serializable { * if the specified provider is not available. * @throws InvalidKeyException * if the specified key cannot be used to decrypt the data. - * @since Android 1.0 */ public final Object getObject(Key key, String provider) throws IOException, ClassNotFoundException, diff --git a/crypto/src/main/java/javax/crypto/SecretKey.java b/crypto/src/main/java/javax/crypto/SecretKey.java index 102f888..ac61074 100644 --- a/crypto/src/main/java/javax/crypto/SecretKey.java +++ b/crypto/src/main/java/javax/crypto/SecretKey.java @@ -24,21 +24,18 @@ import java.security.Key; * <p> * This interface is a <i>marker interface</i> to group secret keys and to * provide type safety for. - * </p> + * <p> * Implementations of this interface have to overwrite the * {@link Object#equals(Object) equals} and {@link Object#hashCode() hashCode} * from {@link java.lang.Object} so comparison is done using the actual key data * and not the object reference. - * - * @since Android 1.0 */ public interface SecretKey extends Key { /** * The serialization version identifier. - * + * * @serial - * @since Android 1.0 */ public static final long serialVersionUID = -4795878709595146952L; }
\ No newline at end of file diff --git a/crypto/src/main/java/javax/crypto/SecretKeyFactory.java b/crypto/src/main/java/javax/crypto/SecretKeyFactory.java index a420dab..57bca3e 100644 --- a/crypto/src/main/java/javax/crypto/SecretKeyFactory.java +++ b/crypto/src/main/java/javax/crypto/SecretKeyFactory.java @@ -40,9 +40,6 @@ import org.apache.harmony.security.fortress.Engine; * </ul> * Which key specifications are supported by the {@link #generateSecret} and * {@link #getKeySpec} is provider dependent. - * </p> - * - * @since Android 1.0 */ public class SecretKeyFactory { @@ -60,14 +57,13 @@ public class SecretKeyFactory { /** * Creates a new {@code SecretKeyFactory} - * + * * @param keyFacSpi * the SPI delegate. * @param provider * the provider providing this key factory. * @param algorithm * the algorithm name for the secret key. - * @since Android 1.0 */ protected SecretKeyFactory(SecretKeyFactorySpi keyFacSpi, Provider provider, String algorithm) { @@ -78,9 +74,8 @@ public class SecretKeyFactory { /** * Returns the name of the secret key algorithm. - * + * * @return the name of the secret key algorithm. - * @since Android 1.0 */ public final String getAlgorithm() { return algorithm; @@ -88,9 +83,8 @@ public class SecretKeyFactory { /** * Returns the provider for this {@code SecretKeyFactory} instance. - * + * * @return the provider for this {@code SecretKeyFactory} instance. - * @since Android 1.0 */ public final Provider getProvider() { return provider; @@ -99,7 +93,7 @@ public class SecretKeyFactory { /** * Creates a new {@code SecretKeyFactory} instance for the specified key * algorithm. - * + * * @param algorithm * the name of the key algorithm. * @return a secret key factory for the specified key algorithm. @@ -107,7 +101,6 @@ public class SecretKeyFactory { * if no installed provider can provide the requested algorithm. * @throws NullPointerException * if the specified algorithm is {@code null}. - * @since Android 1.0 */ public static final SecretKeyFactory getInstance(String algorithm) throws NoSuchAlgorithmException { @@ -124,7 +117,7 @@ public class SecretKeyFactory { /** * Creates a new {@code SecretKeyFactory} instance for the specified key * algorithm from the specified {@code provider}. - * + * * @param algorithm * the name of the key algorithm. * @param provider @@ -139,7 +132,6 @@ public class SecretKeyFactory { * if the specified provider does not exist. * @throws IllegalArgumentException * if the specified provider name is {@code null} or empty. - * @since Android 1.0 */ public static final SecretKeyFactory getInstance(String algorithm, String provider) throws NoSuchAlgorithmException, @@ -157,7 +149,7 @@ public class SecretKeyFactory { /** * Creates a new {@code SecretKeyFactory} instance for the specified key * algorithm from the specified provider. - * + * * @param algorithm * the name of the key algorithm. * @param provider @@ -171,7 +163,6 @@ public class SecretKeyFactory { * if the specified provider is {@code null}. * @throws NullPointerException * is the specified algorithm name is {@code null}. - * @since Android 1.0 */ public static final SecretKeyFactory getInstance(String algorithm, Provider provider) throws NoSuchAlgorithmException { @@ -190,14 +181,13 @@ public class SecretKeyFactory { /** * Generate a secret key from the specified key specification. - * + * * @param keySpec * the key specification. * @return a secret key. * @throws InvalidKeySpecException * if the specified key specification cannot be used to generate * a secret key. - * @since Android 1.0 */ public final SecretKey generateSecret(KeySpec keySpec) throws InvalidKeySpecException { @@ -206,7 +196,7 @@ public class SecretKeyFactory { /** * Returns the key specification of the specified secret key. - * + * * @param key * the secret key to get the specification from. * @param keySpec @@ -215,7 +205,6 @@ public class SecretKeyFactory { * @throws InvalidKeySpecException * if the specified secret key cannot be transformed into the * requested key specification. - * @since Android 1.0 */ @SuppressWarnings("unchecked") public final KeySpec getKeySpec(SecretKey key, Class keySpec) @@ -226,14 +215,13 @@ public class SecretKeyFactory { /** * Translates the specified secret key into an instance of the corresponding * key from the provider of this key factory. - * + * * @param key * the secret key to translate. * @return the corresponding translated key. * @throws InvalidKeyException * if the specified key cannot be translated using this key * factory. - * @since Android 1.0 */ public final SecretKey translateKey(SecretKey key) throws InvalidKeyException { diff --git a/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java b/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java index f834dbb..5d7764e 100644 --- a/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java +++ b/crypto/src/main/java/javax/crypto/SecretKeyFactorySpi.java @@ -24,35 +24,31 @@ import java.security.spec.KeySpec; /** * The <i>Service Provider Interface</i> (<b>SPI</b>) definition for the {@code * SecretKeyFactory} class. - * - * @since Android 1.0 */ public abstract class SecretKeyFactorySpi { /** * Creates a new {@code SecretKeyFactorySpi} instance. - * @since Android 1.0 */ public SecretKeyFactorySpi() { } /** * Generate a secret key from the specified key specification. - * + * * @param keySpec * the key specification. * @return a secret key. * @throws InvalidKeySpecException * if the specified key specification cannot be used to generate * a secret key. - * @since Android 1.0 */ protected abstract SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException; /** * Returns the key specification of the specified secret key. - * + * * @param key * the secret key to get the specification from. * @param keySpec @@ -61,7 +57,6 @@ public abstract class SecretKeyFactorySpi { * @throws InvalidKeySpecException * if the specified secret key cannot be transformed into the * requested key specification. - * @since Android 1.0 */ @SuppressWarnings("unchecked") protected abstract KeySpec engineGetKeySpec(SecretKey key, Class keySpec) @@ -70,14 +65,13 @@ public abstract class SecretKeyFactorySpi { /** * Translates the specified secret key into an instance of the corresponding * key from the provider of this key factory. - * + * * @param key * the secret key to translate. * @return the corresponding translated key. * @throws InvalidKeyException * if the specified key cannot be translated using this key * factory. - * @since Android 1.0 */ protected abstract SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException; diff --git a/crypto/src/main/java/javax/crypto/ShortBufferException.java b/crypto/src/main/java/javax/crypto/ShortBufferException.java index 593a31e..56480a8 100644 --- a/crypto/src/main/java/javax/crypto/ShortBufferException.java +++ b/crypto/src/main/java/javax/crypto/ShortBufferException.java @@ -27,8 +27,6 @@ import java.security.GeneralSecurityException; /** * The exception that is thrown when the result of an operation is attempted to * store in a user provided buffer that is too small. - * - * @since Android 1.0 */ public class ShortBufferException extends GeneralSecurityException { @@ -43,7 +41,6 @@ public class ShortBufferException extends GeneralSecurityException { * * @param msg * the exception message. - * @since Android 1.0 */ public ShortBufferException(String msg) { super(msg); @@ -51,8 +48,6 @@ public class ShortBufferException extends GeneralSecurityException { /** * Creates a new instance of {@code ShortBufferException}. - * - * @since Android 1.0 */ public ShortBufferException() { } diff --git a/crypto/src/main/java/javax/crypto/interfaces/DHKey.java b/crypto/src/main/java/javax/crypto/interfaces/DHKey.java index f686844..6ef17d4 100644 --- a/crypto/src/main/java/javax/crypto/interfaces/DHKey.java +++ b/crypto/src/main/java/javax/crypto/interfaces/DHKey.java @@ -21,14 +21,12 @@ import javax.crypto.spec.DHParameterSpec; /** * The interface for a Diffie-Hellman key. - * - * @since Android 1.0 */ public interface DHKey { /** * Returns the parameters for this key. - * + * * @return the parameters for this key. */ public DHParameterSpec getParams(); diff --git a/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java b/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java index d39268b..f63e0cb 100644 --- a/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java +++ b/crypto/src/main/java/javax/crypto/interfaces/DHPrivateKey.java @@ -22,8 +22,6 @@ import java.security.PrivateKey; /** * The interface for a private key in the Diffie-Hellman key exchange protocol. - * - * @since Android 1.0 */ public interface DHPrivateKey extends DHKey, PrivateKey { diff --git a/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java b/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java index 75201a7..92e8f10 100644 --- a/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java +++ b/crypto/src/main/java/javax/crypto/interfaces/DHPublicKey.java @@ -21,9 +21,7 @@ import java.math.BigInteger; import java.security.PublicKey; /** - * The interface for a public key in the Diffie-Hellman key exchange protocol. - * - * @since Android 1.0 + * The interface for a public key in the Diffie-Hellman key exchange protocol. */ public interface DHPublicKey extends DHKey, PublicKey { diff --git a/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java b/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java index 4612ad2..c718715 100644 --- a/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java +++ b/crypto/src/main/java/javax/crypto/interfaces/PBEKey.java @@ -21,8 +21,6 @@ import javax.crypto.SecretKey; /** * The interface to a <i>password-based-encryption</i> key. - * - * @since Android 1.0 */ public interface PBEKey extends SecretKey { @@ -33,21 +31,21 @@ public interface PBEKey extends SecretKey { /** * Returns the iteration count, 0 if not specified. - * + * * @return the iteration count, 0 if not specified. */ public int getIterationCount(); /** * Returns a copy of the salt data or null if not specified. - * + * * @return a copy of the salt data or null if not specified. */ public byte[] getSalt(); /** * Returns a copy to the password. - * + * * @return a copy to the password. */ public char[] getPassword(); diff --git a/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java b/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java index 2a994d5..372a68d 100644 --- a/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DESKeySpec.java @@ -24,8 +24,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The key specification for a DES key. - * - * @since Android 1.0 */ public class DESKeySpec implements KeySpec { @@ -96,7 +94,7 @@ public class DESKeySpec implements KeySpec { /** * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the * specified key data. - * + * * @param key * the key data. * @throws InvalidKeyException @@ -109,7 +107,7 @@ public class DESKeySpec implements KeySpec { /** * Creates a new <code>DESKeySpec</code> from the first 8 bytes of the * specified key data starting at <code>offset</code>. - * + * * @param key * the key data * @param offset @@ -133,7 +131,7 @@ public class DESKeySpec implements KeySpec { /** * Returns a copy of the key. - * + * * @return a copy of the key. */ public byte[] getKey() { @@ -145,7 +143,7 @@ public class DESKeySpec implements KeySpec { /** * Returns whether the specified key data starting at <code>offset</code> is * <i>parity-adjusted</i>. - * + * * @param key * the key data. * @param offset @@ -185,7 +183,7 @@ public class DESKeySpec implements KeySpec { /** * Returns whether the specified key data starting at <code>offset</code> is * weak or semi-weak. - * + * * @param key * the key data. * @param offset diff --git a/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java b/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java index 186f07d..199eba6 100644 --- a/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DESedeKeySpec.java @@ -24,8 +24,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The key specification for a triple-DES (DES-EDE) key. - * - * @since Android 1.0 */ public class DESedeKeySpec implements KeySpec { @@ -39,7 +37,7 @@ public class DESedeKeySpec implements KeySpec { /** * Creates a new <code>DESedeKeySpec</code> instance from the first 24 ( * {@link #DES_EDE_KEY_LEN}) bytes of the specified key data. - * + * * @param key * the key data. * @throws InvalidKeyException @@ -64,7 +62,7 @@ public class DESedeKeySpec implements KeySpec { * Creates a new <code>DESedeKeySpec</code> instance from the first 24 ( * {@link #DES_EDE_KEY_LEN} ) bytes of the specified key data starting at * <code>offset</code>. - * + * * @param key * the key data * @param offset @@ -90,7 +88,7 @@ public class DESedeKeySpec implements KeySpec { /** * Returns a copy of the key. - * + * * @return a copy of the key. */ public byte[] getKey() { @@ -102,7 +100,7 @@ public class DESedeKeySpec implements KeySpec { /** * Returns whether the specified key data starting at <code>offset</code> is * <i>parity-adjusted</i>. - * + * * @param key * the key data. * @param offset diff --git a/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java index a149318..f6ddc03 100644 --- a/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DHGenParameterSpec.java @@ -22,8 +22,6 @@ import java.security.spec.AlgorithmParameterSpec; /** * The algorithm parameter specification for generating Diffie-Hellman * parameters used in Diffie-Hellman key agreement. - * - * @since Android 1.0 */ public class DHGenParameterSpec implements AlgorithmParameterSpec { @@ -33,7 +31,7 @@ public class DHGenParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>DHGenParameterSpec</code> instance with the specified * parameters. - * + * * @param primeSize * the size of the <i>prime modulus</i> in bits. * @param exponentSize @@ -46,7 +44,7 @@ public class DHGenParameterSpec implements AlgorithmParameterSpec { /** * Returns the size of the <i>prime modulus</i> in bits. - * + * * @return the size of the prime modulus in bits. */ public int getPrimeSize() { @@ -55,7 +53,7 @@ public class DHGenParameterSpec implements AlgorithmParameterSpec { /** * Returns the size of the <i>random exponent</i> in bits. - * + * * @return the size of the random exponent in bits. */ public int getExponentSize() { diff --git a/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java index 9bb94b5..6030b40 100644 --- a/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DHParameterSpec.java @@ -22,8 +22,6 @@ import java.security.spec.AlgorithmParameterSpec; /** * The algorithm parameter specification for the Diffie-Hellman algorithm. - * - * @since Android 1.0 */ public class DHParameterSpec implements AlgorithmParameterSpec { @@ -34,7 +32,7 @@ public class DHParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>DHParameterSpec</code> instance with the specified * <i>prime modulus</i> and <i>base generator</i>. - * + * * @param p * the prime modulus. * @param g @@ -50,7 +48,7 @@ public class DHParameterSpec implements AlgorithmParameterSpec { * Creates a new <code>DHParameterSpec</code> instance with the specified * <i>prime modulus</i>, <i>base generator</i> and size (in bits) of the * <i>random exponent</i>. - * + * * @param p * the prime modulus. * @param g @@ -66,7 +64,7 @@ public class DHParameterSpec implements AlgorithmParameterSpec { /** * Returns the <i>prime modulus</i> of this parameter specification. - * + * * @return the prime modulus. */ public BigInteger getP() { @@ -75,7 +73,7 @@ public class DHParameterSpec implements AlgorithmParameterSpec { /** * Returns the <i>base generator</i> of this parameter specification. - * + * * @return the base generator. */ public BigInteger getG() { @@ -84,7 +82,7 @@ public class DHParameterSpec implements AlgorithmParameterSpec { /** * Returns the size (in bits) of the <i>random exponent</i>. - * + * * @return the size (in bits) of the random exponent. */ public int getL() { diff --git a/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java b/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java index 6652de8..925a003 100644 --- a/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DHPrivateKeySpec.java @@ -22,8 +22,6 @@ import java.security.spec.KeySpec; /** * The key specification for a Diffie-Hellman private key. - * - * @since Android 1.0 */ public class DHPrivateKeySpec implements KeySpec { @@ -35,7 +33,7 @@ public class DHPrivateKeySpec implements KeySpec { * Creates a new <code>DHPrivateKeySpec</code> with the specified <i>private * value</i> <code>x</code>. <i>prime modulus</i> <code>p</code> and <i>base * generator</i> <code>g</code>. - * + * * @param x * the private value. * @param p @@ -51,7 +49,7 @@ public class DHPrivateKeySpec implements KeySpec { /** * Returns the <i>private value</i> <code>x</code>. - * + * * @return the private value <code>x</code>. */ public BigInteger getX() { @@ -60,7 +58,7 @@ public class DHPrivateKeySpec implements KeySpec { /** * Returns the <i>prime modulus</i> <code>p</code>. - * + * * @return the prime modulus <code>p</code>. */ public BigInteger getP() { @@ -69,10 +67,11 @@ public class DHPrivateKeySpec implements KeySpec { /** * Returns the <i>base generator</i> <code>g</code>. - * + * * @return the base generator <code>g</code>. */ public BigInteger getG() { return g; } } + diff --git a/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java b/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java index 68d3267..a5d4461 100644 --- a/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/DHPublicKeySpec.java @@ -22,8 +22,6 @@ import java.security.spec.KeySpec; /** * The key specification for a Diffie-Hellman public key. - * - * @since Android 1.0 */ public class DHPublicKeySpec implements KeySpec { @@ -35,7 +33,7 @@ public class DHPublicKeySpec implements KeySpec { * Creates a new <code>DHPublicKeySpec</code> instance with the specified * <i>public value</i> <code>y</code>, the <i>prime modulus</i> * <code>p</code> and the <i>base generator</i> <code>g</code>. - * + * * @param y * the public value. * @param p @@ -51,7 +49,7 @@ public class DHPublicKeySpec implements KeySpec { /** * Returns the <i>public value</i> <code>y</code>. - * + * * @return the public value <code>y</code>. */ public BigInteger getY() { @@ -60,7 +58,7 @@ public class DHPublicKeySpec implements KeySpec { /** * Returns the <i>prime modulus</i> <code>p</code>. - * + * * @return the prime modulus <code>p</code>. */ public BigInteger getP() { @@ -69,7 +67,7 @@ public class DHPublicKeySpec implements KeySpec { /** * Returns the <i>base generator</i> <code>g</code>; - * + * * @return the base generator <code>g</code>; */ public BigInteger getG() { diff --git a/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java index 2f532a8..ce7f9d3 100644 --- a/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/IvParameterSpec.java @@ -35,7 +35,7 @@ public class IvParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>IvParameterSpec</code> instance with the bytes from * the specified buffer <i>iv</i> used as <i>initialization vector</i>. - * + * * @param iv * the buffer used as initialization vector. * @throws NullPointerException @@ -53,7 +53,7 @@ public class IvParameterSpec implements AlgorithmParameterSpec { * Creates a new <code>IvParameterSpec</code> instance with <code>len</code> * bytes from the specified buffer <code>iv</code> starting at * <code>offset</code>. - * + * * @param iv * the buffer used as initialization vector. * @param offset @@ -81,7 +81,7 @@ public class IvParameterSpec implements AlgorithmParameterSpec { /** * Returns a copy of the <i>initialization vector</i> data. - * + * * @return a copy of the initialization vector data. */ public byte[] getIV() { diff --git a/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java index ebb6cce..29b572d 100644 --- a/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/OAEPParameterSpec.java @@ -26,8 +26,6 @@ import javax.crypto.spec.PSource; * <p> * This padding algorithm is defined in the <a * href="http://www.ietf.org/rfc/rfc3447.txt">PKCS #1</a> standard. - * - * @since Android 1.0 */ public class OAEPParameterSpec implements AlgorithmParameterSpec { @@ -60,7 +58,7 @@ public class OAEPParameterSpec implements AlgorithmParameterSpec { * <i>message digest</i> algorithm name, <i>mask generation function</i> * (<i>mgf</i>) algorithm name, <i>parameters</i> for the <i>mgf</i> * algorithm and the <i>source of the label <code>L</code></i>. - * + * * @param mdName * the message digest algorithm name. * @param mgfName @@ -87,7 +85,7 @@ public class OAEPParameterSpec implements AlgorithmParameterSpec { /** * Returns the algorithm name of the <i>message digest</i>. - * + * * @return the algorithm name of the message digest. */ public String getDigestAlgorithm() { @@ -96,7 +94,7 @@ public class OAEPParameterSpec implements AlgorithmParameterSpec { /** * Returns the algorithm name of the <i>mask generation function</i>. - * + * * @return the algorithm name of the mask generation function. */ public String getMGFAlgorithm() { @@ -106,7 +104,7 @@ public class OAEPParameterSpec implements AlgorithmParameterSpec { /** * Returns the algorithm parameter specification for the mask generation * function algorithm. - * + * * @return the algorithm parameter specification for the mask generation * function algorithm. */ @@ -116,7 +114,7 @@ public class OAEPParameterSpec implements AlgorithmParameterSpec { /** * Returns the source of the label <code>L</code>. - * + * * @return the source of the label <code>L</code>. */ public PSource getPSource() { diff --git a/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java b/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java index c46617e..d79fd3c 100644 --- a/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/PBEKeySpec.java @@ -27,8 +27,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; * <p> * Password based encryption is described in <a * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>. - * - * @since Android 1.0 */ public class PBEKeySpec implements KeySpec { @@ -39,7 +37,7 @@ public class PBEKeySpec implements KeySpec { /** * Creates a new <code>PBEKeySpec</code> with the specified password. - * + * * @param password * the password. */ @@ -58,7 +56,7 @@ public class PBEKeySpec implements KeySpec { /** * Creates a new <code>PBEKeySpec</code> with the specified password, salt, * iteration count and the desired length of the derived key. - * + * * @param password * the password. * @param salt @@ -104,7 +102,7 @@ public class PBEKeySpec implements KeySpec { /** * Creates a new <code>PBEKeySpec</code> with the specified password, salt * and iteration count. - * + * * @param password * the password. * @param salt @@ -150,7 +148,7 @@ public class PBEKeySpec implements KeySpec { /** * Returns a copy of the password of this key specification. - * + * * @return a copy of the password of this key specification. * @throws IllegalStateException * if the password has been cleared before. @@ -166,7 +164,7 @@ public class PBEKeySpec implements KeySpec { /** * Returns a copy of the salt of this key specification. - * + * * @return a copy of the salt of this key specification or null if none is * specified. */ @@ -181,7 +179,7 @@ public class PBEKeySpec implements KeySpec { /** * Returns the iteration count of this key specification. - * + * * @return the iteration count of this key specification. */ public final int getIterationCount() { @@ -190,7 +188,7 @@ public class PBEKeySpec implements KeySpec { /** * Returns the desired key length of the derived key. - * + * * @return the desired key length of the derived key. */ public final int getKeyLength() { diff --git a/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java index 190986e..cce3832 100644 --- a/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/PBEParameterSpec.java @@ -23,12 +23,10 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The algorithm parameter specification for a <i>password based encryption</i> - * algorithm. + * algorithm. * <p> * Password based encryption is described in <a * href="http://www.ietf.org/rfc/rfc2898.txt">PKCS #5</a>. - * - * @since Android 1.0 * */ public class PBEParameterSpec implements AlgorithmParameterSpec { @@ -39,7 +37,7 @@ public class PBEParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>PBEParameterSpec</code> with the specified salt and * iteration count. - * + * * @param salt * the salt. * @param iterationCount @@ -58,7 +56,7 @@ public class PBEParameterSpec implements AlgorithmParameterSpec { /** * Returns a copy to the salt. - * + * * @return a copy to the salt. */ public byte[] getSalt() { @@ -69,7 +67,7 @@ public class PBEParameterSpec implements AlgorithmParameterSpec { /** * Returns the iteration count. - * + * * @return the iteration count. */ public int getIterationCount() { diff --git a/crypto/src/main/java/javax/crypto/spec/PSource.java b/crypto/src/main/java/javax/crypto/spec/PSource.java index d5bdf1b..30fd8af 100644 --- a/crypto/src/main/java/javax/crypto/spec/PSource.java +++ b/crypto/src/main/java/javax/crypto/spec/PSource.java @@ -22,8 +22,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The source of the label <code>L</code> as specified in <a * href="http://www.ietf.org/rfc/rfc3447.txt"> PKCS #1</a>. - * - * @since Android 1.0 */ public class PSource { @@ -34,7 +32,7 @@ public class PSource { /** * Creates a new <code>PSource</code> instance with the specified source * algorithm identifier. - * + * * @param pSrcName * the source algorithm identifier. * @throws NullPointerException @@ -49,7 +47,7 @@ public class PSource { /** * Returns the source algorithm identifier. - * + * * @return the source algorithm identifier. */ public String getAlgorithm() { @@ -59,15 +57,14 @@ public class PSource { /** * The explicit specification of the parameter <code>P</code> used in the * source algorithm. - * - * @since Android 1.0 */ public static final class PSpecified extends PSource { private final byte[] p; /** - * The instance of <code>PSpecified</code> with the default value <code>byte[0]</code> for <code>P</code> + * The instance of <code>PSpecified</code> with the default value + * <code>byte[0]</code> for <code>P</code> */ public static final PSpecified DEFAULT = new PSpecified(); @@ -79,7 +76,7 @@ public class PSource { /** * Creates a new instance of <code>PSpecified</code> with the specified * parameter <code>P</code>. - * + * * @param p * the parameter <code>P</code>. * @throws NullPointerException @@ -98,7 +95,7 @@ public class PSource { /** * Returns a copy of the value of the parameter <code>P</code>. - * + * * @return a copy of the value of the parameter <code>P</code> */ public byte[] getValue() { diff --git a/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java index bd76cf4..bc7a39c 100644 --- a/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/RC2ParameterSpec.java @@ -25,8 +25,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The algorithm parameter specification for the <a * href="http://www.ietf.org/rfc/rfc2268.txt">RC2</a> algorithm. - * - * @since Android 1.0 */ public class RC2ParameterSpec implements AlgorithmParameterSpec { @@ -36,7 +34,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>RC2ParameterSpec</code> instance with the specified * effective key length (in bits), - * + * * @param effectiveKeyBits * the effective key length (in bits). */ @@ -51,7 +49,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { * <p> * The size of the <i>initialization vector</i> must be at least 8 bytes * which are copied to protect them against modification. - * + * * @param effectiveKeyBits * the effective key length (in bits). * @param iv @@ -78,7 +76,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { * The size of the <i>initialization vector</i> starting at * <code>offset</code> must be at least 8 bytes which are copied to protect * them against modification. - * + * * @param effectiveKeyBits * the effective key length (in bits). * @param iv @@ -103,7 +101,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { /** * Returns the effective key length (in bits). - * + * * @return the effective key length (in bits). */ public int getEffectiveKeyBits() { @@ -112,7 +110,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { /** * Returns a copy of the initialization vector. - * + * * @return a copy of the initialization vector, or null if none specified. */ public byte[] getIV() { @@ -127,7 +125,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { /** * Compares the specified object to this <code>RC2ParameterSpec</code> * instance. - * + * * @param obj * the object to compare. * @return true if the effective key length and the initialization vector of @@ -148,7 +146,7 @@ public class RC2ParameterSpec implements AlgorithmParameterSpec { /** * Returns the hash code of this <code>RC2ParameterSpec</code> instance. - * + * * @return the hash code. */ @Override diff --git a/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java b/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java index f711f41..57010f7 100644 --- a/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java +++ b/crypto/src/main/java/javax/crypto/spec/RC5ParameterSpec.java @@ -25,8 +25,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; /** * The algorithm parameter specification for the <a * href="http://www.ietf.org/rfc/rfc2040.txt">RC5</a> algorithm. - * - * @since Android 1.0 */ public class RC5ParameterSpec implements AlgorithmParameterSpec { @@ -38,7 +36,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Creates a new <code>RC5ParameterSpec</code> instance with the specified * version, round count an word size (in bits). - * + * * @param version * the version. * @param rounds @@ -61,7 +59,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { * The size of the <i>initialization vector</i> must be at least * <code>2 * (wordSize / 8)</code> bytes which are copied to protect them * against modification. - * + * * @param version * the version. * @param rounds @@ -97,7 +95,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { * The size of the <i>initialization vector</i> must be at least * <code>offset + (2 * (wordSize / 8))</code> bytes. The bytes starting at * <code>offset</code> are copied to protect them against modification. - * + * * @param version * the version. * @param rounds @@ -135,7 +133,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Returns the version. - * + * * @return the version. */ public int getVersion() { @@ -144,7 +142,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Returns the round count. - * + * * @return the round count. */ public int getRounds() { @@ -153,7 +151,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Returns the word size (in bits). - * + * * @return the word size (in bits). */ public int getWordSize() { @@ -162,7 +160,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Returns a copy of the initialization vector. - * + * * @return a copy of the initialization vector, or null if none specified. */ public byte[] getIV() { @@ -177,7 +175,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Compares the specified object with this <code>RC5ParameterSpec</code> * instance. - * + * * @param obj * the object to compare. * @return true if version, round count, word size and initializaion vector @@ -200,7 +198,7 @@ public class RC5ParameterSpec implements AlgorithmParameterSpec { /** * Returns the hash code of this <code>RC5ParameterSpec</code> instance. - * + * * @return the hash code. */ @Override diff --git a/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java b/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java index 897948c..d1eba47 100644 --- a/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java +++ b/crypto/src/main/java/javax/crypto/spec/SecretKeySpec.java @@ -33,8 +33,6 @@ import org.apache.harmony.crypto.internal.nls.Messages; * A key specification for a <code>SecretKey</code> and also a secret key * implementation that is provider-independent. It can be used for raw secret * keys that can be specified as <code>byte[]</code>. - * - * @since Android 1.0 */ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { @@ -50,7 +48,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Creates a new <code>SecretKeySpec</code> for the specified key data and * algorithm name. - * + * * @param key * the key data. * @param algorithm @@ -79,7 +77,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { * Creates a new <code>SecretKeySpec</code> for the key data from the * specified buffer <code>key</code> starting at <code>offset</code> with * length <code>len</code> and the specified <code>algorithm</code> name. - * + * * @param key * the key data. * @param offset @@ -120,7 +118,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Returns the algorithm name. - * + * * @return the algorithm name. */ public String getAlgorithm() { @@ -129,7 +127,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Returns the name of the format used to encode the key. - * + * * @return the format name "RAW". */ public String getFormat() { @@ -138,7 +136,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Returns the encoded form of this secret key. - * + * * @return the encoded form of this secret key. */ public byte[] getEncoded() { @@ -149,7 +147,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Returns the hash code of this <code>SecretKeySpec</code> object. - * + * * @return the hash code. */ @Override @@ -164,7 +162,7 @@ public class SecretKeySpec implements SecretKey, KeySpec, Serializable { /** * Compares the specified object with this <code>SecretKeySpec</code> * instance. - * + * * @param obj * the object to compare. * @return true if the algorithm name and key of both object are equal, diff --git a/dalvik/src/main/java/dalvik/system/SamplingProfiler.java b/dalvik/src/main/java/dalvik/system/SamplingProfiler.java index 694df38..1d88dd1 100644 --- a/dalvik/src/main/java/dalvik/system/SamplingProfiler.java +++ b/dalvik/src/main/java/dalvik/system/SamplingProfiler.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2009 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 dalvik.system; import java.util.logging.Logger; @@ -15,62 +31,78 @@ public class SamplingProfiler { private static final Logger logger = Logger.getLogger( SamplingProfiler.class.getName()); + static final boolean DEBUG = false; + + enum State { + /** The sampling thread hasn't started or is waiting to resume. */ + PAUSED, + /** The sampling thread is collecting samples. */ + RUNNING, + /** The sampling thread is shutting down. */ + SHUTTING_DOWN + } + /** Pointer to native state. */ int pointer = 0; /** The thread that collects samples. */ Thread samplingThread; - /** Whether or not the profiler is running. */ - boolean running = false; - int delayPerThread; // ms + /** Time between samples. */ + volatile int delay; // ms - /** Number of samples taken. */ - int sampleCount = 0; + /** Number of samples taken (~samples per second * number of threads). */ + int totalThreadsSampled = 0; /** Total time spent collecting samples. */ long totalSampleTime = 0; + /** The state of the profiler. */ + volatile State state = State.PAUSED; + private SamplingProfiler() {} /** * Returns true if the profiler is running. */ public boolean isRunning() { - return running; + return state == State.RUNNING; } /** * Starts collecting samples. * - * @param threadsPerSecond number of threads to sample per second + * @param samplesPerSecond number of times to sample each thread per second + * @throws IllegalStateException if the profiler is + * {@linkplain #shutDown()} shutting down} */ - public synchronized void start(int threadsPerSecond) { - if (threadsPerSecond < 1) { - throw new IllegalArgumentException("threadsPerSecond < 1"); + public synchronized void start(int samplesPerSecond) { + if (samplesPerSecond < 1) { + throw new IllegalArgumentException("samplesPerSecond < 1"); } - if (!running) { - logger.info("Starting profiler."); - running = true; + ensureNotShuttingDown(); + delay = 1000 / samplesPerSecond; + if (!isRunning()) { + if (DEBUG) logger.info("Starting profiler..."); + state = State.RUNNING; if (samplingThread == null) { // TODO: Priority? - samplingThread = new Thread(new Sampler()); + samplingThread = new Thread(new Sampler(), "SamplingProfiler"); samplingThread.setDaemon(true); samplingThread.start(); } else { notifyAll(); } } - delayPerThread = 1000 / threadsPerSecond; } /** - * Stops sample collection. + * Pauses sample collection. */ - public synchronized void stop() { - if (running) { - logger.info("Stopping profiler."); - running = false; + public synchronized void pause() { + if (isRunning()) { + if (DEBUG) logger.info("Pausing profiler..."); + state = State.PAUSED; } } @@ -80,49 +112,123 @@ public class SamplingProfiler { * * <p>Note: The exact format is not documented because it's not set in * stone yet. + * + * @throws IllegalStateException if the profiler is + * {@linkplain #shutDown()} shutting down} */ public synchronized byte[] snapshot() { - if (pointer == 0 || sampleCount == 0) { + ensureNotShuttingDown(); + if (pointer == 0 || totalThreadsSampled == 0) { return null; } - int size = size(pointer); - int collisions = collisions(pointer); - - long start = System.nanoTime(); - byte[] bytes = snapshot(pointer); - long elapsed = System.nanoTime() - start; - - logger.info("Grabbed snapshot in " + (elapsed / 1000) + "us." - + " Samples collected: " + sampleCount - + ", Average sample time (per thread): " - + (((totalSampleTime / sampleCount) << 10) / 1000) + "us" - + ", Set size: " + size - + ", Collisions: " + collisions); - sampleCount = 0; - totalSampleTime = 0; - - return bytes; + if (DEBUG) { + int size = size(pointer); + int collisions = collisions(pointer); + + long start = System.nanoTime(); + byte[] bytes = snapshot(pointer); + long elapsed = System.nanoTime() - start; + + /* + * We shifted the times by 10 bits in the sampling thread to avoid + * overflow. Undo the shift and then convert from ns to us. + */ + long averageSampleTime = ((totalSampleTime / totalThreadsSampled) + << 10) / 1000; + logger.info("Grabbed snapshot in " + (elapsed / 1000) + "us." + + " Samples collected: " + totalThreadsSampled + + ", Average sample time (per thread): " + + averageSampleTime + "us" + + ", Set size: " + size + + ", Collisions: " + collisions); + totalThreadsSampled = 0; + totalSampleTime = 0; + + return bytes; + } else { + totalThreadsSampled = 0; + return snapshot(pointer); + } } /** * Identifies the "event thread". For a user-facing application, this * might be the UI thread. For a background process, this might be the * thread that processes incoming requests. + * + * @throws IllegalStateException if the profiler is + * {@linkplain #shutDown()} shutting down} */ public synchronized void setEventThread(Thread eventThread) { + ensureNotShuttingDown(); if (pointer == 0) { pointer = allocate(); } setEventThread(pointer, eventThread); } + private void ensureNotShuttingDown() { + if (state == State.SHUTTING_DOWN) { + throw new IllegalStateException("Profiler is shutting down."); + } + } + + /** + * Shuts down the profiler thread and frees native memory. The profiler + * will recreate the thread the next time {@link #start(int)} is called. + * + * @throws IllegalStateException if the profiler is already shutting down + * or if it hasn't started yet + * + */ + public void shutDown() { + Thread toStop; + synchronized (this) { + ensureNotShuttingDown(); + + toStop = samplingThread; + if (toStop == null) { + throw new IllegalStateException( + "The profiler was never started."); + } + + state = State.SHUTTING_DOWN; + samplingThread = null; + notifyAll(); + } + + // Release lock to 'this' so background thread can grab it and stop. + // Interrupt the thread in case it's sleeping. + toStop.interrupt(); + while (true) { + try { + toStop.join(); + break; + } catch (InterruptedException e) { /* ignore */ } + } + + synchronized (this) { + if (pointer != 0) { + free(pointer); + pointer = 0; + } + + totalThreadsSampled = 0; + totalSampleTime = 0; + state = State.PAUSED; + } + } + /** Collects some data. Returns number of threads sampled. */ private static native int sample(int pointer); /** Allocates native state. */ private static native int allocate(); + /** Frees native state. */ + private static native void free(int pointer); + /** Gets the number of methods in the sample set. */ private static native int size(int pointer); @@ -142,11 +248,15 @@ public class SamplingProfiler { public void run() { boolean firstSample = true; while (true) { - int threadsSampled; synchronized (SamplingProfiler.this) { - if (!running) { - logger.info("Stopped profiler."); - while (!running) { + if (!isRunning()) { + if (DEBUG) logger.info("Paused profiler."); + while (!isRunning()) { + if (state == State.SHUTTING_DOWN) { + // Stop thread. + return; + } + try { SamplingProfiler.this.wait(); } catch (InterruptedException e) { /* ignore */ } @@ -159,20 +269,24 @@ public class SamplingProfiler { } if (firstSample) { - logger.info("Started profiler."); + if (DEBUG) logger.info("Started profiler."); firstSample = false; } - long start = System.nanoTime(); - threadsSampled = sample(pointer); - long elapsed = System.nanoTime() - start; + if (DEBUG) { + long start = System.nanoTime(); + int threadsSampled = sample(pointer); + long elapsed = System.nanoTime() - start; - sampleCount += threadsSampled; - totalSampleTime += elapsed >> 10; // shift avoids overflow. + totalThreadsSampled += threadsSampled; + totalSampleTime += elapsed >> 10; // avoids overflow. + } else { + totalThreadsSampled += sample(pointer); + } } try { - Thread.sleep(delayPerThread * threadsSampled); + Thread.sleep(delay); } catch (InterruptedException e) { /* ignore */ } } } @@ -211,9 +325,12 @@ public class SamplingProfiler { private static void appendCounts(DataInputStream in, StringBuilder sb) throws IOException { - sb.append(" running: ").append(in.readShort()).append('\n'); - sb.append(" native: ").append(in.readShort()).append('\n'); - sb.append(" suspended: ").append(in.readShort()).append('\n'); + sb.append(" running:\n"); + sb.append(" caller: ").append(in.readShort()).append('\n'); + sb.append(" leaf: ").append(in.readShort()).append('\n'); + sb.append(" suspended:\n"); + sb.append(" caller: ").append(in.readShort()).append('\n'); + sb.append(" leaf: ").append(in.readShort()).append('\n'); } /** This will be allocated when the user calls getInstance(). */ diff --git a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java index 206f0c8..919d865 100644 --- a/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java +++ b/icu/src/main/java/com/ibm/icu4jni/charset/CharsetDecoderICU.java @@ -344,18 +344,11 @@ public final class CharsetDecoderICU extends CharsetDecoder{ // ok was there input held in the previous invocation of decodeLoop // that resulted in output in this invocation? - if(data[OUTPUT_OFFSET]>0 && savedInputHeldLen >0){ - int len = in.position() + data[INPUT_OFFSET] + savedInputHeldLen; - in.position(len); - savedInputHeldLen = data[INPUT_HELD]; - }else{ - in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen); - savedInputHeldLen = data[INPUT_HELD]; - in.position(in.position() - savedInputHeldLen); - } - // BEGIN android-added + // BEGIN android-changed + in.position(in.position() + data[INPUT_OFFSET] + savedInputHeldLen - data[INPUT_HELD]); + savedInputHeldLen = data[INPUT_HELD]; // release reference to input array, which may not be ours input = null; - // END android-added + // END android-changed } } diff --git a/icu/src/main/java/com/ibm/icu4jni/util/Resources.java b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java index 85530ac..0460fde 100644 --- a/icu/src/main/java/com/ibm/icu4jni/util/Resources.java +++ b/icu/src/main/java/com/ibm/icu4jni/util/Resources.java @@ -179,20 +179,28 @@ public class Resources { private static String getDefaultLocaleName() { return java.util.Locale.getDefault().toString(); } - - /** - * Name of default locale at the time this class was initialized. - */ - private static final String initialLocale = getDefaultLocaleName(); /** - * Names of time zones for the default locale. + * Initialization holder for default time zone names. This class will + * be preloaded by the zygote to share the time and space costs of setting + * up the list of time zone names, so although it looks like the lazy + * initialization idiom, it's actually the opposite. */ - private static String[][] defaultTimezoneNames = null; + private static class DefaultTimeZones { + /** + * Name of default locale at the time this class was initialized. + */ + private static final String locale = getDefaultLocaleName(); + + /** + * Names of time zones for the default locale. + */ + private static final String[][] names = createTimeZoneNamesFor(locale); + } /** * Creates array of time zone names for the given locale. This method takes - * about 2s to run on a 400mhz ARM11. + * about 2s to run on a 400MHz ARM11. */ private static String[][] createTimeZoneNamesFor(String locale) { long start = System.currentTimeMillis(); @@ -252,22 +260,16 @@ public class Resources { * the TomeZone class. */ public static String[][] getDisplayTimeZones(String locale) { - // Note: Defer loading DefaultTimeZones as long as possible. - - String defaultLocaleName = getDefaultLocaleName(); + String defaultLocale = getDefaultLocaleName(); if (locale == null) { - locale = defaultLocaleName; + locale = defaultLocale; } // If locale == default and the default locale hasn't changed since // DefaultTimeZones loaded, return the cached names. // TODO: We should force a reboot if the default locale changes. - if (defaultLocaleName.equals(locale) - && initialLocale.equals(defaultLocaleName)) { - if (defaultTimezoneNames == null) { - defaultTimezoneNames = createTimeZoneNamesFor(locale); - } - return defaultTimezoneNames; + if (defaultLocale.equals(locale) && DefaultTimeZones.locale.equals(defaultLocale)) { + return DefaultTimeZones.names; } return createTimeZoneNamesFor(locale); diff --git a/luni-kernel/src/main/java/java/lang/Class.java b/luni-kernel/src/main/java/java/lang/Class.java index 6adf4db..b8e3903 100644 --- a/luni-kernel/src/main/java/java/lang/Class.java +++ b/luni-kernel/src/main/java/java/lang/Class.java @@ -469,6 +469,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * * @param parameterTypes * the parameter types of the requested constructor. + * {@code (Class[]) null} is equivalent to the empty array. * @return the constructor described by {@code parameterTypes}. * @throws NoSuchMethodException * if the constructor can not be found. @@ -587,6 +588,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * * @param parameterTypes * the parameter types of the requested constructor. + * {@code (Class[]) null} is equivalent to the empty array. * @return the constructor described by {@code parameterTypes}. * @throws NoSuchMethodException * if the requested constructor can not be found. @@ -659,12 +661,14 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe sb.append(getSimpleName()); sb.append('('); boolean first = true; - for (Class<?> p : parameterTypes) { - if (!first) { - sb.append(','); + if (parameterTypes != null) { + for (Class<?> p : parameterTypes) { + if (!first) { + sb.append(','); + } + first = false; + sb.append(p.getSimpleName()); } - first = false; - sb.append(p.getSimpleName()); } sb.append(')'); throw new NoSuchMethodException(sb.toString()); @@ -741,6 +745,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * the requested method's name. * @param parameterTypes * the parameter types of the requested method. + * {@code (Class[]) null} is equivalent to the empty array. * @return the method described by {@code name} and {@code parameterTypes}. * @throws NoSuchMethodException * if the requested constructor can not be found. @@ -991,6 +996,7 @@ public final class Class<T> implements Serializable, AnnotatedElement, GenericDe * the requested method's name. * @param parameterTypes * the parameter types of the requested method. + * {@code (Class[]) null} is equivalent to the empty array. * @return the public field specified by {@code name}. * @throws NoSuchMethodException * if the method can not be found. diff --git a/luni-kernel/src/main/java/java/lang/Thread.java b/luni-kernel/src/main/java/java/lang/Thread.java index 484c258..4f9f988 100644 --- a/luni-kernel/src/main/java/java/lang/Thread.java +++ b/luni-kernel/src/main/java/java/lang/Thread.java @@ -922,9 +922,7 @@ public class Thread implements Runnable { * @since Android 1.0 */ public final boolean isAlive() { - Thread.State state = getState(); - - return (state != Thread.State.TERMINATED && state != Thread.State.NEW); + return (vmThread != null); } /** diff --git a/luni/src/main/java/java/net/DatagramSocket.java b/luni/src/main/java/java/net/DatagramSocket.java index 6b3b6cc..ba5e207 100644 --- a/luni/src/main/java/java/net/DatagramSocket.java +++ b/luni/src/main/java/java/net/DatagramSocket.java @@ -81,7 +81,7 @@ public class DatagramSocket { public DatagramSocket(int aPort) throws SocketException { super(); checkListen(aPort); - createSocket(aPort, InetAddress.ANY); + createSocket(aPort, Inet4Address.ANY); } /** @@ -99,7 +99,7 @@ public class DatagramSocket { public DatagramSocket(int aPort, InetAddress addr) throws SocketException { super(); checkListen(aPort); - createSocket(aPort, null == addr ? InetAddress.ANY : addr); + createSocket(aPort, null == addr ? Inet4Address.ANY : addr); } /** @@ -228,7 +228,7 @@ public class DatagramSocket { return null; } if (!isBound()) { - return InetAddress.ANY; + return Inet4Address.ANY; } InetAddress anAddr = impl.getLocalAddress(); try { @@ -237,7 +237,7 @@ public class DatagramSocket { security.checkConnect(anAddr.getHostName(), -1); } } catch (SecurityException e) { - return InetAddress.ANY; + return Inet4Address.ANY; } return anAddr; } @@ -603,7 +603,7 @@ public class DatagramSocket { } if (bind && !isBound()) { checkListen(0); - impl.bind(0, InetAddress.ANY); + impl.bind(0, Inet4Address.ANY); isBound = true; } } @@ -624,7 +624,7 @@ public class DatagramSocket { public void bind(SocketAddress localAddr) throws SocketException { checkClosedAndBind(false); int localPort = 0; - InetAddress addr = InetAddress.ANY; + InetAddress addr = Inet4Address.ANY; if (localAddr != null) { if (!(localAddr instanceof InetSocketAddress)) { throw new IllegalArgumentException(Msg.getString( diff --git a/luni/src/main/java/java/net/Inet4Address.java b/luni/src/main/java/java/net/Inet4Address.java index 23efa5e..5e1a420 100644 --- a/luni/src/main/java/java/net/Inet4Address.java +++ b/luni/src/main/java/java/net/Inet4Address.java @@ -33,11 +33,17 @@ public final class Inet4Address extends InetAddress { private static final long serialVersionUID = 3286316764910316507L; + final static InetAddress ANY = new Inet4Address(new byte[] { 0, 0, 0, 0 }); + final static InetAddress LOOPBACK = new Inet4Address( + new byte[] { 127, 0, 0, 1 }, "localhost"); //$NON-NLS-1$ + Inet4Address(byte[] address) { + family = AF_INET; ipaddress = address; } Inet4Address(byte[] address, String name) { + family = AF_INET; ipaddress = address; hostName = name; } @@ -228,31 +234,17 @@ public final class Inet4Address extends InetAddress { return hostAddress; } - /** - * Gets the hashcode of the represented IP address. - * - * @return the appropriate hashcode value. - */ - @Override - public int hashCode() { - return InetAddress.bytesToInt(ipaddress, 0); - } + // BEGIN android-removed + // public int hashCode() { + // } + // END android-removed - /** - * Compares this instance with the IP address in the object {@code obj} and - * returns {@code true} if they are of the same type and represent the same - * IP address, {@code false} otherwise. - * - * @param obj - * the object to be tested for equality. - * @return {@code true} if the addresses are equal, {@code false} otherwise. - */ - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } + // BEGIN android-removed + // public boolean equals(Object obj) { + // } + // END android-removed private Object writeReplace() throws ObjectStreamException { - return new InetAddress(ipaddress, hostName); + return new Inet4Address(ipaddress, hostName); } } diff --git a/luni/src/main/java/java/net/Inet6Address.java b/luni/src/main/java/java/net/Inet6Address.java index 5c19663..91ec48e 100644 --- a/luni/src/main/java/java/net/Inet6Address.java +++ b/luni/src/main/java/java/net/Inet6Address.java @@ -21,7 +21,6 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.ObjectStreamField; -import java.util.Arrays; import java.util.Enumeration; import org.apache.harmony.luni.util.Inet6Util; @@ -34,16 +33,10 @@ public final class Inet6Address extends InetAddress { private static final long serialVersionUID = 6880410070516793377L; - static final byte[] any_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 }; - - static final byte[] localhost_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 1 }; - - static final InetAddress ANY = new Inet6Address(any_bytes); - - static final InetAddress LOOPBACK = new Inet6Address(localhost_bytes, - "localhost"); //$NON-NLS-1$ + static final InetAddress ANY = new Inet6Address(new byte[] + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }); + static final InetAddress LOOPBACK = new Inet6Address(new byte[] + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, "localhost"); //$NON-NLS-1$ int scope_id; @@ -59,11 +52,13 @@ public final class Inet6Address extends InetAddress { transient NetworkInterface scopedIf; Inet6Address(byte address[]) { + family = AF_INET6; ipaddress = address; scope_id = 0; } Inet6Address(byte address[], String name) { + family = AF_INET6; hostName = name; ipaddress = address; scope_id = 0; @@ -81,6 +76,7 @@ public final class Inet6Address extends InetAddress { * the scope id for link- or site-local addresses. */ Inet6Address(byte address[], String name, int scope_id) { + family = AF_INET6; hostName = name; ipaddress = address; this.scope_id = scope_id; @@ -403,30 +399,13 @@ public final class Inet6Address extends InetAddress { return null; } - /** - * Gets the hashcode of the represented IP address. - * - * @return the appropriate hashcode value. - */ - @Override - public int hashCode() { - return Arrays.hashCode(ipaddress); - } + // BEGIN android-removed + // public int hashCode() {} + // END android-removed - /** - * Compares this instance with the IP address in the object {@code obj} and - * returns {@code true} if they are of the same type and represent the same - * IP address, {@code false} otherwise. The scope id does not seem to be - * part of the comparison. - * - * @param obj - * the object to be tested for equality. - * @return {@code true} if the addresses are equal, {@code false} otherwise. - */ - @Override - public boolean equals(Object obj) { - return super.equals(obj); - } + // BEGIN android-removed + // public boolean equals(Object obj) {} + // END android-removed /** * Returns whether this address is IPv4 compatible or not. An IPv4 diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java index eec153f..a7ea3f6 100644 --- a/luni/src/main/java/java/net/InetAddress.java +++ b/luni/src/main/java/java/net/InetAddress.java @@ -46,17 +46,8 @@ import org.apache.harmony.luni.util.PriviAction; */ public class InetAddress extends Object implements Serializable { - final static byte[] any_bytes = { 0, 0, 0, 0 }; - - final static byte[] localhost_bytes = { 127, 0, 0, 1 }; - - static InetAddress ANY = new Inet4Address(any_bytes); - private final static INetworkSystem NETIMPL = Platform.getNetworkSystem(); - final static InetAddress LOOPBACK = new Inet4Address(localhost_bytes, - "localhost"); //$NON-NLS-1$ - private static final String ERRMSG_CONNECTION_REFUSED = "Connection refused"; //$NON-NLS-1$ private static final long serialVersionUID = 3286316764910316507L; @@ -79,7 +70,9 @@ public class InetAddress extends Object implements Serializable { private int addrCount; - int family = 2; + int family = 0; + static final int AF_INET = 2; + static final int AF_INET6 = 10; byte[] ipaddress; @@ -93,12 +86,22 @@ public class InetAddress extends Object implements Serializable { // END android-removed /** - * Constructs an InetAddress. + * Constructs an {@code InetAddress}. + * + * Note: this constructor should not be used. Creating an InetAddress + * without specifying whether it's an IPv4 or IPv6 address does not make + * sense, because subsequent code cannot know which of of the subclasses' + * methods need to be called to implement a given InetAddress method. The + * proper way to create an InetAddress is to call new Inet4Address or + * Inet6Address or to use one of the static methods that return + * InetAddresses (e.g., getByAddress). That is why the API does not have + * public constructors for any of these classes. */ InetAddress() { super(); } + // BEGIN android-removed /** * Constructs an {@code InetAddress}, representing the {@code address} and * {@code hostName}. @@ -106,23 +109,27 @@ public class InetAddress extends Object implements Serializable { * @param address * the network address. */ - InetAddress(byte[] address) { - super(); - this.ipaddress = address; - } + // InetAddress(byte[] address) { + // super(); + // this.ipaddress = address; + // } + // END android-removed + // BEGIN android-removed /** * Constructs an {@code InetAddress}, representing the {@code address} and * {@code hostName}. * * @param address * the network address. + * */ - InetAddress(byte[] address, String hostName) { - super(); - this.ipaddress = address; - this.hostName = hostName; - } + // InetAddress(byte[] address, String hostName) { + // super(); + // this.ipaddress = address; + // this.hostName = hostName; + // } + // END android-removed // BEGIN android-removed // CacheElement cacheElement() { @@ -145,21 +152,8 @@ public class InetAddress extends Object implements Serializable { if (!(obj instanceof InetAddress)) { return false; } + return Arrays.equals(this.ipaddress, ((InetAddress) obj).ipaddress); // END android-changed - - // now check if their byte arrays match... - byte[] objIPaddress = ((InetAddress) obj).ipaddress; - // BEGIN android-added - if (objIPaddress.length != ipaddress.length) { - return false; - } - // END android-added - for (int i = 0; i < objIPaddress.length; i++) { - if (objIPaddress[i] != this.ipaddress[i]) { - return false; - } - } - return true; } /** @@ -253,15 +247,17 @@ public class InetAddress extends Object implements Serializable { throws UnknownHostException { if (host == null || 0 == host.length()) { if (preferIPv6Addresses()) { - return new InetAddress[] { Inet6Address.LOOPBACK, LOOPBACK }; + return new InetAddress[] { Inet6Address.LOOPBACK, + Inet4Address.LOOPBACK }; } else { - return new InetAddress[] { LOOPBACK, Inet6Address.LOOPBACK }; + return new InetAddress[] { Inet4Address.LOOPBACK, + Inet6Address.LOOPBACK }; } } // Special-case "0" for legacy IPv4 applications. if (host.equals("0")) { //$NON-NLS-1$ - return new InetAddress[] { InetAddress.ANY }; + return new InetAddress[] { Inet4Address.ANY }; } if (isHostName(host)) { @@ -281,8 +277,10 @@ public class InetAddress extends Object implements Serializable { return (new InetAddress[] { new Inet4Address(hBytes) }); } else if (hBytes.length == 16) { return (new InetAddress[] { new Inet6Address(hBytes) }); + } else { + throw new UnknownHostException( + Msg.getString("K0339")); //$NON-NLS-1$ } - return (new InetAddress[] { new InetAddress(hBytes) }); } // END android-added @@ -403,7 +401,7 @@ public class InetAddress extends Object implements Serializable { security.checkConnect(host, -1); } } catch (SecurityException e) { - return InetAddress.LOOPBACK; + return Inet4Address.LOOPBACK; } return lookupHostByName(host)[0]; } @@ -415,18 +413,24 @@ public class InetAddress extends Object implements Serializable { */ @Override public int hashCode() { - return bytesToInt(ipaddress, 0); + // BEGIN android-changed + return Arrays.hashCode(ipaddress); + // END android-changed } - /** - * Returns whether this address is an IP multicast address or not. + // BEGIN android-changed + /* + * Returns whether this address is an IP multicast address or not. This + * implementation returns always {@code false}. * * @return {@code true} if this address is in the multicast group, {@code * false} otherwise. */ public boolean isMulticastAddress() { - return ((ipaddress[0] & 255) >>> 4) == 0xE; + return false; } + // END android-changed + /** * Resolves a hostname to its IP addresses using a cache for faster lookups. @@ -530,7 +534,14 @@ public class InetAddress extends Object implements Serializable { // throws UnknownHostException; static InetAddress getHostByAddrImpl(byte[] addr) throws UnknownHostException { - return new InetAddress(addr, gethostbyaddr(addr)); + if (addr.length == 4) { + return new Inet4Address(addr, gethostbyaddr(addr)); + } else if (addr.length == 16) { + return new Inet6Address(addr, gethostbyaddr(addr)); + } else { + throw new UnknownHostException(Msg.getString( + "K0339")); //$NON-NLS-1$ + } } /** @@ -618,7 +629,7 @@ public class InetAddress extends Object implements Serializable { static String getHostNameInternal(String host) throws UnknownHostException { if (host == null || 0 == host.length()) { - return InetAddress.LOOPBACK.getHostAddress(); + return Inet4Address.LOOPBACK.getHostAddress(); } if (isHostName(host)) { return lookupHostByName(host)[0].getHostAddress(); @@ -1113,7 +1124,7 @@ public class InetAddress extends Object implements Serializable { throws UnknownHostException { // simply call the method by the same name specifying the default scope // id of 0 - return getByAddress(ipAddress, 0); + return getByAddressInternal(null, ipAddress, 0); } /** @@ -1133,51 +1144,35 @@ public class InetAddress extends Object implements Serializable { */ static InetAddress getByAddress(byte[] ipAddress, int scope_id) throws UnknownHostException { - byte[] copy_address; - if (ipAddress != null && ipAddress.length == 4) { - copy_address = new byte[4]; - for (int i = 0; i < 4; i++) { - copy_address[i] = ipAddress[i]; - } - return new Inet4Address(copy_address); - } - - if (ipAddress != null && ipAddress.length == 16) { - // First check to see if the address is an IPv6-mapped - // IPv4 address. If it is, then we can make it a IPv4 - // address, otherwise, we'll create an IPv6 address. - if (isIPv4MappedAddress(ipAddress)) { - copy_address = new byte[4]; - for (int i = 0; i < 4; i++) { - copy_address[i] = ipAddress[12 + i]; - } - return new Inet4Address(copy_address); - } - copy_address = ipAddress.clone(); - return new Inet6Address(copy_address, scope_id); - } - - // K0339=Invalid IP Address is neither 4 or 16 bytes - throw new UnknownHostException(Msg.getString("K0339")); //$NON-NLS-1$ + return getByAddressInternal(null, ipAddress, scope_id); } private static boolean isIPv4MappedAddress(byte ipAddress[]) { // Check if the address matches ::FFFF:d.d.d.d // The first 10 bytes are 0. The next to are -1 (FF). // The last 4 bytes are varied. + if (ipAddress == null || ipAddress.length != 16) { + return false; + } for (int i = 0; i < 10; i++) { if (ipAddress[i] != 0) { return false; } } - if (ipAddress[10] != -1 || ipAddress[11] != -1) { return false; } - return true; } + private static byte[] ipv4MappedToIPv4(byte[] mappedAddress) { + byte[] ipv4Address = new byte[4]; + for(int i = 0; i < 4; i++) { + ipv4Address[i] = mappedAddress[12 + i]; + } + return ipv4Address; + } + /** * Returns the {@code InetAddress} corresponding to the array of bytes, and * the given hostname. In the case of an IPv4 address there must be exactly @@ -1227,36 +1222,32 @@ public class InetAddress extends Object implements Serializable { */ static InetAddress getByAddressInternal(String hostName, byte[] ipAddress, int scope_id) throws UnknownHostException { - byte[] copy_address; - if (ipAddress != null && ipAddress.length == 4) { - copy_address = new byte[4]; - for (int i = 0; i < 4; i++) { - copy_address[i] = ipAddress[i]; - } - return new Inet4Address(ipAddress, hostName); + if (ipAddress == null) { + throw new NullPointerException(); } - - if (ipAddress != null && ipAddress.length == 16) { - // First check to see if the address is an IPv6-mapped - // IPv4 address. If it is, then we can make it a IPv4 - // address, otherwise, we'll create an IPv6 address. - if (isIPv4MappedAddress(ipAddress)) { - copy_address = new byte[4]; - for (int i = 0; i < 4; i++) { - copy_address[i] = ipAddress[12 + i]; + switch (ipAddress.length) { + case 4: + return new Inet4Address(ipAddress.clone()); + case 16: + // First check to see if the address is an IPv6-mapped + // IPv4 address. If it is, then we can make it a IPv4 + // address, otherwise, we'll create an IPv6 address. + if (isIPv4MappedAddress(ipAddress)) { + return new Inet4Address(ipv4MappedToIPv4(ipAddress)); + } else { + return new Inet6Address(ipAddress.clone(), scope_id); + } + default: + if (hostName != null) { + // "Invalid IP Address is neither 4 or 16 bytes: <hostName>" + throw new UnknownHostException( + Msg.getString("K0332", hostName)); //$NON-NLS-1$ + } else { + // "Invalid IP Address is neither 4 or 16 bytes" + throw new UnknownHostException( + Msg.getString("K0339")); //$NON-NLS-1$ } - return new Inet4Address(ipAddress, hostName); - } - - copy_address = new byte[16]; - for (int i = 0; i < 16; i++) { - copy_address[i] = ipAddress[i]; - } - - return new Inet6Address(ipAddress, hostName, scope_id); } - - throw new UnknownHostException(Msg.getString("K0332", hostName)); //$NON-NLS-1$ } /** diff --git a/luni/src/main/java/java/net/InetSocketAddress.java b/luni/src/main/java/java/net/InetSocketAddress.java index 13c10f2..08e75a9 100644 --- a/luni/src/main/java/java/net/InetSocketAddress.java +++ b/luni/src/main/java/java/net/InetSocketAddress.java @@ -35,9 +35,9 @@ public class InetSocketAddress extends SocketAddress { private int port; /** - * Creates a socket endpoint with the given port number {@code port} and the - * wildcard address {@code InetAddress.ANY}. The range for valid port numbers - * is between 0 and 65535 inclusive. + * Creates a socket endpoint with the given port number {@code port} and + * no specified address. The range for valid port numbers is between 0 and + * 65535 inclusive. * * @param port * the specified port number to which this socket is bound. @@ -50,7 +50,7 @@ public class InetSocketAddress extends SocketAddress { * Creates a socket endpoint with the given port number {@code port} and * {@code address}. The range for valid port numbers is between 0 and 65535 * inclusive. If {@code address} is {@code null} this socket is bound to the - * wildcard address {@code InetAddress.ANY}. + * IPv4 wildcard address. * * @param port * the specified port number to which this socket is bound. @@ -62,7 +62,7 @@ public class InetSocketAddress extends SocketAddress { throw new IllegalArgumentException(); } if (address == null) { - addr = InetAddress.ANY; + addr = Inet4Address.ANY; } else { addr = address; } diff --git a/luni/src/main/java/java/net/MulticastSocket.java b/luni/src/main/java/java/net/MulticastSocket.java index 0b1c99b..60d967b 100644 --- a/luni/src/main/java/java/net/MulticastSocket.java +++ b/luni/src/main/java/java/net/MulticastSocket.java @@ -146,7 +146,7 @@ public class MulticastSocket extends DatagramSocket { && (InetAddress.preferIPv6Addresses() == true)) { theAddresses[0] = Inet6Address.ANY; } else { - theAddresses[0] = InetAddress.ANY; + theAddresses[0] = Inet4Address.ANY; } return new NetworkInterface(null, null, theAddresses, NetworkInterface.UNSET_INTERFACE_INDEX); @@ -385,7 +385,7 @@ public class MulticastSocket extends DatagramSocket { throw new NullPointerException(); } if (addr.isAnyLocalAddress()) { - impl.setOption(SocketOptions.IP_MULTICAST_IF, InetAddress.ANY); + impl.setOption(SocketOptions.IP_MULTICAST_IF, Inet4Address.ANY); } else if (addr instanceof Inet4Address) { impl.setOption(SocketOptions.IP_MULTICAST_IF, addr); // keep the address used to do the set as we must return the same @@ -449,7 +449,7 @@ public class MulticastSocket extends DatagramSocket { if (netInterface.getIndex() == NetworkInterface.UNSET_INTERFACE_INDEX) { // set the address using IP_MULTICAST_IF to make sure this // works for both IPV4 and IPV6 - impl.setOption(SocketOptions.IP_MULTICAST_IF, InetAddress.ANY); + impl.setOption(SocketOptions.IP_MULTICAST_IF, Inet4Address.ANY); try { // we have the index so now we pass set the interface diff --git a/luni/src/main/java/java/net/ServerSocket.java b/luni/src/main/java/java/net/ServerSocket.java index 99fad3f..f9d5b22 100644 --- a/luni/src/main/java/java/net/ServerSocket.java +++ b/luni/src/main/java/java/net/ServerSocket.java @@ -84,7 +84,7 @@ public class ServerSocket { * if an error occurs while creating the server socket. */ public ServerSocket(int aport) throws IOException { - this(aport, defaultBacklog(), InetAddress.ANY); + this(aport, defaultBacklog(), Inet4Address.ANY); } /** @@ -102,7 +102,7 @@ public class ServerSocket { * if an error occurs while creating the server socket. */ public ServerSocket(int aport, int backlog) throws IOException { - this(aport, backlog, InetAddress.ANY); + this(aport, backlog, Inet4Address.ANY); } /** @@ -127,7 +127,7 @@ public class ServerSocket { checkListen(aport); impl = factory != null ? factory.createSocketImpl() : new PlainServerSocketImpl(); - InetAddress addr = localAddr == null ? InetAddress.ANY : localAddr; + InetAddress addr = localAddr == null ? Inet4Address.ANY : localAddr; synchronized (this) { impl.create(true); @@ -391,7 +391,7 @@ public class ServerSocket { throw new BindException(Msg.getString("K0315")); //$NON-NLS-1$ } int port = 0; - InetAddress addr = InetAddress.ANY; + InetAddress addr = Inet4Address.ANY; if (localAddr != null) { if (!(localAddr instanceof InetSocketAddress)) { throw new IllegalArgumentException(Msg.getString( diff --git a/luni/src/main/java/java/net/Socket.java b/luni/src/main/java/java/net/Socket.java index 71a1bf2..5289566 100644 --- a/luni/src/main/java/java/net/Socket.java +++ b/luni/src/main/java/java/net/Socket.java @@ -479,7 +479,7 @@ public class Socket { */ public InetAddress getLocalAddress() { if (!isBound()) { - return InetAddress.ANY; + return Inet4Address.ANY; } return Platform.getNetworkSystem().getSocketLocalAddress(impl.fd, InetAddress.preferIPv6Addresses()); @@ -767,7 +767,7 @@ public class Socket { throw new IllegalArgumentException(Msg.getString("K0046")); //$NON-NLS-1$ } - InetAddress addr = localAddress == null ? InetAddress.ANY + InetAddress addr = localAddress == null ? Inet4Address.ANY : localAddress; synchronized (this) { impl.create(streaming); @@ -955,7 +955,7 @@ public class Socket { } int port = 0; - InetAddress addr = InetAddress.ANY; + InetAddress addr = Inet4Address.ANY; if (localAddr != null) { if (!(localAddr instanceof InetSocketAddress)) { throw new IllegalArgumentException(Msg.getString( @@ -1047,7 +1047,7 @@ public class Socket { // options on create // impl.create(true); if (!NetUtil.usingSocks(proxy)) { - impl.bind(InetAddress.ANY, 0); + impl.bind(Inet4Address.ANY, 0); } isBound = true; } diff --git a/luni/src/main/java/java/util/HashMap.java b/luni/src/main/java/java/util/HashMap.java index 999063d..af24d86 100644 --- a/luni/src/main/java/java/util/HashMap.java +++ b/luni/src/main/java/java/util/HashMap.java @@ -1,10 +1,10 @@ /* * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with + * 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 + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -15,279 +15,102 @@ * limitations under the License. */ +// BEGIN android-note +// Completely different implementation from harmony. Runs much faster. +// BEGIN android-note + package java.util; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; import java.io.Serializable; /** * HashMap is an implementation of Map. All optional operations (adding and * removing) are supported. Keys and values can be any objects. + * + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values */ -public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, - Cloneable, Serializable { - - private static final long serialVersionUID = 362498820763181265L; - - /* - * Actual count of entries +public class HashMap<K, V> extends AbstractMap<K, V> + implements Cloneable, Serializable, Map<K, V> { + /** + * Min capacity (other than zero) for a HashMap. Must be a power of two + * greater than 1 (and less than 1 << 30). */ - transient int elementCount; + private static final int MINIMUM_CAPACITY = 4; - /* - * The internal data structure to hold Entries + /** + * Max capacity for a HashMap. Must be a power of two >= MINIMUM_CAPACITY. */ - transient Entry<K, V>[] elementData; + private static final int MAXIMUM_CAPACITY = 1 << 30; - /* - * modification count, to keep track of structural modifications between the - * HashMap and the iterator + /** + * An empty table shared by all zero-capacity maps (typically from default + * constructor). It is never written to, and replaced on first put. Its size + * is set to half the minimum, so that the first resize will create a + * minimum-sized table. */ - transient int modCount = 0; + private static final Entry[] EMPTY_TABLE + = new HashMapEntry[MINIMUM_CAPACITY >>> 1]; - /* - * default size that an HashMap created using the default constructor would - * have. + /** + * The default load factor. Note that this implementation ignores the + * load factor, but cannot do away with it entirely because it's + * metioned in the API. + * + * <p>Note that this constant has no impact on the behavior of the program, + * but it is emitted as part of the serialized form. The load factor of + * .75 is hardwired into the program, which uses cheap shifts in place of + * expensive division. */ - private static final int DEFAULT_SIZE = 16; + static final float DEFAULT_LOAD_FACTOR = .75F; - /* - * maximum ratio of (stored elements)/(storage size) which does not lead to - * rehash + /** + * The hash table. If this hash map contains a mapping for null, it is + * not represented this hash table. */ - final float loadFactor; + transient HashMapEntry<K, V>[] table; - /* - * maximum number of elements that can be put in this map before having to - * rehash + /** + * The entry representing the null key, or null if there's no such mapping. */ - int threshold; - - static class Entry<K, V> extends MapEntry<K, V> { - final int origKeyHash; - - Entry<K, V> next; + transient HashMapEntry<K, V> entryForNullKey; - Entry(K theKey, int hash) { - super(theKey, null); - this.origKeyHash = hash; - } - - Entry(K theKey, V theValue) { - super(theKey, theValue); - origKeyHash = (theKey == null ? 0 : computeHashCode(theKey)); - } - - @Override - @SuppressWarnings("unchecked") - public Object clone() { - Entry<K, V> entry = (Entry<K, V>) super.clone(); - if (next != null) { - entry.next = (Entry<K, V>) next.clone(); - } - return entry; - } - } - - private static class AbstractMapIterator<K, V> { - private int position = 0; - int expectedModCount; - Entry<K, V> futureEntry; - Entry<K, V> currentEntry; - Entry<K, V> prevEntry; - - final HashMap<K, V> associatedMap; - - AbstractMapIterator(HashMap<K, V> hm) { - associatedMap = hm; - expectedModCount = hm.modCount; - futureEntry = null; - } - - public boolean hasNext() { - if (futureEntry != null) { - return true; - } - // BEGIN android-changed - Entry<K, V>[] elementData = associatedMap.elementData; - int length = elementData.length; - int newPosition = position; - boolean result = false; - - while (newPosition < length) { - if (elementData[newPosition] == null) { - newPosition++; - } else { - result = true; - break; - } - } - - position = newPosition; - return result; - // END android-changed - } - - final void checkConcurrentMod() throws ConcurrentModificationException { - if (expectedModCount != associatedMap.modCount) { - throw new ConcurrentModificationException(); - } - } - - final void makeNext() { - // BEGIN android-changed - // inline checkConcurrentMod() - if (expectedModCount != associatedMap.modCount) { - throw new ConcurrentModificationException(); - } - // END android-changed - if (!hasNext()) { - throw new NoSuchElementException(); - } - if (futureEntry == null) { - currentEntry = associatedMap.elementData[position++]; - futureEntry = currentEntry.next; - prevEntry = null; - } else { - if(currentEntry!=null){ - prevEntry = currentEntry; - } - currentEntry = futureEntry; - futureEntry = futureEntry.next; - } - } - - public final void remove() { - checkConcurrentMod(); - if (currentEntry==null) { - throw new IllegalStateException(); - } - if(prevEntry==null){ - int index = currentEntry.origKeyHash & (associatedMap.elementData.length - 1); - associatedMap.elementData[index] = associatedMap.elementData[index].next; - } else { - prevEntry.next = currentEntry.next; - } - currentEntry = null; - expectedModCount++; - associatedMap.modCount++; - associatedMap.elementCount--; - - } - } - - - private static class EntryIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<Map.Entry<K, V>> { - - EntryIterator (HashMap<K, V> map) { - super(map); - } - - public Map.Entry<K, V> next() { - makeNext(); - return currentEntry; - } - } - - private static class KeyIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<K> { - - KeyIterator (HashMap<K, V> map) { - super(map); - } - - public K next() { - makeNext(); - return currentEntry.key; - } - } - - private static class ValueIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<V> { - - ValueIterator (HashMap<K, V> map) { - super(map); - } - - public V next() { - makeNext(); - return currentEntry.value; - } - } - - static class HashMapEntrySet<KT, VT> extends AbstractSet<Map.Entry<KT, VT>> { - private final HashMap<KT, VT> associatedMap; - - public HashMapEntrySet(HashMap<KT, VT> hm) { - associatedMap = hm; - } - - HashMap<KT, VT> hashMap() { - return associatedMap; - } - - @Override - public int size() { - return associatedMap.elementCount; - } - - @Override - public void clear() { - associatedMap.clear(); - } - - @Override - public boolean remove(Object object) { - if (object instanceof Map.Entry) { - Map.Entry<?, ?> oEntry = (Map.Entry<?, ?>) object; - Entry<KT,VT> entry = associatedMap.getEntry(oEntry.getKey()); - if(valuesEq(entry, oEntry)) { - associatedMap.removeEntry(entry); - return true; - } - } - return false; - } - - @Override - public boolean contains(Object object) { - if (object instanceof Map.Entry) { - Map.Entry<?, ?> oEntry = (Map.Entry<?, ?>) object; - Entry<KT, VT> entry = associatedMap.getEntry(oEntry.getKey()); - return valuesEq(entry, oEntry); - } - return false; - } - - private static boolean valuesEq(Entry entry, Map.Entry<?, ?> oEntry) { - return (entry != null) && - ((entry.value == null) ? - (oEntry.getValue() == null) : - (areEqualValues(entry.value, oEntry.getValue()))); - } + /** + * The number of mappings in this hash map. + */ + transient int size; - @Override - public Iterator<Map.Entry<KT, VT>> iterator() { - return new EntryIterator<KT,VT> (associatedMap); - } - } + /** + * Incremented by "structural modifications" to allow (best effort) + * detection of concurrent modification. + */ + transient int modCount; /** - * Create a new element array - * - * @param s - * @return Reference to the element array + * The table is rehashed when its size exceeds this threshold. + * The value of this field is generally .75 * capacity, except when + * the capacity is zero, as described in the EMPTY_TABLE declaration + * above. */ - @SuppressWarnings("unchecked") - Entry<K, V>[] newElementArray(int s) { - return new Entry[s]; - } + private transient int threshold; + + // Views - lazily initialized + private transient Set<K> keySet; + private transient Set<Entry<K, V>> entrySet; + private transient Collection<V> values; /** * Constructs a new empty {@code HashMap} instance. */ + @SuppressWarnings("unchecked") public HashMap() { - this(DEFAULT_SIZE); + table = (HashMapEntry<K, V>[]) EMPTY_TABLE; + threshold = -1; // Forces first put invocation to replace EMPTY_TABLE } /** @@ -299,34 +122,26 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * when the capacity is less than zero. */ public HashMap(int capacity) { - this(capacity, 0.75f); // default load factor of 0.75 + if (capacity < 0) { + throw new IllegalArgumentException("Capacity: " + capacity); } - /** - * Calculates the capacity of storage required for storing given number of - * elements - * - * @param x - * number of elements - * @return storage size - */ - private static final int calculateCapacity(int x) { - if(x >= 1 << 30){ - return 1 << 30; + if (capacity == 0) { + @SuppressWarnings("unchecked") + HashMapEntry<K, V>[] tab = (HashMapEntry<K, V>[]) EMPTY_TABLE; + table = tab; + threshold = -1; // Forces first put() to replace EMPTY_TABLE + return; } - if(x == 0){ - return 16; + + if (capacity < MINIMUM_CAPACITY) { + capacity = MINIMUM_CAPACITY; + } else if (capacity > MAXIMUM_CAPACITY) { + capacity = MAXIMUM_CAPACITY; + } else { + capacity = roundUpToPowerOfTwo(capacity); } - // BEGIN android-note - // this may be better optimized as Integer.highestOneBit(x) - // END android-note - x = x -1; - x |= x >> 1; - x |= x >> 2; - x |= x >> 4; - x |= x >> 8; - x |= x >> 16; - return x + 1; + makeTable(capacity); } /** @@ -339,18 +154,20 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * the initial load factor. * @throws IllegalArgumentException * when the capacity is less than zero or the load factor is - * less or equal to zero. + * less or equal to zero or NaN. */ public HashMap(int capacity, float loadFactor) { - if (capacity >= 0 && loadFactor > 0) { - capacity = calculateCapacity(capacity); - elementCount = 0; - elementData = newElementArray(capacity); - this.loadFactor = loadFactor; - computeThreshold(); - } else { - throw new IllegalArgumentException(); + this(capacity); + + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { + throw new IllegalArgumentException("Load factor: " + loadFactor); } + + /* + * Note that this implementation ignores loadFactor; it always uses + * a load facator of 3/4. This simplifies the code and generally + * improves performance. + */ } /** @@ -361,118 +178,92 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * the mappings to add. */ public HashMap(Map<? extends K, ? extends V> map) { - this(calculateCapacity(map.size())); - putAllImpl(map); + this(capacityForInitSize(map.size())); + constructorPutAll(map); } /** - * Removes all mappings from this hash map, leaving it empty. - * - * @see #isEmpty - * @see #size + * Inserts all of the elements of map into this HashMap in a manner + * suitable for use by constructors and pseudocostructors (i.e., clone, + * readObject). Also used by LinkedHashMap. */ - @Override - public void clear() { - // BEGIN android-changed - internalClear(); - // END android-changed + final void constructorPutAll(Map<? extends K, ? extends V> map) { + for (Entry<? extends K, ? extends V> e : map.entrySet()) { + constructorPut(e.getKey(), e.getValue()); + } } - // BEGIN android-added - void internalClear() { - if (elementCount > 0) { - elementCount = 0; - Arrays.fill(elementData, null); - modCount++; - } + /** + * Returns an appropriate capacity for the specified initial size. Does + * not round the result up to a power of two; the caller must do this! + * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive). + */ + static int capacityForInitSize(int size) { + int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth + + // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY + return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY; } - // END android-added /** * Returns a shallow copy of this map. * * @return a shallow copy of this map. */ - @Override @SuppressWarnings("unchecked") - public Object clone() { + @Override public Object clone() { + /* + * This could be made more efficient. It unnecessarily hashes all of + * the elements in the map. + */ + HashMap<K, V> result; try { - HashMap<K, V> map = (HashMap<K, V>) super.clone(); - map.elementCount = 0; - map.elementData = newElementArray(elementData.length); - map.putAll(this); - - return map; + result = (HashMap<K, V>) super.clone(); } catch (CloneNotSupportedException e) { - return null; + throw new AssertionError(e); } - } - /** - * Computes the threshold for rehashing - */ - private void computeThreshold() { - threshold = (int) (elementData.length * loadFactor); + // Restore clone to empty state, retaining our capacity and threshold + result.makeTable(table.length); + result.entryForNullKey = null; + result.size = 0; + result.keySet = null; + result.entrySet = null; + result.values = null; + + result.init(); // Give subclass a chance to initialize itself + result.constructorPutAll(this); // Calls method overridden in subclass!! + return result; } /** - * Returns whether this map contains the specified key. - * - * @param key - * the key to search for. - * @return {@code true} if this map contains the specified key, - * {@code false} otherwise. + * This method is called from the pseudo-constructors (clone and readObject) + * prior to invoking constructorPut/constructorPutAll, which invoke the + * overriden constructorNewEntry method. Normally it is a VERY bad idea to + * invoke an overridden method from a pseudo-constructor (Effective Java + * Item 17). In this cases it is unavoidable, and the init method provides a + * workaround. */ - @Override - public boolean containsKey(Object key) { - Entry<K, V> m = getEntry(key); - return m != null; - } + void init() { } /** - * Returns whether this map contains the specified value. + * Returns whether this map is empty. * - * @param value - * the value to search for. - * @return {@code true} if this map contains the specified value, - * {@code false} otherwise. + * @return {@code true} if this map has no elements, {@code false} + * otherwise. + * @see #size() */ - @Override - public boolean containsValue(Object value) { - if (value != null) { - for (int i = 0; i < elementData.length; i++) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - if (areEqualValues(value, entry.value)) { - return true; - } - entry = entry.next; - } - } - } else { - for (int i = 0; i < elementData.length; i++) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - if (entry.value == null) { - return true; - } - entry = entry.next; - } - } - } - return false; + @Override public boolean isEmpty() { + return size == 0; } /** - * Returns a set containing all of the mappings in this map. Each mapping is - * an instance of {@link Map.Entry}. As the set is backed by this map, - * changes in one will be reflected in the other. + * Returns the number of elements in this map. * - * @return a set of the mappings. + * @return the number of elements in this map. */ - @Override - public Set<Map.Entry<K, V>> entrySet() { - return new HashMapEntrySet<K, V>(this); + @Override public int size() { + return size; } /** @@ -483,104 +274,88 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * @return the value of the mapping with the specified key, or {@code null} * if no mapping for the specified key is found. */ - @Override public V get(Object key) { - Entry<K, V> m = getEntry(key); - if (m != null) { - return m.value; - } - return null; - } - - final Entry<K, V> getEntry(Object key) { - Entry<K, V> m; if (key == null) { - m = findNullKeyEntry(); - } else { - int hash = computeHashCode(key); - int index = hash & (elementData.length - 1); - m = findNonNullKeyEntry(key, index, hash); + HashMapEntry<K, V> e = entryForNullKey; + return e == null ? null : e.value; } - return m; - } - - final Entry<K,V> findNonNullKeyEntry(Object key, int index, int keyHash) { - Entry<K,V> m = elementData[index]; - // BEGIN android-changed - // The VM can optimize String.equals but not Object.equals - if (key instanceof String) { - String keyString = (String) key; - while (m != null && (m.origKeyHash != keyHash || !keyString.equals(m.key))) { - m = m.next; - } - } else { - while (m != null && (m.origKeyHash != keyHash || !areEqualKeys(key, m.key))) { - m = m.next; + // Doug Lea's supplemental secondaryHash function (inlined) + int hash = key.hashCode(); + hash ^= (hash >>> 20) ^ (hash >>> 12); + hash ^= (hash >>> 7) ^ (hash >>> 4); + + HashMapEntry<K, V>[] tab = table; + for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; + e != null; e = e.next) { + K eKey = e.key; + if (eKey == key || (e.hash == hash && key.equals(eKey))) { + return e.value; } } - return m; - // END android-changed - } - - final Entry<K,V> findNullKeyEntry() { - Entry<K,V> m = elementData[0]; - while (m != null && m.key != null) - m = m.next; - return m; + return null; } /** - * Returns whether this map is empty. + * Returns whether this map contains the specified key. * - * @return {@code true} if this map has no elements, {@code false} - * otherwise. - * @see #size() + * @param key + * the key to search for. + * @return {@code true} if this map contains the specified key, + * {@code false} otherwise. */ - @Override - public boolean isEmpty() { - return elementCount == 0; + @Override public boolean containsKey(Object key) { + if (key == null) { + return entryForNullKey != null; + } + + // Doug Lea's supplemental secondaryHash function (inlined) + int hash = key.hashCode(); + hash ^= (hash >>> 20) ^ (hash >>> 12); + hash ^= (hash >>> 7) ^ (hash >>> 4); + + HashMapEntry<K, V>[] tab = table; + for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; + e != null; e = e.next) { + K eKey = e.key; + if (eKey == key || (e.hash == hash && key.equals(eKey))) { + return true; + } + } + return false; } /** - * Returns a set of the keys contained in this map. The set is backed by - * this map so changes to one are reflected by the other. The set does not - * support adding. + * Returns whether this map contains the specified value. * - * @return a set of the keys. + * @param value + * the value to search for. + * @return {@code true} if this map contains the specified value, + * {@code false} otherwise. */ - @Override - public Set<K> keySet() { - if (keySet == null) { - keySet = new AbstractSet<K>() { - @Override - public boolean contains(Object object) { - return containsKey(object); - } - - @Override - public int size() { - return HashMap.this.size(); - } - - @Override - public void clear() { - HashMap.this.clear(); - } - - @Override - public boolean remove(Object key) { - Entry<K, V> entry = HashMap.this.removeEntry(key); - return entry != null; + @Override public boolean containsValue(Object value) { + HashMapEntry[] tab = table; + int len = tab.length; + if (value == null) { + for (int i = 0; i < len; i++) { + for (HashMapEntry e = tab[i]; e != null; e = e.next) { + if (e.value == null) { + return true; + } } + } + return entryForNullKey != null && entryForNullKey.value == null; + } - @Override - public Iterator<K> iterator() { - return new KeyIterator<K,V> (HashMap.this); + // value is non-null + for (int i = 0; i < len; i++) { + for (HashMapEntry e = tab[i]; e != null; e = e.next) { + if (value.equals(e.value)) { + return true; } - }; + } } - return keySet; + return entryForNullKey != null && value.equals(entryForNullKey.value); } /** @@ -593,53 +368,110 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * @return the value of any previous mapping with the specified key or * {@code null} if there was no such mapping. */ - @Override - public V put(K key, V value) { - return putImpl(key, value); - } + @Override public V put(K key, V value) { + if (key == null) { + return putValueForNullKey(value); + } - V putImpl(K key, V value) { - Entry<K,V> entry; - if(key == null) { - entry = findNullKeyEntry(); - if (entry == null) { - modCount++; - if (++elementCount > threshold) { - rehash(); - } - entry = createHashedEntry(null, 0, 0); + int hash = secondaryHash(key.hashCode()); + HashMapEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + HashMapEntry<K, V> first = tab[index]; + for (HashMapEntry<K, V> e = first; e != null; e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + preModify(e); + V oldValue = e.value; + e.value = value; + return oldValue; } + } + + // No entry for (non-null) key is present; create one + modCount++; + if (size++ > threshold) { + tab = doubleCapacity(); + index = hash & (tab.length - 1); + first = tab[index]; + } + tab[index] = newEntry(key, value, hash, first); + return null; + } + + private V putValueForNullKey(V value) { + HashMapEntry<K, V> entry = entryForNullKey; + if (entry == null) { + entryForNullKey = newEntry(null, value, 0, null); + size++; + modCount++; + return null; } else { - int hash = computeHashCode(key); - int index = hash & (elementData.length - 1); - entry = findNonNullKeyEntry(key, index, hash); + preModify(entry); + V oldValue = entry.value; + entry.value = value; + return oldValue; + } + } + + /** + * Give LinkedHashMap a chance to take action when we modify an exisitng + * entry. + * + * @param e the entry we're about to modify. + */ + void preModify(HashMapEntry<K, V> e) { } + + /** + * This method is just like put, except that it doesn't do things that + * are inappropriate or unnecessary for constructors and pseudo-constructors + * (i.e., clone, readObject). In particular, this method does not check to + * ensure that capacity is sufficient, and does not increment modCount. + */ + private void constructorPut(K key, V value) { + if (key == null) { + HashMapEntry<K, V> entry = entryForNullKey; if (entry == null) { - modCount++; - if (++elementCount > threshold) { - rehash(); - index = hash & (elementData.length - 1); - } - entry = createHashedEntry(key, index, hash); + entryForNullKey = constructorNewEntry(null, value, 0, null); + size++; + } else { + entry.value = value; } + return; } - V result = entry.value; - entry.value = value; - return result; + int hash = secondaryHash(key.hashCode()); + HashMapEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + HashMapEntry<K, V> first = tab[index]; + for (HashMapEntry<K, V> e = first; e != null; e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + e.value = value; + return; + } + } + + // No entry for (non-null) key is present; create one + tab[index] = constructorNewEntry(key, value, hash, first); + size++; } - Entry<K, V> createEntry(K key, int index, V value) { - Entry<K, V> entry = new Entry<K, V>(key, value); - entry.next = elementData[index]; - elementData[index] = entry; - return entry; + /** + * Creates a new entry for the given key, value, hash, and successor entry. + * This method is called by put (and indirectly, putAll), and overridden by + * LinkedHashMap. The hash must incorporate the secondary hash function. + */ + HashMapEntry<K, V> newEntry( + K key, V value, int hash, HashMapEntry<K, V> next) { + return new HashMapEntry<K, V>(key, value, hash, next); } - Entry<K,V> createHashedEntry(K key, int index, int hash) { - Entry<K,V> entry = new Entry<K,V>(key,hash); - entry.next = elementData[index]; - elementData[index] = entry; - return entry; + /** + * Like newEntry, but does not perform any activity that would be + * unnecessary or inappropriate for constructors. In this class, the + * two methods behave identically; in LinkedHashMap, they differ. + */ + HashMapEntry<K, V> constructorNewEntry( + K key, V value, int hash, HashMapEntry<K, V> first) { + return new HashMapEntry<K, V>(key, value, hash, first); } /** @@ -649,46 +481,108 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * * @param map * the map to copy mappings from. - * @throws NullPointerException - * if {@code map} is {@code null}. */ - @Override - public void putAll(Map<? extends K, ? extends V> map) { - if (!map.isEmpty()) { - putAllImpl(map); - } + @Override public void putAll(Map<? extends K, ? extends V> map) { + ensureCapacity(map.size()); + super.putAll(map); } - private void putAllImpl(Map<? extends K, ? extends V> map) { - int capacity = elementCount + map.size(); - if (capacity > threshold) { - rehash(capacity); + /** + * Ensures that the hash table has sufficient capacity to store the + * specified number of mappings, with room to grow. If not, it increases the + * capacity as appropriate. Like doubleCapacity, this method moves existing + * entries to new buckets as appropriate. Unlike doubleCapacity, this method + * can grow the table by factors of 2^n for n > 1. Hopefully, a single call + * to this method will be faster than multiple calls to doubleCapacity. + * + * <p>This method is called only by putAll. + */ + private void ensureCapacity(int numMappings) { + int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings)); + HashMapEntry<K, V>[] oldTable = table; + int oldCapacity = oldTable.length; + if (newCapacity <= oldCapacity) { + return; } - for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { - putImpl(entry.getKey(), entry.getValue()); + if (newCapacity == oldCapacity << 1) { + doubleCapacity(); + return; } - } - - void rehash(int capacity) { - int length = calculateCapacity((capacity == 0 ? 1 : capacity << 1)); - Entry<K, V>[] newData = newElementArray(length); - for (int i = 0; i < elementData.length; i++) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - int index = entry.origKeyHash & (length - 1); - Entry<K, V> next = entry.next; - entry.next = newData[index]; - newData[index] = entry; - entry = next; + // We're growing by at least 4x, rehash in the obvious way + HashMapEntry<K, V>[] newTable = makeTable(newCapacity); + if (size != 0) { + int newMask = newCapacity - 1; + for (int i = 0; i < oldCapacity; i++) { + for (HashMapEntry<K, V> e = oldTable[i]; e != null;) { + HashMapEntry<K, V> oldNext = e.next; + int newIndex = e.hash & newMask; + HashMapEntry<K, V> newNext = newTable[newIndex]; + newTable[newIndex] = e; + e.next = newNext; + e = oldNext; + } } } - elementData = newData; - computeThreshold(); } - void rehash() { - rehash(elementData.length); + /** + * Allocate a table of the given capacity and set the threshold accordingly. + * @param newCapacity must be a power of two + */ + private HashMapEntry<K, V>[] makeTable(int newCapacity) { + @SuppressWarnings("unchecked") HashMapEntry<K, V>[] newTable + = (HashMapEntry<K, V>[]) new HashMapEntry[newCapacity]; + table = newTable; + threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity + return newTable; + } + + /** + * Doubles the capacity of the hash table. Existing entries are placed in + * the correct bucket on the enlarged table. If the current capacity is, + * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which + * will be new unless we were already at MAXIMUM_CAPACITY. + */ + private HashMapEntry<K, V>[] doubleCapacity() { + HashMapEntry<K, V>[] oldTable = table; + int oldCapacity = oldTable.length; + if (oldCapacity == MAXIMUM_CAPACITY) { + return oldTable; + } + int newCapacity = oldCapacity << 1; + HashMapEntry<K, V>[] newTable = makeTable(newCapacity); + if (size == 0) { + return newTable; + } + + for (int j = 0; j < oldCapacity; j++) { + /* + * Rehash the bucket using the minimum number of field writes. + * This is the most subtle and delicate code in the class. + */ + HashMapEntry<K, V> e = oldTable[j]; + if (e == null) { + continue; + } + int highBit = e.hash & oldCapacity; + HashMapEntry<K, V> broken = null; + newTable[j | highBit] = e; + for (HashMapEntry<K, V> n = e.next; n != null; e = n, n = n.next) { + int nextHighBit = n.hash & oldCapacity; + if (nextHighBit != highBit) { + if (broken == null) + newTable[j | nextHighBit] = n; + else + broken.next = n; + broken = e; + highBit = nextHighBit; + } + } + if (broken != null) + broken.next = null; + } + return newTable; } /** @@ -699,75 +593,72 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * @return the value of the removed mapping or {@code null} if no mapping * for the specified key was found. */ - @Override - public V remove(Object key) { - Entry<K, V> entry = removeEntry(key); - if (entry != null) { - return entry.value; + @Override public V remove(Object key) { + if (key == null) { + return removeNullKey(); + } + int hash = secondaryHash(key.hashCode()); + HashMapEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashMapEntry<K, V> e = tab[index], prev = null; + e != null; prev = e, e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + if (prev == null) { + tab[index] = e.next; + } else { + prev.next = e.next; + } + modCount++; + size--; + postRemove(e); + return e.value; + } } return null; } - /* - * Remove the given entry from the hashmap. - * Assumes that the entry is in the map. - */ - final void removeEntry(Entry<K, V> entry) { - int index = entry.origKeyHash & (elementData.length - 1); - Entry<K, V> m = elementData[index]; - if (m == entry) { - elementData[index] = entry.next; - } else { - while (m.next != entry) { - m = m.next; - } - m.next = entry.next; - - } - modCount++; - elementCount--; - } - - final Entry<K, V> removeEntry(Object key) { - int index = 0; - Entry<K, V> entry; - Entry<K, V> last = null; - if (key != null) { - int hash = computeHashCode(key); - index = hash & (elementData.length - 1); - entry = elementData[index]; - while (entry != null && !(entry.origKeyHash == hash && areEqualKeys(key, entry.key))) { - last = entry; - entry = entry.next; - } - } else { - entry = elementData[0]; - while (entry != null && entry.key != null) { - last = entry; - entry = entry.next; - } - } - if (entry == null) { + private V removeNullKey() { + HashMapEntry<K, V> e = entryForNullKey; + if (e == null) { return null; } - if (last == null) { - elementData[index] = entry.next; - } else { - last.next = entry.next; - } + entryForNullKey = null; modCount++; - elementCount--; - return entry; + size--; + postRemove(e); + return e.value; } /** - * Returns the number of elements in this map. + * Subclass overrides this method to unlink entry. + */ + void postRemove(HashMapEntry<K, V> e) { } + + /** + * Removes all mappings from this hash map, leaving it empty. * - * @return the number of elements in this map. + * @see #isEmpty + * @see #size + */ + @Override public void clear() { + if (size != 0) { + Arrays.fill(table, null); + entryForNullKey = null; + modCount++; + size = 0; + } + } + + /** + * Returns a set of the keys contained in this map. The set is backed by + * this map so changes to one are reflected by the other. The set does not + * support adding. + * + * @return a set of the keys. */ - @Override - public int size() { - return elementCount; + @Override public Set<K> keySet() { + Set<K> ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet()); } /** @@ -781,83 +672,363 @@ public class HashMap<K, V> extends AbstractMap<K, V> implements Map<K, V>, * "wrapper object" over the iterator of map's entrySet(). The {@code size} * method wraps the map's size method and the {@code contains} method wraps * the map's containsValue method. + * </p> * <p> * The collection is created when this method is called for the first time * and returned in response to all subsequent calls. This method may return * different collections when multiple concurrent calls occur, since no * synchronization is performed. + * </p> * * @return a collection of the values contained in this map. */ - @Override - public Collection<V> values() { - if (valuesCollection == null) { - valuesCollection = new AbstractCollection<V>() { - @Override - public boolean contains(Object object) { - return containsValue(object); - } + @Override public Collection<V> values() { + Collection<V> vs = values; + return (vs != null) ? vs : (values = new Values()); + } - @Override - public int size() { - return HashMap.this.size(); - } + /** + * Returns a set containing all of the mappings in this map. Each mapping is + * an instance of {@link Map.Entry}. As the set is backed by this map, + * changes in one will be reflected in the other. + * + * @return a set of the mappings. + */ + public Set<Entry<K, V>> entrySet() { + Set<Entry<K, V>> es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet()); + } - @Override - public void clear() { - HashMap.this.clear(); + static class HashMapEntry<K, V> implements Entry<K, V> { + final K key; + V value; + final int hash; + HashMapEntry<K, V> next; + + HashMapEntry(K key, V value, int hash, HashMapEntry<K, V> next) { + this.key = key; + this.value = value; + this.hash = hash; + this.next = next; + } + + public final K getKey() { + return key; + } + + public final V getValue() { + return value; + } + + public final V setValue(V value) { + V oldValue = this.value; + this.value = value; + return oldValue; + } + + @Override public final boolean equals(Object o) { + if (!(o instanceof Entry)) { + return false; + } + Entry<?, ?> e = (Entry<?, ?>) o; + return HashMap.equals(e.getKey(), key) + && HashMap.equals(e.getValue(), value); + } + + @Override public final int hashCode() { + return (key == null ? 0 : key.hashCode()) ^ + (value == null ? 0 : value.hashCode()); + } + + @Override public final String toString() { + return key + "=" + value; + } + } + + private abstract class HashIterator { + int nextIndex; + HashMapEntry<K, V> nextEntry = entryForNullKey; + HashMapEntry<K, V> lastEntryReturned; + int expectedModCount = modCount; + + HashIterator() { + if (nextEntry == null) { + HashMapEntry<K, V>[] tab = table; + HashMapEntry<K, V> next = null; + while (next == null && nextIndex < tab.length) { + next = tab[nextIndex++]; } + nextEntry = next; + } + } + + public boolean hasNext() { + return nextEntry != null; + } + + HashMapEntry<K, V> nextEntry() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + if (nextEntry == null) + throw new NoSuchElementException(); + + HashMapEntry<K, V> entryToReturn = nextEntry; + HashMapEntry<K, V>[] tab = table; + HashMapEntry<K, V> next = entryToReturn.next; + while (next == null && nextIndex < tab.length) { + next = tab[nextIndex++]; + } + nextEntry = next; + return lastEntryReturned = entryToReturn; + } + + public void remove() { + if (lastEntryReturned == null) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + HashMap.this.remove(lastEntryReturned.key); + lastEntryReturned = null; + expectedModCount = modCount; + } + } + + private final class KeyIterator extends HashIterator + implements Iterator<K> { + public K next() { return nextEntry().key; } + } - @Override - public Iterator<V> iterator() { - return new ValueIterator<K,V> (HashMap.this); + private final class ValueIterator extends HashIterator + implements Iterator<V> { + public V next() { return nextEntry().value; } + } + + private final class EntryIterator extends HashIterator + implements Iterator<Entry<K, V>> { + public Entry<K, V> next() { return nextEntry(); } + } + + /** + * Returns true if this map contains the specified mapping. + */ + private boolean containsMapping(Object key, Object value) { + if (key == null) { + HashMapEntry<K, V> e = entryForNullKey; + return e != null && equals(value, e.value); + } + + int hash = secondaryHash(key.hashCode()); + HashMapEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashMapEntry<K, V> e = tab[index]; e != null; e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + return equals(value, e.value); + } + } + return false; // No entry for key + } + + /** + * Removes the mapping from key to value and returns true if this mapping + * exists; otherwise, returns does nothing and returns false. + */ + private boolean removeMapping(Object key, Object value) { + if (key == null) { + HashMapEntry<K, V> e = entryForNullKey; + if (e == null || !equals(value, e.value)) { + return false; + } + entryForNullKey = null; + modCount++; + size--; + postRemove(e); + return true; + } + + int hash = secondaryHash(key.hashCode()); + HashMapEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashMapEntry<K, V> e = tab[index], prev = null; + e != null; prev = e, e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + if (!equals(value, e.value)) { + return false; // Map has wrong value for key } - }; + if (prev == null) { + tab[index] = e.next; + } else { + prev.next = e.next; + } + modCount++; + size--; + postRemove(e); + return true; + } } - return valuesCollection; + return false; // No entry for key } - private void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeInt(elementData.length); - stream.writeInt(elementCount); - Iterator<?> iterator = entrySet().iterator(); - while (iterator.hasNext()) { - Entry<?, ?> entry = (Entry<?, ?>) iterator.next(); - stream.writeObject(entry.key); - stream.writeObject(entry.value); - entry = entry.next; + private static boolean equals(Object o1, Object o2) { + return o1 == o2 || (o1 != null && o1.equals(o2)); + } + + // Subclass (LinkedHashMap) overrrides these for correct iteration order + Iterator<K> newKeyIterator() { return new KeyIterator(); } + Iterator<V> newValueIterator() { return new ValueIterator(); } + Iterator<Entry<K, V>> newEntryIterator() { return new EntryIterator(); } + + private final class KeySet extends AbstractSet<K> { + public Iterator<K> iterator() { + return newKeyIterator(); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + public boolean contains(Object o) { + return containsKey(o); + } + public boolean remove(Object o) { + int oldSize = size; + HashMap.this.remove(o); + return size != oldSize; + } + public void clear() { + HashMap.this.clear(); } } - @SuppressWarnings("unchecked") - private void readObject(ObjectInputStream stream) throws IOException, - ClassNotFoundException { - stream.defaultReadObject(); - int length = stream.readInt(); - elementData = newElementArray(length); - elementCount = stream.readInt(); - for (int i = elementCount; --i >= 0;) { - K key = (K) stream.readObject(); - int index = (null == key) ? 0 : (computeHashCode(key) & (length - 1)); - createEntry(key, index, (V) stream.readObject()); + private final class Values extends AbstractCollection<V> { + public Iterator<V> iterator() { + return newValueIterator(); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + public boolean contains(Object o) { + return containsValue(o); + } + public void clear() { + HashMap.this.clear(); + } + } + + private final class EntrySet extends AbstractSet<Entry<K, V>> { + public Iterator<Entry<K, V>> iterator() { + return newEntryIterator(); + } + public boolean contains(Object o) { + if (!(o instanceof Entry)) + return false; + Entry<?, ?> e = (Entry<?, ?>) o; + return containsMapping(e.getKey(), e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Entry)) + return false; + Entry<?, ?> e = (Entry<?, ?>)o; + return removeMapping(e.getKey(), e.getValue()); + } + public int size() { + return size; + } + public boolean isEmpty() { + return size == 0; + } + public void clear() { + HashMap.this.clear(); } } - /* - * Contract-related functionality + /** + * Applies a supplemental hash function to a given hashCode, 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 or upper bits. */ - static int computeHashCode(Object key) { - return key.hashCode(); -} + private static int secondaryHash(int h) { + // Doug Lea's supplemental hash function + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + /** + * Returns the smallest power of two >= its argument, with several caveats: + * If the argument is negative but not Integer.MIN_VALUE, the method returns + * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method + * returns Integer.MIN_VALUE. If the argument is zero, the method returns + * zero. + */ + private static int roundUpToPowerOfTwo(int i) { + i--; // If input is a power of two, shift its high-order bit right + + // "Smear" the high-order bit all the way to the right + i |= i >>> 1; + i |= i >>> 2; + i |= i >>> 4; + i |= i >>> 8; + i |= i >>> 16; - static boolean areEqualKeys(Object key1, Object key2) { - return (key1 == key2) || key1.equals(key2); + return i + 1; } - static boolean areEqualValues(Object value1, Object value2) { - return (value1 == value2) || value1.equals(value2); + private static final long serialVersionUID = 362498820763181265L; + + /** + * Serializable fields. + * + * @serialField loadFactor float + * load factor for this HashMap + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("loadFactor", Float.TYPE) + }; + + private void writeObject(ObjectOutputStream stream) throws IOException { + // Emulate loadFactor field for other implementations to read + ObjectOutputStream.PutField fields = stream.putFields(); + fields.put("loadFactor", DEFAULT_LOAD_FACTOR); + stream.writeFields(); + + stream.writeInt(table.length); // Capacity + stream.writeInt(size); + for (Entry<K, V> e : entrySet()) { + stream.writeObject(e.getKey()); + stream.writeObject(e.getValue()); + } } + private void readObject(ObjectInputStream stream) throws IOException, + ClassNotFoundException { + stream.defaultReadObject(); + int capacity = stream.readInt(); + if (capacity < 0) { + throw new InvalidObjectException("Capacity: " + capacity); + } + if (capacity < MINIMUM_CAPACITY) { + capacity = MINIMUM_CAPACITY; + } else if (capacity > MAXIMUM_CAPACITY) { + capacity = MAXIMUM_CAPACITY; + } else { + capacity = roundUpToPowerOfTwo(capacity); + } + makeTable(capacity); + + int size = stream.readInt(); + if (size < 0) { + throw new InvalidObjectException("Size: " + size); + } + init(); // Give subclass (LinkedHashMap) a chance to initialize itself + for (int i = 0; i < size; i++) { + @SuppressWarnings("unchecked") K key = (K) stream.readObject(); + @SuppressWarnings("unchecked") V val = (V) stream.readObject(); + constructorPut(key, val); + } + } } diff --git a/luni/src/main/java/java/util/HashSet.java b/luni/src/main/java/java/util/HashSet.java index dca764f..4c97ca5 100644 --- a/luni/src/main/java/java/util/HashSet.java +++ b/luni/src/main/java/java/util/HashSet.java @@ -185,15 +185,11 @@ public class HashSet<E> extends AbstractSet<E> implements Set<E>, Cloneable, private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); - stream.writeInt(backingMap.elementData.length); - stream.writeFloat(backingMap.loadFactor); - stream.writeInt(backingMap.elementCount); - for (int i = backingMap.elementData.length; --i >= 0;) { - HashMap.Entry<E, HashSet<E>> entry = backingMap.elementData[i]; - while (entry != null) { - stream.writeObject(entry.key); - entry = entry.next; - } + stream.writeInt(backingMap.table.length); + stream.writeFloat(HashMap.DEFAULT_LOAD_FACTOR); + stream.writeInt(size()); + for (E e : this) { + stream.writeObject(e); } } diff --git a/luni/src/main/java/java/util/Hashtable.java b/luni/src/main/java/java/util/Hashtable.java index b23364d..ead0db3 100644 --- a/luni/src/main/java/java/util/Hashtable.java +++ b/luni/src/main/java/java/util/Hashtable.java @@ -15,15 +15,19 @@ * limitations under the License. */ +// BEGIN android-note +// Completely different implementation from harmony. Runs much faster. +// BEGIN android-note + package java.util; import java.io.IOException; +import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; +import java.io.ObjectStreamField; import java.io.Serializable; -import org.apache.harmony.luni.internal.nls.Messages; - /** * Hashtable associates keys with values. Both keys and values cannot be null. * The size of the Hashtable is the number of key/value pairs it contains. The @@ -32,212 +36,86 @@ import org.apache.harmony.luni.internal.nls.Messages; * expanding the capacity. If the load factor of the Hashtable is exceeded, the * capacity is doubled. * + * @param <K> the type of keys maintained by this map + * @param <V> the type of mapped values + * * @see Enumeration * @see java.io.Serializable * @see java.lang.Object#equals * @see java.lang.Object#hashCode */ -public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, - Cloneable, Serializable { - - private static final long serialVersionUID = 1421746759512286392L; - - transient int elementCount; - - transient Entry<K, V>[] elementData; - - private float loadFactor; - - private int threshold; - - transient int firstSlot; - - transient int lastSlot = -1; - - transient int modCount; - - private static final Enumeration<?> EMPTY_ENUMERATION = new Enumeration<Object>() { - public boolean hasMoreElements() { - return false; - } - - public Object nextElement() { - throw new NoSuchElementException(); - } - }; - - private static final Iterator<?> EMPTY_ITERATOR = new Iterator<Object>() { - - public boolean hasNext() { - return false; - } - - public Object next() { - throw new NoSuchElementException(); - } - - public void remove() { - throw new IllegalStateException(); - } - }; - - private static <K, V> Entry<K, V> newEntry(K key, V value, int hash) { - return new Entry<K, V>(key, value); - } - - private static class Entry<K, V> extends MapEntry<K, V> { - Entry<K, V> next; - - final int hashcode; - - Entry(K theKey, V theValue) { - super(theKey, theValue); - hashcode = theKey.hashCode(); - } - - @Override - @SuppressWarnings("unchecked") - public Object clone() { - Entry<K, V> entry = (Entry<K, V>) super.clone(); - if (next != null) { - entry.next = (Entry<K, V>) next.clone(); - } - return entry; - } - - @Override - public V setValue(V object) { - if (object == null) { - throw new NullPointerException(); - } - V result = value; - value = object; - return result; - } - - public int getKeyHash() { - return key.hashCode(); - } - - public boolean equalsKey(Object aKey, int hash) { - // BEGIN android-changed - // The VM can inline String.equals - return hashcode == aKey.hashCode() - && (key instanceof String - ? ((String) key).equals(aKey) : key.equals(aKey)); - // END android-changed - } - - @Override - public String toString() { - return key + "=" + value; //$NON-NLS-1$ - } - } - - private class HashIterator<E> implements Iterator<E> { - int position, expectedModCount; +public class Hashtable<K, V> extends Dictionary<K, V> + implements Map<K, V>, Cloneable, Serializable { + /** + * Min capacity (other than zero) for a Hashtable. Must be a power of two + * greater than 1 (and less than 1 << 30). + */ + private static final int MINIMUM_CAPACITY = 4; - final MapEntry.Type<E, K, V> type; + /** + * Max capacity for a Hashtable. Must be a power of two >= MINIMUM_CAPACITY. + */ + private static final int MAXIMUM_CAPACITY = 1 << 30; - Entry<K, V> lastEntry; + /** + * An empty table shared by all zero-capacity maps (typically from default + * constructor). It is never written to, and replaced on first put. Its size + * is set to half the minimum, so that the first resize will create a + * minimum-sized table. + */ + private static final Entry[] EMPTY_TABLE + = new HashtableEntry[MINIMUM_CAPACITY >>> 1]; - int lastPosition; + /** + * The default load factor. Note that this implementation ignores the + * load factor, but cannot do away with it entirely because it's + * metioned in the API. + * + * <p>Note that this constant has no impact on the behavior of the program, + * but it is emitted as part of the serialized form. The load factor of + * .75 is hardwired into the program, which uses cheap shifts in place of + * expensive division. + */ + private static final float DEFAULT_LOAD_FACTOR = .75F; - boolean canRemove = false; + /** + * The hash table. + */ + private transient HashtableEntry<K, V>[] table; - HashIterator(MapEntry.Type<E, K, V> value) { - type = value; - position = lastSlot; - expectedModCount = modCount; - } + /** + * The number of mappings in this hash map. + */ + private transient int size; - public boolean hasNext() { - if (lastEntry != null && lastEntry.next != null) { - return true; - } - while (position >= firstSlot) { - if (elementData[position] == null) { - position--; - } else { - return true; - } - } - return false; - } + /** + * Incremented by "structural modifications" to allow (best effort) + * detection of concurrent modification. + */ + private transient int modCount; - public E next() { - if (expectedModCount == modCount) { - if (lastEntry != null) { - lastEntry = lastEntry.next; - } - if (lastEntry == null) { - while (position >= firstSlot - && (lastEntry = elementData[position]) == null) { - position--; - } - if (lastEntry != null) { - lastPosition = position; - // decrement the position so we don't find the same slot - // next time - position--; - } - } - if (lastEntry != null) { - canRemove = true; - return type.get(lastEntry); - } - throw new NoSuchElementException(); - } - throw new ConcurrentModificationException(); - } + /** + * The table is rehashed when its size exceeds this threshold. + * The value of this field is generally .75 * capacity, except when + * the capacity is zero, as described in the EMPTY_TABLE declaration + * above. + */ + private transient int threshold; - public void remove() { - if (expectedModCount == modCount) { - if (canRemove) { - canRemove = false; - synchronized (Hashtable.this) { - boolean removed = false; - Entry<K, V> entry = elementData[lastPosition]; - if (entry == lastEntry) { - elementData[lastPosition] = entry.next; - removed = true; - } else { - while (entry != null && entry.next != lastEntry) { - entry = entry.next; - } - if (entry != null) { - entry.next = lastEntry.next; - removed = true; - } - } - if (removed) { - modCount++; - elementCount--; - expectedModCount++; - return; - } - // the entry must have been (re)moved outside of the - // iterator - // but this condition wasn't caught by the modCount - // check - // throw ConcurrentModificationException() outside of - // synchronized block - } - } else { - throw new IllegalStateException(); - } - } - throw new ConcurrentModificationException(); - } - } + // Views - lazily initialized + private transient Set<K> keySet; + private transient Set<Entry<K, V>> entrySet; + private transient Collection<V> values; /** * Constructs a new {@code Hashtable} using the default capacity and load * factor. */ + @SuppressWarnings("unchecked") public Hashtable() { - this(11); + table = (HashtableEntry<K, V>[]) EMPTY_TABLE; + threshold = -1; // Forces first put invocation to replace EMPTY_TABLE } /** @@ -248,15 +126,26 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * the initial capacity. */ public Hashtable(int capacity) { - if (capacity >= 0) { - elementCount = 0; - elementData = newElementArray(capacity == 0 ? 1 : capacity); - firstSlot = elementData.length; - loadFactor = 0.75f; - computeMaxSize(); + if (capacity < 0) { + throw new IllegalArgumentException("Capacity: " + capacity); + } + + if (capacity == 0) { + @SuppressWarnings("unchecked") + HashtableEntry<K, V>[] tab = (HashtableEntry<K, V>[]) EMPTY_TABLE; + table = tab; + threshold = -1; // Forces first put() to replace EMPTY_TABLE + return; + } + + if (capacity < MINIMUM_CAPACITY) { + capacity = MINIMUM_CAPACITY; + } else if (capacity > MAXIMUM_CAPACITY) { + capacity = MAXIMUM_CAPACITY; } else { - throw new IllegalArgumentException(); + capacity = roundUpToPowerOfTwo(capacity); } + makeTable(capacity); } /** @@ -269,15 +158,17 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * the initial load factor. */ public Hashtable(int capacity, float loadFactor) { - if (capacity >= 0 && loadFactor > 0) { - elementCount = 0; - firstSlot = capacity; - elementData = newElementArray(capacity == 0 ? 1 : capacity); - this.loadFactor = loadFactor; - computeMaxSize(); - } else { - throw new IllegalArgumentException(); + this(capacity); + + if (loadFactor <= 0 || Float.isNaN(loadFactor)) { + throw new IllegalArgumentException("Load factor: " + loadFactor); } + + /* + * Note that this implementation ignores loadFactor; it always uses + * a load facator of 3/4. This simplifies the code and generally + * improves performance. + */ } /** @@ -288,26 +179,31 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * the mappings to add. */ public Hashtable(Map<? extends K, ? extends V> map) { - this(map.size() < 6 ? 11 : (map.size() * 4 / 3) + 11); - putAll(map); + this(capacityForInitSize(map.size())); + constructorPutAll(map); } - @SuppressWarnings("unchecked") - private Entry<K, V>[] newElementArray(int size) { - return new Entry[size]; + /** + * Inserts all of the elements of map into this Hashtable in a manner + * suitable for use by constructors and pseudocostructors (i.e., clone, + * readObject). + */ + private void constructorPutAll(Map<? extends K, ? extends V> map) { + for (Entry<? extends K, ? extends V> e : map.entrySet()) { + constructorPut(e.getKey(), e.getValue()); + } } /** - * Removes all key/value pairs from this {@code Hashtable}, leaving the - * size zero and the capacity unchanged. - * - * @see #isEmpty - * @see #size + * Returns an appropriate capacity for the specified initial size. Does + * not round the result up to a power of two; the caller must do this! + * The returned value will be between 0 and MAXIMUM_CAPACITY (inclusive). */ - public synchronized void clear() { - elementCount = 0; - Arrays.fill(elementData, null); - modCount++; + private static int capacityForInitSize(int size) { + int result = (size >> 1) + size; // Multiply by 3/2 to allow for growth + + // boolean expr is equivalent to result >= 0 && result<MAXIMUM_CAPACITY + return (result & ~(MAXIMUM_CAPACITY-1))==0 ? result : MAXIMUM_CAPACITY; } /** @@ -317,54 +213,77 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * @return a shallow copy of this {@code Hashtable}. * @see java.lang.Cloneable */ - @Override @SuppressWarnings("unchecked") - public synchronized Object clone() { + @Override public synchronized Object clone() { + /* + * This could be made more efficient. It unnecessarily hashes all of + * the elements in the map. + */ + Hashtable<K, V> result; try { - Hashtable<K, V> hashtable = (Hashtable<K, V>) super.clone(); - hashtable.elementData = new Entry[elementData.length]; - Entry<K, V> entry; - for (int i = elementData.length; --i >= 0;) { - if ((entry = elementData[i]) != null) { - hashtable.elementData[i] = (Entry<K, V>) entry.clone(); - } - } - return hashtable; + result = (Hashtable<K, V>) super.clone(); } catch (CloneNotSupportedException e) { - return null; + throw new AssertionError(e); } - } - private void computeMaxSize() { - threshold = (int) (elementData.length * loadFactor); + // Restore clone to empty state, retaining our capacity and threshold + result.makeTable(table.length); + result.size = 0; + result.keySet = null; + result.entrySet = null; + result.values = null; + + result.constructorPutAll(this); + return result; } /** - * Returns true if this {@code Hashtable} contains the specified object as - * the value of at least one of the key/value pairs. + * Returns true if this {@code Hashtable} has no key/value pairs. * - * @param value - * the object to look for as a value in this {@code Hashtable}. - * @return {@code true} if object is a value in this {@code Hashtable}, + * @return {@code true} if this {@code Hashtable} has no key/value pairs, * {@code false} otherwise. - * @see #containsKey - * @see java.lang.Object#equals + * @see #size */ - public synchronized boolean contains(Object value) { - if (value == null) { - throw new NullPointerException(); - } + public synchronized boolean isEmpty() { + return size == 0; + } - for (int i = elementData.length; --i >= 0;) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - if (entry.value.equals(value)) { - return true; - } - entry = entry.next; + /** + * Returns the number of key/value pairs in this {@code Hashtable}. + * + * @return the number of key/value pairs in this {@code Hashtable}. + * @see #elements + * @see #keys + */ + public synchronized int size() { + return size; + } + + /** + * Returns the value associated with the specified key in this + * {@code Hashtable}. + * + * @param key + * the key of the value returned. + * @return the value associated with the specified key, or {@code null} if + * the specified key does not exist. + * @see #put + */ + public synchronized V get(Object key) { + // Doug Lea's supplemental secondaryHash function (inlined) + int hash = key.hashCode(); + hash ^= (hash >>> 20) ^ (hash >>> 12); + hash ^= (hash >>> 7) ^ (hash >>> 4); + + HashtableEntry<K, V>[] tab = table; + for (HashtableEntry<K, V> e = tab[hash & (tab.length - 1)]; + e != null; e = e.next) { + K eKey = e.key; + if (eKey == key || (e.hash == hash && key.equals(eKey))) { + return e.value; } } - return false; + return null; } /** @@ -379,7 +298,20 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * @see java.lang.Object#equals */ public synchronized boolean containsKey(Object key) { - return getEntry(key) != null; + // Doug Lea's supplemental secondaryHash function (inlined) + int hash = key.hashCode(); + hash ^= (hash >>> 20) ^ (hash >>> 12); + hash ^= (hash >>> 7) ^ (hash >>> 4); + + HashtableEntry<K, V>[] tab = table; + for (HashtableEntry<K, V> e = tab[hash & (tab.length - 1)]; + e != null; e = e.next) { + K eKey = e.key; + if (eKey == key || (e.hash == hash && key.equals(eKey))) { + return true; + } + } + return false; } /** @@ -390,190 +322,319 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * @return {@code true} if {@code value} is a value of this * {@code Hashtable}, {@code false} otherwise. */ - public boolean containsValue(Object value) { - return contains(value); + public synchronized boolean containsValue(Object value) { + if (value == null) { + throw new NullPointerException(); + } + + HashtableEntry[] tab = table; + int len = tab.length; + + for (int i = 0; i < len; i++) { + for (HashtableEntry e = tab[i]; e != null; e = e.next) { + if (value.equals(e.value)) { + return true; + } + } + } + return false; } /** - * Returns an enumeration on the values of this {@code Hashtable}. The - * results of the Enumeration may be affected if the contents of this - * {@code Hashtable} are modified. + * Returns true if this {@code Hashtable} contains the specified object as + * the value of at least one of the key/value pairs. * - * @return an enumeration of the values of this {@code Hashtable}. + * @param value + * the object to look for as a value in this {@code Hashtable}. + * @return {@code true} if object is a value in this {@code Hashtable}, + * {@code false} otherwise. + * @see #containsKey + * @see java.lang.Object#equals + */ + public boolean contains(Object value) { + return containsValue(value); + } + + /** + * Associate the specified value with the specified key in this + * {@code Hashtable}. If the key already exists, the old value is replaced. + * The key and value cannot be null. + * + * @param key + * the key to add. + * @param value + * the value to add. + * @return the old value associated with the specified key, or {@code null} + * if the key did not exist. + * @see #elements + * @see #get * @see #keys - * @see #size - * @see Enumeration + * @see java.lang.Object#equals */ - @Override - @SuppressWarnings("unchecked") - public synchronized Enumeration<V> elements() { - if (elementCount == 0) { - return (Enumeration<V>) EMPTY_ENUMERATION; + public synchronized V put(K key, V value) { + if (value == null) { + throw new NullPointerException(); } - return new HashEnumIterator<V>(new MapEntry.Type<V, K, V>() { - public V get(MapEntry<K, V> entry) { - return entry.value; + int hash = secondaryHash(key.hashCode()); + HashtableEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + HashtableEntry<K, V> first = tab[index]; + for (HashtableEntry<K, V> e = first; e != null; e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + V oldValue = e.value; + e.value = value; + return oldValue; } - }, true); + } + + // No entry for key is present; create one + modCount++; + if (size++ > threshold) { + rehash(); // Does nothing!! + tab = doubleCapacity(); + index = hash & (tab.length - 1); + first = tab[index]; + } + tab[index] = new HashtableEntry<K, V>(key, value, hash, first); + return null; } /** - * Returns a set of the mappings contained in this {@code Hashtable}. Each - * element in the set is a {@link Map.Entry}. The set is backed by this - * {@code Hashtable} so changes to one are reflected by the other. The set - * does not support adding. + * This method is just like put, except that it doesn't do things that + * are inappropriate or unnecessary for constructors and pseudo-constructors + * (i.e., clone, readObject). In particular, this method does not check to + * ensure that capacity is sufficient, and does not increment modCount. + */ + private void constructorPut(K key, V value) { + if (value == null) { + throw new NullPointerException(); + } + int hash = secondaryHash(key.hashCode()); + HashtableEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + HashtableEntry<K, V> first = tab[index]; + for (HashtableEntry<K, V> e = first; e != null; e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + e.value = value; + return; + } + } + + // No entry for key is present; create one + tab[index] = new HashtableEntry<K, V>(key, value, hash, first); + size++; + } + + /** + * Copies every mapping to this {@code Hashtable} from the specified map. * - * @return a set of the mappings. + * @param map + * the map to copy mappings from. */ - public Set<Map.Entry<K, V>> entrySet() { - return new Collections.SynchronizedSet<Map.Entry<K, V>>( - new AbstractSet<Map.Entry<K, V>>() { - @Override - public int size() { - return elementCount; - } - - @Override - public void clear() { - Hashtable.this.clear(); - } - - @Override - @SuppressWarnings("unchecked") - public boolean remove(Object object) { - if (contains(object)) { - Hashtable.this.remove(((Map.Entry<K, V>) object) - .getKey()); - return true; - } - return false; - } - - @Override - @SuppressWarnings("unchecked") - public boolean contains(Object object) { - Entry<K, V> entry = getEntry(((Map.Entry<K, V>) object) - .getKey()); - return object.equals(entry); - } - - @Override - public Iterator<Map.Entry<K, V>> iterator() { - return new HashIterator<Map.Entry<K, V>>( - new MapEntry.Type<Map.Entry<K, V>, K, V>() { - public Map.Entry<K, V> get( - MapEntry<K, V> entry) { - return entry; - } - }); - } - }, this); + public synchronized void putAll(Map<? extends K, ? extends V> map) { + ensureCapacity(map.size()); + for (Entry<? extends K, ? extends V> e : map.entrySet()) { + put(e.getKey(), e.getValue()); + } } /** - * Compares this {@code Hashtable} with the specified object and indicates - * if they are equal. In order to be equal, {@code object} must be an - * instance of Map and contain the same key/value pairs. + * Ensures that the hash table has sufficient capacity to store the + * specified number of mappings, with room to grow. If not, it increases the + * capacity as appropriate. Like doubleCapacity, this method moves existing + * entries to new buckets as appropriate. Unlike doubleCapacity, this method + * can grow the table by factors of 2^n for n > 1. Hopefully, a single call + * to this method will be faster than multiple calls to doubleCapacity. * - * @param object - * the object to compare with this object. - * @return {@code true} if the specified object is equal to this Map, - * {@code false} otherwise. - * @see #hashCode + * <p>This method is called only by putAll. */ - @Override - public synchronized boolean equals(Object object) { - if (this == object) { - return true; + private void ensureCapacity(int numMappings) { + int newCapacity = roundUpToPowerOfTwo(capacityForInitSize(numMappings)); + HashtableEntry<K, V>[] oldTable = table; + int oldCapacity = oldTable.length; + if (newCapacity <= oldCapacity) { + return; } - if (object instanceof Map) { - Map<?, ?> map = (Map<?, ?>) object; - if (size() != map.size()) { - return false; + + rehash(); // Does nothing!! + + if (newCapacity == oldCapacity << 1) { + doubleCapacity(); + return; + } + + // We're growing by at least 4x, rehash in the obvious way + HashtableEntry<K, V>[] newTable = makeTable(newCapacity); + if (size != 0) { + int newMask = newCapacity - 1; + for (int i = 0; i < oldCapacity; i++) { + for (HashtableEntry<K, V> e = oldTable[i]; e != null;) { + HashtableEntry<K, V> oldNext = e.next; + int newIndex = e.hash & newMask; + HashtableEntry<K, V> newNext = newTable[newIndex]; + newTable[newIndex] = e; + e.next = newNext; + e = oldNext; + } } + } + } + + /** + * Increases the capacity of this {@code Hashtable}. This method is called + * when the size of this {@code Hashtable} exceeds the load factor. + */ + protected void rehash() { + /* + * This method has no testable semantics, other than that it gets + * called from time to time. + */ + } + + /** + * Allocate a table of the given capacity and set the threshold accordingly. + * @param newCapacity must be a power of two + */ + private HashtableEntry<K, V>[] makeTable(int newCapacity) { + @SuppressWarnings("unchecked") HashtableEntry<K, V>[] newTable + = (HashtableEntry<K, V>[]) new HashtableEntry[newCapacity]; + table = newTable; + threshold = (newCapacity >> 1) + (newCapacity >> 2); // 3/4 capacity + return newTable; + } + + /** + * Doubles the capacity of the hash table. Existing entries are placed in + * the correct bucket on the enlarged table. If the current capacity is, + * MAXIMUM_CAPACITY, this method is a no-op. Returns the table, which + * will be new unless we were already at MAXIMUM_CAPACITY. + */ + private HashtableEntry<K, V>[] doubleCapacity() { + HashtableEntry<K, V>[] oldTable = table; + int oldCapacity = oldTable.length; + if (oldCapacity == MAXIMUM_CAPACITY) { + return oldTable; + } + int newCapacity = oldCapacity << 1; + HashtableEntry<K, V>[] newTable = makeTable(newCapacity); + if (size == 0) { + return newTable; + } - Set<Map.Entry<K, V>> entries = entrySet(); - for (Map.Entry<?, ?> e : map.entrySet()) { - if (!entries.contains(e)) { - return false; + for (int j = 0; j < oldCapacity; j++) { + /* + * Rehash the bucket using the minimum number of field writes. + * This is the most subtle and delicate code in the class. + */ + HashtableEntry<K, V> e = oldTable[j]; + if (e == null) { + continue; + } + int highBit = e.hash & oldCapacity; + HashtableEntry<K, V> broken = null; + newTable[j | highBit] = e; + for (HashtableEntry<K,V> n = e.next; n != null; e = n, n = n.next) { + int nextHighBit = n.hash & oldCapacity; + if (nextHighBit != highBit) { + if (broken == null) + newTable[j | nextHighBit] = n; + else + broken.next = n; + broken = e; + highBit = nextHighBit; } } - return true; + if (broken != null) + broken.next = null; } - return false; + return newTable; } /** - * Returns the value associated with the specified key in this + * Removes the key/value pair with the specified key from this * {@code Hashtable}. * * @param key - * the key of the value returned. + * the key to remove. * @return the value associated with the specified key, or {@code null} if - * the specified key does not exist. + * the specified key did not exist. + * @see #get * @see #put */ - @Override - public synchronized V get(Object key) { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - Entry<K, V> entry = elementData[index]; - while (entry != null) { - if (entry.equalsKey(key, hash)) { - return entry.value; + public synchronized V remove(Object key) { + int hash = secondaryHash(key.hashCode()); + HashtableEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashtableEntry<K, V> e = tab[index], prev = null; + e != null; prev = e, e = e.next) { + if (e.hash == hash && key.equals(e.key)) { + if (prev == null) { + tab[index] = e.next; + } else { + prev.next = e.next; + } + modCount++; + size--; + return e.value; } - entry = entry.next; } return null; } - Entry<K, V> getEntry(Object key) { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - Entry<K, V> entry = elementData[index]; - while (entry != null) { - if (entry.equalsKey(key, hash)) { - return entry; - } - entry = entry.next; + /** + * Removes all key/value pairs from this {@code Hashtable}, leaving the + * size zero and the capacity unchanged. + * + * @see #isEmpty + * @see #size + */ + public synchronized void clear() { + if (size != 0) { + Arrays.fill(table, null); + modCount++; + size = 0; } - return null; } - @Override - public synchronized int hashCode() { - int result = 0; - Iterator<Map.Entry<K, V>> it = entrySet().iterator(); - while (it.hasNext()) { - Map.Entry<K, V> entry = it.next(); - Object key = entry.getKey(); - if (key == this) { - continue; - } - Object value = entry.getValue(); - if (value == this) { - continue; - } - int hash = (key != null ? key.hashCode() : 0) - ^ (value != null ? value.hashCode() : 0); - result += hash; - } - return result; + /** + * Returns a set of the keys contained in this {@code Hashtable}. The set + * is backed by this {@code Hashtable} so changes to one are reflected by + * the other. The set does not support adding. + * + * @return a set of the keys. + */ + public synchronized Set<K> keySet() { + Set<K> ks = keySet; + return (ks != null) ? ks : (keySet = new KeySet()); } /** - * Returns true if this {@code Hashtable} has no key/value pairs. + * Returns a collection of the values contained in this {@code Hashtable}. + * The collection is backed by this {@code Hashtable} so changes to one are + * reflected by the other. The collection does not support adding. * - * @return {@code true} if this {@code Hashtable} has no key/value pairs, - * {@code false} otherwise. - * @see #size + * @return a collection of the values. */ - @Override - public synchronized boolean isEmpty() { - return elementCount == 0; + public synchronized Collection<V> values() { + Collection<V> vs = values; + return (vs != null) ? vs : (values = new Values()); } /** + * Returns a set of the mappings contained in this {@code Hashtable}. Each + * element in the set is a {@link Map.Entry}. The set is backed by this + * {@code Hashtable} so changes to one are reflected by the other. The set + * does not support adding. + * + * @return a set of the mappings. + */ + public synchronized Set<Entry<K, V>> entrySet() { + Set<Entry<K, V>> es = entrySet; + return (es != null) ? es : (entrySet = new EntrySet()); + } + + + /** * Returns an enumeration on the keys of this {@code Hashtable} instance. * The results of the enumeration may be affected if the contents of this * {@code Hashtable} are modified. @@ -583,400 +644,517 @@ public class Hashtable<K, V> extends Dictionary<K, V> implements Map<K, V>, * @see #size * @see Enumeration */ - @Override - @SuppressWarnings("unchecked") public synchronized Enumeration<K> keys() { - if (elementCount == 0) { - return (Enumeration<K>) EMPTY_ENUMERATION; - } - return new HashEnumIterator<K>(new MapEntry.Type<K, K, V>() { - public K get(MapEntry<K, V> entry) { - return entry.key; - } - }, true); + return new KeyEnumeration(); } /** - * Returns a set of the keys contained in this {@code Hashtable}. The set - * is backed by this {@code Hashtable} so changes to one are reflected by - * the other. The set does not support adding. + * Returns an enumeration on the values of this {@code Hashtable}. The + * results of the Enumeration may be affected if the contents of this + * {@code Hashtable} are modified. * - * @return a set of the keys. + * @return an enumeration of the values of this {@code Hashtable}. + * @see #keys + * @see #size + * @see Enumeration */ - public Set<K> keySet() { - return new Collections.SynchronizedSet<K>(new AbstractSet<K>() { - @Override - public boolean contains(Object object) { - return containsKey(object); - } + public synchronized Enumeration<V> elements() { + return new ValueEnumeration(); + } - @Override - public int size() { - return elementCount; - } + /** + * Note: technically the methods of this class should synchronize the + * backing map. However, this would require them to have a reference + * to it, which would cause consiserable bloat. Moreover, the RI + * behaves the same way. + */ + private static class HashtableEntry<K, V> implements Entry<K, V> { + final K key; + V value; + final int hash; + HashtableEntry<K, V> next; + + HashtableEntry(K key, V value, int hash, HashtableEntry<K, V> next) { + this.key = key; + this.value = value; + this.hash = hash; + this.next = next; + } - @Override - public void clear() { - Hashtable.this.clear(); - } + public final K getKey() { + return key; + } - @Override - public boolean remove(Object key) { - if (containsKey(key)) { - Hashtable.this.remove(key); - return true; - } - return false; - } + public final V getValue() { + return value; + } - @Override - public Iterator<K> iterator() { - if (this.size() == 0) { - return (Iterator<K>) EMPTY_ITERATOR; - } - return new HashEnumIterator<K>(new MapEntry.Type<K, K, V>() { - public K get(MapEntry<K, V> entry) { - return entry.key; - } - }); + public final V setValue(V value) { + if (value == null) { + throw new NullPointerException(); } - }, this); - } - - class HashEnumIterator<E> extends HashIterator<E> implements Enumeration<E> { - - private boolean isEnumeration = false; - - int start; + V oldValue = this.value; + this.value = value; + return oldValue; + } - Entry<K, V> entry; + @Override public final boolean equals(Object o) { + if (!(o instanceof Entry)) { + return false; + } + Entry<?, ?> e = (Entry<?, ?>) o; + return key.equals(e.getKey()) && value.equals(e.getValue()); + } - HashEnumIterator(MapEntry.Type<E, K, V> value) { - super(value); + @Override public final int hashCode() { + return key.hashCode() ^ value.hashCode(); } - HashEnumIterator(MapEntry.Type<E, K, V> value, boolean isEnumeration) { - super(value); - this.isEnumeration = isEnumeration; - start = lastSlot + 1; + @Override public final String toString() { + return key + "=" + value; } + } - public boolean hasMoreElements() { - if (isEnumeration) { - if (entry != null) { - return true; - } - while (start > firstSlot) { - if (elementData[--start] != null) { - entry = elementData[start]; - return true; - } - } - return false; + private abstract class HashIterator { + int nextIndex; + HashtableEntry<K, V> nextEntry; + HashtableEntry<K, V> lastEntryReturned; + int expectedModCount = modCount; + + HashIterator() { + HashtableEntry<K, V>[] tab = table; + HashtableEntry<K, V> next = null; + while (next == null && nextIndex < tab.length) { + next = tab[nextIndex++]; } - // iterator - return super.hasNext(); + nextEntry = next; } public boolean hasNext() { - if (isEnumeration) { - return hasMoreElements(); - } - // iterator - return super.hasNext(); + return nextEntry != null; } - public E next() { - if (isEnumeration) { - if (expectedModCount == modCount) { - return nextElement(); - } else { - throw new ConcurrentModificationException(); - } + HashtableEntry<K, V> nextEntry() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + if (nextEntry == null) + throw new NoSuchElementException(); + + HashtableEntry<K, V> entryToReturn = nextEntry; + HashtableEntry<K, V>[] tab = table; + HashtableEntry<K, V> next = entryToReturn.next; + while (next == null && nextIndex < tab.length) { + next = tab[nextIndex++]; } - // iterator - return super.next(); + nextEntry = next; + return lastEntryReturned = entryToReturn; } - @SuppressWarnings("unchecked") - public E nextElement() { - if (isEnumeration) { - if (hasMoreElements()) { - Object result = type.get(entry); - entry = entry.next; - return (E) result; - } + HashtableEntry<K, V> nextEntryNotFailFast() { + if (nextEntry == null) throw new NoSuchElementException(); + + HashtableEntry<K, V> entryToReturn = nextEntry; + HashtableEntry<K, V>[] tab = table; + HashtableEntry<K, V> next = entryToReturn.next; + while (next == null && nextIndex < tab.length) { + next = tab[nextIndex++]; } - // iterator - return super.next(); + nextEntry = next; + return lastEntryReturned = entryToReturn; } public void remove() { - if (isEnumeration) { - throw new UnsupportedOperationException(); - } else { - super.remove(); - } + if (lastEntryReturned == null) + throw new IllegalStateException(); + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + Hashtable.this.remove(lastEntryReturned.key); + lastEntryReturned = null; + expectedModCount = modCount; } } - /** - * Associate the specified value with the specified key in this - * {@code Hashtable}. If the key already exists, the old value is replaced. - * The key and value cannot be null. - * - * @param key - * the key to add. - * @param value - * the value to add. - * @return the old value associated with the specified key, or {@code null} - * if the key did not exist. - * @see #elements - * @see #get - * @see #keys - * @see java.lang.Object#equals - */ - @Override - public synchronized V put(K key, V value) { - if (key != null && value != null) { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - Entry<K, V> entry = elementData[index]; - while (entry != null && !entry.equalsKey(key, hash)) { - entry = entry.next; - } - if (entry == null) { - modCount++; - if (++elementCount > threshold) { - rehash(); - index = (hash & 0x7FFFFFFF) % elementData.length; - } - if (index < firstSlot) { - firstSlot = index; - } - if (index > lastSlot) { - lastSlot = index; - } - entry = newEntry(key, value, hash); - entry.next = elementData[index]; - elementData[index] = entry; - return null; - } - V result = entry.value; - entry.value = value; - return result; - } - throw new NullPointerException(); + private final class KeyIterator extends HashIterator + implements Iterator<K> { + public K next() { return nextEntry().key; } + } + + private final class ValueIterator extends HashIterator + implements Iterator<V> { + public V next() { return nextEntry().value; } + } + + private final class EntryIterator extends HashIterator + implements Iterator<Entry<K, V>> { + public Entry<K, V> next() { return nextEntry(); } + } + + private final class KeyEnumeration extends HashIterator + implements Enumeration<K> { + public boolean hasMoreElements() { return hasNext(); } + public K nextElement() { return nextEntryNotFailFast().key; } + } + + private final class ValueEnumeration extends HashIterator + implements Enumeration<V> { + public boolean hasMoreElements() { return hasNext(); } + public V nextElement() { return nextEntryNotFailFast().value; } } /** - * Copies every mapping to this {@code Hashtable} from the specified map. - * - * @param map - * the map to copy mappings from. + * Returns true if this map contains the specified mapping. */ - public synchronized void putAll(Map<? extends K, ? extends V> map) { - for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) { - put(entry.getKey(), entry.getValue()); + private synchronized boolean containsMapping(Object key, Object value) { + int hash = secondaryHash(key.hashCode()); + HashtableEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashtableEntry<K, V> e = tab[index]; e != null; e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + return e.value.equals(value); + } } + return false; // No entry for key } /** - * Increases the capacity of this {@code Hashtable}. This method is called - * when the size of this {@code Hashtable} exceeds the load factor. + * Removes the mapping from key to value and returns true if this mapping + * exists; otherwise, returns does nothing and returns false. */ - protected void rehash() { - int length = (elementData.length << 1) + 1; - if (length == 0) { - length = 1; - } - int newFirst = length; - int newLast = -1; - Entry<K, V>[] newData = newElementArray(length); - for (int i = lastSlot + 1; --i >= firstSlot;) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - int index = (entry.getKeyHash() & 0x7FFFFFFF) % length; - if (index < newFirst) { - newFirst = index; + private synchronized boolean removeMapping(Object key, Object value) { + int hash = secondaryHash(key.hashCode()); + HashtableEntry<K, V>[] tab = table; + int index = hash & (tab.length - 1); + for (HashtableEntry<K, V> e = tab[index], prev = null; + e != null; prev = e, e = e.next) { + if (e.hash == hash && e.key.equals(key)) { + if (!e.value.equals(value)) { + return false; // Map has wrong value for key } - if (index > newLast) { - newLast = index; + if (prev == null) { + tab[index] = e.next; + } else { + prev.next = e.next; } - Entry<K, V> next = entry.next; - entry.next = newData[index]; - newData[index] = entry; - entry = next; + modCount++; + size--; + return true; } } - firstSlot = newFirst; - lastSlot = newLast; - elementData = newData; - computeMaxSize(); + return false; // No entry for key } /** - * Removes the key/value pair with the specified key from this - * {@code Hashtable}. + * Compares this {@code Hashtable} with the specified object and indicates + * if they are equal. In order to be equal, {@code object} must be an + * instance of Map and contain the same key/value pairs. * - * @param key - * the key to remove. - * @return the value associated with the specified key, or {@code null} if - * the specified key did not exist. - * @see #get - * @see #put + * @param object + * the object to compare with this object. + * @return {@code true} if the specified object is equal to this Map, + * {@code false} otherwise. + * @see #hashCode */ - @Override - public synchronized V remove(Object key) { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - Entry<K, V> last = null; - Entry<K, V> entry = elementData[index]; - while (entry != null && !entry.equalsKey(key, hash)) { - last = entry; - entry = entry.next; - } - if (entry != null) { - modCount++; - if (last == null) { - elementData[index] = entry.next; - } else { - last.next = entry.next; + @Override public synchronized boolean equals(Object object) { + return (object instanceof Map) && + entrySet().equals(((Map<?, ?>)object).entrySet()); + } + + @Override public synchronized int hashCode() { + int result = 0; + for (Entry<K, V> e : entrySet()) { + K key = e.getKey(); + V value = e.getValue(); + if (key == this || value == this) { + continue; } - elementCount--; - V result = entry.value; - entry.value = null; - return result; + result += (key != null ? key.hashCode() : 0) + ^ (value != null ? value.hashCode() : 0); } - return null; + return result; } /** - * Returns the number of key/value pairs in this {@code Hashtable}. - * - * @return the number of key/value pairs in this {@code Hashtable}. - * @see #elements - * @see #keys + * A rough estimate of the number of characters per entry, for use + * when creating a string buffer in the toString method. */ - @Override - public synchronized int size() { - return elementCount; - } + private static final int CHARS_PER_ENTRY = 15; /** * Returns the string representation of this {@code Hashtable}. * * @return the string representation of this {@code Hashtable}. */ - @Override - public synchronized String toString() { - if (isEmpty()) { - return "{}"; //$NON-NLS-1$ + @Override public synchronized String toString() { + StringBuilder result = new StringBuilder(CHARS_PER_ENTRY * size); + result.append('{'); + Iterator<Entry<K, V>> i = entrySet().iterator(); + boolean hasMore = i.hasNext(); + while (hasMore) { + Entry<K, V> entry = i.next(); + + K key = entry.getKey(); + result.append(key == this ? "(this Map)" : key.toString()); + + result.append('='); + + V value = entry.getValue(); + result.append(value == this ? "(this Map)" : value.toString()); + + if (hasMore = i.hasNext()) { + result.append(", "); + } } - StringBuilder buffer = new StringBuilder(size() * 28); - buffer.append('{'); - for (int i = lastSlot; i >= firstSlot; i--) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - if (entry.key != this) { - buffer.append(entry.key); - } else { - // luni.04=this Map - buffer.append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - } - buffer.append('='); - if (entry.value != this) { - buffer.append(entry.value); - } else { - // luni.04=this Map - buffer.append("(" + Messages.getString("luni.04") + ")"); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - } - buffer.append(", "); //$NON-NLS-1$ - entry = entry.next; + result.append('}'); + return result.toString(); + } + + private final class KeySet extends AbstractSet<K> { + public Iterator<K> iterator() { + return new KeyIterator(); + } + public int size() { + return Hashtable.this.size(); + } + public boolean contains(Object o) { + return containsKey(o); + } + public boolean remove(Object o) { + synchronized (Hashtable.this) { + int oldSize = size; + Hashtable.this.remove(o); + return size != oldSize; + } + } + public void clear() { + Hashtable.this.clear(); + } + public boolean removeAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.removeAll(collection); + } + } + public boolean retainAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.retainAll(collection); + } + } + public boolean containsAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.containsAll(collection); } } - // Remove the last ", " - if (elementCount > 0) { - buffer.setLength(buffer.length() - 2); + public boolean equals(Object object) { + synchronized (Hashtable.this) { + return super.equals(object); + } + } + public int hashCode() { + synchronized (Hashtable.this) { + return super.hashCode(); + } + } + public String toString() { + synchronized (Hashtable.this) { + return super.toString(); + } + } + public Object[] toArray() { + synchronized (Hashtable.this) { + return super.toArray(); + } + } + public <T> T[] toArray(T[] a) { + synchronized (Hashtable.this) { + return super.toArray(a); + } + } + } + + private final class Values extends AbstractCollection<V> { + public Iterator<V> iterator() { + return new ValueIterator(); + } + public int size() { + return Hashtable.this.size(); + } + public boolean contains(Object o) { + return containsValue(o); + } + public void clear() { + Hashtable.this.clear(); + } + public boolean containsAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.containsAll(collection); + } + } + public String toString() { + synchronized (Hashtable.this) { + return super.toString(); + } + } + public Object[] toArray() { + synchronized (Hashtable.this) { + return super.toArray(); + } + } + public <T> T[] toArray(T[] a) { + synchronized (Hashtable.this) { + return super.toArray(a); + } + } + } + + private final class EntrySet extends AbstractSet<Entry<K, V>> { + public Iterator<Entry<K, V>> iterator() { + return new EntryIterator(); + } + public boolean contains(Object o) { + if (!(o instanceof Entry)) + return false; + Entry<?, ?> e = (Entry<?, ?>) o; + return containsMapping(e.getKey(), e.getValue()); + } + public boolean remove(Object o) { + if (!(o instanceof Entry)) + return false; + Entry<?, ?> e = (Entry<?, ?>)o; + return removeMapping(e.getKey(), e.getValue()); + } + public int size() { + return Hashtable.this.size(); + } + public void clear() { + Hashtable.this.clear(); + } + public boolean removeAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.removeAll(collection); + } + } + public boolean retainAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.retainAll(collection); + } + } + public boolean containsAll(Collection<?> collection) { + synchronized (Hashtable.this) { + return super.containsAll(collection); + } + } + public boolean equals(Object object) { + synchronized (Hashtable.this) { + return super.equals(object); + } + } + public int hashCode() { + return Hashtable.this.hashCode(); + } + public String toString() { + synchronized (Hashtable.this) { + return super.toString(); + } + } + public Object[] toArray() { + synchronized (Hashtable.this) { + return super.toArray(); + } + } + public <T> T[] toArray(T[] a) { + synchronized (Hashtable.this) { + return super.toArray(a); + } } - buffer.append('}'); - return buffer.toString(); } /** - * Returns a collection of the values contained in this {@code Hashtable}. - * The collection is backed by this {@code Hashtable} so changes to one are - * reflected by the other. The collection does not support adding. - * - * @return a collection of the values. + * Applies a supplemental hash function to a given hashCode, which defends + * against poor quality hash functions. This is critical because Hashtable + * uses power-of-two length hash tables, that otherwise encounter collisions + * for hashCodes that do not differ in lower or upper bits. + */ + private static int secondaryHash(int h) { + // Doug Lea's supplemental hash function + h ^= (h >>> 20) ^ (h >>> 12); + return h ^ (h >>> 7) ^ (h >>> 4); + } + + /** + * Returns the smallest power of two >= its argument, with several caveats: + * If the argument is negative but not Integer.MIN_VALUE, the method returns + * zero. If the argument is > 2^30 or equal to Integer.MIN_VALUE, the method + * returns Integer.MIN_VALUE. If the argument is zero, the method returns + * zero. */ - public Collection<V> values() { - return new Collections.SynchronizedCollection<V>( - new AbstractCollection<V>() { - @Override - public boolean contains(Object object) { - return Hashtable.this.contains(object); - } - - @Override - public int size() { - return elementCount; - } - - @Override - public void clear() { - Hashtable.this.clear(); - } - - @Override - public Iterator<V> iterator() { - return new HashIterator<V>( - new MapEntry.Type<V, K, V>() { - public V get(MapEntry<K, V> entry) { - return entry.value; - } - }); - } - }, this); + private static int roundUpToPowerOfTwo(int i) { + i--; // If input is a power of two, shift its high-order bit right + + // "Smear" the high-order bit all the way to the right + i |= i >>> 1; + i |= i >>> 2; + i |= i >>> 4; + i |= i >>> 8; + i |= i >>> 16; + + return i + 1; } + private static final long serialVersionUID = 1421746759512286392L; + + /** + * Serializable fields. + * + * @serialField loadFactor float + * load factor for this Hashtable + */ + private static final ObjectStreamField[] serialPersistentFields = { + new ObjectStreamField("threshold", Integer.TYPE), + new ObjectStreamField("loadFactor", Float.TYPE) + }; + private synchronized void writeObject(ObjectOutputStream stream) throws IOException { - stream.defaultWriteObject(); - stream.writeInt(elementData.length); - stream.writeInt(elementCount); - for (int i = elementData.length; --i >= 0;) { - Entry<K, V> entry = elementData[i]; - while (entry != null) { - stream.writeObject(entry.key); - stream.writeObject(entry.value); - entry = entry.next; - } + // Emulate loadFactor field for other implementations to read + ObjectOutputStream.PutField fields = stream.putFields(); + fields.put("threshold", (int) (DEFAULT_LOAD_FACTOR * table.length)); + fields.put("loadFactor", DEFAULT_LOAD_FACTOR); + stream.writeFields(); + + stream.writeInt(table.length); // Capacity + stream.writeInt(size); + for (Entry<K, V> e : entrySet()) { + stream.writeObject(e.getKey()); + stream.writeObject(e.getValue()); } } - @SuppressWarnings("unchecked") private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); - int length = stream.readInt(); - elementData = newElementArray(length); - elementCount = stream.readInt(); - for (int i = elementCount; --i >= 0;) { - Object key = stream.readObject(); - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % length; - if (index < firstSlot) { - firstSlot = index; - } - if (index > lastSlot) { - lastSlot = index; - } - Entry<K, V> entry = newEntry((K) key, (V) stream.readObject(), hash); - entry.next = elementData[index]; - elementData[index] = entry; + int capacity = stream.readInt(); + if (capacity < 0) { + throw new InvalidObjectException("Capacity: " + capacity); + } + if (capacity < MINIMUM_CAPACITY) { + capacity = MINIMUM_CAPACITY; + } else if (capacity > MAXIMUM_CAPACITY) { + capacity = MAXIMUM_CAPACITY; + } else { + capacity = roundUpToPowerOfTwo(capacity); + } + makeTable(capacity); + + int size = stream.readInt(); + if (size < 0) { + throw new InvalidObjectException("Size: " + size); + } + + for (int i = 0; i < size; i++) { + @SuppressWarnings("unchecked") K key = (K) stream.readObject(); + @SuppressWarnings("unchecked") V val = (V) stream.readObject(); + constructorPut(key, val); } } } diff --git a/luni/src/main/java/java/util/LinkedHashMap.java b/luni/src/main/java/java/util/LinkedHashMap.java index ed526d8..4e2fb3c 100644 --- a/luni/src/main/java/java/util/LinkedHashMap.java +++ b/luni/src/main/java/java/util/LinkedHashMap.java @@ -1,10 +1,10 @@ /* * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with + * 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 + * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * @@ -15,6 +15,10 @@ * limitations under the License. */ +// BEGIN android-note +// Completely different implementation from harmony. Runs much faster. +// BEGIN android-note + package java.util; /** @@ -45,69 +49,68 @@ package java.util; * elements during iteration. It is not possible to guarantee that this * mechanism works in all cases of unsynchronized concurrent modification. It * should only be used for debugging purposes. - * - * @since 1.4 */ public class LinkedHashMap<K, V> extends HashMap<K, V> { - private static final long serialVersionUID = 3801124242820219131L; + /** + * A dummy entry in the circular linked list of entries in the map. + * The first real entry is header.nxt, and the last is header.prv. + * If the map is empty, header.nxt == header && header.prv == header. + */ + private transient LinkedEntry<K, V> header; + /** + * True if access ordered, false if insertion ordered. + */ private final boolean accessOrder; - transient private LinkedHashMapEntry<K, V> head, tail; - /** * Constructs a new empty {@code LinkedHashMap} instance. */ public LinkedHashMap() { super(); + init(); accessOrder = false; - head = null; } /** * Constructs a new {@code LinkedHashMap} instance with the specified * capacity. * - * @param s + * @param initialCapacity * the initial capacity of this map. - * @throws IllegalArgumentException - * if the capacity is less than zero. + * @exception IllegalArgumentException + * when the capacity is less than zero. */ - public LinkedHashMap(int s) { - super(s); - accessOrder = false; - head = null; + public LinkedHashMap(int initialCapacity) { + this(initialCapacity, DEFAULT_LOAD_FACTOR); } /** * Constructs a new {@code LinkedHashMap} instance with the specified * capacity and load factor. * - * @param s + * @param initialCapacity * the initial capacity of this map. - * @param lf + * @param loadFactor * the initial load factor. * @throws IllegalArgumentException * when the capacity is less than zero or the load factor is * less or equal to zero. */ - public LinkedHashMap(int s, float lf) { - super(s, lf); - accessOrder = false; - head = null; - tail = null; + public LinkedHashMap(int initialCapacity, float loadFactor) { + this(initialCapacity, loadFactor, false); } /** * Constructs a new {@code LinkedHashMap} instance with the specified * capacity, load factor and a flag specifying the ordering behavior. * - * @param s + * @param initialCapacity * the initial capacity of this hash map. - * @param lf + * @param loadFactor * the initial load factor. - * @param order + * @param accessOrder * {@code true} if the ordering should be done based on the last * access (from least-recently accessed to most-recently * accessed), and {@code false} if the ordering should be the @@ -116,197 +119,75 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> { * when the capacity is less than zero or the load factor is * less or equal to zero. */ - public LinkedHashMap(int s, float lf, boolean order) { - super(s, lf); - accessOrder = order; - head = null; - tail = null; + public LinkedHashMap( + int initialCapacity, float loadFactor, boolean accessOrder) { + super(initialCapacity, loadFactor); + init(); + this.accessOrder = accessOrder; } /** * Constructs a new {@code LinkedHashMap} instance containing the mappings * from the specified map. The order of the elements is preserved. * - * @param m + * @param map * the mappings to add. */ - public LinkedHashMap(Map<? extends K, ? extends V> m) { - accessOrder = false; - head = null; - tail = null; - putAll(m); + public LinkedHashMap(Map<? extends K, ? extends V> map) { + this(capacityForInitSize(map.size())); + constructorPutAll(map); } - private static class AbstractMapIterator<K, V> { - int expectedModCount; - LinkedHashMapEntry<K, V> futureEntry; - LinkedHashMapEntry<K, V> currentEntry; - final LinkedHashMap<K, V> associatedMap; - - AbstractMapIterator(LinkedHashMap<K, V> map) { - expectedModCount = map.modCount; - futureEntry = map.head; - associatedMap = map; - } - - public boolean hasNext() { - return (futureEntry != null); - } - - final void checkConcurrentMod() throws ConcurrentModificationException { - if (expectedModCount != associatedMap.modCount) { - throw new ConcurrentModificationException(); - } - } - - final void makeNext() { - checkConcurrentMod(); - if (!hasNext()) { - throw new NoSuchElementException(); - } - currentEntry = futureEntry; - futureEntry = futureEntry.chainForward; - } - - public void remove() { - checkConcurrentMod(); - if (currentEntry==null) { - throw new IllegalStateException(); - } - associatedMap.removeEntry(currentEntry); - LinkedHashMapEntry<K, V> lhme = currentEntry; - LinkedHashMapEntry<K, V> p = lhme.chainBackward; - LinkedHashMapEntry<K, V> n = lhme.chainForward; - LinkedHashMap<K, V> lhm = associatedMap; - if (p != null) { - p.chainForward = n; - if (n != null) { - n.chainBackward = p; - } else { - lhm.tail = p; - } - } else { - lhm.head = n; - if (n != null) { - n.chainBackward = null; - } else { - lhm.tail = null; - } - } - currentEntry = null; - expectedModCount++; - } + @Override void init(){ + header = new LinkedEntry<K, V>(null, null, 0, null, null, null); + header.nxt = header.prv = header; } - private static class EntryIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<Map.Entry<K, V>> { - - EntryIterator (LinkedHashMap<K, V> map) { - super(map); - } - - public Map.Entry<K, V> next() { - makeNext(); - return currentEntry; - } - } - - private static class KeyIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<K> { - - KeyIterator (LinkedHashMap<K, V> map) { - super(map); - } - - public K next() { - makeNext(); - return currentEntry.key; - } - } - - private static class ValueIterator <K, V> extends AbstractMapIterator<K, V> implements Iterator<V> { - - ValueIterator (LinkedHashMap<K, V> map) { - super(map); - } - - public V next() { - makeNext(); - return currentEntry.value; - } - } - - static final class LinkedHashMapEntrySet<KT, VT> extends - HashMapEntrySet<KT, VT> { - public LinkedHashMapEntrySet(LinkedHashMap<KT, VT> lhm) { - super(lhm); - } - - @Override - public Iterator<Map.Entry<KT, VT>> iterator() { - return new EntryIterator<KT,VT>((LinkedHashMap<KT, VT>) hashMap()); - } - } - - static final class LinkedHashMapEntry<K, V> extends Entry<K, V> { - LinkedHashMapEntry<K, V> chainForward, chainBackward; - - LinkedHashMapEntry(K theKey, V theValue) { - super(theKey, theValue); - chainForward = null; - chainBackward = null; - } - - LinkedHashMapEntry(K theKey, int hash) { - super(theKey, hash); - chainForward = null; - chainBackward = null; - } + /** + * LinkedEntry adds nxt/prv double-links to plain HashMapEntry. + */ + static class LinkedEntry<K, V> extends HashMapEntry<K, V> { + LinkedEntry<K, V> nxt; + LinkedEntry<K, V> prv; - @Override - @SuppressWarnings("unchecked") - public Object clone() { - LinkedHashMapEntry<K, V> entry = (LinkedHashMapEntry<K, V>) super - .clone(); - entry.chainBackward = chainBackward; - entry.chainForward = chainForward; - LinkedHashMapEntry<K, V> lnext = (LinkedHashMapEntry<K, V>) entry.next; - if (lnext != null) { - entry.next = (LinkedHashMapEntry<K, V>) lnext.clone(); - } - return entry; + LinkedEntry(K key, V value, int hash, HashMapEntry<K, V> next, + LinkedEntry<K, V> nxt, LinkedEntry<K, V> prv) { + super(key, value, hash, next); + this.nxt = nxt; + this.prv = prv; } } - @Override - public boolean containsValue(Object value) { - LinkedHashMapEntry<K, V> entry = head; - if (null == value) { - while (null != entry) { - if (null == entry.value) { - return true; - } - entry = entry.chainForward; - } - } else { - while (null != entry) { - if (value.equals(entry.value)) { - return true; - } - entry = entry.chainForward; - } - } - return false; + /** + * Evicts eldest entry if instructed, creates a new entry and links it in + * as head of linked list. This method should call constructorNewEntry + * (instead of duplicating code) if the performance of your VM permits. + */ + @Override LinkedEntry<K, V> newEntry( + K key, V value, int hash, HashMapEntry<K, V> next) { + // Remove eldest entry if instructed to do so. + LinkedEntry<K, V> eldest = header.nxt; + if (eldest != header && removeEldestEntry(eldest)) + remove(eldest.key); + + // Create new entry and link it on to list + LinkedEntry<K, V> header = this.header; + LinkedEntry<K, V> oldTail = header.prv; + LinkedEntry<K, V> newTail + = new LinkedEntry<K,V>(key, value, hash, next, header, oldTail); + return oldTail.nxt = header.prv = newTail; } /** - * Create a new element array - * - * @param s - * @return Reference to the element array + * As above, but without eviction. */ - @Override - @SuppressWarnings("unchecked") - Entry<K, V>[] newElementArray(int s) { - return new LinkedHashMapEntry[s]; + @Override HashMapEntry<K, V> constructorNewEntry( + K key, V value, int hash, HashMapEntry<K, V> next) { + LinkedEntry<K, V> header = this.header; + LinkedEntry<K, V> oldTail = header.prv; + LinkedEntry<K, V> newTail + = new LinkedEntry<K,V>(key, value, hash, next, header, oldTail); + return oldTail.nxt = header.prv = newTail; } /** @@ -317,338 +198,167 @@ public class LinkedHashMap<K, V> extends HashMap<K, V> { * @return the value of the mapping with the specified key, or {@code null} * if no mapping for the specified key is found. */ - @Override - public V get(Object key) { - LinkedHashMapEntry<K, V> m; + @Override public V get(Object key) { + /* + * This method is overridden to eliminate the need for a polymorphic + * invocation in superclass at the expense of code duplication. + */ if (key == null) { - m = (LinkedHashMapEntry<K, V>) findNullKeyEntry(); - } else { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - m = (LinkedHashMapEntry<K, V>) findNonNullKeyEntry(key, index, hash); - } - if (m == null) { - return null; - } - if (accessOrder && tail != m) { - // BEGIN android-added - modCount++; - // END android-added - LinkedHashMapEntry<K, V> p = m.chainBackward; - LinkedHashMapEntry<K, V> n = m.chainForward; - n.chainBackward = p; - if (p != null) { - p.chainForward = n; - } else { - head = n; + HashMapEntry<K, V> e = entryForNullKey; + if (e == null) + return null; + if (accessOrder) + makeTail((LinkedEntry<K, V>) e); + return e.value; + } + + // Doug Lea's supplemental secondaryHash function (inlined) + int hash = key.hashCode(); + hash ^= (hash >>> 20) ^ (hash >>> 12); + hash ^= (hash >>> 7) ^ (hash >>> 4); + + HashMapEntry<K, V>[] tab = table; + for (HashMapEntry<K, V> e = tab[hash & (tab.length - 1)]; + e != null; e = e.next) { + K eKey = e.key; + if (eKey == key || (e.hash == hash && key.equals(eKey))) { + if (accessOrder) + makeTail((LinkedEntry<K, V>) e); + return e.value; } - m.chainForward = null; - m.chainBackward = tail; - tail.chainForward = m; - tail = m; } - return m.value; - } - - /* - * @param key @param index @return Entry - */ - @Override - Entry<K, V> createEntry(K key, int index, V value) { - LinkedHashMapEntry<K, V> m = new LinkedHashMapEntry<K, V>(key, value); - m.next = elementData[index]; - elementData[index] = m; - linkEntry(m); - return m; - } - - Entry<K, V> createHashedEntry(K key, int index, int hash) { - LinkedHashMapEntry<K, V> m = new LinkedHashMapEntry<K, V>(key, hash); - m.next = elementData[index]; - elementData[index] = m; - linkEntry(m); - return m; + return null; } /** - * Maps the specified key to the specified value. - * - * @param key - * the key. - * @param value - * the value. - * @return the value of any previous mapping with the specified key or - * {@code null} if there was no such mapping. + * Relinks the given entry to the tail of the list. Under access ordering, + * this method is invoked whenever the value of a pre-existing entry is + * read by Map.get or modified by Map.put. */ - @Override - public V put(K key, V value) { - V result = putImpl(key, value); - - if (removeEldestEntry(head)) { - remove(head.key); - } - - return result; + private void makeTail(LinkedEntry<K, V> e) { + // Unlink e + e.prv.nxt = e.nxt; + e.nxt.prv = e.prv; + + // Relink e as tail + LinkedEntry<K, V> header = this.header; + LinkedEntry<K, V> oldTail = header.prv; + e.nxt = header; + e.prv = oldTail; + oldTail.nxt = header.prv = e; + modCount++; } - V putImpl(K key, V value) { - LinkedHashMapEntry<K, V> m; - if (elementCount == 0) { - head = tail = null; - } - if (key == null) { - m = (LinkedHashMapEntry<K, V>) findNullKeyEntry(); - if (m == null) { - modCount++; - // Check if we need to remove the oldest entry. The check - // includes accessOrder since an accessOrder LinkedHashMap does - // not record the oldest member in 'head'. - if (++elementCount > threshold) { - rehash(); - } - m = (LinkedHashMapEntry<K, V>) createHashedEntry(null, 0, 0); - } else { - linkEntry(m); - } - } else { - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % elementData.length; - m = (LinkedHashMapEntry<K, V>) findNonNullKeyEntry(key, index, hash); - if (m == null) { - modCount++; - if (++elementCount > threshold) { - rehash(); - index = (hash & 0x7FFFFFFF) % elementData.length; - } - m = (LinkedHashMapEntry<K, V>) createHashedEntry(key, index, - hash); - } else { - linkEntry(m); - } + @Override void preModify(HashMapEntry<K, V> e) { + if (accessOrder) { + makeTail((LinkedEntry<K, V>) e); } + } - V result = m.value; - m.value = value; - return result; + @Override void postRemove(HashMapEntry<K, V> e) { + LinkedEntry<K, V> le = (LinkedEntry<K, V>) e; + le.prv.nxt = le.nxt; + le.nxt.prv = le.prv; + le.nxt = le.prv = null; // Help the GC (for performance) } - /* - * @param m + /** + * This override is done for LinkedHashMap performance: iteration is cheaper + * via LinkedHashMap nxt links. */ - void linkEntry(LinkedHashMapEntry<K, V> m) { - if (tail == m) { - return; - } - - if (head == null) { - // Check if the map is empty - head = tail = m; - return; - } - - // we need to link the new entry into either the head or tail - // of the chain depending on if the LinkedHashMap is accessOrder or not - LinkedHashMapEntry<K, V> p = m.chainBackward; - LinkedHashMapEntry<K, V> n = m.chainForward; - if (p == null) { - if (n != null) { - // The entry must be the head but not the tail - if (accessOrder) { - head = n; - n.chainBackward = null; - m.chainBackward = tail; - m.chainForward = null; - tail.chainForward = m; - tail = m; + @Override public boolean containsValue(Object value) { + if (value == null) { + for (LinkedEntry<K, V> header = this.header, e = header.nxt; + e != header; e = e.nxt) { + if (e.value == null) { + return true; } - } else { - // This is a new entry - m.chainBackward = tail; - m.chainForward = null; - tail.chainForward = m; - tail = m; } - return; + return entryForNullKey != null && entryForNullKey.value == null; } - if (n == null) { - // The entry must be the tail so we can't get here - return; - } - - // The entry is neither the head nor tail - if (accessOrder) { - p.chainForward = n; - n.chainBackward = p; - m.chainForward = null; - m.chainBackward = tail; - tail.chainForward = m; - tail = m; + // value is non-null + for (LinkedEntry<K, V> header = this.header, e = header.nxt; + e != header; e = e.nxt) { + if (value.equals(e.value)) { + return true; + } } + return entryForNullKey != null && value.equals(entryForNullKey.value); } - - /** - * Returns a set containing all of the mappings in this map. Each mapping is - * an instance of {@link Map.Entry}. As the set is backed by this map, - * changes in one will be reflected in the other. - * - * @return a set of the mappings. - */ - @Override - public Set<Map.Entry<K, V>> entrySet() { - return new LinkedHashMapEntrySet<K, V>(this); + + public void clear() { + super.clear(); + + // Clear all links to help GC + LinkedEntry<K, V> header = this.header; + LinkedEntry<K, V> e = header; + do { + LinkedEntry<K, V> nxt = e.nxt; + e.nxt = e.prv = null; + e = nxt; + } while(e != header); + + header.nxt = header.prv = header; } - /** - * Returns a set of the keys contained in this map. The set is backed by - * this map so changes to one are reflected by the other. The set does not - * support adding. - * - * @return a set of the keys. - */ - @Override - public Set<K> keySet() { - if (keySet == null) { - keySet = new AbstractSet<K>() { - @Override - public boolean contains(Object object) { - return containsKey(object); - } + private abstract class LinkedHashIterator<T> implements Iterator<T> { + LinkedEntry<K, V> next = header.nxt; + LinkedEntry<K, V> lastReturned = null; + int expectedModCount = modCount; - @Override - public int size() { - return LinkedHashMap.this.size(); - } - - @Override - public void clear() { - LinkedHashMap.this.clear(); - } + public final boolean hasNext() { + return next != header; + } - @Override - public boolean remove(Object key) { - if (containsKey(key)) { - LinkedHashMap.this.remove(key); - return true; - } - return false; - } + final LinkedEntry<K, V> nextEntry() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + LinkedEntry<K, V> e = next; + if (e == header) + throw new NoSuchElementException(); + next = e.nxt; + return lastReturned = e; + } - @Override - public Iterator<K> iterator() { - return new KeyIterator<K,V>(LinkedHashMap.this); - } - }; + public final void remove() { + if (modCount != expectedModCount) + throw new ConcurrentModificationException(); + if (lastReturned == null) + throw new IllegalStateException(); + LinkedHashMap.this.remove(lastReturned.key); + lastReturned = null; + expectedModCount = modCount; } - return keySet; } - /** - * Returns a collection of the values contained in this map. The collection - * is backed by this map so changes to one are reflected by the other. The - * collection supports remove, removeAll, retainAll and clear operations, - * and it does not support add or addAll operations. - * <p> - * This method returns a collection which is the subclass of - * AbstractCollection. The iterator method of this subclass returns a - * "wrapper object" over the iterator of map's entrySet(). The size method - * wraps the map's size method and the contains method wraps the map's - * containsValue method. - * <p> - * The collection is created when this method is called for the first time - * and returned in response to all subsequent calls. This method may return - * different collections when multiple concurrent calls occur, since no - * synchronization is performed. - * - * @return a collection of the values contained in this map. - */ - @Override - public Collection<V> values() { - if (valuesCollection == null) { - valuesCollection = new AbstractCollection<V>() { - @Override - public boolean contains(Object object) { - return containsValue(object); - } - - @Override - public int size() { - return LinkedHashMap.this.size(); - } + private final class KeyIterator extends LinkedHashIterator<K> { + public final K next() { return nextEntry().key; } + } - @Override - public void clear() { - LinkedHashMap.this.clear(); - } + private final class ValueIterator extends LinkedHashIterator<V> { + public final V next() { return nextEntry().value; } + } - @Override - public Iterator<V> iterator() { - return new ValueIterator<K,V>(LinkedHashMap.this); - } - }; - } - return valuesCollection; + private final class EntryIterator + extends LinkedHashIterator<Map.Entry<K, V>> { + public final Map.Entry<K, V> next() { return nextEntry(); } } - /** - * Removes the mapping with the specified key from this map. - * - * @param key - * the key of the mapping to remove. - * @return the value of the removed mapping or {@code null} if no mapping - * for the specified key was found. - */ - @Override - public V remove(Object key) { - LinkedHashMapEntry<K, V> m = (LinkedHashMapEntry<K, V>) removeEntry(key); - if (m == null) { - return null; - } - LinkedHashMapEntry<K, V> p = m.chainBackward; - LinkedHashMapEntry<K, V> n = m.chainForward; - if (p != null) { - p.chainForward = n; - } else { - head = n; - } - if (n != null) { - n.chainBackward = p; - } else { - tail = p; - } - return m.value; + // Override view iterator methods to generate correct iteration order + @Override Iterator<K> newKeyIterator() { + return new KeyIterator(); + } + @Override Iterator<V> newValueIterator() { + return new ValueIterator(); + } + @Override Iterator<Map.Entry<K, V>> newEntryIterator() { + return new EntryIterator(); } - /** - * This method is queried from the put and putAll methods to check if the - * eldest member of the map should be deleted before adding the new member. - * If this map was created with accessOrder = true, then the result of - * removeEldestEntry is assumed to be false. - * - * @param eldest - * the entry to check if it should be removed. - * @return {@code true} if the eldest member should be removed. - */ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) { return false; } - // BEGIN android-changed - /** - * Removes all elements from this map, leaving it empty. - * - * @see #isEmpty() - * @see #size() - */ - @Override - public void clear() { - internalClear(); - } - - @Override - void internalClear() { - super.internalClear(); - head = tail = null; - } - // END android-changed + private static final long serialVersionUID = 3801124242820219131L; } diff --git a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java index 104a981..2dea92b 100644 --- a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java +++ b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java @@ -1385,7 +1385,9 @@ public class HttpURLConnection extends java.net.HttpURLConnection { output.append("\r\n"); //$NON-NLS-1$ } if (reqHeader.get("Accept") == null) { //$NON-NLS-1$ - output.append("Accept: *; */*\r\n"); //$NON-NLS-1$ + // BEGIN android-changed + output.append("Accept: *, */*\r\n"); //$NON-NLS-1$ + // END android-changed } if (httpVersion > 0 && reqHeader.get("Connection") == null) { //$NON-NLS-1$ output.append("Connection: Keep-Alive\r\n"); //$NON-NLS-1$ diff --git a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java index 1ec6240..70432a6 100644 --- a/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java +++ b/luni/src/main/java/org/apache/harmony/luni/platform/OSNetworkSystem.java @@ -207,20 +207,33 @@ final class OSNetworkSystem implements INetworkSystem { static native void disconnectDatagramImpl(FileDescriptor aFD) throws SocketException; - public InetAddress getHostByAddr(byte[] addr) + public InetAddress getHostByAddr(byte[] ipAddress) throws UnknownHostException { - return getHostByAddrImpl(addr); + // BEGIN android-changed + // Wallpaper fix for http://b/1851257. This is a layering violation, + // but at least the method has the right return type. + // TODO: Fix the socket code to remove this method altogether. + return InetAddress.getByAddress(ipAddress); + // END android-changed } - static native InetAddress getHostByAddrImpl(byte[] addr) - throws UnknownHostException; + // BEGIN android-removed + // static native InetAddress getHostByAddrImpl(byte[] addr) + // throws UnknownHostException; + // END android-removed - public InetAddress getHostByName(String addr, + // BEGIN android-removed + public InetAddress getHostByName(String hostName, boolean preferIPv6Addresses) throws UnknownHostException { - return getHostByNameImpl(addr, preferIPv6Addresses); + // BEGIN android-changed + // Wallpaper fix for http://b/1851257. + return InetAddress.getByName(hostName); + // END android-changed } - static native InetAddress getHostByNameImpl(String addr, - boolean preferIPv6Addresses) throws UnknownHostException; + // BEGIN android-removed + // static native InetAddress getHostByNameImpl(String addr, + // boolean preferIPv6Addresses) throws UnknownHostException; + // END android-removed public int getSocketFlags() { return getSocketFlagsImpl(); diff --git a/luni/src/main/native/java_net_InetAddress.cpp b/luni/src/main/native/java_net_InetAddress.cpp index 8724817..d7b4931 100644 --- a/luni/src/main/native/java_net_InetAddress.cpp +++ b/luni/src/main/native/java_net_InetAddress.cpp @@ -100,7 +100,10 @@ static jobjectArray getAllByNameUsingAdb(JNIEnv* env, const char* name) env->SetByteArrayRegion(byteArray, 0, 4, (jbyte*) &outaddr.s_addr); env->SetObjectArrayElement(addressArray, 1, byteArray); } + } else { + jniThrowException(env, "java/net/UnknownHostException", "adb error"); } + return addressArray; } @@ -111,11 +114,6 @@ static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name, jobjectArray addressArray = NULL; memset(&hints, 0, sizeof(hints)); - /* - * IPv4 only for now until the socket code supports IPv6; otherwise, the - * resolver will create two separate requests, one for IPv4 and one, - * currently unnecessary, for IPv6. - */ hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_ADDRCONFIG; /* @@ -194,8 +192,8 @@ static jobjectArray getAllByNameUsingDns(JNIEnv* env, const char* name, env, "java/lang/SecurityException", "Permission denied (maybe missing INTERNET permission)"); } else { - // Do nothing. Return value will be null and the caller will throw an - // UnknownHostExeption. + jniThrowException(env, "java/net/UnknownHostException", + gai_strerror(result)); } if (addressList) { @@ -232,15 +230,19 @@ jobjectArray InetAddress_getallbyname(JNIEnv* env, jobject obj, out = getAllByNameUsingDns(env, name, preferIPv4Stack); } - if (!out) { - LOGI("Unknown host %s, throwing UnknownHostException", name); - jniThrowException(env, "java/net/UnknownHostException", name); - } env->ReleaseStringUTFChars(javaName, name); return out; } +/** + * Looks up the name corresponding to an IP address. + * + * @param javaAddress: a byte array containing the raw IP address bytes. Must be + * 4 or 16 bytes long. + * @return the hostname. + * @throws UnknownHostException: the IP address has no associated hostname. + */ static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj, jbyteArray javaAddress) { @@ -257,57 +259,45 @@ static jstring InetAddress_gethostbyaddr(JNIEnv* env, jobject obj, } // Convert the raw address bytes into a socket address structure. + int ret = 0; struct sockaddr_storage ss; struct sockaddr_in *sin = (struct sockaddr_in *) &ss; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) &ss; size_t socklen; + memset(&ss, 0, sizeof(ss)); switch (addrlen) { case 4: socklen = sizeof(struct sockaddr_in); - memset(sin, 0, sizeof(struct sockaddr_in)); sin->sin_family = AF_INET; - memcpy(&sin->sin_addr.s_addr, rawAddress, 4); + memcpy(&sin->sin_addr.s_addr, rawAddress, addrlen); env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT); break; case 16: socklen = sizeof(struct sockaddr_in6); - memset(sin6, 0, sizeof(struct sockaddr_in6)); sin6->sin6_family = AF_INET6; - memcpy(&sin6->sin6_addr.s6_addr, rawAddress, 16); + memcpy(&sin6->sin6_addr.s6_addr, rawAddress, addrlen); env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT); break; default: + // The caller already throws an exception in this case. Don't worry + // about it here. env->ReleaseByteArrayElements(javaAddress, rawAddress, JNI_ABORT); - jniThrowException(env, "java/net/UnknownHostException", - "Invalid address length"); return NULL; } - - // Convert the socket address structure to an IP string for logging. - int ret; - char ipstr[INET6_ADDRSTRLEN]; - ret = getnameinfo((struct sockaddr *) &ss, socklen, ipstr, sizeof(ipstr), - NULL, 0, NI_NUMERICHOST); - if (ret) { - LOGE("gethostbyaddr: getnameinfo: %s", gai_strerror(ret)); - return NULL; + // Look up the host name from the IP address. + char name[NI_MAXHOST]; + if (ret == 0) { + ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name), + NULL, 0, NI_NAMEREQD); } - // Look up the IP address from the socket address structure. - jstring result = NULL; - char name[NI_MAXHOST]; - ret = getnameinfo((struct sockaddr *) &ss, socklen, name, sizeof(name), - NULL, 0, 0); if (ret == 0) { - LOGI("gethostbyaddr: getnameinfo: %s = %s", ipstr, name); - result = env->NewStringUTF(name); - } else { - LOGE("gethostbyaddr: getnameinfo: unknown host %s: %s", ipstr, - gai_strerror(ret)); + return env->NewStringUTF(name); } - return result; + jniThrowException(env, "java/net/UnknownHostException", gai_strerror(ret)); + return NULL; } /* diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp index 3e31743..2e814cc 100644 --- a/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp +++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSMemory.cpp @@ -172,12 +172,10 @@ static void harmony_nio_putBytesImpl(JNIEnv *_env, jobject _this, } static void -swapShorts(jshort *shorts, int numBytes) { +swapShorts(jshort *shorts, int count) { jbyte *src = (jbyte *) shorts; jbyte *dst = src; - int i; - - for (i = 0; i < numBytes; i+=2) { + for (int i = 0; i < count; ++i) { jbyte b0 = *src++; jbyte b1 = *src++; *dst++ = b1; @@ -186,11 +184,10 @@ swapShorts(jshort *shorts, int numBytes) { } static void -swapInts(jint *ints, int numBytes) { +swapInts(jint *ints, int count) { jbyte *src = (jbyte *) ints; jbyte *dst = src; - int i; - for (i = 0; i < numBytes; i+=4) { + for (int i = 0; i < count; ++i) { jbyte b0 = *src++; jbyte b1 = *src++; jbyte b2 = *src++; @@ -204,48 +201,30 @@ swapInts(jint *ints, int numBytes) { /* * Class: org_apache_harmony_luni_platform_OSMemory - * Method: putShortsImpl + * Method: setShortArrayImpl * Signature: (I[SIIZ)V */ -static void harmony_nio_putShortsImpl(JNIEnv *_env, jobject _this, +static void harmony_nio_setShortArrayImpl(JNIEnv *_env, jobject _this, jint pointer, jshortArray src, jint offset, jint length, jboolean swap) { - - offset = offset << 1; - length = length << 1; - - jshort *src_ = - (jshort *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0); - if (swap) { - swapShorts(src_ + offset, length); - } - memcpy((jbyte *)pointer, (jbyte *)src_ + offset, length); + jshort* dst = reinterpret_cast<jshort*>(static_cast<uintptr_t>(pointer)); + _env->GetShortArrayRegion(src, offset, length, dst); if (swap) { - swapShorts(src_ + offset, length); + swapShorts(dst, length); } - _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT); } /* * Class: org_apache_harmony_luni_platform_OSMemory - * Method: putIntsImpl + * Method: setIntArrayImpl * Signature: (I[IIIZ)V */ -static void harmony_nio_putIntsImpl(JNIEnv *_env, jobject _this, +static void harmony_nio_setIntArrayImpl(JNIEnv *_env, jobject _this, jint pointer, jintArray src, jint offset, jint length, jboolean swap) { - - offset = offset << 2; - length = length << 2; - - jint *src_ = - (jint *)_env->GetPrimitiveArrayCritical(src, (jboolean *)0); + jint* dst = reinterpret_cast<jint*>(static_cast<uintptr_t>(pointer)); + _env->GetIntArrayRegion(src, offset, length, dst); if (swap) { - swapInts(src_ + offset, length); + swapInts(dst, length); } - memcpy((jbyte *)pointer, (jbyte *)src_ + offset, length); - if (swap) { - swapInts(src_ + offset, length); - } - _env->ReleasePrimitiveArrayCritical(src, src_, JNI_ABORT); } /* @@ -588,8 +567,8 @@ static JNINativeMethod gMethods[] = { { "memmove", "(IIJ)V", (void*) harmony_nio_memmove }, { "getByteArray", "(I[BII)V",(void*) harmony_nio_getBytesImpl }, { "setByteArray", "(I[BII)V",(void*) harmony_nio_putBytesImpl }, - { "setShortArray", "(I[SIIZ)V",(void*) harmony_nio_putShortsImpl }, - { "setIntArray", "(I[IIIZ)V",(void*) harmony_nio_putIntsImpl }, + { "setShortArray", "(I[SIIZ)V",(void*) harmony_nio_setShortArrayImpl }, + { "setIntArray", "(I[IIIZ)V",(void*) harmony_nio_setIntArrayImpl }, { "getByte", "(I)B", (void*) harmony_nio_getByteImpl }, { "setByte", "(IB)V", (void*) harmony_nio_putByteImpl }, { "getShort", "(I)S", (void*) harmony_nio_getShortImpl }, @@ -653,4 +632,3 @@ int register_org_apache_harmony_luni_platform_OSMemory(JNIEnv *_env) { "org/apache/harmony/luni/platform/OSMemory", gMethods, NELEM(gMethods)); } - diff --git a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp index cce822a..d689fc7 100644 --- a/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp +++ b/luni/src/main/native/org_apache_harmony_luni_platform_OSNetworkSystem.cpp @@ -156,8 +156,9 @@ struct CachedFields { jfieldID fd_descriptor; jclass iaddr_class; - jmethodID iaddr_class_init; jmethodID iaddr_getbyaddress; + jclass i4addr_class; + jmethodID i4addr_class_init; jfieldID iaddr_ipaddress; jclass genericipmreq_class; jclass integer_class; @@ -171,6 +172,7 @@ struct CachedFields { jfieldID byte_class_value; jclass string_class; jmethodID string_class_init; + jclass socketimpl_class; jfieldID socketimpl_address; jfieldID socketimpl_port; jclass dpack_class; @@ -1397,229 +1399,77 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj, } memset(&gCachedFields, 0, sizeof(gCachedFields)); - - // initializing InetAddress - - jclass iaddrclass = env->FindClass("java/net/InetAddress"); - - if (iaddrclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.net.InetAddress"); - return; - } - - gCachedFields.iaddr_class = (jclass) env->NewGlobalRef(iaddrclass); - - jmethodID iaddrclassinit = env->GetMethodID(iaddrclass, "<init>", "()V"); - - if (iaddrclassinit == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", "InetAddress.<init>()"); - return; - } - - gCachedFields.iaddr_class_init = iaddrclassinit; - - jmethodID iaddrgetbyaddress = env->GetStaticMethodID(iaddrclass, - "getByAddress", "([B)Ljava/net/InetAddress;"); - - if (iaddrgetbyaddress == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", - "InetAddress.getByAddress(byte[] val)"); - return; - } - - gCachedFields.iaddr_getbyaddress = iaddrgetbyaddress; - - jfieldID iaddripaddress = env->GetFieldID(iaddrclass, "ipaddress", "[B"); - - if (iaddripaddress == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", - "Can't find field InetAddress.ipaddress"); - return; - } - - gCachedFields.iaddr_ipaddress = iaddripaddress; - - // get the GenericIPMreq class - - jclass genericipmreqclass = env->FindClass("org/apache/harmony/luni/net/GenericIPMreq"); - - if (genericipmreqclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "org.apache.harmony.luni.net.GenericIPMreq"); - return; - } - - gCachedFields.genericipmreq_class = (jclass) env->NewGlobalRef(genericipmreqclass); - - // initializing Integer - - jclass integerclass = env->FindClass("java/lang/Integer"); - - if (integerclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.lang.Integer"); - return; - } - - jmethodID integerclassinit = env->GetMethodID(integerclass, "<init>", "(I)V"); - - if (integerclassinit == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", - "Integer.<init>(int val)"); - return; - } - - jfieldID integerclassvalue = env->GetFieldID(integerclass, "value", "I"); - - if (integerclassvalue == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", "Integer.value"); - return; - } - - gCachedFields.integer_class = (jclass) env->NewGlobalRef(integerclass); - gCachedFields.integer_class_init = integerclassinit; - gCachedFields.integer_class_value = integerclassvalue; - - // initializing Boolean - - jclass booleanclass = env->FindClass("java/lang/Boolean"); - - if (booleanclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.lang.Boolean"); - return; - } - - jmethodID booleanclassinit = env->GetMethodID(booleanclass, "<init>", "(Z)V"); - - if (booleanclassinit == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", - "Boolean.<init>(boolean val)"); - return; - } - - jfieldID booleanclassvalue = env->GetFieldID(booleanclass, "value", "Z"); - - if (booleanclassvalue == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", "Boolean.value"); - return; - } - - gCachedFields.boolean_class = (jclass) env->NewGlobalRef(booleanclass); - gCachedFields.boolean_class_init = booleanclassinit; - gCachedFields.boolean_class_value = booleanclassvalue; - - // initializing Byte - - jclass byteclass = env->FindClass("java/lang/Byte"); - - if (byteclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.lang.Byte"); - return; - } - - jmethodID byteclassinit = env->GetMethodID(byteclass, "<init>", "(B)V"); - - if (byteclassinit == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", - "Byte.<init>(byte val)"); - return; - } - - jfieldID byteclassvalue = env->GetFieldID(byteclass, "value", "B"); - - if (byteclassvalue == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", "Byte.value"); - return; - } - - gCachedFields.byte_class = (jclass) env->NewGlobalRef(byteclass); - gCachedFields.byte_class_init = byteclassinit; - gCachedFields.byte_class_value = byteclassvalue; - - // initializing String - - jclass stringclass = env->FindClass("java/lang/String"); - - if (stringclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.lang.String"); - return; - } - - jmethodID stringclassinit = env->GetMethodID(stringclass, "<init>", "([B)V"); - - if (stringclassinit == NULL) { - jniThrowException(env, "java/lang/NoSuchMethodError", - "String.<init>(byte[] val)"); - return; - } - - gCachedFields.string_class = (jclass) env->NewGlobalRef(stringclass); - gCachedFields.string_class_init = stringclassinit; - - // initializing ScoketImpl - - jclass socketimplclass = env->FindClass("java/net/SocketImpl"); - - if (socketimplclass == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.net.SocketImpl"); - return; - } - - jfieldID socketimplport = env->GetFieldID(socketimplclass, "port", "I"); - - if (socketimplport == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", "SocketImpl.port"); - return; - } - - jfieldID socketimpladdress = env->GetFieldID(socketimplclass, "address", - "Ljava/net/InetAddress;"); - - if (socketimpladdress == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", - "SocketImpl.address"); - return; - } - - gCachedFields.socketimpl_address = socketimpladdress; - gCachedFields.socketimpl_port = socketimplport; - - gCachedFields.dpack_class = env->FindClass("java/net/DatagramPacket"); - if (gCachedFields.dpack_class == NULL) { - jniThrowException(env, "java/lang/ClassNotFoundException", - "java.net.DatagramPacket"); - return; - } - - gCachedFields.dpack_address = env->GetFieldID(gCachedFields.dpack_class, - "address", "Ljava/net/InetAddress;"); - if (gCachedFields.dpack_address == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", - "DatagramPacket.address"); - return; - } - - gCachedFields.dpack_port = env->GetFieldID(gCachedFields.dpack_class, - "port", "I"); - if (gCachedFields.dpack_port == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", - "DatagramPacket.port"); - return; - } - - gCachedFields.dpack_length = env->GetFieldID(gCachedFields.dpack_class, - "length", "I"); - if (gCachedFields.dpack_length == NULL) { - jniThrowException(env, "java/lang/NoSuchFieldError", - "DatagramPacket.length"); - return; + struct CachedFields *c = &gCachedFields; + + struct classInfo { + jclass *clazz; + const char *name; + } classes[] = { + {&c->iaddr_class, "java/net/InetAddress"}, + {&c->i4addr_class, "java/net/Inet4Address"}, + {&c->genericipmreq_class, "org/apache/harmony/luni/net/GenericIPMreq"}, + {&c->integer_class, "java/lang/Integer"}, + {&c->boolean_class, "java/lang/Boolean"}, + {&c->byte_class, "java/lang/Byte"}, + {&c->string_class, "java/lang/String"}, + {&c->socketimpl_class, "java/net/SocketImpl"}, + {&c->dpack_class, "java/net/DatagramPacket"} + }; + for (unsigned i = 0; i < sizeof(classes) / sizeof(classes[0]); i++) { + classInfo c = classes[i]; + jclass tempClass = env->FindClass(c.name); + if (tempClass == NULL) return; + *c.clazz = (jclass) env->NewGlobalRef(tempClass); + } + + struct methodInfo { + jmethodID *method; + jclass clazz; + const char *name; + const char *signature; + bool isStatic; + } methods[] = { + {&c->i4addr_class_init, c->i4addr_class, "<init>", "([B)V", false}, + {&c->integer_class_init, c->integer_class, "<init>", "(I)V", false}, + {&c->boolean_class_init, c->boolean_class, "<init>", "(Z)V", false}, + {&c->byte_class_init, c->byte_class, "<init>", "(B)V", false}, + {&c->string_class_init, c->string_class, "<init>", "([B)V", false}, + {&c->iaddr_getbyaddress, c->iaddr_class, "getByAddress", + "([B)Ljava/net/InetAddress;", true} + }; + for (unsigned i = 0; i < sizeof(methods) / sizeof(methods[0]); i++) { + methodInfo m = methods[i]; + if (m.isStatic) { + *m.method = env->GetStaticMethodID(m.clazz, m.name, m.signature); + } else { + *m.method = env->GetMethodID(m.clazz, m.name, m.signature); + } + if (*m.method == NULL) return; + } + + struct fieldInfo { + jfieldID *field; + jclass clazz; + const char *name; + const char *type; + } fields[] = { + {&c->iaddr_ipaddress, c->iaddr_class, "ipaddress", "[B"}, + {&c->integer_class_value, c->integer_class, "value", "I"}, + {&c->boolean_class_value, c->boolean_class, "value", "Z"}, + {&c->byte_class_value, c->byte_class, "value", "B"}, + {&c->socketimpl_port, c->socketimpl_class, "port", "I"}, + {&c->socketimpl_address, c->socketimpl_class, "address", + "Ljava/net/InetAddress;"}, + {&c->dpack_address, c->dpack_class, "address", + "Ljava/net/InetAddress;"}, + {&c->dpack_port, c->dpack_class, "port", "I"}, + {&c->dpack_length, c->dpack_class, "length", "I"} + }; + for (unsigned i = 0; i < sizeof(fields) / sizeof(fields[0]); i++) { + fieldInfo f = fields[i]; + *f.field = env->GetFieldID(f.clazz, f.name, f.type); + if (*f.field == NULL) return; } - } /** @@ -1628,8 +1478,10 @@ static void osNetworkSystem_oneTimeInitializationImpl(JNIEnv* env, jobject obj, * * @param fileDescriptor the file descriptor to bind the socket to * @param type the socket type to create, e.g., SOCK_STREAM + * @throws SocketException an error occurred when creating the socket * - * @return the socket file descriptor, or -1 on failure + * @return the socket file descriptor. On failure, an exception is thrown and + * a negative value is returned. * */ static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor, @@ -1648,6 +1500,7 @@ static int createSocketFileDescriptor(JNIEnv* env, jobject fileDescriptor, if (sock < 0) { int err = convertError(errno); throwSocketException(env, err); + return sock; } jniSetFileDescriptorOfFD(env, fileDescriptor, sock); return sock; @@ -3440,88 +3293,6 @@ static void osNetworkSystem_socketCloseImpl(JNIEnv* env, jclass clazz, close(handle); } -static jobject osNetworkSystem_getHostByAddrImpl(JNIEnv* env, jclass clazz, - jbyteArray addrStr) { - // LOGD("ENTER getHostByAddrImpl"); - - if (addrStr == NULL) { - throwNullPointerException(env); - return JNI_FALSE; - } - - jstring address = (jstring)newJavaLangString(env, addrStr); - jstring result; - const char* addr = env->GetStringUTFChars(address, NULL); - - struct hostent* ent = gethostbyaddr(addr, strlen(addr), AF_INET); - - if (ent != NULL && ent->h_name != NULL) { - result = env->NewStringUTF(ent->h_name); - } else { - result = NULL; - } - - env->ReleaseStringUTFChars(address, addr); - - return result; -} - -static jobject osNetworkSystem_getHostByNameImpl(JNIEnv* env, jclass clazz, - jstring nameStr, jboolean preferIPv6Addresses) { - // LOGD("ENTER getHostByNameImpl"); - - if (nameStr == NULL) { - throwNullPointerException(env); - return NULL; - } - - const char* name = env->GetStringUTFChars(nameStr, NULL); - - if (useAdbNetworking) { - - union { - struct in_addr a; - jbyte j[4]; - } outaddr; - - // LOGD("ADB networking: +gethostbyname '%s'", name); - int err; - err = adb_networking_gethostbyname(name, &(outaddr.a)); - - env->ReleaseStringUTFChars(nameStr, name); -#if 0 - LOGD("ADB networking: -gethostbyname err %d addr 0x%08x %u.%u.%u.%u", - err, (unsigned int)outaddr.a.s_addr, - outaddr.j[0],outaddr.j[1], - outaddr.j[2],outaddr.j[3]); -#endif - - if (err < 0) { - return NULL; - } else { - jbyteArray addr = env->NewByteArray(4); - env->SetByteArrayRegion(addr, 0, 4, outaddr.j); - return addr; - } - } else { - - // normal case...no adb networking - struct hostent* ent = gethostbyname(name); - - env->ReleaseStringUTFChars(nameStr, name); - - if (ent != NULL && ent->h_length > 0) { - jbyteArray addr = env->NewByteArray(4); - jbyte v[4]; - memcpy(v, ent->h_addr, 4); - env->SetByteArrayRegion(addr, 0, 4, v); - return addr; - } else { - return NULL; - } - } -} - static void osNetworkSystem_setInetAddressImpl(JNIEnv* env, jobject obj, jobject sender, jbyteArray address) { // LOGD("ENTER setInetAddressImpl"); @@ -3621,8 +3392,10 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { ntohs(local_addr.sin_port)); // new and set remote addr - addr_object = env->NewObject(gCachedFields.iaddr_class, - gCachedFields.iaddr_class_init); + addr_array = env->NewByteArray((jsize)4); + env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address); + addr_object = env->NewObject(gCachedFields.i4addr_class, + gCachedFields.i4addr_class_init, addr_array); if (NULL == addr_object) { goto clean; } @@ -3634,13 +3407,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { if (NULL == socketaddr_object) { goto clean; } - addr_field = env->GetFieldID(socketaddr_class, "addr", - "Ljava/net/InetAddress;"); - env->SetObjectField(socketaddr_object, addr_field, addr_object); - addr_array = env->NewByteArray((jsize)4); - env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address); - env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, - addr_array); // localAddr socketaddr_class = env->FindClass("java/net/InetSocketAddress"); @@ -3650,9 +3416,11 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { socketaddr_field); localAddr_field = env->GetFieldID(channel_class, "localAddress", - "Ljava/net/InetAddress;"); - localAddr_object = env->NewObject(gCachedFields.iaddr_class, - gCachedFields.iaddr_class_init); + "Ljava/net/Inet4Address;"); + addr_array = env->NewByteArray((jsize)4); + env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr); + localAddr_object = env->NewObject(gCachedFields.i4addr_class, + gCachedFields.i4addr_class_init, addr_array); jfieldID socketaddr_field = env->GetFieldID(channel_class, "connectAddress", "Ljava/net/InetSocketAddress;"); jobject socketaddr_object = env->GetObjectField(channel_object, @@ -3662,10 +3430,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { if (NULL == localAddr_object) { goto clean; } - addr_array = env->NewByteArray((jsize)4); - env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, localAddr); - env->SetObjectField(localAddr_object, gCachedFields.iaddr_ipaddress, - addr_array); // set port @@ -3718,10 +3482,13 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { goto clean; } + addr_array = env->NewByteArray((jsize)4); localAddr_field = env->GetFieldID(channel_class, "localAddress", "Ljava/net/InetAddress;"); - localAddr_object = env->NewObject(gCachedFields.iaddr_class, - gCachedFields.iaddr_class_init); + memset(address, 0, 4); + env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address); + localAddr_object = env->NewObject(gCachedFields.i4addr_class, + gCachedFields.i4addr_class_init, addr_array); if (NULL == localAddr_object) { goto clean; } @@ -3768,8 +3535,10 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { env->SetIntField(channel_object, port_field, ntohs(local_addr.sin_port)); // new and set remote addr + addr_array = env->NewByteArray((jsize)4); + env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address); addr_object = env->NewObject(gCachedFields.iaddr_class, - gCachedFields.iaddr_class_init); + gCachedFields.i4addr_class_init, addr_array); if (NULL == addr_object) { goto clean; } @@ -3780,12 +3549,6 @@ static jobject osNetworkSystem_inheritedChannelImpl(JNIEnv* env, jobject obj) { if (NULL == socketaddr_object) { goto clean; } - addr_field = env->GetFieldID(socketaddr_class, "addr", - "Ljava/net/InetAddress;"); - env->SetObjectField(socketaddr_object, addr_field, addr_object); - addr_array = env->NewByteArray((jsize)4); - env->SetByteArrayRegion(addr_array, (jsize)0, (jsize)4, address); - env->SetObjectField(addr_object, gCachedFields.iaddr_ipaddress, addr_array); // set bound if (0 != local_addr.sin_port) { @@ -3845,8 +3608,6 @@ static JNINativeMethod gMethods[] = { { "setSocketOptionImpl", "(Ljava/io/FileDescriptor;ILjava/lang/Object;)V", (void*) osNetworkSystem_setSocketOptionImpl }, { "getSocketFlagsImpl", "()I", (void*) osNetworkSystem_getSocketFlagsImpl }, { "socketCloseImpl", "(Ljava/io/FileDescriptor;)V", (void*) osNetworkSystem_socketCloseImpl }, - { "getHostByAddrImpl", "([B)Ljava/net/InetAddress;", (void*) osNetworkSystem_getHostByAddrImpl }, - { "getHostByNameImpl", "(Ljava/lang/String;Z)Ljava/net/InetAddress;", (void*) osNetworkSystem_getHostByNameImpl }, { "setInetAddressImpl", "(Ljava/net/InetAddress;[B)V", (void*) osNetworkSystem_setInetAddressImpl }, { "inheritedChannelImpl", "()Ljava/nio/channels/Channel;", (void*) osNetworkSystem_inheritedChannelImpl }, }; diff --git a/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java b/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java new file mode 100644 index 0000000..be28d41 --- /dev/null +++ b/luni/src/test/java/org/apache/harmony/luni/platform/AllTests.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package org.apache.harmony.luni.platform; + +import junit.framework.Test; +import junit.framework.TestSuite; +import junit.textui.TestRunner; + +public class AllTests { + public static void run() { + TestRunner.main(new String[] { AllTests.class.getName() }); + } + + public static final Test suite() { + TestSuite suite = tests.TestSuiteFactory.createTestSuite("Tests for org.apache.harmony.luni.platform"); + + suite.addTestSuite(OSMemoryTest.class); + + return suite; + } +} diff --git a/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java b/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java new file mode 100644 index 0000000..a546289 --- /dev/null +++ b/luni/src/test/java/org/apache/harmony/luni/platform/OSMemoryTest.java @@ -0,0 +1,164 @@ +/* + * 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. + */ + +package org.apache.harmony.luni.platform; + +import dalvik.annotation.TestLevel; +import dalvik.annotation.TestTargetNew; +import dalvik.annotation.TestTargetClass; +import dalvik.annotation.AndroidOnly; + +import junit.framework.TestCase; + +/** + * Tests org.apache.harmony.luni.platform.OSMemory (via IMemorySystem). + */ +@TestTargetClass(org.apache.harmony.luni.platform.OSMemory.class) +public class OSMemoryTest extends TestCase { + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "memset", + args = {} + ) + public void testMemset() { + IMemorySystem memory = Platform.getMemorySystem(); + + int byteCount = 32; + int ptr = memory.malloc(byteCount); + try { + // Ensure our newly-allocated block isn't zeroed. + memory.setByte(ptr, (byte) 1); + assertEquals((byte) 1, memory.getByte(ptr)); + // Check that we can clear memory. + memory.memset(ptr, (byte) 0, byteCount); + assertBytesEqual((byte) 0, ptr, byteCount); + // Check that we can set an arbitrary value. + memory.memset(ptr, (byte) 1, byteCount); + assertBytesEqual((byte) 1, ptr, byteCount); + } finally { + memory.free(ptr); + } + } + + void assertBytesEqual(byte value, int ptr, int byteCount) { + IMemorySystem memory = Platform.getMemorySystem(); + for (int i = 0; i < byteCount; ++i) { + assertEquals(value, memory.getByte(ptr + i)); + } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "setIntArray", + args = {} + ) + public void testSetIntArray() { + IMemorySystem memory = Platform.getMemorySystem(); + + int[] values = { 3, 7, 31, 127, 8191, 131071, 524287, 2147483647 }; + int[] swappedValues = new int[values.length]; + for (int i = 0; i < values.length; ++i) { + swappedValues[i] = swapInt(values[i]); + } + + int scale = ICommonDataTypes.SIZEOF_JINT; + int ptr = memory.malloc(scale * values.length); + try { + // Regular copy. Memset first so we start from a known state. + memory.memset(ptr, (byte) 0, scale * values.length); + memory.setIntArray(ptr, values, 0, values.length, false); + assertIntsEqual(values, ptr); + + // Swapped copy. + memory.memset(ptr, (byte) 0, scale * values.length); + memory.setIntArray(ptr, values, 0, values.length, true); + assertIntsEqual(swappedValues, ptr); + + // Swapped copies of slices (to ensure we test non-zero offsets). + memory.memset(ptr, (byte) 0, scale * values.length); + for (int i = 0; i < values.length; ++i) { + memory.setIntArray(ptr + i * scale, values, i, 1, true); + } + assertIntsEqual(swappedValues, ptr); + } finally { + memory.free(ptr); + } + } + + private void assertIntsEqual(int[] expectedValues, int ptr) { + IMemorySystem memory = Platform.getMemorySystem(); + for (int i = 0; i < expectedValues.length; ++i) { + assertEquals(expectedValues[i], memory.getInt(ptr + ICommonDataTypes.SIZEOF_JINT * i)); + } + } + + private static int swapInt(int n) { + return (((n >> 0) & 0xff) << 24) | + (((n >> 8) & 0xff) << 16) | + (((n >> 16) & 0xff) << 8) | + (((n >> 24) & 0xff) << 0); + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "setShortArray", + args = {} + ) + public void testSetShortArray() { + IMemorySystem memory = Platform.getMemorySystem(); + + short[] values = { 0x0001, 0x0020, 0x0300, 0x4000 }; + short[] swappedValues = { 0x0100, 0x2000, 0x0003, 0x0040 }; + + int scale = ICommonDataTypes.SIZEOF_JSHORT; + int ptr = memory.malloc(scale * values.length); + try { + // Regular copy. Memset first so we start from a known state. + memory.memset(ptr, (byte) 0, scale * values.length); + memory.setShortArray(ptr, values, 0, values.length, false); + assertShortsEqual(values, ptr); + + // Swapped copy. + memory.memset(ptr, (byte) 0, scale * values.length); + memory.setShortArray(ptr, values, 0, values.length, true); + assertShortsEqual(swappedValues, ptr); + + // Swapped copies of slices (to ensure we test non-zero offsets). + memory.memset(ptr, (byte) 0, scale * values.length); + for (int i = 0; i < values.length; ++i) { + memory.setShortArray(ptr + i * scale, values, i, 1, true); + } + assertShortsEqual(swappedValues, ptr); + } finally { + memory.free(ptr); + } + } + + private void assertShortsEqual(short[] expectedValues, int ptr) { + IMemorySystem memory = Platform.getMemorySystem(); + for (int i = 0; i < expectedValues.length; ++i) { + assertEquals(expectedValues[i], memory.getShort(ptr + ICommonDataTypes.SIZEOF_JSHORT * i)); + } + } + + private static short swapShort(short n) { + return (short) ((((n >> 0) & 0xff) << 8) | (((n >> 8) & 0xff) << 0)); + } +} diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java index 5c8808c..6087a46 100644 --- a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java +++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/InetAddressTest.java @@ -479,10 +479,6 @@ public class InetAddressTest extends junit.framework.TestCase { } } - static final int TEST_IP_HASHCODE = 2130706433; - static final int TEST_IP6_HASHCODE = -1022939537; - static final int TEST_IP6_LO_HASHCODE = 1353309698; - /** * @tests java.net.InetAddress#hashCode() */ @@ -492,28 +488,25 @@ public class InetAddressTest extends junit.framework.TestCase { method = "hashCode", args = {} ) - void assertHashCode(String literal, int expectedHashCode) { + int getHashCode(String literal) { InetAddress host = null; try { host = InetAddress.getByName(literal); } catch(UnknownHostException e) { fail("Exception during hashCode test : " + e.getMessage()); } - int hashCode = host.hashCode(); - assertEquals("incorrect hashCode for " + host, expectedHashCode, - hashCode); + return host.hashCode(); } public void test_hashCode() { - // Test for method int java.net.InetAddress.hashCode() - // Create InetAddresses from string literals instead of from hostnames - // because we are only testing hashCode, not getByName. That way the - // test does not depend on name resolution and we can test many - // different addresses, not just localhost. - assertHashCode(Support_Configuration.InetTestIP, TEST_IP_HASHCODE); - assertHashCode(Support_Configuration.InetTestIP6, TEST_IP6_HASHCODE); - assertHashCode(Support_Configuration.InetTestIP6LO, - TEST_IP6_LO_HASHCODE); + int hashCode = getHashCode(Support_Configuration.InetTestIP); + int ip6HashCode = getHashCode(Support_Configuration.InetTestIP6); + int ip6LOHashCode = getHashCode(Support_Configuration.InetTestIP6LO); + assertFalse("Hash collision", hashCode == ip6HashCode); + assertFalse("Hash collision", ip6HashCode == ip6LOHashCode); + assertFalse("Hash collision", hashCode == ip6LOHashCode); + assertFalse("Hash collision", ip6LOHashCode == 0); + assertFalse("Hash collision", ip6LOHashCode == 1); } /** diff --git a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java index bcd73d8..68ccb91 100644 --- a/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java +++ b/luni/src/test/java/org/apache/harmony/luni/tests/java/net/URLConnectionTest.java @@ -17,14 +17,11 @@ package org.apache.harmony.luni.tests.java.net; import dalvik.annotation.BrokenTest; -import dalvik.annotation.KnownFailure; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetClass; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; - import junit.framework.TestCase; - import tests.support.Support_Configuration; import tests.support.Support_PortManager; import tests.support.Support_TestWebData; @@ -59,7 +56,6 @@ import java.net.URLConnection; import java.net.URLStreamHandler; import java.net.UnknownServiceException; import java.security.Permission; -import java.text.DateFormat; import java.text.ParseException; import java.util.Arrays; import java.util.Calendar; @@ -463,6 +459,28 @@ public class URLConnectionTest extends TestCase { } } + public void testHttpPostHeaders() throws IOException { + String path = "/" + Math.random(); + HttpURLConnection connection = (HttpURLConnection) + new URL("http://localhost:" + port + path).openConnection(); + + // post a request + connection.setDoOutput(true); + OutputStreamWriter writer + = new OutputStreamWriter(connection.getOutputStream()); + writer.write("hello"); + writer.flush(); + assertEquals(200, connection.getResponseCode()); + + // validate the request by asking the server what was received + Map<String, String> headers = server.pathToRequest().get(path).getHeaders(); + assertEquals("*, */*", headers.get("Accept")); + assertEquals("application/x-www-form-urlencoded", headers.get("Content-Type")); + assertEquals("5", headers.get("Content-Length")); + assertEquals("localhost:" + port, headers.get("Host")); + // TODO: test User-Agent? + } + /** * @throws IOException * @tests {@link java.net.URLConnection#getAllowUserInteraction()} diff --git a/luni/src/test/java/tests/AllTests.java b/luni/src/test/java/tests/AllTests.java index 26e58c1..893cdf0 100644 --- a/luni/src/test/java/tests/AllTests.java +++ b/luni/src/test/java/tests/AllTests.java @@ -54,6 +54,8 @@ public class AllTests suite.addTest(tests.xml.AllTests.suite()); suite.addTest(tests.xnet.AllTests.suite()); + suite.addTest(org.apache.harmony.luni.platform.AllTests.suite()); + return suite; } } diff --git a/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java b/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java index b745662..22e1af7 100644 --- a/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java +++ b/luni/src/test/java/tests/api/java/io/OutputStreamWriterTest.java @@ -17,7 +17,6 @@ package tests.api.java.io; -import dalvik.annotation.KnownFailure; import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; import dalvik.annotation.TestTargetNew; @@ -31,7 +30,6 @@ import java.io.OutputStreamWriter; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; -import java.util.Arrays; import tests.support.Support_OutputStream; @@ -426,7 +424,6 @@ public class OutputStreamWriterTest extends TestCase { clazz = InputStreamReader.class ) }) - @KnownFailure("Error when reading bytes in UTF-8 expected:<8916> but was:<8907> ") public void test_write$C() throws Exception { int upper; InputStreamReader isr = null; @@ -471,7 +468,7 @@ public class OutputStreamWriterTest extends TestCase { j = 0; } assertEquals("Error when reading bytes in " - + MINIMAL_CHARSETS[i], expected++, largeBuffer[j++]); + + MINIMAL_CHARSETS[i] + " at " + j, expected++, largeBuffer[j++]); } } finally { try { @@ -878,5 +875,4 @@ public class OutputStreamWriterTest extends TestCase { fail("UTF-8 not supported"); } } - } diff --git a/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java b/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java index 6bdb55a..e9554dd 100644 --- a/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java +++ b/luni/src/test/java/tests/api/java/lang/reflect/ConstructorTest.java @@ -104,7 +104,11 @@ public class ConstructorTest extends junit.framework.TestCase { public GenericConstructorTestHelper(T t, S s) {} public GenericConstructorTestHelper() throws E{} } - + + static class NoPublicConstructorTestHelper { + // This class has no public constructor. + } + // Used to test synthetic constructor. // // static class Outer { @@ -479,7 +483,6 @@ public class ConstructorTest extends junit.framework.TestCase { } catch (Exception e) { fail("Exception during getGenericExceptionTypes test:" + e.toString()); } - System.out.println(Arrays.toString(types)); assertEquals("Wrong number of exception types returned", 1, types.length); @@ -555,7 +558,35 @@ public class ConstructorTest extends junit.framework.TestCase { .equals( "public tests.api.java.lang.reflect.ConstructorTest$ConstructorTestHelper(java.lang.Object)")); } - + + /** + * @tests java.lang.reflect.Constructor#getConstructor((Class[]) null) + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getConstructor", + args = {} + ) + public void test_getConstructor() throws Exception { + // Passing new Class[0] should be equivalent to (Class[]) null. + Class<ConstructorTestHelper> c2 = ConstructorTestHelper.class; + assertEquals(c2.getConstructor(new Class[0]), c2.getConstructor((Class[]) null)); + assertEquals(c2.getDeclaredConstructor(new Class[0]), + c2.getDeclaredConstructor((Class[]) null)); + + // We can get a non-public constructor via getDeclaredConstructor... + Class<NoPublicConstructorTestHelper> c1 = NoPublicConstructorTestHelper.class; + c1.getDeclaredConstructor((Class[]) null); + // ...but not with getConstructor (which only returns public constructors). + try { + c1.getConstructor((Class[]) null); + fail("Should throw NoSuchMethodException"); + } catch (NoSuchMethodException ex) { + // Expected. + } + } + /** * Sets up the fixture, for example, open a network connection. This method * is called before a test is executed. @@ -570,4 +601,3 @@ public class ConstructorTest extends junit.framework.TestCase { protected void tearDown() { } } - diff --git a/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java b/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java index 884bc8c..506d173 100644 --- a/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java +++ b/luni/src/test/java/tests/api/java/lang/reflect/MethodTest.java @@ -226,7 +226,41 @@ public class MethodTest extends junit.framework.TestCase { } assertTrue("Inherited method returned not-equal", m1.equals(m2)); } - + + /** + * @tests java.lang.Class#getMethod(java.lang.String, java.lang.Class[]) + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getMethod", + args = {java.lang.String.class, java.lang.Class[].class}, + clazz = java.lang.Class.class + ) + public void test_getMethod() throws NoSuchMethodException, SecurityException { + // Check that getMethod treats null parameterTypes the same as an empty array. + Method m1 = TestMethod.class.getMethod("invokeInstanceTest", new Class[0]); + Method m2 = TestMethod.class.getMethod("invokeInstanceTest", (Class[]) null); + assertEquals(m1, m2); + } + + /** + * @tests java.lang.Class#getDeclaredMethod(java.lang.String, java.lang.Class[]) + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "getDeclaredMethod", + args = {java.lang.String.class, java.lang.Class[].class}, + clazz = java.lang.Class.class + ) + public void test_getDeclaredMethod() throws NoSuchMethodException, SecurityException { + // Check that getDeclaredMethod treats null parameterTypes the same as an empty array. + Method m1 = TestMethod.class.getDeclaredMethod("invokeInstanceTest", new Class[0]); + Method m2 = TestMethod.class.getDeclaredMethod("invokeInstanceTest", (Class[]) null); + assertEquals(m1, m2); + } + /** * @tests java.lang.reflect.Method#getDeclaringClass() */ diff --git a/luni/src/test/java/tests/api/java/util/CollectionsTest.java b/luni/src/test/java/tests/api/java/util/CollectionsTest.java index b75898b..2b1b47e 100644 --- a/luni/src/test/java/tests/api/java/util/CollectionsTest.java +++ b/luni/src/test/java/tests/api/java/util/CollectionsTest.java @@ -1435,11 +1435,7 @@ public class CollectionsTest extends junit.framework.TestCase { .indexOfSubList(src, sub2)); } - /** - * @param string2 - * @param string1 - * @param index - */ + private void testwithCharList(int count, String string1, String string2, boolean first) { char[] chars = string1.toCharArray(); @@ -2379,9 +2375,11 @@ public class CollectionsTest extends junit.framework.TestCase { m.put("one", "1"); m.put("two", "2"); Map um = Collections.unmodifiableMap(m); - assertEquals("{one=1, two=2}", um.toString()); + assertTrue("{one=1, two=2}".equals(um.toString()) || + "{two=2, one=1}".equals(um.toString())); } + @TestTargetNew( level = TestLevel.COMPLETE, notes = "", diff --git a/luni/src/test/java/tests/api/java/util/HashMapTest.java b/luni/src/test/java/tests/api/java/util/HashMapTest.java index 1d726ea..af73c0a 100644 --- a/luni/src/test/java/tests/api/java/util/HashMapTest.java +++ b/luni/src/test/java/tests/api/java/util/HashMapTest.java @@ -20,17 +20,9 @@ package tests.api.java.util; import dalvik.annotation.TestTargetNew; import dalvik.annotation.TestTargets; import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetClass; - -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; +import dalvik.annotation.TestTargetClass; + +import java.util.*; import tests.support.Support_MapTest2; import tests.support.Support_UnmodifiableCollectionTest; @@ -39,7 +31,7 @@ import tests.support.Support_UnmodifiableCollectionTest; public class HashMapTest extends junit.framework.TestCase { class MockMap extends AbstractMap { public Set entrySet() { - return null; + return Collections.EMPTY_SET; } public int size(){ return 0; @@ -151,14 +143,10 @@ public class HashMapTest extends junit.framework.TestCase { for (int counter = 0; counter < hmSize; counter++) assertTrue("Failed to construct correct HashMap", hm .get(objArray2[counter]) == hm2.get(objArray2[counter])); - - try { - Map mockMap = new MockMap(); - hm = new HashMap(mockMap); - fail("Should throw NullPointerException"); - } catch (NullPointerException e) { - //empty - } + + Map mockMap = new MockMap(); + hm = new HashMap(mockMap); + assertEquals(hm, mockMap); } /** @@ -296,6 +284,40 @@ public class HashMapTest extends junit.framework.TestCase { } /** + * @tests java.util.HashMap#entrySet() + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "entrySet", + args = {} + ) + public void test_entrySetEquals() { + Set s1 = hm.entrySet(); + Set s2 = new HashMap(hm).entrySet(); + assertEquals(s1, s2); + } + + /** + * @tests java.util.HashMap#entrySet() + */ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "entrySet", + args = {} + ) + public void test_removeFromViews() { + hm.put("A", null); + hm.put("B", null); + assertTrue(hm.keySet().remove("A")); + + Map<String, String> m2 = new HashMap<String, String>(); + m2.put("B", null); + assertTrue(hm.entrySet().remove(m2.entrySet().iterator().next())); + } + + /** * @tests java.util.HashMap#get(java.lang.Object) */ @TestTargetNew( @@ -479,7 +501,39 @@ public class HashMapTest extends junit.framework.TestCase { } catch (NullPointerException e) { // expected. } - } + } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Checks putAll that causes map to resize", + method = "putAll", + args = {java.util.Map.class} + ) + public void test_putAllLjava_util_Map_Resize() { + Random rnd = new Random(666); + + Map<Integer,Integer> m1 = new HashMap<Integer, Integer>(); + int MID = 10000; + for (int i = 0; i < MID; i++) { + Integer j = rnd.nextInt(); + m1.put(j, j); + } + + Map<Integer,Integer> m2 = new HashMap<Integer, Integer>(); + int HI = 30000; + for (int i = MID; i < HI; i++) { + Integer j = rnd.nextInt(); + m2.put(j, j); + } + + m1.putAll(m2); + + rnd = new Random(666); + for (int i = 0; i < HI; i++) { + Integer j = rnd.nextInt(); + assertEquals(j, m1.get(j)); + } + } /** * @tests java.util.HashMap#remove(java.lang.Object) diff --git a/luni/src/test/java/tests/api/java/util/HashtableTest.java b/luni/src/test/java/tests/api/java/util/HashtableTest.java index bbdad50..6c50f1b 100644 --- a/luni/src/test/java/tests/api/java/util/HashtableTest.java +++ b/luni/src/test/java/tests/api/java/util/HashtableTest.java @@ -35,6 +35,7 @@ import java.util.NoSuchElementException; import java.util.Set; import java.util.TreeMap; import java.util.Vector; +import java.util.Collections; import tests.api.java.util.HashMapTest.ReusableKey; import tests.support.Support_MapTest2; @@ -166,6 +167,24 @@ public class HashtableTest extends junit.framework.TestCase { } /** + * @tests java.util.Hashtable#Hashtable(java.util.Map) + */ + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "", + method = "Hashtable", + args = {java.util.Map.class} + ) + public void test_ConversionConstructorNullValue() { + Map<String, Void> map = Collections.singletonMap("Dog", null); + try { + new Hashtable<String, Void>(map); + fail("NullPointerException expected"); + } catch (NullPointerException e) { + //expected + } + } + /** * @tests java.util.Hashtable#clear() */ @TestTargetNew( @@ -310,46 +329,49 @@ public class HashtableTest extends junit.framework.TestCase { assertEquals("All keys not retrieved", 10, ht10.size()); } - /** - * @tests java.util.Hashtable#elements() - */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "elements", - args = {} - ) - public void test_elements_subtest0() { - // this is the reference implementation behavior - final Hashtable ht = new Hashtable(7); - ht.put("1", "a"); - // these three elements hash to the same bucket in a 7 element Hashtable - ht.put("2", "b"); - ht.put("9", "c"); - ht.put("12", "d"); - // Hashtable looks like: - // 0: "1" - // 1: "12" -> "9" -> "2" - Enumeration en = ht.elements(); - // cache the first entry - en.hasMoreElements(); - ht.remove("12"); - ht.remove("9"); - boolean exception = false; - try { - // cached "12" - Object result = en.nextElement(); - assertNull("unexpected: " + result, result); - // next is removed "9" - result = en.nextElement(); - assertNull("unexpected: " + result, result); - result = en.nextElement(); - assertTrue("unexpected: " + result, "b".equals(result)); - } catch (NoSuchElementException e) { - exception = true; - } - assertTrue("unexpected NoSuchElementException", !exception); - } +// BEGIN android-removed +// implementation dependent +// /** +// * @tests java.util.Hashtable#elements() +// */ +// @TestTargetNew( +// level = TestLevel.COMPLETE, +// notes = "", +// method = "elements", +// args = {} +// ) +// public void test_elements_subtest0() { +// // this is the reference implementation behavior +// final Hashtable ht = new Hashtable(7); +// ht.put("1", "a"); +// // these three elements hash to the same bucket in a 7 element Hashtable +// ht.put("2", "b"); +// ht.put("9", "c"); +// ht.put("12", "d"); +// // Hashtable looks like: +// // 0: "1" +// // 1: "12" -> "9" -> "2" +// Enumeration en = ht.elements(); +// // cache the first entry +// en.hasMoreElements(); +// ht.remove("12"); +// ht.remove("9"); +// boolean exception = false; +// try { +// // cached "12" +// Object result = en.nextElement(); +// assertNull("unexpected: " + result, result); +// // next is removed "9" +// result = en.nextElement(); +// assertNull("unexpected: " + result, result); +// result = en.nextElement(); +// assertTrue("unexpected: " + result, "b".equals(result)); +// } catch (NoSuchElementException e) { +// exception = true; +// } +// assertTrue("unexpected NoSuchElementException", !exception); +// } +// END android-removed /** * @tests java.util.Hashtable#entrySet() @@ -371,9 +393,11 @@ public class HashtableTest extends junit.framework.TestCase { while (e.hasMoreElements()) assertTrue("Returned incorrect entry set", s2.contains(e .nextElement())); - - assertEquals("Not synchronized", - "java.util.Collections$SynchronizedSet", s.getClass().getName()); +// BEGIN android-removed +// implementation dependent +// assertEquals("Not synchronized", +// "java.util.Collections$SynchronizedSet", s.getClass().getName()); +// END android-removed boolean exception = false; try { @@ -417,26 +441,28 @@ public class HashtableTest extends junit.framework.TestCase { Hashtable h = hashtableClone(htfull); assertEquals("Could not retrieve element", "FVal 2", ((String) h.get("FKey 2")) ); - - - // Regression for HARMONY-262 - ReusableKey k = new ReusableKey(); - Hashtable h2 = new Hashtable(); - k.setKey(1); - h2.put(k, "value1"); - - k.setKey(13); - assertNull(h2.get(k)); - - k.setKey(12); - assertNull(h2.get(k)); - try { - h2.get(null); - fail("NullPointerException expected"); - } catch (NullPointerException e) { - //expected - } +// BEGIN android-removed +// implementation dependent +// // Regression for HARMONY-262 +// ReusableKey k = new ReusableKey(); +// Hashtable h2 = new Hashtable(); +// k.setKey(1); +// h2.put(k, "value1"); +// +// k.setKey(13); +// assertNull(h2.get(k)); +// +// k.setKey(12); +// assertNull(h2.get(k)); +// +// try { +// h2.get(null); +// fail("NullPointerException expected"); +// } catch (NullPointerException e) { +// //expected +// } +// END android-removed } /** @@ -569,9 +595,12 @@ public class HashtableTest extends junit.framework.TestCase { assertTrue("Returned incorrect key set", s .contains(e.nextElement())); - assertEquals("Not synchronized", - "java.util.Collections$SynchronizedSet", s.getClass().getName()); - +// BEGIN android-removed +// implementation dependent +// assertEquals("Not synchronized", +// "java.util.Collections$SynchronizedSet", s.getClass().getName()); +// END android-removed + Map map = new Hashtable(101); map.put(new Integer(1), "1"); map.put(new Integer(102), "102"); @@ -651,54 +680,57 @@ public class HashtableTest extends junit.framework.TestCase { } } - /** - * @tests java.util.Hashtable#keySet() - */ - @TestTargetNew( - level = TestLevel.PARTIAL_COMPLETE, - notes = "", - method = "keySet", - args = {} - ) - public void test_keySet_subtest1() { - // this is the reference implementation behavior - final Hashtable ht = new Hashtable(7); - ht.put("1", "a"); - // these three elements hash to the same bucket in a 7 element Hashtable - ht.put("2", "b"); - ht.put("9", "c"); - ht.put("12", "d"); - // Hashtable looks like: - // 0: "1" - // 1: "12" -> "9" -> "2" - Enumeration en = ht.elements(); - // cache the first entry - en.hasMoreElements(); - Iterator it = ht.keySet().iterator(); - // this is mostly a copy of the test in test_elements_subtest0() - // test removing with the iterator does not null the values - while (it.hasNext()) { - String key = (String) it.next(); - if ("12".equals(key) || "9".equals(key)) { - it.remove(); - } - } - it.remove(); - boolean exception = false; - try { - // cached "12" - Object result = en.nextElement(); - assertTrue("unexpected: " + result, "d".equals(result)); - // next is removed "9" - result = en.nextElement(); - assertTrue("unexpected: " + result, "c".equals(result)); - result = en.nextElement(); - assertTrue("unexpected: " + result, "b".equals(result)); - } catch (NoSuchElementException e) { - exception = true; - } - assertTrue("unexpected NoSuchElementException", !exception); - } +// BEGIN android-removed +// implementation dependent +// /** +// * @tests java.util.Hashtable#keySet() +// */ +// @TestTargetNew( +// level = TestLevel.PARTIAL_COMPLETE, +// notes = "", +// method = "keySet", +// args = {} +// ) +// public void test_keySet_subtest1() { +// // this is the reference implementation behavior +// final Hashtable ht = new Hashtable(7); +// ht.put("1", "a"); +// // these three elements hash to the same bucket in a 7 element Hashtable +// ht.put("2", "b"); +// ht.put("9", "c"); +// ht.put("12", "d"); +// // Hashtable looks like: +// // 0: "1" +// // 1: "12" -> "9" -> "2" +// Enumeration en = ht.elements(); +// // cache the first entry +// en.hasMoreElements(); +// Iterator it = ht.keySet().iterator(); +// // this is mostly a copy of the test in test_elements_subtest0() +// // test removing with the iterator does not null the values +// while (it.hasNext()) { +// String key = (String) it.next(); +// if ("12".equals(key) || "9".equals(key)) { +// it.remove(); +// } +// } +// it.remove(); +// boolean exception = false; +// try { +// // cached "12" +// Object result = en.nextElement(); +// assertTrue("unexpected: " + result, "d".equals(result)); +// // next is removed "9" +// result = en.nextElement(); +// assertTrue("unexpected: " + result, "c".equals(result)); +// result = en.nextElement(); +// assertTrue("unexpected: " + result, "b".equals(result)); +// } catch (NoSuchElementException e) { +// exception = true; +// } +// assertTrue("unexpected NoSuchElementException", !exception); +// } +// END android-removed /** * @tests java.util.Hashtable#put(java.lang.Object, java.lang.Object) @@ -871,9 +903,12 @@ public class HashtableTest extends junit.framework.TestCase { while (e.hasMoreElements()) assertTrue("Returned incorrect values", c.contains(e.nextElement())); - assertEquals("Not synchronized", - "java.util.Collections$SynchronizedCollection", c.getClass().getName()); - +// BEGIN android-removed +// implementation dependent +// assertEquals("Not synchronized", +// "java.util.Collections$SynchronizedCollection", c.getClass().getName()); +// END android-removed + Hashtable myHashtable = new Hashtable(); for (int i = 0; i < 100; i++) myHashtable.put(new Integer(i), new Integer(i)); diff --git a/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java b/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java index bfa474b..f3d0a7b 100644 --- a/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java +++ b/luni/src/test/java/tests/api/java/util/LinkedHashMapTest.java @@ -209,6 +209,26 @@ public class LinkedHashMapTest extends junit.framework.TestCase { new Integer(0))); } + + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "test that put on an already present key causes entry to move to tail.", + method = "put", + args = {java.lang.Object.class, java.lang.Object.class} + ) + public void test_putPresent() { + Map<String, String> m = new LinkedHashMap<String, String>(8, .75f, true); + m.put("KEY", "VALUE"); + m.put("WOMBAT", "COMBAT"); + m.put("KEY", "VALUE"); + Map.Entry newest = null; + for (Map.Entry<String, String> e : m.entrySet()) { + newest = e; + } + assertEquals("KEY", newest.getKey()); + assertEquals("VALUE", newest.getValue()); + } + /** * @tests java.util.LinkedHashMap#putAll(java.util.Map) */ @@ -275,6 +295,26 @@ public class LinkedHashMapTest extends junit.framework.TestCase { } } + @TestTargetNew( + level = TestLevel.COMPLETE, + notes = "Test that remove removes the entry from the linked list", + method = "entrySet", + args = {} + ) + public void test_entrySetRemove() { + entrySetRemoveHelper("military", "intelligence"); + entrySetRemoveHelper(null, "hypothesis"); + } + private void entrySetRemoveHelper(String key, String value) { + Map<String, String> m1 = new LinkedHashMap<String, String>(); + m1.put(key, value); + m1.put("jumbo", "shrimp"); + LinkedHashMap<String, String> m2 = new LinkedHashMap<String, String>(m1); + Set<Map.Entry<String, String>> s1 = m1.entrySet(); + s1.remove(m2.entrySet().iterator().next()); + assertEquals("jumbo", s1.iterator().next().getKey()); + } + /** * @tests java.util.LinkedHashMap#keySet() */ diff --git a/prefs/src/main/java/java/util/prefs/AbstractPreferences.java b/prefs/src/main/java/java/util/prefs/AbstractPreferences.java index 711cc01..3264569 100644 --- a/prefs/src/main/java/java/util/prefs/AbstractPreferences.java +++ b/prefs/src/main/java/java/util/prefs/AbstractPreferences.java @@ -20,6 +20,7 @@ package java.util.prefs; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; +import java.util.Collection; import java.util.EventListener; import java.util.EventObject; import java.util.HashMap; @@ -27,7 +28,6 @@ import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; -import java.util.StringTokenizer; import java.util.TreeSet; import org.apache.harmony.luni.util.Base64; @@ -38,8 +38,9 @@ import org.apache.harmony.prefs.internal.nls.Messages; * Preferences, which can be used to simplify {@code Preferences} provider's * implementation. This class defines nine abstract SPI methods, which must be * implemented by a preference provider. - * - * @since Android 1.0 + * + * @since 1.4 + * @see Preferences */ public abstract class AbstractPreferences extends Preferences { /* @@ -47,14 +48,9 @@ public abstract class AbstractPreferences extends Preferences { * Class fields * ----------------------------------------------------------- */ - /** - * The unhandled events collection. - */ + /** the unhandled events collection */ private static final List<EventObject> events = new LinkedList<EventObject>(); - - /** - * The event dispatcher thread. - */ + /** the event dispatcher thread */ private static final EventDispatcher dispatcher = new EventDispatcher("Preference Event Dispatcher"); //$NON-NLS-1$ /* @@ -72,11 +68,13 @@ public abstract class AbstractPreferences extends Preferences { Preferences sroot = Preferences.systemRoot(); try { uroot.flush(); - } catch (BackingStoreException e) {//ignore + } catch (BackingStoreException e) { + // ignore } try { sroot.flush(); - } catch (BackingStoreException e) {//ignore + } catch (BackingStoreException e) { + // ignore } } }); @@ -87,9 +85,7 @@ public abstract class AbstractPreferences extends Preferences { * Instance fields (package-private) * ----------------------------------------------------------- */ - /** - * True, if this node is in user preference hierarchy. - */ + /** true if this node is in user preference hierarchy */ boolean userNode; /* @@ -97,16 +93,11 @@ public abstract class AbstractPreferences extends Preferences { * Instance fields (private) * ----------------------------------------------------------- */ - /** - * Marker class for 'lock' field. - */ - private static class Lock { - } + /** Marker class for 'lock' field. */ + private static class Lock {} /** * The object used to lock this node. - * - * @since Android 1.0 */ protected final Object lock; @@ -115,14 +106,10 @@ public abstract class AbstractPreferences extends Preferences { * backing store. This field's default value is false, and it is checked * when the node creation is completed, and if it is true, the node change * event will be fired for this node's parent. - * - * @since Android 1.0 */ protected boolean newNode; - /** - * Cached child nodes - */ + /** cached child nodes */ private Map<String, AbstractPreferences> cachedNode; //the collections of listeners @@ -147,9 +134,9 @@ public abstract class AbstractPreferences extends Preferences { * ----------------------------------------------------------- */ /** - * Constructs a new {@code AbstractPreferences} instance using the given parent node - * and node name. - * + * Constructs a new {@code AbstractPreferences} instance using the given + * parent node and node name. + * * @param parent * the parent node of the new node or {@code null} to indicate * that the new node is a root node. @@ -159,7 +146,6 @@ public abstract class AbstractPreferences extends Preferences { * @throws IllegalArgumentException * if the name contains a slash character or is empty if {@code * parent} is not {@code null}. - * @since Android 1.0 */ protected AbstractPreferences(AbstractPreferences parent, String name) { if ((null == parent ^ name.length() == 0) || name.indexOf("/") >= 0) { //$NON-NLS-1$ @@ -185,7 +171,6 @@ public abstract class AbstractPreferences extends Preferences { * Returns an array of all cached child nodes. * * @return the array of cached child nodes. - * @since Android 1.0 */ protected final AbstractPreferences[] cachedChildren() { return cachedNode.values().toArray(new AbstractPreferences[cachedNode.size()]); @@ -193,9 +178,10 @@ public abstract class AbstractPreferences extends Preferences { /** * Returns the child node with the specified name or {@code null} if it - * doesn't exist. Implementers can assume that the name supplied to this method - * will be a valid node name string (conforming to the node naming format) and - * will not correspond to a node that has been cached or removed. + * doesn't exist. Implementers can assume that the name supplied to this + * method will be a valid node name string (conforming to the node naming + * format) and will not correspond to a node that has been cached or + * removed. * * @param name * the name of the desired child node. @@ -204,7 +190,6 @@ public abstract class AbstractPreferences extends Preferences { * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected AbstractPreferences getChild(String name) throws BackingStoreException { @@ -226,10 +211,9 @@ public abstract class AbstractPreferences extends Preferences { /** * Returns whether this node has been removed by invoking the method {@code * removeNode()}. - * + * * @return {@code true}, if this node has been removed, {@code false} * otherwise. - * @since Android 1.0 */ protected boolean isRemoved() { synchronized (lock) { @@ -240,33 +224,31 @@ public abstract class AbstractPreferences extends Preferences { /** * Flushes changes of this node to the backing store. This method should * only flush this node and should not include the descendant nodes. Any - * implementation that wants to provide functionality to flush all nodes + * implementation that wants to provide functionality to flush all nodes * at once should override the method {@link #flush() flush()}. - * + * * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected abstract void flushSpi() throws BackingStoreException; /** - * Returns the names of all of the child nodes of this node or an empty array if - * this node has no children. The names of cached children are not required to be - * returned. - * + * Returns the names of all of the child nodes of this node or an empty + * array if this node has no children. The names of cached children are not + * required to be returned. + * * @return the names of this node's children. * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected abstract String[] childrenNamesSpi() throws BackingStoreException; /** * Returns the child preference node with the given name, creating it * if it does not exist. The caller of this method should ensure that the - * given name is valid and that this node has not been removed or cached. + * given name is valid and that this node has not been removed or cached. * If the named node has just been removed, the implementation * of this method must create a new one instead of reactivating the removed * one. @@ -278,7 +260,6 @@ public abstract class AbstractPreferences extends Preferences { * @param name * the name of the child preference to be returned. * @return the child preference node. - * @since Android 1.0 */ protected abstract AbstractPreferences childSpi(String name); @@ -287,39 +268,37 @@ public abstract class AbstractPreferences extends Preferences { * Puts the given key-value pair into this node. Caller of this method * should ensure that both of the given values are valid and that this * node has not been removed. - * + * * @param name * the given preference key. * @param value * the given preference value. - * @since Android 1.0 */ protected abstract void putSpi(String name, String value); /** - * Gets the preference value mapped to the given key. The caller of this method - * should ensure that the given key is valid and that this node has not been - * removed. This method should not throw any exceptions but if it does, the - * caller will ignore the exception, regarding it as a {@code null} return value. - * + * Gets the preference value mapped to the given key. The caller of this + * method should ensure that the given key is valid and that this node has + * not been removed. This method should not throw any exceptions but if it + * does, the caller will ignore the exception, regarding it as a {@code + * null} return value. + * * @param key * the given key to be searched for. * @return the preference value mapped to the given key. - * @since Android 1.0 */ protected abstract String getSpi(String key); /** * Returns an array of all preference keys of this node or an empty array if - * no preferences have been found. The caller of this method should ensure that - * this node has not been removed. - * + * no preferences have been found. The caller of this method should ensure + * that this node has not been removed. + * * @return the array of all preference keys. * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected abstract String[] keysSpi() throws BackingStoreException; @@ -329,11 +308,10 @@ public abstract class AbstractPreferences extends Preferences { * method {@link Preferences#removeNode() Preferences.removeNode()} should * invoke this method multiple-times in bottom-up pattern. The removal is * not required to be persisted until after it is flushed. - * + * * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected abstract void removeNodeSpi() throws BackingStoreException; @@ -344,20 +322,18 @@ public abstract class AbstractPreferences extends Preferences { * * @param key * the key of the preference that is to be removed. - * @since Android 1.0 */ protected abstract void removeSpi(String key); /** * Synchronizes this node with the backing store. This method should only * synchronize this node and should not include the descendant nodes. An - * implementation that wants to provide functionality to synchronize all nodes at once should - * override the method {@link #sync() sync()}. + * implementation that wants to provide functionality to synchronize all + * nodes at once should override the method {@link #sync() sync()}. * * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ protected abstract void syncSpi() throws BackingStoreException; @@ -385,7 +361,7 @@ public abstract class AbstractPreferences extends Preferences { for (int i = 0; i < names.length; i++) { result.add(names[i]); } - return result.toArray(new String[0]); + return result.toArray(new String[result.size()]); } } @@ -439,13 +415,13 @@ public abstract class AbstractPreferences extends Preferences { if (key == null) { throw new NullPointerException(); } - String result; + String result = null; synchronized (lock) { checkState(); try { result = getSpi(key); } catch (Exception e) { - result = null; + // ignored } } return (result == null ? deflt : result); @@ -456,9 +432,10 @@ public abstract class AbstractPreferences extends Preferences { String result = get(key, null); if (result == null) { return deflt; - } else if (result.equalsIgnoreCase("true")) { //$NON-NLS-1$ + } + if ("true".equalsIgnoreCase(result)) { //$NON-NLS-1$ return true; - } else if (result.equalsIgnoreCase("false")) { //$NON-NLS-1$ + } else if ("false".equalsIgnoreCase(result)) { //$NON-NLS-1$ return false; } else { return deflt; @@ -474,17 +451,15 @@ public abstract class AbstractPreferences extends Preferences { if (svalue.length() == 0) { return new byte[0]; } - byte[] dres; try { byte[] bavalue = svalue.getBytes("US-ASCII"); //$NON-NLS-1$ if (bavalue.length % 4 != 0) { return deflt; } - dres = Base64.decode(bavalue); + return Base64.decode(bavalue); } catch (Exception e) { - dres = deflt; + return deflt; } - return dres; } @Override @@ -493,13 +468,11 @@ public abstract class AbstractPreferences extends Preferences { if (result == null) { return deflt; } - double dres; try { - dres = Double.parseDouble(result); + return Double.parseDouble(result); } catch (NumberFormatException e) { - dres = deflt; + return deflt; } - return dres; } @Override @@ -508,13 +481,11 @@ public abstract class AbstractPreferences extends Preferences { if (result == null) { return deflt; } - float fres; try { - fres = Float.parseFloat(result); + return Float.parseFloat(result); } catch (NumberFormatException e) { - fres = deflt; + return deflt; } - return fres; } @Override @@ -523,13 +494,11 @@ public abstract class AbstractPreferences extends Preferences { if (result == null) { return deflt; } - int ires; try { - ires = Integer.parseInt(result); + return Integer.parseInt(result); } catch (NumberFormatException e) { - ires = deflt; + return deflt; } - return ires; } @Override @@ -538,13 +507,11 @@ public abstract class AbstractPreferences extends Preferences { if (result == null) { return deflt; } - long lres; try { - lres = Long.parseLong(result); + return Long.parseLong(result); } catch (NumberFormatException e) { - lres = deflt; + return deflt; } - return lres; } @Override @@ -583,42 +550,44 @@ public abstract class AbstractPreferences extends Preferences { startNode = this; } } - Preferences result = null; try { - result = startNode.nodeImpl(name, true); + return startNode.nodeImpl(name, true); } catch (BackingStoreException e) { - //should not happen + // should not happen + return null; } - return result; } private void validateName(String name) { if (name.endsWith("/") && name.length() > 1) { //$NON-NLS-1$ // prefs.6=Name cannot end with '/'\! - throw new IllegalArgumentException(Messages.getString("prefs.6")); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("prefs.6")); //$NON-NLS-1$ } if (name.indexOf("//") >= 0) { //$NON-NLS-1$ // prefs.7=Name cannot contains consecutive '/'\! - throw new IllegalArgumentException( - Messages.getString("prefs.7")); //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("prefs.7")); //$NON-NLS-1$ } } private AbstractPreferences nodeImpl(String path, boolean createNew) throws BackingStoreException { - StringTokenizer st = new StringTokenizer(path, "/"); //$NON-NLS-1$ + String[] names = path.split("/");//$NON-NLS-1$ AbstractPreferences currentNode = this; AbstractPreferences temp = null; - while (st.hasMoreTokens() && null != currentNode) { - String name = st.nextToken(); - synchronized (currentNode.lock) { - temp = currentNode.cachedNode.get(name); - if (temp == null) { - temp = getNodeFromBackend(createNew, currentNode, name); + if (null != currentNode) { + for (int i = 0; i < names.length; i++) { + String name = names[i]; + synchronized (currentNode.lock) { + temp = currentNode.cachedNode.get(name); + if (temp == null) { + temp = getNodeFromBackend(createNew, currentNode, name); + } + } + currentNode = temp; + if (null == currentNode) { + break; } } - - currentNode = temp; } return currentNode; } @@ -626,12 +595,12 @@ public abstract class AbstractPreferences extends Preferences { private AbstractPreferences getNodeFromBackend(boolean createNew, AbstractPreferences currentNode, String name) throws BackingStoreException { - AbstractPreferences temp; if (name.length() > MAX_NAME_LENGTH) { // prefs.8=Name length is too long: {0} - throw new IllegalArgumentException(Messages.getString("prefs.8", //$NON-NLS-1$ + throw new IllegalArgumentException(Messages.getString("prefs.8", //$NON-NLS-1$ name)); } + AbstractPreferences temp; if (createNew) { temp = currentNode.childSpi(name); currentNode.cachedNode.put(name, temp); @@ -646,6 +615,9 @@ public abstract class AbstractPreferences extends Preferences { @Override public boolean nodeExists(String name) throws BackingStoreException { + if (null == name) { + throw new NullPointerException(); + } AbstractPreferences startNode = null; synchronized (lock) { if (isRemoved()) { @@ -771,10 +743,11 @@ public abstract class AbstractPreferences extends Preferences { cachedNode.put(childrenNames[i], child); } } - AbstractPreferences[] children = cachedNode - .values().toArray(new AbstractPreferences[0]); - for (int i = 0; i < children.length; i++) { - children[i].removeNodeImpl(); + + final Collection<AbstractPreferences> values = cachedNode.values(); + final AbstractPreferences[] children = values.toArray(new AbstractPreferences[values.size()]); + for (AbstractPreferences child : children) { + child.removeNodeImpl(); } removeNodeSpi(); isRemoved = true; diff --git a/prefs/src/main/java/java/util/prefs/BackingStoreException.java b/prefs/src/main/java/java/util/prefs/BackingStoreException.java index e8a805c..553d7ab 100644 --- a/prefs/src/main/java/java/util/prefs/BackingStoreException.java +++ b/prefs/src/main/java/java/util/prefs/BackingStoreException.java @@ -17,40 +17,35 @@ package java.util.prefs; - /** * An exception to indicate that an error was encountered while accessing the * backing store. - * - * @since Android 1.0 + * + * @since 1.4 */ public class BackingStoreException extends Exception { - + private static final long serialVersionUID = 859796500401108469L; - + /** - * Constructs a new {@code BackingStoreException} instance with a detailed exception - * message. + * Constructs a new {@code BackingStoreException} instance with a detailed + * exception message. * * @param s * the detailed exception message. - * @since Android 1.0 */ public BackingStoreException (String s) { super(s); } /** - * Constructs a new {@code BackingStoreException} instance with a nested {@code Throwable}. - * + * Constructs a new {@code BackingStoreException} instance with a nested + * {@code Throwable}. + * * @param t * the nested {@code Throwable}. - * @since Android 1.0 */ public BackingStoreException (Throwable t) { super(t); } } - - - diff --git a/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java b/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java index cc68e62..69eaa01 100644 --- a/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java +++ b/prefs/src/main/java/java/util/prefs/FilePreferencesFactoryImpl.java @@ -17,10 +17,10 @@ package java.util.prefs; /** - * The default implementation of <code>PreferencesFactory</code> for the Linux + * The default implementation of <code>PreferencesFactory</code> for the Linux * platform, using the file system as its back end. - * - * @since Android 1.0 + * + * @since 1.4 */ class FilePreferencesFactoryImpl implements PreferencesFactory { // user root preferences diff --git a/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java b/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java index cf85fa0..f6e5e8f 100644 --- a/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java +++ b/prefs/src/main/java/java/util/prefs/FilePreferencesImpl.java @@ -28,12 +28,12 @@ import java.util.Set; import org.apache.harmony.prefs.internal.nls.Messages; /** - * The default implementation of <code>AbstractPreferences</code> for the Linux platform, - * using the file system as its back end. - * + * The default implementation of <code>AbstractPreferences</code> for the Linux + * platform, using the file system as its back end. + * * TODO some sync mechanism with backend, Performance - check file edit date - * - * @since Android 1.0 + * + * @since 1.4 */ class FilePreferencesImpl extends AbstractPreferences { @@ -64,7 +64,6 @@ class FilePreferencesImpl extends AbstractPreferences { SYSTEM_HOME = System.getProperty("java.home") + "/.systemPrefs";//$NON-NLS-1$//$NON-NLS-2$ return null; } - }); } @@ -97,9 +96,9 @@ class FilePreferencesImpl extends AbstractPreferences { * Constructors * -------------------------------------------------------------- */ - + /** - * Construct root <code>FilePreferencesImpl</code> instance, construct + * Construct root <code>FilePreferencesImpl</code> instance, construct * user root if userNode is true, system root otherwise */ FilePreferencesImpl(boolean userNode) { @@ -108,9 +107,9 @@ class FilePreferencesImpl extends AbstractPreferences { path = userNode ? USER_HOME : SYSTEM_HOME; initPrefs(); } - + /** - * Construct a prefs using given parent and given name + * Construct a prefs using given parent and given name */ private FilePreferencesImpl(AbstractPreferences parent, String name) { super(parent, name); @@ -132,16 +131,16 @@ class FilePreferencesImpl extends AbstractPreferences { @Override protected String[] childrenNamesSpi() throws BackingStoreException { String[] names = AccessController - .doPrivileged(new PrivilegedAction<String[]>() { - public String[] run() { - return dir.list(new FilenameFilter() { - public boolean accept(File parent, String name) { - return new File(path + File.separator + name).isDirectory(); - } - }); - + .doPrivileged(new PrivilegedAction<String[]>() { + public String[] run() { + return dir.list(new FilenameFilter() { + public boolean accept(File parent, String name) { + return new File(path + File.separator + name).isDirectory(); } }); + + } + }); if (null == names) {// file is not a directory, exception case // prefs.3=Cannot get children names for {0}! throw new BackingStoreException( @@ -192,14 +191,16 @@ class FilePreferencesImpl extends AbstractPreferences { prefs = XMLParser.loadFilePrefs(prefsFile); } return prefs.getProperty(key); - } catch (Exception e) {// if Exception happened, return null + } catch (Exception e) { + // if Exception happened, return null return null; } } @Override protected String[] keysSpi() throws BackingStoreException { - return prefs.keySet().toArray(new String[0]); + final Set<Object> ks = prefs.keySet(); + return ks.toArray(new String[ks.size()]); } @Override diff --git a/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java b/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java index b31b3a1..ba8940b 100644 --- a/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java +++ b/prefs/src/main/java/java/util/prefs/InvalidPreferencesFormatException.java @@ -21,51 +21,43 @@ package java.util.prefs; * An exception to indicate that the input XML file is not well-formed or could * not be validated against the appropriate document type (specified by * in the {@code Preferences}). - * - * @since Android 1.0 */ public class InvalidPreferencesFormatException extends Exception { - + private static final long serialVersionUID = -791715184232119669L; - + /** - * Constructs a new {@code InvalidPreferencesFormatException} instance with a - * detailed exception message. + * Constructs a new {@code InvalidPreferencesFormatException} instance with + * a detailed exception message. * * @param s * the detailed exception message. - * @since Android 1.0 */ public InvalidPreferencesFormatException (String s) { super(s); } /** - * Constructs a new {@code InvalidPreferencesFormatException} instance with a - * detailed exception message and a nested {@code Throwable}. + * Constructs a new {@code InvalidPreferencesFormatException} instance with + * a detailed exception message and a nested {@code Throwable}. * * @param s * the detailed exception message. * @param t * the nested {@code Throwable}. - * @since Android 1.0 */ public InvalidPreferencesFormatException (String s, Throwable t) { super(s,t); } /** - * Constructs a new {@code InvalidPreferencesFormatException} instance with a nested - * {@code Throwable}. - * + * Constructs a new {@code InvalidPreferencesFormatException} instance with + * a nested {@code Throwable}. + * * @param t * the nested {@code Throwable}. - * @since Android 1.0 */ public InvalidPreferencesFormatException (Throwable t) { super(t); } } - - - diff --git a/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java b/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java index e9824bc..3e23f5a 100644 --- a/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java +++ b/prefs/src/main/java/java/util/prefs/NodeChangeEvent.java @@ -14,7 +14,6 @@ * limitations under the License. */ - package java.util.prefs; import java.io.Serializable; @@ -28,19 +27,22 @@ import java.io.IOException; * This is the event class to indicate that one child of the preference node has * been added or deleted. * <p> - * Please note that the serialization functionality has not yet been implemented, so - * the serialization methods do nothing but throw a {@code NotSerializableException}. - * </p> + * Please note that although the class is marked as {@code Serializable} by + * inheritance from {@code EventObject}, this type is not intended to be serialized + * so the serialization methods do nothing but throw a {@code NotSerializableException}. + * + * @see java.util.prefs.Preferences + * @see java.util.prefs.NodeChangeListener * - * @since Android 1.0 + * @since 1.4 */ public class NodeChangeEvent extends EventObject implements Serializable { - + private static final long serialVersionUID = 8068949086596572957L; - + private final Preferences parent; private final Preferences child; - + /** * Constructs a new {@code NodeChangeEvent} instance. * @@ -49,43 +51,40 @@ public class NodeChangeEvent extends EventObject implements Serializable { * considered as the event source. * @param c * the child {@code Preferences} instance that was added or deleted. - * @since Android 1.0 */ public NodeChangeEvent (Preferences p, Preferences c) { super(p); parent = p; child = c; } - + /** * Gets the {@code Preferences} instance that fired this event. * * @return the {@code Preferences} instance that fired this event. - * @since Android 1.0 */ public Preferences getParent() { return parent; } - + /** * Gets the child {@code Preferences} node that was added or removed. * * @return the added or removed child {@code Preferences} node. - * @since Android 1.0 */ public Preferences getChild() { return child; } - - /* + + /** * This method always throws a <code>NotSerializableException</code>, * because this object cannot be serialized, */ private void writeObject (ObjectOutputStream out) throws IOException { throw new NotSerializableException(); } - - /* + + /** * This method always throws a <code>NotSerializableException</code>, * because this object cannot be serialized, */ @@ -93,7 +92,3 @@ public class NodeChangeEvent extends EventObject implements Serializable { throw new NotSerializableException(); } } - - - - diff --git a/prefs/src/main/java/java/util/prefs/NodeChangeListener.java b/prefs/src/main/java/java/util/prefs/NodeChangeListener.java index f16b206..41da23e 100644 --- a/prefs/src/main/java/java/util/prefs/NodeChangeListener.java +++ b/prefs/src/main/java/java/util/prefs/NodeChangeListener.java @@ -14,41 +14,36 @@ * limitations under the License. */ - package java.util.prefs; import java.util.EventListener; import java.util.prefs.NodeChangeEvent; /** - * This interface is used to handle preference node change events. - * The implementation of this interface can be installed by the {@code Preferences} instance. + * This interface is used to handle preference node change events. The + * implementation of this interface can be installed by the {@code Preferences} + * instance. * + * @see Preferences * @see NodeChangeEvent * - * @since Android 1.0 + * @since 1.4 */ public interface NodeChangeListener extends EventListener { - /** * This method gets called whenever a child node is added to another node. * * @param e * the node change event. - * @since Android 1.0 */ public void childAdded (NodeChangeEvent e); - + /** * This method gets called whenever a child node is removed from another * node. * * @param e * the node change event. - * @since Android 1.0 */ public void childRemoved (NodeChangeEvent e); } - - - diff --git a/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java b/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java index f0f0787..d355f4e 100644 --- a/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java +++ b/prefs/src/main/java/java/util/prefs/PreferenceChangeEvent.java @@ -14,7 +14,6 @@ * limitations under the License. */ - package java.util.prefs; import java.io.IOException; @@ -28,16 +27,19 @@ import java.util.EventObject; * This is the event class to indicate that a preference has been added, deleted * or updated. * <p> - * Please note that the serialization functionality has not yet been implemented, so - * the serialization methods do nothing but throw a {@code NotSerializableException}. - * </p> + * Please note that although the class is marked as {@code Serializable} by + * inheritance from {@code EventObject}, this type is not intended to be serialized + * so the serialization methods do nothing but throw a {@code NotSerializableException}. + * + * @see java.util.prefs.Preferences + * @see java.util.prefs.PreferenceChangeListener * - * @since Android 1.0 + * @since 1.4 */ public class PreferenceChangeEvent extends EventObject implements Serializable { private static final long serialVersionUID = 793724513368024975L; - + private final Preferences node; private final String key; @@ -55,7 +57,6 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { * @param v * the new value of the changed preference, this value can be * {@code null}, which means the preference has been removed. - * @since Android 1.0 */ public PreferenceChangeEvent(Preferences p, String k, String v) { super(p); @@ -68,7 +69,6 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { * Gets the key of the changed preference. * * @return the changed preference's key. - * @since Android 1.0 */ public String getKey() { return key; @@ -78,9 +78,8 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { * Gets the new value of the changed preference or {@code null} if the * preference has been removed. * - * @return the new value of the changed preference or null if the preference - * has been removed. - * @since Android 1.0 + * @return the new value of the changed preference or {@code null} if the + * preference has been removed. */ public String getNewValue() { return value; @@ -90,13 +89,12 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { * Gets the {@code Preferences} instance that fired this event. * * @return the {@code Preferences} instance that fired this event. - * @since Android 1.0 */ public Preferences getNode() { return node; } - /* + /** * This method always throws a <code>NotSerializableException</code>, * because this object cannot be serialized, */ @@ -104,7 +102,7 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { throw new NotSerializableException(); } - /* + /** * This method always throws a <code>NotSerializableException</code>, * because this object cannot be serialized, */ @@ -112,5 +110,3 @@ public class PreferenceChangeEvent extends EventObject implements Serializable { throw new NotSerializableException(); } } - - diff --git a/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java b/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java index 28bb763..97aeced 100644 --- a/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java +++ b/prefs/src/main/java/java/util/prefs/PreferenceChangeListener.java @@ -14,21 +14,23 @@ * limitations under the License. */ - package java.util.prefs; import java.util.EventListener; /** - * This interface is used to handle preferences change events. The implementation of - * this interface can be installed by the {@code Preferences} instance. + * This interface is used to handle preferences change events. The + * implementation of this interface can be installed by the {@code Preferences} + * instance. * + * @see Preferences * @see PreferenceChangeEvent + * * - * @since Android 1.0 + * @since 1.4 */ public interface PreferenceChangeListener extends EventListener { - + /** * This method gets invoked whenever a preference is added, deleted or * updated. @@ -36,10 +38,6 @@ public interface PreferenceChangeListener extends EventListener { * @param pce * the event instance which describes the changed {@code Preferences} * instance and the preference value. - * @since Android 1.0 */ void preferenceChange (PreferenceChangeEvent pce); } - - - diff --git a/prefs/src/main/java/java/util/prefs/Preferences.java b/prefs/src/main/java/java/util/prefs/Preferences.java index 719c89a..8b961e4 100644 --- a/prefs/src/main/java/java/util/prefs/Preferences.java +++ b/prefs/src/main/java/java/util/prefs/Preferences.java @@ -30,89 +30,83 @@ import java.io.OutputStream; import java.net.MalformedURLException; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Locale; import org.apache.harmony.prefs.internal.nls.Messages; /** - * An instance of the class {@code Preferences} represents one node in a preference tree, - * which provides a mechanism to store and access configuration data in a - * hierarchical way. Two hierarchy trees are maintained, one for system - * preferences shared by all users and the other for user preferences + * An instance of the class {@code Preferences} represents one node in a + * preference tree, which provides a mechanism to store and access configuration + * data in a hierarchical way. Two hierarchy trees are maintained, one for + * system preferences shared by all users and the other for user preferences * specific to the user. {@code Preferences} hierarchy trees and data are stored * in an implementation-dependent back-end. * <p> - * Every node has one name and one unique absolute path following the same - * notational conventions as directories in a file system. The root node's - * name is "", and other node name strings cannot contain the slash character - * and cannot be empty. The root node's absolute path is "/", and all other - * nodes' absolute paths are constructed in the standard way: <parent's absolute - * path> + "/" + <node's name>. Since the set of nodes forms a tree with - * the root node at its base, all absolute paths start with the slash character. - * Every node has one relative path to each of its ancestors. The relative path - * doesn't start with slash: it equals the node's absolute path with leading - * substring removed corresponding to the ancestor's absolute path and a slash. - * </p> + * Every node has one name and one unique absolute path following the same + * notational conventions as directories in a file system. The root node's + * name is "", and other node name strings cannot contain the slash character + * and cannot be empty. The root node's absolute path is "/", and all other + * nodes' absolute paths are constructed in the standard way: <parent's + * absolute path> + "/" + <node's name>. Since the set of nodes forms a + * tree with the root node at its base, all absolute paths start with the slash + * character. Every node has one relative path to each of its ancestors. The + * relative path doesn't start with slash: it equals the node's absolute path + * with leading substring removed corresponding to the ancestor's absolute path + * and a slash. * <p> - * Modification to preferences data may be asynchronous, which means that - * preference update method calls may return immediately instead of blocking. - * The {@code flush()} and {@code sync()} methods force the back-end to - * synchronously perform all pending updates, but the implementation is - * permitted to perform the modifications on the underlying back-end data - * at any time between the moment the request is made and the moment the - * {@code flush()} or {@code sync()} method returns. - * Please note that if JVM exit normally, the implementation must assure all - * modifications are persisted implicitly. - * </p> + * Modification to preferences data may be asynchronous, which means that + * preference update method calls may return immediately instead of blocking. + * The {@code flush()} and {@code sync()} methods force the back-end to + * synchronously perform all pending updates, but the implementation is + * permitted to perform the modifications on the underlying back-end data + * at any time between the moment the request is made and the moment the + * {@code flush()} or {@code sync()} method returns. Please note that if the JVM + * exits normally, the implementation must assure all modifications are + * persisted implicitly. * <p> - * When invoking a method that retrieves preferences, the user must provide - * a default value. The default value is returned when the preferences cannot - * be found or the back-end is unavailable. Some other methods will throw + * When invoking a method that retrieves preferences, the user must provide + * a default value. The default value is returned when the preferences cannot + * be found or the back-end is unavailable. Some other methods will throw * {@code BackingStoreException} when the back-end is unavailable. * </p> * <p> - * Preferences can be exported to and imported from an XML files. + * Preferences can be exported to and imported from an XML files. These + * documents must have an XML DOCTYPE declaration: + * <pre>{@code + * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> + * }</pre> + * This system URI is not really accessed by network, it is only a + * identification string. Visit the DTD location to see the actual format + * permitted. * <p> * There must be a concrete {@code PreferencesFactory} type for every concrete - * {@code Preferences} type developed. Every J2SE implementation must provide a default - * implementation for every supported platform, and must also provide a means of - * replacing the default implementation. This implementation uses the system property - * {@code java.util.prefs.PreferencesFactory} to detemine which preferences - * implementation to use. - * </p> + * {@code Preferences} type developed. Every J2SE implementation must provide a + * default implementation for every supported platform, and must also provide a + * means of replacing the default implementation. This implementation uses the + * system property {@code java.util.prefs.PreferencesFactory} to detemine which + * preferences implementation to use. * <p> - * The methods of this class are thread-safe. If multiple JVMs are using the same - * back-end concurrently, the back-end won't be corrupted, but no other + * The methods of this class are thread-safe. If multiple JVMs are using the + * same back-end concurrently, the back-end won't be corrupted, but no other * behavior guarantees are made. - * </p> + * + * @see PreferencesFactory * - * @since Android 1.0 + * @since 1.4 */ public abstract class Preferences { - - /* - * --------------------------------------------------------- - * Class fields - * --------------------------------------------------------- - */ - /** * Maximum size in characters allowed for a preferences key. - * - * @since Android 1.0 */ public static final int MAX_KEY_LENGTH = 80; - + /** * Maximum size in characters allowed for a preferences name. - * - * @since Android 1.0 */ public static final int MAX_NAME_LENGTH = 80; - + /** * Maximum size in characters allowed for a preferences value. - * - * @since Android 1.0 */ public static final int MAX_VALUE_LENGTH = 8192; @@ -137,36 +131,53 @@ public abstract class Preferences { //permission private static final RuntimePermission PREFS_PERM = new RuntimePermission("preferences"); //$NON-NLS-1$ - + //factory used to get user/system prefs root private static final PreferencesFactory factory; - - /** - * --------------------------------------------------------- - * Class initializer - * --------------------------------------------------------- - */ - static{ + + // BEGIN android-removed + // // default provider factory name for Windows + // private static final String DEFAULT_FACTORY_NAME_WIN = "java.util.prefs.RegistryPreferencesFactoryImpl"; //$NON-NLS-1$ + // + // // default provider factory name for Unix + // private static final String DEFAULT_FACTORY_NAME_UNIX = "java.util.prefs.FilePreferencesFactoryImpl"; //$NON-NLS-1$ + // END android-removed + + static { String factoryClassName = AccessController.doPrivileged(new PrivilegedAction<String>() { public String run() { return System.getProperty("java.util.prefs.PreferencesFactory"); //$NON-NLS-1$ } }); // BEGIN android-removed - // if(factoryClassName != null) { - // try { - // ClassLoader loader = Thread.currentThread().getContextClassLoader(); - // if(loader == null){ - // loader = ClassLoader.getSystemClassLoader(); + // // set default provider + // if (factoryClassName == null) { + // String osName = AccessController.doPrivileged(new PrivilegedAction<String>() { + // public String run() { + // return System.getProperty("os.name"); //$NON-NLS-1$ + // } + // }); + // + // // only comparing ASCII, so assume english locale + // osName = (osName == null ? null : osName.toLowerCase(Locale.ENGLISH)); + // + // if (osName != null && osName.startsWith("windows")) { + // factoryClassName = DEFAULT_FACTORY_NAME_WIN; + // } else { + // factoryClassName = DEFAULT_FACTORY_NAME_UNIX; + // } // } - // Class<?> factoryClass = loader.loadClass(factoryClassName); - // factory = (PreferencesFactory) factoryClass.newInstance(); + // try { + // ClassLoader loader = Thread.currentThread().getContextClassLoader(); + // if(loader == null){ + // loader = ClassLoader.getSystemClassLoader(); + // } + // Class<?> factoryClass = loader.loadClass(factoryClassName); + // factory = (PreferencesFactory) factoryClass.newInstance(); // } catch (Exception e) { - // // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1} - // throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$ + // // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1} + // throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$ // } - // } - // END android-removed // BEGIN android-added ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader == null) { @@ -182,10 +193,8 @@ public abstract class Preferences { try { InputStream is = en.nextElement().openStream(); // Read each line for charset provider class names - // BEGIN android-modified reader = new BufferedReader(new InputStreamReader(is, CONFIGURATION_FILE_ENCODING), 8192); - // END android-modified factoryClassName = reader.readLine(); commentIndex = factoryClassName.indexOf(CONFIGURATION_FILE_COMMENT); if (commentIndex > 0) { @@ -215,42 +224,27 @@ public abstract class Preferences { factory = (PreferencesFactory)c.newInstance(); } catch (Exception e) { // prefs.10=Cannot initiate PreferencesFactory: {0}. Caused by {1} - throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$ + throw new InternalError(Messages.getString("prefs.10", factoryClassName, e)); //$NON-NLS-1$ } // END android-added } - - /* - * --------------------------------------------------------- - * Constructors - * --------------------------------------------------------- - */ - + /** * Default constructor, for use by subclasses only. - * - * @since Android 1.0 */ protected Preferences() { super(); } - - /* - * --------------------------------------------------------- - * Methods - * --------------------------------------------------------- - */ - + /** * Gets the absolute path string of this preference node. * * @return the preference node's absolute path string. - * @since Android 1.0 */ public abstract String absolutePath(); - + /** - * Returns the names of all children of this node or an empty string if this + * Returns the names of all children of this node or an empty array if this * node has no children. * * @return the names of all children of this node. @@ -259,10 +253,9 @@ public abstract class Preferences { * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract String[] childrenNames() throws BackingStoreException; - + /** * Removes all preferences of this node. * @@ -271,13 +264,12 @@ public abstract class Preferences { * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract void clear() throws BackingStoreException; - + /** - * Exports all of the preferences of this node to a XML document using the given - * output stream. + * Exports all of the preferences of this node to a XML document using the + * given output stream. * <p> * This XML document uses the UTF-8 encoding and is written according to the * DTD in its DOCTYPE declaration, which is the following: @@ -286,7 +278,8 @@ public abstract class Preferences { * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> * </pre> * - * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i> + * <i>Please note that (unlike the methods of this class that don't concern + * serialization), this call is not thread-safe.</i> * </p> * * @param ostream @@ -298,13 +291,12 @@ public abstract class Preferences { * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void exportNode (OutputStream ostream) throws IOException, BackingStoreException; - + public abstract void exportNode(OutputStream ostream) throws IOException, BackingStoreException; + /** - * Exports all of the preferences of this node and all its descendants to a XML - * document using the given output stream. + * Exports all of the preferences of this node and all its descendants to a + * XML document using the given output stream. * <p> * This XML document uses the UTF-8 encoding and is written according to the * DTD in its DOCTYPE declaration, which is the following: @@ -313,7 +305,8 @@ public abstract class Preferences { * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> * </pre> * - * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i> + * <i>Please note that (unlike the methods of this class that don't concern + * serialization), this call is not thread-safe.</i> * </p> * * @param ostream @@ -325,12 +318,12 @@ public abstract class Preferences { * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void exportSubtree (OutputStream ostream) throws IOException, BackingStoreException; - + public abstract void exportSubtree(OutputStream ostream) throws IOException, + BackingStoreException; + /** - * Forces all pending updates to this node and its descendants to be + * Forces all pending updates to this node and its descendants to be * persisted in the backing store. * <p> * If this node has been removed, the invocation of this method only flushes @@ -340,13 +333,12 @@ public abstract class Preferences { * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ public abstract void flush() throws BackingStoreException; - + /** - * Gets the {@code String} value mapped to the given key or its default value if no - * value is mapped or no backing store is available. + * Gets the {@code String} value mapped to the given key or its default + * value if no value is mapped or no backing store is available. * <p> * Some implementations may store default values in backing stores. In this * case, if there is no value mapped to the given key, the stored default @@ -363,16 +355,16 @@ public abstract class Preferences { * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract String get (String key, String deflt); - + public abstract String get(String key, String deflt); + /** - * Gets the {@code boolean} value mapped to the given key or its default value if no - * value is mapped, if the backing store is unavailable, or if the value is invalid. + * Gets the {@code boolean} value mapped to the given key or its default + * value if no value is mapped, if the backing store is unavailable, or if + * the value is invalid. * <p> - * The only valid values are the {@code String} "true", which represents {@code true} and - * "false", which represents {@code false}, ignoring case. + * The only valid values are the {@code String} "true", which represents + * {@code true} and "false", which represents {@code false}, ignoring case. * </p> * <p> * Some implementations may store default values in backing stores. In this @@ -384,25 +376,24 @@ public abstract class Preferences { * the preference key. * @param deflt * the default value, which will be returned if no value is - * mapped to the given key, if the backing store is unavailable, or if the - * value is invalid. + * mapped to the given key, if the backing store is unavailable, + * or if the value is invalid. * @return the boolean value mapped to the given key. * @throws IllegalStateException * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract boolean getBoolean (String key, boolean deflt); - + public abstract boolean getBoolean(String key, boolean deflt); + /** - * Gets the {@code byte} array value mapped to the given key or its default value if - * no value is mapped, if the backing store is unavailable, or if the value is an - * invalid string. + * Gets the {@code byte} array value mapped to the given key or its default + * value if no value is mapped, if the backing store is unavailable, or if + * the value is an invalid string. * <p> - * To be valid, the value string must be Base64-encoded binary data. The Base64 encoding - * is as defined in <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC - * 2045</a>, section 6.8. + * To be valid, the value string must be Base64-encoded binary data. The + * Base64 encoding is as defined in <a + * href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>, section 6.8. * </p> * <p> * Some implementations may store default values in backing stores. In this @@ -414,25 +405,24 @@ public abstract class Preferences { * the preference key. * @param deflt * the default value, which will be returned if no value is - * mapped to the given key, if the backing store is unavailable, or if the - * value is invalid. + * mapped to the given key, if the backing store is unavailable, + * or if the value is invalid. * @return the byte array value mapped to the given key. * @throws IllegalStateException * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract byte[] getByteArray (String key, byte[] deflt); - + public abstract byte[] getByteArray(String key, byte[] deflt); + /** - * Gets the {@code double} value mapped to the given key or its default value if no - * value is mapped, if the backing store is unavailable, or if the value is an invalid - * string. + * Gets the {@code double} value mapped to the given key or its default + * value if no value is mapped, if the backing store is unavailable, or if + * the value is an invalid string. * <p> - * To be valid, the value string must be a string that can be converted to a {@code double} by - * {@link Double#parseDouble(String) Double.parseDouble(String)}. - * </p> + * To be valid, the value string must be a string that can be converted to a + * {@code double} by {@link Double#parseDouble(String) + * Double.parseDouble(String)}. * <p> * Some implementations may store default values in backing stores. In this * case, if there is no value mapped to the given key, the stored default @@ -450,17 +440,17 @@ public abstract class Preferences { * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract double getDouble (String key, double deflt); - + public abstract double getDouble(String key, double deflt); + /** - * Gets the {@code float} value mapped to the given key or its default value if no - * value is mapped, if the backing store is unavailable, or if the value is an invalid - * string. + * Gets the {@code float} value mapped to the given key or its default value + * if no value is mapped, if the backing store is unavailable, or if the + * value is an invalid string. * <p> - * To be valid, the value string must be a string that can be converted to a {@code float} by - * {@link Float#parseFloat(String) Float.parseFloat(String)}. + * To be valid, the value string must be a string that can be converted to a + * {@code float} by {@link Float#parseFloat(String) + * Float.parseFloat(String)}. * </p> * <p> * Some implementations may store default values in backing stores. In this @@ -479,17 +469,17 @@ public abstract class Preferences { * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract float getFloat (String key, float deflt); - + public abstract float getFloat(String key, float deflt); + /** - * Gets the {@code int} value mapped to the given key or its default value if no - * value is mapped, if the backing store is unavailable, or if the value is an invalid - * string. + * Gets the {@code int} value mapped to the given key or its default value + * if no value is mapped, if the backing store is unavailable, or if the + * value is an invalid string. * <p> - * To be valid, the value string must be a string that can be converted to an {@code int} by - * {@link Integer#parseInt(String) Integer.parseInt(String)}. + * To be valid, the value string must be a string that can be converted to + * an {@code int} by {@link Integer#parseInt(String) + * Integer.parseInt(String)}. * </p> * <p> * Some implementations may store default values in backing stores. In this @@ -501,24 +491,23 @@ public abstract class Preferences { * the preference key. * @param deflt * the default value, which will be returned if no value is - * mapped to the given key, if the backing store is unavailable, or if the - * value is invalid. + * mapped to the given key, if the backing store is unavailable, + * or if the value is invalid. * @return the integer value mapped to the given key. * @throws IllegalStateException * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract int getInt (String key, int deflt); - + public abstract int getInt(String key, int deflt); + /** - * Gets the {@code long} value mapped to the given key or its default value if no - * value is mapped, if the backing store is unavailable, or if the value is an invalid - * string. + * Gets the {@code long} value mapped to the given key or its default value + * if no value is mapped, if the backing store is unavailable, or if the + * value is an invalid string. * <p> - * To be valid, the value string must be a string that can be converted to a {@code long} by - * {@link Long#parseLong(String) Long.parseLong(String)}. + * To be valid, the value string must be a string that can be converted to a + * {@code long} by {@link Long#parseLong(String) Long.parseLong(String)}. * </p> * <p> * Some implementations may store default values in backing stores. In this @@ -530,29 +519,29 @@ public abstract class Preferences { * the preference key. * @param deflt * the default value, which will be returned if no value is - * mapped to the given key, if the backing store is unavailable, or if the - * value is invalid. + * mapped to the given key, if the backing store is unavailable, + * or if the value is invalid. * @return the long value mapped to the given key. * @throws IllegalStateException * if this node has been removed. * @throws NullPointerException * if the parameter {@code key} is {@code null}. - * @since Android 1.0 */ - public abstract long getLong (String key, long deflt); - + public abstract long getLong(String key, long deflt); + /** * Imports all the preferences from an XML document using the given input * stream. * <p> - * This XML document uses the UTF-8 encoding and must be written according to the - * DTD in its DOCTYPE declaration, which must be the following: + * This XML document uses the UTF-8 encoding and must be written according + * to the DTD in its DOCTYPE declaration, which must be the following: * * <pre> * <!DOCTYPE preferences SYSTEM "http://java.sun.com/dtd/preferences.dtd"> * </pre> * - * <i>Please note that (unlike the methods of this class that don't concern serialization), this call is not thread-safe.</i> + * <i>Please note that (unlike the methods of this class that don't concern + * serialization), this call is not thread-safe.</i> * </p> * * @param istream @@ -565,7 +554,6 @@ public abstract class Preferences { * @throws SecurityException * if {@code RuntimePermission("preferences")} is denied by a * SecurityManager. - * @since Android 1.0 */ public static void importPreferences (InputStream istream) throws InvalidPreferencesFormatException, IOException { checkSecurity(); @@ -575,16 +563,15 @@ public abstract class Preferences { } XMLParser.importPrefs(istream); } - + /** * Returns whether this is a user preference node. * * @return {@code true}, if this is a user preference node, {@code false} if * this is a system preference node. - * @since Android 1.0 */ public abstract boolean isUserNode(); - + /** * Returns all preference keys stored in this node or an empty array if no * key was found. @@ -595,18 +582,16 @@ public abstract class Preferences { * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract String[] keys() throws BackingStoreException; - + /** * Returns the name of this node. * * @return the name of this node. - * @since Android 1.0 */ public abstract String name(); - + /** * Returns the preference node with the given path name. The path name can * be relative or absolute. The requested node and its ancestors will @@ -625,10 +610,9 @@ public abstract class Preferences { * if the path name is invalid. * @throws NullPointerException * if the given path is {@code null}. - * @since Android 1.0 */ - public abstract Preferences node (String path); - + public abstract Preferences node(String path); + /** * Returns whether the preference node with the given path name exists. The * path is treated as relative to this node if it doesn't start with a slash, @@ -653,10 +637,9 @@ public abstract class Preferences { * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. - * @since Android 1.0 */ - public abstract boolean nodeExists (String path) throws BackingStoreException; - + public abstract boolean nodeExists(String path) throws BackingStoreException; + /** * Returns the parent preference node of this node or {@code null} if this * node is the root node. @@ -664,10 +647,9 @@ public abstract class Preferences { * @return the parent preference node of this node. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract Preferences parent(); - + /** * Adds a new preference to this node using the given key and value or * updates the value if a preference with the given key already exists. @@ -684,14 +666,13 @@ public abstract class Preferences { * MAX_VALUE_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void put (String key, String value); - + public abstract void put(String key, String value); + /** - * Adds a new preference with a {@code boolean} value to this node using the given - * key and value or updates the value if a preference with the given key - * already exists. + * Adds a new preference with a {@code boolean} value to this node using the + * given key and value or updates the value if a preference with the given + * key already exists. * * @param key * the preference key to be added or updated. @@ -704,10 +685,9 @@ public abstract class Preferences { * MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putBoolean (String key, boolean value); - + public abstract void putBoolean(String key, boolean value); + /** * Adds a new preference to this node using the given key and the string * form of the given value or updates the value if a preference with the @@ -730,10 +710,9 @@ public abstract class Preferences { * quarters of {@code MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putByteArray (String key, byte[] value); - + public abstract void putByteArray(String key, byte[] value); + /** * Adds a new preference to this node using the given key and {@code double} * value or updates the value if a preference with the @@ -754,12 +733,11 @@ public abstract class Preferences { * MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putDouble (String key, double value); - + public abstract void putDouble(String key, double value); + /** - * Adds a new preference to this node using the given key and {@code float} + * Adds a new preference to this node using the given key and {@code float} * value or updates the value if a preference with the * given key already exists. * <p> @@ -778,12 +756,11 @@ public abstract class Preferences { * MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putFloat (String key, float value); - + public abstract void putFloat(String key, float value); + /** - * Adds a new preference to this node using the given key and {@code int} + * Adds a new preference to this node using the given key and {@code int} * value or updates the value if a preference with the * given key already exists. * <p> @@ -802,12 +779,11 @@ public abstract class Preferences { * MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putInt (String key, int value); - + public abstract void putInt(String key, int value); + /** - * Adds a new preference to this node using the given key and {@code long} + * Adds a new preference to this node using the given key and {@code long} * value or updates the value if a preference with the * given key already exists. * <p> @@ -826,9 +802,8 @@ public abstract class Preferences { * MAX_KEY_LENGTH}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void putLong (String key, long value); + public abstract void putLong(String key, long value); /** * Removes the preference mapped to the given key from this node. @@ -839,13 +814,12 @@ public abstract class Preferences { * if the given key is {@code null}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void remove (String key); - + public abstract void remove(String key); + /** - * Removes this preference node with all its descendants. The removal - * won't necessarily be persisted until the method {@code flush()} is invoked. + * Removes this preference node with all its descendants. The removal won't + * necessarily be persisted until the method {@code flush()} is invoked. * * @throws BackingStoreException * if the backing store is unavailable or causes an operation @@ -854,14 +828,13 @@ public abstract class Preferences { * if this node has been removed. * @throws UnsupportedOperationException * if this is a root node. - * @since Android 1.0 */ public abstract void removeNode() throws BackingStoreException; - + /** - * Registers a {@code NodeChangeListener} instance for this node, which will handle - * {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired when a child node has - * been added to or removed from this node. + * Registers a {@code NodeChangeListener} instance for this node, which will + * handle {@code NodeChangeEvent}s. {@code NodeChangeEvent}s will be fired + * when a child node has been added to or removed from this node. * * @param ncl * the listener to be registered. @@ -869,25 +842,24 @@ public abstract class Preferences { * if the given listener is {@code null}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ - public abstract void addNodeChangeListener (NodeChangeListener ncl); - + public abstract void addNodeChangeListener(NodeChangeListener ncl); + /** - * Registers a {@code PreferenceChangeListener} instance for this node, which will - * handle {@code PreferenceChangeEvent}s. {@code PreferenceChangeEvent}s will be fired when - * a preference has been added to, removed from, or updated for this node. - * + * Registers a {@code PreferenceChangeListener} instance for this node, + * which will handle {@code PreferenceChangeEvent}s. {@code + * PreferenceChangeEvent}s will be fired when a preference has been added + * to, removed from, or updated for this node. + * * @param pcl * the listener to be registered. * @throws NullPointerException * if the given listener is {@code null}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract void addPreferenceChangeListener (PreferenceChangeListener pcl); - + /** * Removes the given {@code NodeChangeListener} instance from this node. * @@ -897,12 +869,12 @@ public abstract class Preferences { * if the given listener is {@code null}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract void removeNodeChangeListener (NodeChangeListener ncl); - + /** - * Removes the given {@code PreferenceChangeListener} instance from this node. + * Removes the given {@code PreferenceChangeListener} instance from this + * node. * * @param pcl * the listener to be removed. @@ -910,36 +882,34 @@ public abstract class Preferences { * if the given listener is {@code null}. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract void removePreferenceChangeListener (PreferenceChangeListener pcl); - + /** * Synchronizes the data of this preference node and its descendants with - * the back-end preference store. Any changes found in the back-end data should be reflected - * in this node and its descendants, and at the same time any local changes to this node and - * descendants should be persisted. + * the back-end preference store. Any changes found in the back-end data + * should be reflected in this node and its descendants, and at the same + * time any local changes to this node and descendants should be persisted. * * @throws BackingStoreException * if the backing store is unavailable or causes an operation * failure. * @throws IllegalStateException * if this node has been removed. - * @since Android 1.0 */ public abstract void sync() throws BackingStoreException; - + /** * Returns the system preference node for the package of the given class. * The absolute path of the returned node is one slash followed by the given * class's full package name, replacing each period character ('.') with - * a slash. For example, the absolute path of the preference associated with + * a slash. For example, the absolute path of the preference associated with * the class Object would be "/java/lang". As a special case, the unnamed * package is associated with a preference node "/<unnamed>". This * method will create the node and its ancestors as needed. Any nodes created - * by this method won't necessarily be persisted until the method {@code flush()} is - * invoked. - * + * by this method won't necessarily be persisted until the method {@code + * flush()} is invoked. + * * @param c * the given class. * @return the system preference node for the package of the given class. @@ -948,13 +918,12 @@ public abstract class Preferences { * @throws SecurityException * if the {@code RuntimePermission("preferences")} is denied by * a SecurityManager. - * @since Android 1.0 */ public static Preferences systemNodeForPackage (Class<?> c) { checkSecurity(); return factory.systemRoot().node(getNodeName(c)); } - + /** * Returns the root node of the system preference hierarchy. * @@ -962,33 +931,32 @@ public abstract class Preferences { * @throws SecurityException * if the {@code RuntimePermission("preferences")} is denied by * a SecurityManager. - * @since Android 1.0 */ public static Preferences systemRoot() { checkSecurity(); return factory.systemRoot(); } - + //check the RuntimePermission("preferences") private static void checkSecurity() { SecurityManager manager = System.getSecurityManager(); if(null != manager){ manager.checkPermission(PREFS_PERM); } - + } /** * Returns the user preference node for the package of the given class. * The absolute path of the returned node is one slash followed by the given * class's full package name, replacing each period character ('.') with - * a slash. For example, the absolute path of the preference associated with + * a slash. For example, the absolute path of the preference associated with * the class Object would be "/java/lang". As a special case, the unnamed * package is associated with a preference node "/<unnamed>". This * method will create the node and its ancestors as needed. Any nodes created - * by this method won't necessarily be persisted until the method {@code flush()} is - * invoked. - * + * by this method won't necessarily be persisted until the method {@code + * flush()} is invoked. + * * @param c * the given class. * @return the user preference node for the package of the given class. @@ -997,13 +965,12 @@ public abstract class Preferences { * @throws SecurityException * if the {@code RuntimePermission("preferences")} is denied by * a SecurityManager. - * @since Android 1.0 */ public static Preferences userNodeForPackage (Class<?> c) { checkSecurity(); return factory.userRoot().node(getNodeName(c)); } - + //parse node's absolute path from class instance private static String getNodeName(Class<?> c){ Package p = c.getPackage(); @@ -1020,7 +987,6 @@ public abstract class Preferences { * @throws SecurityException * if the {@code RuntimePermission("preferences")} is denied by * a SecurityManager. - * @since Android 1.0 */ public static Preferences userRoot() { checkSecurity(); @@ -1032,7 +998,6 @@ public abstract class Preferences { * Preference Node: " followed by this node's absolute path. * * @return the string representation of this node. - * @since Android 1.0 */ @Override public abstract String toString(); diff --git a/prefs/src/main/java/java/util/prefs/PreferencesFactory.java b/prefs/src/main/java/java/util/prefs/PreferencesFactory.java index e56dd95..3ac13e4 100644 --- a/prefs/src/main/java/java/util/prefs/PreferencesFactory.java +++ b/prefs/src/main/java/java/util/prefs/PreferencesFactory.java @@ -14,36 +14,30 @@ * limitations under the License. */ - package java.util.prefs; /** * This interface is used by the {@link Preferences} class as factory class to - * create {@code Preferences} instances. This interface can be implemented and installed - * to replace the default preferences implementation. + * create {@code Preferences} instances. This interface can be implemented and + * installed to replace the default preferences implementation. + * + * @see java.util.prefs.Preferences * - * @since Android 1.0 + * @since 1.4 */ public interface PreferencesFactory { - /** * Returns the root node of the preferences hierarchy for the calling user * context. * * @return the user preferences hierarchy root node. - * @since Android 1.0 */ Preferences userRoot(); - + /** * Returns the root node of the system preferences hierarchy. * * @return the system preferences hierarchy root node. - * @since Android 1.0 */ Preferences systemRoot(); } - - - - diff --git a/prefs/src/main/java/java/util/prefs/XMLParser.java b/prefs/src/main/java/java/util/prefs/XMLParser.java index 2edfc71..c5a234c 100644 --- a/prefs/src/main/java/java/util/prefs/XMLParser.java +++ b/prefs/src/main/java/java/util/prefs/XMLParser.java @@ -14,7 +14,6 @@ * limitations under the License. */ - package java.util.prefs; import java.io.BufferedInputStream; @@ -27,6 +26,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.StringReader; +import java.io.Writer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.security.AccessController; @@ -64,9 +64,7 @@ import org.w3c.dom.Node; // END android-added /** - * Utility class for importing and exporting {@code Preferences} data from an XML file. - * - * @since Android 1.0 + * Utility class for the Preferences import/export from XML file. */ class XMLParser { @@ -79,15 +77,15 @@ class XMLParser { * Constant - the DTD string */ static final String PREFS_DTD = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" //$NON-NLS-1$ - + " <!ELEMENT preferences (root)>" //$NON-NLS-1$ - + " <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA \"0.0\" >" //$NON-NLS-1$ - + " <!ELEMENT root (map, node*) >" //$NON-NLS-1$ - + " <!ATTLIST root type (system|user) #REQUIRED >" //$NON-NLS-1$ - + " <!ELEMENT node (map, node*) >" //$NON-NLS-1$ - + " <!ATTLIST node name CDATA #REQUIRED >" //$NON-NLS-1$ - + " <!ELEMENT map (entry*) >" //$NON-NLS-1$ - + " <!ELEMENT entry EMPTY >" //$NON-NLS-1$ - + " <!ATTLIST entry key CDATA #REQUIRED value CDATA #REQUIRED >"; //$NON-NLS-1$ + + " <!ELEMENT preferences (root)>" //$NON-NLS-1$ + + " <!ATTLIST preferences EXTERNAL_XML_VERSION CDATA \"0.0\" >" //$NON-NLS-1$ + + " <!ELEMENT root (map, node*) >" //$NON-NLS-1$ + + " <!ATTLIST root type (system|user) #REQUIRED >" //$NON-NLS-1$ + + " <!ELEMENT node (map, node*) >" //$NON-NLS-1$ + + " <!ATTLIST node name CDATA #REQUIRED >" //$NON-NLS-1$ + + " <!ELEMENT map (entry*) >" //$NON-NLS-1$ + + " <!ELEMENT entry EMPTY >" //$NON-NLS-1$ + + " <!ATTLIST entry key CDATA #REQUIRED value CDATA #REQUIRED >"; //$NON-NLS-1$ /* * Constant - the specified header @@ -103,24 +101,24 @@ class XMLParser { * empty string array constant */ private static final String[] EMPTY_SARRAY = new String[0]; - + /* - * Constant - used by FilePreferencesImpl, which is default implementation of Linux platform + * Constant - used by FilePreferencesImpl, which is default implementation of Linux platform */ private static final String FILE_PREFS = "<!DOCTYPE map SYSTEM 'http://java.sun.com/dtd/preferences.dtd'>"; //$NON-NLS-1$ /* * Constant - specify the DTD version */ - private static final float XML_VERSION = 1.0f; - + private static final float XML_VERSION = 1.0f; + /* * DOM builder */ private static final DocumentBuilder builder; /* - * specify the indent level + * specify the indent level */ private static int indent = -1; @@ -139,7 +137,7 @@ class XMLParser { } builder.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) - throws SAXException, IOException { + throws SAXException, IOException { if (systemId.equals(PREFS_DTD_NAME)) { InputSource result = new InputSource(new StringReader( PREFS_DTD)); @@ -196,7 +194,7 @@ class XMLParser { flushEmptyElement("map", out); //$NON-NLS-1$ StringTokenizer ancestors = new StringTokenizer(prefs.absolutePath(), - "/"); //$NON-NLS-1$ + "/"); //$NON-NLS-1$ exportNode(ancestors, prefs, withSubTree, out); flushEndTag("root", out); //$NON-NLS-1$ @@ -207,7 +205,7 @@ class XMLParser { private static void exportNode(StringTokenizer ancestors, Preferences prefs, boolean withSubTree, BufferedWriter out) - throws IOException, BackingStoreException { + throws IOException, BackingStoreException { if (ancestors.hasMoreTokens()) { String name = ancestors.nextToken(); flushStartTag( @@ -226,7 +224,7 @@ class XMLParser { } private static void exportSubTree(Preferences prefs, BufferedWriter out) - throws BackingStoreException, IOException { + throws BackingStoreException, IOException { String[] names = prefs.childrenNames(); if (names.length > 0) { for (int i = 0; i < names.length; i++) { @@ -241,7 +239,7 @@ class XMLParser { } private static void exportEntries(Preferences prefs, BufferedWriter out) - throws BackingStoreException, IOException { + throws BackingStoreException, IOException { String[] keys = prefs.keys(); String[] values = new String[keys.length]; for (int i = 0; i < keys.length; i++) { @@ -267,7 +265,7 @@ class XMLParser { } private static void flushEndTag(String tagName, BufferedWriter out) - throws IOException { + throws IOException { flushIndent(indent--, out); out.write("</"); //$NON-NLS-1$ out.write(tagName); @@ -276,7 +274,7 @@ class XMLParser { } private static void flushEmptyElement(String tagName, BufferedWriter out) - throws IOException { + throws IOException { flushIndent(++indent, out); out.write("<"); //$NON-NLS-1$ out.write(tagName); @@ -308,7 +306,7 @@ class XMLParser { } private static void flushIndent(int ind, BufferedWriter out) - throws IOException { + throws IOException { for (int i = 0; i < ind; i++) { out.write(" "); //$NON-NLS-1$ } @@ -325,7 +323,7 @@ class XMLParser { } private static void flushStartTag(String tagName, BufferedWriter out) - throws IOException { + throws IOException { flushIndent(++indent, out); out.write("<"); //$NON-NLS-1$ out.write(tagName); @@ -365,7 +363,7 @@ class XMLParser { * utilities for Preferences import **************************************************************************/ static void importPrefs(InputStream in) throws IOException, - InvalidPreferencesFormatException { + InvalidPreferencesFormatException { try { // load XML document Document doc = builder.parse(new InputSource(in)); @@ -382,7 +380,7 @@ class XMLParser { // check preferences root's type Element root = (Element) preferences - .getElementsByTagName("root").item(0); //$NON-NLS-1$ + .getElementsByTagName("root").item(0); //$NON-NLS-1$ Preferences prefsRoot = null; String type = root.getAttribute("type"); //$NON-NLS-1$ if (type.equals("user")) { //$NON-NLS-1$ @@ -445,15 +443,15 @@ class XMLParser { // TODO dirty implementation of a method from javax.xml.xpath // should be replaced with a call to a good impl of this method private static NodeList selectNodeList(Element documentElement, String string) { - + NodeList result = null; - + ArrayList<Node> input = new ArrayList<Node>(); - + String[] path = string.split("/"); - + NodeList childNodes = documentElement.getChildNodes(); - + if(path[0].equals("entry") || path[0].equals("node")) { for(int i = 0; i < childNodes.getLength(); i++) { Object next = childNodes.item(i); @@ -483,21 +481,21 @@ class XMLParser { } } } - + result = new NodeSet(input.iterator()); - + return result; } // END android-added - + /*************************************************************************** * utilities for FilePreferencesImpl, which is default implementation of Linux platform **************************************************************************/ /** * load preferences from file, if cannot load, create a new one FIXME: need * lock or not? - * - * @param file the XML file to be read + * + * @param file the XML file to be read * @return Properties instance which indicates the preferences key-value pairs */ static Properties loadFilePrefs(final File file) { @@ -506,14 +504,6 @@ class XMLParser { return loadFilePrefsImpl(file); } }); - - // try { - // //FIXME: lines below can be deleted, because it is not required to - // persistent at the very beginning - // flushFilePrefs(file, result); - // } catch (IOException e) { - // e.printStackTrace(); - // } } static Properties loadFilePrefsImpl(final File file) { @@ -524,7 +514,6 @@ class XMLParser { InputStream in = null; FileLock lock = null; try { - FileInputStream istream = new FileInputStream(file); // BEGIN android-modified in = new BufferedInputStream(istream, 8192); @@ -544,17 +533,16 @@ class XMLParser { result.setProperty(key, value); } return result; - } catch (Exception e) { - e.printStackTrace(); + } catch (IOException e) { + } catch (SAXException e) { + // BEGIN android-removed + // } catch (TransformerException e) { + // // transform shouldn't fail for xpath call + // throw new AssertionError(e); + // END android-removed } finally { - try { - lock.release(); - } catch (Exception e) {//ignore - } - try { - in.close(); - } catch (Exception e) {//ignore - } + releaseQuietly(lock); + closeQuietly(in); } } else { file.delete(); @@ -563,7 +551,7 @@ class XMLParser { } /** - * + * * @param file * @param prefs * @throws PrivilegedActionException @@ -576,7 +564,7 @@ class XMLParser { } }); } - + static void flushFilePrefsImpl(File file, Properties prefs) throws IOException { BufferedWriter out = null; FileLock lock = null; @@ -604,18 +592,35 @@ class XMLParser { } out.flush(); } finally { - try { - lock.release(); - } catch (Exception e) {//ignore - } - try { - if (null != out) { - out.close(); - } - } catch (Exception e) {//ignore - } + releaseQuietly(lock); + closeQuietly(out); } } -} + private static void releaseQuietly(FileLock lock) { + if (lock == null) { + return; + } + try { + lock.release(); + } catch (IOException e) {} + } + private static void closeQuietly(Writer out) { + if (out == null) { + return; + } + try { + out.close(); + } catch (IOException e) {} + } + + private static void closeQuietly(InputStream in) { + if (in == null) { + return; + } + try { + in.close(); + } catch (IOException e) {} + } +} diff --git a/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java index cfc7236..aaf5d8d 100644 --- a/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java +++ b/prefs/src/main/java/org/apache/harmony/prefs/internal/nls/Messages.java @@ -43,7 +43,7 @@ import org.apache.harmony.luni.util.MsgHelp; * is looked up, or resource bundle support is not available, the key itself * will be returned as the associated message. This means that the <em>KEY</em> * should a reasonable human-readable (english) string. - * + * */ public class Messages { @@ -54,7 +54,7 @@ public class Messages { /** * Retrieves a message which has no arguments. - * + * * @param msg * String the key to look up. * @return String the message for that key in the system message bundle. @@ -67,7 +67,7 @@ public class Messages { /** * Retrieves a message which takes 1 argument. - * + * * @param msg * String the key to look up. * @param arg @@ -80,7 +80,7 @@ public class Messages { /** * Retrieves a message which takes 1 integer argument. - * + * * @param msg * String the key to look up. * @param arg @@ -93,7 +93,7 @@ public class Messages { /** * Retrieves a message which takes 1 character argument. - * + * * @param msg * String the key to look up. * @param arg @@ -106,7 +106,7 @@ public class Messages { /** * Retrieves a message which takes 2 arguments. - * + * * @param msg * String the key to look up. * @param arg1 @@ -121,7 +121,7 @@ public class Messages { /** * Retrieves a message which takes several arguments. - * + * * @param msg * String the key to look up. * @param args diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java index 418e52d..76ef4e7 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/AbstractPreferencesTest.java @@ -35,9 +35,13 @@ import java.util.prefs.PreferenceChangeEvent; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; +import tests.util.PrefsTester; + @TestTargetClass(AbstractPreferences.class) public class AbstractPreferencesTest extends TestCase { + private final PrefsTester prefsTester = new PrefsTester(); + AbstractPreferences pref; static AbstractPreferences root; @@ -51,13 +55,8 @@ public class AbstractPreferencesTest extends TestCase { protected void setUp() throws Exception { super.setUp(); + prefsTester.setUp(); - System.setProperty("user.home", System.getProperty("java.io.tmpdir")); - System.setProperty("java.home", System.getProperty("java.io.tmpdir")); - - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - root = (AbstractPreferences) Preferences.userRoot(); parent = (AbstractPreferences) Preferences.userNodeForPackage(this.getClass()); @@ -65,11 +64,7 @@ public class AbstractPreferencesTest extends TestCase { } protected void tearDown() throws Exception { - parent.removeNode(); - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - System.setProperty("user.home", oldUserHome); - System.setProperty("java.home", oldJavaHome); + prefsTester.tearDown(); super.tearDown(); } @@ -855,6 +850,31 @@ public class AbstractPreferencesTest extends TestCase { } @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "", + method = "nodeExists", + args = {String.class} + ) + public void test_nodeExists() throws BackingStoreException { + AbstractPreferences test = (AbstractPreferences) Preferences.userRoot() + .node("test"); + try { + test.nodeExists(null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // Expected + } + + test.removeNode(); + try { + test.nodeExists(null); + fail("should throw NullPointerException"); + } catch (NullPointerException e) { + // Expected + } + } + + @TestTargetNew( level = TestLevel.COMPLETE, notes = "", method = "parent", diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java index 0c61e75..0cb1975 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/FilePreferencesImplTest.java @@ -28,28 +28,22 @@ import java.util.prefs.BackingStoreException; import java.util.prefs.Preferences; import junit.framework.TestCase; +import tests.util.PrefsTester; @TestTargetClass(java.util.prefs.Preferences.class) public class FilePreferencesImplTest extends TestCase { - String oldUserHome = System.getProperty("user.home"); - String oldJavaHome = System.getProperty("java.home"); + private final PrefsTester prefsTester = new PrefsTester(); + @Override protected void setUp() throws Exception { super.setUp(); - - System.setProperty("user.home", System.getProperty("java.io.tmpdir")); - System.setProperty("java.home", System.getProperty("java.io.tmpdir")); - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); + prefsTester.setUp(); } + @Override protected void tearDown() throws Exception { - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - System.setProperty("user.home", oldUserHome); - System.setProperty("java.home", oldJavaHome); - + prefsTester.tearDown(); super.tearDown(); } @@ -313,6 +307,7 @@ public class FilePreferencesImplTest extends TestCase { System.setSecurityManager(dflt); } + @Override public void checkPermission(Permission perm) { if (perm instanceof FilePermission) { throw new SecurityException(); @@ -321,6 +316,7 @@ public class FilePreferencesImplTest extends TestCase { } } + @Override public void checkPermission(Permission perm, Object ctx) { if (perm instanceof FilePermission) { System.out.println(perm.getActions()); diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java index 28c953e..c7ff946 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/InvalidPreferencesFormatExceptionTest.java @@ -44,7 +44,7 @@ public class InvalidPreferencesFormatExceptionTest extends TestCase { ) public void testInvalidPreferencesFormatExceptionString() { InvalidPreferencesFormatException e = new InvalidPreferencesFormatException( - "msg"); + "msg"); assertNull(e.getCause()); assertEquals("msg", e.getMessage()); } @@ -99,7 +99,7 @@ public class InvalidPreferencesFormatExceptionTest extends TestCase { public void testSerializationSelf() throws Exception { SerializationTest.verifySelf(new InvalidPreferencesFormatException( - "msg")); + "msg")); } /** diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java index 1820954..b149225 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockAbstractPreferences.java @@ -84,6 +84,7 @@ public class MockAbstractPreferences extends AbstractPreferences { return lock; } + @Override public String[] childrenNamesSpi() throws BackingStoreException { checkException(); if (result == returnNull) @@ -108,6 +109,7 @@ public class MockAbstractPreferences extends AbstractPreferences { return childSpi(name); } + @Override public AbstractPreferences childSpi(String name) { try { checkException(); @@ -123,11 +125,13 @@ public class MockAbstractPreferences extends AbstractPreferences { return r; } + @Override public void flushSpi() throws BackingStoreException { checkException(); flushedTimes++; } + @Override public String getSpi(String key) { try { checkException(); @@ -139,6 +143,7 @@ public class MockAbstractPreferences extends AbstractPreferences { return result == returnNull ? null : attr.getProperty(key); } + @Override public String[] keysSpi() throws BackingStoreException { checkException(); Set<Object> keys = attr.keySet(); @@ -147,6 +152,7 @@ public class MockAbstractPreferences extends AbstractPreferences { return result == returnNull ? null : results; } + @Override public void putSpi(String name, String value) { try { checkException(); @@ -158,11 +164,13 @@ public class MockAbstractPreferences extends AbstractPreferences { attr.put(name, value); } + @Override protected void removeNodeSpi() throws BackingStoreException { checkException(); ((MockAbstractPreferences) parent()).childs.remove(name()); } + @Override public void removeSpi(String key) { try { checkException(); @@ -174,6 +182,7 @@ public class MockAbstractPreferences extends AbstractPreferences { attr.remove(key); } + @Override public void syncSpi() throws BackingStoreException { checkException(); syncTimes++; diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java index e5a0bfd..d6047fb 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/MockSecurityManager.java @@ -39,6 +39,7 @@ class MockSecurityManager extends SecurityManager { System.setSecurityManager(dflt); } + @Override public void checkPermission(Permission perm) { if (perm instanceof RuntimePermission && perm.getName().equals("preferences")) { @@ -48,6 +49,7 @@ class MockSecurityManager extends SecurityManager { } } + @Override public void checkPermission(Permission perm, Object ctx) { if (perm instanceof RuntimePermission && perm.getName().equals("preferences")) { diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java index eab3b14..1afd755 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeEventTest.java @@ -30,6 +30,7 @@ import java.util.prefs.Preferences; import junit.framework.TestCase; import org.apache.harmony.testframework.serialization.SerializationTest; +import tests.util.PrefsTester; /** * @@ -37,26 +38,17 @@ import org.apache.harmony.testframework.serialization.SerializationTest; @TestTargetClass(NodeChangeEvent.class) public class NodeChangeEventTest extends TestCase { - NodeChangeEvent event; + private final PrefsTester prefsTester = new PrefsTester(); - String oldUserHome = System.getProperty("user.home"); - String oldJavaHome = System.getProperty("java.home"); + NodeChangeEvent event; protected void setUp() throws Exception { super.setUp(); - - System.setProperty("user.home", System.getProperty("java.io.tmpdir")); - System.setProperty("java.home", System.getProperty("java.io.tmpdir")); - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); + prefsTester.setUp(); } protected void tearDown() throws Exception { - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - System.setProperty("user.home", oldUserHome); - System.setProperty("java.home", oldJavaHome); - + prefsTester.tearDown(); super.tearDown(); } diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java index c5e3252..3cdb4d9 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/NodeChangeListenerTest.java @@ -26,6 +26,7 @@ import java.util.prefs.NodeChangeListener; import java.util.prefs.Preferences; import junit.framework.TestCase; +import tests.util.PrefsTester; /** * @@ -33,20 +34,26 @@ import junit.framework.TestCase; @TestTargetClass(NodeChangeListener.class) public class NodeChangeListenerTest extends TestCase { + private final PrefsTester prefsTester = new PrefsTester(); + NodeChangeListener l; /* * @see TestCase#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); + prefsTester.setUp(); l = new NodeChangeListenerImpl(); } /* * @see TestCase#tearDown() */ + @Override protected void tearDown() throws Exception { + prefsTester.tearDown(); super.tearDown(); } diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java index 4030b89..dda1f6c 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeEventTest.java @@ -92,7 +92,7 @@ public class PreferenceChangeEventTest extends TestCase { ) public void testConstructor() { event = new PreferenceChangeEvent(Preferences.userRoot(), "key", - "value"); + "value"); assertEquals("key", event.getKey()); assertEquals("value", event.getNewValue()); assertSame(Preferences.userRoot(), event.getNode()); @@ -107,7 +107,7 @@ public class PreferenceChangeEventTest extends TestCase { ) public void testSerialization() throws Exception { event = new PreferenceChangeEvent(Preferences.userRoot(), "key", - "value"); + "value"); try { SerializationTest.copySerializable(event); fail("No expected NotSerializableException"); diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java index e4df9c4..7080aa5 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferenceChangeListenerTest.java @@ -38,6 +38,7 @@ public class PreferenceChangeListenerTest extends TestCase { /* * @see TestCase#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); l = new PreferenceChangeListenerImpl(); diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java index 818d5ad..729bc05 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesFactoryTest.java @@ -37,6 +37,7 @@ public class PreferencesFactoryTest extends TestCase { /* * @see TestCase#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); f = new PreferencesFactoryImpl(); @@ -49,7 +50,7 @@ public class PreferencesFactoryTest extends TestCase { args = {} ) public void testUserRoot() { - f.userRoot(); + assertNull(f.userRoot()); } @TestTargetNew( @@ -59,7 +60,7 @@ public class PreferencesFactoryTest extends TestCase { args = {} ) public void testSystemRoot() { - f.systemRoot(); + assertNull(f.systemRoot()); } public static class PreferencesFactoryImpl implements PreferencesFactory { diff --git a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java index 0ebf6bb..c9c74fd 100644 --- a/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java +++ b/prefs/src/test/java/org/apache/harmony/prefs/tests/java/util/prefs/PreferencesTest.java @@ -39,14 +39,15 @@ import java.util.prefs.NodeChangeListener; import java.util.prefs.PreferenceChangeListener; import java.util.prefs.Preferences; +import tests.util.PrefsTester; + /** * */ @TestTargetClass(Preferences.class) public class PreferencesTest extends TestCase { - String oldUserHome = System.getProperty("user.home"); - String oldJavaHome = System.getProperty("java.home"); + private final PrefsTester prefsTester = new PrefsTester(); MockSecurityManager manager = new MockSecurityManager(); @@ -74,43 +75,24 @@ public class PreferencesTest extends TestCase { /* * @see TestCase#setUp() */ + @Override protected void setUp() throws Exception { super.setUp(); in = new ByteArrayInputStream( "<!DOCTYPE preferences SYSTEM \"http://java.sun.com/dtd/preferences.dtd\"><preferences><root type=\"user\"><map></map></root></preferences>" .getBytes("UTF-8")); stream = new MockInputStream(in); - - System.setProperty("user.home", System.getProperty("java.io.tmpdir")); - System.setProperty("java.home", System.getProperty("java.io.tmpdir")); - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - - Preferences p = Preferences.userNodeForPackage(Preferences.class); - p.clear(); - try { - p.removeNode(); - } catch (BackingStoreException e) { - } + prefsTester.setUp(); } /* * @see TestCase#tearDown() */ + @Override protected void tearDown() throws Exception { - super.tearDown(); stream.close(); - Preferences p = Preferences.userNodeForPackage(Preferences.class); - p.clear(); - try { - p.removeNode(); - } catch (BackingStoreException e) { - } - - Preferences.systemRoot().clear(); - Preferences.userRoot().clear(); - System.setProperty("user.home", oldUserHome); - System.setProperty("java.home", oldJavaHome); + prefsTester.tearDown(); + super.tearDown(); } @TestTargetNew( @@ -1830,6 +1812,7 @@ public class PreferencesTest extends TestCase { wrapper = in; } + @Override public int read() throws IOException { checkException(); return wrapper.read(); @@ -1843,136 +1826,170 @@ public class PreferencesTest extends TestCase { super(); } + @Override public String absolutePath() { return null; } + @Override public String[] childrenNames() throws BackingStoreException { return null; } + @Override public void clear() throws BackingStoreException { } + @Override public void exportNode(OutputStream ostream) throws IOException, BackingStoreException { } + @Override public void exportSubtree(OutputStream ostream) throws IOException, BackingStoreException { } + @Override public void flush() throws BackingStoreException { } + @Override public String get(String key, String deflt) { return null; } + @Override public boolean getBoolean(String key, boolean deflt) { return false; } + @Override public byte[] getByteArray(String key, byte[] deflt) { return null; } + @Override public double getDouble(String key, double deflt) { return 0; } + @Override public float getFloat(String key, float deflt) { return 0; } + @Override public int getInt(String key, int deflt) { return 0; } + @Override public long getLong(String key, long deflt) { return 0; } + @Override public boolean isUserNode() { return false; } + @Override public String[] keys() throws BackingStoreException { return null; } + @Override public String name() { return null; } + @Override public Preferences node(String name) { return null; } + @Override public boolean nodeExists(String name) throws BackingStoreException { return false; } + @Override public Preferences parent() { return null; } + @Override public void put(String key, String value) { } + @Override public void putBoolean(String key, boolean value) { } + @Override public void putByteArray(String key, byte[] value) { } + @Override public void putDouble(String key, double value) { } + @Override public void putFloat(String key, float value) { } + @Override public void putInt(String key, int value) { } + @Override public void putLong(String key, long value) { } + @Override public void remove(String key) { } + @Override public void removeNode() throws BackingStoreException { } + @Override public void addNodeChangeListener(NodeChangeListener ncl) { } + @Override public void addPreferenceChangeListener(PreferenceChangeListener pcl) { } + @Override public void removeNodeChangeListener(NodeChangeListener ncl) { } + @Override public void removePreferenceChangeListener(PreferenceChangeListener pcl) { } + @Override public void sync() throws BackingStoreException { } + @Override public String toString() { return null; } diff --git a/prefs/src/test/java/tests/prefs/AllTests.java b/prefs/src/test/java/tests/prefs/AllTests.java index 843d733..b3f2ed6 100644 --- a/prefs/src/test/java/tests/prefs/AllTests.java +++ b/prefs/src/test/java/tests/prefs/AllTests.java @@ -20,7 +20,8 @@ import junit.framework.Test; import junit.framework.TestSuite; /** - * Test suite that includes all tests for the Math project. + * Test suite that includes all tests for the Prefs project. + * */ public class AllTests { diff --git a/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd b/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd deleted file mode 100644 index a116015..0000000 --- a/prefs/src/test/resources/prefs/java/util/prefs/preferences.dtd +++ /dev/null @@ -1,56 +0,0 @@ -<!-- - 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. - --> - -<!-- DTD for a Preferences tree. --> - -<!-- The preferences element is at the root of an XML document - representing a Preferences tree. --> -<!ELEMENT preferences (root)> - -<!-- The preferences element contains an optional version attribute, - which specifies version of DTD. --> -<!ATTLIST preferences EXTERNAL_XML_VERSION CDATA "0.0" > - -<!-- The root element has a map representing the root's preferences - (if any), and one node for each child of the root (if any). --> -<!ELEMENT root (map, node*) > - -<!-- Additionally, the root contains a type attribute, which - specifies whether it's the system or user root. --> -<!ATTLIST root - type (system|user) #REQUIRED > - -<!-- Each node has a map representing its preferences (if any), - and one node for each child (if any). --> - -<!ELEMENT node (map, node*) > - -<!-- Additionally, each node has a name attribute --> -<!ATTLIST node - name CDATA #REQUIRED > - -<!-- A map represents the preferences stored at a node (if any). --> -<!ELEMENT map (entry*) > - -<!-- An entry represents a single preference, which is simply - a key-value pair. --> -<!ELEMENT entry EMPTY > -<!ATTLIST entry - key CDATA #REQUIRED - value CDATA #REQUIRED >
\ No newline at end of file diff --git a/regex/src/main/java/java/util/regex/Pattern.java b/regex/src/main/java/java/util/regex/Pattern.java index c058db8..2853bbe 100644 --- a/regex/src/main/java/java/util/regex/Pattern.java +++ b/regex/src/main/java/java/util/regex/Pattern.java @@ -356,28 +356,33 @@ public final class Pattern implements Serializable { } /** - * Splits the given input sequence around occurrences of the {@code Pattern}. - * The function first determines all occurrences of the {@code Pattern} - * inside the input sequence. It then builds an array of the - * "remaining" strings before, in-between, and after these - * occurrences. An additional parameter determines the maximal number of - * entries in the resulting array and the handling of trailing empty - * strings. + * Splits the given input sequence at occurrences of this {@code Pattern}. + * + * If this {@code Pattern} does not occur in the input, the result is an + * array containing the input (converted from a {@code CharSequence} to + * a {@code String}). + * + * Otherwise, the {@code limit} parameter controls the contents of the + * returned array as described below. * * @param inputSeq * the input sequence. * @param limit - * Determines the maximal number of entries in the resulting - * array. + * Determines the maximum number of entries in the resulting + * array, and the treatment of trailing empty strings. * <ul> - * <li>For n > 0, it is guaranteed that the resulting array - * contains at most n entries. + * <li>For n > 0, the resulting array contains at most n + * entries. If this is fewer than the number of matches, the + * final entry will contain all remaining input. * <li>For n < 0, the length of the resulting array is - * exactly the number of occurrences of the {@code Pattern} +1. + * exactly the number of occurrences of the {@code Pattern} + * plus one for the text after the final separator. * All entries are included. - * <li>For n == 0, the length of the resulting array is at most - * the number of occurrences of the {@code Pattern} +1. Empty - * strings at the end of the array are not included. + * <li>For n == 0, the result is as for n < 0, except + * trailing empty strings will not be returned. (Note that + * the case where the input is itself an empty string is + * special, as described above, and the limit parameter does + * not apply there.) * </ul> * * @return the resulting array. @@ -385,6 +390,13 @@ public final class Pattern implements Serializable { * @since Android 1.0 */ public String[] split(CharSequence inputSeq, int limit) { + if (inputSeq.length() == 0) { + // Unlike Perl, which considers the result of splitting the empty + // string to be the empty array, Java returns an array containing + // the empty string. + return new String[] { "" }; + } + int maxLength = limit <= 0 ? Integer.MAX_VALUE : limit; String input = inputSeq.toString(); @@ -393,14 +405,10 @@ public final class Pattern implements Serializable { Matcher matcher = new Matcher(this, inputSeq); int savedPos = 0; - // Add text preceding each occurrence, if enough space. Only do this for - // non-empty input sequences, because otherwise we'd add the "trailing - // empty string" twice. - if (inputSeq.length() != 0) { - while(matcher.find() && list.size() + 1 < maxLength) { - list.add(input.substring(savedPos, matcher.start())); - savedPos = matcher.end(); - } + // Add text preceding each occurrence, if enough space. + while(matcher.find() && list.size() + 1 < maxLength) { + list.add(input.substring(savedPos, matcher.start())); + savedPos = matcher.end(); } // Add trailing text if enough space. @@ -412,11 +420,10 @@ public final class Pattern implements Serializable { } } - // Remove trailing spaces, if limit == 0 is requested. + // Remove trailing empty matches in the limit == 0 case. if (limit == 0) { int i = list.size() - 1; - // Don't remove 1st element, since array must not be empty. - while(i > 0 && "".equals(list.get(i))) { + while (i >= 0 && "".equals(list.get(i))) { list.remove(i); i--; } diff --git a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java index ea615c0..894dfff 100644 --- a/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java +++ b/regex/src/test/java/org/apache/harmony/regex/tests/java/util/regex/SplitTest.java @@ -32,12 +32,62 @@ public class SplitTest extends TestCase { Pattern p = Pattern.compile("/"); String[] results = p.split("have/you/done/it/right"); String[] expected = new String[] { "have", "you", "done", "it", "right" }; - assertEquals(expected.length, results.length); + assertArraysEqual(expected, results); + } + + @TestTargets({ + @TestTargetNew( + level = TestLevel.PARTIAL_COMPLETE, + notes = "Verifies the basic functionality of split with empty matches.", + method = "split", + args = {java.lang.CharSequence.class} + ) + }) + public void testEmptySplits() { + // Trailing empty matches are removed. + assertArraysEqual(new String[0], "hello".split(".")); + assertArraysEqual(new String[] { "1", "2" }, "1:2:".split(":")); + // ...including when that results in an empty result. + assertArraysEqual(new String[0], ":".split(":")); + // ...but not when limit < 0. + assertArraysEqual(new String[] { "1", "2", "" }, "1:2:".split(":", -1)); + + // Leading empty matches are retained. + assertArraysEqual(new String[] { "", "", "o" }, "hello".split("..")); + + // A separator that doesn't occur in the input gets you the input. + assertArraysEqual(new String[] { "hello" }, "hello".split("not-present-in-test")); + // ...including when the input is the empty string. + // (Perl returns an empty list instead.) + assertArraysEqual(new String[] { "" }, "".split("not-present-in-test")); + assertArraysEqual(new String[] { "" }, "".split("A?")); + + // The limit argument controls the size of the result. + // If l == 0, the result is as long as needed, except trailing empty matches are dropped. + // If l < 0, the result is as long as needed, and trailing empty matches are retained. + // If l > 0, the result contains the first l matches, plus one string containing the remaining input. + // Examples without a trailing separator (and hence without a trailing empty match): + assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", 0)); + assertArraysEqual(new String[] { "a,b,c" }, "a,b,c".split(",", 1)); + assertArraysEqual(new String[] { "a", "b,c" }, "a,b,c".split(",", 2)); + assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", 3)); + assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c".split(",", Integer.MAX_VALUE)); + // Examples with a trailing separator (and hence possibly with a trailing empty match): + assertArraysEqual(new String[] { "a", "b", "c" }, "a,b,c,".split(",", 0)); + assertArraysEqual(new String[] { "a,b,c," }, "a,b,c,".split(",", 1)); + assertArraysEqual(new String[] { "a", "b,c," }, "a,b,c,".split(",", 2)); + assertArraysEqual(new String[] { "a", "b", "c," }, "a,b,c,".split(",", 3)); + assertArraysEqual(new String[] { "a", "b", "c", "" }, "a,b,c,".split(",", Integer.MAX_VALUE)); + assertArraysEqual(new String[] { "a", "b", "c", "" }, "a,b,c,".split(",", -1)); + } + + private void assertArraysEqual(String[] expected, String[] actual) { + assertEquals(expected.length, actual.length); for (int i = 0; i < expected.length; i++) { - assertEquals(results[i], expected[i]); + assertEquals(Integer.toString(i), expected[i], actual[i]); } } - + @TestTargetNew( level = TestLevel.PARTIAL_COMPLETE, notes = "Verifies the functionality of split(java.lang.CharSequence). Test uses not empty pattern.", diff --git a/security/src/main/files/cacerts.bks b/security/src/main/files/cacerts.bks Binary files differindex bbcc080..36f4919 100644 --- a/security/src/main/files/cacerts.bks +++ b/security/src/main/files/cacerts.bks diff --git a/security/src/main/files/cacerts/3e7271e8.0 b/security/src/main/files/cacerts/3e7271e8.0 new file mode 100644 index 0000000..62b5b22 --- /dev/null +++ b/security/src/main/files/cacerts/3e7271e8.0 @@ -0,0 +1,85 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 946059622 (0x3863b966) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Dec 24 17:50:51 1999 GMT + Not After : Dec 24 18:20:51 2019 GMT + Subject: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:ad:4d:4b:a9:12:86:b2:ea:a3:20:07:15:16:64: + 2a:2b:4b:d1:bf:0b:4a:4d:8e:ed:80:76:a5:67:b7: + 78:40:c0:73:42:c8:68:c0:db:53:2b:dd:5e:b8:76: + 98:35:93:8b:1a:9d:7c:13:3a:0e:1f:5b:b7:1e:cf: + e5:24:14:1e:b1:81:a9:8d:7d:b8:cc:6b:4b:03:f1: + 02:0c:dc:ab:a5:40:24:00:7f:74:94:a1:9d:08:29: + b3:88:0b:f5:87:77:9d:55:cd:e4:c3:7e:d7:6a:64: + ab:85:14:86:95:5b:97:32:50:6f:3d:c8:ba:66:0c: + e3:fc:bd:b8:49:c1:76:89:49:19:fd:c0:a8:bd:89: + a3:67:2f:c6:9f:bc:71:19:60:b8:2d:e9:2c:c9:90: + 76:66:7b:94:e2:af:78:d6:65:53:5d:3c:d6:9c:b2: + cf:29:03:f9:2f:a4:50:b2:d4:48:ce:05:32:55:8a: + fd:b2:64:4c:0e:e4:98:07:75:db:7f:df:b9:08:55: + 60:85:30:29:f9:7b:48:a4:69:86:e3:35:3f:1e:86: + 5d:7a:7a:15:bd:ef:00:8e:15:22:54:17:00:90:26: + 93:bc:0e:49:68:91:bf:f8:47:d3:9d:95:42:c1:0e: + 4d:df:6f:26:cf:c3:18:21:62:66:43:70:d6:d5:c0: + 07:e1 + Exponent: 65537 (0x10001) + X509v3 extensions: + Netscape Cert Type: + SSL CA, S/MIME CA, Object Signing CA + X509v3 Authority Key Identifier: + keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + + X509v3 Subject Key Identifier: + 55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + 1.2.840.113533.7.65.0: + 0...V5.0:4.0.... + Signature Algorithm: sha1WithRSAEncryption + 59:47:ac:21:84:8a:17:c9:9c:89:53:1e:ba:80:85:1a:c6:3c: + 4e:3e:b1:9c:b6:7c:c6:92:5d:18:64:02:e3:d3:06:08:11:61: + 7c:63:e3:2b:9d:31:03:70:76:d2:a3:28:a0:f4:bb:9a:63:73: + ed:6d:e5:2a:db:ed:14:a9:2b:c6:36:11:d0:2b:eb:07:8b:a5: + da:9e:5c:19:9d:56:12:f5:54:29:c8:05:ed:b2:12:2a:8d:f4: + 03:1b:ff:e7:92:10:87:b0:3a:b5:c3:9d:05:37:12:a3:c7:f4: + 15:b9:d5:a4:39:16:9b:53:3a:23:91:f1:a8:82:a2:6a:88:68: + c1:79:02:22:bc:aa:a6:d6:ae:df:b0:14:5f:b8:87:d0:dd:7c: + 7f:7b:ff:af:1c:cf:e6:db:07:ad:5e:db:85:9d:d0:2b:0d:33: + db:04:d1:e6:49:40:13:2b:76:fb:3e:e9:9c:89:0f:15:ce:18: + b0:85:78:21:4f:6b:4f:0e:fa:36:67:cd:07:f2:ff:08:d0:e2: + de:d9:bf:2a:af:b8:87:86:21:3c:04:ca:b7:94:68:7f:cf:3c: + e9:98:d7:38:ff:ec:c0:d9:50:f0:2e:4b:58:ae:46:6f:d0:2e: + c3:60:da:72:55:72:bd:4c:45:9e:61:ba:bf:84:81:92:03:d1: + d2:69:7c:c5 +-----BEGIN CERTIFICATE----- +MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0xOTEy +MjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo3QwcjARBglghkgBhvhCAQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGA +vtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdERgL7YibkIozH5oSQJFrlwMB0G +CSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA +WUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo +oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQ +h7A6tcOdBTcSo8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18 +f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN +B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy +vUxFnmG6v4SBkgPR0ml8xQ== +-----END CERTIFICATE----- diff --git a/security/src/main/files/cacerts/ab86d4de.0 b/security/src/main/files/cacerts/ab86d4de.0 new file mode 100644 index 0000000..c6f241f --- /dev/null +++ b/security/src/main/files/cacerts/ab86d4de.0 @@ -0,0 +1,104 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 946062766 (0x3863c5ae) + Signature Algorithm: sha1WithRSAEncryption + Issuer: O=Entrust.net, OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Certification Authority (2048) + Validity + Not Before: Aug 25 18:14:26 2008 GMT + Not After : Aug 25 18:44:26 2018 GMT + Subject: C=US, O=Entrust, Inc., OU=AND ADDITIONAL TERMS GOVERNING USE AND RELIANCE, OU=CPS CONTAINS IMPORTANT LIMITATIONS OF WARRANTIES AND LIABILITY, OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2008 Entrust, Inc., CN=Entrust Certification Authority - L1B + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:dc:21:f5:68:f9:7a:ce:87:f2:78:df:d8:3b:4d: + 06:7d:c6:24:e4:a9:cd:9d:01:56:e4:f6:71:17:aa: + 7f:75:22:18:e4:74:6d:1b:3e:56:d5:b1:a6:1e:dd: + 59:26:53:ca:06:e6:ba:0b:6f:37:bb:a8:c6:9c:15: + 3b:06:1b:87:0c:c2:1a:4d:d3:81:ae:db:50:65:a5: + 3a:64:4f:30:34:9a:2b:a9:1f:fd:2b:d1:38:71:19: + 68:f2:8e:eb:7b:c9:40:3c:48:c4:19:b1:b7:10:25: + ef:44:a7:e6:77:9b:7d:22:9a:de:d8:5e:d9:c3:ce: + c9:71:22:bb:ae:ef:05:d6:f2:17:e7:56:78:e1:53: + 05:4a:26:73:b8:c7:49:67:93:23:0f:56:b2:8f:dd: + c9:59:05:e5:63:15:b4:87:7e:40:46:e9:b5:00:7b: + 03:b4:0d:e4:96:67:2c:de:1b:59:0b:1a:1f:b8:63: + 44:ae:c1:d7:44:87:c4:91:59:9c:00:43:6d:c6:df: + 0a:b0:b1:04:cd:fe:be:30:5e:3a:25:72:dd:a2:3e: + ed:46:3a:c7:a4:5c:5c:e4:25:f2:13:07:e8:ae:da: + 9b:19:9b:a2:d9:60:9d:ce:90:47:6a:61:7b:40:e8: + 14:c2:fe:2f:84:5a:66:17:c0:97:d3:49:38:de:63: + 02:9f + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + URI:http://crl.entrust.net/2048ca.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/CPS + + X509v3 Subject Key Identifier: + F5:F2:96:88:7D:0D:F3:2A:F9:4E:E7:34:A0:BD:46:7E:13:D6:16:C8 + X509v3 Authority Key Identifier: + keyid:55:E4:81:D1:11:80:BE:D8:89:B9:08:A3:31:F9:A1:24:09:16:B9:70 + + 1.2.840.113533.7.65.0: + 0 +..V7.1.... + Signature Algorithm: sha1WithRSAEncryption + 0b:25:3c:58:fa:8e:dc:a2:42:3b:76:71:6e:6c:d4:4f:2b:b9: + 53:5c:b2:58:b9:b1:dc:6f:1a:e4:e3:c4:50:f2:41:82:ba:f4: + 7d:c7:c1:f9:fa:8c:53:bf:b9:62:b7:49:e3:1d:0a:fc:1f:d6: + c4:76:6a:93:cb:77:1e:2c:7f:d0:3f:16:63:4c:72:4c:67:60: + 0f:f8:80:d6:a7:9a:ca:a2:33:91:0f:44:b2:66:3d:8e:68:0c: + 40:85:12:37:91:b9:82:77:34:59:2d:5c:df:82:6e:2c:b6:7a: + d2:04:90:67:68:4b:70:fc:2d:b8:ff:90:64:6f:7e:91:f7:d1: + 47:33:f3:5b:b8:58:2e:21:d8:75:60:1b:13:cc:f8:b2:a8:fa: + 6a:a9:2a:5a:4f:45:85:40:b4:dd:34:05:b7:70:ca:01:ef:e1: + 81:e7:11:50:db:3e:e2:d7:10:2e:6a:15:7f:b7:d4:a3:62:b2: + 89:69:61:57:c6:7f:8e:9e:d4:24:7a:f3:a1:43:5f:a0:7a:89: + dc:59:cd:7d:d7:75:a7:bc:53:d5:47:35:c6:31:30:20:9f:9b: + ba:b5:83:e6:89:55:01:4d:91:3b:d6:89:35:87:3c:83:6b:7a: + 29:82:d4:4b:d4:e6:16:74:b0:01:10:ab:69:06:14:37:7b:f7: + 66:30:3a:c5 +-----BEGIN CERTIFICATE----- +MIIFkTCCBHmgAwIBAgIEOGPFrjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw0wODA4MjUxODE0MjZaFw0xODA4 +MjUxODQ0MjZaMIIBNDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIElu +Yy4xODA2BgNVBAsTL0FORCBBRERJVElPTkFMIFRFUk1TIEdPVkVSTklORyBVU0Ug +QU5EIFJFTElBTkNFMUcwRQYDVQQLEz5DUFMgQ09OVEFJTlMgSU1QT1JUQU5UIExJ +TUlUQVRJT05TIE9GIFdBUlJBTlRJRVMgQU5EIExJQUJJTElUWTE5MDcGA1UECxMw +d3d3LmVudHJ1c3QubmV0L0NQUyBpcyBpbmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNl +MR8wHQYDVQQLExYoYykgMjAwOCBFbnRydXN0LCBJbmMuMS4wLAYDVQQDEyVFbnRy +dXN0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gTDFCMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA3CH1aPl6zofyeN/YO00GfcYk5KnNnQFW5PZxF6p/ +dSIY5HRtGz5W1bGmHt1ZJlPKBua6C283u6jGnBU7BhuHDMIaTdOBrttQZaU6ZE8w +NJorqR/9K9E4cRlo8o7re8lAPEjEGbG3ECXvRKfmd5t9Ipre2F7Zw87JcSK7ru8F +1vIX51Z44VMFSiZzuMdJZ5MjD1ayj93JWQXlYxW0h35ARum1AHsDtA3klmcs3htZ +CxofuGNErsHXRIfEkVmcAENtxt8KsLEEzf6+MF46JXLdoj7tRjrHpFxc5CXyEwfo +rtqbGZui2WCdzpBHamF7QOgUwv4vhFpmF8CX00k43mMCnwIDAQABo4IBJjCCASIw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wMwYIKwYBBQUHAQEEJzAl +MCMGCCsGAQUFBzABhhdodHRwOi8vb2NzcC5lbnRydXN0Lm5ldDAyBgNVHR8EKzAp +MCegJaAjhiFodHRwOi8vY3JsLmVudHJ1c3QubmV0LzIwNDhjYS5jcmwwOwYDVR0g +BDQwMjAwBgRVHSAAMCgwJgYIKwYBBQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5u +ZXQvQ1BTMB0GA1UdDgQWBBT18paIfQ3zKvlO5zSgvUZ+E9YWyDAfBgNVHSMEGDAW +gBRV5IHREYC+2Im5CKMx+aEkCRa5cDAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIA +gTANBgkqhkiG9w0BAQUFAAOCAQEACyU8WPqO3KJCO3ZxbmzUTyu5U1yyWLmx3G8a +5OPEUPJBgrr0fcfB+fqMU7+5YrdJ4x0K/B/WxHZqk8t3Hix/0D8WY0xyTGdgD/iA +1qeayqIzkQ9EsmY9jmgMQIUSN5G5gnc0WS1c34JuLLZ60gSQZ2hLcPwtuP+QZG9+ +kffRRzPzW7hYLiHYdWAbE8z4sqj6aqkqWk9FhUC03TQFt3DKAe/hgecRUNs+4tcQ +LmoVf7fUo2KyiWlhV8Z/jp7UJHrzoUNfoHqJ3FnNfdd1p7xT1Uc1xjEwIJ+burWD +5olVAU2RO9aJNYc8g2t6KYLUS9TmFnSwARCraQYUN3v3ZjA6xQ== +-----END CERTIFICATE----- diff --git a/security/src/main/files/cacerts/b0f3e76e.0 b/security/src/main/files/cacerts/b0f3e76e.0 index 05ce1ec..386b70a 100644 --- a/security/src/main/files/cacerts/b0f3e76e.0 +++ b/security/src/main/files/cacerts/b0f3e76e.0 @@ -2,12 +2,12 @@ Certificate: Data: Version: 3 (0x2) Serial Number: - 02:00:00:00:00:00:d6:78:b7:94:05 - Signature Algorithm: md5WithRSAEncryption + 04:00:00:00:00:01:15:4b:5a:c3:94 + Signature Algorithm: sha1WithRSAEncryption Issuer: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA Validity Not Before: Sep 1 12:00:00 1998 GMT - Not After : Jan 28 12:00:00 2014 GMT + Not After : Jan 28 12:00:00 2028 GMT Subject: C=BE, O=GlobalSign nv-sa, OU=Root CA, CN=GlobalSign Root CA Subject Public Key Info: Public Key Algorithm: rsaEncryption @@ -35,32 +35,31 @@ Certificate: X509v3 extensions: X509v3 Key Usage: critical Certificate Sign, CRL Sign - X509v3 Subject Key Identifier: - 60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B X509v3 Basic Constraints: critical CA:TRUE - Signature Algorithm: md5WithRSAEncryption - ae:aa:9f:fc:b7:d2:cb:1f:5f:39:29:28:18:9e:34:c9:6c:4f: - 6f:1a:f0:64:a2:70:4a:4f:13:86:9b:60:28:9e:e8:81:49:98: - 7d:0a:bb:e5:b0:9d:3d:36:db:8f:05:51:ff:09:31:2a:1f:dd: - 89:77:9e:0f:2e:6c:95:04:ed:86:cb:b4:00:3f:84:02:4d:80: - 6a:2a:2d:78:0b:ae:6f:2b:a2:83:44:83:1f:cd:50:82:4c:24: - af:bd:f7:a5:b4:c8:5a:0f:f4:e7:47:5e:49:8e:37:96:fe:9a: - 88:05:3a:d9:c0:db:29:87:e6:19:96:47:a7:3a:a6:8c:8b:3c: - 77:fe:46:63:a7:53:da:21:d1:ac:7e:49:a2:4b:e6:c3:67:59: - 2f:b3:8a:0e:bb:2c:bd:a9:aa:42:7c:35:c1:d8:7f:d5:a7:31: - 3a:4e:63:43:39:af:08:b0:61:34:8c:d3:98:a9:43:34:f6:0f: - 87:29:3b:9d:c2:56:58:98:77:c3:f7:1b:ac:f6:9d:f8:3e:aa: - a7:54:45:f0:f5:f9:d5:31:65:fe:6b:58:9c:71:b3:1e:d7:52: - ea:32:17:fc:40:60:1d:c9:79:24:b2:f6:6c:fd:a8:66:0e:82: - dd:98:cb:da:c2:44:4f:2e:a0:7b:f2:f7:6b:2c:76:11:84:46: - 8a:78:a3:e3 -SHA1 Fingerprint=2F:17:3F:7D:E9:96:67:AF:A5:7A:F8:0A:A2:D1:B1:2F:AC:83:03:38 + X509v3 Subject Key Identifier: + 60:7B:66:1A:45:0D:97:CA:89:50:2F:7D:04:CD:34:A8:FF:FC:FD:4B + Signature Algorithm: sha1WithRSAEncryption + d6:73:e7:7c:4f:76:d0:8d:bf:ec:ba:a2:be:34:c5:28:32:b5: + 7c:fc:6c:9c:2c:2b:bd:09:9e:53:bf:6b:5e:aa:11:48:b6:e5: + 08:a3:b3:ca:3d:61:4d:d3:46:09:b3:3e:c3:a0:e3:63:55:1b: + f2:ba:ef:ad:39:e1:43:b9:38:a3:e6:2f:8a:26:3b:ef:a0:50: + 56:f9:c6:0a:fd:38:cd:c4:0b:70:51:94:97:98:04:df:c3:5f: + 94:d5:15:c9:14:41:9c:c4:5d:75:64:15:0d:ff:55:30:ec:86: + 8f:ff:0d:ef:2c:b9:63:46:f6:aa:fc:df:bc:69:fd:2e:12:48: + 64:9a:e0:95:f0:a6:ef:29:8f:01:b1:15:b5:0c:1d:a5:fe:69: + 2c:69:24:78:1e:b3:a7:1c:71:62:ee:ca:c8:97:ac:17:5d:8a: + c2:f8:47:86:6e:2a:c4:56:31:95:d0:67:89:85:2b:f9:6c:a6: + 5d:46:9d:0c:aa:82:e4:99:51:dd:70:b7:db:56:3d:61:e4:6a: + e1:5c:d6:f6:fe:3d:de:41:cc:07:ae:63:52:bf:53:53:f4:2b: + e9:c7:fd:b6:f7:82:5f:85:d2:41:18:db:81:b3:04:1c:c5:1f: + a4:80:6f:15:20:c9:de:0c:88:0a:1d:d6:66:55:e2:fc:48:c9: + 29:26:69:e0 -----BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILAgAAAAAA1ni3lAUwDQYJKoZIhvcNAQEEBQAwVzELMAkG +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0xNDAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp @@ -68,12 +67,12 @@ xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp 1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIABjAdBgNVHQ4EFgQU -YHtmGkUNl8qJUC99BM00qP/8/UswDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0B -AQQFAAOCAQEArqqf/LfSyx9fOSkoGJ40yWxPbxrwZKJwSk8ThptgKJ7ogUmYfQq7 -5bCdPTbbjwVR/wkxKh/diXeeDy5slQTthsu0AD+EAk2AaioteAuubyuig0SDH81Q -gkwkr733pbTIWg/050deSY43lv6aiAU62cDbKYfmGZZHpzqmjIs8d/5GY6dT2iHR -rH5Jokvmw2dZL7OKDrssvamqQnw1wdh/1acxOk5jQzmvCLBhNIzTmKlDNPYPhyk7 -ncJWWJh3w/cbrPad+D6qp1RF8PX51TFl/mtYnHGzHtdS6jIX/EBgHcl5JLL2bP2o -Zg6C3ZjL2sJETy6ge/L3ayx2EYRGinij4w== +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== -----END CERTIFICATE----- diff --git a/security/src/main/files/cacerts/bf64f35b.0 b/security/src/main/files/cacerts/bf64f35b.0 new file mode 100644 index 0000000..389623c --- /dev/null +++ b/security/src/main/files/cacerts/bf64f35b.0 @@ -0,0 +1,92 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 1116155212 (0x42872d4c) + Signature Algorithm: sha1WithRSAEncryption + Issuer: C=US, O=Entrust.net, OU=www.entrust.net/CPS incorp. by ref. (limits liab.), OU=(c) 1999 Entrust.net Limited, CN=Entrust.net Secure Server Certification Authority + Validity + Not Before: Jan 5 19:20:39 2007 GMT + Not After : Jan 5 19:50:39 2017 GMT + Subject: C=US, O=Entrust, Inc., OU=www.entrust.net/CPS is incorporated by reference, OU=(c) 2006 Entrust, Inc., CN=Entrust Root Certification Authority + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:b6:95:b6:43:42:fa:c6:6d:2a:6f:48:df:94:4c: + 39:57:05:ee:c3:79:11:41:68:36:ed:ec:fe:9a:01: + 8f:a1:38:28:fc:f7:10:46:66:2e:4d:1e:1a:b1:1a: + 4e:c6:d1:c0:95:88:b0:c9:ff:31:8b:33:03:db:b7: + 83:7b:3e:20:84:5e:ed:b2:56:28:a7:f8:e0:b9:40: + 71:37:c5:cb:47:0e:97:2a:68:c0:22:95:62:15:db: + 47:d9:f5:d0:2b:ff:82:4b:c9:ad:3e:de:4c:db:90: + 80:50:3f:09:8a:84:00:ec:30:0a:3d:18:cd:fb:fd: + 2a:59:9a:23:95:17:2c:45:9e:1f:6e:43:79:6d:0c: + 5c:98:fe:48:a7:c5:23:47:5c:5e:fd:6e:e7:1e:b4: + f6:68:45:d1:86:83:5b:a2:8a:8d:b1:e3:29:80:fe: + 25:71:88:ad:be:bc:8f:ac:52:96:4b:aa:51:8d:e4: + 13:31:19:e8:4e:4d:9f:db:ac:b3:6a:d5:bc:39:54: + 71:ca:7a:7a:7f:90:dd:7d:1d:80:d9:81:bb:59:26: + c2:11:fe:e6:93:e2:f7:80:e4:65:fb:34:37:0e:29: + 80:70:4d:af:38:86:2e:9e:7f:57:af:9e:17:ae:eb: + 1c:cb:28:21:5f:b6:1c:d8:e7:a2:04:22:f9:d3:da: + d8:cb + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Key Usage: critical + Certificate Sign, CRL Sign + X509v3 Basic Constraints: critical + CA:TRUE + Authority Information Access: + OCSP - URI:http://ocsp.entrust.net + + X509v3 CRL Distribution Points: + URI:http://crl.entrust.net/server1.crl + + X509v3 Certificate Policies: + Policy: X509v3 Any Policy + CPS: http://www.entrust.net/CPS + + X509v3 Subject Key Identifier: + 68:90:E4:67:A4:A6:53:80:C7:86:66:A4:F1:F7:4B:43:FB:84:BD:6D + X509v3 Authority Key Identifier: + keyid:F0:17:62:13:55:3D:B3:FF:0A:00:6B:FB:50:84:97:F3:ED:62:D0:1A + + 1.2.840.113533.7.65.0: + 0 +..V7.1.... + Signature Algorithm: sha1WithRSAEncryption + 0c:b0:84:7c:2d:13:fe:9a:3d:bf:18:05:95:3d:20:48:a3:16: + 81:87:15:50:15:a4:88:8d:9f:60:d4:3a:6f:eb:2d:6e:3a:86: + a4:a9:d2:c1:9d:89:7a:08:1c:a4:2d:b3:47:8e:0f:64:4a:6f: + 66:03:83:3f:4f:34:94:36:aa:29:6d:8b:8d:02:22:2b:8c:cd: + 77:a5:70:95:86:91:d1:b6:bf:52:be:33:6a:6b:99:f9:6f:e1: + 12:be:04:cb:33:bf:f5:12:1a:4e:44:ba:5b:16:4d:30:b9:f3: + b4:74:ce:6e:f2:68:56:58:dd:d8:a1:fd:54:05:f4:23:91:85: + c9:f9 +-----BEGIN CERTIFICATE----- +MIIEmzCCBASgAwIBAgIEQoctTDANBgkqhkiG9w0BAQUFADCBwzELMAkGA1UEBhMC +VVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MTswOQYDVQQLEzJ3d3cuZW50cnVzdC5u +ZXQvQ1BTIGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTElMCMGA1UECxMc +KGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDE6MDgGA1UEAxMxRW50cnVzdC5u +ZXQgU2VjdXJlIFNlcnZlciBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNzAx +MDUxOTIwMzlaFw0xNzAxMDUxOTUwMzlaMIGwMQswCQYDVQQGEwJVUzEWMBQGA1UE +ChMNRW50cnVzdCwgSW5jLjE5MDcGA1UECxMwd3d3LmVudHJ1c3QubmV0L0NQUyBp +cyBpbmNvcnBvcmF0ZWQgYnkgcmVmZXJlbmNlMR8wHQYDVQQLExYoYykgMjAwNiBF +bnRydXN0LCBJbmMuMS0wKwYDVQQDEyRFbnRydXN0IFJvb3QgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2lbZD +QvrGbSpvSN+UTDlXBe7DeRFBaDbt7P6aAY+hOCj89xBGZi5NHhqxGk7G0cCViLDJ +/zGLMwPbt4N7PiCEXu2yViin+OC5QHE3xctHDpcqaMAilWIV20fZ9dAr/4JLya0+ +3kzbkIBQPwmKhADsMAo9GM37/SpZmiOVFyxFnh9uQ3ltDFyY/kinxSNHXF79buce +tPZoRdGGg1uiio2x4ymA/iVxiK2+vI+sUpZLqlGN5BMxGehOTZ/brLNq1bw5VHHK +enp/kN19HYDZgbtZJsIR/uaT4veA5GX7NDcOKYBwTa84hi6ef1evnheu6xzLKCFf +thzY56IEIvnT2tjLAgMBAAGjggEnMIIBIzAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zAzBggrBgEFBQcBAQQnMCUwIwYIKwYBBQUHMAGGF2h0dHA6Ly9v +Y3NwLmVudHJ1c3QubmV0MDMGA1UdHwQsMCowKKAmoCSGImh0dHA6Ly9jcmwuZW50 +cnVzdC5uZXQvc2VydmVyMS5jcmwwOwYDVR0gBDQwMjAwBgRVHSAAMCgwJgYIKwYB +BQUHAgEWGmh0dHA6Ly93d3cuZW50cnVzdC5uZXQvQ1BTMB0GA1UdDgQWBBRokORn +pKZTgMeGZqTx90tD+4S9bTAfBgNVHSMEGDAWgBTwF2ITVT2z/woAa/tQhJfz7WLQ +GjAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIAgTANBgkqhkiG9w0BAQUFAAOBgQAM +sIR8LRP+mj2/GAWVPSBIoxaBhxVQFaSIjZ9g1Dpv6y1uOoakqdLBnYl6CBykLbNH +jg9kSm9mA4M/TzSUNqopbYuNAiIrjM13pXCVhpHRtr9SvjNqa5n5b+ESvgTLM7/1 +EhpORLpbFk0wufO0dM5u8mhWWN3Yof1UBfQjkYXJ+Q== +-----END CERTIFICATE----- diff --git a/security/src/main/files/certimport.sh b/security/src/main/files/certimport.sh index 7c0fab0..c021a10 100755 --- a/security/src/main/files/certimport.sh +++ b/security/src/main/files/certimport.sh @@ -1,4 +1,5 @@ #!/bin/bash +# java version >= 1.6 is required for this script. # This script was tested to work with bouncycastle 1.32. set -x @@ -6,6 +7,14 @@ set -e CERTSTORE=cacerts.bks +# Check java version. +JAVA_VERSION=`java -version 2>&1 | head -1` +JAVA_VERSION_MINOR=`expr match "$JAVA_VERSION" "java version \"[1-9]\.\([0-9]\).*\""` +if [ $JAVA_VERSION_MINOR -lt 6 ]; then + echo "java version 1.6 or greater required for keytool usage" + exit 255 +fi + if [ -a $CERTSTORE ]; then rm $CERTSTORE || exit 1 fi diff --git a/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java b/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java index c8f9494..34337eb 100644 --- a/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java +++ b/security/src/main/java/org/apache/harmony/security/x501/AttributeTypeAndValue.java @@ -327,11 +327,15 @@ public class AttributeTypeAndValue { if (attrFormat == X500Principal.CANONICAL) { // only PrintableString and UTF8String in string format // all others are output in hex format + // BEGIN android-changed + // no hex for teletex; see bug 2102191 int tag = value.getTag(); if (!ASN1StringType.UTF8STRING.checkTag(tag) - && !ASN1StringType.PRINTABLESTRING.checkTag(tag)) { + && !ASN1StringType.PRINTABLESTRING.checkTag(tag) + && !ASN1StringType.TELETEXSTRING.checkTag(tag)) { hexFormat = true; } + // END android-changed } } else { diff --git a/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java b/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java new file mode 100644 index 0000000..e9fbdb0 --- /dev/null +++ b/security/src/test/java/org/bouncycastle/jce/provider/AllTests.java @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2009 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 org.bouncycastle.jce.provider; + +import junit.framework.Test; +import junit.framework.TestSuite; + +public class AllTests { + + public static void main(String[] args) { + junit.textui.TestRunner.run(AllTests.suite()); + } + + public static Test suite() { + TestSuite suite = tests.TestSuiteFactory.createTestSuite( + "All tests for " + AllTests.class.getPackage()); + suite.addTestSuite(PKIXCertPathValidatorSpiTest.class); + return suite; + } +} diff --git a/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java b/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java new file mode 100644 index 0000000..734e11d --- /dev/null +++ b/security/src/test/java/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpiTest.java @@ -0,0 +1,65 @@ +// Copyright 2009 Google Inc. All Rights Reserved. + +package org.bouncycastle.jce.provider; + +import junit.framework.TestCase; +import org.apache.harmony.security.provider.cert.X509CertImpl; +import org.apache.harmony.security.provider.cert.X509CertPathImpl; +import org.bouncycastle.asn1.x509.X509CertificateStructure; +import org.bouncycastle.asn1.ASN1Sequence; +import org.bouncycastle.asn1.ASN1InputStream; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Set; +import java.util.HashSet; +import java.security.cert.CertificateException; +import java.security.cert.TrustAnchor; +import java.security.cert.CertPathValidatorException; +import java.security.KeyStoreException; +import java.security.InvalidAlgorithmParameterException; + +/** + * Verify the behavior of PKIXCertPathValidatorSpi. + */ +public class PKIXCertPathValidatorSpiTest extends TestCase { + + /** + * A chain of 3 ASN1-encoded certificates for https://service.sprint.com. + * The certificate subjects are "service.sprint.com", "Entrust Certification + * Authority - L1B", and "Entrust.net Certification Authority (2048)". The + * last certificate uses UTF8 encoding for its X509 name. + */ + private final byte[][] serviceSprintComCertChain = new byte[][] { + new byte[] { 48, -126, 6, 89, 48, -126, 5, 65, -96, 3, 2, 1, 2, 2, 4, 72, 13, 115, -81, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -126, 1, 52, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 10, 19, 13, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 56, 48, 54, 6, 3, 85, 4, 11, 19, 47, 65, 78, 68, 32, 65, 68, 68, 73, 84, 73, 79, 78, 65, 76, 32, 84, 69, 82, 77, 83, 32, 71, 79, 86, 69, 82, 78, 73, 78, 71, 32, 85, 83, 69, 32, 65, 78, 68, 32, 82, 69, 76, 73, 65, 78, 67, 69, 49, 71, 48, 69, 6, 3, 85, 4, 11, 19, 62, 67, 80, 83, 32, 67, 79, 78, 84, 65, 73, 78, 83, 32, 73, 77, 80, 79, 82, 84, 65, 78, 84, 32, 76, 73, 77, 73, 84, 65, 84, 73, 79, 78, 83, 32, 79, 70, 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 65, 78, 68, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 49, 57, 48, 55, 6, 3, 85, 4, 11, 19, 48, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 32, 105, 115, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 98, 121, 32, 114, 101, 102, 101, 114, 101, 110, 99, 101, 49, 31, 48, 29, 6, 3, 85, 4, 11, 19, 22, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 46, 48, 44, 6, 3, 85, 4, 3, 19, 37, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 45, 32, 76, 49, 66, 48, 30, 23, 13, 48, 57, 48, 52, 50, 57, 49, 53, 50, 54, 53, 57, 90, 23, 13, 49, 49, 48, 53, 48, 53, 49, 53, 53, 54, 53, 55, 90, 48, 120, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 15, 48, 13, 6, 3, 85, 4, 8, 19, 6, 75, 65, 78, 83, 65, 83, 49, 22, 48, 20, 6, 3, 85, 4, 7, 19, 13, 79, 118, 101, 114, 108, 97, 110, 100, 32, 80, 97, 114, 107, 49, 15, 48, 13, 6, 3, 85, 4, 10, 19, 6, 83, 112, 114, 105, 110, 116, 49, 18, 48, 16, 6, 3, 85, 4, 11, 19, 9, 100, 97, 115, 110, 109, 112, 48, 52, 98, 49, 27, 48, 25, 6, 3, 85, 4, 3, 19, 18, 115, 101, 114, 118, 105, 99, 101, 46, 115, 112, 114, 105, 110, 116, 46, 99, 111, 109, 48, -127, -97, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -127, -115, 0, 48, -127, -119, 2, -127, -127, 0, -80, 99, 109, 108, 94, -41, -78, 88, 56, -97, 33, -23, 65, -74, -118, 0, 1, 119, 126, 122, -59, -83, -25, -16, -75, -87, 100, 46, 37, -98, 65, -104, 54, -87, 56, -81, 96, -38, -4, -78, 11, 101, -29, 70, -13, -110, -76, -125, -106, -35, 41, 83, 71, 56, 6, 67, -8, 82, -58, -81, -113, 90, 91, 79, 74, -38, 34, 28, 39, -37, -12, 54, 87, 61, 48, 33, -16, 10, 112, -40, -37, -15, 59, -72, 112, 96, 85, 109, 123, -122, 58, 18, 95, 56, -81, 49, 43, -39, 99, 69, -28, -81, -106, -64, 8, -62, 40, -92, 95, -109, -122, 94, 53, -13, -33, 88, -104, 3, -77, -30, -27, 23, 92, -69, 12, -23, -9, 125, 2, 3, 1, 0, 1, -93, -126, 2, -81, 48, -126, 2, -85, 48, 11, 6, 3, 85, 29, 15, 4, 4, 3, 2, 5, -96, 48, 43, 6, 3, 85, 29, 16, 4, 36, 48, 34, -128, 15, 50, 48, 48, 57, 48, 52, 50, 57, 49, 53, 50, 54, 53, 57, 90, -127, 15, 50, 48, 49, 49, 48, 53, 48, 53, 49, 53, 53, 54, 53, 55, 90, 48, 19, 6, 3, 85, 29, 37, 4, 12, 48, 10, 6, 8, 43, 6, 1, 5, 5, 7, 3, 1, 48, 51, 6, 3, 85, 29, 31, 4, 44, 48, 42, 48, 40, -96, 38, -96, 36, -122, 34, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 108, 101, 118, 101, 108, 49, 98, 46, 99, 114, 108, 48, 100, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 88, 48, 86, 48, 35, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, -122, 23, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 48, 47, 6, 8, 43, 6, 1, 5, 5, 7, 48, 2, -122, 35, 104, 116, 116, 112, 58, 47, 47, 97, 105, 97, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 50, 48, 52, 56, 45, 108, 49, 98, 46, 99, 101, 114, 48, -126, 1, 87, 6, 3, 85, 29, 32, 4, -126, 1, 78, 48, -126, 1, 74, 48, -126, 1, 70, 6, 9, 42, -122, 72, -122, -10, 125, 7, 75, 2, 48, -126, 1, 55, 48, 38, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 26, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 99, 112, 115, 48, -126, 1, 11, 6, 8, 43, 6, 1, 5, 5, 7, 2, 2, 48, -127, -2, 26, -127, -5, 84, 104, 101, 32, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 80, 114, 97, 99, 116, 105, 99, 101, 32, 83, 116, 97, 116, 101, 109, 101, 110, 116, 32, 40, 67, 80, 83, 41, 32, 97, 118, 97, 105, 108, 97, 98, 108, 101, 32, 97, 116, 32, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 99, 112, 115, 32, 32, 105, 115, 32, 104, 101, 114, 101, 98, 121, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 105, 110, 116, 111, 32, 121, 111, 117, 114, 32, 117, 115, 101, 32, 111, 114, 32, 114, 101, 108, 105, 97, 110, 99, 101, 32, 111, 110, 32, 116, 104, 105, 115, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 101, 46, 32, 32, 84, 104, 105, 115, 32, 67, 80, 83, 32, 99, 111, 110, 116, 97, 105, 110, 115, 32, 108, 105, 109, 105, 116, 97, 116, 105, 111, 110, 115, 32, 111, 110, 32, 119, 97, 114, 114, 97, 110, 116, 105, 101, 115, 32, 97, 110, 100, 32, 108, 105, 97, 98, 105, 108, 105, 116, 105, 101, 115, 46, 32, 67, 111, 112, 121, 114, 105, 103, 104, 116, 32, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 32, 76, 105, 109, 105, 116, 101, 100, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, -11, -14, -106, -120, 125, 13, -13, 42, -7, 78, -25, 52, -96, -67, 70, 126, 19, -42, 22, -56, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 68, 101, 26, -23, -69, -107, 32, 89, 18, 28, -123, 32, 74, -116, -33, -48, 70, -52, 68, 77, 48, 9, 6, 3, 85, 29, 19, 4, 2, 48, 0, 48, 25, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 12, 48, 10, 27, 4, 86, 55, 46, 49, 3, 2, 3, 40, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 18, 56, 92, -74, -100, -56, 95, 121, 27, -84, -88, -104, -27, -98, -12, 58, 48, -26, 40, -7, 25, -68, -124, -104, -54, -121, 84, 52, 3, 22, -106, 88, 44, -39, 126, 17, 96, 4, -41, -84, -101, 74, -92, -113, -12, -99, 77, 108, -30, 38, 19, 78, 48, 32, -126, 95, -10, -114, 58, 98, -49, -108, -109, -87, 5, -80, -43, 121, 21, -99, 43, -73, 26, 51, 31, 87, -38, -119, 78, -113, -59, -100, -118, -84, -46, -48, 93, 99, 2, 40, -39, 76, -48, -122, -60, -25, -73, 103, 126, 83, -86, -26, 66, 122, -65, -89, -102, 115, 105, -124, -85, -18, -66, 85, 30, -29, -96, 104, 65, -66, 40, 69, -91, 101, -19, 39, -86, -21, -18, 39, 51, -1, 36, -52, 53, -65, 53, 12, -62, -97, -45, -26, 113, -20, 102, 56, 102, 104, 37, 17, 57, -96, -83, -71, 106, 63, -64, -122, 61, 59, 8, -123, 108, 22, 62, -58, -105, 88, 38, 96, -6, -29, -114, 105, 110, -102, -72, 109, -33, 56, 61, 52, 70, -75, -92, 97, -9, -6, -64, 53, -76, 81, -100, 90, -50, 19, -87, 30, -24, -53, 109, -75, 45, -38, 14, 119, -31, 44, -30, -93, -76, 14, 97, -53, -107, 60, 30, -102, 68, 12, 26, 76, -114, 73, -13, -127, 21, 94, -42, 94, 30, -50, -3, 116, 41, -3, -89, 23, -27, -49, -3, -95, 119, -104, -45, 112, 35, 66, 59, 84, 116, 19, -102, -68, -104, 1 }, + new byte[] { 48, -126, 5, -111, 48, -126, 4, 121, -96, 3, 2, 1, 2, 2, 4, 56, 99, -59, -82, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 48, 56, 48, 56, 50, 53, 49, 56, 49, 52, 50, 54, 90, 23, 13, 49, 56, 48, 56, 50, 53, 49, 56, 52, 52, 50, 54, 90, 48, -126, 1, 52, 49, 11, 48, 9, 6, 3, 85, 4, 6, 19, 2, 85, 83, 49, 22, 48, 20, 6, 3, 85, 4, 10, 19, 13, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 56, 48, 54, 6, 3, 85, 4, 11, 19, 47, 65, 78, 68, 32, 65, 68, 68, 73, 84, 73, 79, 78, 65, 76, 32, 84, 69, 82, 77, 83, 32, 71, 79, 86, 69, 82, 78, 73, 78, 71, 32, 85, 83, 69, 32, 65, 78, 68, 32, 82, 69, 76, 73, 65, 78, 67, 69, 49, 71, 48, 69, 6, 3, 85, 4, 11, 19, 62, 67, 80, 83, 32, 67, 79, 78, 84, 65, 73, 78, 83, 32, 73, 77, 80, 79, 82, 84, 65, 78, 84, 32, 76, 73, 77, 73, 84, 65, 84, 73, 79, 78, 83, 32, 79, 70, 32, 87, 65, 82, 82, 65, 78, 84, 73, 69, 83, 32, 65, 78, 68, 32, 76, 73, 65, 66, 73, 76, 73, 84, 89, 49, 57, 48, 55, 6, 3, 85, 4, 11, 19, 48, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 32, 105, 115, 32, 105, 110, 99, 111, 114, 112, 111, 114, 97, 116, 101, 100, 32, 98, 121, 32, 114, 101, 102, 101, 114, 101, 110, 99, 101, 49, 31, 48, 29, 6, 3, 85, 4, 11, 19, 22, 40, 99, 41, 32, 50, 48, 48, 56, 32, 69, 110, 116, 114, 117, 115, 116, 44, 32, 73, 110, 99, 46, 49, 46, 48, 44, 6, 3, 85, 4, 3, 19, 37, 69, 110, 116, 114, 117, 115, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 45, 32, 76, 49, 66, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -36, 33, -11, 104, -7, 122, -50, -121, -14, 120, -33, -40, 59, 77, 6, 125, -58, 36, -28, -87, -51, -99, 1, 86, -28, -10, 113, 23, -86, 127, 117, 34, 24, -28, 116, 109, 27, 62, 86, -43, -79, -90, 30, -35, 89, 38, 83, -54, 6, -26, -70, 11, 111, 55, -69, -88, -58, -100, 21, 59, 6, 27, -121, 12, -62, 26, 77, -45, -127, -82, -37, 80, 101, -91, 58, 100, 79, 48, 52, -102, 43, -87, 31, -3, 43, -47, 56, 113, 25, 104, -14, -114, -21, 123, -55, 64, 60, 72, -60, 25, -79, -73, 16, 37, -17, 68, -89, -26, 119, -101, 125, 34, -102, -34, -40, 94, -39, -61, -50, -55, 113, 34, -69, -82, -17, 5, -42, -14, 23, -25, 86, 120, -31, 83, 5, 74, 38, 115, -72, -57, 73, 103, -109, 35, 15, 86, -78, -113, -35, -55, 89, 5, -27, 99, 21, -76, -121, 126, 64, 70, -23, -75, 0, 123, 3, -76, 13, -28, -106, 103, 44, -34, 27, 89, 11, 26, 31, -72, 99, 68, -82, -63, -41, 68, -121, -60, -111, 89, -100, 0, 67, 109, -58, -33, 10, -80, -79, 4, -51, -2, -66, 48, 94, 58, 37, 114, -35, -94, 62, -19, 70, 58, -57, -92, 92, 92, -28, 37, -14, 19, 7, -24, -82, -38, -101, 25, -101, -94, -39, 96, -99, -50, -112, 71, 106, 97, 123, 64, -24, 20, -62, -2, 47, -124, 90, 102, 23, -64, -105, -45, 73, 56, -34, 99, 2, -97, 2, 3, 1, 0, 1, -93, -126, 1, 38, 48, -126, 1, 34, 48, 14, 6, 3, 85, 29, 15, 1, 1, -1, 4, 4, 3, 2, 1, 6, 48, 15, 6, 3, 85, 29, 19, 1, 1, -1, 4, 5, 48, 3, 1, 1, -1, 48, 51, 6, 8, 43, 6, 1, 5, 5, 7, 1, 1, 4, 39, 48, 37, 48, 35, 6, 8, 43, 6, 1, 5, 5, 7, 48, 1, -122, 23, 104, 116, 116, 112, 58, 47, 47, 111, 99, 115, 112, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 48, 50, 6, 3, 85, 29, 31, 4, 43, 48, 41, 48, 39, -96, 37, -96, 35, -122, 33, 104, 116, 116, 112, 58, 47, 47, 99, 114, 108, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 50, 48, 52, 56, 99, 97, 46, 99, 114, 108, 48, 59, 6, 3, 85, 29, 32, 4, 52, 48, 50, 48, 48, 6, 4, 85, 29, 32, 0, 48, 40, 48, 38, 6, 8, 43, 6, 1, 5, 5, 7, 2, 1, 22, 26, 104, 116, 116, 112, 58, 47, 47, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, -11, -14, -106, -120, 125, 13, -13, 42, -7, 78, -25, 52, -96, -67, 70, 126, 19, -42, 22, -56, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 25, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 12, 48, 10, 27, 4, 86, 55, 46, 49, 3, 2, 0, -127, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 11, 37, 60, 88, -6, -114, -36, -94, 66, 59, 118, 113, 110, 108, -44, 79, 43, -71, 83, 92, -78, 88, -71, -79, -36, 111, 26, -28, -29, -60, 80, -14, 65, -126, -70, -12, 125, -57, -63, -7, -6, -116, 83, -65, -71, 98, -73, 73, -29, 29, 10, -4, 31, -42, -60, 118, 106, -109, -53, 119, 30, 44, 127, -48, 63, 22, 99, 76, 114, 76, 103, 96, 15, -8, -128, -42, -89, -102, -54, -94, 51, -111, 15, 68, -78, 102, 61, -114, 104, 12, 64, -123, 18, 55, -111, -71, -126, 119, 52, 89, 45, 92, -33, -126, 110, 44, -74, 122, -46, 4, -112, 103, 104, 75, 112, -4, 45, -72, -1, -112, 100, 111, 126, -111, -9, -47, 71, 51, -13, 91, -72, 88, 46, 33, -40, 117, 96, 27, 19, -52, -8, -78, -88, -6, 106, -87, 42, 90, 79, 69, -123, 64, -76, -35, 52, 5, -73, 112, -54, 1, -17, -31, -127, -25, 17, 80, -37, 62, -30, -41, 16, 46, 106, 21, 127, -73, -44, -93, 98, -78, -119, 105, 97, 87, -58, 127, -114, -98, -44, 36, 122, -13, -95, 67, 95, -96, 122, -119, -36, 89, -51, 125, -41, 117, -89, -68, 83, -43, 71, 53, -58, 49, 48, 32, -97, -101, -70, -75, -125, -26, -119, 85, 1, 77, -111, 59, -42, -119, 53, -121, 60, -125, 107, 122, 41, -126, -44, 75, -44, -26, 22, 116, -80, 1, 16, -85, 105, 6, 20, 55, 123, -9, 102, 48, 58, -59 }, + new byte[] { 48, -126, 4, 92, 48, -126, 3, 68, -96, 3, 2, 1, 2, 2, 4, 56, 99, -71, 102, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 57, 57, 49, 50, 50, 52, 49, 55, 53, 48, 53, 49, 90, 23, 13, 49, 57, 49, 50, 50, 52, 49, 56, 50, 48, 53, 49, 90, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -83, 77, 75, -87, 18, -122, -78, -22, -93, 32, 7, 21, 22, 100, 42, 43, 75, -47, -65, 11, 74, 77, -114, -19, -128, 118, -91, 103, -73, 120, 64, -64, 115, 66, -56, 104, -64, -37, 83, 43, -35, 94, -72, 118, -104, 53, -109, -117, 26, -99, 124, 19, 58, 14, 31, 91, -73, 30, -49, -27, 36, 20, 30, -79, -127, -87, -115, 125, -72, -52, 107, 75, 3, -15, 2, 12, -36, -85, -91, 64, 36, 0, 127, 116, -108, -95, -99, 8, 41, -77, -120, 11, -11, -121, 119, -99, 85, -51, -28, -61, 126, -41, 106, 100, -85, -123, 20, -122, -107, 91, -105, 50, 80, 111, 61, -56, -70, 102, 12, -29, -4, -67, -72, 73, -63, 118, -119, 73, 25, -3, -64, -88, -67, -119, -93, 103, 47, -58, -97, -68, 113, 25, 96, -72, 45, -23, 44, -55, -112, 118, 102, 123, -108, -30, -81, 120, -42, 101, 83, 93, 60, -42, -100, -78, -49, 41, 3, -7, 47, -92, 80, -78, -44, 72, -50, 5, 50, 85, -118, -3, -78, 100, 76, 14, -28, -104, 7, 117, -37, 127, -33, -71, 8, 85, 96, -123, 48, 41, -7, 123, 72, -92, 105, -122, -29, 53, 63, 30, -122, 93, 122, 122, 21, -67, -17, 0, -114, 21, 34, 84, 23, 0, -112, 38, -109, -68, 14, 73, 104, -111, -65, -8, 71, -45, -99, -107, 66, -63, 14, 77, -33, 111, 38, -49, -61, 24, 33, 98, 102, 67, 112, -42, -43, -64, 7, -31, 2, 3, 1, 0, 1, -93, 116, 48, 114, 48, 17, 6, 9, 96, -122, 72, 1, -122, -8, 66, 1, 1, 4, 4, 3, 2, 0, 7, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 16, 48, 14, 27, 8, 86, 53, 46, 48, 58, 52, 46, 48, 3, 2, 4, -112, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 89, 71, -84, 33, -124, -118, 23, -55, -100, -119, 83, 30, -70, -128, -123, 26, -58, 60, 78, 62, -79, -100, -74, 124, -58, -110, 93, 24, 100, 2, -29, -45, 6, 8, 17, 97, 124, 99, -29, 43, -99, 49, 3, 112, 118, -46, -93, 40, -96, -12, -69, -102, 99, 115, -19, 109, -27, 42, -37, -19, 20, -87, 43, -58, 54, 17, -48, 43, -21, 7, -117, -91, -38, -98, 92, 25, -99, 86, 18, -11, 84, 41, -56, 5, -19, -78, 18, 42, -115, -12, 3, 27, -1, -25, -110, 16, -121, -80, 58, -75, -61, -99, 5, 55, 18, -93, -57, -12, 21, -71, -43, -92, 57, 22, -101, 83, 58, 35, -111, -15, -88, -126, -94, 106, -120, 104, -63, 121, 2, 34, -68, -86, -90, -42, -82, -33, -80, 20, 95, -72, -121, -48, -35, 124, 127, 123, -1, -81, 28, -49, -26, -37, 7, -83, 94, -37, -123, -99, -48, 43, 13, 51, -37, 4, -47, -26, 73, 64, 19, 43, 118, -5, 62, -23, -100, -119, 15, 21, -50, 24, -80, -123, 120, 33, 79, 107, 79, 14, -6, 54, 103, -51, 7, -14, -1, 8, -48, -30, -34, -39, -65, 42, -81, -72, -121, -122, 33, 60, 4, -54, -73, -108, 104, 127, -49, 60, -23, -104, -41, 56, -1, -20, -64, -39, 80, -16, 46, 75, 88, -82, 70, 111, -48, 46, -61, 96, -38, 114, 85, 114, -67, 76, 69, -98, 97, -70, -65, -124, -127, -110, 3, -47, -46, 105, 124, -59 }, + }; + + /** + * ASN1-encoded trusted certificate #946059622 for Entrust.net. This + * certificate uses the TELETEX encoding for its X509 name. + */ + private final byte[] trustedCert = new byte[] { 48, -126, 4, 92, 48, -126, 3, 68, -96, 3, 2, 1, 2, 2, 4, 56, 99, -71, 102, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, 30, 23, 13, 57, 57, 49, 50, 50, 52, 49, 55, 53, 48, 53, 49, 90, 23, 13, 49, 57, 49, 50, 50, 52, 49, 56, 50, 48, 53, 49, 90, 48, -127, -76, 49, 20, 48, 18, 6, 3, 85, 4, 10, 19, 11, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 49, 64, 48, 62, 6, 3, 85, 4, 11, 20, 55, 119, 119, 119, 46, 101, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 47, 67, 80, 83, 95, 50, 48, 52, 56, 32, 105, 110, 99, 111, 114, 112, 46, 32, 98, 121, 32, 114, 101, 102, 46, 32, 40, 108, 105, 109, 105, 116, 115, 32, 108, 105, 97, 98, 46, 41, 49, 37, 48, 35, 6, 3, 85, 4, 11, 19, 28, 40, 99, 41, 32, 49, 57, 57, 57, 32, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 76, 105, 109, 105, 116, 101, 100, 49, 51, 48, 49, 6, 3, 85, 4, 3, 19, 42, 69, 110, 116, 114, 117, 115, 116, 46, 110, 101, 116, 32, 67, 101, 114, 116, 105, 102, 105, 99, 97, 116, 105, 111, 110, 32, 65, 117, 116, 104, 111, 114, 105, 116, 121, 32, 40, 50, 48, 52, 56, 41, 48, -126, 1, 34, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 1, 5, 0, 3, -126, 1, 15, 0, 48, -126, 1, 10, 2, -126, 1, 1, 0, -83, 77, 75, -87, 18, -122, -78, -22, -93, 32, 7, 21, 22, 100, 42, 43, 75, -47, -65, 11, 74, 77, -114, -19, -128, 118, -91, 103, -73, 120, 64, -64, 115, 66, -56, 104, -64, -37, 83, 43, -35, 94, -72, 118, -104, 53, -109, -117, 26, -99, 124, 19, 58, 14, 31, 91, -73, 30, -49, -27, 36, 20, 30, -79, -127, -87, -115, 125, -72, -52, 107, 75, 3, -15, 2, 12, -36, -85, -91, 64, 36, 0, 127, 116, -108, -95, -99, 8, 41, -77, -120, 11, -11, -121, 119, -99, 85, -51, -28, -61, 126, -41, 106, 100, -85, -123, 20, -122, -107, 91, -105, 50, 80, 111, 61, -56, -70, 102, 12, -29, -4, -67, -72, 73, -63, 118, -119, 73, 25, -3, -64, -88, -67, -119, -93, 103, 47, -58, -97, -68, 113, 25, 96, -72, 45, -23, 44, -55, -112, 118, 102, 123, -108, -30, -81, 120, -42, 101, 83, 93, 60, -42, -100, -78, -49, 41, 3, -7, 47, -92, 80, -78, -44, 72, -50, 5, 50, 85, -118, -3, -78, 100, 76, 14, -28, -104, 7, 117, -37, 127, -33, -71, 8, 85, 96, -123, 48, 41, -7, 123, 72, -92, 105, -122, -29, 53, 63, 30, -122, 93, 122, 122, 21, -67, -17, 0, -114, 21, 34, 84, 23, 0, -112, 38, -109, -68, 14, 73, 104, -111, -65, -8, 71, -45, -99, -107, 66, -63, 14, 77, -33, 111, 38, -49, -61, 24, 33, 98, 102, 67, 112, -42, -43, -64, 7, -31, 2, 3, 1, 0, 1, -93, 116, 48, 114, 48, 17, 6, 9, 96, -122, 72, 1, -122, -8, 66, 1, 1, 4, 4, 3, 2, 0, 7, 48, 31, 6, 3, 85, 29, 35, 4, 24, 48, 22, -128, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 3, 85, 29, 14, 4, 22, 4, 20, 85, -28, -127, -47, 17, -128, -66, -40, -119, -71, 8, -93, 49, -7, -95, 36, 9, 22, -71, 112, 48, 29, 6, 9, 42, -122, 72, -122, -10, 125, 7, 65, 0, 4, 16, 48, 14, 27, 8, 86, 53, 46, 48, 58, 52, 46, 48, 3, 2, 4, -112, 48, 13, 6, 9, 42, -122, 72, -122, -9, 13, 1, 1, 5, 5, 0, 3, -126, 1, 1, 0, 89, 71, -84, 33, -124, -118, 23, -55, -100, -119, 83, 30, -70, -128, -123, 26, -58, 60, 78, 62, -79, -100, -74, 124, -58, -110, 93, 24, 100, 2, -29, -45, 6, 8, 17, 97, 124, 99, -29, 43, -99, 49, 3, 112, 118, -46, -93, 40, -96, -12, -69, -102, 99, 115, -19, 109, -27, 42, -37, -19, 20, -87, 43, -58, 54, 17, -48, 43, -21, 7, -117, -91, -38, -98, 92, 25, -99, 86, 18, -11, 84, 41, -56, 5, -19, -78, 18, 42, -115, -12, 3, 27, -1, -25, -110, 16, -121, -80, 58, -75, -61, -99, 5, 55, 18, -93, -57, -12, 21, -71, -43, -92, 57, 22, -101, 83, 58, 35, -111, -15, -88, -126, -94, 106, -120, 104, -63, 121, 2, 34, -68, -86, -90, -42, -82, -33, -80, 20, 95, -72, -121, -48, -35, 124, 127, 123, -1, -81, 28, -49, -26, -37, 7, -83, 94, -37, -123, -99, -48, 43, 13, 51, -37, 4, -47, -26, 73, 64, 19, 43, 118, -5, 62, -23, -100, -119, 15, 21, -50, 24, -80, -123, 120, 33, 79, 107, 79, 14, -6, 54, 103, -51, 7, -14, -1, 8, -48, -30, -34, -39, -65, 42, -81, -72, -121, -122, 33, 60, 4, -54, -73, -108, 104, 127, -49, 60, -23, -104, -41, 56, -1, -20, -64, -39, 80, -16, 46, 75, 88, -82, 70, 111, -48, 46, -61, 96, -38, 114, 85, 114, -67, 76, 69, -98, 97, -70, -65, -124, -127, -110, 3, -47, -46, 105, 124, -59 }; + + public void testTrustAndRemoteCertificatesWithDifferentEncodings() + throws IOException, CertificateException, KeyStoreException, + InvalidAlgorithmParameterException, CertPathValidatorException { + + X509CertPathImpl certPath = new X509CertPathImpl(Arrays.asList( + new X509CertImpl(serviceSprintComCertChain[0]), + new X509CertImpl(serviceSprintComCertChain[1]), + new X509CertImpl(serviceSprintComCertChain[2]))); + + Set<TrustAnchor> trustAnchors = new HashSet<TrustAnchor>(); + trustAnchors.add(new TrustAnchor(new X509CertificateObject( + new X509CertificateStructure( + (ASN1Sequence) new ASN1InputStream(trustedCert).readObject())), null)); + + IndexedPKIXParameters indexedPKIXParameters = new IndexedPKIXParameters(trustAnchors); + indexedPKIXParameters.setRevocationEnabled(false); + + new PKIXCertPathValidatorSpi().engineValidate(certPath, indexedPKIXParameters); + // completing normally indicates that the certificate was valid + } +} diff --git a/security/src/test/java/tests/security/AllTests.java b/security/src/test/java/tests/security/AllTests.java index 2a69b59..a88cc0e 100644 --- a/security/src/test/java/tests/security/AllTests.java +++ b/security/src/test/java/tests/security/AllTests.java @@ -32,6 +32,7 @@ public class AllTests { TestSuite suite = tests.TestSuiteFactory.createTestSuite("All security test suites"); // $JUnit-BEGIN$ suite.addTest(org.apache.harmony.security.tests.java.security.AllTests.suite()); + suite.addTest(org.bouncycastle.jce.provider.AllTests.suite()); suite.addTest(tests.api.java.security.AllTests.suite()); suite.addTest(tests.java.security.AllTests.suite()); diff --git a/support/src/test/java/tests/resources/EmptyEntries_signed.jar b/support/src/test/java/tests/resources/EmptyEntries_signed.jar Binary files differnew file mode 100644 index 0000000..237d244 --- /dev/null +++ b/support/src/test/java/tests/resources/EmptyEntries_signed.jar diff --git a/support/src/test/java/tests/support/Support_TestWebServer.java b/support/src/test/java/tests/support/Support_TestWebServer.java index 8ee7248..609e993 100644 --- a/support/src/test/java/tests/support/Support_TestWebServer.java +++ b/support/src/test/java/tests/support/Support_TestWebServer.java @@ -19,9 +19,9 @@ package tests.support; import java.io.*; import java.lang.Thread; import java.net.*; -import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Logger; /** @@ -42,6 +42,10 @@ public class Support_TestWebServer implements Support_HttpConstants { /* Where worker threads stand idle */ Vector threads = new Vector(); + /** maps the recently requested URLs to the full request snapshot */ + private final Map<String, Request> pathToRequest + = new ConcurrentHashMap<String, Request>(); + /* List of all active worker threads */ Vector activeThreads = new Vector(); @@ -206,7 +210,7 @@ public class Support_TestWebServer implements Support_HttpConstants { * a redirect code with the Location response header set to the value * specified. * @param redirect The location to be redirected to - * @param redirectCode The code to send when redirecting + * @param code The code to send when redirecting */ public void setRedirect(String redirect, int code) { redirectHost = redirect; @@ -215,6 +219,14 @@ public class Support_TestWebServer implements Support_HttpConstants { } /** + * Returns a map from recently-requested paths (like "/index.html") to a + * snapshot of the request data. + */ + public Map<String, Request> pathToRequest() { + return pathToRequest; + } + + /** * Cause the thread accepting connections on the server socket to close */ public void close() { @@ -328,6 +340,28 @@ public class Support_TestWebServer implements Support_HttpConstants { static final byte[] EOL = {(byte)'\r', (byte)'\n' }; /** + * An immutable snapshot of an HTTP request. + */ + public static class Request { + private final String path; + private final Map<String, String> headers; + // TODO: include posted content? + + public Request(String path, Map<String, String> headers) { + this.path = path; + this.headers = new LinkedHashMap<String, String>(headers); + } + + public String getPath() { + return path; + } + + public Map<String, String> getHeaders() { + return headers; + } + } + + /** * The worker thread handles all interactions with a current open * connection. If pipelining is turned on, this will allow this * thread to continuously operate on numerous requests before the @@ -347,6 +381,9 @@ public class Support_TestWebServer implements Support_HttpConstants { /* Reference to current requests test file/data */ private String testID; + /* The requested path, such as "/test1" */ + private String path; + /* Reference to test number from testID */ private int testNum; @@ -359,7 +396,7 @@ public class Support_TestWebServer implements Support_HttpConstants { boolean running = false; /* Request headers are stored here */ - private Hashtable<String, String> headers = new Hashtable<String, String>(); + private Map<String, String> headers = new LinkedHashMap<String, String>(); /* Create a new worker thread */ Worker() { @@ -559,10 +596,8 @@ public class Support_TestWebServer implements Support_HttpConstants { i++; } - testID = new String(buf, 0, index, i-index); - if (testID.startsWith("/")) { - testID = testID.substring(1); - } + path = new String(buf, 0, index, i-index); + testID = path.substring(1); return nread; } @@ -601,7 +636,7 @@ public class Support_TestWebServer implements Support_HttpConstants { while (buf[i] == ' ') { i++; } - String headerValue = new String(buf, i, nread-1); + String headerValue = new String(buf, i, nread-i); headers.put(headerName, headerValue); return nread; @@ -666,6 +701,8 @@ public class Support_TestWebServer implements Support_HttpConstants { // If status line found, read any headers nread = readHeaders(is); + pathToRequest().put(path, new Request(path, headers)); + // Then read content (if any) // TODO handle chunked encoding from the client if (headers.get(requestHeaders[REQ_CONTENT_LENGTH]) != null) { diff --git a/support/src/test/java/tests/util/PrefsTester.java b/support/src/test/java/tests/util/PrefsTester.java new file mode 100644 index 0000000..047b357 --- /dev/null +++ b/support/src/test/java/tests/util/PrefsTester.java @@ -0,0 +1,73 @@ +/* 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. + */ + +package tests.util; + +import java.util.prefs.BackingStoreException; +import java.util.prefs.Preferences; +import java.util.Arrays; + +/** + * Prepares the shared preferences store for a test by wiping preference data + * before and after the test. Sample usage: + * <pre> + * public void MyPreferencesTest extends TestCase { + * private final PrefsTester prefsTester = new PrefsTester(); + * + * public void setUp() throws BackingStoreException { + * super.setUp(); + * prefsTester.setUp(); + * } + * + * public void tearDown() throws BackingStoreException { + * prefsTester.tearDown(); + * super.tearDown(); + * } + * + * ... + * }</pre> + * + * <p>Once the preferences classes have been initialized, the path where their + * data is stored is fixed. For that reason, every test that reads or writes + * preferences must first prepare preferences for testing by using this class. + */ +public final class PrefsTester { + + static { + String tmp = System.getProperty("java.io.tmpdir"); + System.setProperty("user.home", tmp); + System.setProperty("java.home", tmp); + } + + public void setUp() throws BackingStoreException { + clear(); + } + + public void tearDown() throws BackingStoreException { + clear(); + } + + private void clear() throws BackingStoreException { + for (Preferences root : Arrays .asList( + Preferences.systemRoot(), Preferences.userRoot())) { + for (String child : root.childrenNames()) { + root.node(child).removeNode(); + } + root.clear(); + root.flush(); + } + } +} diff --git a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp index 8f36632..87f2af3 100644 --- a/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp +++ b/x-net/src/main/native/org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl.cpp @@ -421,7 +421,7 @@ typedef struct app_data { static int sslCreateAppData(SSL* ssl) { APP_DATA* data = (APP_DATA*) malloc(sizeof(APP_DATA)); - memset(data, sizeof(APP_DATA), 0); + memset(data, 0, sizeof(APP_DATA)); data->aliveAndKicking = 1; data->waitingThreads = 0; |