-
Put jsjbridge.jar in your buildpath and classpath in place of plugin.jar. If using version 1.7 or below, you also need json.jar in your buildpath and classpath.
-
Change imports of
netscape.javascript.*toau.com.advancedcontrols.jsjbridge.*. -
Change mentions of class
ApplettoWebpageHelper. -
Turn your Applet
.jaror.classfile into a runnable JAR that usesWebpageHelperas its main class (or havemainin one of yourWebpageHelperclasses callWebpageHelper.main). -
Strip or comment any Applet graphics code that is causing compile errors. Support for (slow-changing) graphics may be added at some point.
-
You can no longer read from
System.inor write toSystem.out. As a replacement for logging to the Java Console via the standard output, there is aWebpageHelperinstance field callednlog(native log), which is a java.util.logging.Logger. Logging to this object logs to both the standard error stream (which can be redirected to a file, as described below) and the browser console (unless one logs to levelNativeMessagingLogLevel.STDERR_ONLY). The level of these loggers can be set via AppletlogLevelparameters. e.g.
<param name="logLevel" value="FINE" />The default log level is "INFO".
- The LiveConnect JSObject API should be able to be used unchanged, except that the
evalmethod isn't available on the Firefox version (it's considered a security risk), and aJSObject.UNDEFINEDobject is now returned when JavaScript returnsundefined. Also, Java arrays are now passed to JavaScript by value rather than reference. This greatly speeds sending a large amount of data from Java to JavaScript, since there was previously a call to Java for each array access. But it also means that array changes are not automatically propagated back to Java.
-
By default, the JSJBridge browser extension is inactive at all URLs. Go to the JSJBridge extension Preference page in the Extension Manager to set one or more URL prefixes at which the extension becomes active. If you're using Chrome, and your HTML is on the filesystem, remember to enable the "Allow access to file URLs" JavaScript-Java Bridge extension setting.
-
The
applet/objectHTML tags for your Applets can stay the same. JavaScript objects which represent your Applets must obtained viadocument.getElementByIdcalls. It should also be OK when the actualgetElementByIdcalls are being made through a JavaScript library. -
For each Java program (each of which can host more than one
Applet/WebpageHelperclass) you then need to create a Native Messaging manifest file (Firefox, Chrome).The
namefield in each manifest file (and the basename of the.jsonmanifest filename) must be the same as the Appletarchiveparameter, with the.jarsuffix removed, and the JSJBridge extension must be given permission to use it. You will need to create and point manifests to a script that runs your WebpageHelper JAR files viajava -jar myHelper.jar.e.g., for Firefox
{ "name": "<The value of the Applet-element 'archive' parameter without the '.jar' suffix = the basename of original Applet JAR file>", "description": "My Java WebpageHelper", "path": "/path/to/helper_start_script", "type": "stdio", "allowed_extensions": ["jsjbridge@advancedcontrols.com.au"] }It's useful for debugging to have the start-script append standard error output from the program to a log file: e.g.
#!/bin/bash exec java -jar myHelper.jar 2>> /path/to/myJavaProgram.logThen put or link your manifest files in the correct location for your OS (Firefox, Chrome).
-
You can have as many active Applets as you like in and across tabs, and each program can have more than one
WebpageHelperclass, but only one instance of each Java program runs at any one time, meaning that there can only be one active Applet for each combination of program name andWebpageHelperclass. -
The extension makes Applet DOM objects both ususal
HTMLElementobjects, on which you can get and set normal properties, and also objects on which you can access and set Java fields, and call Java methods.The
initializedevent will fire on theapplet/objectelement when its Javainit()method has returned, allowing you to delay work until this has occurred.However, because the extension has to check URL prefixes, it is not guaranteed to be active when the
document.DOMContentLoadedorwindow.loadevents fire, or when inline JavaScript is executed.getElementByIdcalls on Applets will return normalHTMLElements rather than Java proxies before thewindow.jsjbridgeActiveevent fires, so instantiation of these should wait until then:addEventListener('jsjbridgeActive', function() { var myHelper = document.getElementById('myApplet'); myHelper.addEventListener('initialized', function() { ... }); });
The HTML element can still be accessed before the
window.jsjbridgeActiveevent, but it then needs to be reassigned before it can be used to interact with Java:var myHelper = document.getElementById('myApplet'); myHelper.addEventListener('initialized', function() { myHelper = document.getElementById('myApplet'); ... });
-
If an attempt is made to access a nonexisting property of an Applet object, a call to Java is triggered, and the JavaScript expression returns a Promise. The JavaScript execution cycle will continue to execute the code after the Java call before the result is available.
So if you want JavaScript code to do something dependent on a value retrieved from Java, you must either,
(a) Preface your Java-calling expressions with
await, inside an async function (or in a browser console).e.g. Original code
console.log('Vector size is ' + helper.javaVector.size());
must become either
console.log('Vector size is ' + await helper.javaVector.size());
or
async function showSize(javaVector) { console.log('Vector size is ' + await helper.javaVector.size()); } showSize(javaVector);
The
showSizecall will return immediately, but the logging will be executed when the size is returned from Java.If Java calls a JavaScript method that makes a number of
showSizecalls: e.g.function showSizes(vector1, vector2, vector3) { showSize(vector1); showSize(vector2); showSize(vector3); }
The function as written above will return before making any
size()calls to Java, causing the calling Java thread to immediately continue. If you instead wish for Java calls to JavaScript functions to block until the function is fully evaluated, as was the case with the Java Plugin, you need to either,(i), If the sequence of
showSizecalls is important, addawaitto eachshowSizecall:async function showSizes(vector1, vector2, vector3) { await showSize(vector1); await showSize(vector2); await showSize(vector3); }
or (ii), allow the calls to execute in any order, but prevent the function from resolving until all have been completed:
async function showSizes(vector1, vector2, vector3) { await Promise.all([ showSize(vector1), showSize(vector2), showSize(vector3) ]); }
or, equivalently, you can explicity return the Promise:
function showSizes(vector1, vector2, vector3) { return Promise.all([ showSize(vector1), showSize(vector2), showSize(vector3) ]); }
or (b) Instead of using
await, you can put dependent code in athenblock, which can be done at the JavaScript top-level:
helper.javaVector.size().then(size => console.log('Vector size is ' + size));You can also put await in front of a Java field access expression. e.g.
if (await helper.initialized) ...but you can't put await in front of a Java field assignment. To wait for the assignment you need to wait on its value e.g.
var scanner = await helper.scanner;
scanner.enabled = false;
await scanner.enabled;- Expression Chains
Java can be called in an expression chain, which will return a Promise that resolves when the value is available for the chain.
However, while JSJBridge knows whether the first property in a call chain on a Java Object is a field or a method, it cannot know the same for later properties in the chain before that result is available (unless JSJBridge pre-cached information on methods and fields in all Java classes that each program has included, which is not currently done).
So instead of writing
var l = await helper.javaVector.get(0).name.length;one must use a function for all calls in the chain past the first javaVector one, even for JavaScript properties like the last string length one:
var l = await helper.javaVector.get(0).name().length();Such functions don't have to be used if the chain is split:
var v0 = await helper.javaVector.get(0);
var name = await v0.name;
var l = name.length;or, if the Promises are directly handled using then:
var l = await helper.javaVector.get(0).then(v0 => v0.name).then(name => name.length);- JavaScript iterable objects except typed arrays become Java
Objectarrays. Typed arrays become Java primitive arrays of the naturalbyte,short,int,long,float, ordoubletypes. Unsigned typed arrays become the size-equivalent Java signed type, so Java 8+ unsigned methods must be used to get their correct values.