Java Platform, Standard Edition Deployment Guide
Contents    Previous    Next

16 Java and JavaScript

This topic shows how Java and JavaFX applications can be accessed from JavaScript code, and how JavaScript code can be accessed from Java and JavaFX applications.

An application can communicate with the web page in which it is embedded by using a JavaScript engine. The host web page can also communicate to embedded applications using JavaScript.


Note:

To a large extent, this functionality is based on the Java-to-JavaScript communication bridge that is implemented in the Java Plug-in. Therefore, much of the available documentation and examples for Java applets are also applicable to JavaFX applications. For more information about the Java implementation, see the Java LiveConnect documentation.

This topic contains the following sections.

16.1 Accessing an Application from a Web Page

To access a Java or JavaFX application from JavaScript, the first step is to get a reference to a JavaScript object that represents the application. The easiest way to get the reference is to use a standard JavaScript getElementById() function, using the name attribute of the applet tag, as shown in Example 16-1. The <fx:deploy> ant task automatically generates the applet tag, and the name is taken from the id attribute of the <fx:application>.

The result corresponds to the main class of the application.

By getting the reference to a JavaScript object, you can use JavaScript code to access any public methods and fields of a Java object by referencing the Java objects as fields of the corresponding JavaScript object. After you have the app reference, you can do something similar to the following code statement:

var r = app.doSomething()

The implementation of the doSomething() method in Java code returns a Java object. The variable r becomes a reference to the Java object. You can then use code such as r.doSomethingElse() or app.dosomethingWithR(r). For example, Example 16-2 contains Java code, and Example 16-3 contains JavaScript that interacts with that code. Look at both examples to see how they work together.

The JavaScript snippet in Example 16-3 passes several values to the Java code in Example 16-2. Before these values are used in the Java code, they are automatically converted to the closest Java type.

Example 16-3 JavaScript Code for Example 16-2

function navigateTo(cityName) {
    //Assumes that the applet tag uses "myMapApp" as the name for this application
    var mapApp = document.getElementById("myMapApp");
    if (mapApp != null) {
        var city = mapApp.getCity(cityName);
        mapApp.navigateTo(city, mapApp.ZOOM_STREET);
        return mapApp.currentZipCode;
    }
    return "unknown";
}
window.alert("Area zip: " + navigateTo("San Francisco"));

The JavaScript string, numeric, and Boolean objects can be converted into most of the Java primitive typesBoolean, byte, char, short, int, long, float, and doubleand java.lang.String.

For JavaScript objects representing Java objects (in other words, objects that have previously been returned from Java), conversion results in extracting a reference to that Java object.

Conversion into one and multidimensional arrays is supported according to rules similar to rules for conversion of individual objects. If conversion cannot be performed successfully, then the JavaScript engine raises an exception.

All Java objects returned to the web browser are associated with a particular application instance. References held by the JavaScript engine to Java objects act as persistent references, which prevent that Java object from being garbage-collected in the hosting JVM. However, if a particular application is destroyed, for example by leaving the web page hosting the application or by detaching the application from the HTML DOM tree, then references are immediately invalidated and further attempts to use those object in JavaScript raise exceptions.

For more information about data type conversion and object lifetimes, see

http://jdk6.java.net/plugin2/liveconnect/#JS_JAVA_CONVERSIONS


Note:

If a Java object has overloaded methods, which are multiple methods with the same name but different sets of argument types, then the method with the closest types is used. For information, see the Java LiveConnect documentation.

The general recommendation is to avoid overloaded methods if you plan to use them from JavaScript code.


16.2 Accessing the Host Web Page from a Java Applet

See Invoking JavaScript Code From an Applet in the Java Tutorial for information on communication between the applet and host web page.

16.3 Accessing the Host Web Page from an Embedded JavaFX Application

JavaFX applications can call the following JavaScript components:

  • Functions

  • The get, set, and remove fields of JavaScript objects

  • The get and set elements of JavaScript arrays

JavaFX applications can also evaluate JavaScript code. Through the JavaScript DOM APIs, JavaFX applications can modify the web page dynamically by adding, removing and moving HTML elements.

To bootstrap JavaFX-to-JavaScript communication, the JavaFX application must get a reference to the JavaScript window object containing the application. This reference can be used for subsequent operations such as evaluation, function calls, and fetches of variables.

Both the main and preloader application can get this reference by accessing the HostServices class in the JavaFX API and requesting getWebContext(), as shown in Example 16-4.

All instances of JavaScript objects, including references to the DOM window, appear within Java code as instances of netscape.javascript.JSObject.

Example 16-5 shows how to use JavaScript to implement a function to resize an embedded application with id='myMapApp' at runtime.

16.4 Advanced topics

JavaFX applications embedded in a web page can call JavaScript methods in a web page after the init() method is called for the preloader or main application class.

JavaScript code can access Java applications at any time, but if the application is not ready yet, then the request might be blocked until the application is ready. Specifically for JavaFX applications, this happens if the init() method of the main application class has not finished yet and the main application did not perform calls to the web page itself. A JavaScript call from the preloader does not fully unblock JavaScript-to-Java communication.

