JavaScript not being blocked/synched by Applet init()


R

Richard Maher

Hi,

I'm probably seeing-things again but here goes: -

IE6 with JRE 1.6.0_12 looks to continue the Javascript processing while my
Applet.init() has yet to return. FireFox is fine and when I went for a small
reproducer IE also performed as expected. (Both with Applet appended in a
<div> or document.writeN() as an <object> in the body)

See below for a reasonable code snippet, but the critical bit is this: -

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


If I take out that 'alert("Auth =' bit then isAuthorised() gets called and
returns false even though the user hasn't had a chance to enter their
Username/Password yet. (Pop-up dialog currently sitting on the screen)

I understand when it would be valid to let the JS run past the
getElementById so I normally stick a method call (such as isAuthorized()) in
their to force the block-for-init but this time it doesn't seem to work :-(

For a similar setup please see: -
http://manson.vistech.net/t3$examples/demo_client_flex.html
Username: TIER3_DEMO
Password: QUEUE

All (slightly dated) Java/Javascript/HTML source code is at: -
http://manson.vistech.net/t3$examples/

Unfortunately that example works but the one below doesn't :-(

Anyone know the mechanics behind what Javascript is looking for on IE to
tell it that the Applet has finished init()ing? Or how I might be stomping
on it? (Or at least failing to flag it?)

Cheers Richard Maher


/**
* Copyright (c) Richard Maher. All rights reserved.
*/

function Tier3Client(application,
codeBase,
port,
maxBuf,
hostCharSet,
sslReqd)
{
this.application = application;
this.codeBase = codeBase;
this.port = port;
this.maxBuf = maxBuf;
this.hostCharSet = hostCharSet;
this.sslReqd = sslReqd;

var appletId = "Tier3__" + application + "_Applet";

try {
var idTaken = document.getElementById(appletId);
}
catch (err) {};

if (idTaken != null) {
throw new Error("Tier3 Client already registered for " +
this.application);
return;
}

var archiveName = "tier3Client.jar";
var className = "tier3Client/Tier3Application";

var appletParams = [{"name":"archive", "value":archiveName},
{"name":"codebase", "value":codeBase },
{"name":"code", "value":className },
{"name":"mayscript", "value":"true" },
{"name":"scriptable", "value":"true" },
{"name":"APPLICATION", "value":application},
{"name":"PORT", "value":port },
{"name":"MAXBUF", "value":maxBuf },
{"name":"HOSTCHARSET", "value":hostCharSet},
{"name":"SSLREQD", "value":sslReqd }];
var startParam = 0;

var objectTag = "<object classid=";

if (/Internet Explorer/.test(navigator.appName)) {
objectTag = objectTag +
'"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
} else {
objectTag = objectTag +
'"java:' + className + '.class" type="application/x-java-applet
" ' +
'archive="' + codeBase + archiveName + '"';
startParam = 1;
}

objectTag = objectTag + ' width= "0" height= "0" id="' + appletId +
'">';

for (i=startParam; i<appletParams.length; i++){
objectTag = objectTag + '<param name ="' + appletParams.name +
'" ' +
'value ="' + appletParams.value +
'">';
}

objectTag = objectTag + "</object>";

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

var tier3Chan;
try {
document.body.appendChild(appletDiv);
tier3Chan = document.getElementById(appletId);
alert("Auth = " + tier3Chan.getThree());
var userAuthorized = tier3Chan.isAuthorized();
}
catch(err) {
alert("Err =" + err.description);
tier3Chan = null;
};
alert("After check");
if (tier3Chan == null) {
throw new Error("Tier3 was unable to initialize the applet for " +
this.application);
return;
} else {
if (!userAuthorized) {
throw new Error("Tier3 User authentication unsuccessful for " +
this.application);
return;
}
}

this.chan = tier3Chan;

Tier3Client.applications[this.application] = this;

return this;
}
 
Ad

Advertisements

R

Richard Maher

(Shameless bump.)

Just in case you were on school holidays and missed the opportunity to solve
this conundrum, here it is again :)

