diff --git a/.hgtags b/.hgtags
index 80a9d6813dc09cf2d1f4fb818aa02e8dabc1cc9d..24dc9213f13fbcadddfb2807883e1d9b4f333064 100644
--- a/.hgtags
+++ b/.hgtags
@@ -91,3 +91,5 @@ b53f226b1d91473ac54184afa827be07b87e0319 jdk7-b112
e250cef36ea05e627e7e6f7d75e5e19f529e2ba3 jdk7-b114
449bad8d67b5808ecf0f927683acc0a5940f8c85 jdk7-b115
1657ed4e1d86c8aa2028ab5a41f9da1ac4a369f8 jdk7-b116
+3e6726bbf80a4254ecd01051c8ed77ee19325e46 jdk7-b117
+b357910aa04aead2a16b6d6ff395a8df4b51d1dd jdk7-b118
diff --git a/make/java/java/FILES_java.gmk b/make/java/java/FILES_java.gmk
index f9fdea5cf069d74c50e08d8ea907879eb4679fc8..acbc8a7323098b3ff61ef5d088b3623337f5a4f7 100644
--- a/make/java/java/FILES_java.gmk
+++ b/make/java/java/FILES_java.gmk
@@ -413,6 +413,7 @@ JAVA_JAVA_java = \
java/io/FilePermission.java \
java/io/Serializable.java \
java/io/Externalizable.java \
+ java/io/SerialCallbackContext.java \
java/io/Bits.java \
java/io/ObjectInput.java \
java/io/ObjectInputStream.java \
diff --git a/make/java/jli/Makefile b/make/java/jli/Makefile
index 40ddc17e358d13546e3cb19b1c4aa03a88a42d41..9c1b9bc7c835cb02b629a94ef3b3a3c6dec54e75 100644
--- a/make/java/jli/Makefile
+++ b/make/java/jli/Makefile
@@ -148,14 +148,9 @@ include $(BUILDDIR)/common/Library.gmk
#
ifeq ($(PLATFORM), windows)
-STATIC_LIBRARY_DIR = $(OBJDIR)/static
-STATIC_LIBRARY_NAME = $(LIBPREFIX)$(LIBRARY).lib
-STATIC_LIBRARY = $(STATIC_LIBRARY_DIR)/$(STATIC_LIBRARY_NAME)
+STATIC_LIBRARY = $(OBJDIR)/static/$(LIBPREFIX)$(LIBRARY).lib
-$(STATIC_LIBRARY_DIR): $(OBJDIR)
- @$(MKDIR) $(STATIC_LIBRARY_DIR)
-
-$(STATIC_LIBRARY): $(STATIC_LIBRARY_DIR)
+$(STATIC_LIBRARY): $(FILES_o)
@$(prep-target)
$(LIBEXE) -nologo -out:$@ $(FILES_o)
diff --git a/make/java/nio/FILES_java.gmk b/make/java/nio/FILES_java.gmk
index e49d5267a4761ffce938d64aaedb157615ce3a4c..5a00e3172f3c8c0a080f0ae53f39637bf37803a3 100644
--- a/make/java/nio/FILES_java.gmk
+++ b/make/java/nio/FILES_java.gmk
@@ -33,7 +33,6 @@ FILES_src = \
java/nio/channels/AsynchronousByteChannel.java \
java/nio/channels/AsynchronousChannel.java \
java/nio/channels/AsynchronousChannelGroup.java \
- java/nio/channels/AsynchronousDatagramChannel.java \
java/nio/channels/AsynchronousFileChannel.java \
java/nio/channels/AsynchronousServerSocketChannel.java \
java/nio/channels/AsynchronousSocketChannel.java \
@@ -207,7 +206,6 @@ FILES_src = \
sun/nio/ch/SelChImpl.java \
sun/nio/ch/ServerSocketAdaptor.java \
sun/nio/ch/ServerSocketChannelImpl.java \
- sun/nio/ch/SimpleAsynchronousDatagramChannelImpl.java \
sun/nio/ch/SinkChannelImpl.java \
sun/nio/ch/SocketAdaptor.java \
sun/nio/ch/SocketChannelImpl.java \
diff --git a/make/netbeans/jmx/build.properties b/make/netbeans/jmx/build.properties
index fc36497359e8f100b719c0dfa6f59bc48b88a966..e998e58a17f7355fbe1e1b4b589e95af2f7188d3 100644
--- a/make/netbeans/jmx/build.properties
+++ b/make/netbeans/jmx/build.properties
@@ -48,8 +48,8 @@ jar.jmx.name = jmx.jar
jar.jmx.sealed = true
jar.jmx.spec.title = JSR 003, 160, 255 - JMX API
jar.jmx.spec.version = ${project.spec.version}
-jar.jmx.spec.vendor = Sun Microsystems, Inc.
-jar.jmx.impl.title = JSR 003, 160, 255 - OpenJDK 7 JMX API
+jar.jmx.spec.vendor = Oracle Corporation
+jar.jmx.impl.title = JSR 003, 160, 255 - OpenJDK 7 JMX API
jar.jmx.impl.vendor = Project OpenJDK
javadoc.options=-J-Xmx256m
diff --git a/src/share/bin/java.c b/src/share/bin/java.c
index 4c61fb7c8534f788cf05d49ada742b9014c69843..01eeb2a0547ab076b0db300e7e2eed29c301f54f 100644
--- a/src/share/bin/java.c
+++ b/src/share/bin/java.c
@@ -355,7 +355,6 @@ JavaMain(void * _args)
JavaVM *vm = 0;
JNIEnv *env = 0;
- jstring mainClassName;
jclass mainClass;
jmethodID mainID;
jobjectArray mainArgs;
diff --git a/src/share/bin/parse_manifest.c b/src/share/bin/parse_manifest.c
index 2c916d87cb5c33226f93c8088f5baadd279f9880..61b8bdb6b6942e55e32f7eafd3fd3fb6363367ba 100644
--- a/src/share/bin/parse_manifest.c
+++ b/src/share/bin/parse_manifest.c
@@ -72,7 +72,7 @@ inflate_file(int fd, zentry *entry, int *size_out)
if (entry->how == STORED) {
*(char *)((size_t)in + entry->csize) = '\0';
if (size_out) {
- *size_out = entry->csize;
+ *size_out = (int)entry->csize;
}
return (in);
} else if (entry->how == DEFLATED) {
@@ -103,7 +103,7 @@ inflate_file(int fd, zentry *entry, int *size_out)
return (NULL);
}
if (size_out) {
- *size_out = entry->isize;
+ *size_out = (int)entry->isize;
}
return (out);
} else
@@ -317,7 +317,7 @@ find_file(int fd, zentry *entry, const char *file_name)
* manifest. If so, build the entry record from the data found in
* the header located and return success.
*/
- if (CENNAM(p) == JLI_StrLen(file_name) &&
+ if ((size_t)CENNAM(p) == JLI_StrLen(file_name) &&
memcmp((p + CENHDR), file_name, JLI_StrLen(file_name)) == 0) {
if (lseek(fd, base_offset + CENOFF(p), SEEK_SET) < (off_t)0) {
free(buffer);
@@ -606,8 +606,5 @@ JLI_ManifestIterate(const char *jarfile, attribute_closure ac, void *user_data)
}
free(mp);
close(fd);
- if (rc == 0)
- return (0);
- else
- return (-2);
+ return (rc == 0) ? 0 : -2;
}
diff --git a/src/share/bin/wildcard.c b/src/share/bin/wildcard.c
index 3abcd18a97c7168c7ca8283ed7ff5f2d0c582ae1..0d834e635b5c5cf70d9c003e3cefb96b463f22f3 100644
--- a/src/share/bin/wildcard.c
+++ b/src/share/bin/wildcard.c
@@ -290,12 +290,12 @@ FileList_join(FileList fl, char sep)
char *path;
char *p;
for (i = 0, size = 1; i < fl->size; i++)
- size += JLI_StrLen(fl->files[i]) + 1;
+ size += (int)JLI_StrLen(fl->files[i]) + 1;
path = JLI_MemAlloc(size);
for (i = 0, p = path; i < fl->size; i++) {
- int len = JLI_StrLen(fl->files[i]);
+ int len = (int)JLI_StrLen(fl->files[i]);
if (i > 0) *p++ = sep;
memcpy(p, fl->files[i], len);
p += len;
@@ -309,7 +309,7 @@ static FileList
FileList_split(const char *path, char sep)
{
const char *p, *q;
- int len = JLI_StrLen(path);
+ int len = (int)JLI_StrLen(path);
int count;
FileList fl;
for (count = 1, p = path; p < path + len; p++)
@@ -330,7 +330,7 @@ FileList_split(const char *path, char sep)
static int
isJarFileName(const char *filename)
{
- int len = JLI_StrLen(filename);
+ int len = (int)JLI_StrLen(filename);
return (len >= 4) &&
(filename[len - 4] == '.') &&
(equal(filename + len - 3, "jar") ||
@@ -342,8 +342,8 @@ isJarFileName(const char *filename)
static char *
wildcardConcat(const char *wildcard, const char *basename)
{
- int wildlen = JLI_StrLen(wildcard);
- int baselen = JLI_StrLen(basename);
+ int wildlen = (int)JLI_StrLen(wildcard);
+ int baselen = (int)JLI_StrLen(basename);
char *filename = (char *) JLI_MemAlloc(wildlen + baselen);
/* Replace the trailing '*' with basename */
memcpy(filename, wildcard, wildlen-1);
@@ -369,7 +369,7 @@ wildcardFileList(const char *wildcard)
static int
isWildcard(const char *filename)
{
- int len = JLI_StrLen(filename);
+ int len = (int)JLI_StrLen(filename);
return (len > 0) &&
(filename[len - 1] == '*') &&
(len == 1 || IS_FILE_SEPARATOR(filename[len - 2])) &&
diff --git a/src/share/classes/com/sun/crypto/provider/AESCrypt.java b/src/share/classes/com/sun/crypto/provider/AESCrypt.java
index 9bf9c42ae38b30528219c69234e22ce047ec70a6..0940817376b6a11e253295c305aa97d38b5c1a2a 100644
--- a/src/share/classes/com/sun/crypto/provider/AESCrypt.java
+++ b/src/share/classes/com/sun/crypto/provider/AESCrypt.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -253,7 +253,8 @@ final class AESCrypt extends SymmetricCipher implements AESConstants
for (j = 0; j < 8; j++) {
if (AA[i][j] != 0) {
AA[i][j] = (byte)
- alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF]) % 255];
+ alog[(255 + log[AA[i][j] & 0xFF] - log[pivot & 0xFF])
+ % 255];
}
}
for (t = 0; t < 4; t++) {
diff --git a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
index a474e8c00a77f55eb969af2cd503dd37abb57237..f5b99c1ae51b904b23c904026aa203b95ecf17ed 100644
--- a/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
+++ b/src/share/classes/com/sun/crypto/provider/ARCFOURCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -92,7 +92,8 @@ public final class ARCFOURCipher extends CipherSpi {
}
// core crypt code. OFB style, so works for both encryption and decryption
- private void crypt(byte[] in, int inOfs, int inLen, byte[] out, int outOfs) {
+ private void crypt(byte[] in, int inOfs, int inLen, byte[] out,
+ int outOfs) {
if (is < 0) {
// doFinal() was called, need to reset the cipher to initial state
init(lastKey);
diff --git a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
index 0d75742bd2702d2c3e3b346846911cd51c592580..135ed24d3eed5f9e497e5cf095fa09907e003c28 100644
--- a/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
+++ b/src/share/classes/com/sun/crypto/provider/DESedeCipher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,8 +31,8 @@ import javax.crypto.*;
import javax.crypto.spec.*;
/**
- * This class implements the DESede algorithm (DES-EDE, tripleDES) in its various
- * modes (ECB, CFB, OFB,
+ * This class implements the DESede algorithm (DES-EDE, tripleDES) in
+ * its various modes (ECB, CFB, OFB,
* CBC, PCBC) and padding schemes
* (PKCS5Padding, NoPadding,
* ISO10126Padding).
diff --git a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
index f83ae597b52ea68c7839653d94eeac74fefa379a..4af003d68ae791e3c26298b7a556bb925c0cbb7f 100644
--- a/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
+++ b/src/share/classes/com/sun/crypto/provider/DHPrivateKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -190,7 +190,8 @@ javax.crypto.interfaces.DHPrivateKey, Serializable {
ike.initCause(e);
throw ike;
} catch (IOException e) {
- InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+ InvalidKeyException ike = new InvalidKeyException(
+ "Error parsing key encoding: " + e.getMessage());
ike.initCause(e);
throw ike;
}
@@ -300,7 +301,8 @@ javax.crypto.interfaces.DHPrivateKey, Serializable {
DerInputStream in = new DerInputStream(this.key);
this.x = in.getBigInteger();
} catch (IOException e) {
- InvalidKeyException ike = new InvalidKeyException("Error parsing key encoding: " + e.getMessage());
+ InvalidKeyException ike = new InvalidKeyException(
+ "Error parsing key encoding: " + e.getMessage());
ike.initCause(e);
throw ike;
}
diff --git a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
index 9318fbd8caf59919ecc412d3a2f684b810c267d4..46bf6024dd446f3652ff700a81cfea236e72b790 100644
--- a/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
+++ b/src/share/classes/com/sun/crypto/provider/DHPublicKey.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -180,7 +180,8 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
throw new InvalidKeyException("Private-value length too big");
} catch (IOException e) {
- throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+ throw new InvalidKeyException(
+ "Error parsing key encoding: " + e.toString());
}
}
@@ -281,7 +282,8 @@ javax.crypto.interfaces.DHPublicKey, Serializable {
DerInputStream in = new DerInputStream(this.key);
this.y = in.getBigInteger();
} catch (IOException e) {
- throw new InvalidKeyException("Error parsing key encoding: " + e.toString());
+ throw new InvalidKeyException(
+ "Error parsing key encoding: " + e.toString());
}
}
diff --git a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
index 5d54688069914ee0cbca6bd7208f386c44cdc31a..1f37e18579661251f15454cb9036a4af64aff0f1 100644
--- a/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
+++ b/src/share/classes/com/sun/crypto/provider/JceKeyStore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -764,7 +764,8 @@ public final class JceKeyStore extends KeyStoreSpi {
cf = (CertificateFactory)cfs.get(certType);
} else {
// create new certificate factory
- cf = CertificateFactory.getInstance(certType);
+ cf = CertificateFactory.getInstance(
+ certType);
// store the certificate factory so we can
// reuse it later
cfs.put(certType, cf);
@@ -863,8 +864,9 @@ public final class JceKeyStore extends KeyStoreSpi {
dis.readFully(actual);
for (int i = 0; i < computed.length; i++) {
if (computed[i] != actual[i]) {
- throw new IOException("Keystore was tampered with, or "
- + "password was incorrect");
+ throw new IOException(
+ "Keystore was tampered with, or "
+ + "password was incorrect");
}
}
}
diff --git a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
index 65a85e753315ed68b10c598d457c11c2ecc865c8..07d613babe8b757f1759e5c23f3c092ef0238b58 100644
--- a/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
+++ b/src/share/classes/com/sun/crypto/provider/OAEPParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -139,7 +139,8 @@ public final class OAEPParameters extends AlgorithmParametersSpi {
if (!val.getOID().equals((Object) OID_MGF1)) {
throw new IOException("Only MGF1 mgf is supported");
}
- AlgorithmId params = AlgorithmId.parse(new DerValue(val.getEncodedParams()));
+ AlgorithmId params = AlgorithmId.parse(
+ new DerValue(val.getEncodedParams()));
String mgfDigestName = convertToStandardName(params.getName());
if (mgfDigestName.equals("SHA-1")) {
mgfSpec = MGF1ParameterSpec.SHA1;
@@ -150,7 +151,8 @@ public final class OAEPParameters extends AlgorithmParametersSpi {
} else if (mgfDigestName.equals("SHA-512")) {
mgfSpec = MGF1ParameterSpec.SHA512;
} else {
- throw new IOException("Unrecognized message digest algorithm");
+ throw new IOException(
+ "Unrecognized message digest algorithm");
}
} else if (data.isContextSpecific((byte) 0x02)) {
// pSource algid
diff --git a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
index c5c0d844912f832de73bb0483fecc4a45060a282..7f74609c002aeb0720e7d23a4ce6190a0ecfe536 100644
--- a/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
+++ b/src/share/classes/com/sun/crypto/provider/PBKDF2KeyImpl.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -121,8 +121,8 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
this.key = deriveKey(prf, passwdBytes, salt, iterCount, keyLength);
}
- private static byte[] deriveKey(final Mac prf, final byte[] password, byte[] salt,
- int iterCount, int keyLengthInBit) {
+ private static byte[] deriveKey(final Mac prf, final byte[] password,
+ byte[] salt, int iterCount, int keyLengthInBit) {
int keyLength = keyLengthInBit/8;
byte[] key = new byte[keyLength];
try {
@@ -155,8 +155,9 @@ final class PBKDF2KeyImpl implements javax.crypto.interfaces.PBEKey {
if (this == obj) return true;
if (this.getClass() != obj.getClass()) return false;
SecretKey sk = (SecretKey)obj;
- return prf.getAlgorithm().equalsIgnoreCase(sk.getAlgorithm()) &&
- Arrays.equals(password, sk.getEncoded());
+ return prf.getAlgorithm().equalsIgnoreCase(
+ sk.getAlgorithm()) &&
+ Arrays.equals(password, sk.getEncoded());
}
};
prf.init(macKey);
diff --git a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
index fce352f1d3c651a58ca24762fca9c3d2585e88eb..e091e90e2c116835e891e9c3150ffe74172658ef 100644
--- a/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
+++ b/src/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -206,7 +206,8 @@ final class PKCS12PBECipherCore {
(algo.equalsIgnoreCase("RC2")?"RC2_40":algo), "SunJCE");
} catch (GeneralSecurityException gse) {
// should never happen
- throw new RuntimeException("SunJCE provider is not configured properly");
+ throw new RuntimeException(
+ "SunJCE provider is not configured properly");
}
try {
params.init(pbeSpec);
@@ -316,7 +317,8 @@ final class PKCS12PBECipherCore {
try {
paramSpec = params.getParameterSpec(PBEParameterSpec.class);
} catch (InvalidParameterSpecException ipse) {
- throw new InvalidAlgorithmParameterException("requires PBE parameters");
+ throw new InvalidAlgorithmParameterException(
+ "requires PBE parameters");
}
}
implInit(opmode, key, paramSpec, random);
diff --git a/src/share/classes/com/sun/crypto/provider/SunJCE.java b/src/share/classes/com/sun/crypto/provider/SunJCE.java
index df68b11aaebfbbb1e254e9d84c15c6c8a13918b9..4b53f84fedc0fc63cc1ee933503afb3b3e2551a5 100644
--- a/src/share/classes/com/sun/crypto/provider/SunJCE.java
+++ b/src/share/classes/com/sun/crypto/provider/SunJCE.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -423,15 +423,31 @@ public final class SunJCE extends Provider {
/*
* SSL/TLS mechanisms
+ *
+ * These are strictly internal implementations and may
+ * be changed at any time. These names were chosen
+ * because PKCS11/SunPKCS11 does not yet have TLS1.2
+ * mechanisms, and it will cause calls to come here.
*/
put("KeyGenerator.SunTlsPrf",
- "com.sun.crypto.provider.TlsPrfGenerator");
- put("KeyGenerator.SunTlsRsaPremasterSecret",
- "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+ "com.sun.crypto.provider.TlsPrfGenerator$V10");
+ put("KeyGenerator.SunTls12Prf",
+ "com.sun.crypto.provider.TlsPrfGenerator$V12");
+
put("KeyGenerator.SunTlsMasterSecret",
- "com.sun.crypto.provider.TlsMasterSecretGenerator");
+ "com.sun.crypto.provider.TlsMasterSecretGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12MasterSecret",
+ "SunTlsMasterSecret");
+
put("KeyGenerator.SunTlsKeyMaterial",
- "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+ "com.sun.crypto.provider.TlsKeyMaterialGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12KeyMaterial",
+ "SunTlsKeyMaterial");
+
+ put("KeyGenerator.SunTlsRsaPremasterSecret",
+ "com.sun.crypto.provider.TlsRsaPremasterSecretGenerator");
+ put("Alg.Alias.KeyGenerator.SunTls12RsaPremasterSecret",
+ "SunTlsRsaPremasterSecret");
return null;
}
diff --git a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
index 91a8d3b5a99230eb3e248c5a5236e92e67ed0202..8e4f6a15d8e5f7dfd1cc07bc8319c60128bf3834 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsKeyMaterialGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -65,12 +65,14 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
}
this.spec = (TlsKeyMaterialParameterSpec)params;
if ("RAW".equals(spec.getMasterSecret().getFormat()) == false) {
- throw new InvalidAlgorithmParameterException("Key format must be RAW");
+ throw new InvalidAlgorithmParameterException(
+ "Key format must be RAW");
}
- protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
- if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
- throw new InvalidAlgorithmParameterException
- ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+ protocolVersion = (spec.getMajorVersion() << 8)
+ | spec.getMinorVersion();
+ if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
}
}
@@ -80,8 +82,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsKeyMaterialGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsKeyMaterialGenerator must be initialized");
}
try {
return engineGenerateKey0();
@@ -99,8 +101,8 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
SecretKey clientMacKey = null;
SecretKey serverMacKey = null;
SecretKey clientCipherKey = null;
- IvParameterSpec clientIv = null;
SecretKey serverCipherKey = null;
+ IvParameterSpec clientIv = null;
IvParameterSpec serverIv = null;
int macLength = spec.getMacKeyLength();
@@ -109,21 +111,33 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
int keyLength = spec.getCipherKeyLength();
int ivLength = spec.getIvLength();
- int keyBlockLen = macLength + keyLength + (isExportable ? 0 : ivLength);
+ int keyBlockLen = macLength + keyLength
+ + (isExportable ? 0 : ivLength);
keyBlockLen <<= 1;
byte[] keyBlock = new byte[keyBlockLen];
- MessageDigest md5 = MessageDigest.getInstance("MD5");
- MessageDigest sha = MessageDigest.getInstance("SHA1");
+ // These may be used again later for exportable suite calculations.
+ MessageDigest md5 = null;
+ MessageDigest sha = null;
// generate key block
- if (protocolVersion >= 0x0301) {
- // TLS
+ if (protocolVersion >= 0x0303) {
+ // TLS 1.2
+ byte[] seed = concat(serverRandom, clientRandom);
+ keyBlock = doTLS12PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+ keyBlockLen, spec.getPRFHashAlg(),
+ spec.getPRFHashLength(), spec.getPRFBlockSize());
+ } else if (protocolVersion >= 0x0301) {
+ // TLS 1.0/1.1
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA1");
byte[] seed = concat(serverRandom, clientRandom);
- keyBlock = doPRF(masterSecret, LABEL_KEY_EXPANSION, seed,
+ keyBlock = doTLS10PRF(masterSecret, LABEL_KEY_EXPANSION, seed,
keyBlockLen, md5, sha);
} else {
// SSL
+ md5 = MessageDigest.getInstance("MD5");
+ sha = MessageDigest.getInstance("SHA1");
keyBlock = new byte[keyBlockLen];
byte[] tmp = new byte[20];
@@ -169,6 +183,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
String alg = spec.getCipherAlgorithm();
+ // cipher keys
byte[] clientKeyBytes = new byte[keyLength];
System.arraycopy(keyBlock, ofs, clientKeyBytes, 0, keyLength);
ofs += keyLength;
@@ -182,6 +197,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
clientCipherKey = new SecretKeySpec(clientKeyBytes, alg);
serverCipherKey = new SecretKeySpec(serverKeyBytes, alg);
+ // IV keys if needed.
if (ivLength != 0) {
tmp = new byte[ivLength];
@@ -194,21 +210,28 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
serverIv = new IvParameterSpec(tmp);
}
} else {
+ // if exportable suites, calculate the alternate
// cipher key expansion and IV generation
- if (protocolVersion >= 0x0301) {
+ if (protocolVersion >= 0x0302) {
+ // TLS 1.1+
+ throw new RuntimeException(
+ "Internal Error: TLS 1.1+ should not be negotiating" +
+ "exportable ciphersuites");
+ } else if (protocolVersion == 0x0301) {
+ // TLS 1.0
byte[] seed = concat(clientRandom, serverRandom);
- tmp = doPRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
+ tmp = doTLS10PRF(clientKeyBytes, LABEL_CLIENT_WRITE_KEY, seed,
expandedKeyLength, md5, sha);
clientCipherKey = new SecretKeySpec(tmp, alg);
- tmp = doPRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
+ tmp = doTLS10PRF(serverKeyBytes, LABEL_SERVER_WRITE_KEY, seed,
expandedKeyLength, md5, sha);
serverCipherKey = new SecretKeySpec(tmp, alg);
if (ivLength != 0) {
tmp = new byte[ivLength];
- byte[] block = doPRF(null, LABEL_IV_BLOCK, seed,
+ byte[] block = doTLS10PRF(null, LABEL_IV_BLOCK, seed,
ivLength << 1, md5, sha);
System.arraycopy(block, 0, tmp, 0, ivLength);
clientIv = new IvParameterSpec(tmp);
@@ -216,6 +239,7 @@ public final class TlsKeyMaterialGenerator extends KeyGeneratorSpi {
serverIv = new IvParameterSpec(tmp);
}
} else {
+ // SSLv3
tmp = new byte[expandedKeyLength];
md5.update(clientKeyBytes);
diff --git a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
index 9a6fb80180268d0f79b27195d4e423cfbffcd5c1..1d5e97aefbf26d1b5a730c8799bd7a5b68c927c4 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsMasterSecretGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -64,12 +64,14 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
}
this.spec = (TlsMasterSecretParameterSpec)params;
if ("RAW".equals(spec.getPremasterSecret().getFormat()) == false) {
- throw new InvalidAlgorithmParameterException("Key format must be RAW");
+ throw new InvalidAlgorithmParameterException(
+ "Key format must be RAW");
}
- protocolVersion = (spec.getMajorVersion() << 8) | spec.getMinorVersion();
- if ((protocolVersion < 0x0300) || (protocolVersion > 0x0302)) {
- throw new InvalidAlgorithmParameterException
- ("Only SSL 3.0, TLS 1.0, and TLS 1.1 supported");
+ protocolVersion = (spec.getMajorVersion() << 8)
+ | spec.getMinorVersion();
+ if ((protocolVersion < 0x0300) || (protocolVersion > 0x0303)) {
+ throw new InvalidAlgorithmParameterException(
+ "Only SSL 3.0, TLS 1.0/1.1/1.2 supported");
}
}
@@ -79,8 +81,8 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsMasterSecretGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsMasterSecretGenerator must be initialized");
}
SecretKey premasterKey = spec.getPremasterSecret();
byte[] premaster = premasterKey.getEncoded();
@@ -103,7 +105,11 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
if (protocolVersion >= 0x0301) {
byte[] seed = concat(clientRandom, serverRandom);
- master = doPRF(premaster, LABEL_MASTER_SECRET, seed, 48);
+ master = ((protocolVersion >= 0x0303) ?
+ doTLS12PRF(premaster, LABEL_MASTER_SECRET, seed, 48,
+ spec.getPRFHashAlg(), spec.getPRFHashLength(),
+ spec.getPRFBlockSize()) :
+ doTLS10PRF(premaster, LABEL_MASTER_SECRET, seed, 48));
} else {
master = new byte[48];
MessageDigest md5 = MessageDigest.getInstance("MD5");
@@ -124,7 +130,8 @@ public final class TlsMasterSecretGenerator extends KeyGeneratorSpi {
}
- return new TlsMasterSecretKey(master, premasterMajor, premasterMinor);
+ return new TlsMasterSecretKey(master, premasterMajor,
+ premasterMinor);
} catch (NoSuchAlgorithmException e) {
throw new ProviderException(e);
} catch (DigestException e) {
diff --git a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
index f73045e6eb26a357f7df9a261a404422d350dae7..137ba255c339928bf0a15c34efb04ae2a92ce9f6 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsPrfGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,11 +37,15 @@ import sun.security.internal.spec.TlsPrfParameterSpec;
/**
* KeyGenerator implementation for the TLS PRF function.
+ *
+ * This class duplicates the HMAC functionality (RFC 2104) with + * performance optimizations (e.g. XOR'ing keys with padding doesn't + * need to be redone for each HMAC operation). * * @author Andreas Sterbenz * @since 1.6 */ -public final class TlsPrfGenerator extends KeyGeneratorSpi { +abstract class TlsPrfGenerator extends KeyGeneratorSpi { // magic constants and utility functions, also used by other files // in this package @@ -69,8 +73,10 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { * TLS HMAC "inner" and "outer" padding. This isn't a function * of the digest algorithm. */ - private static final byte[] HMAC_ipad = genPad((byte)0x36, 64); - private static final byte[] HMAC_opad = genPad((byte)0x5c, 64); + private static final byte[] HMAC_ipad64 = genPad((byte)0x36, 64); + private static final byte[] HMAC_ipad128 = genPad((byte)0x36, 128); + private static final byte[] HMAC_opad64 = genPad((byte)0x5c, 64); + private static final byte[] HMAC_opad128 = genPad((byte)0x5c, 128); // SSL3 magic mix constants ("A", "BB", "CCC", ...) final static byte[][] SSL3_CONST = genConst(); @@ -123,8 +129,8 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { this.spec = (TlsPrfParameterSpec)params; SecretKey key = spec.getSecret(); if ((key != null) && ("RAW".equals(key.getFormat()) == false)) { - throw new InvalidAlgorithmParameterException - ("Key encoding format must be RAW"); + throw new InvalidAlgorithmParameterException( + "Key encoding format must be RAW"); } } @@ -132,17 +138,21 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { throw new InvalidParameterException(MSG); } - protected SecretKey engineGenerateKey() { + SecretKey engineGenerateKey0(boolean tls12) { if (spec == null) { - throw new IllegalStateException - ("TlsPrfGenerator must be initialized"); + throw new IllegalStateException( + "TlsPrfGenerator must be initialized"); } SecretKey key = spec.getSecret(); byte[] secret = (key == null) ? null : key.getEncoded(); try { byte[] labelBytes = spec.getLabel().getBytes("UTF8"); int n = spec.getOutputLength(); - byte[] prfBytes = doPRF(secret, labelBytes, spec.getSeed(), n); + byte[] prfBytes = (tls12 ? + doTLS12PRF(secret, labelBytes, spec.getSeed(), n, + spec.getPRFHashAlg(), spec.getPRFHashLength(), + spec.getPRFBlockSize()) : + doTLS10PRF(secret, labelBytes, spec.getSeed(), n)); return new SecretKeySpec(prfBytes, "TlsPrf"); } catch (GeneralSecurityException e) { throw new ProviderException("Could not generate PRF", e); @@ -151,16 +161,67 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { } } - static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed, - int outputLength) throws NoSuchAlgorithmException, DigestException { + static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, + String prfHash, int prfHashLength, int prfBlockSize) + throws NoSuchAlgorithmException, DigestException { + if (prfHash == null) { + throw new NoSuchAlgorithmException("Unspecified PRF algorithm"); + } + MessageDigest prfMD = MessageDigest.getInstance(prfHash); + return doTLS12PRF(secret, labelBytes, seed, outputLength, + prfMD, prfHashLength, prfBlockSize); + } + + static byte[] doTLS12PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, + MessageDigest mdPRF, int mdPRFLen, int mdPRFBlockSize) + throws DigestException { + + if (secret == null) { + secret = B0; + } + + // If we have a long secret, digest it first. + if (secret.length > mdPRFBlockSize) { + secret = mdPRF.digest(secret); + } + + byte[] output = new byte[outputLength]; + byte [] ipad; + byte [] opad; + + switch (mdPRFBlockSize) { + case 64: + ipad = HMAC_ipad64.clone(); + opad = HMAC_opad64.clone(); + break; + case 128: + ipad = HMAC_ipad128.clone(); + opad = HMAC_opad128.clone(); + break; + default: + throw new DigestException("Unexpected block size."); + } + + // P_HASH(Secret, label + seed) + expand(mdPRF, mdPRFLen, secret, 0, secret.length, labelBytes, + seed, output, ipad, opad); + + return output; + } + + static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength) throws NoSuchAlgorithmException, + DigestException { MessageDigest md5 = MessageDigest.getInstance("MD5"); MessageDigest sha = MessageDigest.getInstance("SHA1"); - return doPRF(secret, labelBytes, seed, outputLength, md5, sha); + return doTLS10PRF(secret, labelBytes, seed, outputLength, md5, sha); } - static final byte[] doPRF(byte[] secret, byte[] labelBytes, byte[] seed, - int outputLength, MessageDigest md5, MessageDigest sha) - throws DigestException { + static byte[] doTLS10PRF(byte[] secret, byte[] labelBytes, + byte[] seed, int outputLength, MessageDigest md5, + MessageDigest sha) throws DigestException { /* * Split the secret into two halves S1 and S2 of same length. * S1 is taken from the first half of the secret, S2 from the @@ -183,10 +244,12 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { byte[] output = new byte[outputLength]; // P_MD5(S1, label + seed) - expand(md5, 16, secret, 0, seclen, labelBytes, seed, output); + expand(md5, 16, secret, 0, seclen, labelBytes, seed, output, + HMAC_ipad64.clone(), HMAC_opad64.clone()); // P_SHA-1(S2, label + seed) - expand(sha, 20, secret, off, seclen, labelBytes, seed, output); + expand(sha, 20, secret, off, seclen, labelBytes, seed, output, + HMAC_ipad64.clone(), HMAC_opad64.clone()); return output; } @@ -201,16 +264,13 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { * @param seed the seed * @param output the output array */ - private static final void expand(MessageDigest digest, int hmacSize, + private static void expand(MessageDigest digest, int hmacSize, byte[] secret, int secOff, int secLen, byte[] label, byte[] seed, - byte[] output) throws DigestException { + byte[] output, byte[] pad1, byte[] pad2) throws DigestException { /* * modify the padding used, by XORing the key into our copy of that * padding. That's to avoid doing that for each HMAC computation. */ - byte[] pad1 = HMAC_ipad.clone(); - byte[] pad2 = HMAC_opad.clone(); - for (int i = 0; i < secLen; i++) { pad1[i] ^= secret[i + secOff]; pad2[i] ^= secret[i + secOff]; @@ -275,7 +335,34 @@ public final class TlsPrfGenerator extends KeyGeneratorSpi { } remaining -= k; } + } + /** + * A KeyGenerator implementation that supports TLS 1.2. + *
+ * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the PRF
+ * calculations. As of 2010, there is no PKCS11-level support for TLS
+ * 1.2 PRF calculations, and no known OS's have an internal variant
+ * we could use. Therefore for TLS 1.2, we are updating JSSE to request
+ * a different provider algorithm: "SunTls12Prf". If we reused the
+ * name "SunTlsPrf", the PKCS11 provider would need be updated to
+ * fail correctly when presented with the wrong version number
+ * (via Provider.Service.supportsParameters()), and add the
+ * appropriate supportsParamters() checks into KeyGenerators (not
+ * currently there).
+ */
+ static public class V12 extends TlsPrfGenerator {
+ protected SecretKey engineGenerateKey() {
+ return engineGenerateKey0(true);
+ }
}
+ /**
+ * A KeyGenerator implementation that supports TLS 1.0/1.1.
+ */
+ static public class V10 extends TlsPrfGenerator {
+ protected SecretKey engineGenerateKey() {
+ return engineGenerateKey0(false);
+ }
+ }
}
diff --git a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
index 9402a1bb2930ddc249762a9a2495522586d5acad..1820ee8cbc384edb48929505bf5090452cae8837 100644
--- a/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
+++ b/src/share/classes/com/sun/crypto/provider/TlsRsaPremasterSecretGenerator.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -69,8 +69,8 @@ public final class TlsRsaPremasterSecretGenerator extends KeyGeneratorSpi {
protected SecretKey engineGenerateKey() {
if (spec == null) {
- throw new IllegalStateException
- ("TlsRsaPremasterSecretGenerator must be initialized");
+ throw new IllegalStateException(
+ "TlsRsaPremasterSecretGenerator must be initialized");
}
if (random == null) {
random = new SecureRandom();
diff --git a/src/share/classes/com/sun/jmx/defaults/ServiceName.java b/src/share/classes/com/sun/jmx/defaults/ServiceName.java
index aa0a46fe2acba9549242df54c2db22b11c5b86f4..8f742dff0f8601fbb1cd71ae792bece1371c9fae 100644
--- a/src/share/classes/com/sun/jmx/defaults/ServiceName.java
+++ b/src/share/classes/com/sun/jmx/defaults/ServiceName.java
@@ -76,9 +76,9 @@ public class ServiceName {
/**
* The vendor of the JMX specification implemented by this product.
*
- * The value is Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_SPEC_VENDOR = "Sun Microsystems";
+ public static final String JMX_SPEC_VENDOR = "Oracle Corporation";
/**
* The name of this product implementing the JMX specification.
@@ -91,7 +91,7 @@ public class ServiceName {
* The name of the vendor of this product implementing the
* JMX specification.
*
- * The value is Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_IMPL_VENDOR = "Sun Microsystems";
+ public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
}
diff --git a/src/share/classes/com/sun/jmx/snmp/ServiceName.java b/src/share/classes/com/sun/jmx/snmp/ServiceName.java
index 0301389aa563e70f062a5f5d81e40f94f340f618..edf77073ee8d3db97568135bf5af604956bc4f56 100644
--- a/src/share/classes/com/sun/jmx/snmp/ServiceName.java
+++ b/src/share/classes/com/sun/jmx/snmp/ServiceName.java
@@ -27,7 +27,7 @@ package com.sun.jmx.snmp;
/**
* Used for storing default values used by SNMP Runtime services.
- *
This API is a Sun Microsystems internal API and is subject + *
This API is an Oracle Corporation internal API and is subject * to change without notice.
*/ public class ServiceName { @@ -144,16 +144,16 @@ public class ServiceName { /** * The vendor of the JMX specification implemented by this product. *Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_SPEC_VENDOR = "Sun Microsystems";
+ public static final String JMX_SPEC_VENDOR = "Oracle Corporation";
/**
* The name of the vendor of this product implementing the JMX specification.
* Sun Microsystems.
+ * The value is Oracle Corporation.
*/
- public static final String JMX_IMPL_VENDOR = "Sun Microsystems";
+ public static final String JMX_IMPL_VENDOR = "Oracle Corporation";
/**
* The build number of the current product version, of the form rXX.
diff --git a/src/share/classes/com/sun/management/package.html b/src/share/classes/com/sun/management/package.html
index b4c66900c22ed3c94b52c32a0c4c7bf2993af4da..c26d4309da6bfb666866c37a44c059113fb09ad5 100644
--- a/src/share/classes/com/sun/management/package.html
+++ b/src/share/classes/com/sun/management/package.html
@@ -30,7 +30,7 @@ questions.
-This package contains Sun Microsystem's platform extension to
+This package contains Oracle Corporation's platform extension to
the implementation of the
java.lang.management API and also defines the management
diff --git a/src/share/classes/java/awt/GridBagConstraints.java b/src/share/classes/java/awt/GridBagConstraints.java
index 445d937c185812e0356fb67b6971a769f8f776a0..9460c43500a56c0d284ee24686b18451181c2224 100644
--- a/src/share/classes/java/awt/GridBagConstraints.java
+++ b/src/share/classes/java/awt/GridBagConstraints.java
@@ -126,7 +126,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area
* associated with the start of a page for the current
- * ComponentOrienation. Equal to NORTH for horizontal
+ * {@code ComponentOrientation}. Equal to NORTH for horizontal
* orientations.
*/
public static final int PAGE_START = 19;
@@ -134,7 +134,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area
* associated with the end of a page for the current
- * ComponentOrienation. Equal to SOUTH for horizontal
+ * {@code ComponentOrientation}. Equal to SOUTH for horizontal
* orientations.
*/
public static final int PAGE_END = 20;
@@ -142,7 +142,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area where
* lines of text would normally begin for the current
- * ComponentOrienation. Equal to WEST for horizontal,
+ * {@code ComponentOrientation}. Equal to WEST for horizontal,
* left-to-right orientations and EAST for horizontal, right-to-left
* orientations.
*/
@@ -151,7 +151,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component centered along the edge of its display area where
* lines of text would normally end for the current
- * ComponentOrienation. Equal to EAST for horizontal,
+ * {@code ComponentOrientation}. Equal to EAST for horizontal,
* left-to-right orientations and WEST for horizontal, right-to-left
* orientations.
*/
@@ -160,7 +160,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally begin for the current
- * ComponentOrienation. Equal to NORTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHWEST for horizontal,
* left-to-right orientations and NORTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -169,7 +169,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the first line of text on a page would normally end for the current
- * ComponentOrienation. Equal to NORTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to NORTHEAST for horizontal,
* left-to-right orientations and NORTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -178,7 +178,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally start for the current
- * ComponentOrienation. Equal to SOUTHWEST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHWEST for horizontal,
* left-to-right orientations and SOUTHEAST for horizontal, right-to-left
* orientations.
*/
@@ -187,7 +187,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
/**
* Place the component in the corner of its display area where
* the last line of text on a page would normally end for the current
- * ComponentOrienation. Equal to SOUTHEAST for horizontal,
+ * {@code ComponentOrientation}. Equal to SOUTHEAST for horizontal,
* left-to-right orientations and SOUTHWEST for horizontal, right-to-left
* orientations.
*/
@@ -437,7 +437,7 @@ public class GridBagConstraints implements Cloneable, java.io.Serializable {
* LINE_START, LINE_END,
* FIRST_LINE_START, FIRST_LINE_END,
* LAST_LINE_START and LAST_LINE_END. The
- * baseline relvative values are:
+ * baseline relative values are:
* BASELINE, BASELINE_LEADING,
* BASELINE_TRAILING,
* ABOVE_BASELINE, ABOVE_BASELINE_LEADING,
diff --git a/src/share/classes/java/awt/Scrollbar.java b/src/share/classes/java/awt/Scrollbar.java
index 56835aa9dd4326ea49a6604ac758e3a848ceb3d3..d43414305b56c9c95189b94db58ede9a915516d1 100644
--- a/src/share/classes/java/awt/Scrollbar.java
+++ b/src/share/classes/java/awt/Scrollbar.java
@@ -213,7 +213,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible {
* The size of the Scrollbar's bubble.
* When a scroll bar is used to select a range of values,
* the visibleAmount represents the size of this range.
- * This is visually indicated by the size of the bubble.
+ * Depending on platform, this may be visually indicated
+ * by the size of the bubble.
*
* @serial
* @see #getVisibleAmount
@@ -637,6 +638,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible {
* bubble (also called a thumb or scroll box), usually gives a
* visual representation of the relationship of the visible
* amount to the range of the scroll bar.
+ * Note that depending on platform, the value of the visible amount property
+ * may not be visually indicated by the size of the bubble.
* * The scroll bar's bubble may not be displayed when it is not * moveable (e.g. when it takes up the entire length of the @@ -670,6 +673,8 @@ public class Scrollbar extends Component implements Adjustable, Accessible { * bubble (also called a thumb or scroll box), usually gives a * visual representation of the relationship of the visible * amount to the range of the scroll bar. + * Note that depending on platform, the value of the visible amount property + * may not be visually indicated by the size of the bubble. *
* The scroll bar's bubble may not be displayed when it is not * moveable (e.g. when it takes up the entire length of the diff --git a/src/share/classes/java/dyn/BootstrapMethod.java b/src/share/classes/java/dyn/BootstrapMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..a5c41b4854be591e0bd5900b8575f04f644b9618 --- /dev/null +++ b/src/share/classes/java/dyn/BootstrapMethod.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.dyn; + +import java.lang.annotation.*; + +/** + * Annotation on InvokeDynamic method calls which requests the JVM to use a specific + * bootstrap method + * to link the call. This annotation is not retained as such in the class file, + * but is transformed into a constant-pool entry for the invokedynamic instruction which + * specifies the desired bootstrap method. + *
+ * If only the value is given, it must name a subclass of {@link CallSite}
+ * with a constructor which accepts a class, string, and method type.
+ * If the value and name are both given, there must be
+ * a static method in the given class of the given name which accepts a class, string,
+ * and method type, and returns a reference coercible to {@link CallSite}.
+ *
+ * This annotation can be placed either on the return type of a single {@link InvokeDynamic} + * call (see examples) or else it can be placed on an enclosing class or method, where it + * determines a default bootstrap method for any {@link InvokeDynamic} calls which are not + * specifically annotated with a bootstrap method. + * Every {@link InvokeDynamic} call must be given a bootstrap method. + *
+ * Examples: +
+@BootstrapMethod(value=MyLanguageRuntime.class, name="bootstrapDynamic")
+String x = (String) InvokeDynamic.greet();
+//BSM => MyLanguageRuntime.bootstrapDynamic(Here.class, "greet", methodType(String.class))
+@BootstrapMethod(MyCallSite.class)
+void example() throws Throwable {
+ InvokeDynamic.greet();
+ //BSM => new MyCallSite(Here.class, "greet", methodType(void.class))
+}
+
+ * + */ +@Target({ElementType.TYPE_USE, + // For defaulting every indy site within a class or method; cf. @SuppressWarnings: + ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR + }) +@Retention(RetentionPolicy.SOURCE) +public @interface BootstrapMethod { + /** The class containing the bootstrap method. */ + Class> value(); + + /** The name of the bootstrap method. + * If this is the empty string, an instance of the bootstrap class is created, + * and a constructor is invoked. + * Otherwise, there must be a static method of the required name. + */ + String name() default ""; // empty string denotes a constructor with 'new' + + /** The argument types of the bootstrap method, as passed out by the JVM. + * There is usually no reason to override the default. + */ + Class>[] arguments() default {Class.class, String.class, MethodType.class}; +} diff --git a/src/share/classes/java/dyn/CallSite.java b/src/share/classes/java/dyn/CallSite.java index b833577485125da50729fe3d98c2a9c4fa752aeb..7c4ed52ea68d371ba77fb98b8b91df30dfe8d859 100644 --- a/src/share/classes/java/dyn/CallSite.java +++ b/src/share/classes/java/dyn/CallSite.java @@ -25,56 +25,26 @@ package java.dyn; -import sun.dyn.Access; -import sun.dyn.MemberName; -import sun.dyn.CallSiteImpl; +import sun.dyn.*; +import java.util.Collection; /** - * A {@code CallSite} reifies an {@code invokedynamic} instruction from bytecode, - * and controls its linkage. - * Every linked {@code CallSite} object corresponds to a distinct instance - * of the {@code invokedynamic} instruction, and vice versa. + * A {@code CallSite} is a holder for a variable {@link MethodHandle}, + * which is called its {@code target}. + * Every call to a {@code CallSite} is delegated to the site's current target. *
- * Every linked {@code CallSite} object has one state variable, - * a {@link MethodHandle} reference called the {@code target}. - * This reference is never null. Though it can change its value - * successive values must always have exactly the {@link MethodType method type} - * called for by the bytecodes of the associated {@code invokedynamic} instruction + * A call site is initially created in an unlinked state, + * which is distinguished by a null target variable. + * Before the call site may be invoked (and before certain other + * operations are attempted), the call site must be linked to + * a non-null target. *
- * It is the responsibility of each class's - * {@link Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method} - * to produce call sites which have been pre-linked to an initial target method. - * The required {@link MethodType type} for the target method is a parameter - * to each bootstrap method call. - *
- * The bootstrap method may elect to produce call sites of a - * language-specific subclass of {@code CallSite}. In such a case, - * the subclass may claim responsibility for initializing its target to - * a non-null value, by overriding {@link #initialTarget}. - *
- * An {@code invokedynamic} instruction which has not yet been executed - * is said to be unlinked. When an unlinked call site is executed, - * the containing class's bootstrap method is called to manufacture a call site, - * for the instruction. If the bootstrap method does not assign a non-null - * value to the new call site's target variable, the method {@link #initialTarget} - * is called to produce the new call site's first target method. - *
- * A freshly-created {@code CallSite} object is not yet in a linked state. - * An unlinked {@code CallSite} object reports null for its {@code callerClass}. - * When the JVM receives a {@code CallSite} object from a bootstrap method, - * it first ensures that its target is non-null and of the correct type. - * The JVM then links the {@code CallSite} object to the call site instruction, - * enabling the {@code callerClass} to return the class in which the instruction occurs. - *
- * Next, the JVM links the instruction to the {@code CallSite}, at which point - * any further execution of the {@code invokedynamic} instruction implicitly - * invokes the current target of the {@code CallSite} object. - * After this two-way linkage, both the instruction and the {@code CallSite} - * object are said to be linked. - *
- * This state of linkage continues until the method containing the - * dynamic call site is garbage collected, or the dynamic call site - * is invalidated by an explicit request. + * A call site may be relinked by changing its target. + * The new target must be non-null and must have the same + * {@linkplain MethodHandle#type() type} + * as the previous target. + * Thus, though a call site can be relinked to a series of + * successive targets, it cannot change its type. *
* Linkage happens once in the lifetime of any given {@code CallSite} object. * Because of call site invalidation, this linkage can be repeated for @@ -87,6 +57,10 @@ import sun.dyn.CallSiteImpl; * Here is a sample use of call sites and bootstrap methods which links every * dynamic call site to print its arguments:
+@BootstrapMethod(value=PrintArgsDemo.class, name="bootstrapDynamic")
+static void test() throws Throwable {
+ InvokeDynamic.baz("baz arg", 2, 3.14);
+}
private static void printArgs(Object... args) {
System.out.println(java.util.Arrays.deepToString(args));
}
@@ -96,17 +70,16 @@ static {
Class thisClass = lookup.lookupClass(); // (who am I?)
printArgs = lookup.findStatic(thisClass,
"printArgs", MethodType.methodType(void.class, Object[].class));
- Linkage.registerBootstrapMethod("bootstrapDynamic");
}
private static CallSite bootstrapDynamic(Class caller, String name, MethodType type) {
// ignore caller and name, but match the type:
return new CallSite(MethodHandles.collectArguments(printArgs, type));
}
- * @see Linkage#registerBootstrapMethod(java.lang.Class, java.dyn.MethodHandle)
* @author John Rose, JSR 292 EG
*/
public class CallSite
+ implements MethodHandleProvider
{
private static final Access IMPL_TOKEN = Access.getToken();
@@ -209,6 +182,7 @@ public class CallSite
* {@code InvokeDynamicBootstrapError}, which in turn causes the
* linkage of the {@code invokedynamic} instruction to terminate
* abnormally.
+ * @deprecated transitional form defined in EDR but removed in PFD
*/
protected MethodHandle initialTarget(Class> callerClass, String name, MethodType type) {
throw new InvokeDynamicBootstrapError("target must be initialized before call site is linked: "+name+type);
@@ -278,16 +252,44 @@ public class CallSite
*/
@Override
public String toString() {
- StringBuilder buf = new StringBuilder("CallSite#");
- buf.append(hashCode());
- if (!isLinked())
- buf.append("[unlinked]");
- else
- buf.append("[")
- .append("from ").append(vmmethod.getDeclaringClass().getName())
- .append(" : ").append(getTarget().type())
- .append(" => ").append(getTarget())
- .append("]");
- return buf.toString();
+ return "CallSite"+(target == null ? "" : target.type());
+ }
+
+ /**
+ * PROVISIONAL API, WORK IN PROGRESS:
+ * Produce a method handle equivalent to an invokedynamic instruction
+ * which has been linked to this call site.
+ * If this call site is a {@link ConstantCallSite}, this method + * simply returns the call site's target, since that will not change. + *
Otherwise, this method is equivalent to the following code: + *
+ * @return a method handle which always invokes this call site's current target + */ + public final MethodHandle dynamicInvoker() { + if (this instanceof ConstantCallSite) + return getTarget(); // will not change dynamically + MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, GET_TARGET, this); + MethodHandle invoker = MethodHandles.exactInvoker(this.type()); + return MethodHandles.foldArguments(invoker, getTarget); } + private static final MethodHandle GET_TARGET; + static { + try { + GET_TARGET = MethodHandles.Lookup.IMPL_LOOKUP. + findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class)); + } catch (NoAccessException ignore) { + throw new InternalError(); + } + } + + /** Implementation of {@link MethodHandleProvider} which returns {@code this.dynamicInvoker()}. */ + public final MethodHandle asMethodHandle() { return dynamicInvoker(); } + + /** Implementation of {@link MethodHandleProvider}, which returns {@code this.dynamicInvoker().asType(type)}. */ + public final MethodHandle asMethodHandle(MethodType type) { return dynamicInvoker().asType(type); } } diff --git a/src/share/classes/java/dyn/ClassValue.java b/src/share/classes/java/dyn/ClassValue.java new file mode 100644 index 0000000000000000000000000000000000000000..325d55e0742ad43759563fb06dbf06ed6456bc06 --- /dev/null +++ b/src/share/classes/java/dyn/ClassValue.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.dyn; + +import java.util.WeakHashMap; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +/** + * Lazily associate a computed value with (potentially) every class. + * @author John Rose, JSR 292 EG + */ +public abstract class ClassValue+ * MethodHandle getTarget, invoker, result; + * getTarget = MethodHandles.lookup().bind(this, "getTarget", MethodType.methodType(MethodHandle.class)); + * invoker = MethodHandles.exactInvoker(this.type()); + * result = MethodHandles.foldArguments(invoker, getTarget) + *
+ * This method will be invoked within the first thread that accesses + * the value with the {@link #get}. + *
+ * Normally, this method is invoked at most once per class, + * but it may be invoked again in case of subsequent invocations + * of {@link #remove} followed by {@link #get}. + * + * @return the computed value for this thread-local + */ + protected abstract T computeValue(Class> type); + + /** + * Creates a new class value. + */ + protected ClassValue() { + } + + /** + * Returns the value for the given class. + * If no value has yet been computed, it is obtained by + * by an invocation of the {@link #computeValue} method. + *
+ * The actual installation of the value on the class
+ * is performed while the class's synchronization lock
+ * is held. At that point, if racing threads have
+ * computed values, one is chosen, and returned to
+ * all the racing threads.
+ *
+ * @return the current thread's value of this thread-local
+ */
+ public T get(Class> type) {
+ ClassValueMap map = getMap(type);
+ if (map != null) {
+ Object x = map.get(this);
+ if (x != null) {
+ return (T) map.unmaskNull(x);
+ }
+ }
+ return setComputedValue(type);
+ }
+
+ /**
+ * Removes the associated value for the given class.
+ * If this value is subsequently {@linkplain #get read} for the same class,
+ * its value will be reinitialized by invoking its {@link #computeValue} method.
+ * This may result in an additional invocation of the
+ * {@code computeValue} method for the given class.
+ */
+ public void remove(Class> type) {
+ ClassValueMap map = getMap(type);
+ if (map != null) {
+ synchronized (map) {
+ map.remove(this);
+ }
+ }
+ }
+
+ /// Implementation...
+
+ /** The hash code for this type is based on the identity of the object,
+ * and is well-dispersed for power-of-two tables.
+ */
+ public final int hashCode() { return hashCode; }
+ private final int hashCode = HASH_CODES.getAndAdd(0x61c88647);
+ private static final AtomicInteger HASH_CODES = new AtomicInteger();
+
+ private static final AtomicInteger STORE_BARRIER = new AtomicInteger();
+
+ /** Slow path for {@link #get}. */
+ private T setComputedValue(Class> type) {
+ ClassValueMap map = getMap(type);
+ if (map == null) {
+ map = initializeMap(type);
+ }
+ T value = computeValue(type);
+ STORE_BARRIER.lazySet(0);
+ // All stores pending from computeValue are completed.
+ synchronized (map) {
+ // Warm up the table with a null entry.
+ map.preInitializeEntry(this);
+ }
+ // All stores pending from table expansion are completed.
+ synchronized (map) {
+ value = (T) map.initializeEntry(this, value);
+ // One might fear a possible race condition here
+ // if the code for map.put has flushed the write
+ // to map.table[*] before the writes to the Map.Entry
+ // are done. This is not possible, since we have
+ // warmed up the table with an empty entry.
+ }
+ return value;
+ }
+
+ // Replace this map by a per-class slot.
+ private static final WeakHashMap
* The type {@code InvokeDynamic} has no particular meaning as a
@@ -45,22 +45,31 @@ package java.dyn;
* It may be imported for ease of use.
*
* Here are some examples:
- *
* The argument types are taken directly from the actual arguments,
- * while the return type is taken from the type parameter.
- * (This type parameter may be a primtive, and it defaults to {@code Object}.)
+ * while the return type corresponds to the target of the assignment.
+ * (Currently, the return type must be given as a false type parameter.
+ * This type parameter is an irregular use of the generic type syntax,
+ * and is likely to change in favor of a convention based on target typing.)
+ *
* The final example uses a special syntax for uttering non-Java names.
* Any name legal to the JVM may be given between the double quotes.
+ *
* None of these calls is complete without a bootstrap method,
- * which must be registered by the static initializer of the enclosing class.
+ * which must be declared for the enclosing class or method.
* @author John Rose, JSR 292 EG
*/
@MethodHandle.PolymorphicSignature
diff --git a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
index a301dfa42bced3fed14b92b19b5c38c2667bd664..3820e94c7747a40fbc48f825ae76117d300df822 100644
--- a/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
+++ b/src/share/classes/java/dyn/InvokeDynamicBootstrapError.java
@@ -28,15 +28,11 @@ package java.dyn;
/**
* Thrown to indicate that an {@code invokedynamic} instruction has
* failed to find its
- * {@linkplain Linkage#registerBootstrapMethod(Class, MethodHandle) bootstrap method},
+ * {@linkplain BootstrapMethod bootstrap method},
* or the bootstrap method has
* failed to provide a
* {@linkplain CallSite} call site with a non-null {@linkplain MethodHandle target}
* of the correct {@linkplain MethodType method type}.
- *
- * The bootstrap method must have been declared during a class's initialization
- * by a call to one of the overloadings of
- * {@link Linkage#registerBootstrapMethod registerBootstrapMethod}.
*
* @author John Rose, JSR 292 EG
* @since 1.7
diff --git a/src/share/classes/java/dyn/Linkage.java b/src/share/classes/java/dyn/Linkage.java
index d65ae41c31c55ad71070b4a2b5b8030ad3d1769e..98eedbbabfbba4781e3b6e54f5d6e46d2f9610fa 100644
--- a/src/share/classes/java/dyn/Linkage.java
+++ b/src/share/classes/java/dyn/Linkage.java
@@ -25,7 +25,6 @@
package java.dyn;
-import java.lang.annotation.Annotation;
import java.dyn.MethodHandles.Lookup;
import java.util.WeakHashMap;
import sun.dyn.Access;
@@ -56,11 +55,7 @@ public class Linkage {
*
@@ -86,6 +81,7 @@ public class Linkage {
* or is already running in another thread
* @exception SecurityException if there is a security manager installed,
* and a {@link LinkagePermission} check fails for "registerBootstrapMethod"
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(Class callerClass, MethodHandle bootstrapMethod) {
@@ -97,14 +93,9 @@ public class Linkage {
static private void checkBSM(MethodHandle mh) {
if (mh == null) throw newIllegalArgumentException("null bootstrap method");
- if (mh.type() == BOOTSTRAP_METHOD_TYPE_2)
- // For now, always pass an empty array for the Annotations argument
- mh = MethodHandles.insertArguments(mh, BOOTSTRAP_METHOD_TYPE_2.parameterCount()-1,
- (Object)NO_ANNOTATIONS);
if (mh.type() == BOOTSTRAP_METHOD_TYPE) return;
throw new WrongMethodTypeException(mh.toString());
}
- static private final Annotation[] NO_ANNOTATIONS = { };
/**
* PROVISIONAL API, WORK IN PROGRESS:
@@ -115,6 +106,7 @@ public class Linkage {
* @throws NoSuchMethodException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(Class> runtime, String name) {
@@ -131,6 +123,7 @@ public class Linkage {
* @throws IllegalArgumentException if there is no such method
* @throws IllegalStateException if the caller class's static initializer
* has already run, or is already running in another thread
+ * @deprecated Use @{@link BootstrapMethod} annotations instead
*/
public static
void registerBootstrapMethod(String name) {
@@ -142,18 +135,10 @@ public class Linkage {
void registerBootstrapMethodLookup(Class> callerClass, Class> runtime, String name) {
Lookup lookup = new Lookup(IMPL_TOKEN, callerClass);
MethodHandle bootstrapMethod;
- // Try both types. TBD
try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE_2);
+ bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
} catch (NoAccessException ex) {
- bootstrapMethod = null;
- }
- if (bootstrapMethod == null) {
- try {
- bootstrapMethod = lookup.findStatic(runtime, name, BOOTSTRAP_METHOD_TYPE);
- } catch (NoAccessException ex) {
- throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
- }
+ throw new IllegalArgumentException("no such bootstrap method in "+runtime+": "+name, ex);
}
checkBSM(bootstrapMethod);
MethodHandleImpl.registerBootstrap(IMPL_TOKEN, callerClass, bootstrapMethod);
@@ -172,6 +157,7 @@ public class Linkage {
* and the immediate caller of this method is not in the same
* package as the caller class
* and a {@link LinkagePermission} check fails for "getBootstrapMethod"
+ * @deprecated
*/
public static
MethodHandle getBootstrapMethod(Class callerClass) {
@@ -188,10 +174,6 @@ public class Linkage {
public static final MethodType BOOTSTRAP_METHOD_TYPE
= MethodType.methodType(CallSite.class,
Class.class, String.class, MethodType.class);
- static final MethodType BOOTSTRAP_METHOD_TYPE_2
- = MethodType.methodType(CallSite.class,
- Class.class, String.class, MethodType.class,
- Annotation[].class);
/**
* PROVISIONAL API, WORK IN PROGRESS:
diff --git a/src/share/classes/java/dyn/LinkagePermission.java b/src/share/classes/java/dyn/LinkagePermission.java
index 6f6dc5004eb26046ad34cc771a059019959b177e..9861843918d151f8ac1928cb1d48fd58fe6fdfb6 100644
--- a/src/share/classes/java/dyn/LinkagePermission.java
+++ b/src/share/classes/java/dyn/LinkagePermission.java
@@ -31,6 +31,7 @@ import java.util.Hashtable;
import java.util.StringTokenizer;
/**
+ * PROVISIONAL API, WORK IN PROGRESS:
* This class is for managing runtime permission checking for
* operations performed by methods in the {@link Linkage} class.
* Like a {@link RuntimePermission}, on which it is modeled,
@@ -52,13 +53,6 @@ import java.util.StringTokenizer;
*
*
* ISSUE: Is this still needed?
*
- * @see java.security.RuntimePermission
+ * @see java.lang.RuntimePermission
* @see java.lang.SecurityManager
*
* @author John Rose, JSR 292 EG
@@ -86,7 +81,7 @@ public final class LinkagePermission extends BasicPermission {
/**
* Create a new LinkagePermission with the given name.
* The name is the symbolic name of the LinkagePermission, such as
- * "registerBootstrapMethod", "invalidateCallerClass.*", etc. An asterisk
+ * "invalidateCallerClass.*", etc. An asterisk
* may appear at the end of the name, following a ".", or by itself, to
* signify a wildcard match.
*
diff --git a/src/share/classes/java/dyn/MethodHandle.java b/src/share/classes/java/dyn/MethodHandle.java
index 20387ca6859f85e73ba9251652054044532d1979..4904e975306b2a69ce0817c57b5e497e7f535a3a 100644
--- a/src/share/classes/java/dyn/MethodHandle.java
+++ b/src/share/classes/java/dyn/MethodHandle.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -36,11 +36,13 @@ import static sun.dyn.MemberName.newIllegalArgumentException; // utility
/**
* A method handle is a typed, directly executable reference to a method,
* constructor, field, or similar low-level operation, with optional
- * conversion or substitution of arguments or return values.
+ * transformations of arguments or return values.
+ * (These transformations include conversion, insertion, deletion,
+ * substitution. See the methods of this class and of {@link MethodHandles}.)
*
* Method handles are strongly typed according to signature.
* They are not distinguished by method name or enclosing class.
- * A method handle must be invoked under a signature which exactly matches
+ * A method handle must be invoked under a signature which matches
* the method handle's own {@link MethodType method type}.
*
* Every method handle confesses its type via the {@code type} accessor.
@@ -174,9 +176,10 @@ assert(i == 3);
* merely a documentation convention. These type parameters do
* not play a role in type-checking method handle invocations.
*
- * Note: Like classes and strings, method handles that correspond directly
- * to fields and methods can be represented directly as constants to be
- * loaded by {@code ldc} bytecodes.
+ * Like classes and strings, method handles that correspond to accessible
+ * fields, methods, and constructors can be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * Loading such a constant causes the component classes of its type to be loaded as necessary.
*
* @see MethodType
* @see MethodHandles
@@ -186,6 +189,7 @@ public abstract class MethodHandle
// Note: This is an implementation inheritance hack, and will be removed
// with a JVM change which moves the required hidden state onto this class.
extends MethodHandleImpl
+ implements MethodHandleProvider
{
private static Access IMPL_TOKEN = Access.getToken();
@@ -197,7 +201,7 @@ public abstract class MethodHandle
* those methods which are signature polymorphic.
*/
@java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD,java.lang.annotation.ElementType.TYPE})
- @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.CLASS)
+ @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@interface PolymorphicSignature { }
private MethodType type;
@@ -274,10 +278,14 @@ public abstract class MethodHandle
* and performing simple conversions for arguments and return types.
* The signature at the call site of {@code invokeGeneric} must
* have the same arity as this method handle's {@code type}.
- * The same conversions are allowed on arguments or return values as are supported by
- * by {@link MethodHandles#convertArguments}.
+ *
* If the call site signature exactly matches this method handle's {@code type},
* the call proceeds as if by {@link #invokeExact}.
+ *
+ * Otherwise, the call proceeds as if this method handle were first
+ * adjusted by calling {@link #asType} to adjust this method handle
+ * to the required type, and then the call proceeds as if by
+ * {@link #invokeExact} on the adjusted method handle.
*/
public final native @PolymorphicSignature
+ * The type {@link MethodHandle} is a concrete class whose implementation
+ * hierarchy (if any) may be tightly coupled to the underlying JVM implementation.
+ * It cannot also serve as a base type for user-defined functional APIs.
+ * For this reason, {@code MethodHandle} cannot be subclassed to add new
+ * behavior to method handles. But this interface can be used to provide
+ * a link between a user-defined function and the {@code invokedynamic}
+ * instruction and the method handle API.
+ */
+public interface MethodHandleProvider {
+ /** Produce a method handle which will serve as a behavioral proxy for the current object.
+ * The type and invocation behavior of the proxy method handle are user-defined,
+ * and should have some relation to the intended meaning of the original object itself.
+ *
+ * The current object may have a changeable behavior.
+ * For example, {@link CallSite} has a {@code setTarget} method which changes its invocation.
+ * In such a case, it is incorrect for {@code asMethodHandle} to return
+ * a method handle whose behavior may diverge from that of the current object.
+ * Rather, the returned method handle must stably and permanently access
+ * the behavior of the current object, even if that behavior is changeable.
+ *
+ * The reference identity of the proxy method handle is not guaranteed to
+ * have any particular relation to the reference identity of the object.
+ * In particular, several objects with the same intended meaning could
+ * share a common method handle, or the same object could return different
+ * method handles at different times. In the latter case, the different
+ * method handles should have the same type and invocation behavior,
+ * and be usable from any thread at any time.
+ * In particular, if a MethodHandleProvider is bound to an
+ * The type {@link MethodHandle} itself implements {@code MethodHandleProvider}, and
+ * for this method simply returns {@code this}.
+ */
+ public MethodHandle asMethodHandle();
+
+ /** Produce a method handle of a given type which will serve as a behavioral proxy for the current object.
+ * As for the no-argument version {@link #asMethodHandle()}, the invocation behavior of the
+ * proxy method handle is user-defined. But the type must be the given type,
+ * or else a {@link WrongMethodTypeException} must be thrown.
+ *
+ * If the current object somehow represents a variadic or overloaded behavior,
+ * the method handle returned for a given type might represent only a subset of
+ * the current object's repertoire of behaviors, which correspond to that type.
+ */
+ public MethodHandle asMethodHandle(MethodType type) throws WrongMethodTypeException;
+}
diff --git a/src/share/classes/java/dyn/MethodHandles.java b/src/share/classes/java/dyn/MethodHandles.java
index ac35f88e14353b436992f4f4562ef21cf6670624..b6e8333834094497ecc7c8105a8f5bb5c440cd05 100644
--- a/src/share/classes/java/dyn/MethodHandles.java
+++ b/src/share/classes/java/dyn/MethodHandles.java
@@ -25,15 +25,12 @@
package java.dyn;
-import java.lang.reflect.Constructor;
+import java.lang.reflect.*;
import sun.dyn.Access;
import sun.dyn.MemberName;
import sun.dyn.MethodHandleImpl;
import sun.dyn.util.VerifyAccess;
import sun.dyn.util.Wrapper;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
@@ -81,6 +78,14 @@ public class MethodHandles {
* Return a {@link Lookup lookup object} which is trusted minimally.
* It can only be used to create method handles to
* publicly accessible fields and methods.
+ *
+ * As a matter of pure convention, the {@linkplain Lookup#lookupClass lookup class}
+ * of this lookup object will be {@link java.lang.Object}.
+ *
+ * The lookup class can be changed to any other class {@code C} using an expression of the form
+ * {@linkplain Lookup#in
* In general, the conditions under which a method handle may be
* created for a method {@code M} are exactly as restrictive as the conditions
* under which the lookup class could have compiled a call to {@code M}.
- * At least some of these error conditions are likely to be
- * represented by checked exceptions in the final version of this API.
+ * This rule is applied even if the Java compiler might have created
+ * an wrapper method to access a private method of another class
+ * in the same top-level declaration.
+ * For example, a lookup object created for a nested class {@code C.D}
+ * can access private members within other related classes such as
+ * {@code C}, {@code C.D.E}, or {@code C.B}.
*/
public static final
class Lookup {
/** The class on behalf of whom the lookup is being performed. */
private final Class> lookupClass;
- /** The allowed sorts of members which may be looked up (public, etc.), with STRICT for package. */
+ /** The allowed sorts of members which may be looked up (public, etc.), with STATIC for package. */
private final int allowedModes;
private static final int
PUBLIC = Modifier.PUBLIC,
- PACKAGE = Modifier.STRICT,
+ PACKAGE = Modifier.STATIC,
PROTECTED = Modifier.PROTECTED,
PRIVATE = Modifier.PRIVATE,
ALL_MODES = (PUBLIC | PACKAGE | PROTECTED | PRIVATE),
@@ -155,8 +166,10 @@ public class MethodHandles {
/** Which class is performing the lookup? It is this class against
* which checks are performed for visibility and access permissions.
*
- * This value is null if and only if this lookup was produced
- * by {@link MethodHandles#publicLookup}.
+ * The class implies a maximum level of access permission,
+ * but the permissions may be additionally limited by the bitmask
+ * {@link #lookupModes}, which controls whether non-public members
+ * can be accessed.
*/
public Class> lookupClass() {
return lookupClass;
@@ -168,10 +181,15 @@ public class MethodHandles {
}
/** Which types of members can this lookup object produce?
- * The result is a bit-mask of the modifier bits PUBLIC, PROTECTED, PRIVATE, and STRICT.
- * The modifier bit STRICT stands in for the (non-existent) package protection mode.
+ * The result is a bit-mask of the {@link Modifier} bits
+ * {@linkplain Modifier#PUBLIC PUBLIC (0x01)},
+ * {@linkplain Modifier#PROTECTED PROTECTED (0x02)},
+ * {@linkplain Modifier#PRIVATE PRIVATE (0x04)},
+ * and {@linkplain Modifier#STATIC STATIC (0x08)}.
+ * The modifier bit {@code STATIC} stands in for the package protection mode,
+ * which does not have an explicit modifier bit.
*/
- int lookupModes() {
+ public int lookupModes() {
return allowedModes & ALL_MODES;
}
@@ -621,32 +639,32 @@ public class MethodHandles {
/// Helper methods, all package-private.
- MemberName resolveOrFail(Class> refc, String name, Class> type, boolean isStatic) {
+ MemberName resolveOrFail(Class> refc, String name, Class> type, boolean isStatic) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
- MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic) {
+ MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), true, lookupClassOrNull());
}
MemberName resolveOrFail(Class> refc, String name, MethodType type, boolean isStatic,
- boolean searchSupers, Class> specialCaller) {
+ boolean searchSupers, Class> specialCaller) throws NoAccessException {
checkSymbolicClass(refc); // do this before attempting to resolve
int mods = (isStatic ? Modifier.STATIC : 0);
return IMPL_NAMES.resolveOrFail(new MemberName(refc, name, type, mods), searchSupers, specialCaller);
}
- void checkSymbolicClass(Class> refc) {
+ void checkSymbolicClass(Class> refc) throws NoAccessException {
Class> caller = lookupClassOrNull();
if (caller != null && !VerifyAccess.isClassAccessible(refc, caller))
throw newNoAccessException("symbolic reference class is not public", new MemberName(refc), caller);
}
- void checkMethod(Class> refc, MemberName m, boolean wantStatic) {
+ void checkMethod(Class> refc, MemberName m, boolean wantStatic) throws NoAccessException {
String message;
if (m.isConstructor())
message = "expected a method, not a constructor";
@@ -659,7 +677,7 @@ public class MethodHandles {
throw newNoAccessException(message, m, lookupClass());
}
- void checkAccess(Class> refc, MemberName m) {
+ void checkAccess(Class> refc, MemberName m) throws NoAccessException {
int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return;
int mods = m.getModifiers();
@@ -695,14 +713,14 @@ public class MethodHandles {
return "member is private to package";
}
- void checkSpecialCaller(Class> specialCaller) {
+ void checkSpecialCaller(Class> specialCaller) throws NoAccessException {
if (allowedModes == TRUSTED) return;
if (!VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))
throw newNoAccessException("no private access for invokespecial",
new MemberName(specialCaller), lookupClass());
}
- MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) {
+ MethodHandle restrictProtectedReceiver(MemberName method, MethodHandle mh) throws NoAccessException {
// The accessing class only has the right to use a protected member
// on itself or a subclass. Enforce that restriction, from JVMS 5.4.4, etc.
if (!method.isProtected() || method.isStatic()
@@ -712,7 +730,7 @@ public class MethodHandles {
else
return restrictReceiver(method, mh, lookupClass());
}
- MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class> caller) {
+ MethodHandle restrictReceiver(MemberName method, MethodHandle mh, Class> caller) throws NoAccessException {
assert(!method.isStatic());
Class> defc = method.getDeclaringClass(); // receiver type of mh is too wide
if (defc.isInterface() || !defc.isAssignableFrom(caller)) {
@@ -898,11 +916,16 @@ public class MethodHandles {
* @return a method handle which always invokes the call site's target
*/
public static
- MethodHandle dynamicInvoker(CallSite site) {
+ MethodHandle dynamicInvoker(CallSite site) throws NoAccessException {
MethodHandle getCSTarget = GET_TARGET;
- if (getCSTarget == null)
- GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
- findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+ if (getCSTarget == null) {
+ try {
+ GET_TARGET = getCSTarget = Lookup.IMPL_LOOKUP.
+ findVirtual(CallSite.class, "getTarget", MethodType.methodType(MethodHandle.class));
+ } catch (NoAccessException ex) {
+ throw new InternalError();
+ }
+ }
MethodHandle getTarget = MethodHandleImpl.bindReceiver(IMPL_TOKEN, getCSTarget, site);
MethodHandle invoker = exactInvoker(site.type());
return foldArguments(invoker, getTarget);
@@ -1260,17 +1283,20 @@ public class MethodHandles {
*
* Example:
*
+ * The resulting instance of the required SAM type will respond to
+ * invocation of the SAM type's single abstract method by calling
+ * the given {@code target} on the incoming arguments,
+ * and returning or throwing whatever the {@code target}
+ * returns or throws. The invocation will be as if by
+ * {@code target.invokeExact}.
+ *
+ * The method handle may throw an undeclared exception,
+ * which means any checked exception (or other checked throwable)
+ * not declared by the SAM type's single abstract method.
+ * If this happens, the throwable will be wrapped in an instance
+ * of {@link UndeclaredThrowableException} and thrown in that
+ * wrapped form.
+ *
+ * The wrapper instance is guaranteed to be of a non-public
+ * implementation class C in a package containing no classes
+ * or methods except system-defined classes and methods.
+ * The implementation class C will have no public supertypes
+ * or public methods beyond the following:
+ *
+ * No stable mapping is promised between the SAM type and
+ * the implementation class C. Over time, several implementation
+ * classes might be used for the same SAM type.
+ *
+ * This method is not guaranteed to return a distinct
+ * wrapper object for each separate call. If the JVM is able
+ * to prove that a wrapper has already been created for a given
+ * method handle, or for another method handle with the
+ * same behavior, the JVM may return that wrapper in place of
+ * a new wrapper.
+ * @param target the method handle to invoke from the wrapper
+ * @param samType the desired type of the wrapper, a SAM type
+ * @return a correctly-typed wrapper for the given {@code target}
+ * @throws IllegalArgumentException if the {@code target} throws
+ * an undeclared exception
+ */
+ // ISSUE: Should we delegate equals/hashCode to the targets?
+ // Not useful unless there is a stable equals/hashCode behavior
+ // for MethodHandle, and for MethodHandleProvider.asMethodHandle.
+ public static
+
* The structure is a return type accompanied by any number of parameter types.
- * The types (primitive, void, and reference) are represented by Class objects.
+ * The types (primitive, {@code void}, and reference) are represented by {@link Class} objects.
+ * (For ease of exposition, we treat {@code void} as if it were a type.
+ * In fact, it denotes the absence of a return type.)
*
- * All instances of
* This type can be created only by factory methods.
* All factory methods may cache values, though caching is not guaranteed.
*
- * Note: Like classes and strings, method types can be represented directly
- * as constants to be loaded by {@code ldc} bytecodes.
+ * {@code MethodType} objects are sometimes derived from bytecode instructions
+ * such as {@code invokedynamic}, specifically from the type descriptor strings associated
+ * with the instructions in a class file's constant pool.
+ * When this occurs, any classes named in the descriptor strings must be loaded.
+ * (But they need not be initialized.)
+ * This loading may occur at any time before the {@code MethodType} object is first derived.
+ *
+ * Like classes and strings, method types can be represented directly
+ * in a class file's constant pool as constants to be loaded by {@code ldc} bytecodes.
+ * Loading such a constant causes its component classes to be loaded as necessary.
* @author John Rose, JSR 292 EG
*/
public final
-class MethodType {
+class MethodType implements java.lang.reflect.Type {
private final Class> rtype;
private final Class>[] ptypes;
private MethodTypeForm form; // erased form, plus cached data about primitives
@@ -636,11 +649,11 @@ class MethodType {
/** Convenience method for {@link #methodType(java.lang.Class, java.lang.Class[])}.
* Find or create an instance of the given method type.
- * Any class or interface name embedded in the signature string
+ * Any class or interface name embedded in the descriptor string
* will be resolved by calling {@link ClassLoader#loadClass(java.lang.String)}
* on the given loader (or if it is null, on the system class loader).
*
- * Note that it is possible to build method types which cannot be
+ * Note that it is possible to encounter method types which cannot be
* constructed by this method, because their component types are
* not all reachable from a common class loader.
*
@@ -662,8 +675,11 @@ class MethodType {
}
/**
- * Create a bytecode signature representation of the type.
- * Note that this is not a strict inverse of
+ * Create a bytecode descriptor representation of the method type.
+ *
+ * Note that this is not a strict inverse of {@link #fromMethodDescriptorString}.
+ * Two distinct classes which share a common name but have different class loaders
+ * will appear identical when viewed within descriptor strings.
*
* This method is included for the benfit of applications that must
* generate bytecodes that process method handles and invokedynamic.
diff --git a/src/share/classes/java/dyn/NoAccessException.java b/src/share/classes/java/dyn/NoAccessException.java
index 6b2fbcebcae7a49687ecd262183030462c25bf38..89c1a52af2a6ae061f8ab7acb1fb96d1490bc6a5 100644
--- a/src/share/classes/java/dyn/NoAccessException.java
+++ b/src/share/classes/java/dyn/NoAccessException.java
@@ -37,7 +37,7 @@ package java.dyn;
* @author John Rose, JSR 292 EG
* @since 1.7
*/
-public class NoAccessException extends RuntimeException {
+public class NoAccessException extends ReflectiveOperationException {
private static final long serialVersionUID = 292L;
/**
diff --git a/src/share/classes/java/dyn/package-info.java b/src/share/classes/java/dyn/package-info.java
index 7a285b75d22be3dfe78d5914da85aa6246cfbcca..37555be14b4044dafaf6dc56ceb2c239bc3b41cd 100644
--- a/src/share/classes/java/dyn/package-info.java
+++ b/src/share/classes/java/dyn/package-info.java
@@ -40,20 +40,18 @@
* The JVM links any such call (regardless of signature) to a dynamically
* typed method handle invocation. In the case of {@code invokeGeneric},
* argument and return value conversions are applied.
+ *
+ * Each instance of an {@code invokedynamic} instruction is called a dynamic call site.
+ * Multiple instances of an {@code invokedynamic} instruction can share a single
+ * {@code CONSTANT_InvokeDynamic} entry.
+ * In any case, distinct call sites always have distinct linkage state.
+ *
+ * Moreover, for the purpose of distinguishing dynamic call sites,
+ * the JVM is allowed (but not required) to make internal copies
+ * of {@code invokedynamic} instructions, each one
+ * constituting a separate dynamic call site with its own linkage state.
+ * Such copying, if it occurs, cannot be observed except indirectly via
+ * execution of bootstrap methods and target methods.
+ *
+ * A dynamic call site is originally in an unlinked state. In this state, there is
+ * no target method for the call site to invoke.
+ * A dynamic call site is linked by means of a bootstrap method,
+ * as described below.
+ *
+ * (Historic Note: Some older JVMs may allow the index of a {@code CONSTANT_NameAndType}
+ * instead of a {@code CONSTANT_InvokeDynamic}. In earlier, obsolete versions of this API, the
+ * bootstrap method was specified dynamically, in a per-class basis, during class initialization.)
+ *
+ *
+ * The JVM will ensure that on first
+ * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType MethodType}
* will be created which represents the signature.
* Any classes mentioned in the {@code MethodType} will be loaded if necessary,
* but not initialized.
@@ -86,12 +116,15 @@
*
* The JVM will ensure that on first execution of an {@code ldc} instruction
- * for this entry, a {@link java.dyn.MethodHandle} will be created which represents
+ * for this entry, a {@link java.dyn.MethodHandle MethodHandle} will be created which represents
* the field or method reference, according to the specific mode implied by the subtag.
*
* As with {@code CONSTANT_Class} and {@code CONSTANT_MethodType} constants,
@@ -126,6 +159,129 @@
* Method handles for subtags {@code REF_getStatic}, {@code REF_putStatic}, and {@code REF_invokeStatic}
* may force class initialization on their first invocation, just like the corresponding bytecodes.
*
+ *
+ * Each {@code invokedynamic} instruction statically specifies its own
+ * bootstrap method as a constant pool reference.
+ * The constant pool reference also specifies the call site's name and type signature,
+ * just like {@code invokevirtual} and the other invoke instructions.
+ *
+ * Linking starts with resolving the constant pool entry for the
+ * bootstrap method, and resolving a {@link java.dyn.MethodType MethodType} object for
+ * the type signature of the dynamic call site.
+ * This resolution process may trigger class loading.
+ * It may therefore throw an error if a class fails to load.
+ * This error becomes the abnormal termination of the dynamic
+ * call site execution.
+ * Linkage does not trigger class initialization.
+ *
+ * Next, the bootstrap method call is started, with four values being stacked:
+ *
+ * After resolution, the linkage process may fail in a variety of ways.
+ * All failures are reported by an {@link java.dyn.InvokeDynamicBootstrapError InvokeDynamicBootstrapError},
+ * which is thrown as the abnormal termination of the dynamic call
+ * site execution.
+ * The following circumstances will cause this:
+ *
+ * If there are several such threads, the JVM picks one thread
+ * and runs the bootstrap method while the others wait for the
+ * invocation to terminate normally or abnormally.
+ *
+ * After a bootstrap method is called and a method handle target
+ * successfully extracted, the JVM attempts to link the instruction
+ * being executed to the target method handle.
+ * This may fail if there has been intervening linkage
+ * or invalidation event for the same instruction.
+ * If such a failure occurs, the dynamic call site must be
+ * re-executed from the beginning, either re-linking it
+ * (if it has been invalidated) or invoking the target
+ * (if it the instruction has been linked by some other means).
+ *
+ * If the instruction is linked successfully, the target method
+ * handle is invoked to complete the instruction execution.
+ * The state of linkage continues until the method containing the
+ * dynamic call site is garbage collected, or the dynamic call site
+ * is invalidated by an explicit request,
+ * such as {@link java.dyn.Linkage#invalidateCallerClass Linkage.invalidateCallerClass}.
+ *
+ * In an application which requires dynamic call sites with individually
+ * mutable behaviors, their bootstrap methods should produce distinct
+ * {@link java.dyn.CallSite CallSite} objects, one for each linkage request.
+ *
+ * If a class containing {@code invokedynamic} instructions
+ * is {@linkplain java.dyn.Linkage#invalidateCallerClass(Class) invalidated},
+ * subsequent execution of those {@code invokedynamic} instructions
+ * will require linking.
+ * It is as if they had never been executed in the first place.
+ * (However, invalidation does not cause constant pool entries to be
+ * resolved a second time.)
+ *
+ * Invalidation events and bootstrap method calls for a particular
+ * dynamic call site are globally ordered relative to each other.
+ * When an invokedynamic instruction is invalidated, if there is
+ * simultaneously a bootstrap method invocation in process
+ * (in the same thread or a different thread), the result
+ * eventually returned must not be used to link the call site.
+ * Put another way, when a call site is invalidated, its
+ * subsequent linkage (if any) must be performed by a bootstrap method
+ * call initiated after the invalidation occurred.
+ *
+ * If several threads simultaneously execute a bootstrap method for a single dynamic
+ * call site, the JVM must choose one target object and installs it visibly to
+ * all threads. Any other bootstrap method calls are allowed to complete, but their
+ * results are ignored, and their dynamic call site invocations proceed with the originally
+ * chosen target object.
+ *
+ * The JVM is free to duplicate dynamic call sites.
+ * This means that, even if a class contains just one {@code invokedynamic}
+ * instruction, its bootstrap method may be executed several times,
+ * once for each duplicate. Thus, bootstrap method code should not
+ * assume an exclusive one-to-one correspondence between particular occurrences
+ * of {@code invokedynamic} bytecodes in class files and linkage events.
+ *
+ * In principle, each individual execution of an {@code invokedynamic}
+ * instruction could be deemed (by a conforming implementation) to be a separate
+ * duplicate, requiring its own execution of the bootstrap method.
+ * However, implementations are expected to perform code duplication
+ * (if at all) in order to improve performance, not make it worse.
+ *
* @author John Rose, JSR 292 EG
*/
diff --git a/src/share/classes/java/io/ObjectInputStream.java b/src/share/classes/java/io/ObjectInputStream.java
index 3a5c1dee08093c6922e01b9d9ae0ed53f22b07f4..2ed505f3b07c6cd940bb632037e8e854f9cf4cd9 100644
--- a/src/share/classes/java/io/ObjectInputStream.java
+++ b/src/share/classes/java/io/ObjectInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -265,7 +265,7 @@ public class ObjectInputStream
* object currently being deserialized and descriptor for current class.
* Null when not during readObject upcall.
*/
- private CallbackContext curContext;
+ private SerialCallbackContext curContext;
/**
* Creates an ObjectInputStream that reads from the specified InputStream.
@@ -1798,7 +1798,7 @@ public class ObjectInputStream
private void readExternalData(Externalizable obj, ObjectStreamClass desc)
throws IOException
{
- CallbackContext oldContext = curContext;
+ SerialCallbackContext oldContext = curContext;
curContext = null;
try {
boolean blocked = desc.hasBlockExternalData();
@@ -1857,10 +1857,10 @@ public class ObjectInputStream
slotDesc.hasReadObjectMethod() &&
handles.lookupException(passHandle) == null)
{
- CallbackContext oldContext = curContext;
+ SerialCallbackContext oldContext = curContext;
try {
- curContext = new CallbackContext(obj, slotDesc);
+ curContext = new SerialCallbackContext(obj, slotDesc);
bin.setBlockDataMode(true);
slotDesc.invokeReadObject(obj, this);
@@ -3505,42 +3505,4 @@ public class ObjectInputStream
}
}
- /**
- * Context that during upcalls to class-defined readObject methods; holds
- * object currently being deserialized and descriptor for current class.
- * This context keeps a boolean state to indicate that defaultReadObject
- * or readFields has already been invoked with this context or the class's
- * readObject method has returned; if true, the getObj method throws
- * NotActiveException.
- */
- private static class CallbackContext {
- private final Object obj;
- private final ObjectStreamClass desc;
- private final AtomicBoolean used = new AtomicBoolean();
-
- public CallbackContext(Object obj, ObjectStreamClass desc) {
- this.obj = obj;
- this.desc = desc;
- }
-
- public Object getObj() throws NotActiveException {
- checkAndSetUsed();
- return obj;
- }
-
- public ObjectStreamClass getDesc() {
- return desc;
- }
-
- private void checkAndSetUsed() throws NotActiveException {
- if (!used.compareAndSet(false, true)) {
- throw new NotActiveException(
- "not in readObject invocation or fields already read");
- }
- }
-
- public void setUsed() {
- used.set(true);
- }
- }
}
diff --git a/src/share/classes/java/io/ObjectOutputStream.java b/src/share/classes/java/io/ObjectOutputStream.java
index 3a722d43a9efdc0fe36fc9d7cb5196b7e83976d6..5b37e4dc6ca494b4bd549940d4fdafd6b6b27d08 100644
--- a/src/share/classes/java/io/ObjectOutputStream.java
+++ b/src/share/classes/java/io/ObjectOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@ import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue;
+import java.io.SerialCallbackContext;
/**
* An ObjectOutputStream writes primitive data types and graphs of Java objects
@@ -191,10 +192,12 @@ public class ObjectOutputStream
private boolean enableReplace;
// values below valid only during upcalls to writeObject()/writeExternal()
- /** object currently being serialized */
- private Object curObj;
- /** descriptor for current class (null if in writeExternal()) */
- private ObjectStreamClass curDesc;
+ /**
+ * Context during upcalls to class-defined writeObject methods; holds
+ * object currently being serialized and descriptor for current class.
+ * Null when not during writeObject upcall.
+ */
+ private SerialCallbackContext curContext;
/** current PutField object */
private PutFieldImpl curPut;
@@ -426,9 +429,11 @@ public class ObjectOutputStream
* An asynchronous datagram channel is created by invoking one of the {@link
- * #open open} methods defined by this class. It is not possible to create a channel
- * for an arbitrary, pre-existing datagram socket. A newly-created asynchronous
- * datagram channel is open but not connected. It need not be connected in order
- * for the {@link #send send} and {@link #receive receive} methods to be used.
- * A datagram channel may be connected, by invoking its {@link #connect connect}
- * method, in order to avoid the overhead of the security checks that are otherwise
- * performed as part of every send and receive operation when a security manager
- * is set. The channel must be connected in order to use the {@link #read read}
- * and {@link #write write} methods, since those methods do not accept or return
- * socket addresses. Once connected, an asynchronous datagram channel remains
- * connected until it is disconnected or closed.
- *
- * Socket options are configured using the {@link #setOption(SocketOption,Object)
- * setOption} method. An asynchronous datagram channel to an Internet Protocol
- * (IP) socket supports the following options:
- * Asynchronous datagram channels allow more than one read/receive and
- * write/send to be oustanding at any given time.
- *
- * Usage Example:
- * The new channel is created by invoking the {@link
- * java.nio.channels.spi.AsynchronousChannelProvider#openAsynchronousDatagramChannel
- * openAsynchronousDatagramChannel} method on the {@link
- * java.nio.channels.spi.AsynchronousChannelProvider} object that created
- * the given group (or the default provider where {@code group} is {@code
- * null}).
- *
- * The {@code family} parameter is used to specify the {@link ProtocolFamily}.
- * If the datagram channel is to be used for Internet Protocol {@link
- * MulticastChannel multicasting} then this parameter should correspond to
- * the address type of the multicast groups that this channel will join.
- *
- * @param family
- * The protocol family, or {@code null} to use the default protocol
- * family
- * @param group
- * The group to which the newly constructed channel should be bound,
- * or {@code null} for the default group
- *
- * @return A new asynchronous datagram channel
- *
- * @throws UnsupportedOperationException
- * If the specified protocol family is not supported. For example,
- * suppose the parameter is specified as {@link
- * java.net.StandardProtocolFamily#INET6 INET6} but IPv6 is not
- * enabled on the platform.
- * @throws ShutdownChannelGroupException
- * The specified group is shutdown
- * @throws IOException
- * If an I/O error occurs
- */
- public static AsynchronousDatagramChannel open(ProtocolFamily family,
- AsynchronousChannelGroup group)
- throws IOException
- {
- AsynchronousChannelProvider provider = (group == null) ?
- AsynchronousChannelProvider.provider() : group.provider();
- return provider.openAsynchronousDatagramChannel(family, group);
- }
-
- /**
- * Opens an asynchronous datagram channel.
- *
- * This method returns an asynchronous datagram channel that is
- * bound to the default group. This method is equivalent to evaluating
- * the expression:
- * Where the channel is connected to an Internet Protocol socket address
- * then the return value from this method is of type {@link
- * java.net.InetSocketAddress}.
- *
- * @return The remote address; {@code null} if the channel's socket is not
- * connected
- *
- * @throws ClosedChannelException
- * If the channel is closed
- * @throws IOException
- * If an I/O error occurs
- */
- public abstract SocketAddress getRemoteAddress() throws IOException;
-
- /**
- * Connects this channel's socket.
- *
- * The channel's socket is configured so that it only receives
- * datagrams from, and sends datagrams to, the given remote peer
- * address. Once connected, datagrams may not be received from or sent to
- * any other address. A datagram socket remains connected until it is
- * explicitly disconnected or until it is closed.
- *
- * This method performs exactly the same security checks as the {@link
- * java.net.DatagramSocket#connect connect} method of the {@link
- * java.net.DatagramSocket} class. That is, if a security manager has been
- * installed then this method verifies that its {@link
- * java.lang.SecurityManager#checkAccept checkAccept} and {@link
- * java.lang.SecurityManager#checkConnect checkConnect} methods permit
- * datagrams to be received from and sent to, respectively, the given
- * remote address.
- *
- * This method may be invoked at any time. Whether it has any effect
- * on outstanding read or write operations is implementation specific and
- * therefore not specified.
- *
- * @param remote
- * The remote address to which this channel is to be connected
- *
- * @return This datagram channel
- *
- * @throws ClosedChannelException
- * If this channel is closed
- *
- * @throws SecurityException
- * If a security manager has been installed
- * and it does not permit access to the given remote address
- *
- * @throws IOException
- * If some other I/O error occurs
- */
- public abstract AsynchronousDatagramChannel connect(SocketAddress remote)
- throws IOException;
-
- /**
- * Disconnects this channel's socket.
- *
- * The channel's socket is configured so that it can receive datagrams
- * from, and sends datagrams to, any remote address so long as the security
- * manager, if installed, permits it.
- *
- * This method may be invoked at any time. Whether it has any effect
- * on outstanding read or write operations is implementation specific and
- * therefore not specified.
- *
- * @return This datagram channel
- *
- * @throws IOException
- * If some other I/O error occurs
- */
- public abstract AsynchronousDatagramChannel disconnect() throws IOException;
-
- /**
- * Receives a datagram via this channel.
- *
- * This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is the datagram's source address.
- *
- * The datagram is transferred into the given byte buffer starting at
- * its current position, as if by a regular {@link AsynchronousByteChannel#read
- * read} operation. If there are fewer bytes remaining in the buffer
- * than are required to hold the datagram then the remainder of the datagram
- * is silently discarded.
- *
- * If a timeout is specified and the timeout elapses before the operation
- * completes then the operation completes with the exception {@link
- * InterruptedByTimeoutException}. When a timeout elapses then the state of
- * the {@link ByteBuffer} is not defined. The buffers should be discarded or
- * at least care must be taken to ensure that the buffer is not accessed
- * while the channel remains open.
- *
- * When a security manager has been installed and the channel is not
- * connected, then it verifies that the source's address and port number are
- * permitted by the security manager's {@link SecurityManager#checkAccept
- * checkAccept} method. The permission check is performed with privileges that
- * are restricted by the calling context of this method. If the permission
- * check fails then the operation completes with a {@link SecurityException}.
- * The overhead of this security check can be avoided by first connecting the
- * socket via the {@link #connect connect} method.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param timeout
- * The timeout, or {@code 0L} for no timeout
- * @param unit
- * The time unit of the {@code timeout} argument
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the timeout is negative or the buffer is read-only
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void receive(ByteBuffer dst,
- long timeout,
- TimeUnit unit,
- A attachment,
- CompletionHandler This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is the datagram's source address.
- *
- * This method is equivalent to invoking {@link
- * #receive(ByteBuffer,long,TimeUnit,Object,CompletionHandler)} with a
- * timeout of {@code 0L}.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the buffer is read-only
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public final void receive(ByteBuffer dst,
- A attachment,
- CompletionHandler This method initiates the receiving of a datagram into the given
- * buffer. The method behaves in exactly the same manner as the {@link
- * #receive(ByteBuffer,Object,CompletionHandler)
- * receive(ByteBuffer,Object,CompletionHandler)} method except that instead
- * of specifying a completion handler, this method returns a {@code Future}
- * representing the pending result. The {@code Future}'s {@link Future#get()
- * get} method returns the datagram's source address.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- *
- * @return a {@code Future} object representing the pending result
- *
- * @throws IllegalArgumentException
- * If the buffer is read-only
- */
- public abstract Future This method initiates sending of a datagram from the given buffer to
- * the given address. The {@code handler} parameter is a completion handler
- * that is invoked when the send completes (or fails). The result passed to
- * the completion handler is the number of bytes sent.
- *
- * Otherwise this method works in the same manner as the {@link
- * AsynchronousByteChannel#write(ByteBuffer,Object,CompletionHandler)}
- * method.
- *
- * @param src
- * The buffer containing the datagram to be sent
- * @param target
- * The address to which the datagram is to be sent
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws UnresolvedAddressException
- * If the given remote address is not fully resolved
- * @throws UnsupportedAddressTypeException
- * If the type of the given remote address is not supported
- * @throws IllegalArgumentException
- * If the channel's socket is connected and is connected to an
- * address that is not equal to {@code target}
- * @throws SecurityException
- * If a security manager has been installed and it does not permit
- * datagrams to be sent to the given address
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void send(ByteBuffer src,
- SocketAddress target,
- A attachment,
- CompletionHandler This method initiates sending of a datagram from the given buffer to
- * the given address. The method behaves in exactly the same manner as the
- * {@link #send(ByteBuffer,SocketAddress,Object,CompletionHandler)
- * send(ByteBuffer,SocketAddress,Object,CompletionHandler)} method except
- * that instead of specifying a completion handler, this method returns a
- * {@code Future} representing the pending result. The {@code Future}'s
- * {@link Future#get() get} method returns the number of bytes sent.
- *
- * @param src
- * The buffer containing the datagram to be sent
- * @param target
- * The address to which the datagram is to be sent
- *
- * @return a {@code Future} object representing the pending result
- *
- * @throws UnresolvedAddressException
- * If the given remote address is not fully resolved
- * @throws UnsupportedAddressTypeException
- * If the type of the given remote address is not supported
- * @throws IllegalArgumentException
- * If the channel's socket is connected and is connected to an
- * address that is not equal to {@code target}
- * @throws SecurityException
- * If a security manager has been installed and it does not permit
- * datagrams to be sent to the given address
- */
- public abstract Future This method initiates the receiving of a datagram into the given
- * buffer. The {@code handler} parameter is a completion handler that is
- * invoked when the receive operation completes (or fails). The result
- * passed to the completion handler is number of bytes read.
- *
- * This method may only be invoked if this channel is connected, and it
- * only accepts datagrams from the peer that the channel is connected too.
- * The datagram is transferred into the given byte buffer starting at
- * its current position and exactly as specified in the {@link
- * AsynchronousByteChannel} interface. If there are fewer bytes
- * remaining in the buffer than are required to hold the datagram then the
- * remainder of the datagram is silently discarded.
- *
- * If a timeout is specified and the timeout elapses before the operation
- * completes then the operation completes with the exception {@link
- * InterruptedByTimeoutException}. When a timeout elapses then the state of
- * the {@link ByteBuffer} is not defined. The buffers should be discarded or
- * at least care must be taken to ensure that the buffer is not accessed
- * while the channel remains open.
- *
- * @param dst
- * The buffer into which the datagram is to be transferred
- * @param timeout
- * The timeout, or {@code 0L} for no timeout
- * @param unit
- * The time unit of the {@code timeout} argument
- * @param attachment
- * The object to attach to the I/O operation; can be {@code null}
- * @param handler
- * The handler for consuming the result
- *
- * @throws IllegalArgumentException
- * If the timeout is negative or buffer is read-only
- * @throws NotYetConnectedException
- * If this channel is not connected
- * @throws ShutdownChannelGroupException
- * If the channel group has terminated
- */
- public abstract void read(ByteBuffer dst,
- long timeout,
- TimeUnit unit,
- A attachment,
- CompletionHandler
+ * {@code AlgorithmConstraints} objects are immutable. An implementation
+ * of this interface should not provide methods that can change the state
+ * of an instance once it has been created.
+ *
+ * Note that {@code AlgorithmConstraints} can be used to represent the
+ * restrictions described by the security properties
+ * {@code jdk.certpath.disabledAlgorithms} and
+ * {@code jdk.tls.disabledAlgorithms}, or could be used by a
+ * concrete {@code PKIXCertPathChecker} to check whether a specified
+ * certificate in the certification path contains the required algorithm
+ * constraints.
+ *
+ * @see javax.net.ssl.SSLParameters#getAlgorithmConstraints
+ * @see javax.net.ssl.SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+
+public interface AlgorithmConstraints {
+
+ /**
+ * Determines whether an algorithm is granted permission for the
+ * specified cryptographic primitives.
+ *
+ * @param primitives a set of cryptographic primitives
+ * @param algorithm the algorithm name
+ * @param parameters the algorithm parameters, or null if no additional
+ * parameters
+ *
+ * @return true if the algorithm is permitted and can be used for all
+ * of the specified cryptographic primitives
+ *
+ * @throws IllegalArgumentException if primitives or algorithm is null
+ * or empty
+ */
+ public boolean permits(Set
+ * This method is usually used to check key size and key usage.
+ *
+ * @param primitives a set of cryptographic primitives
+ * @param key the key
+ *
+ * @return true if the key can be used for all of the specified
+ * cryptographic primitives
+ *
+ * @throws IllegalArgumentException if primitives is null or empty,
+ * or the key is null
+ */
+ public boolean permits(Set The serialVersionUID of this class is
+ * Note: this method is used to indicate to the peer which signature
+ * algorithms may be used for digital signatures in TLS 1.2. It is
+ * not meaningful for TLS versions prior to 1.2.
+ *
+ * The signature algorithm name must be a standard Java Security
+ * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+ * See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * Note: the local supported signature algorithms should conform to
+ * the algorithm constraints specified by
+ * {@link SSLParameters#getAlgorithmConstraints getAlgorithmConstraints()}
+ * method in
+ * Note: this method is used to indicate to the local side which signature
+ * algorithms may be used for digital signatures in TLS 1.2. It is
+ * not meaningful for TLS versions prior to 1.2.
+ *
+ * The signature algorithm name must be a standard Java Security
+ * name (such as "SHA1withRSA", "SHA256withECDSA", and so on).
+ * See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * @return An array of supported signature algorithms, in descending
+ * order of preference. The return value is an empty array if
+ * the peer has not sent the supported signature algorithms.
+ *
+ * @see X509KeyManager
+ * @see X509ExtendedKeyManager
+ */
+ public abstract String[] getPeerSupportedSignatureAlgorithms();
+}
diff --git a/src/share/classes/javax/net/ssl/HttpsURLConnection.java b/src/share/classes/javax/net/ssl/HttpsURLConnection.java
index e9c478fece1549cb1deeed0a3ec631962ee98d77..6d799e3ff5fe8193a2a151eea111ba1c8cc007bf 100644
--- a/src/share/classes/javax/net/ssl/HttpsURLConnection.java
+++ b/src/share/classes/javax/net/ssl/HttpsURLConnection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1999, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -188,19 +188,8 @@ class HttpsURLConnection extends HttpURLConnection
*
* The default implementation will deny such connections.
*/
- private static HostnameVerifier defaultHostnameVerifier;
-
- /**
- * Initialize the default
+ * TLS protocols may negotiate parameters that are needed when using
+ * an instance of this class, but before the {@code SSLSession} has
+ * been completely initialized and made available via {@code getSession}.
+ * For example, the list of valid signature algorithms may restrict
+ * the type of certificates that can used during TrustManager
+ * decisions, or the maximum TLS fragment packet sizes can be
+ * resized to better support the network environment.
+ *
+ * This method provides early access to the {@code SSLSession} being
+ * constructed. Depending on how far the handshake has progressed,
+ * some data may not yet be available for use. For example, if a
+ * remote server will be sending a Certificate chain, but that chain
+ * has yet not been processed, the {@code getPeerCertificates}
+ * method of {@code SSLSession} will throw a
+ * SSLPeerUnverifiedException. Once that chain has been processed,
+ * {@code getPeerCertificates} will return the proper value.
+ *
+ * @see SSLSocket
+ * @see SSLSession
+ * @see ExtendedSSLSession
+ * @see X509ExtendedKeyManager
+ * @see X509ExtendedTrustManager
+ *
+ * @return null if this instance is not currently handshaking, or
+ * if the current handshake has not progressed far enough to
+ * create a basic SSLSession. Otherwise, this method returns the
+ * {@code SSLSession} currently being negotiated.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ *
+ * @since 1.7
+ */
+ public SSLSession getHandshakeSession() {
+ throw new UnsupportedOperationException();
+ }
+
+
/**
* Initiates handshaking (initial or renegotiation) on this SSLEngine.
*
diff --git a/src/share/classes/javax/net/ssl/SSLParameters.java b/src/share/classes/javax/net/ssl/SSLParameters.java
index ed8913230afbd8ee0fb6b0f4dd8c28d530abd3d0..4bb20a164eb50bc3a5657e5cbaa4395c52e529c2 100644
--- a/src/share/classes/javax/net/ssl/SSLParameters.java
+++ b/src/share/classes/javax/net/ssl/SSLParameters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,24 +25,29 @@
package javax.net.ssl;
+import java.security.AlgorithmConstraints;
+
/**
* Encapsulates parameters for an SSL/TLS connection. The parameters
* are the list of ciphersuites to be accepted in an SSL/TLS handshake,
- * the list of protocols to be allowed, and whether SSL/TLS servers should
- * request or require client authentication.
- *
- * SSLParameters can be created via the constructors in this class.
+ * the list of protocols to be allowed, the endpoint identification
+ * algorithm during SSL/TLS handshaking, the algorithm constraints and
+ * whether SSL/TLS servers should request or require client authentication.
+ *
+ * SSLParameters can be created via the constructors in this class.
* Objects can also be obtained using the SSLParameters can be applied to a connection via the methods
+ *
+ * SSLParameters can be applied to a connection via the methods
* {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
- * {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
+ * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
+ * and {@link SSLEngine#setSSLParameters SSLEngine.getSSLParameters()}.
*
* @see SSLSocket
* @see SSLEngine
@@ -56,11 +61,13 @@ public class SSLParameters {
private String[] protocols;
private boolean wantClientAuth;
private boolean needClientAuth;
+ private String identificationAlgorithm;
+ private AlgorithmConstraints algorithmConstraints;
/**
* Constructs SSLParameters.
- *
- * The cipherSuites and protocols values are set to
+ * The cipherSuites and protocols values are set to
* Calling this constructor is equivalent to calling the no-args
* constructor followed by
*
* Calling this constructor is equivalent to calling the no-args
* constructor followed by
*
+ * If the
+ * If the
@@ -449,8 +449,79 @@ public abstract class SSLServerSocket extends ServerSocket
*
* @return true indicates that sessions may be created; this
* is the default. false indicates that an existing
- * session must be resumed.
+ * session must be resumed
* @see #setEnableSessionCreation(boolean)
*/
public abstract boolean getEnableSessionCreation();
+
+ /**
+ * Returns the SSLParameters in effect for newly accepted connections.
+ * The ciphersuites and protocols of the returned SSLParameters
+ * are always non-null.
+ *
+ * @return the SSLParameters in effect for newly accepted connections
+ *
+ * @see #setSSLParameters(SSLParameters)
+ *
+ * @since 1.7
+ */
+ public SSLParameters getSSLParameters() {
+ SSLParameters parameters = new SSLParameters();
+
+ parameters.setCipherSuites(getEnabledCipherSuites());
+ parameters.setProtocols(getEnabledProtocols());
+ if (getNeedClientAuth()) {
+ parameters.setNeedClientAuth(true);
+ } else if (getWantClientAuth()) {
+ parameters.setWantClientAuth(true);
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Applies SSLParameters to newly accepted connections.
+ *
+ * This means:
+ *
+ * TLS protocols may negotiate parameters that are needed when using
+ * an instance of this class, but before the {@code SSLSession} has
+ * been completely initialized and made available via {@code getSession}.
+ * For example, the list of valid signature algorithms may restrict
+ * the type of certificates that can used during TrustManager
+ * decisions, or the maximum TLS fragment packet sizes can be
+ * resized to better support the network environment.
+ *
+ * This method provides early access to the {@code SSLSession} being
+ * constructed. Depending on how far the handshake has progressed,
+ * some data may not yet be available for use. For example, if a
+ * remote server will be sending a Certificate chain, but that chain
+ * has yet not been processed, the {@code getPeerCertificates}
+ * method of {@code SSLSession} will throw a
+ * SSLPeerUnverifiedException. Once that chain has been processed,
+ * {@code getPeerCertificates} will return the proper value.
+ *
+ * Unlike {@link #getSession()}, this method does not initiate the
+ * initial handshake and does not block until handshaking is
+ * complete.
+ *
+ * @see SSLEngine
+ * @see SSLSession
+ * @see ExtendedSSLSession
+ * @see X509ExtendedKeyManager
+ * @see X509ExtendedTrustManager
+ *
+ * @return null if this instance is not currently handshaking, or
+ * if the current handshake has not progressed far enough to
+ * create a basic SSLSession. Otherwise, this method returns the
+ * {@code SSLSession} currently being negotiated.
+ * @throws UnsupportedOperationException if the underlying provider
+ * does not implement the operation.
+ *
+ * @since 1.7
+ */
+ public SSLSession getHandshakeSession() {
+ throw new UnsupportedOperationException();
+ }
+
+
/**
* Registers an event listener to receive notifications that an
* SSL handshake has completed on this connection.
diff --git a/src/share/classes/javax/net/ssl/SSLSocketFactory.java b/src/share/classes/javax/net/ssl/SSLSocketFactory.java
index a7971b5504beb5cefa360f9255f7779488070aca..f7d5e5b0a2fc2ca1970cca081a4304c49c9717c0 100644
--- a/src/share/classes/javax/net/ssl/SSLSocketFactory.java
+++ b/src/share/classes/javax/net/ssl/SSLSocketFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -30,6 +30,7 @@ import java.net.*;
import javax.net.SocketFactory;
import java.io.IOException;
import java.security.*;
+import java.util.Locale;
import sun.security.action.GetPropertyAction;
@@ -50,7 +51,8 @@ public abstract class SSLSocketFactory extends SocketFactory
static {
String s = java.security.AccessController.doPrivileged(
- new GetPropertyAction("javax.net.debug", "")).toLowerCase();
+ new GetPropertyAction("javax.net.debug", "")).toLowerCase(
+ Locale.ENGLISH);
DEBUG = s.contains("all") || s.contains("ssl");
}
diff --git a/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java
new file mode 100644
index 0000000000000000000000000000000000000000..e69a282c55f3149c9a0bcb759615911b11d336a3
--- /dev/null
+++ b/src/share/classes/javax/net/ssl/X509ExtendedTrustManager.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package javax.net.ssl;
+
+import java.net.Socket;
+import javax.net.ssl.X509TrustManager;
+
+import java.security.cert.X509Certificate;
+import java.security.cert.CertificateException;
+
+/**
+ * Extensions to the
+ * To prevent man-in-the-middle attacks, hostname checks can be done
+ * to verify that the hostname in an end-entity certificate matches the
+ * targeted hostname. TLS does not require such checks, but some protocols
+ * over TLS (such as HTTPS) do. In earlier versions of the JDK, the
+ * certificate chain checks were done at the SSL/TLS layer, and the hostname
+ * verification checks were done at the layer over TLS. This class allows
+ * for the checking to be done during a single call to this class.
+ *
+ * RFC 2830 defines the server identification specification for the "LDAPS"
+ * algorithm. RFC 2818 defines both the server identification and the
+ * client identification specification for the "HTTPS" algorithm.
+ *
+ * @see X509TrustManager
+ * @see HostnameVerifier
+ *
+ * @since 1.7
+ */
+public abstract class X509ExtendedTrustManager implements X509TrustManager {
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ *
+ * The authentication type is determined by the actual certificate
+ * used. For instance, if RSAPublicKey is used, the authType
+ * should be "RSA". Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is the key exchange algorithm portion
+ * of the cipher suites represented as a String, such as "RSA",
+ * "DHE_DSS". Note: for some exportable cipher suites, the key
+ * exchange algorithm is determined at run time during the
+ * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+ * the authType should be RSA_EXPORT when an ephemeral RSA key is
+ * used for the key exchange, and RSA when the key from the server
+ * certificate is used. Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is determined by the actual certificate
+ * used. For instance, if RSAPublicKey is used, the authType
+ * should be "RSA". Checking is case-sensitive.
+ *
+ * If the
+ * If the
+ * The authentication type is the key exchange algorithm portion
+ * of the cipher suites represented as a String, such as "RSA",
+ * "DHE_DSS". Note: for some exportable cipher suites, the key
+ * exchange algorithm is determined at run time during the
+ * handshake. For instance, for TLS_RSA_EXPORT_WITH_RC4_40_MD5,
+ * the authType should be RSA_EXPORT when an ephemeral RSA key is
+ * used for the key exchange, and RSA when the key from the server
+ * certificate is used. Checking is case-sensitive.
+ *
+ * If the
+ * If the
diff --git a/src/share/classes/sun/dyn/CallSiteImpl.java b/src/share/classes/sun/dyn/CallSiteImpl.java
index 2e02e74ebd08b54a459e6d529729649cfd04ef0f..f7c2d7099a78cd2406b62148e40f8adfef58c33d 100644
--- a/src/share/classes/sun/dyn/CallSiteImpl.java
+++ b/src/share/classes/sun/dyn/CallSiteImpl.java
@@ -26,6 +26,7 @@
package sun.dyn;
import java.dyn.*;
+import static sun.dyn.MemberName.uncaughtException;
/**
* Parts of CallSite known to the JVM.
@@ -49,18 +50,21 @@ public class CallSiteImpl {
}
CallSite site;
try {
- if (bootstrapMethod.type().parameterCount() == 3)
- site = bootstrapMethod.
- * The method is specified by name and type, as if via this expression:
- * {@code MethodHandles.lookup().findVirtual(this.getClass(), name, type)}.
- * The class defining the method might be an anonymous inner class.
- *
- * The method handle type of {@code this} (i.e, the fully constructed object)
- * will be the given method handle type.
- * A call to {@code this} will invoke the selected method.
- * The receiver argument will be bound to {@code this} on every method
- * handle invocation.
- *
- * Rationale:
- * Although this constructor may seem to be a mere luxury,
- * it is not subsumed by the more general constructor which
- * takes any {@code MethodHandle} as the entry point argument.
- * In order to convert an entry point name to a method handle,
- * the self-class of the object is required (in order to do
- * the lookup). The self-class, in turn, is generally not
- * available at the time of the constructor invocation,
- * due to the rules of Java and the JVM verifier.
- * One cannot call {@code this.getClass()}, because
- * the value of {@code this} is inaccessible at the point
- * of the constructor call. (Changing this would require
- * change to the Java language, verifiers, and compilers.)
- * In particular, this constructor allows {@code JavaMethodHandle}s
- * to be created in combination with the anonymous inner class syntax.
- * @param entryPointName the name of the entry point method
- * @param type (optional) the desired type of the method handle
- */
- protected JavaMethodHandle(String entryPointName, MethodType type) {
- super(entryPointName, type, true);
-
- }
-
- /**
- * Create a method handle whose entry point is a non-static method
- * visible in the exact (most specific) class of
- * the newly constructed object.
- *
- * The method is specified only by name.
- * There must be exactly one method of that name visible in the object class,
- * either inherited or locally declared.
- * (That is, the method must not be overloaded.)
- *
- * The method handle type of {@code this} (i.e, the fully constructed object)
- * will be the same as the type of the selected non-static method.
- * The receiver argument will be bound to {@code this} on every method
- * handle invocation.
- * ISSUE: This signature wildcarding feature does not correspond to
- * any MethodHandles.Lookup API element. Can we eliminate it?
- * Alternatively, it is useful for naming non-overloaded methods.
- * Shall we make type arguments optional in the Lookup methods,
- * throwing an error in cases of ambiguity?
- *
- * For this method's rationale, see the documentation
- * for {@link #JavaMethodHandle(String,MethodType)}.
- * @param entryPointName the name of the entry point method
- */
- protected JavaMethodHandle(String entryPointName) {
- super(entryPointName, (MethodType) null, false);
- }
}
diff --git a/src/share/classes/sun/dyn/MemberName.java b/src/share/classes/sun/dyn/MemberName.java
index db21f2b4121cd4c53fef37a1b3626fade411c055..f45d1603ebf157031a65966d15d82dc33e41e259 100644
--- a/src/share/classes/sun/dyn/MemberName.java
+++ b/src/share/classes/sun/dyn/MemberName.java
@@ -521,6 +521,11 @@ public final class MemberName implements Member, Cloneable {
if (lookupClass != null) message += ", from " + lookupClass.getName();
return new NoAccessException(message);
}
+ public static Error uncaughtException(Exception ex) {
+ Error err = new InternalError("uncaught exception");
+ err.initCause(ex);
+ return err;
+ }
/** Actually making a query requires an access check. */
public static Factory getFactory(Access token) {
@@ -641,7 +646,7 @@ public final class MemberName implements Member, Cloneable {
* If lookup fails or access is not permitted, a {@linkplain NoAccessException} is thrown.
* Otherwise a fresh copy of the given member is returned, with modifier bits filled in.
*/
- public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class> lookupClass) {
+ public MemberName resolveOrFail(MemberName m, boolean searchSupers, Class> lookupClass) throws NoAccessException {
MemberName result = resolveOrNull(m, searchSupers, lookupClass);
if (result != null)
return result;
diff --git a/src/share/classes/sun/dyn/MethodHandleImpl.java b/src/share/classes/sun/dyn/MethodHandleImpl.java
index 25dc470d061228539a7a73f8b894f2d36eb56dba..caa96b90d69642fc99cc8561d06c1f876f7c5d3c 100644
--- a/src/share/classes/sun/dyn/MethodHandleImpl.java
+++ b/src/share/classes/sun/dyn/MethodHandleImpl.java
@@ -25,11 +25,8 @@
package sun.dyn;
-import java.dyn.JavaMethodHandle;
-import java.dyn.MethodHandle;
-import java.dyn.MethodHandles;
+import java.dyn.*;
import java.dyn.MethodHandles.Lookup;
-import java.dyn.MethodType;
import java.util.logging.Level;
import java.util.logging.Logger;
import sun.dyn.util.VerifyType;
@@ -46,6 +43,7 @@ import sun.dyn.util.Wrapper;
import sun.misc.Unsafe;
import static sun.dyn.MemberName.newIllegalArgumentException;
import static sun.dyn.MemberName.newNoAccessException;
+import static sun.dyn.MemberName.uncaughtException;
/**
* Base class for method handles, containing JVM-specific fields and logic.
@@ -173,7 +171,7 @@ public abstract class MethodHandleImpl {
*/
public static
MethodHandle findMethod(Access token, MemberName method,
- boolean doDispatch, Class> lookupClass) {
+ boolean doDispatch, Class> lookupClass) throws NoAccessException {
Access.check(token); // only trusted calls
MethodType mtype = method.getMethodType();
if (!method.isStatic()) {
@@ -320,7 +318,7 @@ public abstract class MethodHandleImpl {
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(AllocateObject.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
// Corresponding generic constructor types:
@@ -416,9 +414,7 @@ public abstract class MethodHandleImpl {
f = c.getDeclaredField(field.getName());
return unsafe.staticFieldBase(f);
} catch (Exception ee) {
- Error e = new InternalError();
- e.initCause(ee);
- throw e;
+ throw uncaughtException(ee);
}
}
@@ -473,10 +469,8 @@ public abstract class MethodHandleImpl {
MethodHandle mh;
try {
mh = IMPL_LOOKUP.findVirtual(FieldAccessor.class, name, type);
- } catch (NoAccessException ee) {
- Error e = new InternalError("name,type="+name+type);
- e.initCause(ee);
- throw e;
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
}
if (evclass != vclass || (!isStatic && ecclass != cclass)) {
MethodType strongType = FieldAccessor.ftype(cclass, vclass, isSetter, isStatic);
@@ -543,10 +537,8 @@ public abstract class MethodHandleImpl {
MethodHandle mh;
try {
mh = IMPL_LOOKUP.findStatic(FieldAccessor.class, name, type);
- } catch (NoAccessException ee) {
- Error e = new InternalError("name,type="+name+type);
- e.initCause(ee);
- throw e;
+ } catch (NoAccessException ex) {
+ throw uncaughtException(ex);
}
if (caclass != null) {
MethodType strongType = FieldAccessor.atype(caclass, isSetter);
@@ -1031,7 +1023,7 @@ public abstract class MethodHandleImpl {
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithTest.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
}
@@ -1167,7 +1159,7 @@ public abstract class MethodHandleImpl {
try {
VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true));
} catch (NoAccessException ex) {
- throw new InternalError("");
+ throw uncaughtException(ex);
}
}
}
@@ -1207,9 +1199,16 @@ public abstract class MethodHandleImpl {
return AdapterMethodHandle.makeRetypeRaw(token, type, THROW_EXCEPTION);
}
- static final MethodHandle THROW_EXCEPTION
+ static final MethodHandle THROW_EXCEPTION;
+ static {
+ try {
+ THROW_EXCEPTION
= IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException",
MethodType.methodType(Empty.class, Throwable.class));
+ } catch (NoAccessException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
static A The An application-generated path will generally have no need
- * to contain calls to this method; they are typically introduced
- * by a Other
+ * Certificate fields such as the subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to
+ * the specified algorithm constraints.
*
- * @author Xuelei Fan
+ * @see PKIXCertPathChecker
+ * @see PKIXParameters
*/
final public class AlgorithmChecker extends PKIXCertPathChecker {
- // the disabled algorithms
- private static final String[] disabledAlgorithms = new String[] {"md2"};
+ private final AlgorithmConstraints constraints;
+ private final PublicKey trustedPubKey;
+ private PublicKey prevPubKey;
+
+ private final static Set
+ * Note that this constructor will be used to check a certification
+ * path where the trust anchor is unknown, or a certificate list which may
+ * contain the trust anchor. This constructor is used by SunJSSE.
+ *
+ * @param constraints the algorithm constraints (or null)
*/
- static AlgorithmChecker getInstance() {
- return INSTANCE;
+ public AlgorithmChecker(AlgorithmConstraints constraints) {
+ this.prevPubKey = null;
+ this.trustedPubKey = null;
+ this.constraints = constraints;
}
/**
- * Initializes the internal state of the checker from parameters
- * specified in the constructor.
+ * Create a new
+ * If there is no trust anchor specified and the checker has not started,
+ * set the trust anchor.
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
+ */
+ void trySetTrustAnchor(TrustAnchor anchor) {
+ // Don't bother if the check has started or trust anchor has already
+ // specified.
+ if (prevPubKey == null) {
+ if (anchor == null) {
+ throw new IllegalArgumentException(
+ "The trust anchor cannot be null");
+ }
+
+ // Don't bother to change the trustedPubKey.
+ if (anchor.getTrustedCert() != null) {
+ prevPubKey = anchor.getTrustedCert().getPublicKey();
+ } else {
+ prevPubKey = anchor.getCAPublicKey();
+ }
+ }
}
- private static void check(String algName)
- throws CertPathValidatorException {
+ /**
+ * Check the signature algorithm with the specified public key.
+ *
+ * @param key the public key to verify the CRL signature
+ * @param crl the target CRL
+ */
+ static void check(PublicKey key, X509CRL crl)
+ throws CertPathValidatorException {
- String lowerCaseAlgName = algName.toLowerCase(Locale.ENGLISH);
+ X509CRLImpl x509CRLImpl = null;
+ try {
+ x509CRLImpl = X509CRLImpl.toImpl(crl);
+ } catch (CRLException ce) {
+ throw new CertPathValidatorException(ce);
+ }
- for (String disabled : disabledAlgorithms) {
- // checking the signature algorithm name
- if (lowerCaseAlgName.indexOf(disabled) != -1) {
- throw new CertPathValidatorException(
- "algorithm check failed: " + algName + " is disabled");
- }
+ AlgorithmId algorithmId = x509CRLImpl.getSigAlgId();
+ check(key, algorithmId);
+ }
+
+ /**
+ * Check the signature algorithm with the specified public key.
+ *
+ * @param key the public key to verify the CRL signature
+ * @param crl the target CRL
+ */
+ static void check(PublicKey key, AlgorithmId algorithmId)
+ throws CertPathValidatorException {
+ String sigAlgName = algorithmId.getName();
+ AlgorithmParameters sigAlgParams = algorithmId.getParameters();
+
+ if (!certPathDefaultConstraints.permits(
+ SIGNATURE_PRIMITIVE_SET, sigAlgName, key, sigAlgParams)) {
+ throw new CertPathValidatorException(
+ "algorithm check failed: " + sigAlgName + " is disabled");
}
}
}
+
diff --git a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
index 4dd29710ef1fbabdbf4e0928e8b8efe5e9d07682..a980e7d16573d083049a5ef52a41efb389f1a661 100644
--- a/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
+++ b/src/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -289,16 +289,6 @@ class DistributionPointFetcher {
X500Name certIssuer = (X500Name) certImpl.getIssuerDN();
X500Name crlIssuer = (X500Name) crlImpl.getIssuerDN();
- // check the crl signature algorithm
- try {
- AlgorithmChecker.check(crl);
- } catch (CertPathValidatorException cpve) {
- if (debug != null) {
- debug.println("CRL signature algorithm check failed: " + cpve);
- }
- return false;
- }
-
// if crlIssuer is set, verify that it matches the issuer of the
// CRL and the CRL contains an IDP extension with the indirectCRL
// boolean asserted. Otherwise, verify that the CRL issuer matches the
@@ -637,6 +627,16 @@ class DistributionPointFetcher {
}
}
+ // check the crl signature algorithm
+ try {
+ AlgorithmChecker.check(prevKey, crl);
+ } catch (CertPathValidatorException cpve) {
+ if (debug != null) {
+ debug.println("CRL signature algorithm check failed: " + cpve);
+ }
+ return false;
+ }
+
// validate the signature on the CRL
try {
crl.verify(prevKey, provider);
diff --git a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
index ae7ccd3884684e68b89420bb64571606d448bca2..7e828884940bcacf8e3a75601ec449117c05b39e 100644
--- a/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
+++ b/src/share/classes/sun/security/provider/certpath/ForwardBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -718,11 +718,6 @@ class ForwardBuilder extends Builder {
/* we don't perform any validation of the trusted cert */
if (!isTrustedCert) {
- /*
- * check that the signature algorithm is not disabled.
- */
- AlgorithmChecker.check(cert);
-
/*
* Check CRITICAL private extensions for user checkers that
* support forward checking (forwardCheckers) and remove
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
index b72cd79a31cf6dccfa7556460e215dc109df613f..d734ff90408f9eaeb6248c31d867860def3db481 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -327,6 +327,10 @@ class OCSPChecker extends PKIXCertPathChecker {
"(set using the OCSP security properties).");
}
+ // The algorithm constraints of the OCSP trusted responder certificate
+ // does not need to be checked in this code. The constraints will be
+ // checked when the responder's certificate is validated.
+
CertId certId = null;
OCSPResponse response = null;
try {
diff --git a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
index 0b64e412cf688a02cb9964a3cd1ecc89dd67aa3d..63566dd555879a8f378873a8daab0f7d241e6e06 100644
--- a/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
+++ b/src/share/classes/sun/security/provider/certpath/OCSPResponse.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@ import java.security.cert.CertificateException;
import java.security.cert.CertificateParsingException;
import java.security.cert.CertPathValidatorException;
import java.security.cert.CRLReason;
+import java.security.cert.TrustAnchor;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.Date;
@@ -371,6 +372,13 @@ public final class OCSPResponse {
"OCSP responses", cpe);
}
+ // Check algorithm constraints specified in security property
+ // "jdk.certpath.disabledAlgorithms".
+ AlgorithmChecker algChecker = new AlgorithmChecker(
+ new TrustAnchor(responderCert, null));
+ algChecker.init(false);
+ algChecker.check(cert, Collections.
- *
+ *
* This class supports both the Simple validation algorithm from previous
* JSSE versions and PKIX validation. Currently, it is not possible for the
* application to specify PKIX parameters other than trust anchors. This will
@@ -50,19 +51,10 @@ import sun.security.util.HostnameChecker;
* classes.
*
* @author Andreas Sterbenz
- * @author Xuelei Fan
*/
final class X509TrustManagerImpl extends X509ExtendedTrustManager
implements X509TrustManager {
- /**
- * Flag indicating whether to enable revocation check for the PKIX trust
- * manager. Typically, this will only work if the PKIX implementation
- * supports CRL distribution points as we do not manually setup CertStores.
- */
- private final static boolean checkRevocation =
- Debug.getBooleanProperty("com.sun.net.ssl.checkRevocation", false);
-
private final String validatorType;
/**
@@ -103,188 +95,259 @@ final class X509TrustManagerImpl extends X509ExtendedTrustManager
showTrustedCerts();
}
- private void showTrustedCerts() {
- if (debug != null && Debug.isOn("trustmanager")) {
- for (X509Certificate cert : trustedCerts) {
- System.out.println("adding as trusted cert:");
- System.out.println(" Subject: "
- + cert.getSubjectX500Principal());
- System.out.println(" Issuer: "
- + cert.getIssuerX500Principal());
- System.out.println(" Algorithm: "
- + cert.getPublicKey().getAlgorithm()
- + "; Serial number: 0x"
- + cert.getSerialNumber().toString(16));
- System.out.println(" Valid from "
- + cert.getNotBefore() + " until "
- + cert.getNotAfter());
- System.out.println();
- }
- }
+ @Override
+ public void checkClientTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, (Socket)null, true);
}
- private Validator getValidator(String variant) {
- Validator v;
- if (pkixParams == null) {
- v = Validator.getInstance(validatorType, variant, trustedCerts);
- // if the PKIX validator is created from a KeyStore,
- // disable revocation checking
- if (v instanceof PKIXValidator) {
- PKIXValidator pkixValidator = (PKIXValidator)v;
- pkixValidator.getParameters().setRevocationEnabled
- (checkRevocation);
- }
- } else {
- v = Validator.getInstance(validatorType, variant, pkixParams);
- }
- return v;
+ @Override
+ public void checkServerTrusted(X509Certificate chain[], String authType)
+ throws CertificateException {
+ checkTrusted(chain, authType, (Socket)null, false);
}
- private static X509Certificate[] validate(Validator v,
- X509Certificate[] chain, String authType) throws CertificateException {
- Object o = JsseJce.beginFipsProvider();
- try {
- return v.validate(chain, null, authType);
- } finally {
- JsseJce.endFipsProvider(o);
- }
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
+ trustedCerts.toArray(certsArray);
+ return certsArray;
}
- /**
- * Returns true if the client certificate can be trusted.
- *
- * @param chain certificates which establish an identity for the client.
- * Chains of arbitrary length are supported, and certificates
- * marked internally as trusted will short-circuit signature checks.
- * @throws IllegalArgumentException if null or zero-length chain
- * is passed in for the chain parameter or if null or zero-length
- * string is passed in for the authType parameter.
- * @throws CertificateException if the certificate chain is not trusted
- * by this TrustManager.
- */
- public void checkClientTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ checkTrusted(chain, authType, socket, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ Socket socket) throws CertificateException {
+ checkTrusted(chain, authType, socket, false);
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ checkTrusted(chain, authType, engine, true);
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine) throws CertificateException {
+ checkTrusted(chain, authType, engine, false);
+ }
+
+ private Validator checkTrustedInit(X509Certificate[] chain,
+ String authType, boolean isClient) {
if (chain == null || chain.length == 0) {
throw new IllegalArgumentException(
"null or zero-length certificate chain");
}
+
if (authType == null || authType.length() == 0) {
throw new IllegalArgumentException(
"null or zero-length authentication type");
}
- // assume double checked locking with a volatile flag works
- // (guaranteed under the new Tiger memory model)
- Validator v = clientValidator;
- if (v == null) {
- synchronized (this) {
- v = clientValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_CLIENT);
- clientValidator = v;
+ Validator v = null;
+ if (isClient) {
+ v = clientValidator;
+ if (v == null) {
+ synchronized (this) {
+ v = clientValidator;
+ if (v == null) {
+ v = getValidator(Validator.VAR_TLS_CLIENT);
+ clientValidator = v;
+ }
+ }
+ }
+ } else {
+ // assume double checked locking with a volatile flag works
+ // (guaranteed under the new Tiger memory model)
+ v = serverValidator;
+ if (v == null) {
+ synchronized (this) {
+ v = serverValidator;
+ if (v == null) {
+ v = getValidator(Validator.VAR_TLS_SERVER);
+ serverValidator = v;
+ }
+ }
+ }
+ }
+
+ return v;
+ }
+
+
+ private void checkTrusted(X509Certificate[] chain, String authType,
+ Socket socket, boolean isClient) throws CertificateException {
+ Validator v = checkTrustedInit(chain, authType, isClient);
+
+ AlgorithmConstraints constraints = null;
+ if ((socket != null) && socket.isConnected() &&
+ (socket instanceof SSLSocket)) {
+
+ SSLSocket sslSocket = (SSLSocket)socket;
+ SSLSession session = sslSocket.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = sslSocket.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ checkIdentity(hostname, chain[0], identityAlg);
+ }
+
+ // create the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] localSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
+
+ constraints = new SSLAlgorithmConstraints(
+ sslSocket, localSupportedSignAlgs, false);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(sslSocket, false);
}
+ } else {
+ constraints = new SSLAlgorithmConstraints(sslSocket, false);
}
}
- X509Certificate[] trustedChain = validate(v, chain, null);
+
+ X509Certificate[] trustedChain = null;
+ if (isClient) {
+ trustedChain = validate(v, chain, constraints, null);
+ } else {
+ trustedChain = validate(v, chain, constraints, authType);
+ }
if (debug != null && Debug.isOn("trustmanager")) {
System.out.println("Found trusted certificate:");
System.out.println(trustedChain[trustedChain.length - 1]);
}
}
- /**
- * Returns true if the server certifcate can be trusted.
- *
- * @param chain certificates which establish an identity for the server.
- * Chains of arbitrary length are supported, and certificates
- * marked internally as trusted will short-circuit signature checks.
- * @throws IllegalArgumentException if null or zero-length chain
- * is passed in for the chain parameter or if null or zero-length
- * string is passed in for the authType parameter.
- * @throws CertificateException if the certificate chain is not trusted
- * by this TrustManager.
- */
- public void checkServerTrusted(X509Certificate chain[], String authType)
- throws CertificateException {
- if (chain == null || chain.length == 0) {
- throw new IllegalArgumentException(
- "null or zero-length certificate chain");
- }
- if (authType == null || authType.length() == 0) {
- throw new IllegalArgumentException(
- "null or zero-length authentication type");
- }
+ private void checkTrusted(X509Certificate[] chain, String authType,
+ SSLEngine engine, boolean isClient) throws CertificateException {
+ Validator v = checkTrustedInit(chain, authType, isClient);
+
+ AlgorithmConstraints constraints = null;
+ if (engine != null) {
+ SSLSession session = engine.getHandshakeSession();
+ if (session == null) {
+ throw new CertificateException("No handshake session");
+ }
+
+ // check endpoint identity
+ String identityAlg = engine.getSSLParameters().
+ getEndpointIdentificationAlgorithm();
+ if (identityAlg != null && identityAlg.length() != 0) {
+ String hostname = session.getPeerHost();
+ checkIdentity(hostname, chain[0], identityAlg);
+ }
+
+ // create the algorithm constraints
+ ProtocolVersion protocolVersion =
+ ProtocolVersion.valueOf(session.getProtocol());
+ if (protocolVersion.v >= ProtocolVersion.TLS12.v) {
+ if (session instanceof ExtendedSSLSession) {
+ ExtendedSSLSession extSession =
+ (ExtendedSSLSession)session;
+ String[] localSupportedSignAlgs =
+ extSession.getLocalSupportedSignatureAlgorithms();
- // assume double checked locking with a volatile flag works
- // (guaranteed under the new Tiger memory model)
- Validator v = serverValidator;
- if (v == null) {
- synchronized (this) {
- v = serverValidator;
- if (v == null) {
- v = getValidator(Validator.VAR_TLS_SERVER);
- serverValidator = v;
+ constraints = new SSLAlgorithmConstraints(
+ engine, localSupportedSignAlgs, false);
+ } else {
+ constraints =
+ new SSLAlgorithmConstraints(engine, false);
}
+ } else {
+ constraints = new SSLAlgorithmConstraints(engine, false);
}
}
- X509Certificate[] trustedChain = validate(v, chain, authType);
+
+ X509Certificate[] trustedChain = null;
+ if (isClient) {
+ trustedChain = validate(v, chain, constraints, null);
+ } else {
+ trustedChain = validate(v, chain, constraints, authType);
+ }
if (debug != null && Debug.isOn("trustmanager")) {
System.out.println("Found trusted certificate:");
System.out.println(trustedChain[trustedChain.length - 1]);
}
}
- /**
- * Returns a list of CAs accepted to authenticate entities for the
- * specified purpose.
- *
- * @param purpose activity for which CAs should be trusted
- * @return list of CAs accepted for authenticating such tasks
- */
- public X509Certificate[] getAcceptedIssuers() {
- X509Certificate[] certsArray = new X509Certificate[trustedCerts.size()];
- trustedCerts.toArray(certsArray);
- return certsArray;
+ private void showTrustedCerts() {
+ if (debug != null && Debug.isOn("trustmanager")) {
+ for (X509Certificate cert : trustedCerts) {
+ System.out.println("adding as trusted cert:");
+ System.out.println(" Subject: "
+ + cert.getSubjectX500Principal());
+ System.out.println(" Issuer: "
+ + cert.getIssuerX500Principal());
+ System.out.println(" Algorithm: "
+ + cert.getPublicKey().getAlgorithm()
+ + "; Serial number: 0x"
+ + cert.getSerialNumber().toString(16));
+ System.out.println(" Valid from "
+ + cert.getNotBefore() + " until "
+ + cert.getNotAfter());
+ System.out.println();
+ }
+ }
}
- /**
- * Given the partial or complete certificate chain provided by the
- * peer, check its identity and build a certificate path to a trusted
- * root, return if it can be validated and is trusted for client SSL
- * authentication based on the authentication type.
- */
- public void checkClientTrusted(X509Certificate[] chain, String authType,
- String hostname, String algorithm) throws CertificateException {
- checkClientTrusted(chain, authType);
- checkIdentity(hostname, chain[0], algorithm);
+ private Validator getValidator(String variant) {
+ Validator v;
+ if (pkixParams == null) {
+ v = Validator.getInstance(validatorType, variant, trustedCerts);
+ } else {
+ v = Validator.getInstance(validatorType, variant, pkixParams);
+ }
+ return v;
}
- /**
- * Given the partial or complete certificate chain provided by the
- * peer, check its identity and build a certificate path to a trusted
- * root, return if it can be validated and is trusted for server SSL
- * authentication based on the authentication type.
- */
- public void checkServerTrusted(X509Certificate[] chain, String authType,
- String hostname, String algorithm) throws CertificateException {
- checkServerTrusted(chain, authType);
- checkIdentity(hostname, chain[0], algorithm);
+ private static X509Certificate[] validate(Validator v,
+ X509Certificate[] chain, AlgorithmConstraints constraints,
+ String authType) throws CertificateException {
+ Object o = JsseJce.beginFipsProvider();
+ try {
+ return v.validate(chain, null, constraints, authType);
+ } finally {
+ JsseJce.endFipsProvider(o);
+ }
}
- // Identify the peer by its certificate and hostname.
- private void checkIdentity(String hostname, X509Certificate cert,
- String algorithm) throws CertificateException {
+ /*
+ * Identify the peer by its certificate and hostname.
+ *
+ * Lifted from sun.net.www.protocol.https.HttpsClient.
+ */
+ static void checkIdentity(String hostname, X509Certificate cert,
+ String algorithm) throws CertificateException {
if (algorithm != null && algorithm.length() != 0) {
// if IPv6 strip off the "[]"
- if (hostname != null && hostname.startsWith("[") &&
- hostname.endsWith("]")) {
- hostname = hostname.substring(1, hostname.length()-1);
+ if ((hostname != null) && hostname.startsWith("[") &&
+ hostname.endsWith("]")) {
+ hostname = hostname.substring(1, hostname.length() - 1);
}
if (algorithm.equalsIgnoreCase("HTTPS")) {
HostnameChecker.getInstance(HostnameChecker.TYPE_TLS).match(
hostname, cert);
- } else if (algorithm.equalsIgnoreCase("LDAP")) {
+ } else if (algorithm.equalsIgnoreCase("LDAP") ||
+ algorithm.equalsIgnoreCase("LDAPS")) {
HostnameChecker.getInstance(HostnameChecker.TYPE_LDAP).match(
hostname, cert);
} else {
diff --git a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
index 8cc2d0e497dc47f8c2351606726f399aedca53f8..7e220bc06ebce22f0bb0167b3c585a91caedd4fd 100644
--- a/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosClientKeyExchangeImpl.java
@@ -244,7 +244,7 @@ public final class KerberosClientKeyExchangeImpl
clientVersion, rand, input, sessionKey);
} else {
// Generate bogus premaster secret
- preMaster = new KerberosPreMasterSecret(protocolVersion, rand);
+ preMaster = new KerberosPreMasterSecret(clientVersion, rand);
}
}
diff --git a/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
index 0d7571aab7525e6ad815e6890bca705af0a97f24..84c96a35b3fa2404960223bba7ef2cdb2fec9dbe 100644
--- a/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
+++ b/src/share/classes/sun/security/ssl/krb5/KerberosPreMasterSecret.java
@@ -176,13 +176,21 @@ final class KerberosPreMasterSecret {
// check if the premaster secret version is ok
// the specification says that it must be the maximum version supported
// by the client from its ClientHello message. However, many
- // implementations send the negotiated version, so accept both
+ // old implementations send the negotiated version, so accept both
+ // for SSL v3.0 and TLS v1.0.
// NOTE that we may be comparing two unsupported version numbers in
// the second case, which is why we cannot use object references
// equality in this special case
- boolean versionMismatch = (protocolVersion != currentVersion) &&
- (protocolVersion.v != clientVersion.v);
+ boolean versionMismatch = (protocolVersion.v != clientVersion.v);
+ /*
+ * we never checked the client_version in server side
+ * for TLS v1.0 and SSL v3.0. For compatibility, we
+ * maintain this behavior.
+ */
+ if (versionMismatch && (clientVersion.v <= 0x0301)) {
+ versionMismatch = (protocolVersion.v != currentVersion.v);
+ }
/*
* Bogus decrypted ClientKeyExchange? If so, conjure a
@@ -203,8 +211,14 @@ final class KerberosPreMasterSecret {
Debug.println(System.out, "Invalid secret", preMaster);
}
}
- preMaster = generatePreMaster(generator, currentVersion);
- protocolVersion = currentVersion;
+
+ /*
+ * Randomize the preMaster secret with the
+ * ClientHello.client_version, as will produce invalid master
+ * secret to prevent the attacks.
+ */
+ preMaster = generatePreMaster(generator, clientVersion);
+ protocolVersion = clientVersion;
}
}
diff --git a/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..a537c55485422f0d3b957fbe6144b1cd5929f34e
--- /dev/null
+++ b/src/share/classes/sun/security/util/DisabledAlgorithmConstraints.java
@@ -0,0 +1,486 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.security.util;
+
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
+import java.security.AlgorithmParameters;
+
+import java.security.Key;
+import java.security.Security;
+import java.security.PrivilegedAction;
+import java.security.AccessController;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.DSAKey;
+import javax.crypto.SecretKey;
+import javax.crypto.interfaces.DHKey;
+
+import java.util.Locale;
+import java.util.Set;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+
+/**
+ * Algorithm constraints for disabled algorithms property
+ *
+ * See the "jdk.certpath.disabledAlgorithms" specification in java.security
+ * for the syntax of the disabled algorithm string.
+ */
+public class DisabledAlgorithmConstraints implements AlgorithmConstraints {
+
+ // the known security property, jdk.certpath.disabledAlgorithms
+ public final static String PROPERTY_CERTPATH_DISABLED_ALGS =
+ "jdk.certpath.disabledAlgorithms";
+
+ // the known security property, jdk.tls.disabledAlgorithms
+ public final static String PROPERTY_TLS_DISABLED_ALGS =
+ "jdk.tls.disabledAlgorithms";
+
+ private static Map
+ * For example, we need to decompose "SHA1WithRSA" into "SHA1" and "RSA"
+ * so that we can check the "SHA1" and "RSA" algorithm constraints
+ * separately.
+ *
+ * Please override the method if need to support more name pattern.
+ */
+ protected Set
+
- * Object x; String s; int i;
- * x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
- * s = InvokeDynamic.<String>hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
- * InvokeDynamic.<void>cogito(); // cogito()V
- * i = InvokeDynamic.<int>#"op:+"(2, 3); // "op:+"(II)I
- *
* Each of the above calls generates a single invokedynamic instruction
* with the name-and-type descriptors indicated in the comments.
+ *
+@BootstrapMethod(value=Here.class, name="bootstrapDynamic")
+static void example() throws Throwable {
+ Object x; String s; int i;
+ x = InvokeDynamic.greet("world"); // greet(Ljava/lang/String;)Ljava/lang/Object;
+ s = (String) InvokeDynamic.hail(x); // hail(Ljava/lang/Object;)Ljava/lang/String;
+ InvokeDynamic.cogito(); // cogito()V
+ i = (int) InvokeDynamic.#"op:+"(2, 3); // "op:+"(II)I
+}
+static MethodHandle bootstrapDynamic(Class caller, String name, MethodType type) { ... }
+
- *
- *
- * registerBootstrapMethod.{class name}
- * Specifying a bootstrap method for {@code invokedynamic} instructions within a class of the given name
- * An attacker could attempt to attach a bootstrap method to a class which
- * has just been loaded, thus gaining control of its {@code invokedynamic} calls.
- *
*
*
+ * invalidateAll
* Force the relinking of invokedynamic call sites everywhere.
* This could allow an attacker to slow down the system,
@@ -73,8 +67,9 @@ import java.util.StringTokenizer;
* See {@code invalidateAll}.
* invokedynamic
+ * call site, the proxy method handle extracted at the time of binding
+ * will be used for an unlimited time, until the call site is rebound.
+ * publicLookup().in(C.class)}.
+ * Since all classes have equal access to public names,
+ * such a change would confer no new access rights.
*/
public static Lookup publicLookup() {
return Lookup.PUBLIC_LOOKUP;
@@ -90,9 +95,10 @@ public class MethodHandles {
* A lookup object is a factory for creating method handles,
* when the creation requires access checking.
* Method handles do not perform
- * access checks when they are called; this is a major difference
+ * access checks when they are called, but rather when they are created.
+ * (This is a major difference
* from reflective {@link Method}, which performs access checking
- * against every caller, on every call.
+ * against every caller, on every call.)
* Therefore, method handle access
* restrictions must be enforced when a method handle is created.
* The caller class against which those restrictions are enforced
@@ -107,7 +113,7 @@ public class MethodHandles {
* It may then use this factory to create method handles on
* all of its methods, including private ones.
* It may also delegate the lookup (e.g., to a metaobject protocol)
- * by passing the {@code Lookup} object to other code.
+ * by passing the lookup object to other code.
* If this other code creates method handles, they will be access
* checked against the original lookup class, and not with any higher
* privileges.
@@ -125,23 +131,28 @@ public class MethodHandles {
* It can also fail if a security manager is installed and refuses
* access. In any of these cases, an exception will be
* thrown from the attempted lookup.
+ *
* @param target the method handle to invoke after the argument is dropped
* @param valueTypes the type(s) of the argument to drop
@@ -1562,4 +1588,107 @@ public class MethodHandles {
MethodHandle throwException(Class> returnType, Class extends Throwable> exType) {
return MethodHandleImpl.throwException(IMPL_TOKEN, MethodType.methodType(returnType, exType));
}
+
+ /**
+ * Produce a wrapper instance of the given "SAM" type which redirects its calls to the given method handle.
+ * A SAM type is a type which declares a single abstract method.
+ * Additionally, it must have either no constructor (as an interface)
+ * or have a public or protected constructor of zero arguments (as a class).
+ *
- * MethodHandle cat = MethodHandles.lookup().
- * findVirtual(String.class, "concat", String.class, String.class);
- * System.out.println(cat.<String>invokeExact("x", "y")); // xy
+ * import static java.dyn.MethodHandles.*;
+ * import static java.dyn.MethodType.*;
+ * ...
+ * MethodHandle cat = lookup().findVirtual(String.class,
+ * "concat", methodType(String.class, String.class));
+ * System.out.println((String) cat.invokeExact("x", "y")); // xy
* MethodHandle d0 = dropArguments(cat, 0, String.class);
- * System.out.println(d0.<String>invokeExact("x", "y", "z")); // xy
+ * System.out.println((String) d0.invokeExact("x", "y", "z")); // yz
* MethodHandle d1 = dropArguments(cat, 1, String.class);
- * System.out.println(d1.<String>invokeExact("x", "y", "z")); // xz
+ * System.out.println((String) d1.invokeExact("x", "y", "z")); // xz
* MethodHandle d2 = dropArguments(cat, 2, String.class);
- * System.out.println(d2.<String>invokeExact("x", "y", "z")); // yz
- * MethodHandle d12 = dropArguments(cat, 1, String.class, String.class);
- * System.out.println(d12.<String>invokeExact("w", "x", "y", "z")); // wz
+ * System.out.println((String) d2.invokeExact("x", "y", "z")); // xy
+ * MethodHandle d12 = dropArguments(cat, 1, int.class, boolean.class);
+ * System.out.println((String) d12.invokeExact("x", 12, true, "z")); // xz
*
+ *
+ * MethodType are immutable.
+ * All instances of {@code MethodType} are immutable.
* Two instances are completely interchangeable if they compare equal.
* Equality depends on pairwise correspondence of the return and parameter types and on nothing else.
* Corresponding JVM bytecode format changes
@@ -65,18 +63,50 @@
* The first byte is the opcode 186 (hexadecimal {@code BA}).
* The next two bytes are a constant pool index (in the same format as for the other {@code invoke} instructions).
* The final two bytes are reserved for future use and required to be zero.
- * The constant pool reference is to a entry with tag {@code CONSTANT_NameAndType}
- * (decimal 12). It is thus not a method reference of any sort, but merely
- * the method name, argument types, and return type of the dynamic call site.
- * (TBD: The EG is discussing the possibility of a special constant pool entry type,
- * so that other information may be added, such as a per-instruction bootstrap
- * method and/or annotations.)
+ * The constant pool reference of an {@code invokedynamic} instruction is to a entry
+ * with tag {@code CONSTANT_InvokeDynamic} (decimal 17). See below for its format.
+ * The entry specifies the bootstrap method (a {@link java.dyn.MethodHandle MethodHandle} constant),
+ * the dynamic invocation name, and the argument types and return type of the call.
+ * constant pool entries for {@code invokedynamic} instructions
+ * If a constant pool entry has the tag {@code CONSTANT_InvokeDynamic} (decimal 17),
+ * it must contain exactly four more bytes.
+ * The first two bytes after the tag must be an index to a {@code CONSTANT_MethodHandle}
+ * entry, and the second two bytes must be an index to a {@code CONSTANT_NameAndType}.
+ * The first index specifies a bootstrap method used by the associated dynamic call sites.
+ * The second index specifies the method name, argument types, and return type of the dynamic call site.
+ * The structure of such an entry is therefore analogous to a {@code CONSTANT_Methodref},
+ * except that the {@code CONSTANT_Class} reference in a {@code CONSTANT_Methodref} entry
+ * is replaced by a bootstrap method reference.
*
* constant pool entries for {@code MethodType}s
* If a constant pool entry has the tag {@code CONSTANT_MethodType} (decimal 16),
- * it must contain exactly two more bytes, which are an index to a {@code CONSTANT_Utf8}
- * entry which represents a method type signature. The JVM will ensure that on first
- * execution of an {@code ldc} instruction for this entry, a {@link java.dyn.MethodType}
+ * it must contain exactly two more bytes, which must be an index to a {@code CONSTANT_Utf8}
+ * entry which represents a method type signature.
+ * constant pool entries for {@code MethodHandle}s
* If a constant pool entry has the tag {@code CONSTANT_MethodHandle} (decimal 15),
* it must contain exactly three more bytes. The first byte after the tag is a subtag
- * value in the range 1 through 9, and the last two are an index to a
+ * value which must be in the range 1 through 9, and the last two must be an index to a
* {@code CONSTANT_Fieldref}, {@code CONSTANT_Methodref}, or
* {@code CONSTANT_InterfaceMethodref} entry which represents a field or method
* for which a method handle is to be created.
+ * Furthermore, the subtag value and the type of the constant index value
+ * must agree according to the table below.
+ * Bootstrap Methods
+ * Before the JVM can execute a dynamic call site (an {@code invokedynamic} instruction),
+ * the call site must first be linked.
+ * Linking is accomplished by calling a bootstrap method
+ * which is given the static information content of the call site,
+ * and which must produce a {@link java.dyn.MethodHandle method handle}
+ * that gives the behavior of the call site.
+ *
+ *
+ * The method handle is then applied to the other values as if by
+ * {@linkplain java.dyn.MethodHandle#invokeGeneric the invokeGeneric method}.
+ * The returned result must be a {@link java.dyn.CallSite CallSite}, a {@link java.dyn.MethodHandle MethodHandle},
+ * or another {@link java.dyn.MethodHandleProvider MethodHandleProvider} value.
+ * The method {@linkplain java.dyn.MethodHandleProvider#asMethodHandle asMethodHandle}
+ * is then called on the returned value. The result of that second
+ * call is the {@code MethodHandle} which becomes the
+ * permanent binding for the dynamic call site.
+ * That method handle's type must be exactly equal to the type
+ * derived from the dynamic call site signature and passed to
+ * the bootstrap method.
+ *
+ *
+ * timing of linkage
+ * A dynamic call site is linked just before its first execution.
+ * The bootstrap method call implementing the linkage occurs within
+ * a thread that is attempting a first execution.
+ * OutputStream
*/
public void defaultWriteObject() throws IOException {
- if (curObj == null || curDesc == null) {
+ if ( curContext == null ) {
throw new NotActiveException("not in call to writeObject");
}
+ Object curObj = curContext.getObj();
+ ObjectStreamClass curDesc = curContext.getDesc();
bout.setBlockDataMode(false);
defaultWriteFields(curObj, curDesc);
bout.setBlockDataMode(true);
@@ -446,9 +451,11 @@ public class ObjectOutputStream
*/
public ObjectOutputStream.PutField putFields() throws IOException {
if (curPut == null) {
- if (curObj == null || curDesc == null) {
+ if (curContext == null) {
throw new NotActiveException("not in call to writeObject");
}
+ Object curObj = curContext.getObj();
+ ObjectStreamClass curDesc = curContext.getDesc();
curPut = new PutFieldImpl(curDesc);
}
return curPut;
@@ -1420,17 +1427,15 @@ public class ObjectOutputStream
* writeExternal() method.
*/
private void writeExternalData(Externalizable obj) throws IOException {
- Object oldObj = curObj;
- ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
- curObj = obj;
- curDesc = null;
curPut = null;
if (extendedDebugInfo) {
debugInfoStack.push("writeExternal data");
}
+ SerialCallbackContext oldContext = curContext;
try {
+ curContext = null;
if (protocol == PROTOCOL_VERSION_1) {
obj.writeExternal(this);
} else {
@@ -1440,13 +1445,12 @@ public class ObjectOutputStream
bout.writeByte(TC_ENDBLOCKDATA);
}
} finally {
+ curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
- curObj = oldObj;
- curDesc = oldDesc;
curPut = oldPut;
}
@@ -1461,12 +1465,9 @@ public class ObjectOutputStream
for (int i = 0; i < slots.length; i++) {
ObjectStreamClass slotDesc = slots[i].desc;
if (slotDesc.hasWriteObjectMethod()) {
- Object oldObj = curObj;
- ObjectStreamClass oldDesc = curDesc;
PutFieldImpl oldPut = curPut;
- curObj = obj;
- curDesc = slotDesc;
curPut = null;
+ SerialCallbackContext oldContext = curContext;
if (extendedDebugInfo) {
debugInfoStack.push(
@@ -1474,18 +1475,19 @@ public class ObjectOutputStream
slotDesc.getName() + "\")");
}
try {
+ curContext = new SerialCallbackContext(obj, slotDesc);
bout.setBlockDataMode(true);
slotDesc.invokeWriteObject(obj, this);
bout.setBlockDataMode(false);
bout.writeByte(TC_ENDBLOCKDATA);
} finally {
+ curContext.setUsed();
+ curContext = oldContext;
if (extendedDebugInfo) {
debugInfoStack.pop();
}
}
- curObj = oldObj;
- curDesc = oldDesc;
curPut = oldPut;
} else {
defaultWriteFields(obj, slotDesc);
diff --git a/src/share/classes/java/io/ObjectStreamClass.java b/src/share/classes/java/io/ObjectStreamClass.java
index 6b54f36f4b3754dcea51d288a781c873e5c868be..b3842f9128cf57e1f898d438bf6cf6a5111c2048 100644
--- a/src/share/classes/java/io/ObjectStreamClass.java
+++ b/src/share/classes/java/io/ObjectStreamClass.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -1830,8 +1830,10 @@ public class ObjectStreamClass implements Serializable {
private final ObjectStreamField[] fields;
/** number of primitive fields */
private final int numPrimFields;
- /** unsafe field keys */
- private final long[] keys;
+ /** unsafe field keys for reading fields - may contain dupes */
+ private final long[] readKeys;
+ /** unsafe fields keys for writing fields - no dupes */
+ private final long[] writeKeys;
/** field data offsets */
private final int[] offsets;
/** field type codes */
@@ -1849,16 +1851,22 @@ public class ObjectStreamClass implements Serializable {
FieldReflector(ObjectStreamField[] fields) {
this.fields = fields;
int nfields = fields.length;
- keys = new long[nfields];
+ readKeys = new long[nfields];
+ writeKeys = new long[nfields];
offsets = new int[nfields];
typeCodes = new char[nfields];
ArrayList
- *
- * Additional (implementation specific) options may also be supported.
- *
- *
- *
- *
- *
- * Option Name
- * Description
- *
- *
- * {@link java.net.StandardSocketOption#SO_SNDBUF SO_SNDBUF}
- * The size of the socket send buffer
- *
- *
- * {@link java.net.StandardSocketOption#SO_RCVBUF SO_RCVBUF}
- * The size of the socket receive buffer
- *
- *
- * {@link java.net.StandardSocketOption#SO_REUSEADDR SO_REUSEADDR}
- * Re-use address
- *
- *
- * {@link java.net.StandardSocketOption#SO_BROADCAST SO_BROADCAST}
- * Allow transmission of broadcast datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_TOS IP_TOS}
- * The Type of Service (ToS) octet in the Internet Protocol (IP) header
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_IF IP_MULTICAST_IF}
- * The network interface for Internet Protocol (IP) multicast datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_TTL
- * IP_MULTICAST_TTL}
- * The time-to-live for Internet Protocol (IP) multicast
- * datagrams
- *
- *
- * {@link java.net.StandardSocketOption#IP_MULTICAST_LOOP
- * IP_MULTICAST_LOOP}
- * Loopback for Internet Protocol (IP) multicast datagrams
- *
- * final AsynchronousDatagramChannel dc = AsynchronousDatagramChannel.open()
- * .bind(new InetSocketAddress(4000));
- *
- * // print the source address of all packets that we receive
- * dc.receive(buffer, buffer, new CompletionHandler<SocketAddress,ByteBuffer>() {
- * public void completed(SocketAddress sa, ByteBuffer buffer) {
- * System.out.println(sa);
- * buffer.clear();
- * dc.receive(buffer, buffer, this);
- * }
- * public void failed(Throwable exc, ByteBuffer buffer) {
- * ...
- * }
- * });
- *
- *
- * @since 1.7
- */
-
-public abstract class AsynchronousDatagramChannel
- implements AsynchronousByteChannel, MulticastChannel
-{
- private final AsynchronousChannelProvider provider;
-
- /**
- * Initializes a new instance of this class.
- */
- protected AsynchronousDatagramChannel(AsynchronousChannelProvider provider) {
- this.provider = provider;
- }
-
- /**
- * Returns the provider that created this channel.
- */
- public final AsynchronousChannelProvider provider() {
- return provider;
- }
-
- /**
- * Opens an asynchronous datagram channel.
- *
- *
- *
- * @return A new asynchronous datagram channel
- *
- * @throws IOException
- * If an I/O error occurs
- */
- public static AsynchronousDatagramChannel open()
- throws IOException
- {
- return open(null, null);
- }
-
- // -- Socket-specific operations --
-
- /**
- * @throws AlreadyBoundException {@inheritDoc}
- * @throws UnsupportedAddressTypeException {@inheritDoc}
- * @throws ClosedChannelException {@inheritDoc}
- * @throws IOException {@inheritDoc}
- * @throws SecurityException
- * If a security manager has been installed and its {@link
- * SecurityManager#checkListen checkListen} method denies the
- * operation
- */
- @Override
- public abstract AsynchronousDatagramChannel bind(SocketAddress local)
- throws IOException;
-
- /**
- * @throws IllegalArgumentException {@inheritDoc}
- * @throws ClosedChannelException {@inheritDoc}
- * @throws IOException {@inheritDoc}
- */
- @Override
- public abstract
- * open((ProtocolFamily)null, (AsynchronousChannelGroup)null);
- *
An asynchronous channel to a stream-oriented connecting socket
*
- * {@link java.nio.channels.AsynchronousServerSocketChannel}
* An asynchronous channel to a stream-oriented listening socket
* {@link java.nio.channels.AsynchronousDatagramChannel}
- * An asynchronous channel to a datagram-oriented socket
* {@link java.nio.channels.CompletionHandler}
* A handler for consuming the result of an asynchronous operation {@link java.nio.channels.AsynchronousChannelGroup}
diff --git a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
index 4ed5a707768fd818f6da8511eca79045e6c1cdef..9df31d4645e92306856be6c0c3a6a1d8459684b3 100644
--- a/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
+++ b/src/share/classes/java/nio/channels/spi/AsynchronousChannelProvider.java
@@ -26,7 +26,6 @@
package java.nio.channels.spi;
import java.nio.channels.*;
-import java.net.ProtocolFamily;
import java.io.IOException;
import java.util.Iterator;
import java.util.ServiceLoader;
@@ -239,26 +238,4 @@ public abstract class AsynchronousChannelProvider {
*/
public abstract AsynchronousSocketChannel openAsynchronousSocketChannel
(AsynchronousChannelGroup group) throws IOException;
-
- /**
- * Opens an asynchronous datagram channel.
- *
- * @param family
- * The protocol family, or {@code null} for the default protocol
- * family
- * @param group
- * The group to which the channel is bound, or {@code null} to
- * bind to the default group
- *
- * @return The new channel
- *
- * @throws IllegalChannelGroupException
- * If the provider that created the group differs from this provider
- * @throws ShutdownChannelGroupException
- * The group is shutdown
- * @throws IOException
- * If an I/O error occurs
- */
- public abstract AsynchronousDatagramChannel openAsynchronousDatagramChannel
- (ProtocolFamily family, AsynchronousChannelGroup group) throws IOException;
}
diff --git a/src/share/classes/java/security/AlgorithmConstraints.java b/src/share/classes/java/security/AlgorithmConstraints.java
new file mode 100644
index 0000000000000000000000000000000000000000..7341603dc7cf65d3941cee8dce0e38194ed1a560
--- /dev/null
+++ b/src/share/classes/java/security/AlgorithmConstraints.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.security;
+
+import java.util.Set;
+
+/**
+ * This interface specifies constraints for cryptographic algorithms,
+ * keys (key sizes), and other algorithm parameters.
+ * sun.com, would have
- * domains such as com.sun.MyDomain. This is essentially
+ * example.com would have
+ * domains such as com.example.MyDomain. This is essentially
* the same convention as for Java-language package names.1081892073854801359L.
diff --git a/src/share/classes/javax/management/build.xml b/src/share/classes/javax/management/build.xml
index 24357d694af18828523afdff2446903253aa7648..e1d263520f03c0d83bd5ea5eb419cc2981bb5ac6 100644
--- a/src/share/classes/javax/management/build.xml
+++ b/src/share/classes/javax/management/build.xml
@@ -35,18 +35,18 @@
. Please also read the important comment on basedir definition below.
-->
-SSLSession interface to support additional
+ * session attributes.
+ *
+ * @since 1.7
+ */
+public abstract class ExtendedSSLSession implements SSLSession {
+ /**
+ * Obtains an array of supported signature algorithms that the local side
+ * is willing to use.
+ * SSLParameters.
+ *
+ * @return An array of supported signature algorithms, in descending
+ * order of preference. The return value is an empty array if
+ * no signature algorithm is supported.
+ *
+ * @see SSLParameters#getAlgorithmConstraints
+ */
+ public abstract String[] getLocalSupportedSignatureAlgorithms();
+
+ /**
+ * Obtains an array of supported signature algorithms that the peer is
+ * able to use.
+ * HostnameVerifier.
- */
- static {
- try {
- defaultHostnameVerifier =
- new sun.net.www.protocol.https.DefaultHostnameVerifier();
- } catch (NoClassDefFoundError e) {
- defaultHostnameVerifier = new DefaultHostnameVerifier();
- }
- }
+ private static HostnameVerifier defaultHostnameVerifier =
+ new DefaultHostnameVerifier();
/*
* The initial default HostnameVerifier. Should be
diff --git a/src/share/classes/javax/net/ssl/SSLEngine.java b/src/share/classes/javax/net/ssl/SSLEngine.java
index df3830858a6d96654dfaab89b789ab5e799d49b5..2eea55121cb6ce401edaacb0fd79e6ab4d135627 100644
--- a/src/share/classes/javax/net/ssl/SSLEngine.java
+++ b/src/share/classes/javax/net/ssl/SSLEngine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -967,6 +967,47 @@ public abstract class SSLEngine {
public abstract SSLSession getSession();
+ /**
+ * Returns the {@code SSLSession} being constructed during a SSL/TLS
+ * handshake.
+ * getSSLParameters()
* methods in
* {@link SSLSocket#getSSLParameters SSLSocket} and
+ * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
* {@link SSLEngine#getSSLParameters SSLEngine} or the
* {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
* {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
* methods in SSLContext.
- *
- * null,
+ * null,
* wantClientAuth and needClientAuth are set to false.
*/
public SSLParameters() {
@@ -69,6 +76,7 @@ public class SSLParameters {
/**
* Constructs SSLParameters from the specified array of ciphersuites.
+ * setCipherSuites(cipherSuites);.
@@ -82,6 +90,7 @@ public class SSLParameters {
/**
* Constructs SSLParameters from the specified array of ciphersuites
* and protocols.
+ * setCipherSuites(cipherSuites); setProtocols(protocols);.
@@ -178,4 +187,71 @@ public class SSLParameters {
this.needClientAuth = needClientAuth;
}
+ /**
+ * Returns the cryptographic algorithm constraints.
+ *
+ * @return the cryptographic algorithm constraints, or null if the
+ * constraints have not been set
+ *
+ * @see #setAlgorithmConstraints(AlgorithmConstraints)
+ *
+ * @since 1.7
+ */
+ public AlgorithmConstraints getAlgorithmConstraints() {
+ return algorithmConstraints;
+ }
+
+ /**
+ * Sets the cryptographic algorithm constraints, which will be used
+ * in addition to any configured by the runtime environment.
+ * constraints parameter is non-null, every
+ * cryptographic algorithm, key and algorithm parameters used in the
+ * SSL/TLS handshake must be permitted by the constraints.
+ *
+ * @param constraints the algorithm constraints (or null)
+ *
+ * @since 1.7
+ */
+ public void setAlgorithmConstraints(AlgorithmConstraints constraints) {
+ // the constraints object is immutable
+ this.algorithmConstraints = constraints;
+ }
+
+ /**
+ * Gets the endpoint identification algorithm.
+ *
+ * @return the endpoint identification algorithm, or null if none
+ * has been set.
+ *
+ * @see X509ExtendedTrustManager
+ * @see #setEndpointIdentificationAlgorithm(String)
+ *
+ * @since 1.7
+ */
+ public String getEndpointIdentificationAlgorithm() {
+ return identificationAlgorithm;
+ }
+
+ /**
+ * Sets the endpoint identification algorithm.
+ * algorithm parameter is non-null or non-empty, the
+ * endpoint identification/verification procedures must be handled during
+ * SSL/TLS handshaking. This is to prevent man-in-the-middle attacks.
+ *
+ * @param algorithm The standard string name of the endpoint
+ * identification algorithm (or null). See Appendix A in the
+ * Java Cryptography Architecture API Specification & Reference
+ * for information about standard algorithm names.
+ *
+ * @see X509ExtendedTrustManager
+ *
+ * @since 1.7
+ */
+ public void setEndpointIdentificationAlgorithm(String algorithm) {
+ this.identificationAlgorithm = algorithm;
+ }
+
}
diff --git a/src/share/classes/javax/net/ssl/SSLServerSocket.java b/src/share/classes/javax/net/ssl/SSLServerSocket.java
index 6bcb8a678e8f14cb7acd0d41b6d16dca7fbbdf60..d5bbaaf5da5ab79d9dd0f6a60ecb87550b550570 100644
--- a/src/share/classes/javax/net/ssl/SSLServerSocket.java
+++ b/src/share/classes/javax/net/ssl/SSLServerSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -56,8 +56,8 @@ import java.net.*;
* @since 1.4
* @author David Brownell
*/
-public abstract class SSLServerSocket extends ServerSocket
-{
+public abstract class SSLServerSocket extends ServerSocket {
+
/**
* Used only by subclasses.
*
+ *
+ *
+ * @param params the parameters
+ * @throws IllegalArgumentException if the setEnabledCipherSuites() or
+ * the setEnabledProtocols() call fails
+ *
+ * @see #getSSLParameters()
+ *
+ * @since 1.7
+ */
+ public void setSSLParameters(SSLParameters params) {
+ String[] s;
+ s = params.getCipherSuites();
+ if (s != null) {
+ setEnabledCipherSuites(s);
+ }
+
+ s = params.getProtocols();
+ if (s != null) {
+ setEnabledProtocols(s);
+ }
+
+ if (params.getNeedClientAuth()) {
+ setNeedClientAuth(true);
+ } else if (params.getWantClientAuth()) {
+ setWantClientAuth(true);
+ } else {
+ setWantClientAuth(false);
+ }
+ }
+
}
diff --git a/src/share/classes/javax/net/ssl/SSLSocket.java b/src/share/classes/javax/net/ssl/SSLSocket.java
index 29b69f1ccbf000821871fce2810de7da70725cf5..b61f94a5a75801dc67fb53bbb3dcec193f4a594e 100644
--- a/src/share/classes/javax/net/ssl/SSLSocket.java
+++ b/src/share/classes/javax/net/ssl/SSLSocket.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -370,6 +370,51 @@ public abstract class SSLSocket extends Socket
public abstract SSLSession getSession();
+ /**
+ * Returns the {@code SSLSession} being constructed during a SSL/TLS
+ * handshake.
+ * params.getCipherSuites() is non-null,
+ * setEnabledCipherSuites() is called with that value
+ * params.getProtocols() is non-null,
+ * setEnabledProtocols() is called with that value
+ * params.getNeedClientAuth() or
+ * params.getWantClientAuth() return true,
+ * setNeedClientAuth(true) and
+ * setWantClientAuth(true) are called, respectively;
+ * otherwise setWantClientAuth(false) is called.
+ * X509TrustManager interface to support
+ * SSL/TLS connection sensitive trust management.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the endpoint identification
+ * algorithm of the SSLParameters is non-empty, to prevent
+ * man-in-the-middle attacks, the address that the socket
+ * connected to should be checked against the peer's identity presented
+ * in the end-entity X509 certificate, as specified in the endpoint
+ * identification algorithm.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+ * SSLParameters is non-null, for every certificate in the
+ * certification path, fields such as subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to the
+ * algorithm constraints in place on this socket.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param socket the socket used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkClientTrusted(X509Certificate[] chain,
+ String authType, Socket socket) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the endpoint identification
+ * algorithm of the SSLParameters is non-empty, to prevent
+ * man-in-the-middle attacks, the address that the socket
+ * connected to should be checked against the peer's identity presented
+ * in the end-entity X509 certificate, as specified in the endpoint
+ * identification algorithm.
+ * socket parameter is an instance of
+ * {@link javax.net.SSLSocket}, and the algorithm constraints of the
+ * SSLParameters is non-null, for every certificate in the
+ * certification path, fields such as subject public key, the signature
+ * algorithm, key usage, extended key usage, etc. need to conform to the
+ * algorithm constraints in place on this socket.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param socket the socket used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkServerTrusted(X509Certificate[] chain,
+ String authType, Socket socket) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * engine parameter is available, and the endpoint
+ * identification algorithm of the SSLParameters is
+ * non-empty, to prevent man-in-the-middle attacks, the address that
+ * the engine connected to should be checked against
+ * the peer's identity presented in the end-entity X509 certificate,
+ * as specified in the endpoint identification algorithm.
+ * engine parameter is available, and the algorithm
+ * constraints of the SSLParameters is non-null, for every
+ * certificate in the certification path, fields such as subject public
+ * key, the signature algorithm, key usage, extended key usage, etc.
+ * need to conform to the algorithm constraints in place on this engine.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param engine the engine used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkClientTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) throws CertificateException;
+
+ /**
+ * Given the partial or complete certificate chain provided by the
+ * peer, build and validate the certificate path based on the
+ * authentication type and ssl parameters.
+ * engine parameter is available, and the endpoint
+ * identification algorithm of the SSLParameters is
+ * non-empty, to prevent man-in-the-middle attacks, the address that
+ * the engine connected to should be checked against
+ * the peer's identity presented in the end-entity X509 certificate,
+ * as specified in the endpoint identification algorithm.
+ * engine parameter is available, and the algorithm
+ * constraints of the SSLParameters is non-null, for every
+ * certificate in the certification path, fields such as subject public
+ * key, the signature algorithm, key usage, extended key usage, etc.
+ * need to conform to the algorithm constraints in place on this engine.
+ *
+ * @param chain the peer certificate chain
+ * @param authType the key exchange algorithm used
+ * @param engine the engine used for this connection. This parameter
+ * can be null, which indicates that implementations need not check
+ * the ssl parameters
+ * @throws IllegalArgumentException if null or zero-length array is passed
+ * in for the chain parameter or if null or zero-length
+ * string is passed in for the authType parameter
+ * @throws CertificateException if the certificate chain is not trusted
+ * by this TrustManager
+ *
+ * @see SSLParameters#getEndpointIdentificationProtocol
+ * @see SSLParameters#setEndpointIdentificationProtocol(String)
+ * @see SSLParameters#getAlgorithmConstraints
+ * @see SSLParameters#setAlgorithmConstraints(AlgorithmConstraints)
+ */
+ public abstract void checkServerTrusted(X509Certificate[] chain,
+ String authType, SSLEngine engine) throws CertificateException;
+
+}
diff --git a/src/share/classes/sun/dyn/BoundMethodHandle.java b/src/share/classes/sun/dyn/BoundMethodHandle.java
index 5152187229ec9e40bcd5b81447c71c9180e9049e..f2ae32efbc95b7f845bb90e2acc55314cf6ff118 100644
--- a/src/share/classes/sun/dyn/BoundMethodHandle.java
+++ b/src/share/classes/sun/dyn/BoundMethodHandle.java
@@ -48,8 +48,6 @@ public class BoundMethodHandle extends MethodHandle {
private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory(IMPL_TOKEN);
// Constructors in this class *must* be package scoped or private.
- // Exception: JavaMethodHandle constructors are protected.
- // (The link between JMH and BMH is temporary.)
/** Bind a direct MH to its receiver (or first ref. argument).
* The JVM will pre-dispatch the MH if it is not already static.
@@ -122,55 +120,6 @@ public class BoundMethodHandle extends MethodHandle {
assert(this instanceof JavaMethodHandle);
}
- /** Initialize the current object as a Java method handle.
- */
- protected BoundMethodHandle(String entryPointName, MethodType type, boolean matchArity) {
- super(Access.TOKEN, null);
- MethodHandle entryPoint
- = findJavaMethodHandleEntryPoint(this.getClass(),
- entryPointName, type, matchArity);
- MethodHandleImpl.initType(this, entryPoint.type().dropParameterTypes(0, 1));
- this.argument = this; // kludge; get rid of
- this.vmargslot = this.type().parameterSlotDepth(0);
- initTarget(entryPoint, 0);
- assert(this instanceof JavaMethodHandle);
- }
-
- private static
- MethodHandle findJavaMethodHandleEntryPoint(Class> caller,
- String name,
- MethodType type,
- boolean matchArity) {
- if (matchArity) type.getClass(); // elicit NPE
- ListDasher class takes a series of linear commands
* (moveTo, lineTo, close and
@@ -36,18 +38,16 @@ package sun.java2d.pisces;
* semantics are unclear.
*
*/
-public class Dasher implements LineSink {
- private final LineSink output;
+public class Dasher implements sun.awt.geom.PathConsumer2D {
+
+ private final PathConsumer2D out;
private final float[] dash;
private final float startPhase;
private final boolean startDashOn;
private final int startIdx;
- private final float m00, m10, m01, m11;
- private final float det;
-
- private boolean firstDashOn;
private boolean starting;
+ private boolean needsMoveTo;
private int idx;
private boolean dashOn;
@@ -55,28 +55,23 @@ public class Dasher implements LineSink {
private float sx, sy;
private float x0, y0;
- private float sx1, sy1;
+ // temporary storage for the current curve
+ private float[] curCurvepts;
/**
* Constructs a Dasher.
*
- * @param output an output LineSink.
- * @param dash an array of ints containing the dash pattern
- * @param phase an int containing the dash phase
- * @param transform a Transform4 object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to compute dash lengths
- * properly.
+ * @param out an output PathConsumer2D.
+ * @param dash an array of floats containing the dash pattern
+ * @param phase a float containing the dash phase
*/
- public Dasher(LineSink output,
- float[] dash, float phase,
- float a00, float a01, float a10, float a11) {
+ public Dasher(PathConsumer2D out, float[] dash, float phase) {
if (phase < 0) {
throw new IllegalArgumentException("phase < 0 !");
}
- this.output = output;
+ this.out = out;
// Normalize so 0 <= phase < dash[0]
int idx = 0;
@@ -92,16 +87,19 @@ public class Dasher implements LineSink {
this.startPhase = this.phase = phase;
this.startDashOn = dashOn;
this.startIdx = idx;
+ this.starting = true;
- m00 = a00;
- m01 = a01;
- m10 = a10;
- m11 = a11;
- det = m00 * m11 - m01 * m10;
+ // we need curCurvepts to be able to contain 2 curves because when
+ // dashing curves, we need to subdivide it
+ curCurvepts = new float[8 * 2];
}
public void moveTo(float x0, float y0) {
- output.moveTo(x0, y0);
+ if (firstSegidx > 0) {
+ out.moveTo(sx, sy);
+ emitFirstSegments();
+ }
+ needsMoveTo = true;
this.idx = startIdx;
this.dashOn = this.startDashOn;
this.phase = this.startPhase;
@@ -110,104 +108,398 @@ public class Dasher implements LineSink {
this.starting = true;
}
- public void lineJoin() {
- output.lineJoin();
+ private void emitSeg(float[] buf, int off, int type) {
+ switch (type) {
+ case 8:
+ out.curveTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3],
+ buf[off+4], buf[off+5]);
+ break;
+ case 6:
+ out.quadTo(buf[off+0], buf[off+1],
+ buf[off+2], buf[off+3]);
+ break;
+ case 4:
+ out.lineTo(buf[off], buf[off+1]);
+ }
+ }
+
+ private void emitFirstSegments() {
+ for (int i = 0; i < firstSegidx; ) {
+ emitSeg(firstSegmentsBuffer, i+1, (int)firstSegmentsBuffer[i]);
+ i += (((int)firstSegmentsBuffer[i]) - 1);
+ }
+ firstSegidx = 0;
}
- private void goTo(float x1, float y1) {
+ // We don't emit the first dash right away. If we did, caps would be
+ // drawn on it, but we need joins to be drawn if there's a closePath()
+ // So, we store the path elements that make up the first dash in the
+ // buffer below.
+ private float[] firstSegmentsBuffer = new float[7];
+ private int firstSegidx = 0;
+ // precondition: pts must be in relative coordinates (relative to x0,y0)
+ // fullCurve is true iff the curve in pts has not been split.
+ private void goTo(float[] pts, int off, final int type) {
+ float x = pts[off + type - 4];
+ float y = pts[off + type - 3];
if (dashOn) {
if (starting) {
- this.sx1 = x1;
- this.sy1 = y1;
- firstDashOn = true;
- starting = false;
+ firstSegmentsBuffer = Helpers.widenArray(firstSegmentsBuffer,
+ firstSegidx, type - 2);
+ firstSegmentsBuffer[firstSegidx++] = type;
+ System.arraycopy(pts, off, firstSegmentsBuffer, firstSegidx, type - 2);
+ firstSegidx += type - 2;
+ } else {
+ if (needsMoveTo) {
+ out.moveTo(x0, y0);
+ needsMoveTo = false;
+ }
+ emitSeg(pts, off, type);
}
- output.lineTo(x1, y1);
} else {
- if (starting) {
- firstDashOn = false;
- starting = false;
- }
- output.moveTo(x1, y1);
+ starting = false;
+ needsMoveTo = true;
}
- this.x0 = x1;
- this.y0 = y1;
+ this.x0 = x;
+ this.y0 = y;
}
public void lineTo(float x1, float y1) {
- // The widened line is squished to a 0 width one, so no drawing is done
- if (det == 0) {
- goTo(x1, y1);
- return;
- }
float dx = x1 - x0;
float dy = y1 - y0;
+ float len = (float) Math.hypot(dx, dy);
- // Compute segment length in the untransformed
- // coordinate system
-
- float la = (dy*m00 - dx*m10)/det;
- float lb = (dy*m01 - dx*m11)/det;
- float origLen = (float) Math.hypot(la, lb);
-
- if (origLen == 0) {
- // Let the output LineSink deal with cases where dx, dy are 0.
- goTo(x1, y1);
+ if (len == 0) {
return;
}
// The scaling factors needed to get the dx and dy of the
// transformed dash segments.
- float cx = dx / origLen;
- float cy = dy / origLen;
+ float cx = dx / len;
+ float cy = dy / len;
while (true) {
float leftInThisDashSegment = dash[idx] - phase;
- if (origLen < leftInThisDashSegment) {
- goTo(x1, y1);
+ if (len <= leftInThisDashSegment) {
+ curCurvepts[0] = x1;
+ curCurvepts[1] = y1;
+ goTo(curCurvepts, 0, 4);
// Advance phase within current dash segment
- phase += origLen;
- return;
- } else if (origLen == leftInThisDashSegment) {
- goTo(x1, y1);
- phase = 0f;
- idx = (idx + 1) % dash.length;
- dashOn = !dashOn;
+ phase += len;
+ if (len == leftInThisDashSegment) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
return;
}
- float dashx, dashy;
float dashdx = dash[idx] * cx;
float dashdy = dash[idx] * cy;
if (phase == 0) {
- dashx = x0 + dashdx;
- dashy = y0 + dashdy;
+ curCurvepts[0] = x0 + dashdx;
+ curCurvepts[1] = y0 + dashdy;
} else {
- float p = (leftInThisDashSegment) / dash[idx];
- dashx = x0 + p * dashdx;
- dashy = y0 + p * dashdy;
+ float p = leftInThisDashSegment / dash[idx];
+ curCurvepts[0] = x0 + p * dashdx;
+ curCurvepts[1] = y0 + p * dashdy;
}
- goTo(dashx, dashy);
+ goTo(curCurvepts, 0, 4);
+
+ len -= leftInThisDashSegment;
+ // Advance to next dash segment
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ phase = 0;
+ }
+ }
+
+ private LengthIterator li = null;
+
+ // preconditions: curCurvepts must be an array of length at least 2 * type,
+ // that contains the curve we want to dash in the first type elements
+ private void somethingTo(int type) {
+ if (pointCurve(curCurvepts, type)) {
+ return;
+ }
+ if (li == null) {
+ li = new LengthIterator(4, 0.0001f);
+ }
+ li.initializeIterationOnCurve(curCurvepts, type);
- origLen -= (dash[idx] - phase);
+ int curCurveoff = 0; // initially the current curve is at curCurvepts[0...type]
+ float lastSplitT = 0;
+ float t = 0;
+ float leftInThisDashSegment = dash[idx] - phase;
+ while ((t = li.next(leftInThisDashSegment)) < 1) {
+ if (t != 0) {
+ Helpers.subdivideAt((t - lastSplitT) / (1 - lastSplitT),
+ curCurvepts, curCurveoff,
+ curCurvepts, 0,
+ curCurvepts, type, type);
+ lastSplitT = t;
+ goTo(curCurvepts, 2, type);
+ curCurveoff = type;
+ }
// Advance to next dash segment
idx = (idx + 1) % dash.length;
dashOn = !dashOn;
phase = 0;
+ leftInThisDashSegment = dash[idx];
+ }
+ goTo(curCurvepts, curCurveoff+2, type);
+ phase += li.lastSegLen();
+ if (phase >= dash[idx]) {
+ phase = 0f;
+ idx = (idx + 1) % dash.length;
+ dashOn = !dashOn;
+ }
+ }
+
+ private static boolean pointCurve(float[] curve, int type) {
+ for (int i = 2; i < type; i++) {
+ if (curve[i] != curve[i-2]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ // Objects of this class are used to iterate through curves. They return
+ // t values where the left side of the curve has a specified length.
+ // It does this by subdividing the input curve until a certain error
+ // condition has been met. A recursive subdivision procedure would
+ // return as many as 1<src array at indices srcoff
+ * through (srcoff + 7) and stores the
+ * resulting two subdivided curves into the two result arrays at the
+ * corresponding indices.
+ * Either or both of the left and right
+ * arrays may be null or a reference to the same array
+ * as the src array.
+ * Note that the last point in the first subdivided curve is the
+ * same as the first point in the second subdivided curve. Thus,
+ * it is possible to pass the same array for left
+ * and right and to use offsets, such as rightoff
+ * equals (leftoff + 6), in order
+ * to avoid allocating extra storage for this common point.
+ * @param src the array holding the coordinates for the source curve
+ * @param srcoff the offset into the array of the beginning of the
+ * the 6 source coordinates
+ * @param left the array for storing the coordinates for the first
+ * half of the subdivided curve
+ * @param leftoff the offset into the array of the beginning of the
+ * the 6 left coordinates
+ * @param right the array for storing the coordinates for the second
+ * half of the subdivided curve
+ * @param rightoff the offset into the array of the beginning of the
+ * the 6 right coordinates
+ * @since 1.7
+ */
+ static void subdivideCubic(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = (x1 + ctrlx1) / 2.0f;
+ y1 = (y1 + ctrly1) / 2.0f;
+ x2 = (x2 + ctrlx2) / 2.0f;
+ y2 = (y2 + ctrly2) / 2.0f;
+ float centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ float centery = (ctrly1 + ctrly2) / 2.0f;
+ ctrlx1 = (x1 + centerx) / 2.0f;
+ ctrly1 = (y1 + centery) / 2.0f;
+ ctrlx2 = (x2 + centerx) / 2.0f;
+ ctrly2 = (y2 + centery) / 2.0f;
+ centerx = (ctrlx1 + ctrlx2) / 2.0f;
+ centery = (ctrly1 + ctrly2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+
+ static void subdivideCubicAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx1 = src[srcoff + 2];
+ float ctrly1 = src[srcoff + 3];
+ float ctrlx2 = src[srcoff + 4];
+ float ctrly2 = src[srcoff + 5];
+ float x2 = src[srcoff + 6];
+ float y2 = src[srcoff + 7];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 6] = x2;
+ right[rightoff + 7] = y2;
+ }
+ x1 = x1 + t * (ctrlx1 - x1);
+ y1 = y1 + t * (ctrly1 - y1);
+ x2 = ctrlx2 + t * (x2 - ctrlx2);
+ y2 = ctrly2 + t * (y2 - ctrly2);
+ float centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ float centery = ctrly1 + t * (ctrly2 - ctrly1);
+ ctrlx1 = x1 + t * (centerx - x1);
+ ctrly1 = y1 + t * (centery - y1);
+ ctrlx2 = centerx + t * (x2 - centerx);
+ ctrly2 = centery + t * (y2 - centery);
+ centerx = ctrlx1 + t * (ctrlx2 - ctrlx1);
+ centery = ctrly1 + t * (ctrly2 - ctrly1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx1;
+ left[leftoff + 5] = ctrly1;
+ left[leftoff + 6] = centerx;
+ left[leftoff + 7] = centery;
+ }
+ if (right != null) {
+ right[rightoff + 0] = centerx;
+ right[rightoff + 1] = centery;
+ right[rightoff + 2] = ctrlx2;
+ right[rightoff + 3] = ctrly2;
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ }
+
+ static void subdivideQuad(float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = (x1 + ctrlx) / 2.0f;
+ y1 = (y1 + ctrly) / 2.0f;
+ x2 = (x2 + ctrlx) / 2.0f;
+ y2 = (y2 + ctrly) / 2.0f;
+ ctrlx = (x1 + x2) / 2.0f;
+ ctrly = (y1 + y2) / 2.0f;
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideQuadAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff)
+ {
+ float x1 = src[srcoff + 0];
+ float y1 = src[srcoff + 1];
+ float ctrlx = src[srcoff + 2];
+ float ctrly = src[srcoff + 3];
+ float x2 = src[srcoff + 4];
+ float y2 = src[srcoff + 5];
+ if (left != null) {
+ left[leftoff + 0] = x1;
+ left[leftoff + 1] = y1;
+ }
+ if (right != null) {
+ right[rightoff + 4] = x2;
+ right[rightoff + 5] = y2;
+ }
+ x1 = x1 + t * (ctrlx - x1);
+ y1 = y1 + t * (ctrly - y1);
+ x2 = ctrlx + t * (x2 - ctrlx);
+ y2 = ctrly + t * (y2 - ctrly);
+ ctrlx = x1 + t * (x2 - x1);
+ ctrly = y1 + t * (y2 - y1);
+ if (left != null) {
+ left[leftoff + 2] = x1;
+ left[leftoff + 3] = y1;
+ left[leftoff + 4] = ctrlx;
+ left[leftoff + 5] = ctrly;
+ }
+ if (right != null) {
+ right[rightoff + 0] = ctrlx;
+ right[rightoff + 1] = ctrly;
+ right[rightoff + 2] = x2;
+ right[rightoff + 3] = y2;
+ }
+ }
+
+ static void subdivideAt(float t, float src[], int srcoff,
+ float left[], int leftoff,
+ float right[], int rightoff, int size)
+ {
+ switch(size) {
+ case 8:
+ subdivideCubicAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ case 6:
+ subdivideQuadAt(t, src, srcoff, left, leftoff, right, rightoff);
+ break;
+ }
+ }
+}
diff --git a/src/share/classes/sun/java2d/pisces/LineSink.java b/src/share/classes/sun/java2d/pisces/LineSink.java
deleted file mode 100644
index 81300a25fa067cac00c2ba57d66049e62bdd3c0c..0000000000000000000000000000000000000000
--- a/src/share/classes/sun/java2d/pisces/LineSink.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package sun.java2d.pisces;
-
-/**
- * The LineSink interface accepts a series of line
- * drawing commands: moveTo, lineTo,
- * close (equivalent to a lineTo command
- * with an argument equal to the argument of the last
- * moveTo command), and end.
- *
- * Flattener may be used to connect a general path
- * source to a LineSink.
- *
- * Renderer class implements the
- * LineSink interface.
- *
- */
-public interface LineSink {
-
- /**
- * Moves the current drawing position to the point (x0,
- * y0).
- *
- * @param x0 the X coordinate
- * @param y0 the Y coordinate
- */
- public void moveTo(float x0, float y0);
-
- /**
- * Provides a hint that the current segment should be joined to
- * the following segment using an explicit miter or round join if
- * required.
- *
- * Flattener to mark segment divisions that
- * appear in its input, and consumed by a Stroker
- * that is responsible for emitting the miter or round join
- * segments.
- *
- * LineSink classes should simply pass this
- * hint to their output sink as needed.
- */
- public void lineJoin();
-
- /**
- * Draws a line from the current drawing position to the point
- * (x1, y1) and sets the current drawing position to
- * (x1, y1).
- *
- * @param x1 the X coordinate
- * @param y1 the Y coordinate
- */
- public void lineTo(float x1, float y1);
-
- /**
- * Closes the current path by drawing a line from the current
- * drawing position to the point specified by the moset recent
- * moveTo command.
- */
- public void close();
-
- /**
- * Ends the current path. It may be necessary to end a path in
- * order to allow end caps to be drawn.
- */
- public void end();
-
-}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesCache.java b/src/share/classes/sun/java2d/pisces/PiscesCache.java
index 0ecc420969887808e72f5635e79852331954efb5..dcd595c48f636887a405ae8b1e9da8e3103cfad5 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesCache.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesCache.java
@@ -25,6 +25,8 @@
package sun.java2d.pisces;
+import java.util.Arrays;
+
/**
* An object used to cache pre-rendered complex paths.
*
@@ -32,115 +34,153 @@ package sun.java2d.pisces;
*/
public final class PiscesCache {
- int bboxX0, bboxY0, bboxX1, bboxY1;
+ final int bboxX0, bboxY0, bboxX1, bboxY1;
+
+ // rowAARLE[i] holds the encoding of the pixel row with y = bboxY0+i.
+ // The format of each of the inner arrays is: rowAARLE[i][0,1] = (x0, n)
+ // where x0 is the first x in row i with nonzero alpha, and n is the
+ // number of RLE entries in this row. rowAARLE[i][j,j+1] for j>1 is
+ // (val,runlen)
+ final int[][] rowAARLE;
+
+ // RLE encodings are added in increasing y rows and then in increasing
+ // x inside those rows. Therefore, at any one time there is a well
+ // defined position (x,y) where a run length is about to be added (or
+ // the row terminated). x0,y0 is this (x,y)-(bboxX0,bboxY0). They
+ // are used to get indices into the current tile.
+ private int x0 = Integer.MIN_VALUE, y0 = Integer.MIN_VALUE;
+
+ // touchedTile[i][j] is the sum of all the alphas in the tile with
+ // y=i*TILE_SIZE+bboxY0 and x=j*TILE_SIZE+bboxX0.
+ private final int[][] touchedTile;
+
+ static final int TILE_SIZE_LG = 5;
+ static final int TILE_SIZE = 1 << TILE_SIZE_LG; // 32
+ private static final int INIT_ROW_SIZE = 8; // enough for 3 run lengths
+
+ PiscesCache(int minx, int miny, int maxx, int maxy) {
+ assert maxy >= miny && maxx >= minx;
+ bboxX0 = minx;
+ bboxY0 = miny;
+ bboxX1 = maxx + 1;
+ bboxY1 = maxy + 1;
+ // we could just leave the inner arrays as null and allocate them
+ // lazily (which would be beneficial for shapes with gaps), but we
+ // assume there won't be too many of those so we allocate everything
+ // up front (which is better for other cases)
+ rowAARLE = new int[bboxY1 - bboxY0 + 1][INIT_ROW_SIZE];
+ x0 = 0;
+ y0 = -1; // -1 makes the first assert in startRow succeed
+ // the ceiling of (maxy - miny + 1) / TILE_SIZE;
+ int nyTiles = (maxy - miny + TILE_SIZE) >> TILE_SIZE_LG;
+ int nxTiles = (maxx - minx + TILE_SIZE) >> TILE_SIZE_LG;
+
+ touchedTile = new int[nyTiles][nxTiles];
+ }
- byte[] rowAARLE;
- int alphaRLELength;
+ void addRLERun(int val, int runLen) {
+ if (runLen > 0) {
+ addTupleToRow(y0, val, runLen);
+ if (val != 0) {
+ // the x and y of the current row, minus bboxX0, bboxY0
+ int tx = x0 >> TILE_SIZE_LG;
+ int ty = y0 >> TILE_SIZE_LG;
+ int tx1 = (x0 + runLen - 1) >> TILE_SIZE_LG;
+ // while we forbid rows from starting before bboxx0, our users
+ // can still store rows that go beyond bboxx1 (although this
+ // shouldn't happen), so it's a good idea to check that i
+ // is not going out of bounds in touchedTile[ty]
+ if (tx1 >= touchedTile[ty].length) {
+ tx1 = touchedTile[ty].length - 1;
+ }
+ if (tx <= tx1) {
+ int nextTileXCoord = (tx + 1) << TILE_SIZE_LG;
+ if (nextTileXCoord > x0+runLen) {
+ touchedTile[ty][tx] += val * runLen;
+ } else {
+ touchedTile[ty][tx] += val * (nextTileXCoord - x0);
+ }
+ tx++;
+ }
+ // don't go all the way to tx1 - we need to handle the last
+ // tile as a special case (just like we did with the first
+ for (; tx < tx1; tx++) {
+// try {
+ touchedTile[ty][tx] += (val << TILE_SIZE_LG);
+// } catch (RuntimeException e) {
+// System.out.println("x0, y0: " + x0 + ", " + y0);
+// System.out.printf("tx, ty, tx1: %d, %d, %d %n", tx, ty, tx1);
+// System.out.printf("bboxX/Y0/1: %d, %d, %d, %d %n",
+// bboxX0, bboxY0, bboxX1, bboxY1);
+// throw e;
+// }
+ }
+ // they will be equal unless x0>>TILE_SIZE_LG == tx1
+ if (tx == tx1) {
+ int lastXCoord = Math.min(x0 + runLen, (tx + 1) << TILE_SIZE_LG);
+ int txXCoord = tx << TILE_SIZE_LG;
+ touchedTile[ty][tx] += val * (lastXCoord - txXCoord);
+ }
+ }
+ x0 += runLen;
+ }
+ }
- int[] rowOffsetsRLE;
- int[] minTouched;
- int alphaRows;
+ void startRow(int y, int x) {
+ // rows are supposed to be added by increasing y.
+ assert y - bboxY0 > y0;
+ assert y <= bboxY1; // perhaps this should be < instead of <=
- private PiscesCache() {}
+ y0 = y - bboxY0;
+ // this should be a new, uninitialized row.
+ assert rowAARLE[y0][1] == 0;
- public static PiscesCache createInstance() {
- return new PiscesCache();
- }
+ x0 = x - bboxX0;
+ assert x0 >= 0 : "Input must not be to the left of bbox bounds";
- private static final float ROWAA_RLE_FACTOR = 1.5f;
- private static final float TOUCHED_FACTOR = 1.5f;
- private static final int MIN_TOUCHED_LEN = 64;
-
- private void reallocRowAARLE(int newLength) {
- if (rowAARLE == null) {
- rowAARLE = new byte[newLength];
- } else if (rowAARLE.length < newLength) {
- int len = Math.max(newLength,
- (int)(rowAARLE.length*ROWAA_RLE_FACTOR));
- byte[] newRowAARLE = new byte[len];
- System.arraycopy(rowAARLE, 0, newRowAARLE, 0, rowAARLE.length);
- rowAARLE = newRowAARLE;
- }
+ // the way addTupleToRow is implemented it would work for this but it's
+ // not a good idea to use it because it is meant for adding
+ // RLE tuples, not the first tuple (which is special).
+ rowAARLE[y0][0] = x;
+ rowAARLE[y0][1] = 2;
}
- private void reallocRowInfo(int newHeight) {
- if (minTouched == null) {
- int len = Math.max(newHeight, MIN_TOUCHED_LEN);
- minTouched = new int[len];
- rowOffsetsRLE = new int[len];
- } else if (minTouched.length < newHeight) {
- int len = Math.max(newHeight,
- (int)(minTouched.length*TOUCHED_FACTOR));
- int[] newMinTouched = new int[len];
- int[] newRowOffsetsRLE = new int[len];
- System.arraycopy(minTouched, 0, newMinTouched, 0,
- alphaRows);
- System.arraycopy(rowOffsetsRLE, 0, newRowOffsetsRLE, 0,
- alphaRows);
- minTouched = newMinTouched;
- rowOffsetsRLE = newRowOffsetsRLE;
- }
+ int alphaSumInTile(int x, int y) {
+ x -= bboxX0;
+ y -= bboxY0;
+ return touchedTile[y>>TILE_SIZE_LG][x>>TILE_SIZE_LG];
}
- void addRLERun(byte val, int runLen) {
- reallocRowAARLE(alphaRLELength + 2);
- rowAARLE[alphaRLELength++] = val;
- rowAARLE[alphaRLELength++] = (byte)runLen;
+ int minTouched(int rowidx) {
+ return rowAARLE[rowidx][0];
}
- void startRow(int y, int x0, int x1) {
- if (alphaRows == 0) {
- bboxY0 = y;
- bboxY1 = y+1;
- bboxX0 = x0;
- bboxX1 = x1+1;
- } else {
- if (bboxX0 > x0) bboxX0 = x0;
- if (bboxX1 < x1 + 1) bboxX1 = x1 + 1;
- while (bboxY1++ < y) {
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = 0;
- // Assuming last 2 entries in rowAARLE are 0,0
- rowOffsetsRLE[alphaRows] = alphaRLELength-2;
- alphaRows++;
- }
- }
- reallocRowInfo(alphaRows+1);
- minTouched[alphaRows] = x0;
- rowOffsetsRLE[alphaRows] = alphaRLELength;
- alphaRows++;
+ int rowLength(int rowidx) {
+ return rowAARLE[rowidx][1];
}
- public synchronized void dispose() {
- rowAARLE = null;
- alphaRLELength = 0;
-
- minTouched = null;
- rowOffsetsRLE = null;
- alphaRows = 0;
-
- bboxX0 = bboxY0 = bboxX1 = bboxY1 = 0;
+ private void addTupleToRow(int row, int a, int b) {
+ int end = rowAARLE[row][1];
+ rowAARLE[row] = Helpers.widenArray(rowAARLE[row], end, 2);
+ rowAARLE[row][end++] = a;
+ rowAARLE[row][end++] = b;
+ rowAARLE[row][1] = end;
}
- public void print(java.io.PrintStream out) {
- synchronized (out) {
- out.println("bbox = ["+
- bboxX0+", "+bboxY0+" => "+
- bboxX1+", "+bboxY1+"]");
-
- out.println("alphRLELength = "+alphaRLELength);
-
- for (int y = bboxY0; y < bboxY1; y++) {
- int i = y-bboxY0;
- out.println("row["+i+"] == {"+
- "minX = "+minTouched[i]+
- ", off = "+rowOffsetsRLE[i]+"}");
- }
-
- for (int i = 0; i < alphaRLELength; i += 2) {
- out.println("rle["+i+"] = "+
- (rowAARLE[i+1]&0xff)+" of "+(rowAARLE[i]&0xff));
+ @Override
+ public String toString() {
+ String ret = "bbox = ["+
+ bboxX0+", "+bboxY0+" => "+
+ bboxX1+", "+bboxY1+"]\n";
+ for (int[] row : rowAARLE) {
+ if (row != null) {
+ ret += ("minTouchedX=" + row[0] +
+ "\tRLE Entries: " + Arrays.toString(
+ Arrays.copyOfRange(row, 2, row[1])) + "\n");
+ } else {
+ ret += "[]\n";
+ }
}
- }
+ return ret;
}
}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
index ee2b35e68096cc7140380f083b865d03e842db7d..ed6524ceb1b1447a6099449f386180071893d0ac 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesRenderingEngine.java
@@ -27,7 +27,7 @@ package sun.java2d.pisces;
import java.awt.Shape;
import java.awt.BasicStroke;
-import java.awt.geom.FlatteningPathIterator;
+import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Path2D;
import java.awt.geom.AffineTransform;
import java.awt.geom.PathIterator;
@@ -38,8 +38,6 @@ import sun.java2d.pipe.RenderingEngine;
import sun.java2d.pipe.AATileGenerator;
public class PiscesRenderingEngine extends RenderingEngine {
- public static double defaultFlat = 0.1;
-
private static enum NormMode {OFF, ON_NO_AA, ON_WITH_AA}
/**
@@ -78,20 +76,29 @@ public class PiscesRenderingEngine extends RenderingEngine {
miterlimit,
dashes,
dashphase,
- new LineSink() {
+ new PathConsumer2D() {
public void moveTo(float x0, float y0) {
p2d.moveTo(x0, y0);
}
- public void lineJoin() {}
public void lineTo(float x1, float y1) {
p2d.lineTo(x1, y1);
}
- public void close() {
+ public void closePath() {
p2d.closePath();
}
- public void end() {}
+ public void pathDone() {}
+ public void curveTo(float x1, float y1,
+ float x2, float y2,
+ float x3, float y3) {
+ p2d.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ public void quadTo(float x1, float y1, float x2, float y2) {
+ p2d.quadTo(x1, y1, x2, y2);
+ }
+ public long getNativeConsumer() {
+ throw new InternalError("Not using a native peer");
+ }
});
-
return p2d;
}
@@ -133,22 +140,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
NormMode norm = (normalize) ?
((antialias) ? NormMode.ON_WITH_AA : NormMode.ON_NO_AA)
: NormMode.OFF;
- strokeTo(src, at, bs, thin, norm, antialias,
- new LineSink() {
- public void moveTo(float x0, float y0) {
- consumer.moveTo(x0, y0);
- }
- public void lineJoin() {}
- public void lineTo(float x1, float y1) {
- consumer.lineTo(x1, y1);
- }
- public void close() {
- consumer.closePath();
- }
- public void end() {
- consumer.pathDone();
- }
- });
+ strokeTo(src, at, bs, thin, norm, antialias, consumer);
}
void strokeTo(Shape src,
@@ -157,7 +149,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
boolean thin,
NormMode normalize,
boolean antialias,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
float lw;
if (thin) {
@@ -178,7 +170,7 @@ public class PiscesRenderingEngine extends RenderingEngine {
bs.getMiterLimit(),
bs.getDashArray(),
bs.getDashPhase(),
- lsink);
+ pc2d);
}
private float userSpaceLineWidth(AffineTransform at, float lw) {
@@ -256,28 +248,113 @@ public class PiscesRenderingEngine extends RenderingEngine {
float miterlimit,
float dashes[],
float dashphase,
- LineSink lsink)
+ PathConsumer2D pc2d)
{
- float a00 = 1f, a01 = 0f, a10 = 0f, a11 = 1f;
+ // We use inat and outat so that in Stroker and Dasher we can work only
+ // with the pre-transformation coordinates. This will repeat a lot of
+ // computations done in the path iterator, but the alternative is to
+ // work with transformed paths and compute untransformed coordinates
+ // as needed. This would be faster but I do not think the complexity
+ // of working with both untransformed and transformed coordinates in
+ // the same code is worth it.
+ // However, if a path's width is constant after a transformation,
+ // we can skip all this untransforming.
+
+ // If normalization is off we save some transformations by not
+ // transforming the input to pisces. Instead, we apply the
+ // transformation after the path processing has been done.
+ // We can't do this if normalization is on, because it isn't a good
+ // idea to normalize before the transformation is applied.
+ AffineTransform inat = null;
+ AffineTransform outat = null;
+
+ PathIterator pi = null;
+
if (at != null && !at.isIdentity()) {
- a00 = (float)at.getScaleX();
- a01 = (float)at.getShearX();
- a10 = (float)at.getShearY();
- a11 = (float)at.getScaleY();
+ final double a = at.getScaleX();
+ final double b = at.getShearX();
+ final double c = at.getShearY();
+ final double d = at.getScaleY();
+ final double det = a * d - c * b;
+ if (Math.abs(det) <= 2 * Float.MIN_VALUE) {
+ // this rendering engine takes one dimensional curves and turns
+ // them into 2D shapes by giving them width.
+ // However, if everything is to be passed through a singular
+ // transformation, these 2D shapes will be squashed down to 1D
+ // again so, nothing can be drawn.
+
+ // Every path needs an initial moveTo and a pathDone. If these
+ // aren't there this causes a SIGSEV in libawt.so (at the time
+ // of writing of this comment (September 16, 2010)). Actually,
+ // I'm not sure if the moveTo is necessary to avoid the SIGSEV
+ // but the pathDone is definitely needed.
+ pc2d.moveTo(0, 0);
+ pc2d.pathDone();
+ return;
+ }
+
+ // If the transform is a constant multiple of an orthogonal transformation
+ // then every length is just multiplied by a constant, so we just
+ // need to transform input paths to stroker and tell stroker
+ // the scaled width. This condition is satisfied if
+ // a*b == -c*d && a*a+c*c == b*b+d*d. In the actual check below, we
+ // leave a bit of room for error.
+ if (nearZero(a*b + c*d, 2) && nearZero(a*a+c*c - (b*b+d*d), 2)) {
+ double scale = Math.sqrt(a*a + c*c);
+ if (dashes != null) {
+ dashes = java.util.Arrays.copyOf(dashes, dashes.length);
+ for (int i = 0; i < dashes.length; i++) {
+ dashes[i] = (float)(scale * dashes[i]);
+ }
+ dashphase = (float)(scale * dashphase);
+ }
+ width = (float)(scale * width);
+ pi = src.getPathIterator(at);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
+ // leave inat and outat null.
+ } else {
+ // We only need the inverse if normalization is on. Otherwise
+ // we just don't transform the input paths, do all the stroking
+ // and then transform out output (instead of making PathIterator
+ // apply the transformation, us applying the inverse, and then
+ // us applying the transform again to our output).
+ outat = at;
+ if (normalize != NormMode.OFF) {
+ try {
+ inat = outat.createInverse();
+ } catch (NoninvertibleTransformException e) {
+ // we made sure this can't happen
+ e.printStackTrace();
+ }
+ pi = src.getPathIterator(at);
+ pi = new NormalizingPathIterator(pi, normalize);
+ } else {
+ pi = src.getPathIterator(null);
+ }
+ }
+ } else {
+ // either at is null or it's the identity. In either case
+ // we don't transform the path.
+ pi = src.getPathIterator(null);
+ if (normalize != NormMode.OFF) {
+ pi = new NormalizingPathIterator(pi, normalize);
+ }
}
- lsink = new Stroker(lsink, width, caps, join, miterlimit, a00, a01, a10, a11);
+
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, outat);
+ pc2d = new Stroker(pc2d, width, caps, join, miterlimit);
if (dashes != null) {
- lsink = new Dasher(lsink, dashes, dashphase, a00, a01, a10, a11);
- }
- PathIterator pi;
- if (normalize != NormMode.OFF) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(src.getPathIterator(at), normalize),
- defaultFlat);
- } else {
- pi = src.getPathIterator(at, defaultFlat);
+ pc2d = new Dasher(pc2d, dashes, dashphase);
}
- pathTo(pi, lsink);
+ pc2d = TransformingPathConsumer2D.transformConsumer(pc2d, inat);
+
+ pathTo(pi, pc2d);
+ }
+
+ private static boolean nearZero(double num, int nulps) {
+ return Math.abs(num) < nulps * Math.ulp(num);
}
private static class NormalizingPathIterator implements PathIterator {
@@ -337,10 +414,10 @@ public class PiscesRenderingEngine extends RenderingEngine {
}
// normalize endpoint
- float x_adjust = (float)Math.floor(coords[lastCoord] + lval) + rval -
- coords[lastCoord];
- float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) + rval -
- coords[lastCoord + 1];
+ float x_adjust = (float)Math.floor(coords[lastCoord] + lval) +
+ rval - coords[lastCoord];
+ float y_adjust = (float)Math.floor(coords[lastCoord+1] + lval) +
+ rval - coords[lastCoord + 1];
coords[lastCoord ] += x_adjust;
coords[lastCoord + 1] += y_adjust;
@@ -393,27 +470,9 @@ public class PiscesRenderingEngine extends RenderingEngine {
}
}
- void pathTo(PathIterator pi, LineSink lsink) {
- float coords[] = new float[2];
- while (!pi.isDone()) {
- switch (pi.currentSegment(coords)) {
- case PathIterator.SEG_MOVETO:
- lsink.moveTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_LINETO:
- lsink.lineJoin();
- lsink.lineTo(coords[0], coords[1]);
- break;
- case PathIterator.SEG_CLOSE:
- lsink.lineJoin();
- lsink.close();
- break;
- default:
- throw new InternalError("unknown flattened segment type");
- }
- pi.next();
- }
- lsink.end();
+ static void pathTo(PathIterator pi, PathConsumer2D pc2d) {
+ RenderingEngine.feedConsumer(pi, pc2d);
+ pc2d.pathDone();
}
/**
@@ -471,32 +530,29 @@ public class PiscesRenderingEngine extends RenderingEngine {
boolean normalize,
int bbox[])
{
- PiscesCache pc = PiscesCache.createInstance();
Renderer r;
NormMode norm = (normalize) ? NormMode.ON_WITH_AA : NormMode.OFF;
if (bs == null) {
PathIterator pi;
if (normalize) {
- pi = new FlatteningPathIterator(
- new NormalizingPathIterator(s.getPathIterator(at), norm),
- defaultFlat);
+ pi = new NormalizingPathIterator(s.getPathIterator(at), norm);
} else {
- pi = s.getPathIterator(at, defaultFlat);
+ pi = s.getPathIterator(at);
}
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- pi.getWindingRule(), pc);
+ pi.getWindingRule());
pathTo(pi, r);
} else {
r = new Renderer(3, 3,
clip.getLoX(), clip.getLoY(),
clip.getWidth(), clip.getHeight(),
- PathIterator.WIND_NON_ZERO, pc);
+ PathIterator.WIND_NON_ZERO);
strokeTo(s, at, bs, thin, norm, true, r);
}
r.endRendering();
- PiscesTileGenerator ptg = new PiscesTileGenerator(pc, r.MAX_AA_ALPHA);
+ PiscesTileGenerator ptg = new PiscesTileGenerator(r, r.MAX_AA_ALPHA);
ptg.getBbox(bbox);
return ptg;
}
diff --git a/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java b/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
index 93ff5315d9fc96b45762aa9aae7d82a29175a06a..e2779b8fe0393002c50842540b7b4bc2fd761939 100644
--- a/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
+++ b/src/share/classes/sun/java2d/pisces/PiscesTileGenerator.java
@@ -25,40 +25,54 @@
package sun.java2d.pisces;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
import sun.java2d.pipe.AATileGenerator;
-public class PiscesTileGenerator implements AATileGenerator {
- public static final int TILE_SIZE = 32;
+public final class PiscesTileGenerator implements AATileGenerator {
+ public static final int TILE_SIZE = PiscesCache.TILE_SIZE;
+
+ // perhaps we should be using weak references here, but right now
+ // that's not necessary. The way the renderer is, this map will
+ // never contain more than one element - the one with key 64, since
+ // we only do 8x8 supersampling.
+ private static final MapStroker.
*
- * @param output an output LineSink.
+ * @param pc2d an output PathConsumer2D.
* @param lineWidth the desired line width in pixels
* @param capStyle the desired end cap style, one of
* CAP_BUTT, CAP_ROUND or
@@ -120,183 +108,61 @@ public class Stroker implements LineSink {
* JOIN_MITER, JOIN_ROUND or
* JOIN_BEVEL.
* @param miterLimit the desired miter limit
- * @param transform a Transform4 object indicating
- * the transform that has been previously applied to all incoming
- * coordinates. This is required in order to produce consistently
- * shaped end caps and joins.
*/
- public Stroker(LineSink output,
+ public Stroker(PathConsumer2D pc2d,
float lineWidth,
int capStyle,
int joinStyle,
- float miterLimit,
- float m00, float m01, float m10, float m11) {
- this.output = output;
+ float miterLimit)
+ {
+ this.out = pc2d;
this.lineWidth2 = lineWidth / 2;
- this.scaledLineWidth2 = m00 * lineWidth2;
this.capStyle = capStyle;
this.joinStyle = joinStyle;
- m00_2_m01_2 = m00*m00 + m01*m01;
- m10_2_m11_2 = m10*m10 + m11*m11;
- m00_m10_m01_m11 = m00*m10 + m01*m11;
-
- this.m00 = m00;
- this.m01 = m01;
- this.m10 = m10;
- this.m11 = m11;
- det = m00*m11 - m01*m10;
-
- float limit = miterLimit * lineWidth2 * det;
+ float limit = miterLimit * lineWidth2;
this.miterLimitSq = limit*limit;
- this.numPenSegments = (int)(3.14159f * lineWidth);
- this.pen_dx = new float[numPenSegments];
- this.pen_dy = new float[numPenSegments];
- this.penIncluded = new boolean[numPenSegments];
- this.join = new float[2*numPenSegments];
-
- for (int i = 0; i < numPenSegments; i++) {
- double theta = (i * 2.0 * Math.PI)/numPenSegments;
-
- double cos = Math.cos(theta);
- double sin = Math.sin(theta);
- pen_dx[i] = (float)(lineWidth2 * (m00*cos + m01*sin));
- pen_dy[i] = (float)(lineWidth2 * (m10*cos + m11*sin));
- }
-
- prev = CLOSE;
- rindex = 0;
- started = false;
- lineToOrigin = false;
+ this.prev = CLOSE;
}
- private void computeOffset(float x0, float y0,
- float x1, float y1, float[] m) {
- float lx = x1 - x0;
- float ly = y1 - y0;
-
- float dx, dy;
- if (m00 > 0 && m00 == m11 && m01 == 0 & m10 == 0) {
- float ilen = (float)Math.hypot(lx, ly);
- if (ilen == 0) {
- dx = dy = 0;
- } else {
- dx = (ly * scaledLineWidth2)/ilen;
- dy = -(lx * scaledLineWidth2)/ilen;
- }
+ private static void computeOffset(final float lx, final float ly,
+ final float w, final float[] m)
+ {
+ final float len = (float)Math.hypot(lx, ly);
+ if (len == 0) {
+ m[0] = m[1] = 0;
} else {
- int sdet = (det > 0) ? 1 : -1;
- float a = ly * m00 - lx * m10;
- float b = ly * m01 - lx * m11;
- float dh = (float)Math.hypot(a, b);
- float div = sdet * lineWidth2/dh;
-
- float ddx = ly * m00_2_m01_2 - lx * m00_m10_m01_m11;
- float ddy = ly * m00_m10_m01_m11 - lx * m10_2_m11_2;
- dx = ddx*div;
- dy = ddy*div;
- }
-
- m[0] = dx;
- m[1] = dy;
- }
-
- private void ensureCapacity(int newrindex) {
- if (reverse.length < newrindex) {
- reverse = java.util.Arrays.copyOf(reverse, 6*reverse.length/5);
+ m[0] = (ly * w)/len;
+ m[1] = -(lx * w)/len;
}
}
- private boolean isCCW(float x0, float y0,
- float x1, float y1,
- float x2, float y2) {
- return (x1 - x0) * (y2 - y1) < (y1 - y0) * (x2 - x1);
- }
-
- private boolean side(float x, float y,
- float x0, float y0,
- float x1, float y1) {
- return (y0 - y1)*x + (x1 - x0)*y + (x0*y1 - x1*y0) > 0;
- }
-
- private int computeRoundJoin(float cx, float cy,
- float xa, float ya,
- float xb, float yb,
- int side,
- boolean flip,
- float[] join) {
- float px, py;
- int ncoords = 0;
-
- boolean centerSide;
- if (side == 0) {
- centerSide = side(cx, cy, xa, ya, xb, yb);
- } else {
- centerSide = (side == 1);
- }
- for (int i = 0; i < numPenSegments; i++) {
- px = cx + pen_dx[i];
- py = cy + pen_dy[i];
-
- boolean penSide = side(px, py, xa, ya, xb, yb);
- penIncluded[i] = (penSide != centerSide);
- }
-
- int start = -1, end = -1;
- for (int i = 0; i < numPenSegments; i++) {
- if (penIncluded[i] &&
- !penIncluded[(i + numPenSegments - 1) % numPenSegments]) {
- start = i;
- }
- if (penIncluded[i] &&
- !penIncluded[(i + 1) % numPenSegments]) {
- end = i;
- }
- }
-
- if (end < start) {
- end += numPenSegments;
- }
-
- if (start != -1 && end != -1) {
- float dxa = cx + pen_dx[start] - xa;
- float dya = cy + pen_dy[start] - ya;
- float dxb = cx + pen_dx[start] - xb;
- float dyb = cy + pen_dy[start] - yb;
-
- boolean rev = (dxa*dxa + dya*dya > dxb*dxb + dyb*dyb);
- int i = rev ? end : start;
- int incr = rev ? -1 : 1;
- while (true) {
- int idx = i % numPenSegments;
- px = cx + pen_dx[idx];
- py = cy + pen_dy[idx];
- join[ncoords++] = px;
- join[ncoords++] = py;
- if (i == (rev ? start : end)) {
- break;
- }
- i += incr;
- }
- }
-
- return ncoords/2;
+ // Returns true if the vectors (dx1, dy1) and (dx2, dy2) are
+ // clockwise (if dx1,dy1 needs to be rotated clockwise to close
+ // the smallest angle between it and dx2,dy2).
+ // This is equivalent to detecting whether a point q is on the right side
+ // of a line passing through points p1, p2 where p2 = p1+(dx1,dy1) and
+ // q = p2+(dx2,dy2), which is the same as saying p1, p2, q are in a
+ // clockwise order.
+ // NOTE: "clockwise" here assumes coordinates with 0,0 at the bottom left.
+ private static boolean isCW(final float dx1, final float dy1,
+ final float dx2, final float dy2)
+ {
+ return dx1 * dy2 <= dy1 * dx2;
}
// pisces used to use fixed point arithmetic with 16 decimal digits. I
- // didn't want to change the values of the constants below when I converted
+ // didn't want to change the values of the constant below when I converted
// it to floating point, so that's why the divisions by 2^16 are there.
private static final float ROUND_JOIN_THRESHOLD = 1000/65536f;
- private static final float ROUND_JOIN_INTERNAL_THRESHOLD = 1000000000/65536f;
private void drawRoundJoin(float x, float y,
float omx, float omy, float mx, float my,
- int side,
- boolean flip,
boolean rev,
- float threshold) {
+ float threshold)
+ {
if ((omx == 0 && omy == 0) || (mx == 0 && my == 0)) {
return;
}
@@ -314,54 +180,148 @@ public class Stroker implements LineSink {
mx = -mx;
my = -my;
}
+ drawRoundJoin(x, y, omx, omy, mx, my, rev);
+ }
- float bx0 = x + omx;
- float by0 = y + omy;
- float bx1 = x + mx;
- float by1 = y + my;
+ private void drawRoundJoin(float cx, float cy,
+ float omx, float omy,
+ float mx, float my,
+ boolean rev)
+ {
+ // The sign of the dot product of mx,my and omx,omy is equal to the
+ // the sign of the cosine of ext
+ // (ext is the angle between omx,omy and mx,my).
+ double cosext = omx * mx + omy * my;
+ // If it is >=0, we know that abs(ext) is <= 90 degrees, so we only
+ // need 1 curve to approximate the circle section that joins omx,omy
+ // and mx,my.
+ final int numCurves = cosext >= 0 ? 1 : 2;
+
+ switch (numCurves) {
+ case 1:
+ drawBezApproxForArc(cx, cy, omx, omy, mx, my, rev);
+ break;
+ case 2:
+ // we need to split the arc into 2 arcs spanning the same angle.
+ // The point we want will be one of the 2 intersections of the
+ // perpendicular bisector of the chord (omx,omy)->(mx,my) and the
+ // circle. We could find this by scaling the vector
+ // (omx+mx, omy+my)/2 so that it has length=lineWidth2 (and thus lies
+ // on the circle), but that can have numerical problems when the angle
+ // between omx,omy and mx,my is close to 180 degrees. So we compute a
+ // normal of (omx,omy)-(mx,my). This will be the direction of the
+ // perpendicular bisector. To get one of the intersections, we just scale
+ // this vector that its length is lineWidth2 (this works because the
+ // perpendicular bisector goes through the origin). This scaling doesn't
+ // have numerical problems because we know that lineWidth2 divided by
+ // this normal's length is at least 0.5 and at most sqrt(2)/2 (because
+ // we know the angle of the arc is > 90 degrees).
+ float nx = my - omy, ny = omx - mx;
+ float nlen = (float)Math.sqrt(nx*nx + ny*ny);
+ float scale = lineWidth2/nlen;
+ float mmx = nx * scale, mmy = ny * scale;
+
+ // if (isCW(omx, omy, mx, my) != isCW(mmx, mmy, mx, my)) then we've
+ // computed the wrong intersection so we get the other one.
+ // The test above is equivalent to if (rev).
+ if (rev) {
+ mmx = -mmx;
+ mmy = -mmy;
+ }
+ drawBezApproxForArc(cx, cy, omx, omy, mmx, mmy, rev);
+ drawBezApproxForArc(cx, cy, mmx, mmy, mx, my, rev);
+ break;
+ }
+ }
- int npoints = computeRoundJoin(x, y,
- bx0, by0, bx1, by1, side, flip,
- join);
- for (int i = 0; i < npoints; i++) {
- emitLineTo(join[2*i], join[2*i + 1], rev);
+ // the input arc defined by omx,omy and mx,my must span <= 90 degrees.
+ private void drawBezApproxForArc(final float cx, final float cy,
+ final float omx, final float omy,
+ final float mx, final float my,
+ boolean rev)
+ {
+ float cosext2 = (omx * mx + omy * my) / (2 * lineWidth2 * lineWidth2);
+ // cv is the length of P1-P0 and P2-P3 divided by the radius of the arc
+ // (so, cv assumes the arc has radius 1). P0, P1, P2, P3 are the points that
+ // define the bezier curve we're computing.
+ // It is computed using the constraints that P1-P0 and P3-P2 are parallel
+ // to the arc tangents at the endpoints, and that |P1-P0|=|P3-P2|.
+ float cv = (float)((4.0 / 3.0) * Math.sqrt(0.5-cosext2) /
+ (1.0 + Math.sqrt(cosext2+0.5)));
+ // if clockwise, we need to negate cv.
+ if (rev) { // rev is equivalent to isCW(omx, omy, mx, my)
+ cv = -cv;
}
+ final float x1 = cx + omx;
+ final float y1 = cy + omy;
+ final float x2 = x1 - cv * omy;
+ final float y2 = y1 + cv * omx;
+
+ final float x4 = cx + mx;
+ final float y4 = cy + my;
+ final float x3 = x4 + cv * my;
+ final float y3 = y4 - cv * mx;
+
+ emitCurveTo(x1, y1, x2, y2, x3, y3, x4, y4, rev);
}
- // Return the intersection point of the lines (ix0, iy0) -> (ix1, iy1)
- // and (ix0p, iy0p) -> (ix1p, iy1p) in m[0] and m[1]
- private void computeMiter(float x0, float y0, float x1, float y1,
- float x0p, float y0p, float x1p, float y1p,
- float[] m) {
+ private void drawRoundCap(float cx, float cy, float mx, float my) {
+ final float C = 0.5522847498307933f;
+ // the first and second arguments of the following two calls
+ // are really will be ignored by emitCurveTo (because of the false),
+ // but we put them in anyway, as opposed to just giving it 4 zeroes,
+ // because it's just 4 additions and it's not good to rely on this
+ // sort of assumption (right now it's true, but that may change).
+ emitCurveTo(cx+mx, cy+my,
+ cx+mx-C*my, cy+my+C*mx,
+ cx-my+C*mx, cy+mx+C*my,
+ cx-my, cy+mx,
+ false);
+ emitCurveTo(cx-my, cy+mx,
+ cx-my-C*mx, cy+mx-C*my,
+ cx-mx-C*my, cy-my+C*mx,
+ cx-mx, cy-my,
+ false);
+ }
+
+ // Return the intersection point of the lines (x0, y0) -> (x1, y1)
+ // and (x0p, y0p) -> (x1p, y1p) in m[0] and m[1]
+ private void computeMiter(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x0p, final float y0p,
+ final float x1p, final float y1p,
+ final float[] m, int off)
+ {
float x10 = x1 - x0;
float y10 = y1 - y0;
float x10p = x1p - x0p;
float y10p = y1p - y0p;
+ // if this is 0, the lines are parallel. If they go in the
+ // same direction, there is no intersection so m[off] and
+ // m[off+1] will contain infinity, so no miter will be drawn.
+ // If they go in the same direction that means that the start of the
+ // current segment and the end of the previous segment have the same
+ // tangent, in which case this method won't even be involved in
+ // miter drawing because it won't be called by drawMiter (because
+ // (mx == omx && my == omy) will be true, and drawMiter will return
+ // immediately).
float den = x10*y10p - x10p*y10;
- if (den == 0) {
- m[0] = x0;
- m[1] = y0;
- return;
- }
-
- float t = x1p*(y0 - y0p) - x0*y10p + x0p*(y1p - y0);
- m[0] = x0 + (t*x10)/den;
- m[1] = y0 + (t*y10)/den;
+ float t = x10p*(y0-y0p) - y10p*(x0-x0p);
+ t /= den;
+ m[off++] = x0 + t*x10;
+ m[off] = y0 + t*y10;
}
- private void drawMiter(float px0, float py0,
- float x0, float y0,
- float x1, float y1,
+ private void drawMiter(final float pdx, final float pdy,
+ final float x0, final float y0,
+ final float dx, final float dy,
float omx, float omy, float mx, float my,
- boolean rev) {
- if (mx == omx && my == omy) {
- return;
- }
- if (px0 == x0 && py0 == y0) {
- return;
- }
- if (x0 == x1 && y0 == y1) {
+ boolean rev)
+ {
+ if ((mx == omx && my == omy) ||
+ (pdx == 0 && pdy == 0) ||
+ (dx == 0 && dy == 0)) {
return;
}
@@ -372,297 +332,734 @@ public class Stroker implements LineSink {
my = -my;
}
- computeMiter(px0 + omx, py0 + omy, x0 + omx, y0 + omy,
- x0 + mx, y0 + my, x1 + mx, y1 + my,
- miter);
+ computeMiter((x0 - pdx) + omx, (y0 - pdy) + omy, x0 + omx, y0 + omy,
+ (dx + x0) + mx, (dy + y0) + my, x0 + mx, y0 + my,
+ miter, 0);
- // Compute miter length in untransformed coordinates
- float dx = miter[0] - x0;
- float dy = miter[1] - y0;
- float a = dy*m00 - dx*m10;
- float b = dy*m01 - dx*m11;
- float lenSq = a*a + b*b;
+ float lenSq = (miter[0]-x0)*(miter[0]-x0) + (miter[1]-y0)*(miter[1]-y0);
if (lenSq < miterLimitSq) {
emitLineTo(miter[0], miter[1], rev);
}
}
-
public void moveTo(float x0, float y0) {
- // System.out.println("Stroker.moveTo(" + x0/65536.0 + ", " + y0/65536.0 + ")");
-
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- }
-
- if (prev == LINE_TO) {
+ if (prev == DRAWING_OP_TO) {
finish();
}
-
- this.sx0 = this.x0 = x0;
- this.sy0 = this.y0 = y0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
+ this.sx0 = this.cx0 = x0;
+ this.sy0 = this.cy0 = y0;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
this.prev = MOVE_TO;
}
- boolean joinSegment = false;
+ public void lineTo(float x1, float y1) {
+ float dx = x1 - cx0;
+ float dy = y1 - cy0;
+ if (dx == 0f && dy == 0f) {
+ dx = 1;
+ }
+ computeOffset(dx, dy, lineWidth2, offset[0]);
+ float mx = offset[0][0];
+ float my = offset[0][1];
+
+ drawJoin(cdx, cdy, cx0, cy0, dx, dy, cmx, cmy, mx, my);
- public void lineJoin() {
- // System.out.println("Stroker.lineJoin()");
- this.joinSegment = true;
- }
+ emitLineTo(cx0 + mx, cy0 + my);
+ emitLineTo(x1 + mx, y1 + my);
- public void lineTo(float x1, float y1) {
- // System.out.println("Stroker.lineTo(" + x1/65536.0 + ", " + y1/65536.0 + ")");
+ emitLineTo(cx0 - mx, cy0 - my, true);
+ emitLineTo(x1 - mx, y1 - my, true);
+
+ this.cmx = mx;
+ this.cmy = my;
+ this.cdx = dx;
+ this.cdy = dy;
+ this.cx0 = x1;
+ this.cy0 = y1;
+ this.prev = DRAWING_OP_TO;
+ }
- if (lineToOrigin) {
- if (x1 == sx0 && y1 == sy0) {
- // staying in the starting point
+ public void closePath() {
+ if (prev != DRAWING_OP_TO) {
+ if (prev == CLOSE) {
return;
}
-
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
- } else if (x1 == x0 && y1 == y0) {
- return;
- } else if (x1 == sx0 && y1 == sy0) {
- lineToOrigin = true;
- joinToOrigin = joinSegment;
- joinSegment = false;
+ emitMoveTo(cx0, cy0 - lineWidth2);
+ this.cmx = this.smx = 0;
+ this.cmy = this.smy = -lineWidth2;
+ this.cdx = this.sdx = 1;
+ this.cdy = this.sdy = 0;
+ finish();
return;
}
- lineToImpl(x1, y1, joinSegment);
- joinSegment = false;
+ if (cx0 != sx0 || cy0 != sy0) {
+ lineTo(sx0, sy0);
+ }
+
+ drawJoin(cdx, cdy, cx0, cy0, sdx, sdy, cmx, cmy, smx, smy);
+
+ emitLineTo(sx0 + smx, sy0 + smy);
+
+ emitMoveTo(sx0 - smx, sy0 - smy);
+ emitReverse();
+
+ this.prev = CLOSE;
+ emitClose();
}
- private void lineToImpl(float x1, float y1, boolean joinSegment) {
- computeOffset(x0, y0, x1, y1, offset);
- float mx = offset[0];
- float my = offset[1];
+ private void emitReverse() {
+ while(!reverse.isEmpty()) {
+ reverse.pop(out);
+ }
+ }
- if (!started) {
- emitMoveTo(x0 + mx, y0 + my);
- this.sx1 = x1;
- this.sy1 = y1;
- this.mx0 = mx;
- this.my0 = my;
- started = true;
- } else {
- boolean ccw = isCCW(px0, py0, x0, y0, x1, y1);
- if (joinSegment) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, x1, y1, omx, omy, mx, my,
- ccw);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_THRESHOLD);
- }
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
- }
+ public void pathDone() {
+ if (prev == DRAWING_OP_TO) {
+ finish();
+ }
+
+ out.pathDone();
+ // this shouldn't matter since this object won't be used
+ // after the call to this method.
+ this.prev = CLOSE;
+ }
- emitLineTo(x0, y0, !ccw);
+ private void finish() {
+ if (capStyle == CAP_ROUND) {
+ drawRoundCap(cx0, cy0, cmx, cmy);
+ } else if (capStyle == CAP_SQUARE) {
+ emitLineTo(cx0 - cmy + cmx, cy0 + cmx + cmy);
+ emitLineTo(cx0 - cmy - cmx, cy0 + cmx - cmy);
}
- emitLineTo(x0 + mx, y0 + my, false);
- emitLineTo(x1 + mx, y1 + my, false);
+ emitReverse();
- emitLineTo(x0 - mx, y0 - my, true);
- emitLineTo(x1 - mx, y1 - my, true);
+ if (capStyle == CAP_ROUND) {
+ drawRoundCap(sx0, sy0, -smx, -smy);
+ } else if (capStyle == CAP_SQUARE) {
+ emitLineTo(sx0 + smy - smx, sy0 - smx - smy);
+ emitLineTo(sx0 + smy + smx, sy0 - smx + smy);
+ }
- this.omx = mx;
- this.omy = my;
- this.px0 = x0;
- this.py0 = y0;
- this.x0 = x1;
- this.y0 = y1;
- this.prev = LINE_TO;
+ emitClose();
}
- public void close() {
- // System.out.println("Stroker.close()");
+ private void emitMoveTo(final float x0, final float y0) {
+ out.moveTo(x0, y0);
+ }
- if (lineToOrigin) {
- // ignore the previous lineTo
- lineToOrigin = false;
+ private void emitLineTo(final float x1, final float y1) {
+ out.lineTo(x1, y1);
+ }
+
+ private void emitLineTo(final float x1, final float y1,
+ final boolean rev)
+ {
+ if (rev) {
+ reverse.pushLine(x1, y1);
+ } else {
+ emitLineTo(x1, y1);
}
+ }
- if (!started) {
- finish();
- return;
+ private void emitQuadTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushQuad(x0, y0, x1, y1);
+ } else {
+ out.quadTo(x1, y1, x2, y2);
}
+ }
+
+ private void emitCurveTo(final float x0, final float y0,
+ final float x1, final float y1,
+ final float x2, final float y2,
+ final float x3, final float y3, final boolean rev)
+ {
+ if (rev) {
+ reverse.pushCubic(x0, y0, x1, y1, x2, y2);
+ } else {
+ out.curveTo(x1, y1, x2, y2, x3, y3);
+ }
+ }
- computeOffset(x0, y0, sx0, sy0, offset);
- float mx = offset[0];
- float my = offset[1];
+ private void emitClose() {
+ out.closePath();
+ }
- // Draw penultimate join
- boolean ccw = isCCW(px0, py0, x0, y0, sx0, sy0);
- if (joinSegment) {
+ private void drawJoin(float pdx, float pdy,
+ float x0, float y0,
+ float dx, float dy,
+ float omx, float omy,
+ float mx, float my)
+ {
+ if (prev != DRAWING_OP_TO) {
+ emitMoveTo(x0 + mx, y0 + my);
+ this.sdx = dx;
+ this.sdy = dy;
+ this.smx = mx;
+ this.smy = my;
+ } else {
+ boolean cw = isCW(pdx, pdy, dx, dy);
if (joinStyle == JOIN_MITER) {
- drawMiter(px0, py0, x0, y0, sx0, sy0, omx, omy, mx, my, ccw);
+ drawMiter(pdx, pdy, x0, y0, dx, dy, omx, omy, mx, my, cw);
} else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(x0, y0, omx, omy, mx, my, 0, false, ccw,
+ drawRoundJoin(x0, y0,
+ omx, omy,
+ mx, my, cw,
ROUND_JOIN_THRESHOLD);
}
- } else {
- // Draw internal joins as round
- drawRoundJoin(x0, y0,
- omx, omy,
- mx, my, 0, false, ccw,
- ROUND_JOIN_INTERNAL_THRESHOLD);
+ emitLineTo(x0, y0, !cw);
}
+ prev = DRAWING_OP_TO;
+ }
- emitLineTo(x0 + mx, y0 + my);
- emitLineTo(sx0 + mx, sy0 + my);
+ private static boolean within(final float x1, final float y1,
+ final float x2, final float y2,
+ final float ERR)
+ {
+ assert ERR > 0 : "";
+ // compare taxicab distance. ERR will always be small, so using
+ // true distance won't give much benefit
+ return (Helpers.within(x1, x2, ERR) && // we want to avoid calling Math.abs
+ Helpers.within(y1, y2, ERR)); // this is just as good.
+ }
- ccw = isCCW(x0, y0, sx0, sy0, sx1, sy1);
+ private void getLineOffsets(float x1, float y1,
+ float x2, float y2,
+ float[] left, float[] right) {
+ computeOffset(x2 - x1, y2 - y1, lineWidth2, offset[0]);
+ left[0] = x1 + offset[0][0];
+ left[1] = y1 + offset[0][1];
+ left[2] = x2 + offset[0][0];
+ left[3] = y2 + offset[0][1];
+ right[0] = x1 - offset[0][0];
+ right[1] = y1 - offset[0][1];
+ right[2] = x2 - offset[0][0];
+ right[3] = y2 - offset[0][1];
+ }
- // Draw final join on the outside
- if (!ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- mx, my, mx0, my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, mx, my, mx0, my0, 0, false, false,
- ROUND_JOIN_THRESHOLD);
- }
+ private int computeOffsetCubic(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+ final float x4 = pts[off + 6], y4 = pts[off + 7];
+
+ float dx4 = x4 - x3;
+ float dy4 = y4 - y3;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore if p1 == p2
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p3eqp4 = within(x3,y3,x4,y4, 6 * Math.ulp(y4));
+ if (p1eqp2 && p3eqp4) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ } else if (p1eqp2) {
+ dx1 = x3 - x1;
+ dy1 = y3 - y1;
+ } else if (p3eqp4) {
+ dx4 = x4 - x2;
+ dy4 = y4 - y2;
}
- emitLineTo(sx0 + mx0, sy0 + my0);
- emitLineTo(sx0 - mx0, sy0 - my0); // same as reverse[0], reverse[1]
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx4 + dy1 * dy4);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l4sq = dx4 * dx4 + dy4 * dy4;
+ if (Helpers.within(dotsq, l1sq * l4sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x4, y4, leftOff, rightOff);
+ return 4;
+ }
- // Draw final join on the inside
- if (ccw) {
- if (joinStyle == JOIN_MITER) {
- drawMiter(x0, y0, sx0, sy0, sx1, sy1,
- -mx, -my, -mx0, -my0, false);
- } else if (joinStyle == JOIN_ROUND) {
- drawRoundJoin(sx0, sy0, -mx, -my, -mx0, -my0, 0,
- true, false,
- ROUND_JOIN_THRESHOLD);
- }
+// What we're trying to do in this function is to approximate an ideal
+// offset curve (call it I) of the input curve B using a bezier curve Bp.
+// The constraints I use to get the equations are:
+//
+// 1. The computed curve Bp should go through I(0) and I(1). These are
+// x1p, y1p, x4p, y4p, which are p1p and p4p. We still need to find
+// 4 variables: the x and y components of p2p and p3p (i.e. x2p, y2p, x3p, y3p).
+//
+// 2. Bp should have slope equal in absolute value to I at the endpoints. So,
+// (by the way, the operator || in the comments below means "aligned with".
+// It is defined on vectors, so when we say I'(0) || Bp'(0) we mean that
+// vectors I'(0) and Bp'(0) are aligned, which is the same as saying
+// that the tangent lines of I and Bp at 0 are parallel. Mathematically
+// this means (I'(t) || Bp'(t)) <==> (I'(t) = c * Bp'(t)) where c is some
+// nonzero constant.)
+// I'(0) || Bp'(0) and I'(1) || Bp'(1). Obviously, I'(0) || B'(0) and
+// I'(1) || B'(1); therefore, Bp'(0) || B'(0) and Bp'(1) || B'(1).
+// We know that Bp'(0) || (p2p-p1p) and Bp'(1) || (p4p-p3p) and the same
+// is true for any bezier curve; therefore, we get the equations
+// (1) p2p = c1 * (p2-p1) + p1p
+// (2) p3p = c2 * (p4-p3) + p4p
+// We know p1p, p4p, p2, p1, p3, and p4; therefore, this reduces the number
+// of unknowns from 4 to 2 (i.e. just c1 and c2).
+// To eliminate these 2 unknowns we use the following constraint:
+//
+// 3. Bp(0.5) == I(0.5). Bp(0.5)=(x,y) and I(0.5)=(xi,yi), and I should note
+// that I(0.5) is *the only* reason for computing dxm,dym. This gives us
+// (3) Bp(0.5) = (p1p + 3 * (p2p + p3p) + p4p)/8, which is equivalent to
+// (4) p2p + p3p = (Bp(0.5)*8 - p1p - p4p) / 3
+// We can substitute (1) and (2) from above into (4) and we get:
+// (5) c1*(p2-p1) + c2*(p4-p3) = (Bp(0.5)*8 - p1p - p4p)/3 - p1p - p4p
+// which is equivalent to
+// (6) c1*(p2-p1) + c2*(p4-p3) = (4/3) * (Bp(0.5) * 2 - p1p - p4p)
+//
+// The right side of this is a 2D vector, and we know I(0.5), which gives us
+// Bp(0.5), which gives us the value of the right side.
+// The left side is just a matrix vector multiplication in disguise. It is
+//
+// [x2-x1, x4-x3][c1]
+// [y2-y1, y4-y3][c2]
+// which, is equal to
+// [dx1, dx4][c1]
+// [dy1, dy4][c2]
+// At this point we are left with a simple linear system and we solve it by
+// getting the inverse of the matrix above. Then we use [c1,c2] to compute
+// p2p and p3p.
+
+ float x = 0.125f * (x1 + 3 * (x2 + x3) + x4);
+ float y = 0.125f * (y1 + 3 * (y2 + y3) + y4);
+ // (dxm,dym) is some tangent of B at t=0.5. This means it's equal to
+ // c*B'(0.5) for some constant c.
+ float dxm = x3 + x4 - x1 - x2, dym = y3 + y4 - y1 - y2;
+
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dxm, dym, lineWidth2, offset[1]);
+ computeOffset(dx4, dy4, lineWidth2, offset[2]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float xi = x + offset[1][0]; // interpolation
+ float yi = y + offset[1][1]; // point
+ float x4p = x4 + offset[2][0]; // end
+ float y4p = y4 + offset[2][1]; // point
+
+ float invdet43 = 4f / (3f * (dx1 * dy4 - dy1 * dx4));
+
+ float two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ float two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ float c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ float c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ float x2p, y2p, x3p, y3p;
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[2] = x2p; leftOff[3] = y2p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ leftOff[6] = x4p; leftOff[7] = y4p;
+
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ xi = xi - 2 * offset[1][0]; yi = yi - 2 * offset[1][1];
+ x4p = x4 - offset[2][0]; y4p = y4 - offset[2][1];
+
+ two_pi_m_p1_m_p4x = 2*xi - x1p - x4p;
+ two_pi_m_p1_m_p4y = 2*yi - y1p - y4p;
+ c1 = invdet43 * (dy4 * two_pi_m_p1_m_p4x - dx4 * two_pi_m_p1_m_p4y);
+ c2 = invdet43 * (dx1 * two_pi_m_p1_m_p4y - dy1 * two_pi_m_p1_m_p4x);
+
+ x2p = x1p + c1*dx1;
+ y2p = y1p + c1*dy1;
+ x3p = x4p + c2*dx4;
+ y3p = y4p + c2*dy4;
+
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[2] = x2p; rightOff[3] = y2p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ rightOff[6] = x4p; rightOff[7] = y4p;
+ return 8;
+ }
+
+ // compute offset curves using bezier spline through t=0.5 (i.e.
+ // ComputedCurve(0.5) == IdealParallelCurve(0.5))
+ // return the kind of curve in the right and left arrays.
+ private int computeOffsetQuad(float[] pts, final int off,
+ float[] leftOff, float[] rightOff)
+ {
+ final float x1 = pts[off + 0], y1 = pts[off + 1];
+ final float x2 = pts[off + 2], y2 = pts[off + 3];
+ final float x3 = pts[off + 4], y3 = pts[off + 5];
+
+ float dx3 = x3 - x2;
+ float dy3 = y3 - y2;
+ float dx1 = x2 - x1;
+ float dy1 = y2 - y1;
+
+ // if p1=p2 or p3=p4 it means that the derivative at the endpoint
+ // vanishes, which creates problems with computeOffset. Usually
+ // this happens when this stroker object is trying to winden
+ // a curve with a cusp. What happens is that curveTo splits
+ // the input curve at the cusp, and passes it to this function.
+ // because of inaccuracies in the splitting, we consider points
+ // equal if they're very close to each other.
+
+ // if p1 == p2 && p3 == p4: draw line from p1->p4, unless p1 == p4,
+ // in which case ignore.
+ final boolean p1eqp2 = within(x1,y1,x2,y2, 6 * Math.ulp(y2));
+ final boolean p2eqp3 = within(x2,y2,x3,y3, 6 * Math.ulp(y3));
+ if (p1eqp2 || p2eqp3) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
}
- emitLineTo(sx0 - mx, sy0 - my);
- emitLineTo(x0 - mx, y0 - my);
- for (int i = rindex - 2; i >= 0; i -= 2) {
- emitLineTo(reverse[i], reverse[i + 1]);
+ // if p2-p1 and p4-p3 are parallel, that must mean this curve is a line
+ float dotsq = (dx1 * dx3 + dy1 * dy3);
+ dotsq = dotsq * dotsq;
+ float l1sq = dx1 * dx1 + dy1 * dy1, l3sq = dx3 * dx3 + dy3 * dy3;
+ if (Helpers.within(dotsq, l1sq * l3sq, 4 * Math.ulp(dotsq))) {
+ getLineOffsets(x1, y1, x3, y3, leftOff, rightOff);
+ return 4;
}
- this.x0 = this.sx0;
- this.y0 = this.sy0;
- this.rindex = 0;
- this.started = false;
- this.joinSegment = false;
- this.prev = CLOSE;
- emitClose();
+ // this computes the offsets at t=0, 0.5, 1, using the property that
+ // for any bezier curve the vectors p2-p1 and p4-p3 are parallel to
+ // the (dx/dt, dy/dt) vectors at the endpoints.
+ computeOffset(dx1, dy1, lineWidth2, offset[0]);
+ computeOffset(dx3, dy3, lineWidth2, offset[1]);
+ float x1p = x1 + offset[0][0]; // start
+ float y1p = y1 + offset[0][1]; // point
+ float x3p = x3 + offset[1][0]; // end
+ float y3p = y3 + offset[1][1]; // point
+
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, leftOff, 2);
+ leftOff[0] = x1p; leftOff[1] = y1p;
+ leftOff[4] = x3p; leftOff[5] = y3p;
+ x1p = x1 - offset[0][0]; y1p = y1 - offset[0][1];
+ x3p = x3 - offset[1][0]; y3p = y3 - offset[1][1];
+ computeMiter(x1p, y1p, x1p+dx1, y1p+dy1, x3p, y3p, x3p-dx3, y3p-dy3, rightOff, 2);
+ rightOff[0] = x1p; rightOff[1] = y1p;
+ rightOff[4] = x3p; rightOff[5] = y3p;
+ return 6;
}
- public void end() {
- // System.out.println("Stroker.end()");
+ // This is where the curve to be processed is put. We give it
+ // enough room to store 2 curves: one for the current subdivision, the
+ // other for the rest of the curve.
+ private float[][] middle = new float[2][8];
+ private float[] lp = new float[8];
+ private float[] rp = new float[8];
+ private static final int MAX_N_CURVES = 11;
+ private float[] subdivTs = new float[MAX_N_CURVES - 1];
+
+ private void somethingTo(final int type) {
+ // need these so we can update the state at the end of this method
+ final float xf = middle[0][type-2], yf = middle[0][type-1];
+ float dxs = middle[0][2] - middle[0][0];
+ float dys = middle[0][3] - middle[0][1];
+ float dxf = middle[0][type - 2] - middle[0][type - 4];
+ float dyf = middle[0][type - 1] - middle[0][type - 3];
+ switch(type) {
+ case 6:
+ if ((dxs == 0f && dys == 0f) ||
+ (dxf == 0f && dyf == 0f)) {
+ dxs = dxf = middle[0][4] - middle[0][0];
+ dys = dyf = middle[0][5] - middle[0][1];
+ }
+ break;
+ case 8:
+ boolean p1eqp2 = (dxs == 0f && dys == 0f);
+ boolean p3eqp4 = (dxf == 0f && dyf == 0f);
+ if (p1eqp2) {
+ dxs = middle[0][4] - middle[0][0];
+ dys = middle[0][5] - middle[0][1];
+ if (dxs == 0f && dys == 0f) {
+ dxs = middle[0][6] - middle[0][0];
+ dys = middle[0][7] - middle[0][1];
+ }
+ }
+ if (p3eqp4) {
+ dxf = middle[0][6] - middle[0][2];
+ dyf = middle[0][7] - middle[0][3];
+ if (dxf == 0f && dyf == 0f) {
+ dxf = middle[0][6] - middle[0][0];
+ dyf = middle[0][7] - middle[0][1];
+ }
+ }
+ }
+ if (dxs == 0f && dys == 0f) {
+ // this happens iff the "curve" is just a point
+ lineTo(middle[0][0], middle[0][1]);
+ return;
+ }
+ // if these vectors are too small, normalize them, to avoid future
+ // precision problems.
+ if (Math.abs(dxs) < 0.1f && Math.abs(dys) < 0.1f) {
+ double len = Math.hypot(dxs, dys);
+ dxs = (float)(dxs / len);
+ dys = (float)(dys / len);
+ }
+ if (Math.abs(dxf) < 0.1f && Math.abs(dyf) < 0.1f) {
+ double len = Math.hypot(dxf, dyf);
+ dxf = (float)(dxf / len);
+ dyf = (float)(dyf / len);
+ }
- if (lineToOrigin) {
- // not closing the path, do the previous lineTo
- lineToImpl(sx0, sy0, joinToOrigin);
- lineToOrigin = false;
+ computeOffset(dxs, dys, lineWidth2, offset[0]);
+ final float mx = offset[0][0];
+ final float my = offset[0][1];
+ drawJoin(cdx, cdy, cx0, cy0, dxs, dys, cmx, cmy, mx, my);
+
+ int nSplits = findSubdivPoints(middle[0], subdivTs, type,lineWidth2);
+
+ int kind = 0;
+ IteratorKeyTabEntry.
*/
public KeyTabEntry[] getEntries() {
- if (entries != null) {
- KeyTabEntry[] kentries = new KeyTabEntry[entries.size()];
- for (int i = 0; i < kentries.length; i++) {
- kentries[i] = entries.elementAt(i);
- }
- return kentries;
- } else {
- return null;
+ KeyTabEntry[] kentries = new KeyTabEntry[entries.size()];
+ for (int i = 0; i < kentries.length; i++) {
+ kentries[i] = entries.elementAt(i);
}
+ return kentries;
}
/**
@@ -464,29 +426,55 @@ public class KeyTab implements KeyTabConstants {
}
/**
- * Removes an entry from the key table.
+ * Removes entries from the key table.
* @param service the service PrincipalName.
- * @param etype the etype to match, first one if -1 provided
- * @return 1 if removed successfully, 0 otherwise
+ * @param etype the etype to match, remove all if -1
+ * @param kvno what kvno to remove, -1 for all, -2 for old
+ * @return the number of entries deleted
*/
- public int deleteEntry(PrincipalName service, int etype) {
- int result = retrieveEntry(service, etype);
- if (result != -1) {
- entries.removeElementAt(result);
- return 1;
+ public int deleteEntries(PrincipalName service, int etype, int kvno) {
+ int count = 0;
+
+ // Remember the highest KVNO for each etype. Used for kvno == -2
+ MapPrincipalName.
- * @return number of entries removed
- */
- public int deleteEntry(PrincipalName service) {
- int count = 0;
- while (deleteEntry(service, -1) > 0) {
- count++;
+ // Second round for kvno == -2, remove old entries
+ if (kvno == -2) {
+ for (int i = entries.size()-1; i >= 0; i--) {
+ KeyTabEntry e = entries.get(i);
+ if (service.match(e.getService())) {
+ if (etype == -1 || e.keyType == etype) {
+ int n = highest.get(e.keyType);
+ if (e.keyVersion != n) {
+ entries.removeElementAt(i);
+ count++;
+ }
+ }
+ }
+ }
}
return count;
}
diff --git a/src/share/classes/sun/security/pkcs11/SunPKCS11.java b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
index 95be485b58a0a2fcef677e09bb46eb1287822e57..33691f87ef725f7c5a20788af6fc8b82f0d2e135 100644
--- a/src/share/classes/sun/security/pkcs11/SunPKCS11.java
+++ b/src/share/classes/sun/security/pkcs11/SunPKCS11.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -655,6 +655,25 @@ public final class SunPKCS11 extends AuthProvider {
d(SIG, "SHA512withRSA", P11Signature,
m(CKM_SHA512_RSA_PKCS, CKM_RSA_PKCS, CKM_RSA_X_509));
+ /*
+ * TLS 1.2 uses a different hash algorithm than 1.0/1.1 for the
+ * PRF calculations. As of 2010, there is no PKCS11-level
+ * support for TLS 1.2 PRF calculations, and no known OS's have
+ * an internal variant we could use. Therefore for TLS 1.2, we
+ * are updating JSSE to request different provider algorithms
+ * (e.g. "SunTls12Prf"), and currently only SunJCE has these
+ * TLS 1.2 algorithms.
+ *
+ * If we reused the names such as "SunTlsPrf", the PKCS11
+ * providers would need be updated to fail correctly when
+ * presented with the wrong version number (via
+ * Provider.Service.supportsParameters()), and we would also
+ * need to add the appropriate supportsParamters() checks into
+ * KeyGenerators (not currently there).
+ *
+ * In the future, if PKCS11 support is added, we will restructure
+ * this.
+ */
d(KG, "SunTlsRsaPremasterSecret",
"sun.security.pkcs11.P11TlsRsaPremasterSecretGenerator",
m(CKM_SSL3_PRE_MASTER_KEY_GEN, CKM_TLS_PRE_MASTER_KEY_GEN));
@@ -887,7 +906,8 @@ public final class SunPKCS11 extends AuthProvider {
return (aliases == null) ? null : Arrays.asList(aliases);
}
- public Object newInstance(Object param) throws NoSuchAlgorithmException {
+ public Object newInstance(Object param)
+ throws NoSuchAlgorithmException {
if (token.isValid() == false) {
throw new NoSuchAlgorithmException("Token has been removed");
}
diff --git a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
index eb18820b2b8c9c0745ae0dbf781196ee7efd6a23..69e560ed4bf8489ea420808c9d73cf24af07893a 100644
--- a/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
+++ b/src/share/classes/sun/security/provider/certpath/AlgorithmChecker.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,95 +25,336 @@
package sun.security.provider.certpath;
-import java.util.Set;
+import java.security.AlgorithmConstraints;
+import java.security.CryptoPrimitive;
import java.util.Collection;
-import java.util.Locale;
+import java.util.Collections;
+import java.util.Set;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.math.BigInteger;
+import java.security.PublicKey;
+import java.security.KeyFactory;
+import java.security.AlgorithmParameters;
+import java.security.NoSuchAlgorithmException;
+import java.security.GeneralSecurityException;
import java.security.cert.Certificate;
-import java.security.cert.X509Certificate;
import java.security.cert.X509CRL;
-import java.security.cert.CertPathValidatorException;
+import java.security.cert.X509Certificate;
import java.security.cert.PKIXCertPathChecker;
+import java.security.cert.TrustAnchor;
+import java.security.cert.CRLException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertPathValidatorException;
+import java.io.IOException;
+import java.security.interfaces.*;
+import java.security.spec.*;
+import sun.security.util.DisabledAlgorithmConstraints;
+import sun.security.x509.X509CertImpl;
+import sun.security.x509.X509CRLImpl;
import sun.security.x509.AlgorithmId;
/**
- * AlgorithmChecker is a PKIXCertPathChecker that checks that
- * the signature algorithm of the specified certificate is not disabled.
+ * A PKIXCertPathChecker implementation to check whether a
+ * specified certificate contains the required algorithm constraints.
+ * AlgorithmChecker with the algorithm
+ * constraints specified in security property
+ * "jdk.certpath.disabledAlgorithms".
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
*/
- private AlgorithmChecker() {
- // do nothing
+ public AlgorithmChecker(TrustAnchor anchor) {
+ this(anchor, certPathDefaultConstraints);
}
/**
- * Return a AlgorithmChecker instance.
+ * Create a new AlgorithmChecker with the
+ * given {@code AlgorithmConstraints}.
+ * AlgorithmChecker with the
+ * given TrustAnchor and AlgorithmConstraints.
+ *
+ * @param anchor the trust anchor selected to validate the target
+ * certificate
+ * @param constraints the algorithm constraints (or null)
+ *
+ * @throws IllegalArgumentException if the anchor is null
*/
+ public AlgorithmChecker(TrustAnchor anchor,
+ AlgorithmConstraints constraints) {
+
+ if (anchor == null) {
+ throw new IllegalArgumentException(
+ "The trust anchor cannot be null");
+ }
+
+ if (anchor.getTrustedCert() != null) {
+ this.trustedPubKey = anchor.getTrustedCert().getPublicKey();
+ } else {
+ this.trustedPubKey = anchor.getCAPublicKey();
+ }
+
+ this.prevPubKey = trustedPubKey;
+ this.constraints = constraints;
+ }
+
+ @Override
public void init(boolean forward) throws CertPathValidatorException {
- // do nothing
+ // Note that this class does not support forward mode.
+ if (!forward) {
+ if (trustedPubKey != null) {
+ prevPubKey = trustedPubKey;
+ } else {
+ prevPubKey = null;
+ }
+ } else {
+ throw new
+ CertPathValidatorException("forward checking not supported");
+ }
}
+ @Override
public boolean isForwardCheckingSupported() {
+ // Note that as this class does not support forward mode, the method
+ // will always returns false.
return false;
}
+ @Override
public Set
+ * HandshakeHash hh = new HandshakeHash(...)
+ * hh.update(clientHelloBytes);
+ * hh.setFinishedAlg("SHA-256");
+ * hh.update(serverHelloBytes);
+ * ...
+ * hh.setCertificateVerifyAlg("SHA-384");
+ * hh.update(CertificateVerifyBytes);
+ * byte[] cvDigest = hh.getCertificateVerifyHash();
+ * ...
+ * hh.update(finished1);
+ * byte[] finDigest1 = hh.getFinishedHash();
+ * hh.update(finished2);
+ * byte[] finDigest2 = hh.getFinishedHash();
+ *
+ * If no CertificateVerify message is to be used, call
+ *
+ * hh.setCertificateVerifyAlg(null);
+ *
+ * This call can be made once you are certain that this message
+ * will never be used.
*/
final class HandshakeHash {
- private final MessageDigest md5, sha;
+ // Common
+
+ // -1: unknown
+ // 1: <=TLS 1.1
+ // 2: TLS 1.2
+ private int version = -1;
+ private ByteArrayOutputStream data = new ByteArrayOutputStream();
+ private final boolean isServer;
+
+ // For TLS 1.1
+ private MessageDigest md5, sha;
+ private final int clonesNeeded; // needs to be saved for later use
+
+ // For TLS 1.2
+ // cvAlgDetermined == true means setCertificateVerifyAlg() is called
+ private boolean cvAlgDetermined = false;
+ private String cvAlg;
+ private MessageDigest finMD;
/**
* Create a new HandshakeHash. needCertificateVerify indicates whether
- * a hash for the certificate verify message is required.
+ * a hash for the certificate verify message is required. The argument
+ * algs is a set of all possible hash algorithms that might be used in
+ * TLS 1.2. If the caller is sure that TLS 1.2 won't be used or no
+ * CertificateVerify message will be used, leave it null or empty.
*/
- HandshakeHash(boolean needCertificateVerify) {
- int n = needCertificateVerify ? 3 : 2;
- try {
- md5 = CloneableDigest.getDigest("MD5", n);
- sha = CloneableDigest.getDigest("SHA", n);
- } catch (NoSuchAlgorithmException e) {
- throw new RuntimeException
- ("Algorithm MD5 or SHA not available", e);
-
- }
- }
-
- void update(byte b) {
- md5.update(b);
- sha.update(b);
+ HandshakeHash(boolean isServer, boolean needCertificateVerify,
+ SetprotocolVersion and the highest version of this
+ * protocol list, or null if no protocol version is available.
+ *
+ * The method is used by TLS server to negotiated the protocol
+ * version between client suggested protocol version in the
+ * client hello and protocol versions supported by the server.
+ */
+ ProtocolVersion selectProtocolVersion(ProtocolVersion protocolVersion) {
+ ProtocolVersion selectedVersion = null;
+ for (ProtocolVersion pv : protocols) {
+ if (pv.v > protocolVersion.v) {
+ break; // Safe to break here as this.protocols is sorted
+ }
+ selectedVersion = pv;
+ }
+
+ return selectedVersion;
+ }
+
/**
* Return an array with the names of the ProtocolVersions in this list.
*/
@@ -106,11 +156,18 @@ final class ProtocolList {
}
/**
- * Return the list of default enabled protocols. Currently, this
- * is identical to the supported protocols.
+ * Return the list of default enabled protocols.
*/
- static ProtocolList getDefault() {
- return SUPPORTED;
+ static ProtocolList getDefault(boolean isServer) {
+ return isServer ? SERVER_DEFAULT : CLIENT_DEFAULT;
+ }
+
+ /**
+ * Return whether a protocol list is the original default enabled
+ * protocols. See: SSLSocket/SSLEngine.setEnabledProtocols()
+ */
+ static boolean isDefaultProtocolList(ProtocolList protocols) {
+ return protocols == CLIENT_DEFAULT || protocols == SERVER_DEFAULT;
}
/**
@@ -123,6 +180,13 @@ final class ProtocolList {
static {
if (SunJSSE.isFIPS()) {
SUPPORTED = new ProtocolList(new String[] {
+ ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ SERVER_DEFAULT = SUPPORTED;
+ CLIENT_DEFAULT = new ProtocolList(new String[] {
ProtocolVersion.TLS10.name
});
} else {
@@ -130,6 +194,24 @@ final class ProtocolList {
ProtocolVersion.SSL20Hello.name,
ProtocolVersion.SSL30.name,
ProtocolVersion.TLS10.name,
+ ProtocolVersion.TLS11.name,
+ ProtocolVersion.TLS12.name
+ });
+
+ SERVER_DEFAULT = SUPPORTED;
+
+ /*
+ * RFC 5246 says that sending SSLv2 backward-compatible
+ * hello SHOULD NOT be done any longer.
+ *
+ * We are not enabling TLS 1.1/1.2 by default yet on clients
+ * out of concern for interop with existing
+ * SSLv3/TLS1.0-only servers. When these versions of TLS
+ * gain more traction, we'll enable them.
+ */
+ CLIENT_DEFAULT = new ProtocolList(new String[] {
+ ProtocolVersion.SSL30.name,
+ ProtocolVersion.TLS10.name
});
}
}
diff --git a/src/share/classes/sun/security/ssl/ProtocolVersion.java b/src/share/classes/sun/security/ssl/ProtocolVersion.java
index 8cda729a97a9f00ff5e0346eb9287adfc40351fc..77c102a62901b166161e0420751ed026658d4871 100644
--- a/src/share/classes/sun/security/ssl/ProtocolVersion.java
+++ b/src/share/classes/sun/security/ssl/ProtocolVersion.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2009, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,9 +45,15 @@ package sun.security.ssl;
* @author Andreas Sterbenz
* @since 1.4.1
*/
-public final class ProtocolVersion {
+public final class ProtocolVersion implements ComparableSSLEngine.
@@ -1394,6 +1534,15 @@ final public class SSLEngineImpl extends SSLEngine {
return sess;
}
+ @Override
+ synchronized public SSLSession getHandshakeSession() {
+ return handshakeSession;
+ }
+
+ synchronized void setHandshakeSession(SSLSessionImpl session) {
+ handshakeSession = session;
+ }
+
/**
* Returns a delegated Runnable task for
* this SSLEngine.
@@ -1495,6 +1644,9 @@ final public class SSLEngineImpl extends SSLEngine {
inboundDone = true;
sess.invalidate();
+ if (handshakeSession != null) {
+ handshakeSession.invalidate();
+ }
/*
* If we haven't even started handshaking yet, no need
@@ -1594,10 +1746,18 @@ final public class SSLEngineImpl extends SSLEngine {
* Emit alerts. Caller must have synchronized with "this".
*/
private void sendAlert(byte level, byte description) {
+ // the connectionState cannot be cs_START
if (connectionState >= cs_CLOSED) {
return;
}
+ // For initial handshaking, don't send alert message to peer if
+ // handshaker has not started.
+ if (connectionState == cs_HANDSHAKE &&
+ (handshaker == null || !handshaker.started())) {
+ return;
+ }
+
EngineOutputRecord r = new EngineOutputRecord(Record.ct_alert, this);
r.setVersion(protocolVersion);
@@ -1647,7 +1807,7 @@ final public class SSLEngineImpl extends SSLEngine {
synchronized public void setEnableSessionCreation(boolean flag) {
enableSessionCreation = flag;
- if ((handshaker != null) && !handshaker.started()) {
+ if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnableSessionCreation(enableSessionCreation);
}
}
@@ -1675,7 +1835,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
- !handshaker.started()) {
+ !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
}
}
@@ -1698,7 +1858,7 @@ final public class SSLEngineImpl extends SSLEngine {
if ((handshaker != null) &&
(handshaker instanceof ServerHandshaker) &&
- !handshaker.started()) {
+ !handshaker.activated()) {
((ServerHandshaker) handshaker).setClientAuth(doClientAuth);
}
}
@@ -1717,6 +1877,16 @@ final public class SSLEngineImpl extends SSLEngine {
switch (connectionState) {
case cs_START:
+ /*
+ * If we need to change the engine mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (roleIsServer != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
roleIsServer = !flag;
serverModeSet = true;
break;
@@ -1730,7 +1900,17 @@ final public class SSLEngineImpl extends SSLEngine {
* have the streams.
*/
assert(handshaker != null);
- if (!handshaker.started()) {
+ if (!handshaker.activated()) {
+ /*
+ * If we need to change the engine mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (roleIsServer != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
roleIsServer = !flag;
connectionState = cs_START;
initHandshaker();
@@ -1786,8 +1966,8 @@ final public class SSLEngineImpl extends SSLEngine {
*/
synchronized public void setEnabledCipherSuites(String[] suites) {
enabledCipherSuites = new CipherSuiteList(suites);
- if ((handshaker != null) && !handshaker.started()) {
- handshaker.enabledCipherSuites = enabledCipherSuites;
+ if ((handshaker != null) && !handshaker.activated()) {
+ handshaker.setEnabledCipherSuites(enabledCipherSuites);
}
}
@@ -1809,7 +1989,7 @@ final public class SSLEngineImpl extends SSLEngine {
/**
* Returns the protocols that are supported by this implementation.
* A subset of the supported protocols may be enabled for this connection
- * @ returns an array of protocol names.
+ * @return an array of protocol names.
*/
public String[] getSupportedProtocols() {
return ProtocolList.getSupported().toStringArray();
@@ -1826,7 +2006,7 @@ final public class SSLEngineImpl extends SSLEngine {
*/
synchronized public void setEnabledProtocols(String[] protocols) {
enabledProtocols = new ProtocolList(protocols);
- if ((handshaker != null) && !handshaker.started()) {
+ if ((handshaker != null) && !handshaker.activated()) {
handshaker.setEnabledProtocols(enabledProtocols);
}
}
@@ -1836,28 +2016,31 @@ final public class SSLEngineImpl extends SSLEngine {
}
/**
- * Try to configure the endpoint identification algorithm of the engine.
- *
- * @param identificationAlgorithm the algorithm used to check the
- * endpoint identity.
- * @return true if the identification algorithm configuration success.
+ * Returns the SSLParameters in effect for this SSLEngine.
*/
- synchronized public boolean trySetHostnameVerification(
- String identificationAlgorithm) {
- if (sslContext.getX509TrustManager() instanceof
- X509ExtendedTrustManager) {
- this.identificationAlg = identificationAlgorithm;
- return true;
- } else {
- return false;
- }
+ synchronized public SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+
+ // the super implementation does not handle the following parameters
+ params.setEndpointIdentificationAlgorithm(identificationProtocol);
+ params.setAlgorithmConstraints(algorithmConstraints);
+
+ return params;
}
/**
- * Returns the endpoint identification algorithm of the engine.
+ * Applies SSLParameters to this engine.
*/
- synchronized public String getHostnameVerification() {
- return identificationAlg;
+ synchronized public void setSSLParameters(SSLParameters params) {
+ super.setSSLParameters(params);
+
+ // the super implementation does not handle the following parameters
+ identificationProtocol = params.getEndpointIdentificationAlgorithm();
+ algorithmConstraints = params.getAlgorithmConstraints();
+ if ((handshaker != null) && !handshaker.started()) {
+ handshaker.setIdentificationProtocol(identificationProtocol);
+ handshaker.setAlgorithmConstraints(algorithmConstraints);
+ }
}
/**
diff --git a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
index 914406b2e4281d1672c8ca8a663801b8e74b4297..0ea3cfa9fbad805ca31047132bbc12405ddc32bb 100644
--- a/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
+++ b/src/share/classes/sun/security/ssl/SSLServerSocketImpl.java
@@ -31,11 +31,14 @@ import java.net.InetAddress;
import java.net.Socket;
import java.net.ServerSocket;
+import java.security.AlgorithmConstraints;
+
import java.util.*;
import javax.net.ServerSocketFactory;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLParameters;
/**
@@ -83,6 +86,12 @@ class SSLServerSocketImpl extends SSLServerSocket
/* could enabledCipherSuites ever complete handshaking? */
private boolean checkedEnabled = false;
+ // the endpoint identification protocol to use by default
+ private String identificationProtocol = null;
+
+ // The cryptographic algorithm constraints
+ private AlgorithmConstraints algorithmConstraints = null;
+
/**
* Create an SSL server socket on a port, using a non-default
* authentication context and a specified connection backlog.
@@ -145,7 +154,7 @@ class SSLServerSocketImpl extends SSLServerSocket
}
sslContext = context;
enabledCipherSuites = CipherSuiteList.getDefault();
- enabledProtocols = ProtocolList.getDefault();
+ enabledProtocols = ProtocolList.getDefault(true);
}
/**
@@ -238,6 +247,16 @@ class SSLServerSocketImpl extends SSLServerSocket
* rejoining the already-negotiated SSL connection.
*/
public void setUseClientMode(boolean flag) {
+ /*
+ * If we need to change the socket mode and the enabled
+ * protocols haven't specifically been set by the user,
+ * change them to the corresponding default ones.
+ */
+ if (useServerMode != (!flag) &&
+ ProtocolList.isDefaultProtocolList(enabledProtocols)) {
+ enabledProtocols = ProtocolList.getDefault(!flag);
+ }
+
useServerMode = !flag;
}
@@ -262,6 +281,29 @@ class SSLServerSocketImpl extends SSLServerSocket
return enableSessionCreation;
}
+ /**
+ * Returns the SSLParameters in effect for newly accepted connections.
+ */
+ synchronized public SSLParameters getSSLParameters() {
+ SSLParameters params = super.getSSLParameters();
+
+ // the super implementation does not handle the following parameters
+ params.setEndpointIdentificationAlgorithm(identificationProtocol);
+ params.setAlgorithmConstraints(algorithmConstraints);
+
+ return params;
+ }
+
+ /**
+ * Applies SSLParameters to newly accepted connections.
+ */
+ synchronized public void setSSLParameters(SSLParameters params) {
+ super.setSSLParameters(params);
+
+ // the super implementation does not handle the following parameters
+ identificationProtocol = params.getEndpointIdentificationAlgorithm();
+ algorithmConstraints = params.getAlgorithmConstraints();
+ }
/**
* Accept a new SSL connection. This server identifies itself with
@@ -269,67 +311,15 @@ class SSLServerSocketImpl extends SSLServerSocket
* presented during construction.
*/
public Socket accept() throws IOException {
- checkEnabledSuites();
-
SSLSocketImpl s = new SSLSocketImpl(sslContext, useServerMode,
enabledCipherSuites, doClientAuth, enableSessionCreation,
- enabledProtocols);
+ enabledProtocols, identificationProtocol, algorithmConstraints);
implAccept(s);
s.doneConnect();
return s;
}
-
- /*
- * This is a sometimes helpful diagnostic check that is performed
- * once for each ServerSocket to verify that the initial set of
- * enabled suites are capable of supporting a successful handshake.
- */
- private void checkEnabledSuites() throws IOException {
- //
- // We want to report an error if no cipher suites were actually
- // enabled, since this is an error users are known to make. Then
- // they get vastly confused by having clients report an error!
- //
- synchronized (this) {
- if (checkedEnabled) {
- return;
- }
- if (useServerMode == false) {
- return;
- }
-
- SSLSocketImpl tmp = new SSLSocketImpl(sslContext, useServerMode,
- enabledCipherSuites, doClientAuth,
- enableSessionCreation, enabledProtocols);
-
- try {
- ServerHandshaker handshaker = tmp.getServerHandshaker();
-
- for (Iterator