Most browsers use single-threaded JavaScript engines. When blocking occurs, the host web page and the browser appear to be frozen.

To access an application from the host web page early and avoid blocking, either notify the web page when the application is ready by calling a Java function from the application, or use an onJavascriptReady callback in the Ant task.

Example 16-6 shows an HTML template for an Ant task that uses an onJavascriptReady callback to call the doSomething() method in the main application without blocking the browser.

Example 16-7 shows the relevant part of the Ant task used to generate an HTML page from the template in Example 16-6. For this example, it is assumed that the template has the path src/web/test_template.html.

16.5 Threading

Java code called from JavaScript is executed on a special thread that is not the JavaFX application thread. Use the Platform.runLater() method in the JavaFX code to ensure that something is executed on the JavaFX application thread.

In general, return as quickly as possible from functions that are called from JavaScript. In most modern browsers, JavaScript engines are single-threaded. If the call sticks, then the web page can appear frozen, and the browser is unresponsive. Specifically, avoid writing code that waits for work to be done on a JavaFX application thread. If JavaScript code depends on the result of this work, use a callback from Java to notify the JavaScript code of the result of the execution of the work.

Example 16-8 shows an example of code to avoid in JavaScript.

Example 16-9 shows a better pattern to follow in JavaScript code.

Example 16-9 A Better Implementation of Example 16-8

function process(r) {
    window.alert("Result: "+r);
}
  
myApp.doSomethingLong(function(r) {process(r);});

Example 16-10 shows a better example in Java code.

Java code can call JavaScript from any thread, including the JavaFX application thread. However, if the JavaScript engine in the browser is busy, then a call to JavaScript might stick for some time. If there is a call on the JavaFX application thread, then it might make your application appear frozen, because it is not able to update the screen and handle user events. To avoid this situation, offload execution of LiveConnect calls from the JavaFX application thread.

16.6 Security

JavaScript code on the web page can always make calls to an application on the page. JavaScript code can also access all public methods and fields of Java classes loaded by the application. However, when a JavaScript-to-Java call is made, the call is treated as a call from the sandbox environment. Also, if the HTML document and the application originate from different sites, then JavaScript on the web page cannot cause any network connections to be made on its behalf.

Aside from this restriction, calling Java from JavaScript does not have any other consequences if the application is running in the sandbox. However, if the application has requested elevated permissions, then a call to a Java method from JavaScript is executed in the sandbox without elevated permissions, and a security warning is issued. If elevated permissions are needed, then AccessController.doPrivileged in the Java API can be used to request them in the trusted code.

Be careful not to expose APIs in your applications that would accidentally confer additional privileges on untrusted JavaScript code. If you must grant elevated privileges to JavaScript code, serve your application over verifiable HTTPS connections, and perform checks to ensure that the document base of the web page hosting the application is the same as the expected origin of the application's code.

16.7 Tab Pane Example

This section contains a sample that demonstrates how to use communication between JavaFX and JavaScript to integrate JavaFX web applications with the browser. Example 16-11 shows a JavaFX application that creates a tab pane on a web page, with 20 tabs.

This application can be further improved to save the history of visited tabs into the browser history. This enables users to click the Back and Forward buttons in the browser to move between tabs.

The implementation is based on the onhashchange event introduced in HTML 5 and described at

http://www.whatwg.org/specs/web-apps/current-work/#event-hashchange

The JavaScript technique used by AJAX applications to achieve a similar effect is to save a reference to the current selection in the hash part of the document URL. When the user clicks the Back button, the URL is updated, and a selection state can be extracted that must be restored.

To implement this solution, two new methods are added to the sample: onNavigate() and navigateTo(). The onNavigate() method is called whenever a new tab is selected. This method delivers information about the new selection to the web page by calling the JavaScript method navigateTo() and passing the tab ID to it. The JavaScript code saves the tab ID in the URL hash.

The navigateTo() method is responsible for reverse synchronization. After the web page URL is changed, this method is called with the ID of the tab to be selected.

Example 16-12 shows the updated code of the application. The code that is different from Example 16-11 appears in bold.

Part of the implementation logic is in the HTML page. Example 16-13 shows a page that is used as an input template in an Ant script. When the Ant script is run, it inserts code to embed the JavaFX application next to the custom JavaScript code. For more information about input templates, see <fx:template>.

The implementation of JavaScript functions is straightforward. The onhashchange attribute of the <body> tag is used to subscribe to notifications of updates of the hash part of the URL. After the event is obtained, the JavaFX application is embedded in the web page, and the navigateTo() method is called.

If the application calls with an update on the selected tab, it is saved to the hash part of the URL.

For completeness, Example 16-14 shows the Ant script used to deploy this sample. The application is created with the ID tabbedApp. The JavaScript code uses this ID to find the application on the page. and the HTML template uses it to embed the application into the custom HTML page that is produced by the Ant task.

Contents    Previous    Next

Copyright © 1993, 2017, Oracle and/or its affiliates. All rights reserved.