Cheers Richard Maher

Richard Maher said:
Hi,

I'm probably seeing-things again but here goes: -

IE6 with JRE 1.6.0_12 looks to continue the Javascript processing while my
Applet.init() has yet to return. FireFox is fine and when I went for a small
reproducer IE also performed as expected. (Both with Applet appended in a
<div> or document.writeN() as an <object> in the body)

See below for a reasonable code snippet, but the critical bit is this: -

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


If I take out that 'alert("Auth =' bit then isAuthorised() gets called and
returns false even though the user hasn't had a chance to enter their
Username/Password yet. (Pop-up dialog currently sitting on the screen)

I understand when it would be valid to let the JS run past the
getElementById so I normally stick a method call (such as isAuthorized()) in
their to force the block-for-init but this time it doesn't seem to work :-(

For a similar setup please see: -
http://manson.vistech.net/t3$examples/demo_client_flex.html
Username: TIER3_DEMO
Password: QUEUE

All (slightly dated) Java/Javascript/HTML source code is at: -
http://manson.vistech.net/t3$examples/

Unfortunately that example works but the one below doesn't :-(

Anyone know the mechanics behind what Javascript is looking for on IE to
tell it that the Applet has finished init()ing? Or how I might be stomping
on it? (Or at least failing to flag it?)

Cheers Richard Maher


/**
* Copyright (c) Richard Maher. All rights reserved.
*/

function Tier3Client(application,
codeBase,
port,
maxBuf,
hostCharSet,
sslReqd)
{
this.application = application;
this.codeBase = codeBase;
this.port = port;
this.maxBuf = maxBuf;
this.hostCharSet = hostCharSet;
this.sslReqd = sslReqd;

var appletId = "Tier3__" + application + "_Applet";

try {
var idTaken = document.getElementById(appletId);
}
catch (err) {};

if (idTaken != null) {
throw new Error("Tier3 Client already registered for " +
this.application);
return;
}

var archiveName = "tier3Client.jar";
var className = "tier3Client/Tier3Application";

var appletParams = [{"name":"archive", "value":archiveName},
{"name":"codebase", "value":codeBase },
{"name":"code", "value":className },
{"name":"mayscript", "value":"true" },
{"name":"scriptable", "value":"true" },
{"name":"APPLICATION", "value":application},
{"name":"PORT", "value":port },
{"name":"MAXBUF", "value":maxBuf },
{"name":"HOSTCHARSET", "value":hostCharSet},
{"name":"SSLREQD", "value":sslReqd }];
var startParam = 0;

var objectTag = "<object classid=";

if (/Internet Explorer/.test(navigator.appName)) {
objectTag = objectTag +
'"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
} else {
objectTag = objectTag +
'"java:' + className + '.class" type="application/x-java-applet
" ' +
'archive="' + codeBase + archiveName + '"';
startParam = 1;
}

objectTag = objectTag + ' width= "0" height= "0" id="' + appletId +
'">';

for (i=startParam; i<appletParams.length; i++){
objectTag = objectTag + '<param name ="' + appletParams.name +
'" ' +
'value ="' + appletParams.value +
'">';
}

objectTag = objectTag + "</object>";

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

var tier3Chan;
try {
document.body.appendChild(appletDiv);
tier3Chan = document.getElementById(appletId);
alert("Auth = " + tier3Chan.getThree());
var userAuthorized = tier3Chan.isAuthorized();
}
catch(err) {
alert("Err =" + err.description);
tier3Chan = null;
};
alert("After check");
if (tier3Chan == null) {
throw new Error("Tier3 was unable to initialize the applet for " +
this.application);
return;
} else {
if (!userAuthorized) {
throw new Error("Tier3 User authentication unsuccessful for " +
this.application);
return;
}
}

this.chan = tier3Chan;

Tier3Client.applications[this.application] = this;

return this;
}
 
R

Richard Maher

Hi,

I've come up with a small reproducer (see below) that I hope will help
someone sched light on what's going on. (Also a related SDN Bug ID 6742814
may be of some help: -
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6742814 )

