--- a/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
c5d39b6be65cba0effb5f466ea48fe43764d0e0c jdk7-b71
df4bcd06e1d0ab306efa5a44f24a409dc0c0c742 jdk7-b72
ce74bd35ce948d629a356e168797f44b593b1578 jdk7-b73
+4e7661eaa211e186674f6cbefec4aef1144ac2a0 jdk7-b74
--- a/.hgtags-top-repo Fri Oct 23 18:44:33 2009 -0700
+++ b/.hgtags-top-repo Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
4c36e9853dda27bdac5ef4839a610509fbe31d34 jdk7-b71
0d7e03b426df27c21dcc44ffb9178eacd1b04f10 jdk7-b72
3ac6dcf7823205546fbbc3d4ea59f37358d0b0d4 jdk7-b73
+2c88089b6e1c053597418099a14232182c387edc jdk7-b74
--- a/corba/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/corba/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
3f1ef7f899ea2aec189c4fb67e5c8fa374437c50 jdk7-b71
c793a31209263fbb867c23c752599d85c21abb73 jdk7-b72
b751c528c55560cf2adeaeef24b39ca1f4d1cbf7 jdk7-b73
+5d0cf59a3203b9f57aceebc33ae656b884987955 jdk7-b74
--- a/hotspot/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/hotspot/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
50a95aa4a247f0cbbf66df285a8b1d78ffb153d9 jdk7-b71
a94714c550658fd6741793ef036cb9625dc2ab1a jdk7-b72
faf94d94786b621f8e13cbcc941ca69c6d967c3f jdk7-b73
+f4b900403d6e4b0af51447bd13bbe23fe3a1dac7 jdk7-b74
--- a/hotspot/make/hotspot_version Fri Oct 23 18:44:33 2009 -0700
+++ b/hotspot/make/hotspot_version Wed Oct 28 10:37:17 2009 -0700
@@ -35,7 +35,7 @@
HS_MAJOR_VER=17
HS_MINOR_VER=0
-HS_BUILD_NUMBER=03
+HS_BUILD_NUMBER=04
JDK_MAJOR_VER=1
JDK_MINOR_VER=7
--- a/jaxp/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/jaxp/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
ff94d8ce0daded647bb326630e643d010357afce jdk7-b71
37c805b6156fd492c12301688b54a6bcca39e729 jdk7-b72
feb05980f9f2964e6bc2b3a8532f9b3054c2289b jdk7-b73
+ea7b88c676dd8b269bc858a4a17c14dc96c8aed1 jdk7-b74
--- a/jaxws/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/jaxws/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
03314cf56a7212bbb6c186dbc9f15aca988a48ec jdk7-b71
4c990aa99bc037fd81dd1b1b269690e9bea8a0b4 jdk7-b72
558985e26fe16f5a6ebb2edb9180a42e1c8e8202 jdk7-b73
+f4466e1b608088c90e11beaa4b600f102608c6a1 jdk7-b74
--- a/jdk/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
b3f3240135f0c10b9f2481c174b81b7fcf0daa60 jdk7-b71
460639b036f327282832a4fe52b7aa45688afd50 jdk7-b72
f708138c9aca4b389872838fe6773872fce3609e jdk7-b73
+eacb36e30327e7ae33baa068e82ddccbd91eaae2 jdk7-b74
--- a/jdk/make/common/shared/Defs-java.gmk Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/make/common/shared/Defs-java.gmk Wed Oct 28 10:37:17 2009 -0700
@@ -165,11 +165,6 @@
JAVADOC_CMD = $(JAVA_TOOLS_DIR)/javadoc $(JAVA_TOOLS_FLAGS:%=-J%)
endif
-#always use the bootstrap javah until bug-ID 6889255 is fixed. These
-#five lines should be removed as part of that fix:
-JAVAH_CMD = $(JAVA_TOOLS_DIR)/javah \
- $(JAVAHFLAGS)
-
# Override of what javac to use (see deploy workspace)
ifdef JAVAC
JAVAC_CMD = $(JAVAC)
--- a/jdk/make/java/java/FILES_java.gmk Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/make/java/java/FILES_java.gmk Wed Oct 28 10:37:17 2009 -0700
@@ -258,6 +258,7 @@
java/util/ServiceConfigurationError.java \
java/util/Timer.java \
java/util/TimerTask.java \
+ java/util/Objects.java \
java/util/UUID.java \
java/util/concurrent/AbstractExecutorService.java \
java/util/concurrent/ArrayBlockingQueue.java \
--- a/jdk/make/java/redist/Makefile Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/make/java/redist/Makefile Wed Oct 28 10:37:17 2009 -0700
@@ -211,7 +211,7 @@
$(LIB_LOCATION)/$(KERNEL_LOCATION)/$(JVM_NAME): $(HOTSPOT_KERNEL_PATH)/$(JVM_NAME)
$(install-file)
-$(LIB_LOCATION)/$(LIBJSIG_NAME): $(HOTSPOT_SERVER_PATH)/$(LIBJSIG_NAME)
+$(LIB_LOCATION)/$(LIBJSIG_NAME): $(HOTSPOT_IMPORT_PATH)/$(ARCH_VM_SUBDIR)/$(LIBJSIG_NAME)
$(install-import-file)
$(LIB_LOCATION)/$(CLIENT_LOCATION)/$(LIBJSIG_NAME) \
--- a/jdk/src/share/classes/com/sun/naming/internal/ResourceManager.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/com/sun/naming/internal/ResourceManager.java Wed Oct 28 10:37:17 2009 -0700
@@ -25,11 +25,12 @@
package com.sun.naming.internal;
-import java.applet.Applet;
import java.io.InputStream;
import java.io.IOException;
import java.net.URL;
import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
@@ -112,6 +113,52 @@
private static final WeakHashMap urlFactoryCache = new WeakHashMap(11);
private static final WeakReference NO_FACTORY = new WeakReference(null);
+ /**
+ * A class to allow JNDI properties be specified as applet parameters
+ * without creating a static dependency on java.applet.
+ */
+ private static class AppletParameter {
+ private static final Class<?> clazz = getClass("java.applet.Applet");
+ private static final Method getMethod =
+ getMethod(clazz, "getParameter", String.class);
+ private static Class<?> getClass(String name) {
+ try {
+ return Class.forName(name, true, null);
+ } catch (ClassNotFoundException e) {
+ return null;
+ }
+ }
+ private static Method getMethod(Class<?> clazz,
+ String name,
+ Class<?>... paramTypes)
+ {
+ if (clazz != null) {
+ try {
+ return clazz.getMethod(name, paramTypes);
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Returns the value of the applet's named parameter.
+ */
+ static Object get(Object applet, String name) {
+ // if clazz is null then applet cannot be an Applet.
+ if (clazz == null || !clazz.isInstance(applet))
+ throw new ClassCastException(applet.getClass().getName());
+ try {
+ return getMethod.invoke(applet, name);
+ } catch (InvocationTargetException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException iae) {
+ throw new AssertionError(iae);
+ }
+ }
+ }
// There should be no instances of this class.
private ResourceManager() {
@@ -143,7 +190,7 @@
if (env == null) {
env = new Hashtable(11);
}
- Applet applet = (Applet)env.get(Context.APPLET);
+ Object applet = env.get(Context.APPLET);
// Merge property values from env param, applet params, and system
// properties. The first value wins: there's no concatenation of
@@ -157,7 +204,7 @@
Object val = env.get(props[i]);
if (val == null) {
if (applet != null) {
- val = applet.getParameter(props[i]);
+ val = AppletParameter.get(applet, props[i]);
}
if (val == null) {
// Read system property.
--- a/jdk/src/share/classes/java/io/FilePermission.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/java/io/FilePermission.java Wed Oct 28 10:37:17 2009 -0700
@@ -209,7 +209,17 @@
cpath = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
try {
- return sun.security.provider.PolicyFile.canonPath(cpath);
+ String path = cpath;
+ if (cpath.endsWith("*")) {
+ // call getCanonicalPath with a path with wildcard character
+ // replaced to avoid calling it with paths that are
+ // intended to match all entries in a directory
+ path = path.substring(0, path.length()-1) + "-";
+ path = new File(path).getCanonicalPath();
+ return path.substring(0, path.length()-1) + "*";
+ } else {
+ return new File(path).getCanonicalPath();
+ }
} catch (IOException ioe) {
return cpath;
}
--- a/jdk/src/share/classes/java/lang/Enum.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Enum.java Wed Oct 28 10:37:17 2009 -0700
@@ -40,10 +40,17 @@
* Edition</i>, <a
* href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9">§8.9</a>.
*
+ * <p> Note that when using an enumeration type as the type of a set
+ * or as the type of the keys in a map, specialized and efficient
+ * {@linkplain java.util.EnumSet set} and {@linkplain
+ * java.util.EnumMap map} implementations are available.
+ *
* @param <E> The enum type subclass
* @author Josh Bloch
* @author Neal Gafter
* @see Class#getEnumConstants()
+ * @see java.util.EnumSet
+ * @see java.util.EnumMap
* @since 1.5
*/
public abstract class Enum<E extends Enum<E>>
--- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java Wed Oct 28 10:37:17 2009 -0700
@@ -44,6 +44,8 @@
* as Java Object Serialization or other persistence mechanisms, to
* manipulate objects in a manner that would normally be prohibited.
*
+ * <p>By default, a reflected object is <em>not</em> accessible.
+ *
* @see Field
* @see Method
* @see Constructor
--- a/jdk/src/share/classes/java/nio/file/Path.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/java/nio/file/Path.java Wed Oct 28 10:37:17 2009 -0700
@@ -412,7 +412,7 @@
* dependent if {@code "a/b/../x"} would locate the same file as {@code "/a/x"}.
*
* @param other
- * the resulting path
+ * the path to relativize against this path
*
* @return the resulting relative path, or {@code null} if both paths are
* equal
@@ -1615,23 +1615,23 @@
* Tests if the file referenced by this object is the same file referenced
* by another object.
*
- * <p> If this {@code FileRef} and the given {@code FileRef} are {@link
+ * <p> If this {@code Path} and the given {@code Path} are {@link
* #equals(Object) equal} then this method returns {@code true} without checking
- * if the file exists. If the {@code FileRef} and the given {@code FileRef}
- * are associated with different providers, or the given {@code FileRef} is
+ * if the file exists. If the {@code Path} and the given {@code Path}
+ * are associated with different providers, or the given {@code Path} is
* {@code null} then this method returns {@code false}. Otherwise, this method
- * checks if both {@code FileRefs} locate the same file, and depending on the
+ * checks if both {@code Paths} locate the same file, and depending on the
* implementation, may require to open or access both files.
*
* <p> If the file system and files remain static, then this method implements
- * an equivalence relation for non-null {@code FileRefs}.
+ * an equivalence relation for non-null {@code Paths}.
* <ul>
- * <li>It is <i>reflexive</i>: for a non-null {@code FileRef} {@code f},
+ * <li>It is <i>reflexive</i>: for a non-null {@code Path} {@code f},
* {@code f.isSameFile(f)} should return {@code true}.
- * <li>It is <i>symmetric</i>: for two non-null {@code FileRefs}
+ * <li>It is <i>symmetric</i>: for two non-null {@code Path}
* {@code f} and {@code g}, {@code f.isSameFile(g)} will equal
* {@code g.isSameFile(f)}.
- * <li>It is <i>transitive</i>: for three {@code FileRefs}
+ * <li>It is <i>transitive</i>: for three {@code Paths}
* {@code f}, {@code g}, and {@code h}, if {@code f.isSameFile(g)} returns
* {@code true} and {@code g.isSameFile(h)} returns {@code true}, then
* {@code f.isSameFile(h)} will return return {@code true}.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/Objects.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package java.util;
+
+/**
+ * This class consists of {@code static} utility methods for operating
+ * on objects. These utilities include {@code null}-safe or {@code
+ * null}-tolerant methods for computing the hash code of an object,
+ * returning a string for an object, and comparing two objects.
+ *
+ * @since 1.7
+ */
+public class Objects {
+ private Objects() {
+ throw new AssertionError("No java.util.Objects instances for you!");
+ }
+
+ /**
+ * Returns {@code true} if the arguments are equal to each other
+ * and {@code false} otherwise.
+ * Consequently, if both arguments are {@code null}, {@code true}
+ * is returned and if exactly one argument is {@code null}, {@code
+ * false} is returned. Otherwise, equality is determined by using
+ * the {@link Object#equals equals} method of the first
+ * argument.
+ *
+ * @param a an object
+ * @param b an object to be compared with {@code a} for equality
+ * @return {@code true} if the arguments are equal to each other
+ * and {@code false} otherwise
+ * @see Object#equals(Object)
+ */
+ public static boolean equals(Object a, Object b) {
+ return (a == b) || (a != null && a.equals(b));
+ }
+
+ /**
+ * Returns the hash code of a non-{@code null} argument and 0 for
+ * a {@code null} argument.
+ *
+ * @param o an object
+ * @return the hash code of a non-{@code null} argument and 0 for
+ * a {@code null} argument
+ * @see Object#hashCode
+ */
+ public static int hashCode(Object o) {
+ return o != null ? o.hashCode() : 0;
+ }
+
+ /**
+ * Returns the result of calling {@code toString} for a non-{@code
+ * null} argument and {@code "null"} for a {@code null} argument.
+ *
+ * @param o an object
+ * @return the result of calling {@code toString} for a non-{@code
+ * null} argument and {@code "null"} for a {@code null} argument
+ * @see Object#toString
+ * @see String#valueOf(Object)
+ */
+ public static String toString(Object o) {
+ return String.valueOf(o);
+ }
+
+ /**
+ * Returns 0 if the arguments are identical and {@code
+ * c.compare(a, b)} otherwise.
+ * Consequently, if both arguments are {@code null} 0
+ * is returned.
+ *
+ * <p>Note that if one of the arguments is {@code null}, a {@code
+ * NullPointerException} may or may not be thrown depending on
+ * what ordering policy, if any, the {@link Comparator Comparator}
+ * chooses to have for {@code null} values.
+ *
+ * @param <T> the type of the objects being compared
+ * @param a an object
+ * @param b an object to be compared with {@code a}
+ * @param c the {@code Comparator} to compare the first two arguments
+ * @return 0 if the arguments are identical and {@code
+ * c.compare(a, b)} otherwise.
+ * @see Comparable
+ * @see Comparator
+ */
+ public static <T> int compare(T a, T b, Comparator<? super T> c) {
+ return (a == b) ? 0 : c.compare(a, b);
+ }
+
+ /**
+ * Checks that the specified object reference is not {@code null}. This
+ * method is designed primarily for doing parameter validation in methods
+ * and constructors, as demonstrated below:
+ * <blockquote><pre>
+ * public Foo(Bar bar) {
+ * this.bar = Objects.nonNull(bar);
+ * }
+ * </pre></blockquote>
+ *
+ * @param obj the object reference to check for nullity
+ * @param <T> the type of the reference
+ * @return {@code obj} if not {@code null}
+ * @throws NullPointerException if {@code obj} is {@code null}
+ */
+ public static <T> T nonNull(T obj) {
+ if (obj == null)
+ throw new NullPointerException();
+ return obj;
+ }
+
+ /**
+ * Checks that the specified object reference is not {@code null} and
+ * throws a customized {@link NullPointerException} if it is. This method
+ * is designed primarily for doing parameter validation in methods and
+ * constructors with multiple parameters, as demonstrated below:
+ * <blockquote><pre>
+ * public Foo(Bar bar, Baz baz) {
+ * this.bar = Objects.nonNull(bar, "bar must not be null");
+ * this.baz = Objects.nonNull(baz, "baz must not be null");
+ * }
+ * </pre></blockquote>
+ *
+ * @param obj the object reference to check for nullity
+ * @param message detail message to be used in the event that a {@code
+ * NullPointerException} is thrown
+ * @param <T> the type of the reference
+ * @return {@code obj} if not {@code null}
+ * @throws NullPointerException if {@code obj} is {@code null}
+ */
+ public static <T> T nonNull(T obj, String message) {
+ if (obj == null)
+ throw new NullPointerException(message);
+ return obj;
+ }
+}
--- a/jdk/src/share/classes/java/util/jar/JarVerifier.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java Wed Oct 28 10:37:17 2009 -0700
@@ -293,10 +293,8 @@
}
sfv.process(sigFileSigners);
- } catch (sun.security.pkcs.ParsingException pe) {
- if (debug != null) debug.println("processEntry caught: "+pe);
- // ignore and treat as unsigned
} catch (IOException ioe) {
+ // e.g. sun.security.pkcs.ParsingException
if (debug != null) debug.println("processEntry caught: "+ioe);
// ignore and treat as unsigned
} catch (SignatureException se) {
--- a/jdk/src/share/classes/sun/misc/FloatingDecimal.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java Wed Oct 28 10:37:17 2009 -0700
@@ -730,7 +730,7 @@
* Thus we will need more than one digit if we're using
* E-form
*/
- if ( decExp <= -3 || decExp >= 8 ){
+ if ( decExp < -3 || decExp >= 8 ){
high = low = false;
}
while( ! low && ! high ){
@@ -783,7 +783,7 @@
* Thus we will need more than one digit if we're using
* E-form
*/
- if ( decExp <= -3 || decExp >= 8 ){
+ if ( decExp < -3 || decExp >= 8 ){
high = low = false;
}
while( ! low && ! high ){
@@ -847,7 +847,7 @@
* Thus we will need more than one digit if we're using
* E-form
*/
- if ( decExp <= -3 || decExp >= 8 ){
+ if ( decExp < -3 || decExp >= 8 ){
high = low = false;
}
while( ! low && ! high ){
--- a/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java Wed Oct 28 10:37:17 2009 -0700
@@ -31,6 +31,7 @@
import java.net.*;
import javax.net.ssl.*;
import java.util.*;
+import java.util.logging.Logger;
import java.text.*;
import sun.net.www.MessageHeader;
import com.sun.net.httpserver.*;
@@ -204,6 +205,21 @@
tmpout.write (bytes(statusLine, 0), 0, statusLine.length());
boolean noContentToSend = false; // assume there is content
rspHdrs.set ("Date", df.format (new Date()));
+
+ /* check for response type that is not allowed to send a body */
+
+ if ((rCode>=100 && rCode <200) /* informational */
+ ||(rCode == 204) /* no content */
+ ||(rCode == 304)) /* not modified */
+ {
+ if (contentLen != -1) {
+ Logger logger = server.getLogger();
+ String msg = "sendResponseHeaders: rCode = "+ rCode
+ + ": forcing contentLen = -1";
+ logger.warning (msg);
+ }
+ contentLen = -1;
+ }
if (contentLen == 0) {
if (http10) {
o.setWrappedStream (new UndefLengthOutputStream (this, ros));
--- a/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java Wed Oct 28 10:37:17 2009 -0700
@@ -1180,6 +1180,10 @@
inputStream = http.getInputStream();
respCode = getResponseCode();
+ if (respCode == -1) {
+ disconnectInternal();
+ throw new IOException ("Invalid Http response");
+ }
if (respCode == HTTP_PROXY_AUTH) {
if (streaming()) {
disconnectInternal();
--- a/jdk/src/share/classes/sun/security/provider/PolicyFile.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/PolicyFile.java Wed Oct 28 10:37:17 2009 -0700
@@ -1832,8 +1832,9 @@
return canonCs;
}
- // public for java.io.FilePermission
- public static String canonPath(String path) throws IOException {
+ // Wrapper to return a canonical path that avoids calling getCanonicalPath()
+ // with paths that are intended to match all entries in the directory
+ private static String canonPath(String path) throws IOException {
if (path.endsWith("*")) {
path = path.substring(0, path.length()-1) + "-";
path = new File(path).getCanonicalPath();
--- a/jdk/src/share/classes/sun/security/provider/SunEntries.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java Wed Oct 28 10:37:17 2009 -0700
@@ -210,7 +210,7 @@
* CertStores
*/
map.put("CertStore.LDAP",
- "sun.security.provider.certpath.LDAPCertStore");
+ "sun.security.provider.certpath.ldap.LDAPCertStore");
map.put("CertStore.LDAP LDAPSchema", "RFC2587");
map.put("CertStore.Collection",
"sun.security.provider.certpath.CollectionCertStore");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/CertStoreHelper.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.provider.certpath;
+
+import java.net.URI;
+import java.util.Collection;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertStore;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509CRLSelector;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+
+/**
+ * Helper used by URICertStore when delegating to another CertStore to
+ * fetch certs and CRLs.
+ */
+
+public interface CertStoreHelper {
+
+ /**
+ * Returns a CertStore using the given URI as parameters.
+ */
+ CertStore getCertStore(URI uri)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException;
+
+ /**
+ * Wraps an existing X509CertSelector when needing to avoid DN matching
+ * issues.
+ */
+ X509CertSelector wrap(X509CertSelector selector,
+ X500Principal certSubject,
+ String dn)
+ throws IOException;
+
+ /**
+ * Wraps an existing X509CRLSelector when needing to avoid DN matching
+ * issues.
+ */
+ X509CRLSelector wrap(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers,
+ String dn)
+ throws IOException;
+}
--- a/jdk/src/share/classes/sun/security/provider/certpath/LDAPCertStore.java Fri Oct 23 18:44:33 2009 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,1065 +0,0 @@
-/*
- * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URI;
-import java.util.*;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NameNotFoundException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-import java.security.*;
-import java.security.cert.Certificate;
-import java.security.cert.*;
-import javax.security.auth.x500.X500Principal;
-
-import sun.misc.HexDumpEncoder;
-import sun.security.util.Cache;
-import sun.security.util.Debug;
-import sun.security.x509.X500Name;
-import sun.security.action.GetPropertyAction;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
- * (RFC 2587):
- * <a href="http://www.ietf.org/rfc/rfc2587.txt">
- * http://www.ietf.org/rfc/rfc2587.txt</a>.
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #LDAPCertStore(CertStoreParameters)
- * LDAPCertStore(CertStoreParameters)} constructor is called to create the
- * <code>CertStore</code> and establish the DNS name and port of the LDAP
- * server from which <code>Certificate</code>s and <code>CRL</code>s will be
- * retrieved.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>LDAPCertStore</code> object
- * (or more than one) with no ill effects. This allows a
- * <code>CertPathBuilder</code> to search for a CRL while simultaneously
- * searching for further certificates, for instance.
- * <p>
- * This is achieved by adding the <code>synchronized</code> keyword to the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
- * <p>
- * This classes uses caching and requests multiple attributes at once to
- * minimize LDAP round trips. The cache is associated with the CertStore
- * instance. It uses soft references to hold the values to minimize impact
- * on footprint and currently has a maximum size of 750 attributes and a
- * 30 second default lifetime.
- * <p>
- * We always request CA certificates, cross certificate pairs, and ARLs in
- * a single LDAP request when any one of them is needed. The reason is that
- * we typically need all of them anyway and requesting them in one go can
- * reduce the number of requests to a third. Even if we don't need them,
- * these attributes are typically small enough not to cause a noticeable
- * overhead. In addition, when the prefetchCRLs flag is true, we also request
- * the full CRLs. It is currently false initially but set to true once any
- * request for an ARL to the server returns an null value. The reason is
- * that CRLs could be rather large but are rarely used. This implementation
- * should improve performance in most cases.
- *
- * @see java.security.cert.CertStore
- *
- * @since 1.4
- * @author Steve Hanna
- * @author Andreas Sterbenz
- */
-public class LDAPCertStore extends CertStoreSpi {
-
- private static final Debug debug = Debug.getInstance("certpath");
-
- private final static boolean DEBUG = false;
-
- /**
- * LDAP attribute identifiers.
- */
- private static final String USER_CERT = "userCertificate;binary";
- private static final String CA_CERT = "cACertificate;binary";
- private static final String CROSS_CERT = "crossCertificatePair;binary";
- private static final String CRL = "certificateRevocationList;binary";
- private static final String ARL = "authorityRevocationList;binary";
- private static final String DELTA_CRL = "deltaRevocationList;binary";
-
- // Constants for various empty values
- private final static String[] STRING0 = new String[0];
-
- private final static byte[][] BB0 = new byte[0][];
-
- private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
-
- // cache related constants
- private final static int DEFAULT_CACHE_SIZE = 750;
- private final static int DEFAULT_CACHE_LIFETIME = 30;
-
- private final static int LIFETIME;
-
- private final static String PROP_LIFETIME =
- "sun.security.certpath.ldap.cache.lifetime";
-
- static {
- String s = AccessController.doPrivileged(
- new GetPropertyAction(PROP_LIFETIME));
- if (s != null) {
- LIFETIME = Integer.parseInt(s); // throws NumberFormatException
- } else {
- LIFETIME = DEFAULT_CACHE_LIFETIME;
- }
- }
-
- /**
- * The CertificateFactory used to decode certificates from
- * their binary stored form.
- */
- private CertificateFactory cf;
- /**
- * The JNDI directory context.
- */
- private DirContext ctx;
-
- /**
- * Flag indicating whether we should prefetch CRLs.
- */
- private boolean prefetchCRLs = false;
-
- private final Cache valueCache;
-
- private int cacheHits = 0;
- private int cacheMisses = 0;
- private int requests = 0;
-
- /**
- * Creates a <code>CertStore</code> with the specified parameters.
- * For this class, the parameters object must be an instance of
- * <code>LDAPCertStoreParameters</code>.
- *
- * @param params the algorithm parameters
- * @exception InvalidAlgorithmParameterException if params is not an
- * instance of <code>LDAPCertStoreParameters</code>
- */
- public LDAPCertStore(CertStoreParameters params)
- throws InvalidAlgorithmParameterException {
- super(params);
- if (!(params instanceof LDAPCertStoreParameters))
- throw new InvalidAlgorithmParameterException(
- "parameters must be LDAPCertStoreParameters");
-
- LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
-
- // Create InitialDirContext needed to communicate with the server
- createInitialDirContext(lparams.getServerName(), lparams.getPort());
-
- // Create CertificateFactory for use later on
- try {
- cf = CertificateFactory.getInstance("X.509");
- } catch (CertificateException e) {
- throw new InvalidAlgorithmParameterException(
- "unable to create CertificateFactory for X.509");
- }
- if (LIFETIME == 0) {
- valueCache = Cache.newNullCache();
- } else if (LIFETIME < 0) {
- valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
- } else {
- valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
- }
- }
-
- /**
- * Returns an LDAP CertStore. This method consults a cache of
- * CertStores (shared per JVM) using the LDAP server/port as a key.
- */
- private static final Cache certStoreCache = Cache.newSoftMemoryCache(185);
- static synchronized CertStore getInstance(LDAPCertStoreParameters params)
- throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
- CertStore lcs = (CertStore) certStoreCache.get(params);
- if (lcs == null) {
- lcs = CertStore.getInstance("LDAP", params);
- certStoreCache.put(params, lcs);
- } else {
- if (debug != null) {
- debug.println("LDAPCertStore.getInstance: cache hit");
- }
- }
- return lcs;
- }
-
- /**
- * Create InitialDirContext.
- *
- * @param server Server DNS name hosting LDAP service
- * @param port Port at which server listens for requests
- * @throws InvalidAlgorithmParameterException if creation fails
- */
- private void createInitialDirContext(String server, int port)
- throws InvalidAlgorithmParameterException {
- String url = "ldap://" + server + ":" + port;
- Hashtable<String,Object> env = new Hashtable<String,Object>();
- env.put(Context.INITIAL_CONTEXT_FACTORY,
- "com.sun.jndi.ldap.LdapCtxFactory");
- env.put(Context.PROVIDER_URL, url);
- try {
- ctx = new InitialDirContext(env);
- /*
- * By default, follow referrals unless application has
- * overridden property in an application resource file.
- */
- Hashtable<?,?> currentEnv = ctx.getEnvironment();
- if (currentEnv.get(Context.REFERRAL) == null) {
- ctx.addToEnvironment(Context.REFERRAL, "follow");
- }
- } catch (NamingException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineInit about to throw "
- + "InvalidAlgorithmParameterException");
- e.printStackTrace();
- }
- Exception ee = new InvalidAlgorithmParameterException
- ("unable to create InitialDirContext using supplied parameters");
- ee.initCause(e);
- throw (InvalidAlgorithmParameterException)ee;
- }
- }
-
- /**
- * Private class encapsulating the actual LDAP operations and cache
- * handling. Use:
- *
- * LDAPRequest request = new LDAPRequest(dn);
- * request.addRequestedAttribute(CROSS_CERT);
- * request.addRequestedAttribute(CA_CERT);
- * byte[][] crossValues = request.getValues(CROSS_CERT);
- * byte[][] caValues = request.getValues(CA_CERT);
- *
- * At most one LDAP request is sent for each instance created. If all
- * getValues() calls can be satisfied from the cache, no request
- * is sent at all. If a request is sent, all requested attributes
- * are always added to the cache irrespective of whether the getValues()
- * method is called.
- */
- private class LDAPRequest {
-
- private final String name;
- private Map<String, byte[][]> valueMap;
- private final List<String> requestedAttributes;
-
- LDAPRequest(String name) {
- this.name = name;
- requestedAttributes = new ArrayList<String>(5);
- }
-
- String getName() {
- return name;
- }
-
- void addRequestedAttribute(String attrId) {
- if (valueMap != null) {
- throw new IllegalStateException("Request already sent");
- }
- requestedAttributes.add(attrId);
- }
-
- /**
- * Gets one or more binary values from an attribute.
- *
- * @param name the location holding the attribute
- * @param attrId the attribute identifier
- * @return an array of binary values (byte arrays)
- * @throws NamingException if a naming exception occurs
- */
- byte[][] getValues(String attrId) throws NamingException {
- if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
- System.out.println("Cache hits: " + cacheHits + "; misses: "
- + cacheMisses);
- }
- String cacheKey = name + "|" + attrId;
- byte[][] values = (byte[][])valueCache.get(cacheKey);
- if (values != null) {
- cacheHits++;
- return values;
- }
- cacheMisses++;
- Map<String, byte[][]> attrs = getValueMap();
- values = attrs.get(attrId);
- return values;
- }
-
- /**
- * Get a map containing the values for this request. The first time
- * this method is called on an object, the LDAP request is sent,
- * the results parsed and added to a private map and also to the
- * cache of this LDAPCertStore. Subsequent calls return the private
- * map immediately.
- *
- * The map contains an entry for each requested attribute. The
- * attribute name is the key, values are byte[][]. If there are no
- * values for that attribute, values are byte[0][].
- *
- * @return the value Map
- * @throws NamingException if a naming exception occurs
- */
- private Map<String, byte[][]> getValueMap() throws NamingException {
- if (valueMap != null) {
- return valueMap;
- }
- if (DEBUG) {
- System.out.println("Request: " + name + ":" + requestedAttributes);
- requests++;
- if (requests % 5 == 0) {
- System.out.println("LDAP requests: " + requests);
- }
- }
- valueMap = new HashMap<String, byte[][]>(8);
- String[] attrIds = requestedAttributes.toArray(STRING0);
- Attributes attrs;
- try {
- attrs = ctx.getAttributes(name, attrIds);
- } catch (NameNotFoundException e) {
- // name does not exist on this LDAP server
- // treat same as not attributes found
- attrs = EMPTY_ATTRIBUTES;
- }
- for (String attrId : requestedAttributes) {
- Attribute attr = attrs.get(attrId);
- byte[][] values = getAttributeValues(attr);
- cacheAttribute(attrId, values);
- valueMap.put(attrId, values);
- }
- return valueMap;
- }
-
- /**
- * Add the values to the cache.
- */
- private void cacheAttribute(String attrId, byte[][] values) {
- String cacheKey = name + "|" + attrId;
- valueCache.put(cacheKey, values);
- }
-
- /**
- * Get the values for the given attribute. If the attribute is null
- * or does not contain any values, a zero length byte array is
- * returned. NOTE that it is assumed that all values are byte arrays.
- */
- private byte[][] getAttributeValues(Attribute attr)
- throws NamingException {
- byte[][] values;
- if (attr == null) {
- values = BB0;
- } else {
- values = new byte[attr.size()][];
- int i = 0;
- NamingEnumeration<?> enum_ = attr.getAll();
- while (enum_.hasMore()) {
- Object obj = enum_.next();
- if (debug != null) {
- if (obj instanceof String) {
- debug.println("LDAPCertStore.getAttrValues() "
- + "enum.next is a string!: " + obj);
- }
- }
- byte[] value = (byte[])obj;
- values[i++] = value;
- }
- }
- return values;
- }
-
- }
-
- /*
- * Gets certificates from an attribute id and location in the LDAP
- * directory. Returns a Collection containing only the Certificates that
- * match the specified CertSelector.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @param sel a CertSelector that the Certificates must match
- * @return a Collection of Certificates found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509Certificate> getCertificates(LDAPRequest request,
- String id, X509CertSelector sel) throws CertStoreException {
-
- /* fetch encoded certs from storage */
- byte[][] encodedCert;
- try {
- encodedCert = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCert.length;
- if (n == 0) {
- return Collections.<X509Certificate>emptySet();
- }
-
- List<X509Certificate> certs = new ArrayList<X509Certificate>(n);
- /* decode certs and check if they satisfy selector */
- for (int i = 0; i < n; i++) {
- ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
- try {
- Certificate cert = cf.generateCertificate(bais);
- if (sel.match(cert)) {
- certs.add((X509Certificate)cert);
- }
- } catch (CertificateException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.getCertificates() encountered "
- + "exception while parsing cert, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println(
- "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
- }
- }
- }
-
- return certs;
- }
-
- /*
- * Gets certificate pairs from an attribute id and location in the LDAP
- * directory.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @return a Collection of X509CertificatePairs found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509CertificatePair> getCertPairs(
- LDAPRequest request, String id) throws CertStoreException {
-
- /* fetch the encoded cert pairs from storage */
- byte[][] encodedCertPair;
- try {
- encodedCertPair = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCertPair.length;
- if (n == 0) {
- return Collections.<X509CertificatePair>emptySet();
- }
-
- List<X509CertificatePair> certPairs =
- new ArrayList<X509CertificatePair>(n);
- /* decode each cert pair and add it to the Collection */
- for (int i = 0; i < n; i++) {
- try {
- X509CertificatePair certPair =
- X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
- certPairs.add(certPair);
- } catch (CertificateException e) {
- if (debug != null) {
- debug.println(
- "LDAPCertStore.getCertPairs() encountered exception "
- + "while parsing cert, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println(
- "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
- }
- }
- }
-
- return certPairs;
- }
-
- /*
- * Looks at certificate pairs stored in the crossCertificatePair attribute
- * at the specified location in the LDAP directory. Returns a Collection
- * containing all Certificates stored in the forward component that match
- * the forward CertSelector and all Certificates stored in the reverse
- * component that match the reverse CertSelector.
- * <p>
- * If either forward or reverse is null, all certificates from the
- * corresponding component will be rejected.
- *
- * @param name the location to look in
- * @param forward the forward CertSelector (or null)
- * @param reverse the reverse CertSelector (or null)
- * @return a Collection of Certificates found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509Certificate> getMatchingCrossCerts(
- LDAPRequest request, X509CertSelector forward,
- X509CertSelector reverse)
- throws CertStoreException {
- // Get the cert pairs
- Collection<X509CertificatePair> certPairs =
- getCertPairs(request, CROSS_CERT);
-
- // Find Certificates that match and put them in a list
- ArrayList<X509Certificate> matchingCerts =
- new ArrayList<X509Certificate>();
- for (X509CertificatePair certPair : certPairs) {
- X509Certificate cert;
- if (forward != null) {
- cert = certPair.getForward();
- if ((cert != null) && forward.match(cert)) {
- matchingCerts.add(cert);
- }
- }
- if (reverse != null) {
- cert = certPair.getReverse();
- if ((cert != null) && reverse.match(cert)) {
- matchingCerts.add(cert);
- }
- }
- }
- return matchingCerts;
- }
-
- /**
- * Returns a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector. If no <code>Certificate</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- * <p>
- * It is not practical to search every entry in the LDAP database for
- * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
- * is examined in order to determine where matching <code>Certificate</code>s
- * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
- * If the subject is specified, its directory entry is searched. If the
- * issuer is specified, its directory entry is searched. If neither the
- * subject nor the issuer are specified (or the selector is not an
- * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
- * thrown.
- *
- * @param selector a <code>CertSelector</code> used to select which
- * <code>Certificate</code>s should be returned.
- * @return a <code>Collection</code> of <code>Certificate</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- public synchronized Collection<X509Certificate> engineGetCertificates
- (CertSelector selector) throws CertStoreException {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() selector: "
- + String.valueOf(selector));
- }
-
- if (selector == null) {
- selector = new X509CertSelector();
- }
- if (!(selector instanceof X509CertSelector)) {
- throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
- "to find certs");
- }
- X509CertSelector xsel = (X509CertSelector) selector;
- int basicConstraints = xsel.getBasicConstraints();
- String subject = xsel.getSubjectAsString();
- String issuer = xsel.getIssuerAsString();
- HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
- + basicConstraints);
- }
-
- // basicConstraints:
- // -2: only EE certs accepted
- // -1: no check is done
- // 0: any CA certificate accepted
- // >1: certificate's basicConstraints extension pathlen must match
- if (subject != null) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() "
- + "subject is not null");
- }
- LDAPRequest request = new LDAPRequest(subject);
- if (basicConstraints > -2) {
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
- }
- if (basicConstraints < 0) {
- request.addRequestedAttribute(USER_CERT);
- }
-
- if (basicConstraints > -2) {
- certs.addAll(getMatchingCrossCerts(request, xsel, null));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
- + certs.size());
- }
- certs.addAll(getCertificates(request, CA_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
- + certs.size());
- }
- }
- if (basicConstraints < 0) {
- certs.addAll(getCertificates(request, USER_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
- + certs.size());
- }
- }
- } else {
- if (debug != null) {
- debug.println
- ("LDAPCertStore.engineGetCertificates() subject is null");
- }
- if (basicConstraints == -2) {
- throw new CertStoreException("need subject to find EE certs");
- }
- if (issuer == null) {
- throw new CertStoreException("need subject or issuer to find certs");
- }
- }
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() about to "
- + "getMatchingCrossCerts...");
- }
- if ((issuer != null) && (basicConstraints > -2)) {
- LDAPRequest request = new LDAPRequest(issuer);
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
-
- certs.addAll(getMatchingCrossCerts(request, null, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
- + certs.size());
- }
- certs.addAll(getCertificates(request, CA_CERT, xsel));
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() after "
- + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
- + certs.size());
- }
- }
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCertificates() returning certs");
- }
- return certs;
- }
-
- /*
- * Gets CRLs from an attribute id and location in the LDAP directory.
- * Returns a Collection containing only the CRLs that match the
- * specified CRLSelector.
- *
- * @param name the location holding the attribute
- * @param id the attribute identifier
- * @param sel a CRLSelector that the CRLs must match
- * @return a Collection of CRLs found
- * @throws CertStoreException if an exception occurs
- */
- private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
- X509CRLSelector sel) throws CertStoreException {
-
- /* fetch the encoded crls from storage */
- byte[][] encodedCRL;
- try {
- encodedCRL = request.getValues(id);
- } catch (NamingException namingEx) {
- throw new CertStoreException(namingEx);
- }
-
- int n = encodedCRL.length;
- if (n == 0) {
- return Collections.<X509CRL>emptySet();
- }
-
- List<X509CRL> crls = new ArrayList<X509CRL>(n);
- /* decode each crl and check if it matches selector */
- for (int i = 0; i < n; i++) {
- try {
- CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
- if (sel.match(crl)) {
- crls.add((X509CRL)crl);
- }
- } catch (CRLException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.getCRLs() encountered exception"
- + " while parsing CRL, skipping the bad data: ");
- HexDumpEncoder encoder = new HexDumpEncoder();
- debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
- }
- }
- }
-
- return crls;
- }
-
- /**
- * Returns a <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector. If no <code>CRL</code>s
- * match the selector, an empty <code>Collection</code> will be returned.
- * <p>
- * It is not practical to search every entry in the LDAP database for
- * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
- * is examined in order to determine where matching <code>CRL</code>s
- * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
- * If issuerNames or certChecking are specified, the issuer's directory
- * entry is searched. If neither issuerNames or certChecking are specified
- * (or the selector is not an <code>X509CRLSelector</code>), a
- * <code>CertStoreException</code> is thrown.
- *
- * @param selector A <code>CRLSelector</code> used to select which
- * <code>CRL</code>s should be returned. Specify <code>null</code>
- * to return all <code>CRL</code>s.
- * @return A <code>Collection</code> of <code>CRL</code>s that
- * match the specified selector
- * @throws CertStoreException if an exception occurs
- */
- public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
- throws CertStoreException {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCRLs() selector: "
- + selector);
- }
- // Set up selector and collection to hold CRLs
- if (selector == null) {
- selector = new X509CRLSelector();
- }
- if (!(selector instanceof X509CRLSelector)) {
- throw new CertStoreException("need X509CRLSelector to find CRLs");
- }
- X509CRLSelector xsel = (X509CRLSelector) selector;
- HashSet<X509CRL> crls = new HashSet<X509CRL>();
-
- // Look in directory entry for issuer of cert we're checking.
- Collection<Object> issuerNames;
- X509Certificate certChecking = xsel.getCertificateChecking();
- if (certChecking != null) {
- issuerNames = new HashSet<Object>();
- X500Principal issuer = certChecking.getIssuerX500Principal();
- issuerNames.add(issuer.getName(X500Principal.RFC2253));
- } else {
- // But if we don't know which cert we're checking, try the directory
- // entries of all acceptable CRL issuers
- issuerNames = xsel.getIssuerNames();
- if (issuerNames == null) {
- throw new CertStoreException("need issuerNames or certChecking to "
- + "find CRLs");
- }
- }
- for (Object nameObject : issuerNames) {
- String issuerName;
- if (nameObject instanceof byte[]) {
- try {
- X500Principal issuer = new X500Principal((byte[])nameObject);
- issuerName = issuer.getName(X500Principal.RFC2253);
- } catch (IllegalArgumentException e) {
- continue;
- }
- } else {
- issuerName = (String)nameObject;
- }
- // If all we want is CA certs, try to get the (probably shorter) ARL
- Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet();
- if (certChecking == null || certChecking.getBasicConstraints() != -1) {
- LDAPRequest request = new LDAPRequest(issuerName);
- request.addRequestedAttribute(CROSS_CERT);
- request.addRequestedAttribute(CA_CERT);
- request.addRequestedAttribute(ARL);
- if (prefetchCRLs) {
- request.addRequestedAttribute(CRL);
- }
- try {
- entryCRLs = getCRLs(request, ARL, xsel);
- if (entryCRLs.isEmpty()) {
- // no ARLs found. We assume that means that there are
- // no ARLs on this server at all and prefetch the CRLs.
- prefetchCRLs = true;
- } else {
- crls.addAll(entryCRLs);
- }
- } catch (CertStoreException e) {
- if (debug != null) {
- debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
- + "retrieving ARLs:" + e);
- e.printStackTrace();
- }
- }
- }
- // Otherwise, get the CRL
- // if certChecking is null, we don't know if we should look in ARL or CRL
- // attribute, so check both for matching CRLs.
- if (entryCRLs.isEmpty() || certChecking == null) {
- LDAPRequest request = new LDAPRequest(issuerName);
- request.addRequestedAttribute(CRL);
- entryCRLs = getCRLs(request, CRL, xsel);
- crls.addAll(entryCRLs);
- }
- }
- return crls;
- }
-
- // converts an LDAP URI into LDAPCertStoreParameters
- static LDAPCertStoreParameters getParameters(URI uri) {
- String host = uri.getHost();
- if (host == null) {
- return new SunLDAPCertStoreParameters();
- } else {
- int port = uri.getPort();
- return (port == -1
- ? new SunLDAPCertStoreParameters(host)
- : new SunLDAPCertStoreParameters(host, port));
- }
- }
-
- /*
- * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
- * methods. This is necessary because the parameters are used as
- * keys in the LDAPCertStore cache.
- */
- private static class SunLDAPCertStoreParameters
- extends LDAPCertStoreParameters {
-
- private volatile int hashCode = 0;
-
- SunLDAPCertStoreParameters(String serverName, int port) {
- super(serverName, port);
- }
- SunLDAPCertStoreParameters(String serverName) {
- super(serverName);
- }
- SunLDAPCertStoreParameters() {
- super();
- }
- public boolean equals(Object obj) {
- if (!(obj instanceof LDAPCertStoreParameters)) {
- return false;
- }
- LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
- return (getPort() == params.getPort() &&
- getServerName().equalsIgnoreCase(params.getServerName()));
- }
- public int hashCode() {
- if (hashCode == 0) {
- int result = 17;
- result = 37*result + getPort();
- result = 37*result + getServerName().toLowerCase().hashCode();
- hashCode = result;
- }
- return hashCode;
- }
- }
-
- /*
- * This inner class wraps an existing X509CertSelector and adds
- * additional criteria to match on when the certificate's subject is
- * different than the LDAP Distinguished Name entry. The LDAPCertStore
- * implementation uses the subject DN as the directory entry for
- * looking up certificates. This can be problematic if the certificates
- * that you want to fetch have a different subject DN than the entry
- * where they are stored. You could set the selector's subject to the
- * LDAP DN entry, but then the resulting match would fail to find the
- * desired certificates because the subject DNs would not match. This
- * class avoids that problem by introducing a certSubject which should
- * be set to the certificate's subject DN when it is different than
- * the LDAP DN.
- */
- static class LDAPCertSelector extends X509CertSelector {
-
- private X500Principal certSubject;
- private X509CertSelector selector;
- private X500Principal subject;
-
- /**
- * Creates an LDAPCertSelector.
- *
- * @param selector the X509CertSelector to wrap
- * @param certSubject the subject DN of the certificate that you want
- * to retrieve via LDAP
- * @param ldapDN the LDAP DN where the certificate is stored
- */
- LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
- String ldapDN) throws IOException {
- this.selector = selector == null ? new X509CertSelector() : selector;
- this.certSubject = certSubject;
- this.subject = new X500Name(ldapDN).asX500Principal();
- }
-
- // we only override the get (accessor methods) since the set methods
- // will not be invoked by the code that uses this LDAPCertSelector.
- public X509Certificate getCertificate() {
- return selector.getCertificate();
- }
- public BigInteger getSerialNumber() {
- return selector.getSerialNumber();
- }
- public X500Principal getIssuer() {
- return selector.getIssuer();
- }
- public String getIssuerAsString() {
- return selector.getIssuerAsString();
- }
- public byte[] getIssuerAsBytes() throws IOException {
- return selector.getIssuerAsBytes();
- }
- public X500Principal getSubject() {
- // return the ldap DN
- return subject;
- }
- public String getSubjectAsString() {
- // return the ldap DN
- return subject.getName();
- }
- public byte[] getSubjectAsBytes() throws IOException {
- // return the encoded ldap DN
- return subject.getEncoded();
- }
- public byte[] getSubjectKeyIdentifier() {
- return selector.getSubjectKeyIdentifier();
- }
- public byte[] getAuthorityKeyIdentifier() {
- return selector.getAuthorityKeyIdentifier();
- }
- public Date getCertificateValid() {
- return selector.getCertificateValid();
- }
- public Date getPrivateKeyValid() {
- return selector.getPrivateKeyValid();
- }
- public String getSubjectPublicKeyAlgID() {
- return selector.getSubjectPublicKeyAlgID();
- }
- public PublicKey getSubjectPublicKey() {
- return selector.getSubjectPublicKey();
- }
- public boolean[] getKeyUsage() {
- return selector.getKeyUsage();
- }
- public Set<String> getExtendedKeyUsage() {
- return selector.getExtendedKeyUsage();
- }
- public boolean getMatchAllSubjectAltNames() {
- return selector.getMatchAllSubjectAltNames();
- }
- public Collection<List<?>> getSubjectAlternativeNames() {
- return selector.getSubjectAlternativeNames();
- }
- public byte[] getNameConstraints() {
- return selector.getNameConstraints();
- }
- public int getBasicConstraints() {
- return selector.getBasicConstraints();
- }
- public Set<String> getPolicy() {
- return selector.getPolicy();
- }
- public Collection<List<?>> getPathToNames() {
- return selector.getPathToNames();
- }
-
- public boolean match(Certificate cert) {
- // temporarily set the subject criterion to the certSubject
- // so that match will not reject the desired certificates
- selector.setSubject(certSubject);
- boolean match = selector.match(cert);
- selector.setSubject(subject);
- return match;
- }
- }
-
- /**
- * This class has the same purpose as LDAPCertSelector except it is for
- * X.509 CRLs.
- */
- static class LDAPCRLSelector extends X509CRLSelector {
-
- private X509CRLSelector selector;
- private Collection<X500Principal> certIssuers;
- private Collection<X500Principal> issuers;
- private HashSet<Object> issuerNames;
-
- /**
- * Creates an LDAPCRLSelector.
- *
- * @param selector the X509CRLSelector to wrap
- * @param certIssuers the issuer DNs of the CRLs that you want
- * to retrieve via LDAP
- * @param ldapDN the LDAP DN where the CRL is stored
- */
- LDAPCRLSelector(X509CRLSelector selector,
- Collection<X500Principal> certIssuers, String ldapDN)
- throws IOException {
- this.selector = selector == null ? new X509CRLSelector() : selector;
- this.certIssuers = certIssuers;
- issuerNames = new HashSet<Object>();
- issuerNames.add(ldapDN);
- issuers = new HashSet<X500Principal>();
- issuers.add(new X500Name(ldapDN).asX500Principal());
- }
- // we only override the get (accessor methods) since the set methods
- // will not be invoked by the code that uses this LDAPCRLSelector.
- public Collection<X500Principal> getIssuers() {
- // return the ldap DN
- return Collections.unmodifiableCollection(issuers);
- }
- public Collection<Object> getIssuerNames() {
- // return the ldap DN
- return Collections.unmodifiableCollection(issuerNames);
- }
- public BigInteger getMinCRL() {
- return selector.getMinCRL();
- }
- public BigInteger getMaxCRL() {
- return selector.getMaxCRL();
- }
- public Date getDateAndTime() {
- return selector.getDateAndTime();
- }
- public X509Certificate getCertificateChecking() {
- return selector.getCertificateChecking();
- }
- public boolean match(CRL crl) {
- // temporarily set the issuer criterion to the certIssuers
- // so that match will not reject the desired CRL
- selector.setIssuers(certIssuers);
- boolean match = selector.match(crl);
- selector.setIssuers(issuers);
- return match;
- }
- }
-}
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java Wed Oct 28 10:37:17 2009 -0700
@@ -64,6 +64,8 @@
private static final Debug debug = Debug.getInstance("certpath");
+ private static final int CONNECT_TIMEOUT = 15000; // 15 seconds
+
private OCSP() {}
/**
@@ -176,6 +178,8 @@
debug.println("connecting to OCSP service at: " + url);
}
HttpURLConnection con = (HttpURLConnection)url.openConnection();
+ con.setConnectTimeout(CONNECT_TIMEOUT);
+ con.setReadTimeout(CONNECT_TIMEOUT);
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestMethod("POST");
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSPChecker.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPChecker.java Wed Oct 28 10:37:17 2009 -0700
@@ -25,7 +25,6 @@
package sun.security.provider.certpath;
-import java.io.IOException;
import java.math.BigInteger;
import java.util.*;
import java.security.AccessController;
@@ -335,10 +334,11 @@
(issuerCert, currCertImpl.getSerialNumberObject());
response = OCSP.check(Collections.singletonList(certId), uri,
responderCert, pkixParams.getDate());
- } catch (IOException ioe) {
- // should allow this to pass if network failures are acceptable
+ } catch (Exception e) {
+ // Wrap all exceptions in CertPathValidatorException so that
+ // we can fallback to CRLs, if enabled.
throw new CertPathValidatorException
- ("Unable to send OCSP request", ioe);
+ ("Unable to send OCSP request", e);
}
RevocationStatus rs = (RevocationStatus) response.getSingleResponse(certId);
--- a/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java Wed Oct 28 10:37:17 2009 -0700
@@ -30,6 +30,8 @@
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URLConnection;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.security.Provider;
@@ -121,6 +123,32 @@
private String ldapPath;
/**
+ * Holder class to lazily load LDAPCertStoreHelper if present.
+ */
+ private static class LDAP {
+ private static final String CERT_STORE_HELPER =
+ "sun.security.provider.certpath.ldap.LDAPCertStoreHelper";
+ private static final CertStoreHelper helper =
+ AccessController.doPrivileged(
+ new PrivilegedAction<CertStoreHelper>() {
+ public CertStoreHelper run() {
+ try {
+ Class<?> c = Class.forName(CERT_STORE_HELPER, true, null);
+ return (CertStoreHelper)c.newInstance();
+ } catch (ClassNotFoundException cnf) {
+ return null;
+ } catch (InstantiationException e) {
+ throw new AssertionError(e);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ }
+ }});
+ static CertStoreHelper helper() {
+ return helper;
+ }
+ }
+
+ /**
* Creates a URICertStore.
*
* @param parameters specifying the URI
@@ -135,9 +163,10 @@
this.uri = ((URICertStoreParameters) params).uri;
// if ldap URI, use an LDAPCertStore to fetch certs and CRLs
if (uri.getScheme().toLowerCase().equals("ldap")) {
+ if (LDAP.helper() == null)
+ throw new NoSuchAlgorithmException("LDAP not present");
ldap = true;
- ldapCertStore =
- LDAPCertStore.getInstance(LDAPCertStore.getParameters(uri));
+ ldapCertStore = LDAP.helper().getCertStore(uri);
ldapPath = uri.getPath();
// strip off leading '/'
if (ldapPath.charAt(0) == '/') {
@@ -219,8 +248,7 @@
if (ldap) {
X509CertSelector xsel = (X509CertSelector) selector;
try {
- xsel = new LDAPCertStore.LDAPCertSelector
- (xsel, xsel.getSubject(), ldapPath);
+ xsel = LDAP.helper().wrap(xsel, xsel.getSubject(), ldapPath);
} catch (IOException ioe) {
throw new CertStoreException(ioe);
}
@@ -340,7 +368,7 @@
if (ldap) {
X509CRLSelector xsel = (X509CRLSelector) selector;
try {
- xsel = new LDAPCertStore.LDAPCRLSelector(xsel, null, ldapPath);
+ xsel = LDAP.helper().wrap(xsel, null, ldapPath);
} catch (IOException ioe) {
throw new CertStoreException(ioe);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/ldap/LDAPCertStore.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,1066 @@
+/*
+ * Copyright 2000-2006 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.provider.certpath.ldap;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.math.BigInteger;
+import java.net.URI;
+import java.util.*;
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.NameNotFoundException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+
+import java.security.*;
+import java.security.cert.Certificate;
+import java.security.cert.*;
+import javax.security.auth.x500.X500Principal;
+
+import sun.misc.HexDumpEncoder;
+import sun.security.provider.certpath.X509CertificatePair;
+import sun.security.util.Cache;
+import sun.security.util.Debug;
+import sun.security.x509.X500Name;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * A <code>CertStore</code> that retrieves <code>Certificates</code> and
+ * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
+ * (RFC 2587):
+ * <a href="http://www.ietf.org/rfc/rfc2587.txt">
+ * http://www.ietf.org/rfc/rfc2587.txt</a>.
+ * <p>
+ * Before calling the {@link #engineGetCertificates engineGetCertificates} or
+ * {@link #engineGetCRLs engineGetCRLs} methods, the
+ * {@link #LDAPCertStore(CertStoreParameters)
+ * LDAPCertStore(CertStoreParameters)} constructor is called to create the
+ * <code>CertStore</code> and establish the DNS name and port of the LDAP
+ * server from which <code>Certificate</code>s and <code>CRL</code>s will be
+ * retrieved.
+ * <p>
+ * <b>Concurrent Access</b>
+ * <p>
+ * As described in the javadoc for <code>CertStoreSpi</code>, the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
+ * must be thread-safe. That is, multiple threads may concurrently
+ * invoke these methods on a single <code>LDAPCertStore</code> object
+ * (or more than one) with no ill effects. This allows a
+ * <code>CertPathBuilder</code> to search for a CRL while simultaneously
+ * searching for further certificates, for instance.
+ * <p>
+ * This is achieved by adding the <code>synchronized</code> keyword to the
+ * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
+ * <p>
+ * This classes uses caching and requests multiple attributes at once to
+ * minimize LDAP round trips. The cache is associated with the CertStore
+ * instance. It uses soft references to hold the values to minimize impact
+ * on footprint and currently has a maximum size of 750 attributes and a
+ * 30 second default lifetime.
+ * <p>
+ * We always request CA certificates, cross certificate pairs, and ARLs in
+ * a single LDAP request when any one of them is needed. The reason is that
+ * we typically need all of them anyway and requesting them in one go can
+ * reduce the number of requests to a third. Even if we don't need them,
+ * these attributes are typically small enough not to cause a noticeable
+ * overhead. In addition, when the prefetchCRLs flag is true, we also request
+ * the full CRLs. It is currently false initially but set to true once any
+ * request for an ARL to the server returns an null value. The reason is
+ * that CRLs could be rather large but are rarely used. This implementation
+ * should improve performance in most cases.
+ *
+ * @see java.security.cert.CertStore
+ *
+ * @since 1.4
+ * @author Steve Hanna
+ * @author Andreas Sterbenz
+ */
+public class LDAPCertStore extends CertStoreSpi {
+
+ private static final Debug debug = Debug.getInstance("certpath");
+
+ private final static boolean DEBUG = false;
+
+ /**
+ * LDAP attribute identifiers.
+ */
+ private static final String USER_CERT = "userCertificate;binary";
+ private static final String CA_CERT = "cACertificate;binary";
+ private static final String CROSS_CERT = "crossCertificatePair;binary";
+ private static final String CRL = "certificateRevocationList;binary";
+ private static final String ARL = "authorityRevocationList;binary";
+ private static final String DELTA_CRL = "deltaRevocationList;binary";
+
+ // Constants for various empty values
+ private final static String[] STRING0 = new String[0];
+
+ private final static byte[][] BB0 = new byte[0][];
+
+ private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
+
+ // cache related constants
+ private final static int DEFAULT_CACHE_SIZE = 750;
+ private final static int DEFAULT_CACHE_LIFETIME = 30;
+
+ private final static int LIFETIME;
+
+ private final static String PROP_LIFETIME =
+ "sun.security.certpath.ldap.cache.lifetime";
+
+ static {
+ String s = AccessController.doPrivileged(
+ new GetPropertyAction(PROP_LIFETIME));
+ if (s != null) {
+ LIFETIME = Integer.parseInt(s); // throws NumberFormatException
+ } else {
+ LIFETIME = DEFAULT_CACHE_LIFETIME;
+ }
+ }
+
+ /**
+ * The CertificateFactory used to decode certificates from
+ * their binary stored form.
+ */
+ private CertificateFactory cf;
+ /**
+ * The JNDI directory context.
+ */
+ private DirContext ctx;
+
+ /**
+ * Flag indicating whether we should prefetch CRLs.
+ */
+ private boolean prefetchCRLs = false;
+
+ private final Cache valueCache;
+
+ private int cacheHits = 0;
+ private int cacheMisses = 0;
+ private int requests = 0;
+
+ /**
+ * Creates a <code>CertStore</code> with the specified parameters.
+ * For this class, the parameters object must be an instance of
+ * <code>LDAPCertStoreParameters</code>.
+ *
+ * @param params the algorithm parameters
+ * @exception InvalidAlgorithmParameterException if params is not an
+ * instance of <code>LDAPCertStoreParameters</code>
+ */
+ public LDAPCertStore(CertStoreParameters params)
+ throws InvalidAlgorithmParameterException {
+ super(params);
+ if (!(params instanceof LDAPCertStoreParameters))
+ throw new InvalidAlgorithmParameterException(
+ "parameters must be LDAPCertStoreParameters");
+
+ LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
+
+ // Create InitialDirContext needed to communicate with the server
+ createInitialDirContext(lparams.getServerName(), lparams.getPort());
+
+ // Create CertificateFactory for use later on
+ try {
+ cf = CertificateFactory.getInstance("X.509");
+ } catch (CertificateException e) {
+ throw new InvalidAlgorithmParameterException(
+ "unable to create CertificateFactory for X.509");
+ }
+ if (LIFETIME == 0) {
+ valueCache = Cache.newNullCache();
+ } else if (LIFETIME < 0) {
+ valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
+ } else {
+ valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
+ }
+ }
+
+ /**
+ * Returns an LDAP CertStore. This method consults a cache of
+ * CertStores (shared per JVM) using the LDAP server/port as a key.
+ */
+ private static final Cache certStoreCache = Cache.newSoftMemoryCache(185);
+ static synchronized CertStore getInstance(LDAPCertStoreParameters params)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
+ CertStore lcs = (CertStore) certStoreCache.get(params);
+ if (lcs == null) {
+ lcs = CertStore.getInstance("LDAP", params);
+ certStoreCache.put(params, lcs);
+ } else {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getInstance: cache hit");
+ }
+ }
+ return lcs;
+ }
+
+ /**
+ * Create InitialDirContext.
+ *
+ * @param server Server DNS name hosting LDAP service
+ * @param port Port at which server listens for requests
+ * @throws InvalidAlgorithmParameterException if creation fails
+ */
+ private void createInitialDirContext(String server, int port)
+ throws InvalidAlgorithmParameterException {
+ String url = "ldap://" + server + ":" + port;
+ Hashtable<String,Object> env = new Hashtable<String,Object>();
+ env.put(Context.INITIAL_CONTEXT_FACTORY,
+ "com.sun.jndi.ldap.LdapCtxFactory");
+ env.put(Context.PROVIDER_URL, url);
+ try {
+ ctx = new InitialDirContext(env);
+ /*
+ * By default, follow referrals unless application has
+ * overridden property in an application resource file.
+ */
+ Hashtable<?,?> currentEnv = ctx.getEnvironment();
+ if (currentEnv.get(Context.REFERRAL) == null) {
+ ctx.addToEnvironment(Context.REFERRAL, "follow");
+ }
+ } catch (NamingException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineInit about to throw "
+ + "InvalidAlgorithmParameterException");
+ e.printStackTrace();
+ }
+ Exception ee = new InvalidAlgorithmParameterException
+ ("unable to create InitialDirContext using supplied parameters");
+ ee.initCause(e);
+ throw (InvalidAlgorithmParameterException)ee;
+ }
+ }
+
+ /**
+ * Private class encapsulating the actual LDAP operations and cache
+ * handling. Use:
+ *
+ * LDAPRequest request = new LDAPRequest(dn);
+ * request.addRequestedAttribute(CROSS_CERT);
+ * request.addRequestedAttribute(CA_CERT);
+ * byte[][] crossValues = request.getValues(CROSS_CERT);
+ * byte[][] caValues = request.getValues(CA_CERT);
+ *
+ * At most one LDAP request is sent for each instance created. If all
+ * getValues() calls can be satisfied from the cache, no request
+ * is sent at all. If a request is sent, all requested attributes
+ * are always added to the cache irrespective of whether the getValues()
+ * method is called.
+ */
+ private class LDAPRequest {
+
+ private final String name;
+ private Map<String, byte[][]> valueMap;
+ private final List<String> requestedAttributes;
+
+ LDAPRequest(String name) {
+ this.name = name;
+ requestedAttributes = new ArrayList<String>(5);
+ }
+
+ String getName() {
+ return name;
+ }
+
+ void addRequestedAttribute(String attrId) {
+ if (valueMap != null) {
+ throw new IllegalStateException("Request already sent");
+ }
+ requestedAttributes.add(attrId);
+ }
+
+ /**
+ * Gets one or more binary values from an attribute.
+ *
+ * @param name the location holding the attribute
+ * @param attrId the attribute identifier
+ * @return an array of binary values (byte arrays)
+ * @throws NamingException if a naming exception occurs
+ */
+ byte[][] getValues(String attrId) throws NamingException {
+ if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
+ System.out.println("Cache hits: " + cacheHits + "; misses: "
+ + cacheMisses);
+ }
+ String cacheKey = name + "|" + attrId;
+ byte[][] values = (byte[][])valueCache.get(cacheKey);
+ if (values != null) {
+ cacheHits++;
+ return values;
+ }
+ cacheMisses++;
+ Map<String, byte[][]> attrs = getValueMap();
+ values = attrs.get(attrId);
+ return values;
+ }
+
+ /**
+ * Get a map containing the values for this request. The first time
+ * this method is called on an object, the LDAP request is sent,
+ * the results parsed and added to a private map and also to the
+ * cache of this LDAPCertStore. Subsequent calls return the private
+ * map immediately.
+ *
+ * The map contains an entry for each requested attribute. The
+ * attribute name is the key, values are byte[][]. If there are no
+ * values for that attribute, values are byte[0][].
+ *
+ * @return the value Map
+ * @throws NamingException if a naming exception occurs
+ */
+ private Map<String, byte[][]> getValueMap() throws NamingException {
+ if (valueMap != null) {
+ return valueMap;
+ }
+ if (DEBUG) {
+ System.out.println("Request: " + name + ":" + requestedAttributes);
+ requests++;
+ if (requests % 5 == 0) {
+ System.out.println("LDAP requests: " + requests);
+ }
+ }
+ valueMap = new HashMap<String, byte[][]>(8);
+ String[] attrIds = requestedAttributes.toArray(STRING0);
+ Attributes attrs;
+ try {
+ attrs = ctx.getAttributes(name, attrIds);
+ } catch (NameNotFoundException e) {
+ // name does not exist on this LDAP server
+ // treat same as not attributes found
+ attrs = EMPTY_ATTRIBUTES;
+ }
+ for (String attrId : requestedAttributes) {
+ Attribute attr = attrs.get(attrId);
+ byte[][] values = getAttributeValues(attr);
+ cacheAttribute(attrId, values);
+ valueMap.put(attrId, values);
+ }
+ return valueMap;
+ }
+
+ /**
+ * Add the values to the cache.
+ */
+ private void cacheAttribute(String attrId, byte[][] values) {
+ String cacheKey = name + "|" + attrId;
+ valueCache.put(cacheKey, values);
+ }
+
+ /**
+ * Get the values for the given attribute. If the attribute is null
+ * or does not contain any values, a zero length byte array is
+ * returned. NOTE that it is assumed that all values are byte arrays.
+ */
+ private byte[][] getAttributeValues(Attribute attr)
+ throws NamingException {
+ byte[][] values;
+ if (attr == null) {
+ values = BB0;
+ } else {
+ values = new byte[attr.size()][];
+ int i = 0;
+ NamingEnumeration<?> enum_ = attr.getAll();
+ while (enum_.hasMore()) {
+ Object obj = enum_.next();
+ if (debug != null) {
+ if (obj instanceof String) {
+ debug.println("LDAPCertStore.getAttrValues() "
+ + "enum.next is a string!: " + obj);
+ }
+ }
+ byte[] value = (byte[])obj;
+ values[i++] = value;
+ }
+ }
+ return values;
+ }
+
+ }
+
+ /*
+ * Gets certificates from an attribute id and location in the LDAP
+ * directory. Returns a Collection containing only the Certificates that
+ * match the specified CertSelector.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @param sel a CertSelector that the Certificates must match
+ * @return a Collection of Certificates found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509Certificate> getCertificates(LDAPRequest request,
+ String id, X509CertSelector sel) throws CertStoreException {
+
+ /* fetch encoded certs from storage */
+ byte[][] encodedCert;
+ try {
+ encodedCert = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCert.length;
+ if (n == 0) {
+ return Collections.<X509Certificate>emptySet();
+ }
+
+ List<X509Certificate> certs = new ArrayList<X509Certificate>(n);
+ /* decode certs and check if they satisfy selector */
+ for (int i = 0; i < n; i++) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
+ try {
+ Certificate cert = cf.generateCertificate(bais);
+ if (sel.match(cert)) {
+ certs.add((X509Certificate)cert);
+ }
+ } catch (CertificateException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getCertificates() encountered "
+ + "exception while parsing cert, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println(
+ "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
+ }
+ }
+ }
+
+ return certs;
+ }
+
+ /*
+ * Gets certificate pairs from an attribute id and location in the LDAP
+ * directory.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @return a Collection of X509CertificatePairs found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509CertificatePair> getCertPairs(
+ LDAPRequest request, String id) throws CertStoreException {
+
+ /* fetch the encoded cert pairs from storage */
+ byte[][] encodedCertPair;
+ try {
+ encodedCertPair = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCertPair.length;
+ if (n == 0) {
+ return Collections.<X509CertificatePair>emptySet();
+ }
+
+ List<X509CertificatePair> certPairs =
+ new ArrayList<X509CertificatePair>(n);
+ /* decode each cert pair and add it to the Collection */
+ for (int i = 0; i < n; i++) {
+ try {
+ X509CertificatePair certPair =
+ X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
+ certPairs.add(certPair);
+ } catch (CertificateException e) {
+ if (debug != null) {
+ debug.println(
+ "LDAPCertStore.getCertPairs() encountered exception "
+ + "while parsing cert, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println(
+ "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
+ }
+ }
+ }
+
+ return certPairs;
+ }
+
+ /*
+ * Looks at certificate pairs stored in the crossCertificatePair attribute
+ * at the specified location in the LDAP directory. Returns a Collection
+ * containing all Certificates stored in the forward component that match
+ * the forward CertSelector and all Certificates stored in the reverse
+ * component that match the reverse CertSelector.
+ * <p>
+ * If either forward or reverse is null, all certificates from the
+ * corresponding component will be rejected.
+ *
+ * @param name the location to look in
+ * @param forward the forward CertSelector (or null)
+ * @param reverse the reverse CertSelector (or null)
+ * @return a Collection of Certificates found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509Certificate> getMatchingCrossCerts(
+ LDAPRequest request, X509CertSelector forward,
+ X509CertSelector reverse)
+ throws CertStoreException {
+ // Get the cert pairs
+ Collection<X509CertificatePair> certPairs =
+ getCertPairs(request, CROSS_CERT);
+
+ // Find Certificates that match and put them in a list
+ ArrayList<X509Certificate> matchingCerts =
+ new ArrayList<X509Certificate>();
+ for (X509CertificatePair certPair : certPairs) {
+ X509Certificate cert;
+ if (forward != null) {
+ cert = certPair.getForward();
+ if ((cert != null) && forward.match(cert)) {
+ matchingCerts.add(cert);
+ }
+ }
+ if (reverse != null) {
+ cert = certPair.getReverse();
+ if ((cert != null) && reverse.match(cert)) {
+ matchingCerts.add(cert);
+ }
+ }
+ }
+ return matchingCerts;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector. If no <code>Certificate</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ * <p>
+ * It is not practical to search every entry in the LDAP database for
+ * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
+ * is examined in order to determine where matching <code>Certificate</code>s
+ * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
+ * If the subject is specified, its directory entry is searched. If the
+ * issuer is specified, its directory entry is searched. If neither the
+ * subject nor the issuer are specified (or the selector is not an
+ * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
+ * thrown.
+ *
+ * @param selector a <code>CertSelector</code> used to select which
+ * <code>Certificate</code>s should be returned.
+ * @return a <code>Collection</code> of <code>Certificate</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ public synchronized Collection<X509Certificate> engineGetCertificates
+ (CertSelector selector) throws CertStoreException {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() selector: "
+ + String.valueOf(selector));
+ }
+
+ if (selector == null) {
+ selector = new X509CertSelector();
+ }
+ if (!(selector instanceof X509CertSelector)) {
+ throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
+ "to find certs");
+ }
+ X509CertSelector xsel = (X509CertSelector) selector;
+ int basicConstraints = xsel.getBasicConstraints();
+ String subject = xsel.getSubjectAsString();
+ String issuer = xsel.getIssuerAsString();
+ HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
+ + basicConstraints);
+ }
+
+ // basicConstraints:
+ // -2: only EE certs accepted
+ // -1: no check is done
+ // 0: any CA certificate accepted
+ // >1: certificate's basicConstraints extension pathlen must match
+ if (subject != null) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() "
+ + "subject is not null");
+ }
+ LDAPRequest request = new LDAPRequest(subject);
+ if (basicConstraints > -2) {
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+ }
+ if (basicConstraints < 0) {
+ request.addRequestedAttribute(USER_CERT);
+ }
+
+ if (basicConstraints > -2) {
+ certs.addAll(getMatchingCrossCerts(request, xsel, null));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
+ + certs.size());
+ }
+ certs.addAll(getCertificates(request, CA_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ if (basicConstraints < 0) {
+ certs.addAll(getCertificates(request, USER_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ } else {
+ if (debug != null) {
+ debug.println
+ ("LDAPCertStore.engineGetCertificates() subject is null");
+ }
+ if (basicConstraints == -2) {
+ throw new CertStoreException("need subject to find EE certs");
+ }
+ if (issuer == null) {
+ throw new CertStoreException("need subject or issuer to find certs");
+ }
+ }
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() about to "
+ + "getMatchingCrossCerts...");
+ }
+ if ((issuer != null) && (basicConstraints > -2)) {
+ LDAPRequest request = new LDAPRequest(issuer);
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+
+ certs.addAll(getMatchingCrossCerts(request, null, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
+ + certs.size());
+ }
+ certs.addAll(getCertificates(request, CA_CERT, xsel));
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() after "
+ + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
+ + certs.size());
+ }
+ }
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCertificates() returning certs");
+ }
+ return certs;
+ }
+
+ /*
+ * Gets CRLs from an attribute id and location in the LDAP directory.
+ * Returns a Collection containing only the CRLs that match the
+ * specified CRLSelector.
+ *
+ * @param name the location holding the attribute
+ * @param id the attribute identifier
+ * @param sel a CRLSelector that the CRLs must match
+ * @return a Collection of CRLs found
+ * @throws CertStoreException if an exception occurs
+ */
+ private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
+ X509CRLSelector sel) throws CertStoreException {
+
+ /* fetch the encoded crls from storage */
+ byte[][] encodedCRL;
+ try {
+ encodedCRL = request.getValues(id);
+ } catch (NamingException namingEx) {
+ throw new CertStoreException(namingEx);
+ }
+
+ int n = encodedCRL.length;
+ if (n == 0) {
+ return Collections.<X509CRL>emptySet();
+ }
+
+ List<X509CRL> crls = new ArrayList<X509CRL>(n);
+ /* decode each crl and check if it matches selector */
+ for (int i = 0; i < n; i++) {
+ try {
+ CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
+ if (sel.match(crl)) {
+ crls.add((X509CRL)crl);
+ }
+ } catch (CRLException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.getCRLs() encountered exception"
+ + " while parsing CRL, skipping the bad data: ");
+ HexDumpEncoder encoder = new HexDumpEncoder();
+ debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
+ }
+ }
+ }
+
+ return crls;
+ }
+
+ /**
+ * Returns a <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector. If no <code>CRL</code>s
+ * match the selector, an empty <code>Collection</code> will be returned.
+ * <p>
+ * It is not practical to search every entry in the LDAP database for
+ * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
+ * is examined in order to determine where matching <code>CRL</code>s
+ * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
+ * If issuerNames or certChecking are specified, the issuer's directory
+ * entry is searched. If neither issuerNames or certChecking are specified
+ * (or the selector is not an <code>X509CRLSelector</code>), a
+ * <code>CertStoreException</code> is thrown.
+ *
+ * @param selector A <code>CRLSelector</code> used to select which
+ * <code>CRL</code>s should be returned. Specify <code>null</code>
+ * to return all <code>CRL</code>s.
+ * @return A <code>Collection</code> of <code>CRL</code>s that
+ * match the specified selector
+ * @throws CertStoreException if an exception occurs
+ */
+ public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
+ throws CertStoreException {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCRLs() selector: "
+ + selector);
+ }
+ // Set up selector and collection to hold CRLs
+ if (selector == null) {
+ selector = new X509CRLSelector();
+ }
+ if (!(selector instanceof X509CRLSelector)) {
+ throw new CertStoreException("need X509CRLSelector to find CRLs");
+ }
+ X509CRLSelector xsel = (X509CRLSelector) selector;
+ HashSet<X509CRL> crls = new HashSet<X509CRL>();
+
+ // Look in directory entry for issuer of cert we're checking.
+ Collection<Object> issuerNames;
+ X509Certificate certChecking = xsel.getCertificateChecking();
+ if (certChecking != null) {
+ issuerNames = new HashSet<Object>();
+ X500Principal issuer = certChecking.getIssuerX500Principal();
+ issuerNames.add(issuer.getName(X500Principal.RFC2253));
+ } else {
+ // But if we don't know which cert we're checking, try the directory
+ // entries of all acceptable CRL issuers
+ issuerNames = xsel.getIssuerNames();
+ if (issuerNames == null) {
+ throw new CertStoreException("need issuerNames or certChecking to "
+ + "find CRLs");
+ }
+ }
+ for (Object nameObject : issuerNames) {
+ String issuerName;
+ if (nameObject instanceof byte[]) {
+ try {
+ X500Principal issuer = new X500Principal((byte[])nameObject);
+ issuerName = issuer.getName(X500Principal.RFC2253);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+ } else {
+ issuerName = (String)nameObject;
+ }
+ // If all we want is CA certs, try to get the (probably shorter) ARL
+ Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet();
+ if (certChecking == null || certChecking.getBasicConstraints() != -1) {
+ LDAPRequest request = new LDAPRequest(issuerName);
+ request.addRequestedAttribute(CROSS_CERT);
+ request.addRequestedAttribute(CA_CERT);
+ request.addRequestedAttribute(ARL);
+ if (prefetchCRLs) {
+ request.addRequestedAttribute(CRL);
+ }
+ try {
+ entryCRLs = getCRLs(request, ARL, xsel);
+ if (entryCRLs.isEmpty()) {
+ // no ARLs found. We assume that means that there are
+ // no ARLs on this server at all and prefetch the CRLs.
+ prefetchCRLs = true;
+ } else {
+ crls.addAll(entryCRLs);
+ }
+ } catch (CertStoreException e) {
+ if (debug != null) {
+ debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
+ + "retrieving ARLs:" + e);
+ e.printStackTrace();
+ }
+ }
+ }
+ // Otherwise, get the CRL
+ // if certChecking is null, we don't know if we should look in ARL or CRL
+ // attribute, so check both for matching CRLs.
+ if (entryCRLs.isEmpty() || certChecking == null) {
+ LDAPRequest request = new LDAPRequest(issuerName);
+ request.addRequestedAttribute(CRL);
+ entryCRLs = getCRLs(request, CRL, xsel);
+ crls.addAll(entryCRLs);
+ }
+ }
+ return crls;
+ }
+
+ // converts an LDAP URI into LDAPCertStoreParameters
+ static LDAPCertStoreParameters getParameters(URI uri) {
+ String host = uri.getHost();
+ if (host == null) {
+ return new SunLDAPCertStoreParameters();
+ } else {
+ int port = uri.getPort();
+ return (port == -1
+ ? new SunLDAPCertStoreParameters(host)
+ : new SunLDAPCertStoreParameters(host, port));
+ }
+ }
+
+ /*
+ * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
+ * methods. This is necessary because the parameters are used as
+ * keys in the LDAPCertStore cache.
+ */
+ private static class SunLDAPCertStoreParameters
+ extends LDAPCertStoreParameters {
+
+ private volatile int hashCode = 0;
+
+ SunLDAPCertStoreParameters(String serverName, int port) {
+ super(serverName, port);
+ }
+ SunLDAPCertStoreParameters(String serverName) {
+ super(serverName);
+ }
+ SunLDAPCertStoreParameters() {
+ super();
+ }
+ public boolean equals(Object obj) {
+ if (!(obj instanceof LDAPCertStoreParameters)) {
+ return false;
+ }
+ LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
+ return (getPort() == params.getPort() &&
+ getServerName().equalsIgnoreCase(params.getServerName()));
+ }
+ public int hashCode() {
+ if (hashCode == 0) {
+ int result = 17;
+ result = 37*result + getPort();
+ result = 37*result + getServerName().toLowerCase().hashCode();
+ hashCode = result;
+ }
+ return hashCode;
+ }
+ }
+
+ /*
+ * This inner class wraps an existing X509CertSelector and adds
+ * additional criteria to match on when the certificate's subject is
+ * different than the LDAP Distinguished Name entry. The LDAPCertStore
+ * implementation uses the subject DN as the directory entry for
+ * looking up certificates. This can be problematic if the certificates
+ * that you want to fetch have a different subject DN than the entry
+ * where they are stored. You could set the selector's subject to the
+ * LDAP DN entry, but then the resulting match would fail to find the
+ * desired certificates because the subject DNs would not match. This
+ * class avoids that problem by introducing a certSubject which should
+ * be set to the certificate's subject DN when it is different than
+ * the LDAP DN.
+ */
+ static class LDAPCertSelector extends X509CertSelector {
+
+ private X500Principal certSubject;
+ private X509CertSelector selector;
+ private X500Principal subject;
+
+ /**
+ * Creates an LDAPCertSelector.
+ *
+ * @param selector the X509CertSelector to wrap
+ * @param certSubject the subject DN of the certificate that you want
+ * to retrieve via LDAP
+ * @param ldapDN the LDAP DN where the certificate is stored
+ */
+ LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
+ String ldapDN) throws IOException {
+ this.selector = selector == null ? new X509CertSelector() : selector;
+ this.certSubject = certSubject;
+ this.subject = new X500Name(ldapDN).asX500Principal();
+ }
+
+ // we only override the get (accessor methods) since the set methods
+ // will not be invoked by the code that uses this LDAPCertSelector.
+ public X509Certificate getCertificate() {
+ return selector.getCertificate();
+ }
+ public BigInteger getSerialNumber() {
+ return selector.getSerialNumber();
+ }
+ public X500Principal getIssuer() {
+ return selector.getIssuer();
+ }
+ public String getIssuerAsString() {
+ return selector.getIssuerAsString();
+ }
+ public byte[] getIssuerAsBytes() throws IOException {
+ return selector.getIssuerAsBytes();
+ }
+ public X500Principal getSubject() {
+ // return the ldap DN
+ return subject;
+ }
+ public String getSubjectAsString() {
+ // return the ldap DN
+ return subject.getName();
+ }
+ public byte[] getSubjectAsBytes() throws IOException {
+ // return the encoded ldap DN
+ return subject.getEncoded();
+ }
+ public byte[] getSubjectKeyIdentifier() {
+ return selector.getSubjectKeyIdentifier();
+ }
+ public byte[] getAuthorityKeyIdentifier() {
+ return selector.getAuthorityKeyIdentifier();
+ }
+ public Date getCertificateValid() {
+ return selector.getCertificateValid();
+ }
+ public Date getPrivateKeyValid() {
+ return selector.getPrivateKeyValid();
+ }
+ public String getSubjectPublicKeyAlgID() {
+ return selector.getSubjectPublicKeyAlgID();
+ }
+ public PublicKey getSubjectPublicKey() {
+ return selector.getSubjectPublicKey();
+ }
+ public boolean[] getKeyUsage() {
+ return selector.getKeyUsage();
+ }
+ public Set<String> getExtendedKeyUsage() {
+ return selector.getExtendedKeyUsage();
+ }
+ public boolean getMatchAllSubjectAltNames() {
+ return selector.getMatchAllSubjectAltNames();
+ }
+ public Collection<List<?>> getSubjectAlternativeNames() {
+ return selector.getSubjectAlternativeNames();
+ }
+ public byte[] getNameConstraints() {
+ return selector.getNameConstraints();
+ }
+ public int getBasicConstraints() {
+ return selector.getBasicConstraints();
+ }
+ public Set<String> getPolicy() {
+ return selector.getPolicy();
+ }
+ public Collection<List<?>> getPathToNames() {
+ return selector.getPathToNames();
+ }
+
+ public boolean match(Certificate cert) {
+ // temporarily set the subject criterion to the certSubject
+ // so that match will not reject the desired certificates
+ selector.setSubject(certSubject);
+ boolean match = selector.match(cert);
+ selector.setSubject(subject);
+ return match;
+ }
+ }
+
+ /**
+ * This class has the same purpose as LDAPCertSelector except it is for
+ * X.509 CRLs.
+ */
+ static class LDAPCRLSelector extends X509CRLSelector {
+
+ private X509CRLSelector selector;
+ private Collection<X500Principal> certIssuers;
+ private Collection<X500Principal> issuers;
+ private HashSet<Object> issuerNames;
+
+ /**
+ * Creates an LDAPCRLSelector.
+ *
+ * @param selector the X509CRLSelector to wrap
+ * @param certIssuers the issuer DNs of the CRLs that you want
+ * to retrieve via LDAP
+ * @param ldapDN the LDAP DN where the CRL is stored
+ */
+ LDAPCRLSelector(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers, String ldapDN)
+ throws IOException {
+ this.selector = selector == null ? new X509CRLSelector() : selector;
+ this.certIssuers = certIssuers;
+ issuerNames = new HashSet<Object>();
+ issuerNames.add(ldapDN);
+ issuers = new HashSet<X500Principal>();
+ issuers.add(new X500Name(ldapDN).asX500Principal());
+ }
+ // we only override the get (accessor methods) since the set methods
+ // will not be invoked by the code that uses this LDAPCRLSelector.
+ public Collection<X500Principal> getIssuers() {
+ // return the ldap DN
+ return Collections.unmodifiableCollection(issuers);
+ }
+ public Collection<Object> getIssuerNames() {
+ // return the ldap DN
+ return Collections.unmodifiableCollection(issuerNames);
+ }
+ public BigInteger getMinCRL() {
+ return selector.getMinCRL();
+ }
+ public BigInteger getMaxCRL() {
+ return selector.getMaxCRL();
+ }
+ public Date getDateAndTime() {
+ return selector.getDateAndTime();
+ }
+ public X509Certificate getCertificateChecking() {
+ return selector.getCertificateChecking();
+ }
+ public boolean match(CRL crl) {
+ // temporarily set the issuer criterion to the certIssuers
+ // so that match will not reject the desired CRL
+ selector.setIssuers(certIssuers);
+ boolean match = selector.match(crl);
+ selector.setIssuers(issuers);
+ return match;
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/ldap/LDAPCertStoreHelper.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. 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. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package sun.security.provider.certpath.ldap;
+
+import java.net.URI;
+import java.util.Collection;
+import java.security.NoSuchAlgorithmException;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.cert.CertStore;
+import java.security.cert.X509CertSelector;
+import java.security.cert.X509CRLSelector;
+import javax.security.auth.x500.X500Principal;
+import java.io.IOException;
+
+import sun.security.provider.certpath.CertStoreHelper;
+
+/**
+ * LDAP implementation of CertStoreHelper.
+ */
+
+public class LDAPCertStoreHelper
+ implements CertStoreHelper
+{
+ public LDAPCertStoreHelper() { }
+
+ @Override
+ public CertStore getCertStore(URI uri)
+ throws NoSuchAlgorithmException, InvalidAlgorithmParameterException
+ {
+ return LDAPCertStore.getInstance(LDAPCertStore.getParameters(uri));
+ }
+
+ @Override
+ public X509CertSelector wrap(X509CertSelector selector,
+ X500Principal certSubject,
+ String ldapDN)
+ throws IOException
+ {
+ return new LDAPCertStore.LDAPCertSelector(selector, certSubject, ldapDN);
+ }
+
+ @Override
+ public X509CRLSelector wrap(X509CRLSelector selector,
+ Collection<X500Principal> certIssuers,
+ String ldapDN)
+ throws IOException
+ {
+ return new LDAPCertStore.LDAPCRLSelector(selector, certIssuers, ldapDN);
+ }
+}
--- a/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java Wed Oct 28 10:37:17 2009 -0700
@@ -104,11 +104,11 @@
int uid;
if (user.isSpecial()) {
uid = -1;
- if (who.getName().equals(UnixUserPrincipals.SPECIAL_OWNER.getName()))
+ if (who == UnixUserPrincipals.SPECIAL_OWNER)
flags |= ACE_OWNER;
- else if (who.getName().equals(UnixUserPrincipals.SPECIAL_GROUP.getName()))
- flags |= ACE_GROUP;
- else if (who.getName().equals(UnixUserPrincipals.SPECIAL_EVERYONE.getName()))
+ else if (who == UnixUserPrincipals.SPECIAL_GROUP)
+ flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);
+ else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)
flags |= ACE_EVERYONE;
else
throw new AssertionError("Unable to map special identifier");
@@ -281,7 +281,7 @@
aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
- if ((flags & ACE_INHERIT_ONLY_ACE ) > 0)
+ if ((flags & ACE_INHERIT_ONLY_ACE) > 0)
aceFlags.add(AclEntryFlag.INHERIT_ONLY);
// build the ACL entry and add it to the list
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java Wed Oct 28 10:37:17 2009 -0700
@@ -235,7 +235,8 @@
@Override
public void remove() {
if (isClosed) {
- throw new ClosedDirectoryStreamException();
+ throwAsConcurrentModificationException(new
+ ClosedDirectoryStreamException());
}
Path entry;
synchronized (this) {
--- a/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java Wed Oct 28 10:37:17 2009 -0700
@@ -179,7 +179,7 @@
synchronized (closeLock) {
if (!isOpen)
throwAsConcurrentModificationException(new
- IllegalStateException("Directory stream is closed"));
+ ClosedDirectoryStreamException());
try {
name = FindNextFile(handle, findDataBuffer.address());
if (name == null) {
@@ -236,7 +236,8 @@
@Override
public void remove() {
if (!isOpen) {
- throw new IllegalStateException("Directory stream is closed");
+ throwAsConcurrentModificationException(new
+ ClosedDirectoryStreamException());
}
Path entry;
synchronized (this) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/net/httpserver/bugs/B6886436.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/**
+ * @test
+ * @bug 6886436
+ * @summary
+ */
+
+import com.sun.net.httpserver.*;
+
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.logging.*;
+import java.io.*;
+import java.net.*;
+
+public class B6886436 {
+
+ public static void main (String[] args) throws Exception {
+ Logger logger = Logger.getLogger ("com.sun.net.httpserver");
+ ConsoleHandler c = new ConsoleHandler();
+ c.setLevel (Level.WARNING);
+ logger.addHandler (c);
+ logger.setLevel (Level.WARNING);
+ Handler handler = new Handler();
+ InetSocketAddress addr = new InetSocketAddress (0);
+ HttpServer server = HttpServer.create (addr, 0);
+ HttpContext ctx = server.createContext ("/test", handler);
+ ExecutorService executor = Executors.newCachedThreadPool();
+ server.setExecutor (executor);
+ server.start ();
+
+ URL url = new URL ("http://localhost:"+server.getAddress().getPort()+"/test/foo.html");
+ HttpURLConnection urlc = (HttpURLConnection)url.openConnection ();
+ try {
+ InputStream is = urlc.getInputStream();
+ while (is.read()!= -1) ;
+ is.close ();
+ urlc = (HttpURLConnection)url.openConnection ();
+ urlc.setReadTimeout (3000);
+ is = urlc.getInputStream();
+ while (is.read()!= -1);
+ is.close ();
+
+ } catch (IOException e) {
+ server.stop(2);
+ executor.shutdown();
+ throw new RuntimeException ("Test failed");
+ }
+ server.stop(2);
+ executor.shutdown();
+ System.out.println ("OK");
+ }
+
+ public static boolean error = false;
+
+ static class Handler implements HttpHandler {
+ int invocation = 1;
+ public void handle (HttpExchange t)
+ throws IOException
+ {
+ InputStream is = t.getRequestBody();
+ Headers map = t.getRequestHeaders();
+ Headers rmap = t.getResponseHeaders();
+ while (is.read () != -1) ;
+ is.close();
+ // send a 204 response with an empty chunked body
+ t.sendResponseHeaders (204, 0);
+ t.close();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/Double/ToString.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 4428022
+ * @summary Tests for Double.toString
+ * @author Andrew Haley <aph@redhat.com>
+ */
+
+public class ToString {
+
+ public static void main(String args[]) {
+ if (!Double.toString(0.001).equals("0.001"))
+ throw new RuntimeException("Double.toString(0.001) is not \"0.001\"");
+ if (!Double.toString(0.002).equals("0.002"))
+ throw new RuntimeException("Double.toString(0.001) is not \"0.002\"");
+ }
+}
--- a/jdk/test/java/lang/management/RuntimeMXBean/GetSystemProperties.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/lang/management/RuntimeMXBean/GetSystemProperties.java Wed Oct 28 10:37:17 2009 -0700
@@ -49,6 +49,21 @@
private static final String VALUE4 = "test.property.value4";
public static void main(String[] argv) throws Exception {
+ // Save a copy of the original system properties
+ Properties props = System.getProperties();
+
+ try {
+ // replace the system Properties object for any modification
+ // in case jtreg caches a copy
+ System.setProperties(new Properties(props));
+ runTest();
+ } finally {
+ // restore original system properties
+ System.setProperties(props);
+ }
+ }
+
+ private static void runTest() throws Exception {
RuntimeMXBean mbean = ManagementFactory.getRuntimeMXBean();
// Print all system properties
@@ -88,7 +103,10 @@
Map<String,String> props2 = mbean.getSystemProperties();
// expect the system properties returned should be
// same as the one before adding KEY3 and KEY4
- props1.equals(props2);
+ if (!props1.equals(props2)) {
+ throw new RuntimeException("Two copies of system properties " +
+ "are expected to be equal");
+ }
System.out.println("Test passed.");
}
--- a/jdk/test/java/lang/management/RuntimeMXBean/PropertiesTest.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/lang/management/RuntimeMXBean/PropertiesTest.java Wed Oct 28 10:37:17 2009 -0700
@@ -40,8 +40,21 @@
public class PropertiesTest {
private static int NUM_MYPROPS = 3;
public static void main(String[] argv) throws Exception {
- Properties sysProps = System.getProperties();
+ // Save a copy of the original system properties
+ Properties props = System.getProperties();
+ try {
+ // replace the system Properties object for any modification
+ // in case jtreg caches a copy
+ System.setProperties(new Properties(props));
+ runTest(props.size());
+ } finally {
+ // restore original system properties
+ System.setProperties(props);
+ }
+ }
+
+ private static void runTest(int sysPropsCount) throws Exception {
// Create a new system properties using the old one
// as the defaults
Properties myProps = new Properties( System.getProperties() );
@@ -65,10 +78,10 @@
System.out.println(i++ + ": " + key + " : " + value);
}
- if (props.size() != NUM_MYPROPS + sysProps.size()) {
+ if (props.size() != NUM_MYPROPS + sysPropsCount) {
throw new RuntimeException("Test Failed: " +
"Expected number of properties = " +
- NUM_MYPROPS + sysProps.size() +
+ NUM_MYPROPS + sysPropsCount +
" but found = " + props.size());
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/DefaultAccessibility.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6648344
+ * @summary Test that default accessibility is false
+ * @author Joseph D. Darcy
+ */
+
+import java.lang.reflect.*;
+
+public class DefaultAccessibility {
+ private DefaultAccessibility() {
+ super();
+ }
+
+ private static int f = 42;
+
+ public static void main(String... args) throws Exception {
+ Class<?> daClass = (new DefaultAccessibility()).getClass();
+
+ int elementCount = 0;
+ for(Constructor<?> ctor : daClass.getDeclaredConstructors()) {
+ elementCount++;
+ if (ctor.isAccessible())
+ throw new RuntimeException("Unexpected accessibility for constructor " +
+ ctor);
+ }
+
+ for(Method method : daClass.getDeclaredMethods()) {
+ elementCount++;
+ if (method.isAccessible())
+ throw new RuntimeException("Unexpected accessibility for method " +
+ method);
+ }
+
+ for(Field field : daClass.getDeclaredFields()) {
+ elementCount++;
+ if (field.isAccessible())
+ throw new RuntimeException("Unexpected accessibility for field " +
+ field);
+ }
+
+ if (elementCount < 3)
+ throw new RuntimeException("Expected at least three members; only found " +
+ elementCount);
+ }
+}
--- a/jdk/test/java/nio/file/DirectoryStream/Basic.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java Wed Oct 28 10:37:17 2009 -0700
@@ -154,8 +154,10 @@
stream.close();
// test IllegalStateException
+ dir.resolve(foo).createFile();
stream = dir.newDirectoryStream();
i = stream.iterator();
+ i.next();
try {
stream.iterator();
throw new RuntimeException("IllegalStateException not thrown as expected");
@@ -172,17 +174,26 @@
throw new RuntimeException("ConcurrentModificationException not thrown as expected");
} catch (ConcurrentModificationException x) {
Throwable t = x.getCause();
- if (!(t instanceof IllegalStateException))
- throw new RuntimeException("Cause is not IllegalStateException as expected");
+ if (!(t instanceof ClosedDirectoryStreamException))
+ throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
}
try {
i.next();
- throw new RuntimeException("IllegalStateException not thrown as expected");
+ throw new RuntimeException("ConcurrentModificationException not thrown as expected");
} catch (ConcurrentModificationException x) {
Throwable t = x.getCause();
- if (!(t instanceof IllegalStateException))
- throw new RuntimeException("Cause is not IllegalStateException as expected");
+ if (!(t instanceof ClosedDirectoryStreamException))
+ throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
}
+ try {
+ i.remove();
+ throw new RuntimeException("ConcurrentModificationException not thrown as expected");
+ } catch (ConcurrentModificationException x) {
+ Throwable t = x.getCause();
+ if (!(t instanceof ClosedDirectoryStreamException))
+ throw new RuntimeException("Cause is not ClosedDirectoryStreamException as expected");
+ }
+
}
public static void main(String[] args) throws IOException {
--- a/jdk/test/java/nio/file/Files/ContentType.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/nio/file/Files/ContentType.java Wed Oct 28 10:37:17 2009 -0700
@@ -26,7 +26,7 @@
* @summary Unit test for probeContentType method
* @library ..
* @build ContentType SimpleFileTypeDetector
- * @run main ContentType
+ * @run main/othervm ContentType
*/
import java.nio.file.*;
--- a/jdk/test/java/nio/file/Path/CheckPermissions.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/nio/file/Path/CheckPermissions.java Wed Oct 28 10:37:17 2009 -0700
@@ -25,6 +25,8 @@
* @bug 6866804
* @summary Unit test for java.nio.file.Path
* @library ..
+ * @build CheckPermissions
+ * @run main/othervm CheckPermissions
*/
import java.nio.ByteBuffer;
--- a/jdk/test/java/nio/file/Path/CopyAndMove.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/nio/file/Path/CopyAndMove.java Wed Oct 28 10:37:17 2009 -0700
@@ -92,7 +92,6 @@
{
assertTrue(attrs1.isReadOnly() == attrs2.isReadOnly());
assertTrue(attrs1.isHidden() == attrs2.isHidden());
- assertTrue(attrs1.isArchive() == attrs2.isArchive());
assertTrue(attrs1.isSystem() == attrs2.isSystem());
}
--- a/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java Fri Oct 23 18:44:33 2009 -0700
+++ b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java Wed Oct 28 10:37:17 2009 -0700
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4313887 6838333
+ * @bug 4313887 6838333 6891404
* @summary Unit test for java.nio.file.attribute.AclFileAttribueView
* @library ../..
*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Objects/BasicObjectsTest.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6797535
+ * @summary Basic tests for methods in java.util.Objects
+ * @author Joseph D. Darcy
+ */
+
+import java.util.*;
+
+public class BasicObjectsTest {
+ public static void main(String... args) {
+ int errors = 0;
+ errors += testEquals();
+ errors += testHashCode();
+ errors += testToString();
+ errors += testCompare();
+ errors += testNonNull();
+ if (errors > 0 )
+ throw new RuntimeException();
+ }
+
+ private static int testEquals() {
+ int errors = 0;
+ Object[] values = {null, "42", 42};
+ for(int i = 0; i < values.length; i++)
+ for(int j = 0; j < values.length; j++) {
+ boolean expected = (i == j);
+ Object a = values[i];
+ Object b = values[j];
+ boolean result = Objects.equals(a, b);
+ if (result != expected) {
+ errors++;
+ System.err.printf("When equating %s to %s, got %b instead of %b%n.",
+ a, b, result, expected);
+ }
+ }
+ return errors;
+ }
+
+ private static int testHashCode() {
+ int errors = 0;
+ errors += (Objects.hashCode(null) == 0 ) ? 0 : 1;
+ String s = "42";
+ errors += (Objects.hashCode(s) == s.hashCode() ) ? 0 : 1;
+ return errors;
+ }
+
+ private static int testToString() {
+ int errors = 0;
+ errors += ("null".equals(Objects.toString(null)) ) ? 0 : 1;
+ String s = "Some string";
+ errors += (s.equals(Objects.toString(s)) ) ? 0 : 1;
+ return errors;
+ }
+
+ private static int testCompare() {
+ int errors = 0;
+ String[] values = {"e. e. cummings", "zzz"};
+ String[] VALUES = {"E. E. Cummings", "ZZZ"};
+ errors += compareTest(null, null, 0);
+ for(int i = 0; i < values.length; i++) {
+ String a = values[i];
+ errors += compareTest(a, a, 0);
+ for(int j = 0; j < VALUES.length; j++) {
+ int expected = Integer.compare(i, j);
+ String b = VALUES[j];
+ errors += compareTest(a, b, expected);
+ }
+ }
+ return errors;
+ }
+
+ private static int compareTest(String a, String b, int expected) {
+ int errors = 0;
+ int result = Objects.compare(a, b, String.CASE_INSENSITIVE_ORDER);
+ if (Integer.signum(result) != Integer.signum(expected)) {
+ errors++;
+ System.err.printf("When comparing %s to %s, got %d instead of %d%n.",
+ a, b, result, expected);
+ }
+ return errors;
+ }
+
+ private static int testNonNull() {
+ int errors = 0;
+ String s;
+
+ // Test 1-arg variant
+ try {
+ s = Objects.nonNull("pants");
+ if (s != "pants") {
+ System.err.printf("1-arg non-null failed to return its arg");
+ errors++;
+ }
+ } catch (NullPointerException e) {
+ System.err.printf("1-arg nonNull threw unexpected NPE");
+ errors++;
+ }
+
+ try {
+ s = Objects.nonNull(null);
+ System.err.printf("1-arg nonNull failed to throw NPE");
+ errors++;
+ } catch (NullPointerException e) {
+ // Expected
+ }
+
+ // Test 2-arg variant
+ try {
+ s = Objects.nonNull("pants", "trousers");
+ if (s != "pants") {
+ System.err.printf("2-arg nonNull failed to return its arg");
+ errors++;
+ }
+ } catch (NullPointerException e) {
+ System.err.printf("2-arg nonNull threw unexpected NPE");
+ errors++;
+ }
+
+ try {
+ s = Objects.nonNull(null, "pantaloons");
+ System.err.printf("2-arg nonNull failed to throw NPE");
+ errors++;
+ } catch (NullPointerException e) {
+ if (e.getMessage() != "pantaloons") {
+ System.err.printf("2-arg nonNull threw NPE w/ bad detail msg");
+ errors++;
+ }
+ }
+ return errors;
+ }
+}
--- a/langtools/.hgtags Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/.hgtags Wed Oct 28 10:37:17 2009 -0700
@@ -48,3 +48,4 @@
33c8c38e1757006c17d80499fb3347102501fae5 jdk7-b71
261c54b2312ed26d6ec45c675831375460250519 jdk7-b72
9596dff460935f09684c11d156ce591f92584f0d jdk7-b73
+1a66b08deed0459054b5b1bea3dfbead30d258fa jdk7-b74
--- a/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/classfile/ConstantPool.java Wed Oct 28 10:37:17 2009 -0700
@@ -369,14 +369,33 @@
return 3;
}
+ /**
+ * Get the raw value of the class referenced by this constant pool entry.
+ * This will either be the name of the class, in internal form, or a
+ * descriptor for an array class.
+ * @return the raw value of the class
+ */
public String getName() throws ConstantPoolException {
return cp.getUTF8Value(name_index);
}
+ /**
+ * If this constant pool entry identifies either a class or interface type,
+ * or a possibly multi-dimensional array of a class of interface type,
+ * return the name of the class or interface in internal form. Otherwise,
+ * (i.e. if this is a possibly multi-dimensional array of a primitive type),
+ * return null.
+ * @return the base class or interface name
+ */
public String getBaseName() throws ConstantPoolException {
String name = getName();
- int index = name.indexOf("[L") + 1;
- return name.substring(index);
+ if (name.startsWith("[")) {
+ int index = name.indexOf("[L");
+ if (index == -1)
+ return null;
+ return name.substring(index + 2, name.length() - 1);
+ } else
+ return name;
}
public int getDimensionCount() throws ConstantPoolException {
--- a/langtools/src/share/classes/com/sun/tools/classfile/Signature.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Signature.java Wed Oct 28 10:37:17 2009 -0700
@@ -27,6 +27,7 @@
import java.util.ArrayList;
import java.util.List;
+import com.sun.tools.classfile.Type.*;
/**
* See JVMS3 4.4.4.
@@ -50,19 +51,19 @@
@Override
public int getParameterCount(ConstantPool constant_pool) throws ConstantPoolException {
- Type.MethodType m = (Type.MethodType) getType(constant_pool);
- return m.argTypes.size();
+ MethodType m = (MethodType) getType(constant_pool);
+ return m.paramTypes.size();
}
@Override
public String getParameterTypes(ConstantPool constant_pool) throws ConstantPoolException {
- Type.MethodType m = (Type.MethodType) getType(constant_pool);
+ MethodType m = (MethodType) getType(constant_pool);
StringBuilder sb = new StringBuilder();
sb.append("(");
String sep = "";
- for (Type argType: m.argTypes) {
+ for (Type paramType: m.paramTypes) {
sb.append(sep);
- sb.append(argType);
+ sb.append(paramType);
sep = ", ";
}
sb.append(")");
@@ -71,7 +72,7 @@
@Override
public String getReturnType(ConstantPool constant_pool) throws ConstantPoolException {
- Type.MethodType m = (Type.MethodType) getType(constant_pool);
+ MethodType m = (MethodType) getType(constant_pool);
return m.returnType.toString();
}
@@ -84,12 +85,12 @@
this.sig = sig;
sigp = 0;
- List<Type> typeArgTypes = null;
+ List<TypeParamType> typeParamTypes = null;
if (sig.charAt(sigp) == '<')
- typeArgTypes = parseTypeArgTypes();
+ typeParamTypes = parseTypeParamTypes();
if (sig.charAt(sigp) == '(') {
- List<Type> argTypes = parseTypeSignatures(')');
+ List<Type> paramTypes = parseTypeSignatures(')');
Type returnType = parseTypeSignature();
List<Type> throwsTypes = null;
while (sigp < sig.length() && sig.charAt(sigp) == '^') {
@@ -98,16 +99,19 @@
throwsTypes = new ArrayList<Type>();
throwsTypes.add(parseTypeSignature());
}
- return new Type.MethodType(typeArgTypes, argTypes, returnType, throwsTypes);
+ return new MethodType(typeParamTypes, paramTypes, returnType, throwsTypes);
} else {
Type t = parseTypeSignature();
- if (typeArgTypes == null && sigp == sig.length())
+ if (typeParamTypes == null && sigp == sig.length())
return t;
Type superclass = t;
- List<Type> superinterfaces = new ArrayList<Type>();
- while (sigp < sig.length())
+ List<Type> superinterfaces = null;
+ while (sigp < sig.length()) {
+ if (superinterfaces == null)
+ superinterfaces = new ArrayList<Type>();
superinterfaces.add(parseTypeSignature());
- return new Type.ClassSigType(typeArgTypes, superclass, superinterfaces);
+ }
+ return new ClassSigType(typeParamTypes, superclass, superinterfaces);
}
}
@@ -116,61 +120,61 @@
switch (sig.charAt(sigp)) {
case 'B':
sigp++;
- return new Type.SimpleType("byte");
+ return new SimpleType("byte");
case 'C':
sigp++;
- return new Type.SimpleType("char");
+ return new SimpleType("char");
case 'D':
sigp++;
- return new Type.SimpleType("double");
+ return new SimpleType("double");
case 'F':
sigp++;
- return new Type.SimpleType("float");
+ return new SimpleType("float");
case 'I':
sigp++;
- return new Type.SimpleType("int");
+ return new SimpleType("int");
case 'J':
sigp++;
- return new Type.SimpleType("long");
+ return new SimpleType("long");
case 'L':
return parseClassTypeSignature();
case 'S':
sigp++;
- return new Type.SimpleType("short");
+ return new SimpleType("short");
case 'T':
return parseTypeVariableSignature();
case 'V':
sigp++;
- return new Type.SimpleType("void");
+ return new SimpleType("void");
case 'Z':
sigp++;
- return new Type.SimpleType("boolean");
+ return new SimpleType("boolean");
case '[':
sigp++;
- return new Type.ArrayType(parseTypeSignature());
+ return new ArrayType(parseTypeSignature());
case '*':
sigp++;
- return new Type.WildcardType();
+ return new WildcardType();
case '+':
sigp++;
- return new Type.WildcardType("extends", parseTypeSignature());
+ return new WildcardType(WildcardType.Kind.EXTENDS, parseTypeSignature());
case '-':
sigp++;
- return new Type.WildcardType("super", parseTypeSignature());
+ return new WildcardType(WildcardType.Kind.SUPER, parseTypeSignature());
default:
throw new IllegalStateException(debugInfo());
@@ -194,30 +198,22 @@
private Type parseClassTypeSignatureRest() {
StringBuilder sb = new StringBuilder();
- Type t = null;
- char sigch;
- while (true) {
+ List<Type> argTypes = null;
+ ClassType t = null;
+ char sigch ;
+
+ do {
switch (sigch = sig.charAt(sigp)) {
- case '/':
- sigp++;
- sb.append(".");
+ case '<':
+ argTypes = parseTypeSignatures('>');
break;
case '.':
- sigp++;
- if (t == null)
- t = new Type.SimpleType(sb.toString());
- return new Type.InnerClassType(t, parseClassTypeSignatureRest());
-
case ';':
sigp++;
- if (t == null)
- t = new Type.SimpleType(sb.toString());
- return t;
-
- case '<':
- List<Type> argTypes = parseTypeSignatures('>');
- t = new Type.ClassType(sb.toString(), argTypes);
+ t = new ClassType(t, sb.toString(), argTypes);
+ sb.setLength(0);
+ argTypes = null;
break;
default:
@@ -225,21 +221,22 @@
sb.append(sigch);
break;
}
- }
+ } while (sigch != ';');
+
+ return t;
}
- private List<Type> parseTypeArgTypes() {
+ private List<TypeParamType> parseTypeParamTypes() {
assert sig.charAt(sigp) == '<';
sigp++;
- List<Type> types = null;
- types = new ArrayList<Type>();
+ List<TypeParamType> types = new ArrayList<TypeParamType>();
while (sig.charAt(sigp) != '>')
- types.add(parseTypeArgType());
+ types.add(parseTypeParamType());
sigp++;
return types;
}
- private Type parseTypeArgType() {
+ private TypeParamType parseTypeParamType() {
int sep = sig.indexOf(":", sigp);
String name = sig.substring(sigp, sep);
Type classBound = null;
@@ -253,13 +250,13 @@
interfaceBounds = new ArrayList<Type>();
interfaceBounds.add(parseTypeSignature());
}
- return new Type.TypeArgType(name, classBound, interfaceBounds);
+ return new TypeParamType(name, classBound, interfaceBounds);
}
private Type parseTypeVariableSignature() {
sigp++;
int sep = sig.indexOf(';', sigp);
- Type t = new Type.SimpleType(sig.substring(sigp, sep));
+ Type t = new SimpleType(sig.substring(sigp, sep));
sigp = sep + 1;
return t;
}
--- a/langtools/src/share/classes/com/sun/tools/classfile/Type.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/classfile/Type.java Wed Oct 28 10:37:17 2009 -0700
@@ -31,6 +31,9 @@
import java.util.Set;
/*
+ * Family of classes used to represent the parsed form of a {@link Descriptor}
+ * or {@link Signature}.
+ *
* <p><b>This is NOT part of any API supported by Sun Microsystems. If
* you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
@@ -62,11 +65,26 @@
R visitMethodType(MethodType type, P p);
R visitClassSigType(ClassSigType type, P p);
R visitClassType(ClassType type, P p);
- R visitInnerClassType(InnerClassType type, P p);
- R visitTypeArgType(TypeArgType type, P p);
+ R visitTypeParamType(TypeParamType type, P p);
R visitWildcardType(WildcardType type, P p);
}
+ /**
+ * Represents a type signature with a simple name. The name may be that of a
+ * primitive type, such "{@code int}, {@code float}, etc
+ * or that of a type argument, such as {@code T}, {@code K}, {@code V}, etc.
+ *
+ * See:
+ * JVMS 4.3.2
+ * BaseType:
+ * {@code B}, {@code C}, {@code D}, {@code F}, {@code I},
+ * {@code J}, {@code S}, {@code Z};
+ * VoidDescriptor:
+ * {@code V};
+ * JVMS 4.3.4
+ * TypeVariableSignature:
+ * {@code T} Identifier {@code ;}
+ */
public static class SimpleType extends Type {
public SimpleType(String name) {
this.name = name;
@@ -91,6 +109,14 @@
public final String name;
}
+ /**
+ * Represents an array type signature.
+ *
+ * See:
+ * JVMS 4.3.4
+ * ArrayTypeSignature:
+ * {@code [} TypeSignature {@code ]}
+ */
public static class ArrayType extends Type {
public ArrayType(Type elemType) {
this.elemType = elemType;
@@ -108,17 +134,26 @@
public final Type elemType;
}
+ /**
+ * Represents a method type signature.
+ *
+ * See;
+ * JVMS 4.3.4
+ * MethodTypeSignature:
+ * FormalTypeParameters_opt {@code (} TypeSignature* {@code)} ReturnType
+ * ThrowsSignature*
+ */
public static class MethodType extends Type {
- public MethodType(List<? extends Type> argTypes, Type resultType) {
- this(null, argTypes, resultType, null);
+ public MethodType(List<? extends Type> paramTypes, Type resultType) {
+ this(null, paramTypes, resultType, null);
}
- public MethodType(List<? extends Type> typeArgTypes,
- List<? extends Type> argTypes,
+ public MethodType(List<? extends TypeParamType> typeParamTypes,
+ List<? extends Type> paramTypes,
Type returnType,
List<? extends Type> throwsTypes) {
- this.typeArgTypes = typeArgTypes;
- this.argTypes = argTypes;
+ this.typeParamTypes = typeParamTypes;
+ this.paramTypes = paramTypes;
this.returnType = returnType;
this.throwsTypes = throwsTypes;
}
@@ -130,22 +165,32 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- appendIfNotEmpty(sb, "<", typeArgTypes, "> ");
+ appendIfNotEmpty(sb, "<", typeParamTypes, "> ");
sb.append(returnType);
- append(sb, " (", argTypes, ")");
+ append(sb, " (", paramTypes, ")");
appendIfNotEmpty(sb, " throws ", throwsTypes, "");
return sb.toString();
}
- public final List<? extends Type> typeArgTypes;
- public final List<? extends Type> argTypes;
+ public final List<? extends TypeParamType> typeParamTypes;
+ public final List<? extends Type> paramTypes;
public final Type returnType;
public final List<? extends Type> throwsTypes;
}
+ /**
+ * Represents a class signature. These describe the signature of
+ * a class that has type arguments.
+ *
+ * See:
+ * JVMS 4.3.4
+ * ClassSignature:
+ * FormalTypeParameters_opt SuperclassSignature SuperinterfaceSignature*
+ */
public static class ClassSigType extends Type {
- public ClassSigType(List<Type> typeArgTypes, Type superclassType, List<Type> superinterfaceTypes) {
- this.typeArgTypes = typeArgTypes;
+ public ClassSigType(List<TypeParamType> typeParamTypes, Type superclassType,
+ List<Type> superinterfaceTypes) {
+ this.typeParamTypes = typeParamTypes;
this.superclassType = superclassType;
this.superinterfaceTypes = superinterfaceTypes;
}
@@ -157,7 +202,7 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- appendIfNotEmpty(sb, "<", typeArgTypes, ">");
+ appendIfNotEmpty(sb, "<", typeParamTypes, ">");
if (superclassType != null) {
sb.append(" extends ");
sb.append(superclassType);
@@ -166,13 +211,30 @@
return sb.toString();
}
- public final List<Type> typeArgTypes;
+ public final List<TypeParamType> typeParamTypes;
public final Type superclassType;
public final List<Type> superinterfaceTypes;
}
+ /**
+ * Represents a class type signature. This is used to represent a
+ * reference to a class, such as in a field, parameter, return type, etc.
+ *
+ * See:
+ * JVMS 4.3.4
+ * ClassTypeSignature:
+ * {@code L} PackageSpecifier_opt SimpleClassTypeSignature
+ * ClassTypeSignatureSuffix* {@code ;}
+ * PackageSpecifier:
+ * Identifier {@code /} PackageSpecifier*
+ * SimpleClassTypeSignature:
+ * Identifier TypeArguments_opt }
+ * ClassTypeSignatureSuffix:
+ * {@code .} SimpleClassTypeSignature
+ */
public static class ClassType extends Type {
- public ClassType(String name, List<Type> typeArgs) {
+ public ClassType(ClassType outerType, String name, List<Type> typeArgs) {
+ this.outerType = outerType;
this.name = name;
this.typeArgs = typeArgs;
}
@@ -181,47 +243,54 @@
return visitor.visitClassType(this, data);
}
+ public String getBinaryName() {
+ if (outerType == null)
+ return name;
+ else
+ return (outerType.getBinaryName() + "$" + name);
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
+ if (outerType != null) {
+ sb.append(outerType);
+ sb.append(".");
+ }
sb.append(name);
appendIfNotEmpty(sb, "<", typeArgs, ">");
return sb.toString();
}
+ public final ClassType outerType;
public final String name;
public final List<Type> typeArgs;
}
-
- public static class InnerClassType extends Type {
- public InnerClassType(Type outerType, Type innerType) {
- this.outerType = outerType;
- this.innerType = innerType;
- }
-
- public <R, D> R accept(Visitor<R, D> visitor, D data) {
- return visitor.visitInnerClassType(this, data);
- }
-
- @Override
- public String toString() {
- return outerType + "." + innerType;
- }
-
- public final Type outerType;
- public final Type innerType;
- }
-
- public static class TypeArgType extends Type {
- public TypeArgType(String name, Type classBound, List<Type> interfaceBounds) {
+ /**
+ * Represents a FormalTypeParameter. These are used to declare the type
+ * parameters for generic classes and methods.
+ *
+ * See:
+ * JVMS 4.3.4
+ * FormalTypeParameters:
+ * {@code <} FormalTypeParameter+ {@code >}
+ * FormalTypeParameter:
+ * Identifier ClassBound InterfaceBound*
+ * ClassBound:
+ * {@code :} FieldTypeSignature_opt
+ * InterfaceBound:
+ * {@code :} FieldTypeSignature
+ */
+ public static class TypeParamType extends Type {
+ public TypeParamType(String name, Type classBound, List<Type> interfaceBounds) {
this.name = name;
this.classBound = classBound;
this.interfaceBounds = interfaceBounds;
}
public <R, D> R accept(Visitor<R, D> visitor, D data) {
- return visitor.visitTypeArgType(this, data);
+ return visitor.visitTypeParamType(this, data);
}
@Override
@@ -249,12 +318,25 @@
public final List<Type> interfaceBounds;
}
+ /**
+ * Represents a wildcard type argument. A type argument that is not a
+ * wildcard type argument will be represented by a ClassType, ArrayType, etc.
+ *
+ * See:
+ * JVMS 4.3.4
+ * TypeArgument:
+ * WildcardIndicator_opt FieldTypeSignature
+ * {@code *}
+ * WildcardIndicator:
+ * {@code +}
+ * {@code -}
+ */
public static class WildcardType extends Type {
+ public enum Kind { UNBOUNDED, EXTENDS, SUPER };
public WildcardType() {
- this(null, null);
+ this(Kind.UNBOUNDED, null);
}
-
- public WildcardType(String kind, Type boundType) {
+ public WildcardType(Kind kind, Type boundType) {
this.kind = kind;
this.boundType = boundType;
}
@@ -265,13 +347,19 @@
@Override
public String toString() {
- if (kind == null)
- return "?";
- else
- return "? " + kind + " " + boundType;
+ switch (kind) {
+ case UNBOUNDED:
+ return "?";
+ case EXTENDS:
+ return "? extends " + boundType;
+ case SUPER:
+ return "? super " + boundType;
+ default:
+ throw new AssertionError();
+ }
}
- public final String kind;
+ public final Kind kind;
public final Type boundType;
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/code/Symbol.java Wed Oct 28 10:37:17 2009 -0700
@@ -1212,25 +1212,58 @@
public List<VarSymbol> params() {
owner.complete();
if (params == null) {
- List<Name> names = savedParameterNames;
+ // If ClassReader.saveParameterNames has been set true, then
+ // savedParameterNames will be set to a list of names that
+ // matches the types in type.getParameterTypes(). If any names
+ // were not found in the class file, those names in the list will
+ // be set to the empty name.
+ // If ClassReader.saveParameterNames has been set false, then
+ // savedParameterNames will be null.
+ List<Name> paramNames = savedParameterNames;
savedParameterNames = null;
- if (names == null) {
- names = List.nil();
- int i = 0;
- for (Type t : type.getParameterTypes())
- names = names.prepend(name.table.fromString("arg" + i++));
- names = names.reverse();
- }
+ // discard the provided names if the list of names is the wrong size.
+ if (paramNames == null || paramNames.size() != type.getParameterTypes().size())
+ paramNames = List.nil();
ListBuffer<VarSymbol> buf = new ListBuffer<VarSymbol>();
+ List<Name> remaining = paramNames;
+ // assert: remaining and paramNames are both empty or both
+ // have same cardinality as type.getParameterTypes()
+ int i = 0;
for (Type t : type.getParameterTypes()) {
- buf.append(new VarSymbol(PARAMETER, names.head, t, this));
- names = names.tail;
+ Name paramName;
+ if (remaining.isEmpty()) {
+ // no names for any parameters available
+ paramName = createArgName(i, paramNames);
+ } else {
+ paramName = remaining.head;
+ remaining = remaining.tail;
+ if (paramName.isEmpty()) {
+ // no name for this specific parameter
+ paramName = createArgName(i, paramNames);
+ }
+ }
+ buf.append(new VarSymbol(PARAMETER, paramName, t, this));
+ i++;
}
params = buf.toList();
}
return params;
}
+ // Create a name for the argument at position 'index' that is not in
+ // the exclude list. In normal use, either no names will have been
+ // provided, in which case the exclude list is empty, or all the names
+ // will have been provided, in which case this method will not be called.
+ private Name createArgName(int index, List<Name> exclude) {
+ String prefix = "arg";
+ while (true) {
+ Name argName = name.table.fromString(prefix + index);
+ if (!exclude.contains(argName))
+ return argName;
+ prefix += "$";
+ }
+ }
+
public Symbol asMemberOf(Type site, Types types) {
return new MethodSymbol(flags_field, name, types.memberType(site, this), owner);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/BaseFileObject.java Wed Oct 28 10:37:17 2009 -0700
@@ -120,6 +120,14 @@
}
+ // force subtypes to define equals
+ @Override
+ public abstract boolean equals(Object other);
+
+ // force subtypes to define hashCode
+ @Override
+ public abstract int hashCode();
+
/** The file manager that created this JavaFileObject. */
protected final JavacFileManager fileManager;
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/JavacFileManager.java Wed Oct 28 10:37:17 2009 -0700
@@ -968,7 +968,7 @@
} else {
File siblingDir = null;
if (sibling != null && sibling instanceof RegularFileObject) {
- siblingDir = ((RegularFileObject)sibling).f.getParentFile();
+ siblingDir = ((RegularFileObject)sibling).file.getParentFile();
}
return new RegularFileObject(this, new File(siblingDir, fileName.basename()));
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/RegularFileObject.java Wed Oct 28 10:37:17 2009 -0700
@@ -33,6 +33,8 @@
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
@@ -53,7 +55,8 @@
*/
private boolean hasParents = false;
private String name;
- final File f;
+ final File file;
+ private Reference<File> absFileRef;
public RegularFileObject(JavacFileManager fileManager, File f) {
this(fileManager, f.getName(), f);
@@ -65,17 +68,17 @@
throw new IllegalArgumentException("directories not supported");
}
this.name = name;
- this.f = f;
+ this.file = f;
}
@Override
public URI toUri() {
- return f.toURI().normalize();
+ return file.toURI().normalize();
}
@Override
public String getName() {
- return f.getPath();
+ return file.getPath();
}
@Override
@@ -90,20 +93,20 @@
@Override
public InputStream openInputStream() throws IOException {
- return new FileInputStream(f);
+ return new FileInputStream(file);
}
@Override
public OutputStream openOutputStream() throws IOException {
ensureParentDirectoriesExist();
- return new FileOutputStream(f);
+ return new FileOutputStream(file);
}
@Override
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
- InputStream in = new FileInputStream(f);
+ InputStream in = new FileInputStream(file);
try {
ByteBuffer bb = fileManager.makeByteBuffer(in);
JavaFileObject prev = fileManager.log.useSource(this);
@@ -126,17 +129,17 @@
@Override
public Writer openWriter() throws IOException {
ensureParentDirectoriesExist();
- return new OutputStreamWriter(new FileOutputStream(f), fileManager.getEncodingName());
+ return new OutputStreamWriter(new FileOutputStream(file), fileManager.getEncodingName());
}
@Override
public long getLastModified() {
- return f.lastModified();
+ return file.lastModified();
}
@Override
public boolean delete() {
- return f.delete();
+ return file.delete();
}
@Override
@@ -146,7 +149,7 @@
@Override
protected String inferBinaryName(Iterable<? extends File> path) {
- String fPath = f.getPath();
+ String fPath = file.getPath();
//System.err.println("RegularFileObject " + file + " " +r.getPath());
for (File dir: path) {
//System.err.println("dir: " + dir);
@@ -178,7 +181,7 @@
if (name.equalsIgnoreCase(n)) {
try {
// allow for Windows
- return f.getCanonicalFile().getName().equals(n);
+ return file.getCanonicalFile().getName().equals(n);
} catch (IOException e) {
}
}
@@ -187,7 +190,7 @@
private void ensureParentDirectoriesExist() throws IOException {
if (!hasParents) {
- File parent = f.getParentFile();
+ File parent = file.getParentFile();
if (parent != null && !parent.exists()) {
if (!parent.mkdirs()) {
if (!parent.exists() || !parent.isDirectory()) {
@@ -199,21 +202,34 @@
}
}
+ /**
+ * Check if two file objects are equal.
+ * Two RegularFileObjects are equal if the absolute paths of the underlying
+ * files are equal.
+ */
@Override
public boolean equals(Object other) {
- if (!(other instanceof RegularFileObject)) {
+ if (this == other)
+ return true;
+
+ if (!(other instanceof RegularFileObject))
return false;
- }
+
RegularFileObject o = (RegularFileObject) other;
- try {
- return f.equals(o.f) || f.getCanonicalFile().equals(o.f.getCanonicalFile());
- } catch (IOException e) {
- return false;
- }
+ return getAbsoluteFile().equals(o.getAbsoluteFile());
}
@Override
public int hashCode() {
- return f.hashCode();
+ return getAbsoluteFile().hashCode();
+ }
+
+ private File getAbsoluteFile() {
+ File absFile = (absFileRef == null ? null : absFileRef.get());
+ if (absFile == null) {
+ absFile = file.getAbsoluteFile();
+ absFileRef = new SoftReference<File>(absFile);
+ }
+ return absFile;
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/SymbolArchive.java Wed Oct 28 10:37:17 2009 -0700
@@ -76,13 +76,13 @@
@Override
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
RelativeDirectory prefix_subdir = new RelativeDirectory(prefix, subdirectory.path);
- ZipEntry ze = new RelativeFile(prefix_subdir, file).getZipEntry(zdir);
+ ZipEntry ze = new RelativeFile(prefix_subdir, file).getZipEntry(zfile);
return new SymbolFileObject(this, file, ze);
}
@Override
public String toString() {
- return "SymbolArchive[" + zdir.getName() + "]";
+ return "SymbolArchive[" + zfile.getName() + "]";
}
/**
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipArchive.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipArchive.java Wed Oct 28 10:37:17 2009 -0700
@@ -47,6 +47,8 @@
import com.sun.tools.javac.file.RelativePath.RelativeDirectory;
import com.sun.tools.javac.file.RelativePath.RelativeFile;
import com.sun.tools.javac.util.List;
+import java.lang.ref.Reference;
+import java.lang.ref.SoftReference;
/**
* <p><b>This is NOT part of any API supported by Sun Microsystems.
@@ -56,20 +58,20 @@
*/
public class ZipArchive implements Archive {
- public ZipArchive(JavacFileManager fm, ZipFile zdir) throws IOException {
- this(fm, zdir, true);
+ public ZipArchive(JavacFileManager fm, ZipFile zfile) throws IOException {
+ this(fm, zfile, true);
}
- protected ZipArchive(JavacFileManager fm, ZipFile zdir, boolean initMap) throws IOException {
+ protected ZipArchive(JavacFileManager fm, ZipFile zfile, boolean initMap) throws IOException {
this.fileManager = fm;
- this.zdir = zdir;
+ this.zfile = zfile;
this.map = new HashMap<RelativeDirectory,List<String>>();
if (initMap)
initMap();
}
protected void initMap() throws IOException {
- for (Enumeration<? extends ZipEntry> e = zdir.entries(); e.hasMoreElements(); ) {
+ for (Enumeration<? extends ZipEntry> e = zfile.entries(); e.hasMoreElements(); ) {
ZipEntry entry;
try {
entry = e.nextElement();
@@ -110,7 +112,7 @@
}
public JavaFileObject getFileObject(RelativeDirectory subdirectory, String file) {
- ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zdir);
+ ZipEntry ze = new RelativeFile(subdirectory, file).getZipEntry(zfile);
return new ZipFileObject(this, file, ze);
}
@@ -119,17 +121,39 @@
}
public void close() throws IOException {
- zdir.close();
+ zfile.close();
}
@Override
public String toString() {
- return "ZipArchive[" + zdir.getName() + "]";
+ return "ZipArchive[" + zfile.getName() + "]";
+ }
+
+ private File getAbsoluteFile() {
+ File absFile = (absFileRef == null ? null : absFileRef.get());
+ if (absFile == null) {
+ absFile = new File(zfile.getName()).getAbsoluteFile();
+ absFileRef = new SoftReference<File>(absFile);
+ }
+ return absFile;
}
+ /**
+ * The file manager that created this archive.
+ */
protected JavacFileManager fileManager;
+ /**
+ * The index for the contents of this archive.
+ */
protected final Map<RelativeDirectory,List<String>> map;
- protected final ZipFile zdir;
+ /**
+ * The zip file for the archive.
+ */
+ protected final ZipFile zfile;
+ /**
+ * A reference to the absolute filename for the zip file for the archive.
+ */
+ protected Reference<File> absFileRef;
/**
* A subclass of JavaFileObject representing zip entries.
@@ -148,18 +172,18 @@
}
public URI toUri() {
- File zipFile = new File(zarch.zdir.getName());
+ File zipFile = new File(zarch.zfile.getName());
return createJarUri(zipFile, entry.getName());
}
@Override
public String getName() {
- return zarch.zdir.getName() + "(" + entry.getName() + ")";
+ return zarch.zfile.getName() + "(" + entry.getName() + ")";
}
@Override
public String getShortName() {
- return new File(zarch.zdir.getName()).getName() + "(" + entry + ")";
+ return new File(zarch.zfile.getName()).getName() + "(" + entry + ")";
}
@Override
@@ -169,7 +193,7 @@
@Override
public InputStream openInputStream() throws IOException {
- return zarch.zdir.getInputStream(entry);
+ return zarch.zfile.getInputStream(entry);
}
@Override
@@ -181,7 +205,7 @@
public CharBuffer getCharContent(boolean ignoreEncodingErrors) throws IOException {
CharBuffer cb = fileManager.getCachedContent(this);
if (cb == null) {
- InputStream in = zarch.zdir.getInputStream(entry);
+ InputStream in = zarch.zfile.getInputStream(entry);
try {
ByteBuffer bb = fileManager.makeByteBuffer(in);
JavaFileObject prev = fileManager.log.useSource(this);
@@ -237,18 +261,27 @@
return name.equals(cn + k.extension);
}
+ /**
+ * Check if two file objects are equal.
+ * Two ZipFileObjects are equal if the absolute paths of the underlying
+ * zip files are equal and if the paths within those zip files are equal.
+ */
@Override
public boolean equals(Object other) {
- if (!(other instanceof ZipFileObject)) {
+ if (this == other)
+ return true;
+
+ if (!(other instanceof ZipFileObject))
return false;
- }
+
ZipFileObject o = (ZipFileObject) other;
- return zarch.zdir.equals(o.zarch.zdir) || name.equals(o.name);
+ return zarch.getAbsoluteFile().equals(o.zarch.getAbsoluteFile())
+ && name.equals(o.name);
}
@Override
public int hashCode() {
- return zarch.zdir.hashCode() + name.hashCode();
+ return zarch.getAbsoluteFile().hashCode() + name.hashCode();
}
}
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndex.java Wed Oct 28 10:37:17 2009 -0700
@@ -30,6 +30,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
+import java.lang.ref.Reference;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.Arrays;
@@ -89,6 +90,7 @@
// ZipFileIndex data entries
private File zipFile;
+ private Reference<File> absFileRef;
private long zipFileLastModified = NOT_MODIFIED;
private RandomAccessFile zipRandomFile;
private Entry[] entries;
@@ -1215,6 +1217,15 @@
return zipFile;
}
+ File getAbsoluteFile() {
+ File absFile = (absFileRef == null ? null : absFileRef.get());
+ if (absFile == null) {
+ absFile = zipFile.getAbsoluteFile();
+ absFileRef = new SoftReference<File>(absFile);
+ }
+ return absFile;
+ }
+
private RelativeDirectory getRelativeDirectory(String path) {
RelativeDirectory rd;
SoftReference<RelativeDirectory> ref = relativeDirectoryCache.get(path);
--- a/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/file/ZipFileIndexArchive.java Wed Oct 28 10:37:17 2009 -0700
@@ -219,17 +219,27 @@
return name.equals(cn + k.extension);
}
+ /**
+ * Check if two file objects are equal.
+ * Two ZipFileIndexFileObjects are equal if the absolute paths of the underlying
+ * zip files are equal and if the paths within those zip files are equal.
+ */
@Override
public boolean equals(Object other) {
+ if (this == other)
+ return true;
+
if (!(other instanceof ZipFileIndexFileObject))
return false;
+
ZipFileIndexFileObject o = (ZipFileIndexFileObject) other;
- return entry.equals(o.entry);
+ return zfIndex.getAbsoluteFile().equals(o.zfIndex.getAbsoluteFile())
+ && name.equals(o.name);
}
@Override
public int hashCode() {
- return zipName.hashCode() + (name.hashCode() << 10);
+ return zfIndex.getAbsoluteFile().hashCode() + name.hashCode();
}
private String getPrefixedEntryName() {
--- a/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/jvm/ClassReader.java Wed Oct 28 10:37:17 2009 -0700
@@ -29,6 +29,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.CharBuffer;
+import java.util.Arrays;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
@@ -191,6 +192,16 @@
*/
boolean debugJSR308;
+ /** A table to hold the constant pool indices for method parameter
+ * names, as given in LocalVariableTable attributes.
+ */
+ int[] parameterNameIndices;
+
+ /**
+ * Whether or not any parameter names have been found.
+ */
+ boolean haveParameterNameIndices;
+
/** Get the ClassReader instance for this invocation. */
public static ClassReader instance(Context context) {
ClassReader instance = context.get(classReaderKey);
@@ -922,32 +933,33 @@
void read(Symbol sym, int attrLen) {
int newbp = bp + attrLen;
if (saveParameterNames) {
- // pick up parameter names from the variable table
- List<Name> parameterNames = List.nil();
- int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
- int endParam = firstParam + Code.width(sym.type.getParameterTypes());
+ // Pick up parameter names from the variable table.
+ // Parameter names are not explicitly identified as such,
+ // but all parameter name entries in the LocalVariableTable
+ // have a start_pc of 0. Therefore, we record the name
+ // indicies of all slots with a start_pc of zero in the
+ // parameterNameIndicies array.
+ // Note that this implicitly honors the JVMS spec that
+ // there may be more than one LocalVariableTable, and that
+ // there is no specified ordering for the entries.
int numEntries = nextChar();
- for (int i=0; i<numEntries; i++) {
+ for (int i = 0; i < numEntries; i++) {
int start_pc = nextChar();
int length = nextChar();
int nameIndex = nextChar();
int sigIndex = nextChar();
int register = nextChar();
- if (start_pc == 0 &&
- firstParam <= register &&
- register < endParam) {
- int index = firstParam;
- for (Type t : sym.type.getParameterTypes()) {
- if (index == register) {
- parameterNames = parameterNames.prepend(readName(nameIndex));
- break;
- }
- index += Code.width(t);
+ if (start_pc == 0) {
+ // ensure array large enough
+ if (register >= parameterNameIndices.length) {
+ int newSize = Math.max(register, parameterNameIndices.length + 8);
+ parameterNameIndices =
+ Arrays.copyOf(parameterNameIndices, newSize);
}
+ parameterNameIndices[register] = nameIndex;
+ haveParameterNameIndices = true;
}
}
- parameterNames = parameterNames.reverse();
- ((MethodSymbol)sym).savedParameterNames = parameterNames;
}
bp = newbp;
}
@@ -1839,6 +1851,8 @@
syms.methodClass);
}
MethodSymbol m = new MethodSymbol(flags, name, type, currentOwner);
+ if (saveParameterNames)
+ initParameterNames(m);
Symbol prevOwner = currentOwner;
currentOwner = m;
try {
@@ -1846,9 +1860,90 @@
} finally {
currentOwner = prevOwner;
}
+ if (saveParameterNames)
+ setParameterNames(m, type);
return m;
}
+ /**
+ * Init the parameter names array.
+ * Parameter names are currently inferred from the names in the
+ * LocalVariableTable attributes of a Code attribute.
+ * (Note: this means parameter names are currently not available for
+ * methods without a Code attribute.)
+ * This method initializes an array in which to store the name indexes
+ * of parameter names found in LocalVariableTable attributes. It is
+ * slightly supersized to allow for additional slots with a start_pc of 0.
+ */
+ void initParameterNames(MethodSymbol sym) {
+ // make allowance for synthetic parameters.
+ final int excessSlots = 4;
+ int expectedParameterSlots =
+ Code.width(sym.type.getParameterTypes()) + excessSlots;
+ if (parameterNameIndices == null
+ || parameterNameIndices.length < expectedParameterSlots) {
+ parameterNameIndices = new int[expectedParameterSlots];
+ } else
+ Arrays.fill(parameterNameIndices, 0);
+ haveParameterNameIndices = false;
+ }
+
+ /**
+ * Set the parameter names for a symbol from the name index in the
+ * parameterNameIndicies array. The type of the symbol may have changed
+ * while reading the method attributes (see the Signature attribute).
+ * This may be because of generic information or because anonymous
+ * synthetic parameters were added. The original type (as read from
+ * the method descriptor) is used to help guess the existence of
+ * anonymous synthetic parameters.
+ * On completion, sym.savedParameter names will either be null (if
+ * no parameter names were found in the class file) or will be set to a
+ * list of names, one per entry in sym.type.getParameterTypes, with
+ * any missing names represented by the empty name.
+ */
+ void setParameterNames(MethodSymbol sym, Type jvmType) {
+ // if no names were found in the class file, there's nothing more to do
+ if (!haveParameterNameIndices)
+ return;
+
+ int firstParam = ((sym.flags() & STATIC) == 0) ? 1 : 0;
+ // the code in readMethod may have skipped the first parameter when
+ // setting up the MethodType. If so, we make a corresponding allowance
+ // here for the position of the first parameter. Note that this
+ // assumes the skipped parameter has a width of 1 -- i.e. it is not
+ // a double width type (long or double.)
+ if (sym.name == names.init && currentOwner.hasOuterInstance()) {
+ // Sometimes anonymous classes don't have an outer
+ // instance, however, there is no reliable way to tell so
+ // we never strip this$n
+ if (!currentOwner.name.isEmpty())
+ firstParam += 1;
+ }
+
+ if (sym.type != jvmType) {
+ // reading the method attributes has caused the symbol's type to
+ // be changed. (i.e. the Signature attribute.) This may happen if
+ // there are hidden (synthetic) parameters in the descriptor, but
+ // not in the Signature. The position of these hidden parameters
+ // is unspecified; for now, assume they are at the beginning, and
+ // so skip over them. The primary case for this is two hidden
+ // parameters passed into Enum constructors.
+ int skip = Code.width(jvmType.getParameterTypes())
+ - Code.width(sym.type.getParameterTypes());
+ firstParam += skip;
+ }
+ List<Name> paramNames = List.nil();
+ int index = firstParam;
+ for (Type t: sym.type.getParameterTypes()) {
+ int nameIdx = (index < parameterNameIndices.length
+ ? parameterNameIndices[index] : 0);
+ Name name = nameIdx == 0 ? names.empty : readName(nameIdx);
+ paramNames = paramNames.prepend(name);
+ index += Code.width(t);
+ }
+ sym.savedParameterNames = paramNames.reverse();
+ }
+
/** Skip a field or method
*/
void skipMember() {
@@ -2632,10 +2727,20 @@
return true; // fail-safe mode
}
+ /**
+ * Check if two file objects are equal.
+ * SourceFileObjects are just placeholder objects for the value of a
+ * SourceFile attribute, and do not directly represent specific files.
+ * Two SourceFileObjects are equal if their names are equal.
+ */
@Override
public boolean equals(Object other) {
+ if (this == other)
+ return true;
+
if (!(other instanceof SourceFileObject))
return false;
+
SourceFileObject o = (SourceFileObject) other;
return name.equals(o.name);
}
--- a/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/parser/Scanner.java Wed Oct 28 10:37:17 2009 -0700
@@ -876,7 +876,11 @@
}
scanChar();
skipIllegalUnderscores();
- scanNumber(2);
+ if (digit(2) < 0) {
+ lexError("invalid.binary.number");
+ } else {
+ scanNumber(2);
+ }
} else {
putChar('0');
if (ch == '_') {
--- a/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javac/resources/compiler.properties Wed Oct 28 10:37:17 2009 -0700
@@ -252,6 +252,8 @@
interface methods cannot have body
compiler.err.invalid.annotation.member.type=\
invalid type for annotation member
+compiler.err.invalid.binary.number=\
+ binary numbers must contain at least one binary digit
compiler.err.invalid.hex.number=\
hexadecimal numbers must contain at least one hexadecimal digit
compiler.err.invalid.meth.decl.ret.type.req=\
--- a/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/ClassWriter.java Wed Oct 28 10:37:17 2009 -0700
@@ -179,10 +179,10 @@
// The signature parser cannot disambiguate between a
// FieldType and a ClassSignatureType that only contains a superclass type.
if (t instanceof Type.ClassSigType)
- print(t);
+ print(getJavaName(t.toString()));
else {
print(" extends ");
- print(t);
+ print(getJavaName(t.toString()));
}
} catch (ConstantPoolException e) {
print(report(e));
@@ -310,7 +310,7 @@
writeModifiers(flags.getMethodModifiers());
if (methodType != null) {
- writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
+ writeListIfNotEmpty("<", methodType.typeParamTypes, "> ");
}
if (getName(m).equals("<init>")) {
print(getJavaName(classFile));
--- a/langtools/src/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/com/sun/tools/javap/LocalVariableTypeTableWriter.java Wed Oct 28 10:37:17 2009 -0700
@@ -125,7 +125,7 @@
print(" // ");
Descriptor d = new Signature(entry.signature_index);
try {
- print(d.getFieldType(constant_pool));
+ print(d.getFieldType(constant_pool).toString().replace("/", "."));
} catch (InvalidDescriptor e) {
print(report(e));
} catch (ConstantPoolException e) {
--- a/langtools/src/share/classes/javax/lang/model/util/Elements.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/src/share/classes/javax/lang/model/util/Elements.java Wed Oct 28 10:37:17 2009 -0700
@@ -77,9 +77,25 @@
* Returns the text of the documentation ("Javadoc")
* comment of an element.
*
+ * <p> A documentation comment of an element is a comment that
+ * begins with "{@code /**}" , ends with a separate
+ * "<code>*/</code>", and immediately precedes the element,
+ * ignoring white space. Therefore, a documentation comment
+ * contains at least three"{@code *}" characters. The text
+ * returned for the documentation comment is a processed form of
+ * the comment as it appears in source code. The leading "{@code
+ * /**}" and trailing "<code>*/</code>" are removed. For lines
+ * of the comment starting after the initial "{@code /**}",
+ * leading white space characters are discarded as are any
+ * consecutive "{@code *}" characters appearing after the white
+ * space or starting the line. The processed lines are then
+ * concatenated together (including line terminators) and
+ * returned.
+ *
* @param e the element being examined
* @return the documentation comment of the element, or {@code null}
* if there is none
+ * @jls3 3.6 White Space
*/
String getDocComment(Element e);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/6889255/T6889255.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,485 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6889255
+ * @summary ClassReader does not read parameter names correctly
+ */
+
+import java.io.*;
+import java.util.*;
+import javax.tools.StandardLocation;
+import com.sun.tools.javac.code.Flags;
+import com.sun.tools.javac.code.Kinds;
+import com.sun.tools.javac.code.Scope;
+import com.sun.tools.javac.code.Symbol.*;
+import com.sun.tools.javac.code.Type;
+import com.sun.tools.javac.code.Type.ClassType;
+import com.sun.tools.javac.code.TypeTags;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.jvm.ClassReader;
+import com.sun.tools.javac.util.Context;
+import com.sun.tools.javac.util.Names;
+
+public class T6889255 {
+ boolean testInterfaces = true;
+ boolean testSyntheticMethods = true;
+
+ // The following enums control the generation of the test methods to be compiled.
+ enum GenericKind {
+ NOT_GENERIC,
+ GENERIC
+ };
+
+ enum ClassKind {
+ CLASS("Clss"),
+ INTERFACE("Intf"),
+ ENUM("Enum");
+ final String base;
+ ClassKind(String base) { this.base = base; }
+ };
+
+ enum NestedKind {
+ /** Declare methods inside the outermost container. */
+ NONE,
+ /** Declare methods inside a container with a 'static' modifier. */
+ NESTED,
+ /** Declare methods inside a container without a 'static' modifier. */
+ INNER,
+ /** Declare methods inside a local class in an initializer. */
+ INIT_LOCAL,
+ /** Declare methods inside an anonymous class in an initializer. */
+ INIT_ANON,
+ /** Declare methods inside a local class in a method. */
+ METHOD_LOCAL,
+ /** Declare methods inside an anonymous class in a method. */
+ METHOD_ANON
+ };
+
+ enum MethodKind {
+ ABSTRACT,
+ CONSTRUCTOR,
+ METHOD,
+ STATIC_METHOD,
+ BRIDGE_METHOD
+ };
+
+ enum FinalKind {
+ /** Method body does not reference external final variables. */
+ NO_FINAL,
+ /** Method body references external final variables. */
+ USE_FINAL
+ };
+
+ public static void main(String... args) throws Exception {
+ new T6889255().run();
+ }
+
+ void run() throws Exception {
+ genTest();
+
+ test("no-args", false);
+ test("g", true, "-g");
+
+ if (errors > 0)
+ throw new Exception(errors + " errors found");
+ }
+
+ /**
+ * Create a file containing lots of method definitions to be tested.
+ * There are 3 sets of nested loops that generate the methods.
+ * 1. The outermost set declares [generic] (class | interface | enum)
+ * 2. The middle set declares [(nested | inner | anon | local)] class
+ * 3. The innermost set declares
+ * [generic] (constructor|method|static-method|bridge-method) [using final variables in outer scope]
+ * Invalid combinations are filtered out.
+ */
+ void genTest() throws Exception {
+ BufferedWriter out = new BufferedWriter(new FileWriter("Test.java"));
+
+ // This interface is used to force bridge methods to be generated, by
+ // implementing its methods with subtypes of Object
+ out.write("interface Base {\n");
+ out.write(" Object base_m1(int i1);\n");
+ out.write(" Object base_m2(int i1);\n");
+ out.write("}\n");
+
+ int outerNum = 0;
+ // Outermost set of loops, to generate a top level container
+ for (GenericKind outerGenericKind: GenericKind.values()) {
+ for (ClassKind outerClassKind: ClassKind.values()) {
+ if (outerGenericKind == GenericKind.GENERIC && outerClassKind == ClassKind.ENUM)
+ continue;
+ String outerClassName = outerClassKind.base + (outerNum++);
+ String outerTypeArg = outerClassKind.toString().charAt(0) + "T";
+ if (outerClassKind == ClassKind.CLASS)
+ out.write("abstract ");
+ out.write(outerClassKind.toString().toLowerCase() + " " + outerClassName);
+ if (outerGenericKind == GenericKind.GENERIC)
+ out.write("<" + outerTypeArg + ">");
+ if (outerClassKind == ClassKind.INTERFACE)
+ out.write(" extends Base");
+ else
+ out.write(" implements Base");
+ out.write(" {\n");
+ if (outerClassKind == ClassKind.ENUM) {
+ out.write(" E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
+ out.write(" " + outerClassName + "(int i1, int i2, int i3) { }\n");
+ }
+ // Middle set of loops, to generate an optional nested container
+ int nestedNum = 0;
+ int methodNum = 0;
+ for (GenericKind nestedGenericKind: GenericKind.values()) {
+ nextNestedKind:
+ for (NestedKind nestedKind: NestedKind.values()) {
+ // if the nested kind is none, there is no point iterating over all
+ // nested generic kinds, so arbitarily limit it to just one kind
+ if (nestedKind == NestedKind.NONE && nestedGenericKind != GenericKind.NOT_GENERIC)
+ continue;
+ if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
+ && nestedGenericKind == GenericKind.GENERIC)
+ continue;
+ String indent = " ";
+ boolean haveFinal = false;
+ switch (nestedKind) {
+ case METHOD_ANON: case METHOD_LOCAL:
+ if (outerClassKind == ClassKind.INTERFACE)
+ continue nextNestedKind;
+ out.write(indent + "void m" + + (nestedNum++) + "() {\n");
+ indent += " ";
+ out.write(indent + "final int fi1 = 0;\n");
+ haveFinal = true;
+ break;
+ case INIT_ANON: case INIT_LOCAL:
+ if (outerClassKind == ClassKind.INTERFACE)
+ continue nextNestedKind;
+ out.write(indent + "{\n");
+ indent += " ";
+ break;
+ }
+ for (ClassKind nestedClassKind: ClassKind.values()) {
+ if ((nestedGenericKind == GenericKind.GENERIC)
+ && (nestedClassKind == ClassKind.ENUM))
+ continue;
+ if ((nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.METHOD_LOCAL
+ || nestedKind == NestedKind.INIT_ANON || nestedKind == NestedKind.INIT_LOCAL)
+ && nestedClassKind != ClassKind.CLASS)
+ continue;
+ // if the nested kind is none, there is no point iterating over all
+ // nested class kinds, so arbitarily limit it to just one kind
+ if (nestedKind == NestedKind.NONE && nestedClassKind != ClassKind.CLASS)
+ continue;
+
+ ClassKind methodClassKind;
+ String methodClassName;
+ boolean allowAbstractMethods;
+ boolean allowStaticMethods;
+ switch (nestedKind) {
+ case NONE:
+ methodClassKind = outerClassKind;
+ methodClassName = outerClassName;
+ allowAbstractMethods = (outerClassKind == ClassKind.CLASS);
+ allowStaticMethods = (outerClassKind != ClassKind.INTERFACE);
+ break;
+ case METHOD_ANON:
+ case INIT_ANON:
+ out.write(indent + "new Base() {\n");
+ indent += " ";
+ methodClassKind = ClassKind.CLASS;
+ methodClassName = null;
+ allowAbstractMethods = false;
+ allowStaticMethods = false;
+ break;
+ default: { // INNER, NESTED, LOCAL
+ String nestedClassName = "N" + nestedClassKind.base + (nestedNum++);
+ String nestedTypeArg = nestedClassKind.toString().charAt(0) + "T";
+ out.write(indent);
+ if (nestedKind == NestedKind.NESTED)
+ out.write("static ");
+ if (nestedClassKind == ClassKind.CLASS)
+ out.write("abstract ");
+ out.write(nestedClassKind.toString().toLowerCase() + " " + nestedClassName);
+ if (nestedGenericKind == GenericKind.GENERIC)
+ out.write("<" + nestedTypeArg + ">");
+ if (nestedClassKind == ClassKind.INTERFACE)
+ out.write(" extends Base ");
+ else
+ out.write(" implements Base ");
+ out.write(" {\n");
+ indent += " ";
+ if (nestedClassKind == ClassKind.ENUM) {
+ out.write(indent + "E1(0,0,0), E2(0,0,0), E3(0,0,0);\n");
+ out.write(indent + nestedClassName + "(int i1, int i2, int i3) { }\n");
+ }
+ methodClassKind = nestedClassKind;
+ methodClassName = nestedClassName;
+ allowAbstractMethods = (nestedClassKind == ClassKind.CLASS);
+ allowStaticMethods = (nestedKind == NestedKind.NESTED && nestedClassKind != ClassKind.INTERFACE);
+ break;
+ }
+ }
+
+ // Innermost loops, to generate methods
+ for (GenericKind methodGenericKind: GenericKind.values()) {
+ for (FinalKind finalKind: FinalKind.values()) {
+ for (MethodKind methodKind: MethodKind.values()) {
+// out.write("// " + outerGenericKind
+// + " " + outerClassKind
+// + " " + nestedKind
+// + " " + nestedGenericKind
+// + " " + nestedClassKind
+// + " " + methodGenericKind
+// + " " + finalKind
+// + " " + methodKind
+// + "\n");
+ switch (methodKind) {
+ case CONSTRUCTOR:
+ if (nestedKind == NestedKind.METHOD_ANON || nestedKind == NestedKind.INIT_ANON)
+ break;
+ if (methodClassKind != ClassKind.CLASS)
+ break;
+ if (finalKind == FinalKind.USE_FINAL && !haveFinal)
+ break;
+ out.write(indent);
+ if (methodGenericKind == GenericKind.GENERIC) {
+ out.write("<CT> " + methodClassName + "(CT c1, CT c2");
+ } else {
+ out.write(methodClassName + "(boolean b1, char c2");
+ }
+ if (finalKind == FinalKind.USE_FINAL) {
+ // add a dummy parameter to avoid duplicate declaration
+ out.write(", int i3) { int i = fi1; }\n");
+ } else
+ out.write(") { }\n");
+ break;
+ case ABSTRACT:
+ if (!allowAbstractMethods)
+ continue;
+ // fallthrough
+ case METHOD:
+ if (finalKind == FinalKind.USE_FINAL && !haveFinal)
+ break;
+ out.write(indent);
+ if (methodKind == MethodKind.ABSTRACT)
+ out.write("abstract ");
+ if (methodGenericKind == GenericKind.GENERIC)
+ out.write("<MT> ");
+ out.write("void m" + (methodNum++) + "(int i1, long l2, float f3)");
+ if (methodKind == MethodKind.ABSTRACT || methodClassKind == ClassKind.INTERFACE)
+ out.write(";\n");
+ else {
+ out.write(" {");
+ if (finalKind == FinalKind.USE_FINAL)
+ out.write(" int i = fi1;");
+ out.write(" }\n");
+ }
+ break;
+ case BRIDGE_METHOD:
+ if (methodGenericKind == GenericKind.GENERIC)
+ break;
+ out.write(indent);
+ // methods Base.base_m1 and Base.base_m2 are declared for the
+ // benefit of bridge methods. They need to be implemented
+ // whether or not a final variable is used.
+ String methodName = (finalKind == FinalKind.NO_FINAL ? "base_m1" : "base_m2");
+ out.write("public String " + methodName + "(int i1)");
+ if (methodClassKind == ClassKind.INTERFACE)
+ out.write(";\n");
+ else {
+ out.write(" {");
+ if (finalKind == FinalKind.USE_FINAL && haveFinal)
+ out.write(" int i = fi1;");
+ out.write(" return null; }\n");
+ }
+ break;
+ case STATIC_METHOD:
+ if (!allowStaticMethods)
+ break;
+ if (finalKind == FinalKind.USE_FINAL && !haveFinal)
+ break;
+ out.write(indent + "static ");
+ if (methodGenericKind == GenericKind.GENERIC)
+ out.write("<MT> ");
+ out.write("void m" + (methodNum++) + "(int i1, long l2, float f3) {");
+ if (finalKind == FinalKind.USE_FINAL)
+ out.write(" int i = fi1;");
+ out.write(" }\n");
+ break;
+ }
+
+ }
+ }
+ }
+ if (nestedKind != NestedKind.NONE) {
+ indent = indent.substring(0, indent.length() - 4);
+ out.write(indent + "};\n");
+ }
+ }
+ switch (nestedKind) {
+ case METHOD_ANON: case METHOD_LOCAL:
+ case INIT_ANON: case INIT_LOCAL:
+ indent = indent.substring(0, indent.length() - 4);
+ out.write(indent + "}\n\n");
+ }
+ }
+ }
+ out.write("}\n\n");
+ }
+ }
+ out.close();
+ }
+
+
+ void test(String testName, boolean expectNames, String... opts) throws Exception {
+ System.err.println("Test " + testName
+ + ": expectNames:" + expectNames
+ + " javacOpts:" + Arrays.asList(opts));
+
+ File outDir = new File(testName);
+ outDir.mkdirs();
+ compile(outDir, opts);
+
+ Context ctx = new Context();
+ JavacFileManager fm = new JavacFileManager(ctx, true, null);
+ fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(outDir));
+ ClassReader cr = ClassReader.instance(ctx);
+ cr.saveParameterNames = true;
+ Names names = Names.instance(ctx);
+
+ Set<String> classes = getTopLevelClasses(outDir);
+ Deque<String> work = new LinkedList<String>(classes);
+ String classname;
+ while ((classname = work.poll()) != null) {
+ System.err.println("Checking class " + classname);
+ ClassSymbol sym = cr.enterClass(names.table.fromString(classname));
+ sym.complete();
+
+ if ((sym.flags() & Flags.INTERFACE) != 0 && !testInterfaces)
+ continue;
+
+ for (Scope.Entry e = sym.members_field.elems; e != null; e = e.sibling) {
+ System.err.println("Checking member " + e.sym);
+ switch (e.sym.kind) {
+ case Kinds.TYP: {
+ String name = e.sym.flatName().toString();
+ if (!classes.contains(name)) {
+ classes.add(name);
+ work.add(name);
+ }
+ break;
+ }
+ case Kinds.MTH:
+ verify((MethodSymbol) e.sym, expectNames);
+ break;
+ }
+
+ }
+ }
+ }
+
+ void verify(MethodSymbol m, boolean expectNames) {
+ if ((m.flags() & Flags.SYNTHETIC) != 0 && !testSyntheticMethods)
+ return;
+
+ //System.err.println("verify: " + m.params());
+ int i = 1;
+ for (VarSymbol v: m.params()) {
+ String expectName;
+ if (expectNames)
+ expectName = getExpectedName(v, i);
+ else
+ expectName = "arg" + (i - 1);
+ checkEqual(expectName, v.name.toString());
+ i++;
+ }
+ }
+
+ String getExpectedName(VarSymbol v, int i) {
+ // special cases:
+ // synthetic method
+ if (((v.owner.owner.flags() & Flags.ENUM) != 0)
+ && v.owner.name.toString().equals("valueOf"))
+ return "name";
+ // interfaces don't have saved names
+ // -- no Code attribute for the LocalVariableTable attribute
+ if ((v.owner.owner.flags() & Flags.INTERFACE) != 0)
+ return "arg" + (i - 1);
+ // abstract methods don't have saved names
+ // -- no Code attribute for the LocalVariableTable attribute
+ if ((v.owner.flags() & Flags.ABSTRACT) != 0)
+ return "arg" + (i - 1);
+ // bridge methods use xN
+ if ((v.owner.flags() & Flags.BRIDGE) != 0)
+ return "x" + (i - 1);
+
+ // The rest of this method assumes the local conventions in the test program
+ Type t = v.type;
+ String s;
+ if (t.tag == TypeTags.CLASS)
+ s = ((ClassType) t).tsym.name.toString();
+ else
+ s = t.toString();
+ return String.valueOf(Character.toLowerCase(s.charAt(0))) + i;
+ }
+
+ void compile(File outDir, String... opts) throws Exception {
+ //File testSrc = new File(System.getProperty("test.src"), ".");
+ List<String> args = new ArrayList<String>();
+ args.add("-d");
+ args.add(outDir.getPath());
+ args.addAll(Arrays.asList(opts));
+ //args.add(new File(testSrc, "Test.java").getPath());
+ args.add("Test.java");
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ int rc = com.sun.tools.javac.Main.compile(args.toArray(new String[args.size()]), pw);
+ pw.close();
+ if (rc != 0) {
+ System.err.println(sw.toString());
+ throw new Exception("compilation failed unexpectedly");
+ }
+ }
+
+ Set<String> getTopLevelClasses(File outDir) {
+ Set<String> classes = new HashSet<String>();
+ for (String f: outDir.list()) {
+ if (f.endsWith(".class") && !f.contains("$"))
+ classes.add(f.replace(".class", ""));
+ }
+ return classes;
+ }
+
+ void checkEqual(String expect, String found) {
+ if (!expect.equals(found))
+ error("mismatch: expected:" + expect + " found:" + found);
+ }
+
+ void error(String msg) {
+ System.err.println(msg);
+ errors++;
+ throw new Error();
+ }
+
+ int errors;
+}
--- a/langtools/test/tools/javac/api/6440528/T6440528.java Fri Oct 23 18:44:33 2009 -0700
+++ b/langtools/test/tools/javac/api/6440528/T6440528.java Wed Oct 28 10:37:17 2009 -0700
@@ -59,9 +59,9 @@
}
private File getUnderlyingFile(Object o) throws Exception {
- Field f = o.getClass().getDeclaredField("f");
- f.setAccessible(true);
- return (File)f.get(o);
+ Field file = o.getClass().getDeclaredField("file");
+ file.setAccessible(true);
+ return (File)file.get(o);
}
public static void main(String... args) throws Exception {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/api/T6838467.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6838467
+ * @summary JSR199 FileObjects don't obey general contract of equals.
+ */
+
+import java.io.*;
+import java.util.*;
+import java.util.zip.*;
+import javax.tools.*;
+import com.sun.tools.javac.file.JavacFileManager;
+import com.sun.tools.javac.util.Context;
+
+public class T6838467 {
+ boolean fileSystemIsCaseSignificant = !new File("a").equals(new File("A"));
+
+ enum FileKind {
+ DIR("dir"),
+ ZIP("zip"),
+ ZIPFILEINDEX("zip");
+ FileKind(String path) {
+ file = new File(path);
+ }
+ final File file;
+ };
+
+ enum CompareKind {
+ SAME {
+ File other(File f) { return f; }
+ },
+ ABSOLUTE {
+ File other(File f) { return f.getAbsoluteFile(); }
+ },
+ DIFFERENT {
+ File other(File f) { return new File("not_" + f.getPath()); }
+ },
+ CASEEQUIV {
+ File other(File f) { return new File(f.getPath().toUpperCase()); }
+ };
+ abstract File other(File f);
+ };
+
+ String[] paths = { "p/A.java", "p/B.java", "p/C.java" };
+
+ public static void main(String... args) throws Exception {
+ new T6838467().run();
+ }
+
+ void run() throws Exception {
+ // on Windows, verify file system is not case significant
+ if (System.getProperty("os.name").toLowerCase().startsWith("windows")
+ && fileSystemIsCaseSignificant) {
+ error("fileSystemIsCaseSignificant is set on Windows.");
+ }
+
+ // create a set of directories and zip files to compare
+ createTestDir(new File("dir"), paths);
+ createTestDir(new File("not_dir"), paths);
+ createTestZip(new File("zip"), paths);
+ createTestZip(new File("not_zip"), paths);
+ if (fileSystemIsCaseSignificant) {
+ createTestDir(new File("DIR"), paths);
+ createTestZip(new File("ZIP"), paths);
+ }
+
+ // test the various sorts of file objects that can be obtained from
+ // the file manager, and for various values that may or may not match.
+ for (FileKind fk: FileKind.values()) {
+ for (CompareKind ck: CompareKind.values()) {
+ test(fk, ck);
+ }
+ }
+
+ // verify that the various different types of file object were all
+ // tested
+ Set<String> expectClasses = new HashSet<String>(Arrays.asList(
+ "RegularFileObject", "ZipFileObject", "ZipFileIndexFileObject" ));
+ if (!foundClasses.equals(expectClasses)) {
+ error("expected fileobject classes not found\n"
+ + "expected: " + expectClasses + "\n"
+ + "found: " + foundClasses);
+ }
+
+ if (errors > 0)
+ throw new Exception(errors + " errors");
+ }
+
+ void test(FileKind fk, CompareKind ck) throws IOException {
+ File f1 = fk.file;
+ JavaFileManager fm1 = createFileManager(fk, f1);
+
+ File f2 = ck.other(fk.file);
+ JavaFileManager fm2 = createFileManager(fk, f2);
+
+ try {
+ // If the directories or zip files match, we expect "n" matches in
+ // the "n-squared" comparisons to come, where "n" is the number of
+ // entries in the the directories or zip files.
+ // If the directories or zip files don't themselves match,
+ // we obviously don't expect any of their contents to match either.
+ int expect = (f1.getAbsoluteFile().equals(f2.getAbsoluteFile()) ? paths.length : 0);
+
+ System.err.println("test " + (++count) + " " + fk + " " + ck + " " + f1 + " " + f2);
+ test(fm1, fm2, expect);
+
+ } finally {
+ fm1.close();
+ fm2.close();
+ }
+ }
+
+ // For a pair of file managers that may or may not have similar entries
+ // on the classpath, compare all files returned from one against all files
+ // returned from the other. For each pair of files, verify that if they
+ // are equal, the hashcode is equal as well, and finally verify that the
+ // expected number of matches was found.
+ void test(JavaFileManager fm1, JavaFileManager fm2, int expectEqualCount) throws IOException {
+ boolean foundFiles1 = false;
+ boolean foundFiles2 = false;
+ int foundEqualCount = 0;
+ Set<JavaFileObject.Kind> kinds = EnumSet.allOf(JavaFileObject.Kind.class);
+ for (FileObject fo1: fm1.list(StandardLocation.CLASS_PATH, "p", kinds, false)) {
+ foundFiles1 = true;
+ foundClasses.add(fo1.getClass().getSimpleName());
+ for (FileObject fo2: fm2.list(StandardLocation.CLASS_PATH, "p", kinds, false)) {
+ foundFiles2 = true;
+ foundClasses.add(fo1.getClass().getSimpleName());
+ System.err.println("compare " + fo1 + " " + fo2);
+ if (fo1.equals(fo2)) {
+ foundEqualCount++;
+ int hash1 = fo1.hashCode();
+ int hash2 = fo2.hashCode();
+ if (hash1 != hash2)
+ error("hashCode error: " + fo1 + " [" + hash1 + "] "
+ + fo2 + " [" + hash2 + "]");
+ }
+ }
+ }
+ if (!foundFiles1)
+ error("no files found for file manager 1");
+ if (!foundFiles2)
+ error("no files found for file manager 2");
+ // verify the expected number of matches were found
+ if (foundEqualCount != expectEqualCount)
+ error("expected matches not found: expected " + expectEqualCount + ", found " + foundEqualCount);
+ }
+
+ // create a file manager to test a FileKind, with a given directory
+ // or zip file placed on the classpath
+ JavaFileManager createFileManager(FileKind fk, File classpath) throws IOException {
+ StandardJavaFileManager fm = createFileManager(fk == FileKind.ZIP);
+ fm.setLocation(StandardLocation.CLASS_PATH, Arrays.asList(classpath));
+ return fm;
+ }
+
+ JavacFileManager createFileManager(boolean useJavaUtilZip) {
+ // javac should really not be using system properties like this
+ // -- it should really be using (hidden) options -- but until then
+ // take care to leave system properties as we find them, so as not
+ // to adversely affect other tests that might follow.
+ String prev = System.getProperty("useJavaUtilZip");
+ boolean resetProperties = false;
+ try {
+ if (useJavaUtilZip) {
+ System.setProperty("useJavaUtilZip", "true");
+ resetProperties = true;
+ } else if (System.getProperty("useJavaUtilZip") != null) {
+ System.getProperties().remove("useJavaUtilZip");
+ resetProperties = true;
+ }
+
+ Context c = new Context();
+ return new JavacFileManager(c, false, null);
+ } finally {
+ if (resetProperties) {
+ if (prev == null) {
+ System.getProperties().remove("useJavaUtilZip");
+ } else {
+ System.setProperty("useJavaUtilZip", prev);
+ }
+ }
+ }
+ }
+
+ // create a directory containing a given set of paths
+ void createTestDir(File dir, String[] paths) throws IOException {
+ for (String p: paths) {
+ File file = new File(dir, p);
+ file.getParentFile().mkdirs();
+ FileWriter out = new FileWriter(file);
+ try {
+ out.write(p);
+ } finally {
+ out.close();
+ }
+ }
+ }
+
+ // create a sip file containing a given set of entries
+ void createTestZip(File zip, String[] paths) throws IOException {
+ if (zip.getParentFile() != null)
+ zip.getParentFile().mkdirs();
+ ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(zip));
+ try {
+ for (String p: paths) {
+ ZipEntry ze = new ZipEntry(p);
+ zos.putNextEntry(ze);
+ byte[] bytes = p.getBytes();
+ zos.write(bytes, 0, bytes.length);
+ zos.closeEntry();
+ }
+ } finally {
+ zos.close();
+ }
+ }
+
+ void error(String msg) {
+ System.err.println("Error: " + msg);
+ errors++;
+ }
+
+ int count;
+ int errors;
+ Set<String> foundClasses = new HashSet<String>();
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/literals/T6891079.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,12 @@
+/* @test /nodynamiccopyright/
+ * @bug 6891079
+ * @summary Compiler allows invalid binary literals 0b and oBL
+ * @compile/fail/ref=T6891079.out -XDrawDiagnostics T6891079.java
+ */
+
+class Test {
+ int bi = 0B;
+ long bl = 0BL;
+ int xi = 0X;
+ long xl = 0XL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javac/literals/T6891079.out Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,7 @@
+T6891079.java:8:14: compiler.err.invalid.binary.number
+T6891079.java:9:15: compiler.err.invalid.binary.number
+T6891079.java:9:18: compiler.err.expected: token.identifier
+T6891079.java:10:14: compiler.err.invalid.hex.number
+T6891079.java:11:15: compiler.err.invalid.hex.number
+T6891079.java:11:18: compiler.err.expected: token.identifier
+6 errors
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/6888367/T6888367.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,511 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.Type.ArrayType;
+import com.sun.tools.classfile.Type.ClassSigType;
+import com.sun.tools.classfile.Type.ClassType;
+import com.sun.tools.classfile.Type.MethodType;
+import com.sun.tools.classfile.Type.SimpleType;
+import com.sun.tools.classfile.Type.TypeParamType;
+import com.sun.tools.classfile.Type.WildcardType;
+
+/*
+ * @test
+ * @bug 6888367
+ * @summary classfile library parses signature attributes incorrectly
+ */
+
+/*
+ * This test is a pretty detailed test both of javac signature generation and classfile
+ * signature parsing. The first part of the test tests all the examples given in the
+ * second part of the test. Each example comes with one or two annotations, @Desc, @Sig,
+ * for the descriptor and signature of the annotated declaration. Annotations are
+ * provided whenever the annotated item is expected to have a corresponding value.
+ * Each annotation has two argument values. The first arg is the expected value of the
+ * descriptor/signature as found in the class file. This value is mostly for documentation
+ * purposes in reading the test. The second value is the rendering of the descriptor or
+ * signature using a custom Type visitor that explicitly includes an indication of the
+ * Type classes being used to represent the descriptor/signature. Thus we test
+ * that the descriptor/signature is being parsed into the expected type tree structure.
+ */
+public class T6888367 {
+
+ public static void main(String... args) throws Exception {
+ new T6888367().run();
+ }
+
+ public void run() throws Exception {
+ ClassFile cf = getClassFile("Test");
+
+ testFields(cf);
+ testMethods(cf);
+ testInnerClasses(cf); // recursive
+
+ if (errors > 0)
+ throw new Exception(errors + " errors found");
+ }
+
+ void testFields(ClassFile cf) throws Exception {
+ String cn = cf.getName();
+ ConstantPool cp = cf.constant_pool;
+ for (Field f: cf.fields) {
+ test("field " + cn + "." + f.getName(cp), f.descriptor, f.attributes, cp);
+ }
+ }
+
+ void testMethods(ClassFile cf) throws Exception {
+ String cn = cf.getName();
+ ConstantPool cp = cf.constant_pool;
+ for (Method m: cf.methods) {
+ test("method " + cn + "." + m.getName(cp), m.descriptor, m.attributes, cp);
+ }
+ }
+
+ void testInnerClasses(ClassFile cf) throws Exception {
+ ConstantPool cp = cf.constant_pool;
+ InnerClasses_attribute ic =
+ (InnerClasses_attribute) cf.attributes.get(Attribute.InnerClasses);
+ for (InnerClasses_attribute.Info info: ic.classes) {
+ String outerClassName = cp.getClassInfo(info.outer_class_info_index).getName();
+ if (!outerClassName.equals(cf.getName())) {
+ continue;
+ }
+ String innerClassName = cp.getClassInfo(info.inner_class_info_index).getName();
+ ClassFile icf = getClassFile(innerClassName);
+ test("class " + innerClassName, null, icf.attributes, icf.constant_pool);
+ testInnerClasses(icf);
+ }
+ }
+
+ void test(String name, Descriptor desc, Attributes attrs, ConstantPool cp)
+ throws Exception {
+ AnnotValues d = getDescValue(attrs, cp);
+ AnnotValues s = getSigValue(attrs, cp);
+ if (d == null && s == null) // not a test field or method if no @Desc or @Sig given
+ return;
+
+ System.err.println(name);
+
+ if (desc != null) {
+ System.err.println(" descriptor: " + desc.getValue(cp));
+ checkEqual(d.raw, desc.getValue(cp));
+ Type dt = new Signature(desc.index).getType(cp);
+ checkEqual(d.type, tp.print(dt));
+ }
+
+ Signature_attribute sa = (Signature_attribute) attrs.get(Attribute.Signature);
+ if (sa != null)
+ System.err.println(" signature: " + sa.getSignature(cp));
+
+ if (s != null || sa != null) {
+ if (s != null && sa != null) {
+ checkEqual(s.raw, sa.getSignature(cp));
+ Type st = new Signature(sa.signature_index).getType(cp);
+ checkEqual(s.type, tp.print(st));
+ } else if (s != null)
+ error("@Sig annotation found but not Signature attribute");
+ else
+ error("Signature attribute found but no @Sig annotation");
+ }
+
+ System.err.println();
+ }
+
+
+ ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
+ URL url = getClass().getResource(name + ".class");
+ InputStream in = url.openStream();
+ try {
+ return ClassFile.read(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ AnnotValues getDescValue(Attributes attrs, ConstantPool cp) throws Exception {
+ return getAnnotValues(Desc.class.getName(), attrs, cp);
+ }
+
+ AnnotValues getSigValue(Attributes attrs, ConstantPool cp) throws Exception {
+ return getAnnotValues(Sig.class.getName(), attrs, cp);
+ }
+
+ static class AnnotValues {
+ AnnotValues(String raw, String type) {
+ this.raw = raw;
+ this.type = type;
+ }
+ final String raw;
+ final String type;
+ }
+
+ AnnotValues getAnnotValues(String annotName, Attributes attrs, ConstantPool cp)
+ throws Exception {
+ RuntimeInvisibleAnnotations_attribute annots =
+ (RuntimeInvisibleAnnotations_attribute)attrs.get(Attribute.RuntimeInvisibleAnnotations);
+ if (annots != null) {
+ for (Annotation a: annots.annotations) {
+ if (cp.getUTF8Value(a.type_index).equals("L" + annotName + ";")) {
+ Annotation.Primitive_element_value pv0 =
+ (Annotation.Primitive_element_value) a.element_value_pairs[0].value;
+ Annotation.Primitive_element_value pv1 =
+ (Annotation.Primitive_element_value) a.element_value_pairs[1].value;
+ return new AnnotValues(
+ cp.getUTF8Value(pv0.const_value_index),
+ cp.getUTF8Value(pv1.const_value_index));
+ }
+ }
+ }
+ return null;
+
+ }
+
+ void checkEqual(String expect, String found) {
+ if (!(expect == null ? found == null : expect.equals(found))) {
+ System.err.println("expected: " + expect);
+ System.err.println(" found: " + found);
+ error("unexpected values found");
+ }
+ }
+
+ void error(String msg) {
+ System.err.println("error: " + msg);
+ errors++;
+ }
+
+ int errors;
+
+ TypePrinter tp = new TypePrinter();
+
+ class TypePrinter implements Type.Visitor<String,Void> {
+ String print(Type t) {
+ return t == null ? null : t.accept(this, null);
+ }
+ String print(String pre, List<? extends Type> ts, String post) {
+ if (ts == null)
+ return null;
+ StringBuilder sb = new StringBuilder();
+ sb.append(pre);
+ String sep = "";
+ for (Type t: ts) {
+ sb.append(sep);
+ sb.append(print(t));
+ sep = ",";
+ }
+ sb.append(post);
+ return sb.toString();
+ }
+
+ public String visitSimpleType(SimpleType type, Void p) {
+ return "S{" + type.name + "}";
+ }
+
+ public String visitArrayType(ArrayType type, Void p) {
+ return "A{" + print(type.elemType) + "}";
+ }
+
+ public String visitMethodType(MethodType type, Void p) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("M{");
+ if (type.typeParamTypes != null)
+ sb.append(print("<", type.typeParamTypes, ">"));
+ sb.append(print(type.returnType));
+ sb.append(print("(", type.paramTypes, ")"));
+ if (type.throwsTypes != null)
+ sb.append(print("", type.throwsTypes, ""));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ public String visitClassSigType(ClassSigType type, Void p) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("CS{");
+ if (type.typeParamTypes != null)
+ sb.append(print("<", type.typeParamTypes, ">"));
+ sb.append(print(type.superclassType));
+ if (type.superinterfaceTypes != null)
+ sb.append(print("i(", type.superinterfaceTypes, ")"));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ public String visitClassType(ClassType type, Void p) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("C{");
+ if (type.outerType != null) {
+ sb.append(print(type.outerType));
+ sb.append(".");
+ }
+ sb.append(type.name);
+ if (type.typeArgs != null)
+ sb.append(print("<", type.typeArgs, ">"));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ public String visitTypeParamType(TypeParamType type, Void p) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("TA{");
+ sb.append(type.name);
+ if (type.classBound != null) {
+ sb.append(":c");
+ sb.append(print(type.classBound));
+ }
+ if (type.interfaceBounds != null)
+ sb.append(print(":i", type.interfaceBounds, ""));
+ sb.append("}");
+ return sb.toString();
+ }
+
+ public String visitWildcardType(WildcardType type, Void p) {
+ switch (type.kind) {
+ case UNBOUNDED:
+ return "W{?}";
+ case EXTENDS:
+ return "W{e," + print(type.boundType) + "}";
+ case SUPER:
+ return "W{s," + print(type.boundType) + "}";
+ default:
+ throw new AssertionError();
+ }
+ }
+
+ };
+}
+
+
+@interface Desc {
+ String d();
+ String t();
+}
+
+@interface Sig {
+ String s();
+ String t();
+}
+
+class Clss { }
+interface Intf { }
+class GenClss<T> { }
+
+class Test {
+ // fields
+
+ @Desc(d="Z", t="S{boolean}")
+ boolean z;
+
+ @Desc(d="B", t="S{byte}")
+ byte b;
+
+ @Desc(d="C", t="S{char}")
+ char c;
+
+ @Desc(d="D", t="S{double}")
+ double d;
+
+ @Desc(d="F", t="S{float}")
+ float f;
+
+ @Desc(d="I", t="S{int}")
+ int i;
+
+ @Desc(d="J", t="S{long}")
+ long l;
+
+ @Desc(d="S", t="S{short}")
+ short s;
+
+ @Desc(d="LClss;", t="C{Clss}")
+ Clss clss;
+
+ @Desc(d="LIntf;", t="C{Intf}")
+ Intf intf;
+
+ @Desc(d="[I", t="A{S{int}}")
+ int[] ai;
+
+ @Desc(d="[LClss;", t="A{C{Clss}}")
+ Clss[] aClss;
+
+ @Desc(d="LGenClss;", t="C{GenClss}")
+ @Sig(s="LGenClss<LClss;>;", t="C{GenClss<C{Clss}>}")
+ GenClss<Clss> genClass;
+
+ // methods, return types
+
+ @Desc(d="()V", t="M{S{void}()}")
+ void mv0() { }
+
+ @Desc(d="()I", t="M{S{int}()}")
+ int mi0() { return 0; }
+
+ @Desc(d="()LClss;", t="M{C{Clss}()}")
+ Clss mclss0() { return null; }
+
+ @Desc(d="()[I", t="M{A{S{int}}()}")
+ int[] mai0() { return null; }
+
+ @Desc(d="()[LClss;", t="M{A{C{Clss}}()}")
+ Clss[] maClss0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="()LGenClss<LClss;>;", t="M{C{GenClss<C{Clss}>}()}")
+ GenClss<Clss> mgenClss0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="()LGenClss<*>;", t="M{C{GenClss<W{?}>}()}")
+ GenClss<?> mgenClssW0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="()LGenClss<+LClss;>;", t="M{C{GenClss<W{e,C{Clss}}>}()}")
+ GenClss<? extends Clss> mgenClssWExtClss0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="()LGenClss<-LClss;>;", t="M{C{GenClss<W{s,C{Clss}}>}()}")
+ GenClss<? super Clss> mgenClssWSupClss0() { return null; }
+
+ @Desc(d="()Ljava/lang/Object;", t="M{C{java/lang/Object}()}")
+ @Sig(s="<T:Ljava/lang/Object;>()TT;", t="M{<TA{T:cC{java/lang/Object}}>S{T}()}")
+ <T> T mt0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="<T:Ljava/lang/Object;>()LGenClss<+TT;>;",
+ t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{e,S{T}}>}()}")
+ <T> GenClss<? extends T> mgenClssWExtT0() { return null; }
+
+ @Desc(d="()LGenClss;", t="M{C{GenClss}()}")
+ @Sig(s="<T:Ljava/lang/Object;>()LGenClss<-TT;>;", t="M{<TA{T:cC{java/lang/Object}}>C{GenClss<W{s,S{T}}>}()}")
+ <T> GenClss<? super T> mgenClssWSupT0() { return null; }
+
+ // methods, arg types
+
+ @Desc(d="(I)V", t="M{S{void}(S{int})}")
+ void mi1(int arg) { }
+
+ @Desc(d="(LClss;)V", t="M{S{void}(C{Clss})}")
+ void mclss1(Clss arg) { }
+
+ @Desc(d="([I)V", t="M{S{void}(A{S{int}})}")
+ void mai1(int[] arg) { }
+
+ @Desc(d="([LClss;)V", t="M{S{void}(A{C{Clss}})}")
+ void maClss1(Clss[] arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="(LGenClss<LClss;>;)V", t="M{S{void}(C{GenClss<C{Clss}>})}")
+ void mgenClss1(GenClss<Clss> arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="(LGenClss<*>;)V", t="M{S{void}(C{GenClss<W{?}>})}")
+ void mgenClssW1(GenClss<?> arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="(LGenClss<+LClss;>;)V", t="M{S{void}(C{GenClss<W{e,C{Clss}}>})}")
+ void mgenClssWExtClss1(GenClss<? extends Clss> arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="(LGenClss<-LClss;>;)V", t="M{S{void}(C{GenClss<W{s,C{Clss}}>})}")
+ void mgenClssWSupClss1(GenClss<? super Clss> arg) { }
+
+ @Desc(d="(Ljava/lang/Object;)V", t="M{S{void}(C{java/lang/Object})}")
+ @Sig(s="<T:Ljava/lang/Object;>(TT;)V",
+ t="M{<TA{T:cC{java/lang/Object}}>S{void}(S{T})}")
+ <T> void mt1(T arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="<T:Ljava/lang/Object;>(LGenClss<+TT;>;)V",
+ t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{e,S{T}}>})}")
+ <T> void mgenClssWExtT1(GenClss<? extends T> arg) { }
+
+ @Desc(d="(LGenClss;)V", t="M{S{void}(C{GenClss})}")
+ @Sig(s="<T:Ljava/lang/Object;>(LGenClss<-TT;>;)V",
+ t="M{<TA{T:cC{java/lang/Object}}>S{void}(C{GenClss<W{s,S{T}}>})}")
+ <T> void mgenClssWSupT1(GenClss<? super T> arg) { }
+
+ // methods, throws
+
+ @Desc(d="()V", t="M{S{void}()}")
+ void m_E() throws Exception { }
+
+ @Desc(d="()V", t="M{S{void}()}")
+ @Sig(s="<T:Ljava/lang/Throwable;>()V^TT;",
+ t="M{<TA{T:cC{java/lang/Throwable}}>S{void}()S{T}}")
+ <T extends Throwable> void m_T() throws T { }
+
+ // inner classes
+
+ static class X {
+ // no sig
+ class P { }
+
+ @Sig(s="<TQ:Ljava/lang/Object;>LTest$X$P;",
+ t="CS{<TA{TQ:cC{java/lang/Object}}>C{Test$X$P}}")
+ class Q<TQ> extends P { }
+
+ @Sig(s="<TR:Ljava/lang/Object;>LTest$X$Q<TTR;>;",
+ t="CS{<TA{TR:cC{java/lang/Object}}>C{Test$X$Q<S{TR}>}}")
+ class R<TR> extends Q<TR> { }
+ }
+
+ @Sig(s="<TY:Ljava/lang/Object;>Ljava/lang/Object;",
+ t="CS{<TA{TY:cC{java/lang/Object}}>C{java/lang/Object}}")
+ static class Y<TY> {
+ // no sig
+ class P { }
+
+ @Sig(s="<TQ:Ljava/lang/Object;>LTest$Y<TTY;>.P;",
+ t="CS{<TA{TQ:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.P}}")
+ class Q<TQ> extends P { }
+
+ @Sig(s="<TR:Ljava/lang/Object;>LTest$Y<TTY;>.Q<TTR;>;",
+ t="CS{<TA{TR:cC{java/lang/Object}}>C{C{Test$Y<S{TY}>}.Q<S{TR}>}}")
+ class R<TR> extends Q<TR> {
+ // no sig
+ class R1 { }
+
+ @Sig(s="<TR2:Ljava/lang/Object;>LTest$Y<TTY;>.R<TTR;>.R1;",
+ t="CS{<TA{TR2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.R<S{TR}>}.R1}}")
+ class R2<TR2> extends R1 { }
+ }
+
+ @Sig(s="LTest$Y<TTY;>.Q<TTY;>;", t="C{C{Test$Y<S{TY}>}.Q<S{TY}>}")
+ class S extends Q<TY> {
+ // no sig
+ class S1 { }
+
+ @Sig(s="<TS2:Ljava/lang/Object;>LTest$Y<TTY;>.S.S1;",
+ t="CS{<TA{TS2:cC{java/lang/Object}}>C{C{C{Test$Y<S{TY}>}.S}.S1}}")
+ class S2<TS2> extends S1 { }
+
+ @Sig(s="LTest$Y<TTY;>.S.S2<TTY;>;",
+ t="C{C{C{Test$Y<S{TY}>}.S}.S2<S{TY}>}")
+ class S3 extends S2<TY> { }
+ }
+ }
+}
+
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/langtools/test/tools/javap/classfile/T6887895.java Wed Oct 28 10:37:17 2009 -0700
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+/*
+ * @test
+ * @bug 6887895
+ * @summary CONSTANT_Class_info getBaseName does not handle arrays of primitives correctly
+ */
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import com.sun.tools.classfile.*;
+import com.sun.tools.classfile.ConstantPool.*;
+
+public class T6887895 {
+ public static void main(String[] args) throws Exception {
+ new T6887895().run();
+ }
+
+ void run() throws Exception {
+ Set<String> found = new TreeSet<String>();
+
+ ClassFile cf = getClassFile("T6887895$Test.class");
+ for (CPInfo cpInfo: cf.constant_pool.entries()) {
+ if (cpInfo instanceof CONSTANT_Class_info) {
+ CONSTANT_Class_info info = (CONSTANT_Class_info) cpInfo;
+ String name = info.getName();
+ String baseName = info.getBaseName();
+ System.out.println("found: " + name + " " + baseName);
+ if (baseName != null)
+ found.add(baseName);
+ }
+ }
+
+ String[] expectNames = {
+ "java/lang/Object",
+ "java/lang/String",
+ "T6887895",
+ "T6887895$Test"
+ };
+
+ Set<String> expect = new TreeSet<String>(Arrays.asList(expectNames));
+ if (!found.equals(expect)) {
+ System.err.println("found: " + found);
+ System.err.println("expect: " + expect);
+ throw new Exception("unexpected values found");
+ }
+ }
+
+ ClassFile getClassFile(String name) throws IOException, ConstantPoolException {
+ URL url = getClass().getResource(name);
+ InputStream in = url.openStream();
+ try {
+ return ClassFile.read(in);
+ } finally {
+ in.close();
+ }
+ }
+
+ class Test {
+ void m() {
+ boolean[] az = new boolean[0];
+ boolean[][] aaz = new boolean[0][];
+ boolean[][][] aaaz = new boolean[0][][];
+
+ byte[] ab = new byte[0];
+ byte[][] aab = new byte[0][];
+ byte[][][] aaab = new byte[0][][];
+
+ char[] ac = new char[0];
+ char[][] aac = new char[0][];
+ char[][][] aaac = new char[0][][];
+
+ double[] ad = new double[0];
+ double[][] aad = new double[0][];
+ double[][][] aaad = new double[0][][];
+
+ float[] af = new float[0];
+ float[][] aaf = new float[0][];
+ float[][][] aaaf = new float[0][][];
+
+ int[] ai = new int[0];
+ int[][] aai = new int[0][];
+ int[][][] aaai = new int[0][][];
+
+ long[] al = new long[0];
+ long[][] aal = new long[0][];
+ long[][][] aaal = new long[0][][];
+
+ short[] as = new short[0];
+ short[][] aas = new short[0][];
+ short[][][] aaas = new short[0][][];
+
+ String[] aS = new String[0];
+ String[][] aaS = new String[0][];
+ String[][][] aaaS = new String[0][][];
+ }
+ }
+}
+