JDK-7045247 : Regression: Plugin: invalidate/validate issues in AWT applet
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P2
  • Status: Closed
  • Resolution: Cannot Reproduce
  • OS: generic
  • CPU: generic
  • Submitted: 2011-05-16
  • Updated: 2011-05-18
  • Resolved: 2011-05-18
Related Reports
Relates :  
Description
SYNOPSIS
--------
Regression:  Plugin: invalidate/validate issues in AWT applet

OPERATING SYSTEM
----------------
Tested on Windows, but probably platform independent

FULL JDK VERSION
----------------
JDK 7 b142.
Not reproducible on JDK 6u25.
               
REPRODUCTION INSTRUCTIONS
-------------------------
1. Install JDK 7
2. Ensure that the Next Generation Plugin is enabled
3. Place the provided HTML and Java files in the same folder, and
   compiled the java file.
4. Load the given html file into a browser (the problem is reproducible
   with both Firefox and IE)
5. Click the button

Observed bevaviour:
The "Logon" Button disappears, and the "Logoff" button does not appear.

Expected behaviour:
Clicking the button should toggle the label between "Logon" and "Logoff" (run with Java 6 to observe the correct behaviour).

The problem seems to be caused by inconsistent behaviour in this part of the testcase:

    private void validateComponent(Component component) {
        if (component == null)
            return;

        Component original = component;
        //invalidating this component and all its ancestors
        component.invalidate();            

        //getting to the top-most component in the hierarchy
        while ( (component.getParent() != null) )
            component = component.getParent();

        //validating this top-most component
        component.validate();

        original.repaint();
    }

When running on JDK 7, the top-level AWT component does not get invalidated (despite the fact that we call invalidate() on one of the components lower down the heirarchy). As a result, when we call validate() on the top level component immediately afterwards, nothing happens (because the top-level component is valid), and the Logoff button does not get painted.

TESTCASE
--------
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JPanel;

public class LogOffApplet extends Applet implements ActionListener {

    private LogOffApplet appletInstance;

    public void init() {
        super.init();  
        appletInstance = this;
        LogonPanel p = new LogonPanel();
        setMainPanel(p);
    }

    private class LogonPanel extends JPanel implements ActionListener {
        LogonPanel(){
            Button logonBtn = new Button("Logon");
            logonBtn.addActionListener(this);
            setLayout(new BorderLayout());
            add("Center",logonBtn);
        }

        public void actionPerformed(ActionEvent e) {
            appletInstance.actionPerformed(new ActionEvent(this, 0, "logon"));
        }
    }

    private class LogOffPanel extends JPanel implements ActionListener {
        LogOffPanel(){
            Button logoffBtn = new Button("LogOff");
            logoffBtn.addActionListener(this);
            setLayout(new BorderLayout());
            add("Center",logoffBtn);
        }

        public void actionPerformed(ActionEvent e) {
            appletInstance.actionPerformed(new ActionEvent(this,1,"logoff"));
        }
    }

    public void actionPerformed(ActionEvent e) {
        int ID = e.getID();
        switch (ID) {
        case 0:
            setMainPanel(new LogOffPanel());
            break;
        case 1:
            setMainPanel(new LogonPanel());
            break;
        default:
            break;
        }
    }

    private void setMainPanel(JPanel panel){
        if (appletInstance != null) {
            appletInstance.removeAll();
            appletInstance.setLayout(new BorderLayout(0,0));
            appletInstance.add("Center", panel);
            validateComponent(panel);
        } else
            System.out.println("appletInstance is NULL");
    }

    private void validateComponent(Component component) {
        if (component == null)
            return;

        Component original = component;
        //invalidating this component and all its ancestors
        component.invalidate();            

        //getting to the top-most component in the hierarchy
        while ( (component.getParent() != null) )
            component = component.getParent();

        //validating this top-most component
        component.validate();

        original.repaint();
    }
}

hangtest.html
-------------
<html>
  <head>
    <title>Hang demo</title>
  </head>
  <body>
      <h1>Hang demo</h1>
         <APPLET CODE="LogOffApplet.class" WIDTH=100 HEIGHT=50 />
  </body>
</html>

Comments
EVALUATION With a fix for 7041387 the default invalidate() behavior has been restored, and therefore the issue isn't reproducible anymore.
18-05-2011