In a nutshell with IE6 the Javascript resumes as soon as the init() method
has called JSObject.getWindow(this) but *before* the init() method has
completed/returned, as can be evidenced from the getNum() results. (Nice
trick!) Try it on FireFox to see the difference.

Is this a new bug that was introduced when trying to fix a "freeze" with
JSObject.Call()? If not, how is one ever supposed to synchronize the
completion of Applet initialization? "Callbacks" a la mode de Adobe
FABridge?

I'll do some more testing with other browsers/versions but surely this can't
be right? Possibly fixed in a later version of IE, JRE, or LiveConnect?

Cheers Richard Maher

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

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

public class Sleeper extends Applet {
private int myNum = 0;
private JSObject browser;

public void init() {
try {
browser = JSObject.getWindow(this); }
catch (netscape.javascript.JSException e) {
e.printStackTrace(); }
catch (Exception e) {
e.printStackTrace(); }

System.out.println("Before sleep call");
try {
Thread.sleep(5000);
}
catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("After sleep call");
myNum = 33;
}

public int getNum(){
int i = myNum++;
System.out.println("in getNum " + myNum);
return i;
}

}

Sleeper.html
=========


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

<html>

<meta name="author" content="Richard Maher"/>
<meta name="description" content="JS Function and Applet Test"/>

<head>


<style>

body
{
margin: 0px;
background-color: white;
color: Black;
font-family: times;
font-size: 16px;
border: medium ridge;
}

</style>

<script type="text/javascript">

function load() {
var lclNum;
var chan;
try {
chan = document.getElementById("Sleeper");
lclNum = chan.getNum();
lclNum = chan.getNum();
lclNum = chan.getNum();
}
catch (err) {
alert("In catch " + err.description);
}
if (chan == null) alert("chan is null");
alert(chan.getNum());
}

</script>

</head>

<body onload="load();">

<br /><h2>Test it</h2><hr /><br />

<form name="display" style="margin-left: 100px;">

<input
type="text"
style="text-align: Left;"
name="next"
size=10
/>
</form>

<script type="text/javascript">

var myDef;
if (navigator.appName == "Microsoft Internet Explorer")
myDef =
'<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ' +
'width= "0" height= "0" id="Sleeper">'
+
'<param name="code" value="Sleeper">'
+
'<param name="mayscript" value="true">' +
'<param name="scriptable" value="true">' +
'</object>'
else
myDef =
'<object classid="java:Sleeper.class" '
+
'type="application/x-java-applet" ' +
'width= "0" height= "0" id="Sleeper">'
+
'<param name="code" value="Sleeper">'
+
'<param name="mayscript" value="true">' +
'<param name="scriptable" value="true">' +
'</object>'

document.write(myDef);
</script>

</body>

</html>

Richard Maher said:
Hi,

I'm probably seeing-things again but here goes: -

IE6 with JRE 1.6.0_12 looks to continue the Javascript processing while my
Applet.init() has yet to return. FireFox is fine and when I went for a small
reproducer IE also performed as expected. (Both with Applet appended in a
<div> or document.writeN() as an <object> in the body)

See below for a reasonable code snippet, but the critical bit is this: -

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


If I take out that 'alert("Auth =' bit then isAuthorised() gets called and
returns false even though the user hasn't had a chance to enter their
Username/Password yet. (Pop-up dialog currently sitting on the screen)

I understand when it would be valid to let the JS run past the
getElementById so I normally stick a method call (such as isAuthorized()) in
their to force the block-for-init but this time it doesn't seem to work :-(

For a similar setup please see: -
http://manson.vistech.net/t3$examples/demo_client_flex.html
Username: TIER3_DEMO
Password: QUEUE

All (slightly dated) Java/Javascript/HTML source code is at: -
http://manson.vistech.net/t3$examples/

Unfortunately that example works but the one below doesn't :-(

Anyone know the mechanics behind what Javascript is looking for on IE to
tell it that the Applet has finished init()ing? Or how I might be stomping
on it? (Or at least failing to flag it?)

Cheers Richard Maher


/**
* Copyright (c) Richard Maher. All rights reserved.
*/

function Tier3Client(application,
codeBase,
port,
maxBuf,
hostCharSet,
sslReqd)
{
this.application = application;
this.codeBase = codeBase;
this.port = port;
this.maxBuf = maxBuf;
this.hostCharSet = hostCharSet;
this.sslReqd = sslReqd;

var appletId = "Tier3__" + application + "_Applet";

try {
var idTaken = document.getElementById(appletId);
}
catch (err) {};

if (idTaken != null) {
throw new Error("Tier3 Client already registered for " +
this.application);
return;
}

var archiveName = "tier3Client.jar";
var className = "tier3Client/Tier3Application";

var appletParams = [{"name":"archive", "value":archiveName},
{"name":"codebase", "value":codeBase },
{"name":"code", "value":className },
{"name":"mayscript", "value":"true" },
{"name":"scriptable", "value":"true" },
{"name":"APPLICATION", "value":application},
{"name":"PORT", "value":port },
{"name":"MAXBUF", "value":maxBuf },
{"name":"HOSTCHARSET", "value":hostCharSet},
{"name":"SSLREQD", "value":sslReqd }];
var startParam = 0;

var objectTag = "<object classid=";

if (/Internet Explorer/.test(navigator.appName)) {
objectTag = objectTag +
'"clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ';
} else {
objectTag = objectTag +
'"java:' + className + '.class" type="application/x-java-applet
" ' +
'archive="' + codeBase + archiveName + '"';
startParam = 1;
}

objectTag = objectTag + ' width= "0" height= "0" id="' + appletId +
'">';

for (i=startParam; i<appletParams.length; i++){
objectTag = objectTag + '<param name ="' + appletParams.name +
'" ' +
'value ="' + appletParams.value +
'">';
}

objectTag = objectTag + "</object>";

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

var tier3Chan;
try {
document.body.appendChild(appletDiv);
tier3Chan = document.getElementById(appletId);
alert("Auth = " + tier3Chan.getThree());
var userAuthorized = tier3Chan.isAuthorized();
}
catch(err) {
alert("Err =" + err.description);
tier3Chan = null;
};
alert("After check");
if (tier3Chan == null) {
throw new Error("Tier3 was unable to initialize the applet for " +
this.application);
return;
} else {
if (!userAuthorized) {
throw new Error("Tier3 User authentication unsuccessful for " +
this.application);
return;
}
}

this.chan = tier3Chan;

Tier3Client.applications[this.application] = this;

return this;
}
 
M

Mark Space

Richard said:
trick!) Try it on FireFox to see the difference.

I get the same thing in both IE and FF. I see Test it, a horizontal
rule and a blank form field.

I did redo the program with a lot of scratch work. What am I supposed to
see?
 
R

Richard Maher

Mark Space said:
I get the same thing in both IE and FF. I see Test it, a horizontal
rule and a blank form field.

I did redo the program with a lot of scratch work. What am I supposed to
see?

On Firefox 2 the "alert(chan.getNum())" should result in the number "36" in
the alert box, and the Java Console would contain: -

Before sleep call
After sleep call
in getNum 34
in getNum 35
in getNum 36
in getNum 37

While over on IE6 the alert box would contain the number "3" and the Java
Console would contain: -

in getNum 1
in getNum 2
in getNum 3
in getNum 4
Before sleep call
After sleep call

If you're not seeing this then please let me know what versions of IE and
JRE you're using. If you are seeing the above then try removing the call to
JSObject.getWindow(this) to restore sanity.

Regards Richard Maher
 
M

Mark Space

Richard said:
On Firefox 2 the "alert(chan.getNum())" should result in the number "36" in
the alert box, and the Java Console would contain: -
If you're not seeing this then please let me know what versions of IE and
JRE you're using. If you are seeing the above then try removing the call to
JSObject.getWindow(this) to restore sanity.


Thanks for verifying. On both IE 8 and FF 3 I see a pop-up with the
number 3. So I think IE 7 is correct and FF 2 is the buggy one.

