JDK-4912903 : The jar file gets downloaded for every ImageIcon(URL) constructor
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 1.4.1,1.4.2,1.4.2_06,5.0
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: solaris_8,windows_nt
  • CPU: x86,sparc
  • Submitted: 2003-08-26
  • Updated: 2017-05-16
Related Reports
Relates :  
Description
Name: jk109818			Date: 08/26/2003


FULL PRODUCT VERSION :
java version "1.4.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_02-b06)
Java HotSpot(TM) Client VM (build 1.4.1_02-b06, mixed mode)

FULL OS VERSION :
Windows NT Version 6.0 Service Pack 6A, Windows 2000

EXTRA RELEVANT SYSTEM CONFIGURATION :
Apache web server, Internet Explorer 5.5

A DESCRIPTION OF THE PROBLEM :
Once the setDefaultUseCaches(false) is called on any URLConnection, every call to the ImageIcon(URL) constructor reloads the entire jar.

In an applet, connect to any website or servlet using the URLConnection class. set the DefaultUseCaches value to false using the API URLConnection.setDefaultUseCaches(false). After this call has been made construct an ImageIcon object by passing the URL of an image as the parameter. (The URL can be constructed by passing getClass.getResource() ). When this jar is loaded into the client machine running Internet Explorer and Sun Java Plugin V1.4.1, when the ImageIcon is constructed the entire jar file is loaded again into the client machine. This can be confirmed by turning on the trace level to 5 in the plugin console which will give the following line for every ImageIcon(URL) constructor called for a new image. If the same image is constructed again the jar is not downloaded

Connecting http://Gp400S/ws/client.jar with no proxy

This can also be confirmed by looking at the log of the web server which will say that a GET request has been made for this jar from the client machine.

This does not happen in versions upto 1.3.1.



STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile the code given in the following sections.
2. Put the class file and the image file into the jar.
3. Copy the jar file and the following html file into a web server

<HTML>
    <HEAD>
        <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
        <TITLE>SymfoWARE Navigator WebSight</TITLE>
               
        <SCRIPT language="JavaScript1.2">
            
            var ACTIVITY_TIMEOUT    = 120;
            
            /*******************************************************************************
             * THE REST OF THIS SCRIPT SHOULD NOT BE MODIFIED                              *
             *******************************************************************************/
            //use the JAR file or not
            var USE_ARCHIVE   = true;

            //screen constants
            var MINIMUM_APPLET_WIDTH  = 750;  //based upon an 800x600 resolution
            var MINIMUM_APPLET_HEIGHT = 500;  //based upon an 800x600 resolution

            //browser compatibility
            var bNetscape   = (navigator.appName.indexOf("Netscape") != -1);
            var bIExplorer  = (navigator.appName.indexOf("Microsoft") != -1);

            //------------------------------------------------------------------------------
            /**
             * Definition of the HTML tags associated with the applet.  There are two
             * definitions.  Again this is based upon the differences between Netscape
             * and Internet Explorer.  To use the Java Plug-in
             */
            if (bIExplorer)
            {
                var sAppletBody =   '<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" \n' +
                                    '    width="100%" height="100%" align="middle" \n' +
                                    '    hspace="0" vspace="0" name="WebSightApplet" \n' +
                                    '    codebase="http://java.sun.com/products/plugin/1.3/jinstall-13-win32.cab#Version=1,3,0,0"> \n' +
                                    '    <PARAM NAME="code" VALUE="test.class"> \n' +
                                    '    <PARAM NAME="java_codebase" VALUE="."> \n' +
                                    '    <PARAM NAME="activity_timeout" VALUE="' + ACTIVITY_TIMEOUT + '"> \n' +
                                    '    <PARAM NAME="type" VALUE="application/x-java-applet;version=1.3"> \n' +
                     (USE_ARCHIVE ? '    <PARAM NAME="archive" value="tester.jar"> \n' : '') +
                                    '        No JDK 1.3 support for APPLET!! \n' +
                                    '</OBJECT>';
            }
            else
            {
                var sAppletBody =   '<EMBED type="application/x-java-applet;version=1.3" \n' +
                                    '    width="100%" height="98%" align="middle" \n' +
                                    '    hspace="0" vspace="0" name="WebSightApplet" \n' +
                                    '    code="test.class" \n' +
                                    '    codebase="." \n' +
                                    '    activity_timeout="' + ACTIVITY_TIMEOUT + '" \n' +
                                    '    pluginspage="http://java.sun.com/products/plugin/1.3/plugin-install.html" \n' +
                     (USE_ARCHIVE ? '    archive="tester.jar"' : '') + '>\n' +
                                    '    <NOEMBED>\n' +
                                    '        No JDK 1.3 support for APPLET!! \n' +
                                    '    </NOEMBED> \n' +
                                    '</EMBED> ';
            }
        </SCRIPT>
    </HEAD>

    <BODY bgcolor="#C6C6C6">
        <SCRIPT language="JavaScript1.2">
            this.window.document.writeln(sAppletBody);
        </SCRIPT>
    </BODY>

