Java to JavaScript failure

Help
ociardhp
2007-10-24
2013-04-16
  • ociardhp
    ociardhp
    2007-10-24

    Hi

    I'm running Firefox 2.0.0.8 on Mac OSX 10.4.10 and have encountered a problem where Java to JavaScript communication fails after my applet has been running for some time. No exceptions are thrown and as far as I'm aware nothing is logged. JavaScript to Java communication continues unhindered.

    I'm unable to reliably replicate, but the problem typically occurs after leaving the applet alone for twenty or thirty minutes. I've created a debug build of Firefox (from the 2.0.0.8 branch) and am using that to investigate.

    The Java call that fails to produce any effect is invoked by JavaScript:

    public void getFriends() {
      new Thread(new Runnable() {
        public void run() {
          ... // do some work
          try {
              JSObject.getWindow(UpstreamProxy.this).call("onGetFriendsReturn", new String[] { result } );
              logger.info("Successfully invoked onGetFriendsReturn");
          } catch(Throwable t) {
              logger.log(Level.WARNING, "Failed invoking onGetFriendsReturn", t);
          }
        }
      }).start();
    }

    After a period of time, normal operation ceases, the applet logs "Successfully invoked onGetFriendsReturn", but the browser appears to do nothing. The first line of the JavaScript method onGetFriendsReturn is an invocation of console.log (Firebug) but nothing is logged. Similarly setting a breakpoint in onGetFriendsReturn has no effect.

    I assume the relevant methods are LiveConnectNativeMethods.cpp:Java_netscape_javascript_JSObject_call and LiveConnectNativeMethods.cpp:Java_netscape_javascript_JSObject_getWindow. I had hoped to add a few debug statements to these, but I'm puzzled by the different versions of LiveConnectNativeMethods.cpp in mozilla codebase and in the JEP project.

    When I set a breakpoint in gdb for JSObject_getWindow, it states that the breakpoint was set on line 1667 as I would expect - this is what I see in the JEP source. However, the two versions of LiveConnectNativeMethods.cpp in the mozilla codebase
      12:34 : mozilla $ find . -name 'LiveConnectNativeMethods.cpp'
      ./plugin/oji/MRJ/plugin/Source/LiveConnectNativeMethods.cpp
      ./plugin/oji/MRJCarbon/plugin/Source/LiveConnectNativeMethods.cpp
    are slightly different, but both just over 1000 lines.

    I'd be very grateful if you could tell me what I need to do to include the debug statements in my Firefox build. If you had any insights into why Java -> JavaScript communication is failing, that would be great too.

    Many thanks

    Paul

     
    • Steven Michaud
      Steven Michaud
      2007-10-28

      What I call the "MRJ Plugin JEP" is a replacement for the MRJ Plugin
      that's contained in the Firefox source tree.  I've forked it,
      basically.  For more information see the JEP Readme.  For instructions
      on how to build the MRJ Plugin JEP see the JEP distro's Building.txt.

      I suspect the failures you're seeing are caused by the JavaScript
      method called by JSObject.call() ("onGetFriendsReturn") taking longer
      than 2 seconds to return.

      In the MRJ Plugin JEP's LiveConnectNativeMethods.cpp, there's a
      jsObjectTimeout variable (global and static) that's (by default) set
      to 2000 milliseconds.  This is used to avoid deadlocks in badly
      written Java-to-JavaScript code.

      In most Java-to-JavaScript methods that can return a result, the
      caller (a Java method) is on one thread while the callee (a JavaScript
      method) is on another.  So the caller needs to wait until the callee
      is finished.  But I found that, unless I put in a timeout, the browser
      would sometimes hang in a Java-to-JavaScript method.  So (by default)
      all such methods wait no longer than jsObjectTimeout milliseconds for
      what they're calling to return.

      The JEP has a debug setting (jep.jsobjectnotimeout) that changes
      jsObjectTimeout to '0' (causing the timeout to be infinite).  Try
      adding the following to the "Java Applet Runtime Parameters" box of
      the Java Control Panel (Applications : Utilities : Java : J2SE 5.0 :
      Java Preferences).

        -Djep.jsobjectnotimeout=true

      If I'm right this will stop the mysterious failures that you report.
      But beware that these same failures may now cause the browser to hang
      :-)

      Please post your results.

       
    • ociardhp
      ociardhp
      2007-11-01

      Steven

      Many thanks for your helpful reply. Your suspicions were at least partly correct. When setting -Djep.jsobjectnotimeout=true Firefox would indeed sometimes hang.

      Some of our JavaScript methods invoked by Java do quite a bit of work, firing off AJAX request and using scriptaculous effects. Using console.time to profile method invocation, most JavaScript methods completed in less than 0.5s although the standard deviation was quite high. This would probably explain why the browser sometimes hung.

      On other occassions, though, the browser didn't hang and it appeared that Java-to-JavaScript communication had been severed.

      I finally managed to create a testcase (attached to bug 1824102 as I couldn't attach it here). I also included a failure report in the JAR as there are a number of different outcomes.

      The problem arises in the following scenario only:
      1. method in frame[1] invokes Java method via applet reference in frame[0]
      2. the Java method creates a new thread and returns after starting it
      3. the new thread invokes a JavaScript method, implicitly in frame[0]
      4. the JavaScript method tries to invoke a method that does not exist
      5. at this point Java methods that attempt to invoke JavaScript methods in new Java threads will run JSObject.getWindow().call() successfully, but the JavaScript method will not be invoked.

      I realise the above scenario sounds extremely contrived and yet we managed to hit on it in our application:) I appreciate that the cause (4) is a coding error on our part - due to expecting the DOM to have been modified when it wasn't - but the result (5) is perhaps unnecessarily harsh. Fortunately, there's a workaround. 

      Based on your statement that the Java method is on one thread and that it must wait for the JavaScript method (on another thread) to complete, I decided to make JavaScript methods invoked by Java invoke setTimeout(), passing the real method as a argument and returning immediately. This approach seems to have worked as when the real method tries to invoke a non-existant method, Java-to-JavaScript communication is not severed. In the testcase I've called this approach 'NewJavaScriptThread' although I realise it's not really a new thread.

      Running with -Djep.jsobjectnotimeout=true produced no differences in my test runs.

      Thanks again

      Paul

       
  • neerajum
    neerajum
    2012-06-01

    Hello Paul,

    I know this is a really old issue, but could you send me the solution for the problem you encountered?

    Thanks,
    Neeraj