Merge
authorasaha
Wed, 14 Oct 2009 14:21:25 -0700
changeset 4211 10ea9f654342
parent 4210 8c4290968af0 (current diff)
parent 4045 7c72ce9392fc (diff)
child 4212 9fec83c52b8e
Merge
jdk/src/share/classes/sun/security/provider/certpath/LDAPCertStore.java
jdk/src/share/classes/sun/security/provider/certpath/OCSPChecker.java
--- a/jdk/make/common/shared/Defs-java.gmk	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/make/common/shared/Defs-java.gmk	Wed Oct 14 14:21:25 2009 -0700
@@ -165,6 +165,11 @@
   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	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/make/java/java/FILES_java.gmk	Wed Oct 14 14:21:25 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	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/com/sun/naming/internal/ResourceManager.java	Wed Oct 14 14:21:25 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/lang/Byte.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Byte.java	Wed Oct 14 14:21:25 2009 -0700
@@ -201,7 +201,7 @@
      */
     public static Byte valueOf(String s, int radix)
         throws NumberFormatException {
-        return new Byte(parseByte(s, radix));
+        return valueOf(parseByte(s, radix));
     }
 
     /**
@@ -277,7 +277,7 @@
         if (i < MIN_VALUE || i > MAX_VALUE)
             throw new NumberFormatException(
                     "Value " + i + " out of range from input " + nm);
-        return (byte)i;
+        return valueOf((byte)i);
     }
 
     /**
@@ -374,7 +374,7 @@
      *          base&nbsp;10.
      */
     public String toString() {
-        return String.valueOf((int)value);
+        return Integer.toString((int)value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Double.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Double.java	Wed Oct 14 14:21:25 2009 -0700
@@ -629,7 +629,7 @@
      * @see java.lang.Double#toString(double)
      */
     public String toString() {
-        return String.valueOf(value);
+        return toString(value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Enum.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Enum.java	Wed Oct 14 14:21:25 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/Float.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Float.java	Wed Oct 14 14:21:25 2009 -0700
@@ -551,7 +551,7 @@
      * @see java.lang.Float#toString(float)
      */
     public String toString() {
-        return String.valueOf(value);
+        return Float.toString(value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Integer.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Integer.java	Wed Oct 14 14:21:25 2009 -0700
@@ -746,7 +746,7 @@
      *          base&nbsp;10.
      */
     public String toString() {
-        return String.valueOf(value);
+        return toString(value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Long.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Long.java	Wed Oct 14 14:21:25 2009 -0700
@@ -761,7 +761,7 @@
      *          base&nbsp;10.
      */
     public String toString() {
-        return String.valueOf(value);
+        return toString(value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/Short.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/Short.java	Wed Oct 14 14:21:25 2009 -0700
@@ -170,7 +170,7 @@
      */
     public static Short valueOf(String s, int radix)
         throws NumberFormatException {
-        return new Short(parseShort(s, radix));
+        return valueOf(parseShort(s, radix));
     }
 
     /**
@@ -282,7 +282,7 @@
         if (i < MIN_VALUE || i > MAX_VALUE)
             throw new NumberFormatException(
                     "Value " + i + " out of range from input " + nm);
-        return (short)i;
+        return valueOf((short)i);
     }
 
     /**
@@ -379,7 +379,7 @@
      *          base&nbsp;10.
      */
     public String toString() {
-        return String.valueOf((int)value);
+        return Integer.toString((int)value);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/String.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/String.java	Wed Oct 14 14:21:25 2009 -0700
@@ -2995,7 +2995,7 @@
      * @see     java.lang.Integer#toString(int, int)
      */
     public static String valueOf(int i) {
-        return Integer.toString(i, 10);
+        return Integer.toString(i);
     }
 
     /**
@@ -3009,7 +3009,7 @@
      * @see     java.lang.Long#toString(long)
      */
     public static String valueOf(long l) {
-        return Long.toString(l, 10);
+        return Long.toString(l);
     }
 
     /**
--- a/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/java/lang/reflect/AccessibleObject.java	Wed Oct 14 14:21:25 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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/java/util/Objects.java	Wed Oct 14 14:21:25 2009 -0700
@@ -0,0 +1,110 @@
+/*
+ * 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);
+    }
+}
--- a/jdk/src/share/classes/sun/security/provider/SunEntries.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/SunEntries.java	Wed Oct 14 14:21:25 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 14 14:21:25 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	Wed Oct 07 08:38:43 2009 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1065 +0,0 @@
-/*
- * Copyright 2000-2006 Sun Microsystems, Inc.  All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
-
-package sun.security.provider.certpath;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.net.URI;
-import java.util.*;
-import javax.naming.Context;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.NameNotFoundException;
-import javax.naming.directory.Attribute;
-import javax.naming.directory.Attributes;
-import javax.naming.directory.BasicAttributes;
-import javax.naming.directory.DirContext;
-import javax.naming.directory.InitialDirContext;
-
-import java.security.*;
-import java.security.cert.Certificate;
-import java.security.cert.*;
-import javax.security.auth.x500.X500Principal;
-
-import sun.misc.HexDumpEncoder;
-import sun.security.util.Cache;
-import sun.security.util.Debug;
-import sun.security.x509.X500Name;
-import sun.security.action.GetPropertyAction;
-
-/**
- * A <code>CertStore</code> that retrieves <code>Certificates</code> and
- * <code>CRL</code>s from an LDAP directory, using the PKIX LDAP V2 Schema
- * (RFC 2587):
- * <a href="http://www.ietf.org/rfc/rfc2587.txt">
- * http://www.ietf.org/rfc/rfc2587.txt</a>.
- * <p>
- * Before calling the {@link #engineGetCertificates engineGetCertificates} or
- * {@link #engineGetCRLs engineGetCRLs} methods, the
- * {@link #LDAPCertStore(CertStoreParameters)
- * LDAPCertStore(CertStoreParameters)} constructor is called to create the
- * <code>CertStore</code> and establish the DNS name and port of the LDAP
- * server from which <code>Certificate</code>s and <code>CRL</code>s will be
- * retrieved.
- * <p>
- * <b>Concurrent Access</b>
- * <p>
- * As described in the javadoc for <code>CertStoreSpi</code>, the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods
- * must be thread-safe. That is, multiple threads may concurrently
- * invoke these methods on a single <code>LDAPCertStore</code> object
- * (or more than one) with no ill effects. This allows a
- * <code>CertPathBuilder</code> to search for a CRL while simultaneously
- * searching for further certificates, for instance.
- * <p>
- * This is achieved by adding the <code>synchronized</code> keyword to the
- * <code>engineGetCertificates</code> and <code>engineGetCRLs</code> methods.
- * <p>
- * This classes uses caching and requests multiple attributes at once to
- * minimize LDAP round trips. The cache is associated with the CertStore
- * instance. It uses soft references to hold the values to minimize impact
- * on footprint and currently has a maximum size of 750 attributes and a
- * 30 second default lifetime.
- * <p>
- * We always request CA certificates, cross certificate pairs, and ARLs in
- * a single LDAP request when any one of them is needed. The reason is that
- * we typically need all of them anyway and requesting them in one go can
- * reduce the number of requests to a third. Even if we don't need them,
- * these attributes are typically small enough not to cause a noticeable
- * overhead. In addition, when the prefetchCRLs flag is true, we also request
- * the full CRLs. It is currently false initially but set to true once any
- * request for an ARL to the server returns an null value. The reason is
- * that CRLs could be rather large but are rarely used. This implementation
- * should improve performance in most cases.
- *
- * @see java.security.cert.CertStore
- *
- * @since       1.4
- * @author      Steve Hanna
- * @author      Andreas Sterbenz
- */
-public class LDAPCertStore extends CertStoreSpi {
-
-    private static final Debug debug = Debug.getInstance("certpath");
-
-    private final static boolean DEBUG = false;
-
-    /**
-     * LDAP attribute identifiers.
-     */
-    private static final String USER_CERT = "userCertificate;binary";
-    private static final String CA_CERT = "cACertificate;binary";
-    private static final String CROSS_CERT = "crossCertificatePair;binary";
-    private static final String CRL = "certificateRevocationList;binary";
-    private static final String ARL = "authorityRevocationList;binary";
-    private static final String DELTA_CRL = "deltaRevocationList;binary";
-
-    // Constants for various empty values
-    private final static String[] STRING0 = new String[0];
-
-    private final static byte[][] BB0 = new byte[0][];
-
-    private final static Attributes EMPTY_ATTRIBUTES = new BasicAttributes();
-
-    // cache related constants
-    private final static int DEFAULT_CACHE_SIZE = 750;
-    private final static int DEFAULT_CACHE_LIFETIME = 30;
-
-    private final static int LIFETIME;
-
-    private final static String PROP_LIFETIME =
-                            "sun.security.certpath.ldap.cache.lifetime";
-
-    static {
-        String s = AccessController.doPrivileged(
-                                new GetPropertyAction(PROP_LIFETIME));
-        if (s != null) {
-            LIFETIME = Integer.parseInt(s); // throws NumberFormatException
-        } else {
-            LIFETIME = DEFAULT_CACHE_LIFETIME;
-        }
-    }
-
-    /**
-     * The CertificateFactory used to decode certificates from
-     * their binary stored form.
-     */
-    private CertificateFactory cf;
-    /**
-     * The JNDI directory context.
-     */
-    private DirContext ctx;
-
-    /**
-     * Flag indicating whether we should prefetch CRLs.
-     */
-    private boolean prefetchCRLs = false;
-
-    private final Cache valueCache;
-
-    private int cacheHits = 0;
-    private int cacheMisses = 0;
-    private int requests = 0;
-
-    /**
-     * Creates a <code>CertStore</code> with the specified parameters.
-     * For this class, the parameters object must be an instance of
-     * <code>LDAPCertStoreParameters</code>.
-     *
-     * @param params the algorithm parameters
-     * @exception InvalidAlgorithmParameterException if params is not an
-     *   instance of <code>LDAPCertStoreParameters</code>
-     */
-    public LDAPCertStore(CertStoreParameters params)
-            throws InvalidAlgorithmParameterException {
-        super(params);
-        if (!(params instanceof LDAPCertStoreParameters))
-          throw new InvalidAlgorithmParameterException(
-            "parameters must be LDAPCertStoreParameters");
-
-        LDAPCertStoreParameters lparams = (LDAPCertStoreParameters) params;
-
-        // Create InitialDirContext needed to communicate with the server
-        createInitialDirContext(lparams.getServerName(), lparams.getPort());
-
-        // Create CertificateFactory for use later on
-        try {
-            cf = CertificateFactory.getInstance("X.509");
-        } catch (CertificateException e) {
-            throw new InvalidAlgorithmParameterException(
-                "unable to create CertificateFactory for X.509");
-        }
-        if (LIFETIME == 0) {
-            valueCache = Cache.newNullCache();
-        } else if (LIFETIME < 0) {
-            valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE);
-        } else {
-            valueCache = Cache.newSoftMemoryCache(DEFAULT_CACHE_SIZE, LIFETIME);
-        }
-    }
-
-    /**
-     * Returns an LDAP CertStore. This method consults a cache of
-     * CertStores (shared per JVM) using the LDAP server/port as a key.
-     */
-    private static final Cache certStoreCache = Cache.newSoftMemoryCache(185);
-    static synchronized CertStore getInstance(LDAPCertStoreParameters params)
-        throws NoSuchAlgorithmException, InvalidAlgorithmParameterException {
-        CertStore lcs = (CertStore) certStoreCache.get(params);
-        if (lcs == null) {
-            lcs = CertStore.getInstance("LDAP", params);
-            certStoreCache.put(params, lcs);
-        } else {
-            if (debug != null) {
-                debug.println("LDAPCertStore.getInstance: cache hit");
-            }
-        }
-        return lcs;
-    }
-
-    /**
-     * Create InitialDirContext.
-     *
-     * @param server Server DNS name hosting LDAP service
-     * @param port   Port at which server listens for requests
-     * @throws InvalidAlgorithmParameterException if creation fails
-     */
-    private void createInitialDirContext(String server, int port)
-            throws InvalidAlgorithmParameterException {
-        String url = "ldap://" + server + ":" + port;
-        Hashtable<String,Object> env = new Hashtable<String,Object>();
-        env.put(Context.INITIAL_CONTEXT_FACTORY,
-                "com.sun.jndi.ldap.LdapCtxFactory");
-        env.put(Context.PROVIDER_URL, url);
-        try {
-            ctx = new InitialDirContext(env);
-            /*
-             * By default, follow referrals unless application has
-             * overridden property in an application resource file.
-             */
-            Hashtable<?,?> currentEnv = ctx.getEnvironment();
-            if (currentEnv.get(Context.REFERRAL) == null) {
-                ctx.addToEnvironment(Context.REFERRAL, "follow");
-            }
-        } catch (NamingException e) {
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineInit about to throw "
-                    + "InvalidAlgorithmParameterException");
-                e.printStackTrace();
-            }
-            Exception ee = new InvalidAlgorithmParameterException
-                ("unable to create InitialDirContext using supplied parameters");
-            ee.initCause(e);
-            throw (InvalidAlgorithmParameterException)ee;
-        }
-    }
-
-    /**
-     * Private class encapsulating the actual LDAP operations and cache
-     * handling. Use:
-     *
-     *   LDAPRequest request = new LDAPRequest(dn);
-     *   request.addRequestedAttribute(CROSS_CERT);
-     *   request.addRequestedAttribute(CA_CERT);
-     *   byte[][] crossValues = request.getValues(CROSS_CERT);
-     *   byte[][] caValues = request.getValues(CA_CERT);
-     *
-     * At most one LDAP request is sent for each instance created. If all
-     * getValues() calls can be satisfied from the cache, no request
-     * is sent at all. If a request is sent, all requested attributes
-     * are always added to the cache irrespective of whether the getValues()
-     * method is called.
-     */
-    private class LDAPRequest {
-
-        private final String name;
-        private Map<String, byte[][]> valueMap;
-        private final List<String> requestedAttributes;
-
-        LDAPRequest(String name) {
-            this.name = name;
-            requestedAttributes = new ArrayList<String>(5);
-        }
-
-        String getName() {
-            return name;
-        }
-
-        void addRequestedAttribute(String attrId) {
-            if (valueMap != null) {
-                throw new IllegalStateException("Request already sent");
-            }
-            requestedAttributes.add(attrId);
-        }
-
-        /**
-         * Gets one or more binary values from an attribute.
-         *
-         * @param name          the location holding the attribute
-         * @param attrId                the attribute identifier
-         * @return                      an array of binary values (byte arrays)
-         * @throws NamingException      if a naming exception occurs
-         */
-        byte[][] getValues(String attrId) throws NamingException {
-            if (DEBUG && ((cacheHits + cacheMisses) % 50 == 0)) {
-                System.out.println("Cache hits: " + cacheHits + "; misses: "
-                        + cacheMisses);
-            }
-            String cacheKey = name + "|" + attrId;
-            byte[][] values = (byte[][])valueCache.get(cacheKey);
-            if (values != null) {
-                cacheHits++;
-                return values;
-            }
-            cacheMisses++;
-            Map<String, byte[][]> attrs = getValueMap();
-            values = attrs.get(attrId);
-            return values;
-        }
-
-        /**
-         * Get a map containing the values for this request. The first time
-         * this method is called on an object, the LDAP request is sent,
-         * the results parsed and added to a private map and also to the
-         * cache of this LDAPCertStore. Subsequent calls return the private
-         * map immediately.
-         *
-         * The map contains an entry for each requested attribute. The
-         * attribute name is the key, values are byte[][]. If there are no
-         * values for that attribute, values are byte[0][].
-         *
-         * @return                      the value Map
-         * @throws NamingException      if a naming exception occurs
-         */
-        private Map<String, byte[][]> getValueMap() throws NamingException {
-            if (valueMap != null) {
-                return valueMap;
-            }
-            if (DEBUG) {
-                System.out.println("Request: " + name + ":" + requestedAttributes);
-                requests++;
-                if (requests % 5 == 0) {
-                    System.out.println("LDAP requests: " + requests);
-                }
-            }
-            valueMap = new HashMap<String, byte[][]>(8);
-            String[] attrIds = requestedAttributes.toArray(STRING0);
-            Attributes attrs;
-            try {
-                attrs = ctx.getAttributes(name, attrIds);
-            } catch (NameNotFoundException e) {
-                // name does not exist on this LDAP server
-                // treat same as not attributes found
-                attrs = EMPTY_ATTRIBUTES;
-            }
-            for (String attrId : requestedAttributes) {
-                Attribute attr = attrs.get(attrId);
-                byte[][] values = getAttributeValues(attr);
-                cacheAttribute(attrId, values);
-                valueMap.put(attrId, values);
-            }
-            return valueMap;
-        }
-
-        /**
-         * Add the values to the cache.
-         */
-        private void cacheAttribute(String attrId, byte[][] values) {
-            String cacheKey = name + "|" + attrId;
-            valueCache.put(cacheKey, values);
-        }
-
-        /**
-         * Get the values for the given attribute. If the attribute is null
-         * or does not contain any values, a zero length byte array is
-         * returned. NOTE that it is assumed that all values are byte arrays.
-         */
-        private byte[][] getAttributeValues(Attribute attr)
-                throws NamingException {
-            byte[][] values;
-            if (attr == null) {
-                values = BB0;
-            } else {
-                values = new byte[attr.size()][];
-                int i = 0;
-                NamingEnumeration<?> enum_ = attr.getAll();
-                while (enum_.hasMore()) {
-                    Object obj = enum_.next();
-                    if (debug != null) {
-                        if (obj instanceof String) {
-                            debug.println("LDAPCertStore.getAttrValues() "
-                                + "enum.next is a string!: " + obj);
-                        }
-                    }
-                    byte[] value = (byte[])obj;
-                    values[i++] = value;
-                }
-            }
-            return values;
-        }
-
-    }
-
-    /*
-     * Gets certificates from an attribute id and location in the LDAP
-     * directory. Returns a Collection containing only the Certificates that
-     * match the specified CertSelector.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @param sel a CertSelector that the Certificates must match
-     * @return a Collection of Certificates found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509Certificate> getCertificates(LDAPRequest request,
-        String id, X509CertSelector sel) throws CertStoreException {
-
-        /* fetch encoded certs from storage */
-        byte[][] encodedCert;
-        try {
-            encodedCert = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCert.length;
-        if (n == 0) {
-            return Collections.<X509Certificate>emptySet();
-        }
-
-        List<X509Certificate> certs = new ArrayList<X509Certificate>(n);
-        /* decode certs and check if they satisfy selector */
-        for (int i = 0; i < n; i++) {
-            ByteArrayInputStream bais = new ByteArrayInputStream(encodedCert[i]);
-            try {
-                Certificate cert = cf.generateCertificate(bais);
-                if (sel.match(cert)) {
-                  certs.add((X509Certificate)cert);
-                }
-            } catch (CertificateException e) {
-                if (debug != null) {
-                    debug.println("LDAPCertStore.getCertificates() encountered "
-                        + "exception while parsing cert, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println(
-                        "[ " + encoder.encodeBuffer(encodedCert[i]) + " ]");
-                }
-            }
-        }
-
-        return certs;
-    }
-
-    /*
-     * Gets certificate pairs from an attribute id and location in the LDAP
-     * directory.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @return a Collection of X509CertificatePairs found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509CertificatePair> getCertPairs(
-        LDAPRequest request, String id) throws CertStoreException {
-
-        /* fetch the encoded cert pairs from storage */
-        byte[][] encodedCertPair;
-        try {
-            encodedCertPair = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCertPair.length;
-        if (n == 0) {
-            return Collections.<X509CertificatePair>emptySet();
-        }
-
-        List<X509CertificatePair> certPairs =
-                                new ArrayList<X509CertificatePair>(n);
-        /* decode each cert pair and add it to the Collection */
-        for (int i = 0; i < n; i++) {
-            try {
-                X509CertificatePair certPair =
-                    X509CertificatePair.generateCertificatePair(encodedCertPair[i]);
-                certPairs.add(certPair);
-            } catch (CertificateException e) {
-                if (debug != null) {
-                    debug.println(
-                        "LDAPCertStore.getCertPairs() encountered exception "
-                        + "while parsing cert, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println(
-                        "[ " + encoder.encodeBuffer(encodedCertPair[i]) + " ]");
-                }
-            }
-        }
-
-        return certPairs;
-    }
-
-    /*
-     * Looks at certificate pairs stored in the crossCertificatePair attribute
-     * at the specified location in the LDAP directory. Returns a Collection
-     * containing all Certificates stored in the forward component that match
-     * the forward CertSelector and all Certificates stored in the reverse
-     * component that match the reverse CertSelector.
-     * <p>
-     * If either forward or reverse is null, all certificates from the
-     * corresponding component will be rejected.
-     *
-     * @param name the location to look in
-     * @param forward the forward CertSelector (or null)
-     * @param reverse the reverse CertSelector (or null)
-     * @return a Collection of Certificates found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509Certificate> getMatchingCrossCerts(
-            LDAPRequest request, X509CertSelector forward,
-            X509CertSelector reverse)
-            throws CertStoreException {
-        // Get the cert pairs
-        Collection<X509CertificatePair> certPairs =
-                                getCertPairs(request, CROSS_CERT);
-
-        // Find Certificates that match and put them in a list
-        ArrayList<X509Certificate> matchingCerts =
-                                        new ArrayList<X509Certificate>();
-        for (X509CertificatePair certPair : certPairs) {
-            X509Certificate cert;
-            if (forward != null) {
-                cert = certPair.getForward();
-                if ((cert != null) && forward.match(cert)) {
-                    matchingCerts.add(cert);
-                }
-            }
-            if (reverse != null) {
-                cert = certPair.getReverse();
-                if ((cert != null) && reverse.match(cert)) {
-                    matchingCerts.add(cert);
-                }
-            }
-        }
-        return matchingCerts;
-    }
-
-    /**
-     * Returns a <code>Collection</code> of <code>Certificate</code>s that
-     * match the specified selector. If no <code>Certificate</code>s
-     * match the selector, an empty <code>Collection</code> will be returned.
-     * <p>
-     * It is not practical to search every entry in the LDAP database for
-     * matching <code>Certificate</code>s. Instead, the <code>CertSelector</code>
-     * is examined in order to determine where matching <code>Certificate</code>s
-     * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
-     * If the subject is specified, its directory entry is searched. If the
-     * issuer is specified, its directory entry is searched. If neither the
-     * subject nor the issuer are specified (or the selector is not an
-     * <code>X509CertSelector</code>), a <code>CertStoreException</code> is
-     * thrown.
-     *
-     * @param selector a <code>CertSelector</code> used to select which
-     *  <code>Certificate</code>s should be returned.
-     * @return a <code>Collection</code> of <code>Certificate</code>s that
-     *         match the specified selector
-     * @throws CertStoreException if an exception occurs
-     */
-    public synchronized Collection<X509Certificate> engineGetCertificates
-            (CertSelector selector) throws CertStoreException {
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() selector: "
-                + String.valueOf(selector));
-        }
-
-        if (selector == null) {
-            selector = new X509CertSelector();
-        }
-        if (!(selector instanceof X509CertSelector)) {
-            throw new CertStoreException("LDAPCertStore needs an X509CertSelector " +
-                                         "to find certs");
-        }
-        X509CertSelector xsel = (X509CertSelector) selector;
-        int basicConstraints = xsel.getBasicConstraints();
-        String subject = xsel.getSubjectAsString();
-        String issuer = xsel.getIssuerAsString();
-        HashSet<X509Certificate> certs = new HashSet<X509Certificate>();
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() basicConstraints: "
-                + basicConstraints);
-        }
-
-        // basicConstraints:
-        // -2: only EE certs accepted
-        // -1: no check is done
-        //  0: any CA certificate accepted
-        // >1: certificate's basicConstraints extension pathlen must match
-        if (subject != null) {
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() "
-                    + "subject is not null");
-            }
-            LDAPRequest request = new LDAPRequest(subject);
-            if (basicConstraints > -2) {
-                request.addRequestedAttribute(CROSS_CERT);
-                request.addRequestedAttribute(CA_CERT);
-                request.addRequestedAttribute(ARL);
-                if (prefetchCRLs) {
-                    request.addRequestedAttribute(CRL);
-                }
-            }
-            if (basicConstraints < 0) {
-                request.addRequestedAttribute(USER_CERT);
-            }
-
-            if (basicConstraints > -2) {
-                certs.addAll(getMatchingCrossCerts(request, xsel, null));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getMatchingCrossCerts(subject,xsel,null),certs.size(): "
-                        + certs.size());
-                }
-                certs.addAll(getCertificates(request, CA_CERT, xsel));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getCertificates(subject,CA_CERT,xsel),certs.size(): "
-                        + certs.size());
-                }
-            }
-            if (basicConstraints < 0) {
-                certs.addAll(getCertificates(request, USER_CERT, xsel));
-                if (debug != null) {
-                    debug.println("LDAPCertStore.engineGetCertificates() after "
-                        + "getCertificates(subject,USER_CERT, xsel),certs.size(): "
-                        + certs.size());
-                }
-            }
-        } else {
-            if (debug != null) {
-                debug.println
-                    ("LDAPCertStore.engineGetCertificates() subject is null");
-            }
-            if (basicConstraints == -2) {
-                throw new CertStoreException("need subject to find EE certs");
-            }
-            if (issuer == null) {
-                throw new CertStoreException("need subject or issuer to find certs");
-            }
-        }
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() about to "
-                + "getMatchingCrossCerts...");
-        }
-        if ((issuer != null) && (basicConstraints > -2)) {
-            LDAPRequest request = new LDAPRequest(issuer);
-            request.addRequestedAttribute(CROSS_CERT);
-            request.addRequestedAttribute(CA_CERT);
-            request.addRequestedAttribute(ARL);
-            if (prefetchCRLs) {
-                request.addRequestedAttribute(CRL);
-            }
-
-            certs.addAll(getMatchingCrossCerts(request, null, xsel));
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() after "
-                    + "getMatchingCrossCerts(issuer,null,xsel),certs.size(): "
-                    + certs.size());
-            }
-            certs.addAll(getCertificates(request, CA_CERT, xsel));
-            if (debug != null) {
-                debug.println("LDAPCertStore.engineGetCertificates() after "
-                    + "getCertificates(issuer,CA_CERT,xsel),certs.size(): "
-                    + certs.size());
-            }
-        }
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCertificates() returning certs");
-        }
-        return certs;
-    }
-
-    /*
-     * Gets CRLs from an attribute id and location in the LDAP directory.
-     * Returns a Collection containing only the CRLs that match the
-     * specified CRLSelector.
-     *
-     * @param name the location holding the attribute
-     * @param id the attribute identifier
-     * @param sel a CRLSelector that the CRLs must match
-     * @return a Collection of CRLs found
-     * @throws CertStoreException       if an exception occurs
-     */
-    private Collection<X509CRL> getCRLs(LDAPRequest request, String id,
-            X509CRLSelector sel) throws CertStoreException {
-
-        /* fetch the encoded crls from storage */
-        byte[][] encodedCRL;
-        try {
-            encodedCRL = request.getValues(id);
-        } catch (NamingException namingEx) {
-            throw new CertStoreException(namingEx);
-        }
-
-        int n = encodedCRL.length;
-        if (n == 0) {
-            return Collections.<X509CRL>emptySet();
-        }
-
-        List<X509CRL> crls = new ArrayList<X509CRL>(n);
-        /* decode each crl and check if it matches selector */
-        for (int i = 0; i < n; i++) {
-            try {
-                CRL crl = cf.generateCRL(new ByteArrayInputStream(encodedCRL[i]));
-                if (sel.match(crl)) {
-                    crls.add((X509CRL)crl);
-                }
-            } catch (CRLException e) {
-                if (debug != null) {
-                    debug.println("LDAPCertStore.getCRLs() encountered exception"
-                        + " while parsing CRL, skipping the bad data: ");
-                    HexDumpEncoder encoder = new HexDumpEncoder();
-                    debug.println("[ " + encoder.encodeBuffer(encodedCRL[i]) + " ]");
-                }
-            }
-        }
-
-        return crls;
-    }
-
-    /**
-     * Returns a <code>Collection</code> of <code>CRL</code>s that
-     * match the specified selector. If no <code>CRL</code>s
-     * match the selector, an empty <code>Collection</code> will be returned.
-     * <p>
-     * It is not practical to search every entry in the LDAP database for
-     * matching <code>CRL</code>s. Instead, the <code>CRLSelector</code>
-     * is examined in order to determine where matching <code>CRL</code>s
-     * are likely to be found (according to the PKIX LDAPv2 schema, RFC 2587).
-     * If issuerNames or certChecking are specified, the issuer's directory
-     * entry is searched. If neither issuerNames or certChecking are specified
-     * (or the selector is not an <code>X509CRLSelector</code>), a
-     * <code>CertStoreException</code> is thrown.
-     *
-     * @param selector A <code>CRLSelector</code> used to select which
-     *  <code>CRL</code>s should be returned. Specify <code>null</code>
-     *  to return all <code>CRL</code>s.
-     * @return A <code>Collection</code> of <code>CRL</code>s that
-     *         match the specified selector
-     * @throws CertStoreException if an exception occurs
-     */
-    public synchronized Collection<X509CRL> engineGetCRLs(CRLSelector selector)
-            throws CertStoreException {
-        if (debug != null) {
-            debug.println("LDAPCertStore.engineGetCRLs() selector: "
-                + selector);
-        }
-        // Set up selector and collection to hold CRLs
-        if (selector == null) {
-            selector = new X509CRLSelector();
-        }
-        if (!(selector instanceof X509CRLSelector)) {
-            throw new CertStoreException("need X509CRLSelector to find CRLs");
-        }
-        X509CRLSelector xsel = (X509CRLSelector) selector;
-        HashSet<X509CRL> crls = new HashSet<X509CRL>();
-
-        // Look in directory entry for issuer of cert we're checking.
-        Collection<Object> issuerNames;
-        X509Certificate certChecking = xsel.getCertificateChecking();
-        if (certChecking != null) {
-            issuerNames = new HashSet<Object>();
-            X500Principal issuer = certChecking.getIssuerX500Principal();
-            issuerNames.add(issuer.getName(X500Principal.RFC2253));
-        } else {
-            // But if we don't know which cert we're checking, try the directory
-            // entries of all acceptable CRL issuers
-            issuerNames = xsel.getIssuerNames();
-            if (issuerNames == null) {
-                throw new CertStoreException("need issuerNames or certChecking to "
-                    + "find CRLs");
-            }
-        }
-        for (Object nameObject : issuerNames) {
-            String issuerName;
-            if (nameObject instanceof byte[]) {
-                try {
-                    X500Principal issuer = new X500Principal((byte[])nameObject);
-                    issuerName = issuer.getName(X500Principal.RFC2253);
-                } catch (IllegalArgumentException e) {
-                    continue;
-                }
-            } else {
-                issuerName = (String)nameObject;
-            }
-            // If all we want is CA certs, try to get the (probably shorter) ARL
-            Collection<X509CRL> entryCRLs = Collections.<X509CRL>emptySet();
-            if (certChecking == null || certChecking.getBasicConstraints() != -1) {
-                LDAPRequest request = new LDAPRequest(issuerName);
-                request.addRequestedAttribute(CROSS_CERT);
-                request.addRequestedAttribute(CA_CERT);
-                request.addRequestedAttribute(ARL);
-                if (prefetchCRLs) {
-                    request.addRequestedAttribute(CRL);
-                }
-                try {
-                    entryCRLs = getCRLs(request, ARL, xsel);
-                    if (entryCRLs.isEmpty()) {
-                        // no ARLs found. We assume that means that there are
-                        // no ARLs on this server at all and prefetch the CRLs.
-                        prefetchCRLs = true;
-                    } else {
-                        crls.addAll(entryCRLs);
-                    }
-                } catch (CertStoreException e) {
-                    if (debug != null) {
-                        debug.println("LDAPCertStore.engineGetCRLs non-fatal error "
-                            + "retrieving ARLs:" + e);
-                        e.printStackTrace();
-                    }
-                }
-            }
-            // Otherwise, get the CRL
-            // if certChecking is null, we don't know if we should look in ARL or CRL
-            // attribute, so check both for matching CRLs.
-            if (entryCRLs.isEmpty() || certChecking == null) {
-                LDAPRequest request = new LDAPRequest(issuerName);
-                request.addRequestedAttribute(CRL);
-                entryCRLs = getCRLs(request, CRL, xsel);
-                crls.addAll(entryCRLs);
-            }
-        }
-        return crls;
-    }
-
-    // converts an LDAP URI into LDAPCertStoreParameters
-    static LDAPCertStoreParameters getParameters(URI uri) {
-        String host = uri.getHost();
-        if (host == null) {
-            return new SunLDAPCertStoreParameters();
-        } else {
-            int port = uri.getPort();
-            return (port == -1
-                    ? new SunLDAPCertStoreParameters(host)
-                    : new SunLDAPCertStoreParameters(host, port));
-        }
-    }
-
-    /*
-     * Subclass of LDAPCertStoreParameters with overridden equals/hashCode
-     * methods. This is necessary because the parameters are used as
-     * keys in the LDAPCertStore cache.
-     */
-    private static class SunLDAPCertStoreParameters
-        extends LDAPCertStoreParameters {
-
-        private volatile int hashCode = 0;
-
-        SunLDAPCertStoreParameters(String serverName, int port) {
-            super(serverName, port);
-        }
-        SunLDAPCertStoreParameters(String serverName) {
-            super(serverName);
-        }
-        SunLDAPCertStoreParameters() {
-            super();
-        }
-        public boolean equals(Object obj) {
-            if (!(obj instanceof LDAPCertStoreParameters)) {
-                return false;
-            }
-            LDAPCertStoreParameters params = (LDAPCertStoreParameters) obj;
-            return (getPort() == params.getPort() &&
-                    getServerName().equalsIgnoreCase(params.getServerName()));
-        }
-        public int hashCode() {
-            if (hashCode == 0) {
-                int result = 17;
-                result = 37*result + getPort();
-                result = 37*result + getServerName().toLowerCase().hashCode();
-                hashCode = result;
-            }
-            return hashCode;
-        }
-    }
-
-    /*
-     * This inner class wraps an existing X509CertSelector and adds
-     * additional criteria to match on when the certificate's subject is
-     * different than the LDAP Distinguished Name entry. The LDAPCertStore
-     * implementation uses the subject DN as the directory entry for
-     * looking up certificates. This can be problematic if the certificates
-     * that you want to fetch have a different subject DN than the entry
-     * where they are stored. You could set the selector's subject to the
-     * LDAP DN entry, but then the resulting match would fail to find the
-     * desired certificates because the subject DNs would not match. This
-     * class avoids that problem by introducing a certSubject which should
-     * be set to the certificate's subject DN when it is different than
-     * the LDAP DN.
-     */
-    static class LDAPCertSelector extends X509CertSelector {
-
-        private X500Principal certSubject;
-        private X509CertSelector selector;
-        private X500Principal subject;
-
-        /**
-         * Creates an LDAPCertSelector.
-         *
-         * @param selector the X509CertSelector to wrap
-         * @param certSubject the subject DN of the certificate that you want
-         *      to retrieve via LDAP
-         * @param ldapDN the LDAP DN where the certificate is stored
-         */
-        LDAPCertSelector(X509CertSelector selector, X500Principal certSubject,
-            String ldapDN) throws IOException {
-            this.selector = selector == null ? new X509CertSelector() : selector;
-            this.certSubject = certSubject;
-            this.subject = new X500Name(ldapDN).asX500Principal();
-        }
-
-        // we only override the get (accessor methods) since the set methods
-        // will not be invoked by the code that uses this LDAPCertSelector.
-        public X509Certificate getCertificate() {
-            return selector.getCertificate();
-        }
-        public BigInteger getSerialNumber() {
-            return selector.getSerialNumber();
-        }
-        public X500Principal getIssuer() {
-            return selector.getIssuer();
-        }
-        public String getIssuerAsString() {
-            return selector.getIssuerAsString();
-        }
-        public byte[] getIssuerAsBytes() throws IOException {
-            return selector.getIssuerAsBytes();
-        }
-        public X500Principal getSubject() {
-            // return the ldap DN
-            return subject;
-        }
-        public String getSubjectAsString() {
-            // return the ldap DN
-            return subject.getName();
-        }
-        public byte[] getSubjectAsBytes() throws IOException {
-            // return the encoded ldap DN
-            return subject.getEncoded();
-        }
-        public byte[] getSubjectKeyIdentifier() {
-            return selector.getSubjectKeyIdentifier();
-        }
-        public byte[] getAuthorityKeyIdentifier() {
-            return selector.getAuthorityKeyIdentifier();
-        }
-        public Date getCertificateValid() {
-            return selector.getCertificateValid();
-        }
-        public Date getPrivateKeyValid() {
-            return selector.getPrivateKeyValid();
-        }
-        public String getSubjectPublicKeyAlgID() {
-            return selector.getSubjectPublicKeyAlgID();
-        }
-        public PublicKey getSubjectPublicKey() {
-            return selector.getSubjectPublicKey();
-        }
-        public boolean[] getKeyUsage() {
-            return selector.getKeyUsage();
-        }
-        public Set<String> getExtendedKeyUsage() {
-            return selector.getExtendedKeyUsage();
-        }
-        public boolean getMatchAllSubjectAltNames() {
-            return selector.getMatchAllSubjectAltNames();
-        }
-        public Collection<List<?>> getSubjectAlternativeNames() {
-            return selector.getSubjectAlternativeNames();
-        }
-        public byte[] getNameConstraints() {
-            return selector.getNameConstraints();
-        }
-        public int getBasicConstraints() {
-            return selector.getBasicConstraints();
-        }
-        public Set<String> getPolicy() {
-            return selector.getPolicy();
-        }
-        public Collection<List<?>> getPathToNames() {
-            return selector.getPathToNames();
-        }
-
-        public boolean match(Certificate cert) {
-            // temporarily set the subject criterion to the certSubject
-            // so that match will not reject the desired certificates
-            selector.setSubject(certSubject);
-            boolean match = selector.match(cert);
-            selector.setSubject(subject);
-            return match;
-        }
-    }
-
-    /**
-     * This class has the same purpose as LDAPCertSelector except it is for
-     * X.509 CRLs.
-     */
-    static class LDAPCRLSelector extends X509CRLSelector {
-
-        private X509CRLSelector selector;
-        private Collection<X500Principal> certIssuers;
-        private Collection<X500Principal> issuers;
-        private HashSet<Object> issuerNames;
-
-        /**
-         * Creates an LDAPCRLSelector.
-         *
-         * @param selector the X509CRLSelector to wrap
-         * @param certIssuers the issuer DNs of the CRLs that you want
-         *      to retrieve via LDAP
-         * @param ldapDN the LDAP DN where the CRL is stored
-         */
-        LDAPCRLSelector(X509CRLSelector selector,
-            Collection<X500Principal> certIssuers, String ldapDN)
-            throws IOException {
-            this.selector = selector == null ? new X509CRLSelector() : selector;
-            this.certIssuers = certIssuers;
-            issuerNames = new HashSet<Object>();
-            issuerNames.add(ldapDN);
-            issuers = new HashSet<X500Principal>();
-            issuers.add(new X500Name(ldapDN).asX500Principal());
-        }
-        // we only override the get (accessor methods) since the set methods
-        // will not be invoked by the code that uses this LDAPCRLSelector.
-        public Collection<X500Principal> getIssuers() {
-            // return the ldap DN
-            return Collections.unmodifiableCollection(issuers);
-        }
-        public Collection<Object> getIssuerNames() {
-            // return the ldap DN
-            return Collections.unmodifiableCollection(issuerNames);
-        }
-        public BigInteger getMinCRL() {
-            return selector.getMinCRL();
-        }
-        public BigInteger getMaxCRL() {
-            return selector.getMaxCRL();
-        }
-        public Date getDateAndTime() {
-            return selector.getDateAndTime();
-        }
-        public X509Certificate getCertificateChecking() {
-            return selector.getCertificateChecking();
-        }
-        public boolean match(CRL crl) {
-            // temporarily set the issuer criterion to the certIssuers
-            // so that match will not reject the desired CRL
-            selector.setIssuers(certIssuers);
-            boolean match = selector.match(crl);
-            selector.setIssuers(issuers);
-            return match;
-        }
-    }
-}
--- a/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSP.java	Wed Oct 14 14:21:25 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	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/OCSPChecker.java	Wed Oct 14 14:21:25 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	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/src/share/classes/sun/security/provider/certpath/URICertStore.java	Wed Oct 14 14:21:25 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 14 14:21:25 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 14 14:21:25 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);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/lang/reflect/DefaultAccessibility.java	Wed Oct 14 14:21:25 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/net/MulticastSocket/SetOutgoingIf.java	Wed Oct 07 08:38:43 2009 -0700
+++ b/jdk/test/java/net/MulticastSocket/SetOutgoingIf.java	Wed Oct 14 14:21:25 2009 -0700
@@ -27,7 +27,6 @@
  * @summary Re-test IPv6 (and specifically MulticastSocket) with latest Linux & USAGI code
  */
 import java.net.*;
