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

Public sun.awt.RequestFocusController and sun.awt.AWTAccessor API

XMLWordPrintable

    • x86
    • other

      A DESCRIPTION OF THE REQUEST :
      Jigsaw will disallow access to internal packages.
      We have written a complex validation and focus management implementation for our closed-source RIA and maintain it since JRE 1.4.

      For this we use some internal API. We have a custom implementation of these interfaces:

      sun.awt.RequestFocusController
      sun.awt.AWTAccessor.ComponentAccessor

      And use this getter and setter:

      sun.awt.AWTAccessor#setComponentAccessor(AWTAccessor.ComponentAccessor)
      sun.awt.AWTAccessor#getComponentAccessor()
      sun.awt.AWTAccessor.ComponentAccessor#setRequestFocusController(RequestFocusController)

      Please make this API public.

      Basically we need to detect and intercept focus changes.

      java.awt.Component allows to override this methods:
      requestFocus()
      requestFocus(boolean)
      requestFocusInWindow()
      requestFocusInWindow(boolean)

      requestFocus() is only invoked when the component is focused by a mouse click.
      But no requestFocus* method is invoked when a FocusTraversalPolicy is involed
      (f. e. the user press TAB to focus next component).

      sun.awt.RequestFocusController#acceptRequestFocus is invoked in both cases.

      Attached a demo to reproduce it:
      - if TextField is focused by a mouse click "requestFocus" and "acceptRequestFocus" is logged
      - if TextField is focused by TAB only "acceptRequestFocus" is logged

      Some more notes about the test program:
      ComponentAccessorDelegator delegates all calls to the original ComponentAccessor implementation.
      Only ComponentAccessor#setRequestFocusController is changed to keep our RequestFocusController implementation.


      JUSTIFICATION :
      We can not remove our validation and focus management because it is tightly integrated into our RIA.
      The code run within a JVM which is started by the Oracle Java WebStart.
      So we can not "simple" workaround it.
      We have over 40'000 customers which use our RIA every day and we don't plan to develop and ship a custom WebStart with a OpenJDK fork.


      ---------- BEGIN SOURCE ----------
      import sun.awt.AWTAccessor;
      import sun.awt.AppContext;
      import sun.awt.CausedFocusEvent;
      import sun.awt.RequestFocusController;

      import javax.swing.BoxLayout;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.JTextField;
      import javax.swing.WindowConstants;
      import java.awt.AWTEvent;
      import java.awt.Color;
      import java.awt.Component;
      import java.awt.Container;
      import java.awt.Cursor;
      import java.awt.Font;
      import java.awt.GraphicsConfiguration;
      import java.awt.Point;
      import java.awt.Rectangle;
      import java.awt.Shape;
      import java.awt.peer.ComponentPeer;
      import java.security.AccessControlContext;

      public class RequestFocusDemo {
        public static void main(String[] args) {

          RequestFocusController ourRequestFocusController = new RequestFocusController() {
            @Override
            public boolean acceptRequestFocus(final Component component, final Component component1, final boolean b, final boolean b1, final CausedFocusEvent.Cause cause) {
              System.out.println("acceptRequestFocus");
              return true;
            }
          };

          AWTAccessor.setComponentAccessor(new ComponentAccessorDelegator(AWTAccessor.getComponentAccessor()) {
            @Override
            public void setRequestFocusController(final RequestFocusController requestFocusController) {
              super.setRequestFocusController(ourRequestFocusController); // disallow further changes
            }
          });
          AWTAccessor.getComponentAccessor().setRequestFocusController(ourRequestFocusController);

          JPanel panel = new JPanel();
          BoxLayout layout = new BoxLayout(panel, BoxLayout.Y_AXIS);
          panel.setLayout(layout);
          panel.add(new TextFieldImpl());
          panel.add(new TextFieldImpl());
          panel.add(new TextFieldImpl());
          panel.add(new TextFieldImpl());

          JFrame frame = new JFrame();
          frame.getContentPane().add(panel);
          frame.setSize(400, 400);
          frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
          frame.setVisible(true);
        }

        static class TextFieldImpl extends JTextField {
          TextFieldImpl() {
          }

          @Override
          public void requestFocus() {
            System.out.println("requestFocus");
            super.requestFocus();
          }

          @Override
          public boolean requestFocus(boolean temporary) {
            System.out.println("requestFocus(boolean)");
            return super.requestFocus(temporary);
          }

          @Override
          public boolean requestFocusInWindow() {
            System.out.println("requestFocusInWindow");
            return super.requestFocusInWindow();
          }

          @Override
          protected boolean requestFocusInWindow(boolean temporary) {
            System.out.println("requestFocusInWindow(boolean)");
            return super.requestFocusInWindow(temporary);
          }
        }


        static class ComponentAccessorDelegator implements AWTAccessor.ComponentAccessor {
          private AWTAccessor.ComponentAccessor delegation;

          private ComponentAccessorDelegator(AWTAccessor.ComponentAccessor delegation) {
            this.delegation = delegation;
          }

          @Override
          public void setBackgroundEraseDisabled(Component component, boolean b) {
            delegation.setBackgroundEraseDisabled(component, b);
          }

          @Override
          public boolean getBackgroundEraseDisabled(Component component) {
            return delegation.getBackgroundEraseDisabled(component);
          }

          @Override
          public Rectangle getBounds(Component component) {
            return delegation.getBounds(component);
          }

          @Override
          public void setMixingCutoutShape(Component component, Shape shape) {
            delegation.setMixingCutoutShape(component, shape);
          }

          @Override
          public void setGraphicsConfiguration(Component component, GraphicsConfiguration graphicsConfiguration) {
            delegation.setGraphicsConfiguration(component, graphicsConfiguration);
          }

          @Override
          public boolean requestFocus(Component component, CausedFocusEvent.Cause cause) {
            return delegation.requestFocus(component, cause);
          }

          @Override
          public boolean canBeFocusOwner(Component component) {
            return delegation.canBeFocusOwner(component);
          }

          @Override
          public boolean isVisible(Component component) {
            return delegation.isVisible(component);
          }

          @Override
          public void setRequestFocusController(RequestFocusController requestFocusController) {
            delegation.setRequestFocusController(requestFocusController);
          }

          @Override
          public AppContext getAppContext(Component component) {
            return delegation.getAppContext(component);
          }

          @Override
          public void setAppContext(Component component, AppContext appContext) {
            delegation.setAppContext(component, appContext);
          }

          @Override
          public Container getParent(Component component) {
            return delegation.getParent(component);
          }

          @Override
          public void setParent(Component component, Container container) {
            delegation.setParent(component, container);
          }

          @Override
          public void setSize(Component component, int i, int i1) {
            delegation.setSize(component, i, i1);
          }

          @Override
          public Point getLocation(Component component) {
            return delegation.getLocation(component);
          }

          @Override
          public void setLocation(Component component, int i, int i1) {
            delegation.setLocation(component, i, i1);
          }

          @Override
          public boolean isEnabled(Component component) {
            return delegation.isEnabled(component);
          }

          @Override
          public boolean isDisplayable(Component component) {
            return delegation.isDisplayable(component);
          }

          @Override
          public Cursor getCursor(Component component) {
            return delegation.getCursor(component);
          }

          @Override
          public ComponentPeer getPeer(Component component) {
            return delegation.getPeer(component);
          }

          @Override
          public void setPeer(Component component, ComponentPeer componentPeer) {
            delegation.setPeer(component, componentPeer);
          }

          @Override
          public boolean isLightweight(Component component) {
            return delegation.isLightweight(component);
          }

          @Override
          public boolean getIgnoreRepaint(Component component) {
            return delegation.getIgnoreRepaint(component);
          }

          @Override
          public int getWidth(Component component) {
            return delegation.getWidth(component);
          }

          @Override
          public int getHeight(Component component) {
            return delegation.getHeight(component);
          }

          @Override
          public int getX(Component component) {
            return delegation.getX(component);
          }

          @Override
          public int getY(Component component) {
            return delegation.getY(component);
          }

          @Override
          public Color getForeground(Component component) {
            return delegation.getForeground(component);
          }

          @Override
          public Color getBackground(Component component) {
            return delegation.getBackground(component);
          }

          @Override
          public void setBackground(Component component, Color color) {
            delegation.setBackground(component, color);
          }

          @Override
          public Font getFont(Component component) {
            return delegation.getFont(component);
          }

          @Override
          public void processEvent(Component component, AWTEvent awtEvent) {
            delegation.processEvent(component, awtEvent);
          }

          @Override
          public AccessControlContext getAccessControlContext(Component component) {
            return delegation.getAccessControlContext(component);
          }

          @Override
          public void revalidateSynchronously(Component component) {
            delegation.revalidateSynchronously(component);
          }
        }
      }

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

      CUSTOMER SUBMITTED WORKAROUND :
      Use internal APIs.

            ssadetsky Semyon Sadetsky (Inactive)
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            4 Start watching this issue

              Created:
              Updated:
              Resolved: