As part of Project Jigsaw, we are using java.util.ServiceLoader to load JCE providers (in module mode) instead of the current classpath based ClassLoader/reflection mechanism. While prototyping this, several issues were encountered with the ServiceLoader mechanism that had to be worked around in various ways in order for it to work with the existing java.security.Provider APIs and implementation. These issues have in some cases been worked around using less than perfect solutions and need to be better addressed. The issues are:
1. ServiceLoaders don't support a configured preference order for providers
The providers returned by ServiceLoader are in a random order, which doesn't fit with the JCE Provider APIs which allow you to specify an order via the java.security file. I've worked around this by aggressively loading all the providers and caching them in a HashMap and preserving the order, but this has some potential issues. One is that it could be a slight performance issue in some cases if all you need is the first provider, as the current implementation loads them as needed. The other is that it if a provider throws a ProviderException or UnsupportedOperationException, this needs to be saved and thrown back to the caller when that provider is subsequently accessed (see issue #4 for more info).
2. Cannot pass an optional argument (ex: a config file) to a provider via ServiceLoader
A few of our providers require an optional String argument specifying the name of a configuration file. This is actually an implementation-specific feature (a 3rd party provider can't use this), but nonetheless there is no way to pass an optional argument via the ServiceLoader. There is a current hack in the code that caches the config file argument (specified in the java.security file) and makes it available via a callback that our providers call in their constructor. This is ugly.
A potential solution is to add an init method to the Provider API that accepts additional Provider-specific parameters needed for initialization.
3. Cannot have more than one instance of a provider (ex: the SunPKCS11 Provider
allows multiple instances with different config files)
This is simply not supported right now. A potential solution is to add a layer of indirection, so SunPKCS11 could support multiple instances and delegate to the correct one. Not sure - more investigation is needed.
4. ServiceLoaderConfigurationError does not retain which provider generated the
error
This can probably be solved by adding an ordering mechanism to ServiceLoader but right now there is a hack that matches on the name of the class in the error message of the ServiceConfigurationError.
5. Unregistered providers are ignored
Providers that aren't registered in the java.security file but found by ServiceLoader are currently ignored. We could add them to the end of the list of providers, but there are a few potential issues we should address first. Right now, if you want to use a JCE provider that isn't registered, you instantiate it directly (as I showed above). Or you could also instantiate it and use the Security.addProvider or insertProviderAt methods to add it to the list of registered providers. There are apps doing that today. That code may break (addProvider will return -1) if we automatically registered all JCE providers that were found by ServiceLoader. So I would rather hold off on this and address it later with the ordering of providers. We may need to adjust what it actually means for a JCE provider to be installed:
http://docs.oracle.com/javase/7/docs/api/java/security/Security.html#getProviders%28%29
Right now "installed" means as configured in the java.security file.
6) Potentially use ServiceLoader to load JCE providers in module or classpath mode
If we can remove the need for the java.security file as noted above, then we could potentially use ServiceLoader for loading providers in either module or classpath mode. However, we would need to continue to support legacy providers and the java.security file for these legacy providers that didn't have the required ServiceLoader entries in their JAR files (META-INF/services). So it simply may not be worth doing this and instead encouraging legacy providers to convert to modules instead.
1. ServiceLoaders don't support a configured preference order for providers
The providers returned by ServiceLoader are in a random order, which doesn't fit with the JCE Provider APIs which allow you to specify an order via the java.security file. I've worked around this by aggressively loading all the providers and caching them in a HashMap and preserving the order, but this has some potential issues. One is that it could be a slight performance issue in some cases if all you need is the first provider, as the current implementation loads them as needed. The other is that it if a provider throws a ProviderException or UnsupportedOperationException, this needs to be saved and thrown back to the caller when that provider is subsequently accessed (see issue #4 for more info).
2. Cannot pass an optional argument (ex: a config file) to a provider via ServiceLoader
A few of our providers require an optional String argument specifying the name of a configuration file. This is actually an implementation-specific feature (a 3rd party provider can't use this), but nonetheless there is no way to pass an optional argument via the ServiceLoader. There is a current hack in the code that caches the config file argument (specified in the java.security file) and makes it available via a callback that our providers call in their constructor. This is ugly.
A potential solution is to add an init method to the Provider API that accepts additional Provider-specific parameters needed for initialization.
3. Cannot have more than one instance of a provider (ex: the SunPKCS11 Provider
allows multiple instances with different config files)
This is simply not supported right now. A potential solution is to add a layer of indirection, so SunPKCS11 could support multiple instances and delegate to the correct one. Not sure - more investigation is needed.
4. ServiceLoaderConfigurationError does not retain which provider generated the
error
This can probably be solved by adding an ordering mechanism to ServiceLoader but right now there is a hack that matches on the name of the class in the error message of the ServiceConfigurationError.
5. Unregistered providers are ignored
Providers that aren't registered in the java.security file but found by ServiceLoader are currently ignored. We could add them to the end of the list of providers, but there are a few potential issues we should address first. Right now, if you want to use a JCE provider that isn't registered, you instantiate it directly (as I showed above). Or you could also instantiate it and use the Security.addProvider or insertProviderAt methods to add it to the list of registered providers. There are apps doing that today. That code may break (addProvider will return -1) if we automatically registered all JCE providers that were found by ServiceLoader. So I would rather hold off on this and address it later with the ordering of providers. We may need to adjust what it actually means for a JCE provider to be installed:
http://docs.oracle.com/javase/7/docs/api/java/security/Security.html#getProviders%28%29
Right now "installed" means as configured in the java.security file.
6) Potentially use ServiceLoader to load JCE providers in module or classpath mode
If we can remove the need for the java.security file as noted above, then we could potentially use ServiceLoader for loading providers in either module or classpath mode. However, we would need to continue to support legacy providers and the java.security file for these legacy providers that didn't have the required ServiceLoader entries in their JAR files (META-INF/services). So it simply may not be worth doing this and instead encouraging legacy providers to convert to modules instead.
- relates to
-
JDK-7191662 JCE providers should be located via ServiceLoader
-
- Closed
-