The solution is obvious and you mentioned it yourself. Synchronize the
access of init and getNum. Just add the key word "synchronized" to both
method declarations and both IE and FF display 36. I tested this in IE
8 and FF 3, works fine.
 
Ad

Advertisements

R

Richard Maher

Hi Mark,

Mark Space said:
Thanks for verifying. On both IE 8 and FF 3 I see a pop-up with the
number 3. So I think IE 7 is correct and FF 2 is the buggy one.

Upon re-reading that bug report I quoted, I've come to the conclusion that
(for whatever compelling reasons) it was a deliberate break of
upward-compatibility and the laws of browser-physics as we knew them
pre-Java6. (Java 1.4 and I'm guessing 5 behave "as expected" with IE6)

A couple of relevant-sounding quotes from that bug report from Sept last
year: -
{
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.
}

So it appears that through the wonders of Java6 we now have your init()
method and your JavaScript executing in parallel (presumably in seperate
threads), but *only* if you're doing something with JSObject. And for the
squeamish among us that like our initialization to finish before the
mainline methods start crunching numbers, there's now a need for
intervention.

I do glance through the JRE release notes when they come out but can't
recall seeing this one; anyone else?
The solution is obvious and you mentioned it yourself. Synchronize the
access of init and getNum. Just add the key word "synchronized" to both
method declarations and both IE and FF display 36. I tested this in IE
8 and FF 3, works fine.

Well it's certainly obvious now that you've told me :) Thanks for the
answer and thanks for trying it out on the other browsers for me. I had
finer-grained synchronization blocks in my methods but your solution is
simple and, what's far more important, effective.

Thanks again.

Cheers Richard Maher

PS. Anyone got a link to this "forthcoming new LiveConnect specification"?
 
M

Mark Space

Richard said:
> >
>
> I found this think for those who will also be looking. (I found the bug
> report to be less ambiguous in its terminology, but anyway here's the rules)
>
> https://jdk6.dev.java.net/plugin2/liveconnect/
>


While direct from Sun, I'm pretty sure it's incorrect:

"The JavaScript engines in all of today's web browsers are conceptually
single threaded with respect to the web page. The Java language,
however, is inherently multithreaded. If multiple Java threads attempt
to call into the JavaScript engine, only one will be allowed through at
any given time. The rest of the threads will wait for one of two
situations to occur: either the initial Java-to-JavaScript call
completes, or a JavaScript-to-Java call is made. In either of these
occurrences, the JavaScript engine once again becomes "available" for
Java-to-JavaScript calls. If multiple Java threads were attempting to
make concurrent calls to the JavaScript engine, an arbitrary one will be
selected for its call to proceed."


JavaScript IS NOT single threaded. It can receive events from outside
sources (hello XMLHttpRequest) and will spawn additional threads of
execution. Since there's no synchronization method in JavaScript, this
can be a huge hassle. There's an algorithm available to synchronize
threads using only shared memory. Read on:


<http://www.developer.com/lang/jscript/article.php/3592016>


Anyway, with regard to Java, I think the best policy is to assume your
JApplet is being accessed in a multithreaded environment and program
defensively. I'd make all methods visible to JavaScript "synchronized",
including redefining all JApplet methods just to make them synchronized.

(I refuse to redefine the entire JComponent hierarchy, which is huge.
This is one instance where one must just pray that these methods are
never invoked. I don't think there's any way to synchronize a parent
classes methods. Although if you know a specific method will be call
(setSize() is common) synchronize that.)
 
J

Joshua Cranmer

Mark said:
JavaScript IS NOT single threaded. It can receive events from outside
sources (hello XMLHttpRequest) and will spawn additional threads of
execution. Since there's no synchronization method in JavaScript, this
can be a huge hassle. There's an algorithm available to synchronize
threads using only shared memory. Read on:

I believe that, in the case of XMLHttpRequest, in Mozilla, everything is
proxied back to the display thread. The definition of XMLHttpRequest
also appears to not be thread-safe, which means that using the object
from multiple threads is more or less A Bad Thing™.

Although the SpiderMonkey engine is very much capable of doing
multithreaded execution, the DOM itself is not threadsafe and has to be
modified from a single thread, so must browser JS ends up running in one
thread. Hence the statement: "The JavaScript engines in all of today's
web browsers are conceptually single threaded with respect to the web page."

Yes, I am aware of DOM workers, but these do not allow concurrent access
to the DOM:
"The DOM APIs (Node objects, Document objects, etc) are not available
to workers in this version of this specification."
<http://www.whatwg.org/specs/web-workers/current-work/>.
 
M

Mark Space

Joshua said:
Although the SpiderMonkey engine is very much capable of doing
multithreaded execution, the DOM itself is not threadsafe and has to be
modified from a single thread, so must browser JS ends up running in one
thread. Hence the statement: "The JavaScript engines in all of today's
web browsers are conceptually single threaded with respect to the web
page."


And Richard Maher was able to create concurrent access to his Java
applet pretty much by accident. I don't think I really believe the
documentation in this regard. The synchronization to make JavaScript
single thread seems buggy at best, non-existent at worse. And this is
from both IE and FF.
 
Ad

Advertisements

R

Richard Maher

Hi Mark,

Mark Space said:
And Richard Maher was able to create concurrent access to his Java
applet pretty much by accident.

I may have come across it by accident (and I think the goodness of
upward-compatibility dictates that the "old" behaviour should've been the
default - along the lines of the new classloader_cache parameter) but it
appears to have been definitely implemented on purpose. "Who uses the
functionality and why?" - I know not.
I don't think I really believe the
documentation in this regard.

If anyone can show me two JavaScript functions serving events simultaneously
in the same browser-tab then I'd sure like to see it! (Or at least know
about it) onreadystatechange, onclick, mouseover, whatever - it can't be
done.

