JDK-4711515 : Wrong AppContext used in RMI threads
  • Type: Bug
  • Component: deploy
  • Sub-Component: webstart
  • Affected Version: 1.4.0,1.4.1
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,solaris_8
  • CPU: x86,sparc
  • Submitted: 2002-07-08
  • Updated: 2021-11-09
  • Resolved: 2002-10-15
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other Other
1.0.1_05 05Fixed 1.2.0Fixed 1.4.2Fixed
Related Reports
Relates :  
Relates :  
Description
JavaWebStart application running with the 1.4.0 JRE is creating 2 AWT event queues and events are being dispatched in both queues.  This eventually leads to a deadlock in the GUI.

The second event dispatch thread queue seems to become active (ie. an event is actually dispatched to that thread) when using RMI. To be more specific, the "2nd" event queue gets used when a SwingUtilities.invokeLater() call is invoked from a thread that has performed an RMI operation.

This only occurs when launching the GUI via Web Start.

The problem was not seen with 1.3.1.  1.4.0 JRE is being used with JavaWebStart 1.0.1_02.  The problem has been reproduced on WinNT 4.0 and Solaris 8.

This problem looks very similar to bug 4476452, which was fixed in JAWS 1.0.1_02 for the 1.3.1 JRE.  Also looks related to 4429811.

What the test application does: 

The client contains a JFrame, a JTextArea and 2 buttons: Local Update and Remote Update.  By clicking on "Local Update" button, in the actionPerformed code, it does the following ( ta is the JTextArea): 

                         public void actionPerformed( ActionEvent e ) 
                         { 
                             Runnable localUpdate = new Runnable()            
                             {                
                                 public void run()                
                                 {       
                                     Runnable swingLocalUpdate = new Runnable()            
                                     { 
                                         public void run() 
                                         { 
                                             ta.append( "Local update_________________\n"); 
                                             ta.append( "appContext: " + AppContext.getAppContext().toString() + "\n"); 
                                             ta.append( "Toolkit: " + Toolkit.getDefaultToolkit().toString() + "\n"); 
                                             ta.append( "SystemEventQueue:" + Toolkit.getDefaultToolkit().getSystemEventQueue().toString() + "\n");

                                             ta.append( "Current thread: " + Thread.currentThread().toString() + "\n"); 
                                         } 
                                     };                           
                                     SwingUtilities.invokeLater( swingLocalUpdate ); 
                                 } 
                             }; 
                             
                             Thread t = new Thread( localUpdate ); 
                             t.start();                    
                         } 

By clicking on the "Remote Update" button, in the actionPerformed code, it first starts a new thread and in the thread it invokes a Remote Method HelloI.hello(): 

                              public void actionPerformed( ActionEvent e ) 
                              { 
                                  Runnable remoteUpdate = new Runnable()            
                                  {                
                                      public void run()                
                                      {   
                                          try 
                                          { 
                                              myServer.hello(); 
                                          } 
                                          catch( Exception e ) 
                                          { 
                                              e.printStackTrace(); 
                                          } 
                                      } 
                                  }; 
                                  
                                  Thread t = new Thread( remoteUpdate ); 
                                  t.start();                    
On the server side, by invoking HelloI.hello() it calls back the client ObserverI.update() through RMI where client observer.update() prints out following info in the JTextArea:

                  public void update() 
                  { 
                      Runnable swingRemoteUpdate = new Runnable()            
                      { 
                          public void run() 
                          { 
                              ta.append( "Remote update_________________\n"); 
                              ta.append( "appContext: " + AppContext.getAppContext().toString() + "\n"); 
                              ta.append( "Toolkit: " + Toolkit.getDefaultToolkit().toString() + "\n"); 
                              ta.append( "SystemEventQueue:" + Toolkit.getDefaultToolkit().getSystemEventQueue().toString() + "\n"); 
                              ta.append( "Current thread: " + Thread.currentThread().toString() + "\n"); 
                          } 
                       };                           
                       SwingUtilities.invokeLater( swingRemoteUpdate ); 
                  } 

Test Result: 

When clicking on "Local Update", following information is printed in the JTextArea 

     Local update_________________ 
     appContext: sun.awt.AppContext[threadGroup=javawsApplicationThreadGroup] 
     Toolkit: sun.awt.windows.WToolkit@e3849c 
     SystemEventQueue:java.awt.EventQueue@1756a4 
     Current thread: Thread[AWT-EventQueue-1,6,javawsApplicationThreadGroup] 

When clicking on "Remote Update", following inforamation is printed in the JTextArea 

     Remote update_________________ 
     appContext: sun.awt.AppContext[threadGroup=system] 
     Toolkit: sun.awt.windows.WToolkit@e3849c 
     SystemEventQueue:java.awt.EventQueue@1551b0 
     Current thread: Thread[AWT-EventQueue-0,6,main] 

Two different AppContext, EventQueue and Event Dispatch thread is returned in the same client process. 

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.0.1_05 1.2.0_02 mantis mantis-b02 FIXED IN: 1.0.1_05 1.2.0_02 mantis mantis-b02 INTEGRATED IN: 1.0.1_05 1.2.0_02 mantis mantis-b02 mantis-b04
31-08-2004

SUGGESTED FIX Implement the function getAppContext() in JavaWebStartSecurity. ###@###.### 2002-07-16 ------------------------------- as per evaluation, this won't allways work. Instead, for mantis, we are trying to run the application on the main app context, and run the security dialogs on another appcontext who's threadgroup is a child of the system threadgroup. ###@###.### 2002-07-29 ------------------------------------------
29-07-2002

EVALUATION see comments from RMI team ###@###.### 2002-07-16 The suggested fix assumes the JavaWebStartSecurity SecurityManager is left in place. Many RMI applications start with : System.setSecurityManager(new RMISecurityManager()); since there must be some non-null security manager installed for some rmi functionality. We could put this fix in as suggested, and suggest people not setSecurityManager if it is allready non-null, but we would rather a complete fix, so are re-committing to mantis. ###@###.### 2002-07-19 Fixed this by running the main application code on the main AppContext, and the security dialogs on the secondary context for mantis and beyond. ###@###.### 2002-08-16
19-07-2002

WORK AROUND ----------- work around for rmi/appcontext problems --------------- For any code in rmi observers that currently does gui operations by calling SwingUtilities.invokeLater(Runnable), replace SwingUtilities.invokeLater() with myInvokeLater(). Implement myInvokeLater as follows: private final static ThreadGroup _applicationThreadGroup = Thread.currentThread().getThreadGroup(); public void myInvokeLater(final Runnable code) { (new Thread(_applicationThreadGroup, new Runnable() { public void run() { SwingUtilities.invokeLater(code); } } ) ).start(); } In this way the actual call to SwingUtilities.invokeLater is executed on a thread that is in the ThreadGroup used to load and initialize the class, as opposed to the "main" threadgroup (or one of it's decentants) used by rmi to listen for rmi calls. ###@###.### 2002-07-10 -------------------------------------------------------------------
10-07-2002