/** Get the provider object. Loads the provider if it is not already loaded. */ synchronized Provider getProvider() { // volatile variable load Provider p = provider; if (p != null) { return p; } if (shouldLoad() == false) { return null; } if (isLoading) { // because this method is synchronized, this can only // happen if there is recursion. if (debug != null) { debug.println("Recursion loading provider: " + this); new Exception("Call trace").printStackTrace(); } return null; } try { isLoading = true; tries++; p = doLoadProvider(); } finally { isLoading = false; } provider = p; return p; }
/** * Class representing a configured provider. Encapsulates configuration (className plus optional * argument), the provider loading logic, and the loaded Provider object itself. * * @author Andreas Sterbenz * @since 1.5 */ final class ProviderConfig { private static final sun.security.util.Debug debug = sun.security.util.Debug.getInstance("jca", "ProviderConfig"); // classname of the SunPKCS11-Solaris provider private static final String P11_SOL_NAME = "sun.security.pkcs11.SunPKCS11"; // config file argument of the SunPKCS11-Solaris provider private static final String P11_SOL_ARG = "${java.home}/lib/security/sunpkcs11-solaris.cfg"; // maximum number of times to try loading a provider before giving up private static final int MAX_LOAD_TRIES = 30; // parameters for the Provider(String) constructor, // use by doLoadProvider() private static final Class[] CL_STRING = {String.class}; // name of the provider class private final String className; // argument to the provider constructor, // empty string indicates no-arg constructor private final String argument; // number of times we have already tried to load this provider private int tries; // Provider object, if loaded private volatile Provider provider; // flag indicating if we are currently trying to load the provider // used to detect recursion private boolean isLoading; ProviderConfig(String className, String argument) { if (className.equals(P11_SOL_NAME) && argument.equals(P11_SOL_ARG)) { checkSunPKCS11Solaris(); } this.className = className; this.argument = expand(argument); } ProviderConfig(String className) { this(className, ""); } ProviderConfig(Provider provider) { this.className = provider.getClass().getName(); this.argument = ""; this.provider = provider; } // check if we should try to load the SunPKCS11-Solaris provider // avoid if not available (pre Solaris 10) to reduce startup time // or if disabled via system property private void checkSunPKCS11Solaris() { Boolean o = AccessController.doPrivileged( new PrivilegedAction<Boolean>() { public Boolean run() { File file = new File("/usr/lib/libpkcs11.so"); if (file.exists() == false) { return Boolean.FALSE; } if ("false" .equalsIgnoreCase(System.getProperty("sun.security.pkcs11.enable-solaris"))) { return Boolean.FALSE; } return Boolean.TRUE; } }); if (o == Boolean.FALSE) { tries = MAX_LOAD_TRIES; } } private boolean hasArgument() { return argument.length() != 0; } // should we try to load this provider? private boolean shouldLoad() { return (tries < MAX_LOAD_TRIES); } // do not try to load this provider again private void disableLoad() { tries = MAX_LOAD_TRIES; } boolean isLoaded() { return (provider != null); } public boolean equals(Object obj) { if (this == obj) { return true; } if (obj instanceof ProviderConfig == false) { return false; } ProviderConfig other = (ProviderConfig) obj; return this.className.equals(other.className) && this.argument.equals(other.argument); } public int hashCode() { return className.hashCode() + argument.hashCode(); } public String toString() { if (hasArgument()) { return className + "('" + argument + "')"; } else { return className; } } /** Get the provider object. Loads the provider if it is not already loaded. */ synchronized Provider getProvider() { // volatile variable load Provider p = provider; if (p != null) { return p; } if (shouldLoad() == false) { return null; } if (isLoading) { // because this method is synchronized, this can only // happen if there is recursion. if (debug != null) { debug.println("Recursion loading provider: " + this); new Exception("Call trace").printStackTrace(); } return null; } try { isLoading = true; tries++; p = doLoadProvider(); } finally { isLoading = false; } provider = p; return p; } /** * Load and instantiate the Provider described by this class. * * <p>NOTE use of doPrivileged(). * * @return null if the Provider could not be loaded * @throws ProviderException if executing the Provider's constructor throws a ProviderException. * All other Exceptions are ignored. */ private Provider doLoadProvider() { return AccessController.doPrivileged( new PrivilegedAction<Provider>() { public Provider run() { if (debug != null) { debug.println("Loading provider: " + ProviderConfig.this); } try { ClassLoader cl = ClassLoader.getSystemClassLoader(); Class<?> provClass; if (cl != null) { provClass = cl.loadClass(className); } else { provClass = Class.forName(className); } Object obj; if (hasArgument() == false) { obj = provClass.newInstance(); } else { Constructor<?> cons = provClass.getConstructor(CL_STRING); obj = cons.newInstance(argument); } if (obj instanceof Provider) { if (debug != null) { debug.println("Loaded provider " + obj); } return (Provider) obj; } else { if (debug != null) { debug.println(className + " is not a provider"); } disableLoad(); return null; } } catch (Exception e) { Throwable t; if (e instanceof InvocationTargetException) { t = ((InvocationTargetException) e).getCause(); } else { t = e; } if (debug != null) { debug.println("Error loading provider " + ProviderConfig.this); t.printStackTrace(); } // provider indicates fatal error, pass through exception if (t instanceof ProviderException) { throw (ProviderException) t; } // provider indicates that loading should not be retried if (t instanceof UnsupportedOperationException) { disableLoad(); } return null; } } }); } /** * Perform property expansion of the provider value. * * <p>NOTE use of doPrivileged(). */ private static String expand(final String value) { // shortcut if value does not contain any properties if (value.contains("${") == false) { return value; } return AccessController.doPrivileged( new PrivilegedAction<String>() { public String run() { try { return PropertyExpander.expand(value); } catch (GeneralSecurityException e) { throw new ProviderException(e); } } }); } }