Or so I thought, at least prior to Java 6. I just stuck a
JSObject.getWindow(this).call("someFunc",null) into my Applet.init() -
without the "synchronized" - and it looks very muh to me that the JavaScript
onload event and someFunc are executing in parallel :-o
The synchronization to make JavaScript
single thread seems buggy at best, non-existent at worse. And this is
from both IE and FF.

I'd disagree with you prior to Java 6, but as someone who will be
manipulating the DOM from JSObject.call()s in a separate Java thread in my
Applet, I am more than a tad concerned about developments.

Cheers Richard Maher
 
R

Richard Maher

Hi Again,

Richard Maher said:
Hi Mark,



I may have come across it by accident (and I think the goodness of
upward-compatibility dictates that the "old" behaviour should've been the
default - along the lines of the new classloader_cache parameter) but it
appears to have been definitely implemented on purpose. "Who uses the
functionality and why?" - I know not.


If anyone can show me two JavaScript functions serving events simultaneously
in the same browser-tab then I'd sure like to see it! (Or at least know
about it) onreadystatechange, onclick, mouseover, whatever - it can't be
done.

Or so I thought, at least prior to Java 6. I just stuck a
JSObject.getWindow(this).call("someFunc",null) into my Applet.init() -
without the "synchronized" - and it looks very muh to me that the JavaScript
onload event and someFunc are executing in parallel :-o


I'd disagree with you prior to Java 6, but as someone who will be
manipulating the DOM from JSObject.call()s in a separate Java thread in my
Applet, I am more than a tad concerned about developments.

In case it helps the discussion any, below is a modified version of my
earlier example that certainly appears to show two JavaScripr functions
executing in parallel. (The DOM "value" of the html field "next" ends up
"132" instead of "123")

Ok, "moving forward" can anyone show me similar behaviour outside of the
Applet.init()-JSObject interaction environment? (The work-around, as Mark
suggested, being to stick "synchronized" on the applet methods and call-back
onto the Applet as soon as possible to synch with the return from init() )

Are all JSObject.call()s prone to threading issues rather than all being
queued to the EDT? This'd be disaterous - please advise!

Would a further setTimer(0,"pleaseFireMeOnEDT()") work-around mechanism be
required?
Cheers Richard Maher

Console output
============
Before fromInit call
in getNum 1
in getNum 2
in getNum 3
in getNum 4
After fromInit call
Before sleep call
After sleep call

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

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

public class Sleeper extends Applet {
private int myNum = 0;
private JSObject browser;

public void init() {
super.init();
try {
browser = JSObject.getWindow(this); }
catch (netscape.javascript.JSException e) {
e.printStackTrace(); }
catch (Exception e) {
e.printStackTrace(); }

System.out.println("Before fromInit call");
browser.call("fromInit", null);
System.out.println("After fromInit call");

System.out.println("Before sleep call");
try {
Thread.sleep(5000);
}
catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("After sleep call");
myNum = 33;
}

public int getNum(){
int i = myNum++;
System.out.println("in getNum " + myNum);
return i;
}

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

sleeper.html
=========

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

<html>

<meta name="author" content="Richard Maher"/>
<meta name="description" content="JS Function and Applet Test"/>

<head>


<style>

body
{
margin: 0px;
background-color: white;
color: Black;
font-family: times;
font-size: 16px;
border: medium ridge;
}

</style>

<script type="text/javascript">
var tmp;

function load() {
var lclNum;
var chan;
tmp ="Stage 1";
document.display.next.value = "1";
try {
chan = document.getElementById("Sleeper");
lclNum = chan.getNum();
lclNum = chan.getNum();
lclNum = chan.getNum();
}
catch (err) {
alert("In catch " + err.description);
}
if (chan == null) alert("chan is null");
alert(chan.getNum() + " tmp = " + tmp);
document.display.next.value += "2";
alert("onLoad tmp was " + tmp);
tmp ="Stage 3";
}

function fromInit(){
document.display.next.value += "3";
var oldTmp = tmp;
tmp = "Stage 2";
alert("fromInit tmp = "+tmp+" oldTmp = "+oldTmp);
}

</script>

</head>

<body onload="load();">

<br /><h2>Test it</h2><hr /><br />

<form name="display" style="margin-left: 100px;">

<input
type="text"
style="text-align: Left;"
name="next"
size=10
/>
</form>

<script type="text/javascript">

var myDef;
if (navigator.appName == "Microsoft Internet Explorer")
myDef =
'<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" ' +
'width= "0" height= "0" id="Sleeper">'
+
'<param name="code" value="Sleeper">'
+
'<param name="mayscript" value="true">' +
'<param name="scriptable" value="true">' +
'</object>'
else
myDef =
'<object classid="java:Sleeper.class" '
+
'type="application/x-java-applet" ' +
'width= "0" height= "0" id="Sleeper">'
+
'<param name="code" value="Sleeper">'
+
'<param name="mayscript" value="true">' +
'<param name="scriptable" value="true">' +
'</object>'

document.write(myDef);
</script>

</body>

</html>
 
L

Lew

Mark said:
Anyway, with regard to Java, I think the best policy is to assume your
JApplet is being accessed in a multithreaded environment and program
defensively. I'd make all methods visible to JavaScript "synchronized",
including redefining all JApplet methods just to make them synchronized.

Side note: Any shared state that is protected by synchronization via some
critical sections (e.g., a setter method) must be protected by synchronization
for all accesses (e.g., a getter method). The memory model must be served;
partial protection is just as bad as no protection at all.

Synchronization can be achieved by means other than the 'synchronized'
keyword, of course.
 
Ad

Advertisements

M

Mark Space

Lew said:
Side note: Any shared state that is protected by synchronization via
some critical sections (e.g., a setter method) must be protected by
synchronization for all accesses


It appears that JavaScript is single-threaded, or tries to be. I did
find one Opera developer who admitted that their implementation wasn't
really.

I think he's getting called in response to multiple threads from the
JVM, probably (?) in response to JavaScript events, which DO run
asynchronously with the Java applet. Hence the need for multi-thread
support.

I'm not 100% sure about that, but I think it makes sense. Just a little
note for everyone if you ever have to write an applet.
 

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

Top