Merge
authorohair
Wed, 28 Oct 2009 16:26:52 -0700
changeset 4114 70dcca39287d
parent 4113 e2d47cad2647 (current diff)
parent 4061 35a627ad2443 (diff)
child 4117 b64b35ebbba0
Merge
jdk/src/share/classes/sun/security/provider/certpath/LDAPCertStore.java
--- a/jdk/make/common/shared/Defs-java.gmk	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/make/common/shared/Defs-java.gmk	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/make/java/java/FILES_java.gmk	Wed Oct 28 16:26:52 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/src/share/classes/com/sun/naming/internal/ResourceManager.java	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/com/sun/naming/internal/ResourceManager.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/java/io/FilePermission.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/java/lang/Enum.java	Wed Oct 28 16:26:52 2009 -0700
@@ -40,10 +40,17 @@
  * Edition</i>, <a
  * href="http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9">&sect;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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/java/nio/file/Path.java	Wed Oct 28 16:26:52 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 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/java/util/jar/JarVerifier.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/misc/FloatingDecimal.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/net/httpserver/ExchangeImpl.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/net/www/protocol/http/HttpURLConnection.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/security/provider/PolicyFile.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java	Wed Oct 28 16:26:52 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 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ /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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java	Wed Oct 28 16:26:52 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 16:26:52 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 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixDirectoryStream.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/src/windows/classes/sun/nio/fs/WindowsDirectoryStream.java	Wed Oct 28 16:26:52 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 16:26:52 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 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/lang/management/RuntimeMXBean/GetSystemProperties.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/lang/management/RuntimeMXBean/PropertiesTest.java	Wed Oct 28 16:26:52 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 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/nio/file/DirectoryStream/Basic.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/nio/file/Files/ContentType.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/nio/file/Path/CheckPermissions.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/nio/file/Path/CopyAndMove.java	Wed Oct 28 16:26:52 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	Mon Oct 26 21:42:20 2009 +0000
+++ b/jdk/test/java/nio/file/attribute/AclFileAttributeView/Basic.java	Wed Oct 28 16:26:52 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 16:26:52 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;
+    }
+}