-import java.util.concurrent.*;
 import java.util.*;
 
 
@@ -68,38 +67,61 @@
 
         // We need 2 or more network interfaces to run the test
         //
-        List<NetworkInterface> nics = new ArrayList<NetworkInterface>();
+        List<NetIf> netIfs = new ArrayList<NetIf>();
+        int index = 1;
         for (NetworkInterface nic : Collections.list(NetworkInterface.getNetworkInterfaces())) {
             // we should use only network interfaces with multicast support which are in "up" state
-            if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp())
-                nics.add(nic);
+            if (!nic.isLoopback() && nic.supportsMulticast() && nic.isUp()) {
+                NetIf netIf = NetIf.create(nic);
+
+                // now determine what (if any) type of addresses are assigned to this interface
+                for (InetAddress addr : Collections.list(nic.getInetAddresses())) {
+                    if (addr instanceof Inet4Address) {
+                        netIf.ipv4Address(true);
+                    } else if (addr instanceof Inet6Address) {
+                        netIf.ipv6Address(true);
+                    }
+                }
+                if (netIf.ipv4Address() || netIf.ipv6Address()) {
+                    netIf.index(index++);
+                    netIfs.add(netIf);
+                    debug("Using: " + nic);
+                }
+            }
         }
-        if (nics.size() <= 1) {
+        if (netIfs.size() <= 1) {
             System.out.println("Need 2 or more network interfaces to run. Bye.");
             return;
         }
 
-        // We will send packets to one ipv4, one ipv4-mapped, and one ipv6
+        // We will send packets to one ipv4, and one ipv6
         // multicast group using each network interface :-
         //      224.1.1.1        --|
-        //      ::ffff:224.1.1.2 -----> using network interface #1
-        //      ff02::1:1        --|
+        //      ff02::1:1        --|--> using network interface #1
         //      224.1.2.1        --|
-        //      ::ffff:224.1.2.2 -----> using network interface #2
-        //      ff02::1:2        --|
+        //      ff02::1:2        --|--> using network interface #2
         // and so on.
         //
-        List<InetAddress> groups = new ArrayList<InetAddress>();
-        for (int i = 0; i < nics.size(); i++) {
-            InetAddress groupv4 = InetAddress.getByName("224.1." + (i+1) + ".1");
-            InetAddress groupv4mapped = InetAddress.getByName("::ffff:224.1." + (i+1) + ".2");
-            InetAddress groupv6 = InetAddress.getByName("ff02::1:" + (i+1));
-            groups.add(groupv4);
-            groups.add(groupv4mapped);
-            groups.add(groupv6);
+        for (NetIf netIf : netIfs) {
+            int NetIfIndex = netIf.index();
+            List<InetAddress> groups = new ArrayList<InetAddress>();
 
-            // use a separated thread to send to those 3 groups
-            Thread sender = new Thread(new Sender(nics.get(i), groupv4, groupv4mapped, groupv6, PORT));
+            if (netIf.ipv4Address()) {
+                InetAddress groupv4 = InetAddress.getByName("224.1." + NetIfIndex + ".1");
+                groups.add(groupv4);
+            }
+            if (netIf.ipv6Address()) {
+                InetAddress groupv6 = InetAddress.getByName("ff02::1:" + NetIfIndex);
+                groups.add(groupv6);
+            }
+
+            debug("Adding " + groups + " groups for " + netIf.nic().getName());
+            netIf.groups(groups);
+
+            // use a separated thread to send to those 2 groups
+            Thread sender = new Thread(new Sender(netIf,
+                                                  groups,
+                                                  PORT));
             sender.setDaemon(true); // we want sender to stop when main thread exits
             sender.start();
         }
@@ -108,75 +130,135 @@
         // from the expected network interface
         //
         byte[] buf = new byte[1024];
-        for (InetAddress group : groups) {
-        MulticastSocket mcastsock = new MulticastSocket(PORT);
-        mcastsock.setSoTimeout(5000);   // 5 second
-            DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
-
-            mcastsock.joinGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
+        for (NetIf netIf : netIfs) {
+            NetworkInterface nic = netIf.nic();
+            for (InetAddress group : netIf.groups()) {
+                MulticastSocket mcastsock = new MulticastSocket(PORT);
+                mcastsock.setSoTimeout(5000);   // 5 second
+                DatagramPacket packet = new DatagramPacket(buf, 0, buf.length);
 
-            try {
-                mcastsock.receive(packet);
-            } catch (Exception e) {
-                // test failed if any exception
-                throw new RuntimeException(e);
-            }
+                // the interface supports the IP multicast group
+                debug("Joining " + group + " on " + nic.getName());
+                mcastsock.joinGroup(new InetSocketAddress(group, PORT), nic);
+
+                try {
+                    mcastsock.receive(packet);
+                    debug("received packet on " + packet.getAddress());
+                } catch (Exception e) {
+                    // test failed if any exception
+                    throw new RuntimeException(e);
+                }
 
-            // now check which network interface this packet comes from
-            NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
-            NetworkInterface shouldbe = nics.get(groups.indexOf(group) / 3);
-            if (!from.equals(shouldbe)) {
-                System.out.println("Packets on group "
-                                    + group + " should come from "
-                                    + shouldbe.getName() + ", but came from "
-                                    + from.getName());
-                //throw new RuntimeException("Test failed.");
+                // now check which network interface this packet comes from
+                NetworkInterface from = NetworkInterface.getByInetAddress(packet.getAddress());
+                NetworkInterface shouldbe = nic;
+                if (!from.equals(shouldbe)) {
+                    System.out.println("Packets on group "
+                                        + group + " should come from "
+                                        + shouldbe.getName() + ", but came from "
+                                        + from.getName());
+                    //throw new RuntimeException("Test failed.");
+                }
+
+                mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nic);
             }
+        }
+    }
 
-            mcastsock.leaveGroup(new InetSocketAddress(group, PORT), nics.get(groups.indexOf(group) / 3));
-        }
+    private static boolean debug = true;
+
+    static void debug(String message) {
+        if (debug)
+            System.out.println(message);
     }
 }
 
 class Sender implements Runnable {
-    private NetworkInterface nic;
-    private InetAddress group1;
-    private InetAddress group2;
-    private InetAddress group3;
+    private NetIf netIf;
+    private List<InetAddress> groups;
     private int port;
 
-    public Sender(NetworkInterface nic,
-                    InetAddress groupv4, InetAddress groupv4mapped, InetAddress groupv6,
-                    int port) {
-        this.nic = nic;
-        group1 = groupv4;
-        group2 = groupv4mapped;
-        group3 = groupv6;
+    public Sender(NetIf netIf,
+                  List<InetAddress> groups,
+                  int port) {
+        this.netIf = netIf;
+        this.groups = groups;
         this.port = port;
     }
 
     public void run() {
         try {
             MulticastSocket mcastsock = new MulticastSocket();
-            mcastsock.setNetworkInterface(nic);
+            mcastsock.setNetworkInterface(netIf.nic());
+            List<DatagramPacket> packets = new LinkedList<DatagramPacket>();
 
             byte[] buf = "hello world".getBytes();
-            DatagramPacket packet1 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group1, port));
-            DatagramPacket packet2 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group2, port));
-            DatagramPacket packet3 = new DatagramPacket(buf, buf.length,
-                                        new InetSocketAddress(group3, port));
+            for (InetAddress group : groups) {
+                packets.add(new DatagramPacket(buf, buf.length, new InetSocketAddress(group, port)));
+            }
 
             for (;;) {
-                mcastsock.send(packet1);
-                mcastsock.send(packet2);
-                mcastsock.send(packet3);
+                for (DatagramPacket packet : packets)
+                    mcastsock.send(packet);
 
-                Thread.currentThread().sleep(1000);   // sleep 1 second
+                Thread.sleep(1000);   // sleep 1 second
             }
         } catch (Exception e) {
             throw new RuntimeException(e);
         }
     }
 }
