JDK-4386865 : JAR file not closed after loading .properties file in ResourceBundle.
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util
  • Affected Version: 1.3.0
  • Priority: P4
  • Status: Closed
  • Resolution: Duplicate
  • OS: generic
  • CPU: generic
  • Submitted: 2000-11-07
  • Updated: 2001-11-14
  • Resolved: 2001-11-14
Related Reports
Duplicate :  
Description

Name: yyT116575			Date: 11/07/2000


java version "1.3.0"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-C)
Java HotSpot(TM) Client VM (build 1.3.0-C, mixed mode)

I am seeing an issue where a JAR file remains open after ResourceBundle loads
a resource file from it.

The ResourceBundle class calls getResourceAsStream on the ClassLoader to
open an InputStream to the resource. getResourceAsStream calls getResource
to obtain a URL and then calls openStream on the URL. If the resource is from
a JAR, then the underlying connection is a JarURLConnection. The
JarURLConnection creates a ZipFile which returns a ZipFileInputStream
(private class in ZipFile) as the InputStream. The ResourceBundle does close
the InputStream after it is done with it but the underlying ZipFile is not
closed and the file descriptor remains open.

The impact of this is that if you try to delete or overwrite the JAR file you
can't because it's still in use (NT complains - don't know about other
platforms). We have implemented our own class loading mechanism that monitors
a directory and loads/reloads/unloads classes and properties from JAR files.
Once a JAR is loaded, I can't remove it from the directory because of the
open handle. Worse yet, you may even run out of file handles if you load
enough properties files.

I think the problem lies with the JarURLConnection implementation. It should
somehow close the ZipFile when the InputStream is closed.

I implemented the following workaround in my custom class loader. I override
the getResourceAsStream method and wrap the ZipFileInputStream in my own
class which closes the ZipFile. This works for resources loaded by my class
loaders but not for ones loaded by the system class loader.

class JarFileClassLoader extends FileClassLoader
{
    private static class ResourceInputStream extends InputStream
    {
        private InputStream is ;
        private ZipFile jarFile ;

        ResourceInputStream ( InputStream is, ZipFile jarFile )
        {
            this.is = is ;
            this.jarFile = jarFile ;
        }

        public int read ( byte b[], int off, int len ) throws IOException
        {
            return is.read ( b, off, len ) ;
        }

        public int read () throws IOException
        {
            return is.read () ;
        }

        public long skip ( long n ) throws IOException
        {
            return is.skip ( n ) ;
        }

        public int available () throws IOException
        {
            return is.available () ;
        }

        public void close () throws IOException
        {
            is.close () ;
            jarFile.close () ;
        }
    }
    
    .
    .
    .

    public InputStream getResourceAsStream ( String name )
    {
        InputStream stream = null ;
        ZipFile jarFile = null ;
        try
        {
            jarFile = new ZipFile ( file ) ;
            ZipEntry jarEntry = (ZipEntry) jarFile.getEntry ( name ) ;
            if ( jarEntry != null )
            {
                InputStream is = jarFile.getInputStream ( jarEntry ) ;
                stream = new ResourceInputStream ( is, jarFile ) ;
            }
        }
        catch ( Throwable e )
        {
        }

        if ( jarFile != null && stream == null )
        {
            try
            {
                jarFile.close () ;
            }
            catch ( Exception e ) {}
        }

        return stream ;
    }
}
(Review ID: 111910) 
======================================================================

Comments
EVALUATION This has now been fixed. To avoid caching JarFiles in JarURLConnection call URLConnection.setDefaultUseCaches(false) on any instance of URLConnection before using the resource bundle. ###@###.### 2001-11-13
13-11-2001

PUBLIC COMMENTS This has now been fixed. To avoid caching JarFiles in JarURLConnection call URLConnection.setDefaultUseCaches(false) on any instance of URLConnection before using the resource bundle. ###@###.### 2001-11-13
13-11-2001