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

java.awt.Desktop.browse() does not invoke browser until Java process exits

XMLWordPrintable

    • x86_64
    • linux_redhat_6.0

      ADDITIONAL SYSTEM INFORMATION :
      Fedora Core 34 Linux (5.13.12-200.fc34.x86_64)
      Java 1.8.0_302 (Fedora packages:
      java-1.8.0-openjdk.x86_64 1:1.8.0.302.b08-2.fc34 @updates
      java-1.8.0-openjdk-devel.x86_64 1:1.8.0.302.b08-2.fc34 @updates
      java-1.8.0-openjdk-headless.x86_64 1:1.8.0.302.b08-2.fc34 @updates
      java-1.8.0-openjdk-javadoc.noarch 1:1.8.0.302.b08-2.fc34 @updates
      java-1.8.0-openjdk-javadoc-zip.noarch 1:1.8.0.302.b08-2.fc34 @updates
      java-1.8.0-openjdk-src.x86_64 1:1.8.0.302.b08-2.fc34 @updates
      )
      firefox.x86_64 92.0-2.fc34
      default O/S install desktop manager

      A DESCRIPTION OF THE PROBLEM :
      This worked in previous builds of OpenJDK 8, but has not worked since before build 298 (not sure exactly which build it stopped working in). My AWT desktop application would get the java.awt.Desktop object and call the browse() method on it to open a web page when the user clicked on a button to get help. Now, the browser does not start (or add a new tab if already open) until the Java JVM process terminates. The browse() method does return in a fraction of a second (using timestamped print statements around the method call to measure execution), so that isn't hung. And the AWT application is still otherwise working normally (no UI hangs of any sort). When the application's Exit menu choice is invoked (which eventually calls System.exit()), when the Java application window disappears, the browser window appears viewing the requested webpage. While the application is still running, the following frozen process appears in a ps -ef display:

      user 1205714 1097792 0 20:49 pts/2 00:00:00 /bin/sh -e -u -c export GIO_LAUNCHED_DESKTOP_FILE_PID=$$; cat <&89; exec "$@" 89<&- sh /usr/bin/firefox http://www.aprs-is.net/javAPRSFilter.aspx

      This process disappears as soon as the Java process exits (when the browser displays the requested page).


      REGRESSION : Last worked in version 8

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Use the attached sample program. Click the button to try to open the web page. Then click the window close button to terminate the Java application. At that point, the browser should then (and only then) display the selected webpage.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      This output appears on standard output of the Java process:
      Wed Sep 22 20:49:11 EDT 2021 waiting for started browse() thread to finish...
      Wed Sep 22 20:49:11 EDT 2021 starting browse(http://www.aprs-is.net/javAPRSFilter.aspx) call...
      Wed Sep 22 20:49:11 EDT 2021 browse(http://www.aprs-is.net/javAPRSFilter.aspx) call returned.
      Wed Sep 22 20:49:11 EDT 2021 browse() thread terminated.
      Wed Sep 22 20:49:11 EDT 2021 join() for started browse() thread returned, null

      and I expect the browser to open immediately (or create a new tab in an already-running browser) to view the specified URL.
      ACTUAL -
      The above standard output text appears, but nothing happens with the browser until the Java program terminates normally (not killed, but a call to System.exit()). Then the browser opens or creates a new tab to successfully display the requested web page.

      ---------- BEGIN SOURCE ----------
      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import java.awt.BorderLayout;
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.net.URI;
      import java.util.Arrays;
      import java.util.Date;

      public class BrowseTest extends JFrame {
          public static void main(String[] args) {
              new BrowseTest().setVisible(true);
          }

          BrowseTest() {
              super("Browser test");
              JPanel contentPane = new JPanel(new BorderLayout());
              JButton bBrowse = new JButton("Browse http://www.aprs-is.net");
              contentPane.add(BorderLayout.CENTER, bBrowse);
              bBrowse.addActionListener(new ActionListener() {
                  @Override
                  public void actionPerformed(ActionEvent actionEvent) {
                      openURL("http://www.aprs-is.net");
                  }
              });
      setContentPane(contentPane);
      setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      pack();
          }

          static final String[] browsers = { "google-chrome", "firefox", "opera", "epiphany", "konqueror", "conkeror", "midori", "kazehakase", "mozilla" };
          static transient Thread browserLauncher = null;

          /**
           * Launch O/S-specific browser to view a particular URL.
           * @param url String representation of URL to view
           */
          public static void openURL(final String url) {
              if (browserLauncher == null) {
                  final Throwable[] failureReason = new Throwable[1];
                  browserLauncher = new Thread(new Runnable() {
                      public void run() {
                          try {
                              //attempt to use Desktop library from JDK 1.6+
                              Class<?> d = Class.forName("java.awt.Desktop");
                              System.out.println(new Date().toString() + " starting browse(" + url + ") call...");
                              d.getDeclaredMethod("browse", new Class[]{URI.class}).invoke(d.getDeclaredMethod("getDesktop").invoke(null), new Object[]{new URI(url)});
                              System.out.println(new Date().toString() + " browse(" + url + ") call returned.");
                              //above code mimicks: java.awt.Desktop.getDesktop().browse()
                          } catch (Throwable t) {
                              t.printStackTrace(System.out);
                              failureReason[0] = t;
                          } finally {
                              browserLauncher = null;
                              System.out.println(new Date().toString() + " browse() thread terminated.");
                          }
                      }
                  }, "browser launcher");
                  browserLauncher.setDaemon(true);
                  browserLauncher.start();
                  try {
                      System.out.println(new Date().toString() + " waiting for started browse() thread to finish...");
                      browserLauncher.join(20000L); // give it up to 15 seconds to run
                      System.out.println(new Date().toString() + " join() for started browse() thread returned, " + browserLauncher);
                  } catch (InterruptedException e) {
                      // ignore, we shouldn't get this
                      System.out.println(new Date().toString() + " join() for started browse() thread interrupted, " + browserLauncher);
                  }
                  if (browserLauncher == null && failureReason[0] == null) {
                      // we successfully launched a browser using the Desktop
                      return;
                  } else if (browserLauncher != null) {
                      // still running, must be stuck
                      System.out.println(new Date().toString() + " Stuck browser launching thread, trying to kill it...");
                      browserLauncher.stop();
                  }
              }
              //library not available or failed
              String osName = System.getProperty("os.name");
              System.out.println("last browser launch stuck, trying OS-specific for " + osName); try {
                  if (osName.startsWith("Mac OS")) {
                      Class.forName("com.apple.eio.FileManager").getDeclaredMethod("openURL", new Class[]{String.class}).invoke(null, new Object[]{url});
                  } else if (osName.startsWith("Windows")) {
                      Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url);
                  } else if (osName.startsWith("Android")) {
                      //TODO: how to launch browser on Android?
                      throw new UnsupportedOperationException("don't know yet how to launch a browser on OS=" + osName);
                  } else {
                      //assume Unix or Linux
                      String browser = null;
                      for (String b : browsers) {
                          if (browser == null && Runtime.getRuntime().exec(new String[]{"which", b}).getInputStream().read() != -1) {
                              Runtime.getRuntime().exec(new String[]{browser = b, url});
                          }
                      }
                      if (browser == null) {
                          throw new Exception(Arrays.toString(browsers));
                      }
                  }
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No work-around found. The threading code in the example was the work-around, but it doesn't work any more.

      FREQUENCY : always


            pnarayanaswa Praveen Narayanaswamy
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: