Chrome selects wrong thread for JS-Java upcall on 2nd(ish) Applet instance

Discussion in 'Java' started by Richard Maher, Oct 30, 2010.

  1. Hi,

    This is directly related to "fix" for SDN Bug ID 6742814: -
    http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6742814

    A couple of relevant-sounding quotes from that bug report : -
    {
    The rules for initiating JavaScript-to-Java and Java-to-JavaScript
    calls (which will be formalized in the forthcoming new LiveConnect
    specification) are:

    - JavaScript-to-Java calls against a given applet block until that
    applet has completed init(), or

    - that applet initiates a Java-to-JavaScript call in init().
    }

    The definition of "initiates a Java-to-JavaScript" in that last line appears
    to have been further broadened and amplified to include: -
    {
    - If a request comes to the browser from an applet to fetch the
    JavaScript window object corresponding to the applet, drain the
    queued up messages corresponding to JavaScript-to-Java calls,
    which would otherwise occur when init() was completed.
    }

    This was raised as an issue for me in comp.lang.java on the 22-April-2009
    and Mark Space kindly pointed out that the addition of "synchronized" to the
    relevant Applet methods would achieve the desired results, with the worker
    methods only being invoked after the Applet had completed its initialization
    in the init() method. So everything was peachy until I found that Google
    Chrome can, and often does, choose the wrong thread to execute the JS to
    Java upcall when dealing with more than one instance of the Applet in the
    browser instance. (Different tabs in my case)

    You may recall that my Javascript to invoke the Applet looked like this: -

    document.body.appendChild(appletDiv);
    tier3Chan = document.getElementById(appletId);
    var userAuthorized = tier3Chan.isAuthorized();
    }
    catch(err) {
    alert("Err =" + err.description);
    tier3Chan = null;
    };

    What "normally" happens (Firefox, IE, Chrome-[with-Applet-Instance/Tab-1])
    is that: -

    1) The "getElementById(appletId)" loads the Applet and calls init() in a
    thread the JVM calls: -
    "thread applet-tier3Client/Tier3Application-1"
    My package is "tier3Client" and the class is "Tier3Application" and the
    applet instance is "1".
    2) The tier3Chan.isAuthorized() method (JS->JAVA upcall) is executed on a
    new LiveConnect thread called: -
    "Applet 1 LiveConnect Worker Thread"
    Again the "1" relating to the applet instance in the browser. When the
    applet is loaded again via pages in other tabs the instance number is
    incremented and new threads created.
    3) I also instantiate another Thread that can call down to JS but I don't
    believe that to be relevant at this stage.
    4) When my init() method calls JSObject.getWindow(this) Chrome seeks to
    "drain the queued up messages corresponding to JavaScript-to-Java calls,
    which would otherwise occur when init() was completed" and my isAuthorized()
    method is invoked on the "Applet 1 LiveConnect Worker Thread".
    5) Because both my overridden init() method and my isAuthorized() methods
    are synchronized on the Applet instance's object, the isAuthorized() method
    is forced to wait until initialization is complete and authorization has
    been checked.

    A tad complicated but it worked and I was happy with it.

    What appears to go wrong with Chrome on the 2nd -(usually the 2nd but then
    it might work/fail for additional tabs - the first page always works)- tab
    with an applet invoking page is that the isAuthorized() upcall gets executed
    on the "thread applet-tier3Client/Tier3Application-2" Thread. The same
    Thread that init() was/is executing on!!!

    Now my understanding of the Java threading model is that, to support
    recursion, a Thread cannot lock/mutex/synchronize itself out of an object.
    So my "synchronized" init() and isAuthorized() methods on the Applet 2
    instance don't amount to a hill o' beans and my authorization check occurs
    *before* I've determined if the user is authorized and I've had a chance to
    set the variable :-(

    To summarize, Chrome has a bug where it can permit an upcall to execute on
    the "thread applet-tier3Client/Tier3Application-(n)" thread instead of the
    "Applet (n) LiveConnect Worker Thread". Try as I might I cannot create a
    "simple" reproducer for this :-( My Applet is quite complex and I'm
    clutching at straws to guess what algorithm Chrome uses when looking for
    threads to allocate work to, or for Threads to publish their availability.

    Can someone please shed any light on this? Is there a work around? Is there
    a useful Chrome bug-logging forum that will even look at the source without
    a reproducer to go on?

    Look, I know I shot my mouth off before about this being a race condition
    where the isAuthorized() was being called *before* the init() but that was
    because I couldn't cope with the concept of synchronized Applet instance
    methods executing at the same time.

    Please help if you can.

    Cheers Richard Maher
     
    Richard Maher, Oct 30, 2010
    #1
    1. Advertising

  2. Richard Maher

    Daniel Pitts Guest

    Re: Chrome selects wrong thread for JS-Java upcall on 2nd(ish) Appletinstance

    On 10/30/2010 4:25 AM, Richard Maher wrote:
    > What appears to go wrong with Chrome on the 2nd -(usually the 2nd but then
    > it might work/fail for additional tabs - the first page always works)- tab
    > with an applet invoking page is that the isAuthorized() upcall gets executed
    > on the "thread applet-tier3Client/Tier3Application-2" Thread. The same
    > Thread that init() was/is executing on!!!
    >
    > Now my understanding of the Java threading model is that, to support
    > recursion, a Thread cannot lock/mutex/synchronize itself out of an object.
    > So my "synchronized" init() and isAuthorized() methods on the Applet 2
    > instance don't amount to a hill o' beans and my authorization check occurs
    > *before* I've determined if the user is authorized and I've had a chance to
    > set the variable :-(


    > Look, I know I shot my mouth off before about this being a race condition
    > where the isAuthorized() was being called *before* the init() but that was
    > because I couldn't cope with the concept of synchronized Applet instance
    > methods executing at the same time.
    >
    > Please help if you can.
    >
    > Cheers Richard Maher


    It might help you to add some sort of logging to the "init()" and
    "isAuthorized()" methods, to trace when they start and when they end.

    In either case, you have a mistaken conception that Chrome can
    "interrupt" a running thread (the thread which is running your init
    method) to do some other task.


    What you may need to do is this, although without seeing your code, I
    can only guess at your problem.

    class MyApplet extends Applet {
    private final Object sync = new Object();
    private boolean initFinished;
    public void init() {
    initIfNecessary();
    }

    public void initIfNecessary() {
    synchronize (sync) {
    if (!initFinished) {
    // do initializatation
    initFinished = true;
    }
    }
    }

    public boolean isAuthorized() {
    initIfNecessary();
    return /* check for authorization */
    }
    }

    I suspect that while this may "resolve" your issue, that there is some
    other underlying misunderstanding of yours at the core of this problem,
    which can only be corrected if you post an SSCCE (see
    http://virtualinfinity.net/sscce.html)


    Another problem you may run into is Java->JS calls. Documentation on
    how to make those calls threadsafe is difficult to find. I'm not even
    sure it *is* possible (one can only hope the browser itself has a JS
    engine which is thread-safe).

    HTH,
    Daniel.
    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Nov 2, 2010
    #2
    1. Advertising

  3. Richard Maher

    markspace Guest

    Re: Chrome selects wrong thread for JS-Java upcall on 2nd(ish) Appletinstance

    On 11/1/2010 10:51 PM, Daniel Pitts wrote:

    > It might help you to add some sort of logging to the "init()" and
    > "isAuthorized()" methods, to trace when they start and when they end.


    > which can only be corrected if you post an SSCCE (see
    > http://virtualinfinity.net/sscce.html)



    The above two points are critical. We need an SSCCE to observe what it
    is you are actually seeing. Be sure that the SSCCE is capable of
    reproducing the problem -- give us a sample output from your SSCCE that
    shows (via logging) what you think the problem is.

    Since you're using an applet you ought be able to post the SSCCE as an
    applet as well. That would be handy as it's unlikely that anyone's
    going to write all the JavaScript and Java necessary to produce a proper
    test and fix your issue.

    I suspect your problem either involves:

    1) Multiple instances of the same applet running -- which is why you
    think there's one thread running in two methods at the same time (there
    isn't).

    2) Static variable which are being shared across multiple threads and
    are still not synchronized properly.
     
    markspace, Nov 2, 2010
    #3
  4. Hi Mark,

    "markspace" <> wrote in message
    news:iapkp8$n6q$-september.org...
    > On 11/1/2010 10:51 PM, Daniel Pitts wrote:
    >
    >> It might help you to add some sort of logging to the "init()" and
    >> "isAuthorized()" methods, to trace when they start and when they end.

    >
    >> which can only be corrected if you post an SSCCE (see
    >> http://virtualinfinity.net/sscce.html)

    >
    >
    > The above two points are critical. We need an SSCCE to observe what it is
    > you are actually seeing.


    Yes that would be ideal but to date (as pointed out in my original post) I
    ca'nt reproduce such a beast. I will persist but if I had a rough idea of
    the how work gets allocated to threads, or how threads publish their
    availability, or take new work then I could better try to simulate the
    conditions.

    > Be sure that the SSCCE is capable of reproducing the problem -- give us a
    > sample output from your SSCCE that shows (via logging) what you think the
    > problem is.
    >
    > Since you're using an applet you ought be able to post the SSCCE as an
    > applet as well. That would be handy as it's unlikely that anyone's going
    > to write all the JavaScript and Java necessary to produce a proper test
    > and fix your issue.


    If I can't reproduce it I'll at least provide the "disprover". To get people
    started.
    >
    > I suspect your problem either involves:
    >
    > 1) Multiple instances of the same applet running -- which is why you think
    > there's one thread running in two methods at the same time (there isn't).


    Here is the Chrome output with the isAuthorized() output *including Thread
    Names* surounded by asterix: -

    basic: Added progress listener:
    sun.plugin.util.GrayBoxPainter$GrayBoxProgressListener@3f4ebd
    basic: Plugin2ClassLoader.addURL parent called for
    http://192.168.1./Applets/tier3Client.jar
    basic: Applet loaded.
    basic: Applet resized and added to parent container
    basic: PERF: AppletExecutionRunnable - applet.init() BEGIN ; jvmLaunch dt
    285443 us, pluginInit dt 24183200 us, TotalTime: 24468643 us
    Tier3Client Applet
    Version 1.1
    Copyright (c) Richard Maher
    All rights reserved.

    Thread: thread applet-tier3Client/Tier3Application.class-2
    >>>>>>>>>>JSObject.getWindow(applet) is called here<<<<<<<<<<<<<<<<<<<

    ****************************************
    30/10/2010 4:34:53 PM tier3Client.Tier3Application isAuthorized
    INFO: In isAuthorized() Thread: thread
    applet-tier3Client/Tier3Application.class-2
    ****************************************
    topDocHost = 192.168.1.159
    Called 2 times
    The value of i is 0
    Null index is -1
    After connect
    30/10/2010 4:34:53 PM tier3Client.Tier3Application init
    INFO: Applet initialization complete - WindowSlotIndex is 1
    basic: Applet initialized
    basic: Removed progress listener:
    sun.plugin.util.GrayBoxPainter$GrayBoxProgressListener@3f4ebd
    basic: Applet made visible
    basic: Starting applet
    basic: completed perf rollup
    basic: Applet started
    basic: Told clients applet is started

    Are you saying that I'm making that up or that it is perfectly reasonable
    that another method (isAuthorized() in my case) can pause the applet init(),
    get executed in the same thread and then finish the rest of init()?

    >
    > 2) Static variable which are being shared across multiple threads and are
    > still not synchronized properly.
    >

    Yes but I think that's a seperate issue.

    Look, in the absence of a reproducer, if someone (with direct reference to
    http://download.oracle.com/javase/6/docs/technotes/guides/jweb/applet/applet_execution.html#threads )
    can describe what exactly is happening/permissible then that'd be great.

    Cheers Richard Maher

    PS. Here's the firefox JVM console output: -

    30/10/2010 4:30:41 PM tier3Client.Tier3Application init
    INFO: Applet initialization complete - WindowSlotIndex is 1
    30/10/2010 4:30:41 PM tier3Client.Tier3Application isAuthorized
    INFO: In isAuthorized() Thread: Applet 2 LiveConnect Worker Thread
    basic: Applet initialized
    basic: Removed progress listener:
    sun.plugin.util.GrayBoxPainter$GrayBoxProgressListener@830122
    basic: Applet made visible
    basic: Starting applet
    basic: completed perf rollup
    basic: Applet started
    basic: Told clients applet is started
     
    Richard Maher, Nov 2, 2010
    #4
  5. Richard Maher

    markspace Guest

    Re: Chrome selects wrong thread for JS-Java upcall on 2nd(ish) Appletinstance

    On 11/2/2010 3:51 PM, Richard Maher wrote:
    > it is perfectly reasonable
    > that another method (isAuthorized() in my case)



    Yes. That's what I'm saying. Your Applet is multithreaded. Therefore
    methods get called in an unpredictable fashion.


    > can pause the applet init(),
    > get executed in the same thread and then finish the rest of init()?



    Nothing gets "paused" or executed on the same thread, it's just
    multi-threaded. Read that technote again:

    "A web browser's JavaScript interpreter engine is single thread. The
    Java Plug-in is capable of managing multiple threads. The Java Plug-in
    creates a separate worker thread for every applet."

    That's at least two threads right there. One for JS, one for the Java
    Plug-In. Chrome or Firefox may have more involved. It's unpredictable
    exactly how many.
     
    markspace, Nov 2, 2010
    #5
  6. "markspace" <> wrote in message
    news:iaq70a$9br$-september.org...
    > On 11/2/2010 3:51 PM, Richard Maher wrote:
    >> it is perfectly reasonable
    >> that another method (isAuthorized() in my case)

    >
    >
    > Yes. That's what I'm saying. Your Applet is multithreaded. Therefore
    > methods get called in an unpredictable fashion.
    >
    >
    >> can pause the applet init(),
    >> get executed in the same thread and then finish the rest of init()?

    >
    >
    > Nothing gets "paused" or executed on the same thread, it's just
    > multi-threaded. Read that technote again:


    Please see below and previous post.

    >
    > "A web browser's JavaScript interpreter engine is single thread. The Java
    > Plug-in is capable of managing multiple threads. The Java Plug-in creates
    > a separate worker thread for every applet."
    >
    > That's at least two threads right there. One for JS, one for the Java
    > Plug-In. Chrome or Firefox may have more involved. It's unpredictable
    > exactly how many.
    >


    Yes but please look at the output again. For the second tab/applet-instance
    the isAuthorized() method is executing in the same Thread as the init()
    method!!!

    INFO: In isAuthorized() Thread: thread
    applet-tier3Client/Tier3Application.class-2

    I undoubtedly know of the existance of the "Applet 2 LiveConnect Worker
    Thread" but Chrome chooses not to use in the 2nd instance.

    Firefox does not; IE does not; Chrome on tab-1 (and some others after 2)
    does not!

    Do you see?

    Cheers Richard Maher
     
    Richard Maher, Nov 2, 2010
    #6
  7. Seeing is believing?

    Hi Mark,

    "markspace" <> wrote in message
    news:iaqbd6$njv$-september.org...
    > On 11/2/2010 4:47 PM, Richard Maher wrote:
    >
    >> INFO: In isAuthorized() Thread: thread
    >> applet-tier3Client/Tier3Application.class-2

    >
    > I don't believe these are the same thread. It's just a name, and you can
    > name threads all the same if you like.
    >
    > Print out the object itself and see what you get.


    As requested here are the relevant bits: -

    basic: PERF: AppletExecutionRunnable - applet.init() BEGIN ; jvmLaunch dt
    324932 us, pluginInit dt 51588923 us, TotalTime: 51913855 us
    Tier3Client Applet
    Version 1.0
    Copyright (c) Richard Maher
    All rights reserved.

    In init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    03/11/2010 9:31:21 PM tier3Client.Tier3Application isAuthorized
    INFO: In isAuthorized() Thread: [thread
    applet-tier3Client/Tier3Application.class-2] toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    topDocHost = 192.168.1.159
    Called 2 times
    The value of i is 0
    03/11/2010 9:31:21 PM tier3Client.Tier3Application init
    INFO: Init() - Session ID is 0 refCnt = 1
    Null index is -1
    After connect
    03/11/2010 9:31:21 PM tier3Client.Tier3Application init
    INFO: Applet initialization complete - WindowSlotIndex is 1
    Leaving init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    basic: Applet initialized
    >
    >


    Do you not see the same thread being used from init() [up until the code
    that calls JSObject.getWindow(this)] then isAuthorized receives control of
    the very same thread, and when that finishes the rest of init() gets
    processed.

    Is currentThread() stooging me? Is there something there that I don't
    understand? Or is it you that won't see what's in front of our faces?

    Cheers Richard Maher

    PS. Here is the unsummarized output with much noise from other logging.
    ("Demo" is another thread that I create.)

    basic: Added progress listener:
    sun.plugin.util.GrayBoxPainter$GrayBoxProgressListener@898540
    basic: Plugin2ClassLoader.addURL parent called for
    http://192.168.1/Applets/tier3Client.jar
    basic: Applet loaded.
    basic: Applet resized and added to parent container
    basic: PERF: AppletExecutionRunnable - applet.init() BEGIN ; jvmLaunch dt
    324932 us, pluginInit dt 51588923 us, TotalTime: 51913855 us
    Tier3Client Applet
    Version 1.0
    Copyright (c) Richard Maher
    All rights reserved.

    In init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    After setMember 3100170Wood, Brian MCabinet & Frame
    Manufacturing $10,664.00 $26,988.20 1 4
    In rendezvous() Demo
    past wait
    SEND synchronization is complete
    call returned from JS
    Thread[Demo,4,http://192.168.1.159/Applets/-threadGroup]
    after callback
    03/11/2010 9:31:21 PM tier3Client.Tier3Application isAuthorized
    INFO: In isAuthorized() Thread: [thread
    applet-tier3Client/Tier3Application.class-2] toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    topDocHost = 192.168.1.159
    Called 2 times
    The value of i is 0
    03/11/2010 9:31:21 PM tier3Client.Tier3Application init
    INFO: Init() - Session ID is 0 refCnt = 1
    Null index is -1
    After connect
    03/11/2010 9:31:21 PM tier3Client.Tier3Application init
    INFO: Applet initialization complete - WindowSlotIndex is 1
    Leaving init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    toString = Thread[thread
    applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    hash = 180b22e
    basic: Applet initialized
    basic: Removed progress listener:
    sun.plugin.util.GrayBoxPainter$GrayBoxProgressListener@898540
    basic: Applet made visible
    basic: Starting applet
    basic: completed perf rollup
    basic: Applet started
    basic: Told clients applet is started
     
    Richard Maher, Nov 3, 2010
    #7
  8. Richard Maher

    Daniel Pitts Guest

    Re: Seeing is believing?

    On 11/3/2010 7:03 AM, Richard Maher wrote:
    > Hi Mark,
    >
    > "markspace"<> wrote in message
    > news:iaqbd6$njv$-september.org...
    >> On 11/2/2010 4:47 PM, Richard Maher wrote:
    >>
    >>> INFO: In isAuthorized() Thread: thread
    >>> applet-tier3Client/Tier3Application.class-2

    >>
    >> I don't believe these are the same thread. It's just a name, and you can
    >> name threads all the same if you like.
    >>
    >> Print out the object itself and see what you get.

    >
    > As requested here are the relevant bits: -
    >
    > basic: PERF: AppletExecutionRunnable - applet.init() BEGIN ; jvmLaunch dt
    > 324932 us, pluginInit dt 51588923 us, TotalTime: 51913855 us
    > Tier3Client Applet
    > Version 1.0
    > Copyright (c) Richard Maher
    > All rights reserved.
    >
    > In init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    > toString = Thread[thread
    > applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    > hash = 180b22e
    > 03/11/2010 9:31:21 PM tier3Client.Tier3Application isAuthorized
    > INFO: In isAuthorized() Thread: [thread
    > applet-tier3Client/Tier3Application.class-2] toString = Thread[thread
    > applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    > hash = 180b22e

    [snip]
    > Leaving init() Thread: [thread applet-tier3Client/Tier3Application.class-2]
    > toString = Thread[thread
    > applet-tier3Client/Tier3Application.class-2,4,http://192.168.1.159/Applets/-threadGroup]
    > hash = 180b22e
    > basic: Applet initialized
    >>
    >>

    >
    > Do you not see the same thread being used from init() [up until the code
    > that calls JSObject.getWindow(this)] then isAuthorized receives control of
    > the very same thread, and when that finishes the rest of init() gets
    > processed.

    So, the problem appears to be that JSObject.getWindow(this) actually
    cedes control back to the JS engine parser. Perhaps you should avoid
    calling JSObject.getWindow(this) in init().
    >
    > Is currentThread() stooging me? Is there something there that I don't
    > understand? Or is it you that won't see what's in front of our faces?

    Yes, there is a lot you don't understand, like how to put together an
    SSCCE which could show this problem ;-). Anyway, the solution is to
    avoid calling getWindow(this) in init(), or at least waiting until the
    rest of your initialization is complete.

    HTH,
    Daniel.

    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Nov 4, 2010
    #8
  9. Re: Seeing is believing?

    Hi Daniel,

    "Daniel Pitts" <> wrote in message
    news:NZsAo.3996$...
    > On 11/3/2010 7:03 AM, Richard Maher wrote:

    8<
    >> Do you not see the same thread being used from init() [up until the code
    >> that calls JSObject.getWindow(this)] then isAuthorized receives control
    >> of
    >> the very same thread, and when that finishes the rest of init() gets
    >> processed.

    > So, the problem appears to be that JSObject.getWindow(this) actually cedes
    > control back to the JS engine parser.


    No, I/we can put up with this wierdness; what I cannot countenance is Chrome
    *and specifically/uniquely Chrome* draining-the-queue via the same bloody
    Thread that init() is running in!

    If someone could just postulate on (a) How the JS-Java upcall gets allocated
    to a Thread, (b) How such swinger Threads make their availability known to
    Chrome, and/or (c) How a Java Thread unilaterally assigns itself available
    work, then I'm more than willing to hear it!

    My theory is that, on the 2nd applet instance, the timing is such that the
    isAuthorized() Applet call arrives before Chrome has had a chance to set the
    There's-Tricky-LiveConnect-Crap-Here flag and the method gets executed on
    the natural choice of the standard applet thread rather than the LiveConnect
    worker thread. But someone with knowledge of A, B, or C from above would be
    in a far better place to answer that question.

    > Perhaps you should avoid calling JSObject.getWindow(this) in init().


    Yes, yes, yes. As with your first reply, the "if (firstTimeFlag = "Y")
    doInit();" should work, but it's bloody inconvenient writing off everything
    that Applet.init() is contracted to do and is just bollocks in my opinion.
    Having said that, pragmatism leads me in that direction :-(

    Again, this is only Chrome. (BTW for IE>7 you have to set the registry
    setting TabProcGrowth < 2)

    >>
    >> Is currentThread() stooging me? Is there something there that I don't
    >> understand? Or is it you that won't see what's in front of our faces?

    > Yes, there is a lot you don't understand, like how to put together an
    > SSCCE which could show this problem ;-).


    Look the crying shame (and imho more evidence of the exception/bug) is that
    I can't reproduce it without the several thousand complex lines of Java that
    goes with it :-( Having said that, please see below for a "working" version
    that happily engages the LiveConnect Worker Thread for isDone() every time.

    If anyone is willing to play around with this in order to reproduce the
    described behaviour then compile Sleeper.java and OutThread.java in to a JAR
    called Sleeper2.jar then stick that in your web root directory with
    dyntest.html and give it a go. Turn the Java Console on to see what's
    happening.

    > Anyway, the solution is to avoid calling getWindow(this) in init(), or at
    > least waiting until the rest of your initialization is complete.
    >
    > HTH,
    > Daniel.


    Cheers Richard Maher

    Sleeper.java
    =========

    import java.applet.Applet;
    import netscape.javascript.JSObject;
    //import netscape.javascript.JSException;
    //import java.lang.InterruptedException;
    import java.util.ArrayList;

    public class Sleeper extends Applet {
    private int myNum = 0;
    private JSObject browser;
    private volatile static int appletIndex = 0;
    private static OutThread writer;
    private boolean initFlag = false;
    private volatile static ArrayList<JSObject> windows = new
    ArrayList<JSObject>();

    public synchronized void init() {
    super.init();
    Thread curr = Thread.currentThread();
    System.out.println(" In Init() " + curr.getName() +
    curr + " hash " + Integer.toHexString(curr.hashCode()));
    appletIndex++;
    try {
    browser = JSObject.getWindow(this); }
    catch (netscape.javascript.JSException e) {
    e.printStackTrace(); }
    catch (Exception e) {
    e.printStackTrace(); }

    synchronized(windows){
    windows.add(browser);

    if (writer == null){
    writer = new OutThread("Fred", windows);
    writer.start();
    }
    }
    /**
    System.out.println("Before sleep call");
    try {
    Thread.sleep(1000);
    }
    catch (InterruptedException e){
    e.printStackTrace();
    }
    System.out.println("After sleep call");
    */
    myNum = 33;
    initFlag = true;
    }

    public synchronized boolean isDone() {
    Thread curr = Thread.currentThread();
    System.out.println(" In isDone() " + curr.getName() +
    curr + " hash " + Integer.toHexString(curr.hashCode()));
    return initFlag;
    }

    public synchronized int getNum(String caller){
    int i = myNum++;
    Thread curr = Thread.currentThread();
    System.out.println("in getNum() " + myNum + " caller " + caller + "
    Thread " +
    curr.getName() +
    curr + " hash " + Integer.toHexString(curr.hashCode()));
    return i;
    }

    public synchronized void destroy ()
    {
    System.out.println("Checked - out");
    super.destroy();
    }
    }

    OutThread.java
    ===========

    import netscape.javascript.JSObject;
    import java.util.ArrayList;

    class OutThread extends Thread {
    ArrayList<JSObject> windows;

    public OutThread(String name, ArrayList<JSObject> windows) {
    super(name);
    System.out.println("Thread constructor");
    this.setDaemon(true);
    this.windows = windows;
    }

    public void run() {
    int sel = -1;
    JSObject browser;
    while (true) {
    synchronized(windows){
    sel++;
    if (sel == windows.size()){
    sel = 0;
    }
    browser = windows.get(sel);
    }
    try {
    sleep((int)(Math.random() * 1000));
    browser.call("tickOver", null);
    } catch (InterruptedException e) {break;}
    }
    System.out.println("DONE!");
    }
    }

    dyntest.html
    ========

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">

    <html>

    <head>

    <style>

    body
    {
    background-color: aliceblue;
    color: black;
    font-family: Georgia;
    font-size: 12px;
    margin-left: 5px;
    margin-right: 5px;
    margin-top: 1px;
    padding: 0;
    }

    </style>

    <script type="text/javascript">

    var cntr = 0;
    var chan;

    function load()
    {
    var objectTag = "<object classid=";

    if (/Internet Explorer/.test(navigator.appName)) {
    objectTag = objectTag +
    '"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
    } else {
    objectTag = objectTag +
    '"java:Sleeper.class" type="application/x-java-applet" ' +
    'archive="http://127.0.0.1/Sleeper2.jar" ';
    }

    objectTag = objectTag +
    'width= "0" height= "0" name="TestApp" id="TestApp">' +
    '<param name="archive" value="Sleeper2.jar">' +
    '<param name="codebase" value="http://127.0.0.1/">' +
    '<param name="code" value="Sleeper">' +
    '<param name="java_version" value="1.6+">' +
    '<param name="mayscript" value="true">' +
    '<param name="scriptable" value="true">' +
    '<param name="codebase_lookup" value="false">' +
    '</object>';

    var appletDiv = document.createElement("div");
    appletDiv.innerHTML = objectTag;

    try {
    document.body.appendChild(appletDiv);
    chan = document.getElementById("TestApp");
    }
    catch(err) {
    alert("Tier3 unable to load applet: -\n" +
    (err.description||err.message));
    chan = null;
    };

    if (chan == null) {
    throw new Error("Tier3 was unable to initialize the applet");
    } else {
    try {
    if (!chan.isDone())
    alert("*******RACE******");
    }
    catch(err) {
    chan.setAttribute("id",null);
    chan = null;
    throw new Error("Tier3 unable to load applet: -\n" +
    (err.description||err.message));
    }
    }
    }

    function tickOver(){
    cntr=chan.getNum("TO");
    document.mfForm.username.value="TO:"+cntr;
    setTimeout('fred()',1000);
    }

    function fred(){
    cntr=chan.getNum("AST");
    document.mfForm.username.value="AST:"+cntr;
    }
    </script>

    </head>

    <body id="torso" onload="load()">
    <form name="mfForm">
    Something:
    <input
    name="username";
    class="revLeft";
    style="font-size: 11px";
    type="text";
    size=12;
    /></td>

    </form>
    </body>
    </html>
     
    Richard Maher, Nov 4, 2010
    #9
  10. Richard Maher

    Daniel Pitts Guest

    Re: Seeing is believing?

    On 11/4/2010 3:00 AM, Richard Maher wrote:
    > Hi Daniel,
    >
    > "Daniel Pitts"<> wrote in message
    > news:NZsAo.3996$...
    >> On 11/3/2010 7:03 AM, Richard Maher wrote:

    > 8<
    >>> Do you not see the same thread being used from init() [up until the code
    >>> that calls JSObject.getWindow(this)] then isAuthorized receives control
    >>> of
    >>> the very same thread, and when that finishes the rest of init() gets
    >>> processed.

    >> So, the problem appears to be that JSObject.getWindow(this) actually cedes
    >> control back to the JS engine parser.

    >
    > No, I/we can put up with this wierdness; what I cannot countenance is Chrome
    > *and specifically/uniquely Chrome* draining-the-queue via the same bloody
    > Thread that init() is running in!


    Actually, I think you've put the cart before the horse. What Chrome
    appears to be doing is drainging-the-queue in whatever thread happens to
    call JSObject.getWindow(...). (You could verify this assumption by
    printing "about to get window" and "finished getting window" around that
    call).

    This isn't necessarily expected or unexpected behavior. Armed with this
    knowledge, you should be able to work around the chrome issue, and not
    worry about it any more.


    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
     
    Daniel Pitts, Nov 10, 2010
    #10
  11. Re: Seeing is believing?

    "Daniel Pitts" <> wrote in message
    news:GmmCo.20879$...
    > On 11/4/2010 3:00 AM, Richard Maher wrote:
    >> Hi Daniel,
    >>
    >> "Daniel Pitts"<> wrote in
    >> message
    >> news:NZsAo.3996$...
    >>> On 11/3/2010 7:03 AM, Richard Maher wrote:

    >> 8<
    >>>> Do you not see the same thread being used from init() [up until the
    >>>> code
    >>>> that calls JSObject.getWindow(this)] then isAuthorized receives control
    >>>> of
    >>>> the very same thread, and when that finishes the rest of init() gets
    >>>> processed.
    >>> So, the problem appears to be that JSObject.getWindow(this) actually
    >>> cedes
    >>> control back to the JS engine parser.

    >>
    >> No, I/we can put up with this wierdness; what I cannot countenance is
    >> Chrome
    >> *and specifically/uniquely Chrome* draining-the-queue via the same bloody
    >> Thread that init() is running in!

    >
    > Actually, I think you've put the cart before the horse. What Chrome
    > appears to be doing is drainging-the-queue in whatever thread happens to
    > call JSObject.getWindow(...). (You could verify this assumption by
    > printing "about to get window" and "finished getting window" around that
    > call).


    No. For anyone bothering to read this thread, or type two JAVACs and a JAR
    to reproduce the behaviour, the reward will be a clear view of the init()
    running in [thread applet-tier3Client/Tier3Application.class-"n"] and
    isAuthorized() running in [Applet "n" LiveConnect Worker Thread]. *Once
    again* this is true for FF, IE, and Chrome (Applet instance 1).

    Chrome has a bug that, under currently undefined circumstances, it chooses
    to drain-the-queue on the same thread as init() namely [thread
    applet-tier3Client/Tier3Application.class-"n"] This is wrong. This is a bug.
    This is in need of correction!

    >
    > This isn't necessarily expected or unexpected behavior.


    No it is completely unexpected and I challenge you to reproduce it!

    > Armed with this knowledge, you should be able to work around the chrome
    > issue, and not worry about it any more.


    Ah yes, there are no bugs, only work-around opportunities :-(

    If only I had access to someone who knows what he's talking about then I'm
    sure Chrome would be happy for the heads-up.

    Regards Richard Maher
     
    Richard Maher, Nov 10, 2010
    #11
  12. Chrome just killed the <OBJECT> tag :-(

    "Richard Maher" <> wrote in message
    news:iau08p$uqm$...
    dyntest.html
    > ========
    >
    > <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    > "http://www.w3.org/TR/html4/loose.dtd">
    >
    > <html>
    >
    > <head>
    >
    > <style>
    >
    > body
    > {
    > background-color: aliceblue;
    > color: black;
    > font-family: Georgia;
    > font-size: 12px;
    > margin-left: 5px;
    > margin-right: 5px;
    > margin-top: 1px;
    > padding: 0;
    > }
    >
    > </style>
    >
    > <script type="text/javascript">
    >
    > var cntr = 0;
    > var chan;
    >
    > function load()
    > {
    > var objectTag = "<object classid=";
    >
    > if (/Internet Explorer/.test(navigator.appName)) {
    > objectTag = objectTag +
    > '"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
    > } else {
    > objectTag = objectTag +
    > '"java:Sleeper.class" type="application/x-java-applet" ' +
    > 'archive="http://127.0.0.1/Sleeper2.jar" ';
    > }
    >
    > objectTag = objectTag +
    > 'width= "0" height= "0" name="TestApp" id="TestApp">' +
    > '<param name="archive" value="Sleeper2.jar">' +
    > '<param name="codebase" value="http://127.0.0.1/">' +
    > '<param name="code" value="Sleeper">' +
    > '<param name="java_version" value="1.6+">' +
    > '<param name="mayscript" value="true">' +
    > '<param name="scriptable" value="true">' +
    > '<param name="codebase_lookup" value="false">' +
    > '</object>';
    >
    > var appletDiv = document.createElement("div");
    > appletDiv.innerHTML = objectTag;
    >
    > try {
    > document.body.appendChild(appletDiv);
    > chan = document.getElementById("TestApp");
    > }
    > catch(err) {
    > alert("Tier3 unable to load applet: -\n" +
    > (err.description||err.message));
    > chan = null;
    > };
    >
    > if (chan == null) {
    > throw new Error("Tier3 was unable to initialize the applet");
    > } else {
    > try {
    > if (!chan.isDone())
    > alert("*******RACE******");
    > }
    > catch(err) {
    > chan.setAttribute("id",null);
    > chan = null;
    > throw new Error("Tier3 unable to load applet: -\n" +
    > (err.description||err.message));
    > }
    > }
    > }
    >
    > function tickOver(){
    > cntr=chan.getNum("TO");
    > document.mfForm.username.value="TO:"+cntr;
    > setTimeout('fred()',1000);
    > }
    >
    > function fred(){
    > cntr=chan.getNum("AST");
    > document.mfForm.username.value="AST:"+cntr;
    > }
    > </script>
    >
    > </head>
    >
    > <body id="torso" onload="load()">
    > <form name="mfForm">
    > Something:
    > <input
    > name="username";
    > class="revLeft";
    > style="font-size: 11px";
    > type="text";
    > size=12;
    > /></td>
    >
    > </form>
    > </body>
    > </html>
    >
    >


    For those of you attempting to run the above example, you may now find that
    it no longer activates the JVM. I wasn't (although am now) aware of turning
    off Windows scheduler for Chrome updates and ended up with the latest and
    not so greatest 7.0.517.44.

    For more details see: -
    http://code.google.com/p/chromium/issues/detail?id=62076

    Suffice it to say Google/Chrome have broken the <OBJECT> tag and instead of
    being really, really humble about a bollocks regression-test regime they are
    making pathetic claims such as "Well they shouldn't have been doing that
    anyway" :-(

    Cheers Richard Maher
     
    Richard Maher, Nov 11, 2010
    #12
  13. Richard Maher

    Roedy Green Guest

    Re: Chrome just killed the <OBJECT> tag :-(

    On Thu, 11 Nov 2010 19:09:34 +0800, "Richard Maher"
    <> wrote, quoted or indirectly quoted
    someone who said :

    >"Well they shouldn't have been doing that
    >anyway" :


    I just use the old Applet tag. Nothing as ugly as <OBJECT deserved to
    live.
    --
    Roedy Green Canadian Mind Products
    http://mindprod.com

    Finding a bug is a sign you were asleep a the switch when coding. Stop debugging, and go back over your code line by line.
     
    Roedy Green, Nov 17, 2010
    #13
  14. Re: Chrome just killed the <OBJECT> tag :-(

    Hi Roedy,

    "Roedy Green" <> wrote in message
    news:...
    > On Thu, 11 Nov 2010 19:09:34 +0800, "Richard Maher"
    > <> wrote, quoted or indirectly quoted
    > someone who said :
    >
    >>"Well they shouldn't have been doing that
    >>anyway" :

    >
    > I just use the old Applet tag.


    Deprecation doesn't bother you then? Yep, you tell 'em where to stick it.

    > Nothing as ugly as <OBJECT deserved to
    > live.


    Look at WebSockets if you really want to see a face only a mother could
    love!

    Anyway, the Chrome problem I referred to has been updated to include a Java
    solution/work-around: -
    For more details see: -
    http://code.google.com/p/chromium/issues/detail?id=62076

    Basically, just stop using the 'classid="java:myClass.class"' and everything
    seems to work pretty well cross-browser.
    > --
    > Roedy Green Canadian Mind Products
    >


    Cheers Richard Maher

    PS. Who looks after LiveConnect NPAPI? Is there a forum or useful
    bug-reporting process? I *desperately* need to know the thread-scheduling
    algorithms for the "round-trip" scenario (among others). Specifically WRT: -
    http://download.oracle.com/javase/6/docs/technotes/guides/jweb/applet/applet_execution.html#threads )

    IMHO it's not just Chrome that is allocating/making-available work to the
    wrong threads :-( Demonstrable!
     
    Richard Maher, Nov 17, 2010
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Anton
    Replies:
    2
    Views:
    720
    Raghupathi K
    Sep 14, 2009
  2. Richard Maher
    Replies:
    0
    Views:
    301
    Richard Maher
    Mar 17, 2010
  3. Richard Maher

    Applet UpCall from JS Event - Which Thread?

    Richard Maher, Mar 17, 2010, in forum: Javascript
    Replies:
    0
    Views:
    120
    Richard Maher
    Mar 17, 2010
  4. Richard Maher

    Chrome bug with Applet and threading

    Richard Maher, May 24, 2012, in forum: Java
    Replies:
    5
    Views:
    279
    Richard Maher
    Jun 3, 2012
  5. wdedalus
    Replies:
    0
    Views:
    614
    wdedalus
    Oct 10, 2012
Loading...

Share This Page