</HTML>

4. Access the webserver and load the html into a client.


EXPECTED VERSUS ACTUAL BEHAVIOR :
The jar file should be loaded only once and the image should be taken from the jar file
The jar file got downloaded twice. (In fact it gets downloaded for as many times as ImageIcon(URL) is mentioned for a new image)

ERROR MESSAGES/STACK TRACES THAT OCCUR :
The following line gets displayed in the plugin console for as many ImageIcon(URL) when the trace level is set to 5.

Connecting http://Gp400S/ws/client.jar with no proxy

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------

import javax.swing.*;

import java.net.*;

public class test extends JApplet
{
  public test()
  {
  }

  public void init()
  {
    try
    {
      // Connect to SMH
      System.out.println("Trying to connect to SMH");
      URL SMH = new URL("http://www.smh.com.au");
      URLConnection SMHCnx = SMH.openConnection();
      SMHCnx.setUseCaches(false);
      SMHCnx.setDefaultUseCaches(false);
      System.out.println("Successfully connected to SMH " + SMHCnx.getContentLength());

      //Create an ImageIcon
      URL im = this.getClass().getResource("image.gif");
      ImageIcon ii = new ImageIcon(im);
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
  }
}

---------- END SOURCE ----------
(Incident Review ID: 184943) 
======================================================================

Comments
WORK AROUND The problem of downloading the complete jar file from the webserver is triggered by using the URLConnection.setDefaultUseCaches(false) method call. Either of the following approaches would resolve the issue: 1) Set the default value of the useCache to 'true' using the following method: URLConnection.setDefaultUseCaches(true); Note: Setting the default value causes a session wide effect. Some Applet - Servlet communication implementation uses the default value to be 'false'. Setting connection level value may not be effective as the implementation creates new connection internally when using ImageIcon(URL) constructor. 2) Use the following alternate approach if the above can not be used. Define the following methods and use them to create ImageIcon: ImageIcon getImageIcon(String name){ return getImageIcon(this.getClass(), name); } ImageIcon getImageIcon(Class cls, String name){ ImageIcon img_icon = null; if(cls == null) cls = this.getClass(); //required for loading resource URL img_url = cls.getResource(name); //get the URL try{ URLConnection img_conn = img_url.openConnection(); //get a connection img_conn.setUseCaches(true); //enable the use of cache InputStream img_is = img_conn.getInputStream(); //get the stream to load data byte[] img_data = new byte[img_is.available()]; //allocate enough space for reading data img_icon = new ImageIcon(img_data); //use the ImageIcon[byte[]) constructor to create }catch(IOException ignore){ //any IOException indicates a failure } if(img_icon == null) img_icon = new ImageIcon(); //on failure create a dummy return img_icon; //and return the ImageIcon object } //use the above method wherever required ImageIcon help_icon = getImageIcon("help.gif"); ###@###.### 2005-1-06 04:52:09 GMT
06-01-2005

CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: dragon
23-09-2004

EVALUATION It seems that ClassLoader or it's subclasses doesn't return resources (getResourceAsStream()) from already downloaded Jar files. Instead new connections a made to fetch the Jar file again. Could be too risky to fix for Tiger. Will fix for Dragonfly. ###@###.### 2003-09-30 For the test (in the Description) to work with the fix, it needs to be modified not to use new ImageIcon(URL), but use new ImageIcon(byte[],...), where the byte array for the image comes from this.getClass().getResourceAsStream(String). Will fix for Tiger-bata. ###@###.### 2003-10-29
29-10-2003