+
+@SuppressWarnings("unchecked")
+class NetIf {
+    private boolean ipv4Address; //false
+    private boolean ipv6Address; //false
+    private int index;
+    List<InetAddress> groups = Collections.EMPTY_LIST;
+    private final NetworkInterface nic;
+
+    private NetIf(NetworkInterface nic) {
+        this.nic = nic;
+    }
+
+    static NetIf create(NetworkInterface nic) {
+        return new NetIf(nic);
+    }
+
+    NetworkInterface nic() {
+        return nic;
+    }
+
+    boolean ipv4Address() {
+        return ipv4Address;
+    }
+
+    void ipv4Address(boolean ipv4Address) {
+        this.ipv4Address = ipv4Address;
+    }
+
+    boolean ipv6Address() {
+        return ipv6Address;
+    }
+
+    void ipv6Address(boolean ipv6Address) {
+        this.ipv6Address = ipv6Address;
+    }
+
+    int index() {
+        return index;
+    }
+
+    void index(int index) {
+        this.index = index;
+    }
+
+    List<InetAddress> groups() {
+        return groups;
+    }
+
+    void groups(List<InetAddress> groups) {
+        this.groups = groups;
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/util/Objects/BasicObjectsTest.java	Wed Oct 14 14:21:25 2009 -0700
@@ -0,0 +1,105 @@
+/*
+ * 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();
+        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;
+    }
+}