Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4665132

Webstart not returning ContextClassLoader consistently under jre 1.4.0

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Fixed
    • Icon: P3 P3
    • 1.4.2
    • 1.0.1, 1.4.0
    • deploy
    • mantis
    • x86
    • windows_98, windows_nt

      RATION" section under "Steps to Reproduce")

      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      TEST FILES
      We developed the following test program 'JAWSConsoleBug.java' to demonstrate
      this bug. It should be compiled and the resulting classes added to a JAR with
      the included manifest 'JAWSConsoleBug.mf'. The JAR should be
      named 'JAWSConsoleBug.jar', and it should be signed using the JDK's 'jarsigner'
      tool for use as a signed Java Web Start application. The resulting signed JAR
      should be launched via Java Web Start using the included JNLP application
      descriptor 'JAWSConsoleBug.jnlp'. Note that the 'codebase' attribute of
      the '<jnlp>' tag in this file must be modified so that it is correct for the
      test system. Note also that each time a change is made to the source of the
      test class, the code must be recompiled and the JAR must be updated and re-
      signed before it is re-executed. Logging should be enabled in the Java Web
      Start Application Manager in order to capture the debug output produced by the
      program.

      -------- Start of JAWSConsoleBug.java
      import java.awt.EventQueue;
      import java.awt.event.*;
      import javax.swing.*;

      public class JAWSConsoleBug
      {
      private static void dumpClassLoaders(Thread currThread, Class
      currClass) {
      System.out.println("Current thread's context classloader
      delegation tree:");
      ClassLoader childLoader = currThread.getContextClassLoader();
      System.out.println(childLoader);
      ClassLoader parentLoader = childLoader.getParent();
      while(parentLoader != null) {
      System.out.println(parentLoader);
      parentLoader = parentLoader.getParent();
      }
      System.out.println("(null) bootstrap class loader");

      System.out.println("\nCurrent class's classloader delegation
      tree:");
      childLoader = currClass.getClassLoader();
      System.out.println(childLoader);
      parentLoader = childLoader.getParent();
      while(parentLoader != null) {
      System.out.println(parentLoader);
      parentLoader = parentLoader.getParent();
      }
      System.out.println("(null) bootstrap class loader");
      }

      private static class TestAction extends AbstractAction
      {
      public TestAction() {
      super("Test");
      putValue(Action.MNEMONIC_KEY, new Integer
      (KeyEvent.VK_T));
      }

      public void actionPerformed(ActionEvent e) {
      System.out.println("\nMENU EVENT");
      dumpClassLoaders(Thread.currentThread(), this.getClass
      ());
      }
      }

      public static void main(String[] args) {
      try {
      /////////////////// code block #1
      // Thread.currentThread().sleep(5000);

      /////////////////// code block #2
      // final ClassLoader classLoader =
      JAWSConsoleBug.class.getClassLoader();
      // EventQueue.invokeLater(new Runnable() {
      // public void run() {
      // Thread.currentThread
      ().setContextClassLoader(classLoader);
      // }
      // });

      /////////////////// code block #3
      // Thread.currentThread().sleep(5000);

      System.out.println("\nMAIN THREAD");
      dumpClassLoaders(Thread.currentThread(),
      JAWSConsoleBug.class);

      final JFrame frame = new JFrame("JAWS Console Bug
      Demo");

      JMenuBar menuBar = new JMenuBar();
      JMenu menu = new JMenu("File");
      menu.setMnemonic(KeyEvent.VK_F);
      menu.add(new TestAction());
      menuBar.add(menu);
      frame.setJMenuBar(menuBar);

      JButton button = new JButton("Test");
      button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
      System.out.println("\nBUTTON EVENT");
      dumpClassLoaders(Thread.currentThread
      (), this.getClass());
      }
      });
      frame.getContentPane().add(button);

      frame.addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) {
      frame.setVisible(false);
      frame.dispose();
      System.exit(0);
      }
      });
      frame.pack();
      frame.setVisible(true);
      } catch (Exception e) {
      e.printStackTrace(System.out);
      System.exit(1);
      }
      }
      }
      -------- End of JAWSConsoleBug.java

      -------- Start of JAWSConsoleBug.mf
      Manifest-Version: 1.0
      Created-By: (Electronic Label Technology Inc.)
      Main-Class: JAWSConsoleBug
      -------- End of JAWSConsoleBug.mf

      -------- Start of JAWSConsoleBug.jnlp
      <?xml version="1.0" encoding="UTF-8"?>

      <jnlp spec="1.0+" codebase="file:///temp/JAWS Console Bug/"
      href="JAWSConsoleBug.jnlp">

          <information locale="en">
              <title>JAWS Console Bug</title>
              <vendor>Electronic Label Technology</vendor>
              <description>JAWS Console Bug</description>
      <description kind="short">Demonstrates a Java Web Start classloader
      bug.</description>
          </information>
          
          <security><all-permissions/></security>

          <resources>
              <j2se version="1.4+"/>
              <jar href="JAWSConsoleBug.jar" main="true"/>
          </resources>

          <application-desc main-class="JAWSConsoleBug"/>

      </jnlp>
      -------- End of JAWSConsoleBug.jnlp

      ---------- END SOURCE ----------

      CUSTOMER WORKAROUND :
      Nothing definite. The problem *seems* to vanish for us in
      most cases if you apply the AWT event dispatch thread
      classloader patch recommended for Java Web Start 1.0, *and*
      if you insist on having the Java Web Start console enabled.
      Alternatively, if the patch is applied late enough in the
      main thread (after any startup delays and just before
      displaying the GUI), the problem seems to be avoided
      regardless of the state of the Java Web Start console.
      However, this problem is inconsistent in the symptoms that
      it produces, so these approaches may work under some
      conditions and not others.
      (Review ID: 145754)
      ======================================================================


      Name: nt126004 Date: 04/09/2002


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

      FULL OPERATING SYSTEM VERSION :
      Windows NT Version 4.0

      ADDITIONAL OPERATING SYSTEMS :
      Windows 2000


      EXTRA RELEVANT SYSTEM CONFIGURATION :
      500mhz PIII machine with 256mb of RAM


      A DESCRIPTION OF THE PROBLEM :
      There seems to be a regression problem with the latest j2se
      1.4.0 and its bundled version of webstart. Basically its
      presents as being unable to load any external resources
      from any jars, icons and even getting a xerces xml schema
      parser fail. I've tracked what I think is the cause down to
      the method of getting hold of a valid classloader to load
      these resources. Under certain circumstances it appears
      that calling Thread.currentThread().getContextClassLoader()
      (the preferred method mentioned in the sun webstart faq,
      and used internally by xerces) returned an invalid system
      classloader, rather than the jnlp classloader. This rogue
      classloader can only return classes and resources from the
      system path, not the supplied jnlp jar/classpath resources.

      I've managed to simulate the problem by chopping down our
      application to a minimumal level. I've placed the code here
      on one of our internal machines http://213.48.113.194/tmp/
      and a webstart enabled version of the test here
      http://213.48.113.194/tmp/bugtest_ctcl.jnlp.

      This proves to be a difficult bug to reproduce effectively
      (although our full blown application fails, repeatedly each
      an every time).. Sometimes it will only fail on the initial
      execution, sometimes it fails intermittently after that or
      maybe the sleep() value may need tweaking to provoke any
      failures.. its awkward to reproduce but very real.
      You MUST have the webstart console turned off as this seems
      to override the normal restrictions on classloaders,
      Console must be off, but logging to a file should be on in
      order to see any debug messages..

      The key problem seems to be the delay between webstart
      loading the application, and the application running. I
      simulate the delay with a sleep(5000) in the test; where
      our application is actually loading resource bundles,
      setting up xerces and logging etc.. and usually a splash
      screen is shown.

      However the key point is that after this delay calls to
      getContextClassLoader() return some internal
      sun.misc.Launcher$AppClassLoader rather than the expected
      com.sun.jnlp.JNLPClassLoader.. The dump from the execution
      on my machine is as follows:

      <code>
      Java Web Start Console, started Tue Mar 19 17:30:23 GMT 2002
      Java 2 Runtime Environment: Version 1.4.0 by Sun
      Microsystems Inc.
      Logging to file: c:\temp\webstart.log
      *ToolsetLogin this.class.classloader:
      com.sun.jnlp.JNLPClassLoader@6614e7
      *ToolsetLogin currentThread.ContextClassLoader:
      com.sun.jnlp.JNLPClassLoader@6614e7
      *ToolsetFrame this.class.classloader:
      com.sun.jnlp.JNLPClassLoader@6614e7
      *ToolsetFrame currentThread.ContextClassLoader:
      sun.misc.Launcher$AppClassLoader@bac748
      java.lang.NullPointerException
      </code>

      Where the call to getContextClassLoader in the ToolsetFrame
      class returns the invalid classloader; running the same
      under 1.3.1 or under 1.4 from the command line (rather than
      webstart) all the returned classloaders are the same -- as
      expected, and the application doesn't fail.

      This test case is a bit of a silly mockup of the problem,
      in reality it's made our large swing application unusable
      under 1.4.0 due to its now totally unpredictable nature; in
      its ability to access resources and classes from external
      jars.. Effectively meaning it can only be accessed from the
      commandline, which is of no use to any of our webstart
      clients.


      REGRESSION. Last worked in version 1.3.1

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Download the code example, compile, pack them into a jar,
      sign the jar, put the jar onto a webstart enabled server
      etc.. (or use the suppiled ant build script).



      EXPECTED VERSUS ACTUAL BEHAVIOR :
      Expect mockup version of our login prompt to appear after a
      short five second delay (the delay seems to be key).. press
      OK and a new frame should appear with a duke icon in it.

      When the bug takes hold after pressing OK you will instead
      be presented with the dreadded Nullpointer exception and a
      empty frame..

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      Nullpointer Exception

      This bug can be reproduced often.

      ---------- BEGIN SOURCE ----------
      Beacuse this is a combination of webstart and jvm problems the code exmple is a
      little more complex than usual; the exmple code in on one of our internal
      servers (http://213.48.113.194/tmp/)

      should be here
      http://213.48.113.194/tmp/bugtest_ctcl.zip

      ..and an ready to run webstart compiled test (much easier all round) should be
      here
      http://213.48.113.194/tmp/bugtest_ctcl.jnlp
      ---------- END SOURCE ----------
      (Review ID: 144406)


      CUSTOMER WORKAROUND :
      we have an effective workaround that hasn't failed us yet (line
      4):

      1 public void actionPerformed(ActionEvent e) {
      2 if (e.getActionCommand().equals(LOGIN_COMMAND)) {
      3 Thread doLoginThread = new DoLoginThread();
      4
      doLoginThread.setContextClassLoader(getClass().getClassLoader());
      5 doLoginThread.start();
      6 }
      7 else ...
      8 }
      ======================================================================

      Name: nt126004 Date: 05/16/2002


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


      FULL OPERATING SYSTEM VERSION :
      Windows 98 [Version 4.10.1998]

      A DESCRIPTION OF THE PROBLEM :
      BACKGROUND
      We believe this bug may be related to the bug that
      originally existed in Java Web Start 1.0 that prevented the
      JNLP classloader from being correctly set as the context
      classloader of the AWT event dispatch thread in client
      applications. After modifying our applications to add the
      recommended patch code that set the context class loader of
      the AWT event dispatch thread to match the context
      classloader of the primordial thread, we did not see the
      problem again (everything worked fine under JDK 1.3.1)
      until after upgrading to JDK 1.4. This new bug seems to be
      similar to that original Java Web Start 1.0 bug, which was
      listed as fixed in a subsequent release but seems to have
      reappeared now in a slightly different guise.

      This new bug appears to be specific to JDK/JRE 1.4 FCS
      (1.4.0-b92) and the bundled Java Web Start product
      (1.0.1_02 build b03). We also believe it is related
      (possibly even identical) to the following existing bug in
      progress:

          Bug ID 4665132 Webstart not returning
      ContextClassLoader consistently under jre 1.4.0
          
      http://developer.java.sun.com/developer/bugParade/bugs/4665132.html

      DESCRIPTION
      We run our client programs as signed Java Web Start
      applications with full security permissions. The specific
      behavior we see is that Java Web Start appears to set the
      context class loader of the AWT event dispatch thread
      incorrectly at some point *after* the client application
      has been started, *unless* an AWT event occurs *before*
      some small delay (~5s or so) has elapsed. The standard
      patch recommended for Java Web Start 1.0 to correct the
      context class loader for the AWT event dispatch thread, if
      applied late enough in the execution sequence (after a
      small delay, or after the first AWT event occurs), does
      seem to fix the problem. However, if it is applied too
      early (before the delay or the first AWT event), it only
      fixes the problem for executions during which the Java Web
      Start console is enabled; the problem still occurs in that
      case for executions in which the Java Web Start console is
      disabled. If not applied at all, the problem either occurs
      a)regardless of the state of the Java Web Start console, or
      b)it occurs only when the console is enabled. Behavior b)
      is most common, but both behaviors have been observed.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      DEMONSTRATION
      We have developed a test program to demonstrate this bug
      (see TEST FILES below). This program displays a 'JFrame'
      with a single 'Test' button and a single 'File->Test' menu
      option. When you click the button or select the menu
      option, the associated event handler logs classloader
      information for the current class and thread context to
      stdout. As noted below, logging should be enabled in the
      Java Web Start Application Manager in order to capture the
      debug output produced by the program. These tests were run
      on a 450 MHz machine under Windows 98 (1st edition).

      In looking at the source for the test class, you will note
      that there are 3 commented and numbered code blocks in the
      main() method. For the first test, these code blocks should
      all be commented out and the Java Web Start console in the
      Application Manager should be disabled. Launch the program
      and wait for the GUI to appear. As soon as it does, click
      the button or select the menu option. At this point, you
      can check the Java Web Start log and see the debug output.
      The first part of this output should look similar to the
      following:

          MAIN THREAD
          Current thread's context classloader delegation tree:
          com.sun.jnlp.JNLPClassLoader@3c0b53
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

          Current class's classloader delegation tree:
          com.sun.jnlp.JNLPClassLoader@3c0b53
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

      Here we can see that the classloader delegation trees for
      the main class and primoridal thread are both just as we
      expect them to be for a Java Web Start application;
      specifically, they include an entry for
      the 'JNLPClassLoader'. The second part of the debug output
      should look something like this:

          BUTTON EVENT
          Current thread's context classloader delegation tree:
          com.sun.jnlp.JNLPClassLoader@3c0b53
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

          Current class's classloader delegation tree:
          com.sun.jnlp.JNLPClassLoader@3c0b53
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

      Here we can see that the classloader delegation trees for
      the button action class and the AWT event dispatch thread
      are also just as we expect them to be. Similar output is
      produced if the test program's menu option is selected
      instead of clicking the button. So far, so good.

      Next, run the test again, but this time enable the Java Web
      Start console in the Application Manager. You should get
      the same output for the main thread, but the output for the
      AWT event should be similar to the following:

          BUTTON EVENT
          Current thread's context classloader delegation tree:
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

          Current class's classloader delegation tree:
          com.sun.jnlp.JNLPClassLoader@3c0b53
          sun.misc.Launcher$AppClassLoader@209f4e
          sun.misc.Launcher$ExtClassLoader@bac748
          (null) bootstrap class loader

      Here, we can see that the classloader delegation tree for
      the AWT event dispatch thread is missing an entry
      for 'JNLPClassLoader'. This will cause a problem if we
      attempt to load any new classes known only to that class
      loader from within this thread or its child threads. This
      is the most basic problem symptom we see, and it typically
      results in 'ClassNotFoundException' errors in our client
      applications when running under Java Web Start. From time
      to time, the problem occurs inconsistently, but we can
      always reproduce it at some point by following the steps in
      this demonstration.

      Next, uncomment code block #3 in the test class. This
      introduces a 5-second delay at the beginning of the main
      thread. Running the test this time should show that all the
      expected 'JNLPClassLoader' entries are again present.
      Disabling the Java Web Start console and running the test
      again should show that the AWT event dispatch thread is
      again missing an entry for 'JNLPClassLoader'.

      Next, uncomment code block #2 in the test class, so that
      code blocks #2 and #3 are in effect. This introduces the
      patch recommended for Java Web Start 1.0 to set the context
      classloader of the AWT event dispatch thread appropriately.
      Presumably, this patch is no longer necessary, but it seems
      a good place to start. Note that the patch is introduced
      *prior* to the 5-second delay. This time, running the test
      should show that the AWT event dispatch thread is still
      missing an entry for 'JNLPClassLoader'. Enabling the Java
      Web Start console and running the test again should show
      that the mysterious disappearing classloader has returned.

      Next, comment out code block #3 and uncomment code block
      #1, so that code blocks #1 and #2 are in effect. This
      repositions the classloader patch for the AWT event
      dispatch thread so that it occurs *after* the 5-second
      delay. This time, running the test should show that all the
      expected 'JNLPClassLoader' entries are present, regardless
      of whether the Java Web Start console is enabled or
      disabled.

      CONCLUSIONS
      So, what we seem to have is a flaky classloader delegation
      tree associated with the AWT event dispatch thread under
      Java Web Start. Sometimes the delegation tree includes the
      correct entry for 'JNLPClassLoader', sometimes it doesn't.
      Whether or not it does seems to depend on a combination of
      factors: whether or not there is a certain amount of delay
      between application startup and the initial AWT events,
      whether or not the classloader patch has been applied, at
      what point in the main thread the patch occurs, and whether
      or the Java Web Start console has been enabled.

      Although it seems as though we can hack around on this and
      get it to work somewhat consistently in our applications,
      it isn't really feasible for us to deploy via Java Web
      Start until we can be reasonably sure of the correct
      solution to this problem. We believe this behavior to be a
      bug in Java Web Start itself, and that it has something to
      do with establishing the correct classloader delegation
      tree for all threads at client launch time. We ask that
      this problem be investigated, and a code patch or
      workaround be recommended as soon as possible, with a
      complete fix in the next maintenance release.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      We expected that the JNLP classloader would be present in
      the classloader delegation tree of the AWT event dispatch
      thread for any Java Web Start client. We observed with our
      test program that this was not in fact always the case, and
      that whether or not it was depended on several seemingly-
      unrelated factors. As a result, our production applications
      exhibit 'ClassNotFoundException' errors under Java Web
      Start that we cannot reliably fix.

      ERROR MESSAGES/STACK TRACES THAT OCCUR :
      (see the "DEMONST

            herrick Andy Herrick (Inactive)
            nthompsosunw Nathanael Thompson (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: