Hi Masayosh, Alan,
Thanks for looking at the change.
I suppose application containers are already accustomed to invoke
ResourceBundle.clearCache(ClassLoader) when undeploying an application
so that the corresponding ClassLoader can get GCed right away. But
there's a change in the semantics of this method that Jigsaw introduced...
Before Jigsaw, this method was specified to:
* Removes all resource bundles from the cache that have been loaded
* using the given class loader.
After Jigsaw, this method is specified to:
* Removes all resource bundles from the cache that have been loaded
* by the caller's module using the given class loader.
Now suppose that the "caller's module" that loads the bundle is the
application's module and the module that clears the cache is the
container's module. The app's cache won't get cleared. I understand that
the change in semantics was an attempt to "isolate" modules among
themselves so that one module could not clear the cache of another
module if they happen to map to the same class loader, but this also
means that an application container can't easily clear the cache of the
application it wishes to undeploy unless it uses the new
ResourceBundle.clearCache(Module) method on each application's module
before undeploying it.
I also wonder if the change of the semantics of this method is backwards
compatible. Suppose that some container is using this method to clear
the cache of the application loaded by say "classloaderA" before
undeploying it. It calls ResourceBundle.clearCache(classloaderA). Now
suppose the container code is loaded by some other class loader (say
"classloaderC") which is usually the case in today's containers. Both
container and application classes are part of the unnamed modules of
their corresponding class loaders. With the change in the semantics of
this method introduced by jigsaw, the container will not clear the cache
of the application any more since the container module is not the same
as the application module (they are distinct unnamed modules).
Anyway, I noticed an inconsistency in my webrev.04 immediately after
posting it a week ago. I was off for a week then, so now that I'm back,
here's the corrected webrev of my proposed change:
http://cr.openjdk.java.net/~plevart/jdk9-dev/ResourceBundle.cleanup/webrev.05/
The only real change of logic compared to webrev.04 is that I moved the
"format" field from the LoadSession (previous CacheKey) to
ResourceBundle itself. This field is needed to hold the bundle's format
for invoking the Control.needsReload() method. It is not semantically
correct to use the value from the LoadSession as done in webrev.04. This
has to be the value that the bundle was created with, so it belongs to
the bundle itself. In original code it was taken from the cloned
CacheKey that was attached to the bundle.
All other changes from webrev.04 are limited to ResourceBundle.java file
and include some comments and nits that don't change the overall logic.
All ResourceBundle tests still pass.
The diff from webrev.04 is the following:
*** ResourceBundle.webrev.04.java 2016-08-01 15:33:49.408565452 +0200
--- ResourceBundle.java 2016-08-01 14:43:59.875401697 +0200
***
*** 40,55
package java.util;
- import jdk.internal.misc.JavaUtilResourceBundleAccess;
- import jdk.internal.misc.SharedSecrets;
- import jdk.internal.reflect.CallerSensitive;
- import jdk.internal.reflect.Reflection;
- import jdk.internal.util.concurrent.AbstractClassLoaderValue;
- import jdk.internal.util.concurrent.ClassLoaderValue;
- import sun.util.locale.BaseLocale;
- import sun.util.locale.LocaleObjectCache;
- import sun.util.locale.provider.ResourceBundleProviderSupport;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.ReferenceQueue;
--- 40,45
***
*** 69,74
--- 59,73
import java.util.spi.ResourceBundleControlProvider;
import java.util.spi.ResourceBundleProvider;
+ import jdk.internal.misc.JavaUtilResourceBundleAccess;
+ import jdk.internal.misc.SharedSecrets;
+ import jdk.internal.reflect.CallerSensitive;
+ import jdk.internal.reflect.Reflection;
+ import jdk.internal.util.concurrent.AbstractClassLoaderValue;
+ import jdk.internal.util.concurrent.ClassLoaderValue;
+ import sun.util.locale.BaseLocale;
+ import sun.util.locale.LocaleObjectCache;
+ import sun.util.locale.provider.ResourceBundleProviderSupport;
import static
sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
***
*** 346,354
*/
public abstract class ResourceBundle {
- /** initial size of the bundle cache */
- private static final int INITIAL_CACHE_SIZE = 32;
-
static {
SharedSecrets.setJavaUtilResourceBundleAccess(
new JavaUtilResourceBundleAccess() {
--- 345,350
***
*** 386,392
/**
! * The cache of BundleReference(s) per class l