From c8f8d63a589ddda509689e2d0257dccf4e6f1c4c Mon Sep 17 00:00:00 2001
From: ian.packer <ian.packer@forgerock.com>
Date: Wed, 23 Sep 2015 08:47:00 +0000
Subject: [PATCH] OPENDJ-2247: Improve CertAndKeyGen class location logic

---
 opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java |    4 ++
 opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java        |   62 ++++++++++++++++++++++++++-----
 opendj-server-legacy/src/messages/org/opends/messages/utility.properties       |    2 +
 3 files changed, 58 insertions(+), 10 deletions(-)

diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java b/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
index 1322bd0..2063bb5 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/Platform.java
@@ -48,6 +48,7 @@
 import org.forgerock.i18n.LocalizableMessage;
 
 import static org.opends.messages.UtilityMessages.*;
+import static org.opends.server.util.ServerConstants.CERTANDKEYGEN_PROVIDER;
 
 
 
@@ -65,6 +66,14 @@
   private static final String IBM_SEC = "com.ibm.security";
   private static final String SUN_SEC = "sun.security";
 
+  /** The CertAndKeyGen class is located in different packages depending on JVM environment. */
+  private static final String[] CERTANDKEYGEN_PATHS = new String[] {
+      "sun.security.x509.CertAndKeyGen",          // Oracle/Sun/OpenJDK 6,7
+      "sun.security.tools.keytool.CertAndKeyGen", // Oracle/Sun/OpenJDK 8
+      "com.ibm.security.x509.CertAndKeyGen",      // IBM SDK 7
+      "com.ibm.security.tools.CertAndKeyGen"      // IBM SDK 8
+    };
+
   private static final PlatformIMPL IMPL;
 
   /** The minimum java supported version. */
@@ -118,18 +127,14 @@
     static
     {
 
-      String x509pkg = pkgPrefix + ".x509";
-      String certAndKeyGen;
-      if (pkgPrefix.equals(IBM_SEC)
-          || System.getProperty("java.version").matches("^1\\.[67]\\..*"))
+      String certAndKeyGen = getCertAndKeyGenClassName();
+      if(certAndKeyGen == null)
       {
-        certAndKeyGen = x509pkg + ".CertAndKeyGen";
+        LocalizableMessage msg = ERR_CERTMGR_CERTGEN_NOT_FOUND.get(CERTANDKEYGEN_PROVIDER);
+        throw new ExceptionInInitializerError(msg.toString());
       }
-      else
-      { // Java 8 moved the CertAndKeyGen class to sun.security.tools.keytool
-        certAndKeyGen = pkgPrefix + ".tools.keytool" + ".CertAndKeyGen";
-      }
-      String X500Name = x509pkg + ".X500Name";
+
+      String X500Name = pkgPrefix + ".x509.X500Name";
       try
       {
         certKeyGenClass = Class.forName(certAndKeyGen);
@@ -155,7 +160,44 @@
       }
     }
 
+    /**
+     * Try to decide which CertAndKeyGen class to use.
+     *
+     * @return a fully qualified class name or null
+     */
+    private static String getCertAndKeyGenClassName() {
+      String certAndKeyGen = System.getProperty(CERTANDKEYGEN_PROVIDER);
+      if (certAndKeyGen != null)
+      {
+        return certAndKeyGen;
+      }
 
+      for (String className : CERTANDKEYGEN_PATHS)
+      {
+        if (classExists(className))
+        {
+          return className;
+        }
+      }
+      return null;
+    }
+
+    /**
+     * A quick check to see if a class can be loaded. Doesn't check if
+     * it can be instantiated.
+     *
+     * @param className full class name to check
+     * @return true if the class is found
+     */
+    private static boolean classExists(final String className)
+    {
+      try {
+        Class clazz = Class.forName(className);
+        return true;
+      } catch (ClassNotFoundException | ClassCastException e) {
+        return false;
+      }
+    }
 
     protected PlatformIMPL()
     {
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java b/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
index 74a51cd..558b25d 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/util/ServerConstants.java
@@ -3156,5 +3156,9 @@
    * Enable overcommit of memory in Old Gen space.
    */
   public static final String ENABLE_MEMORY_OVERCOMMIT = "org.forgerock.opendj.EnableMemoryOvercommit";
+
+  /** System property to use for overriding CertAndKeyGen class location. */
+  public static final String CERTANDKEYGEN_PROVIDER = "org.forgerock.opendj.CertAndKeyGenProvider";
+
 }
 
diff --git a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties b/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
index b005ae9..68ce0f5 100644
--- a/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
+++ b/opendj-server-legacy/src/messages/org/opends/messages/utility.properties
@@ -564,6 +564,8 @@
 initialized because of the following reason: %s
 ERR_CERTMGR_NO_METHOD_297=A method needed in the security classes \
 could not be located because of the following reason: %s
+ERR_CERTMGR_CERTGEN_NOT_FOUND_298=The CertAndKeyGen security class cannot be \
+found, consider setting -D%s=
 INFO_ARGPARSER_USAGE_DEFAULT_VALUE_299=Default value: %s
 WARN_EXPORT_LDIF_SET_PERMISSION_FAILED_300=An error occurred while \
  setting file permissions for the LDIF file %s: %s

--
Gitblit v1.10.0