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

R

Richard Maher

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
 
D

Daniel Pitts

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.
 
M

markspace

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.
 
R

Richard Maher

Hi Mark,

markspace said:
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****************************************
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
 
M

markspace

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.
 
R

Richard Maher

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




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
 
R

Richard Maher

Hi Mark,

markspace said:
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
 
D

Daniel Pitts

Hi Mark,

markspace said:
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.
 
R

Richard Maher

Hi Daniel,

Daniel Pitts said:
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)
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>
 
D

Daniel Pitts

Hi Daniel,

Daniel Pitts said:
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.
 
R

Richard Maher

Daniel Pitts said:
Hi Daniel,

message
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
 
R

Richard Maher

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
 
R

Richard Maher

Hi Roedy,

Roedy Green said:
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.
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!
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top