Now that we've discussed the JavaScript data types used by LiveConnect, and the data conversions that go on when JavaScript reads and writes Java data values, we can begin to discuss some of the practical applications of LiveConnect. Bear in mind, while reading this section, that we have still only discussed half of LiveConnect--the half that allows JavaScript to work with Java. The portions of LiveConnect that allow a Java applet to use JavaScript will be documented later.
All of the LiveConnect examples presented so far in this chapter have made use of Java classes from the standard Java libraries from Sun. There is not a whole lot of interesting things you can do with an instance of java.ang.Double, but we have seen some interesting uses of the java.lang.System class, for example.
LiveConnect gives us the capability to create new instances of Java classes, to set and query fields of classes and their instances, and to invoke methods of classes or instances. Using these capabilities, there are some interesting things we can do with the "built-in" or "system" classes that are installed with Navigator. Note also, that there are some things that we cannot do. LiveConnect does not give us the capability to define new Java classes or subclasses from within JavaScript, nor does it give us the ability to create Java arrays. Also, the things we can do with the standard Java classes are restricted for security reasons. A JavaScript program cannot use the java.io.File class, for example, because that would give it the power to read, write, and delete files on the host system--exactly the capabilities needed for Internet "viruses". Because of security issues like this one, JavaScript can use Java only in those ways that untrusted applets can.
Example 19.1 shows JavaScript code that uses standard Java classes (the JavaScript code looks almost identical to Java code, in fact) to pop up a window and display some text. The results are shown in Figure 19.4.
var f = new java.awt.Frame("Hello World"); var ta = new java.awt.TextArea("hello, world", 5, 20); f.add("Center", ta); f.pack(); f.show();
Example 19.1 shows how it is possible to use JavaScript to create simple Java user interfaces. But while this technique of creating and popping up a Java window from JavaScript seems like it could lead to much more complex examples of Java user interfaces and graphics drawn from JavaScript, it is not actually so easy. LiveConnect allows us only to call methods in classes and objects. It does not define any way to subclass Java objects or define Java methods, and both of these techniques are required in Java to be able to handle events (such as button presses). Thus, in general, you can only use JavaScript to create static Java programs, not Java programs that interact with a user. This may change in the future, however--both the JDK 1.1 version of the AWT user-interface library from Sun and the Internet Foundation Classes (IFC) library from Netscape make it easier to define event handlers, and may make it possible to connect Java user-interfaces to JavaScript functions that handle user interaction.
We saw in Chapter 14, Documents and Their Contents, that the Document object has an applets[] property which is an array containing JavaObject objects, one for each Java applet in the document. The JavaObject objects in this array represent the Java object of each applet--this will always be an instance of some subclass java.applet.Applet. Because LiveConnect exposes the Java object for each applet on a web page, you can freely read and write public fields of the applet and just as freely invoke public methods of the applet.
Example 19.2 shows some simple HTML that embeds an applet in a web page and includes buttons that start and stop the applet by using LiveConnect to invoke the applet's start() and stop() methods.
<!-- Here's the applet --> <APPLET NAME="animation" CODE="Animation.class" WIDTH=500 HEIGHT=200> </APPLET> <!-- And here are the buttons that start and stop it. --> <FORM> <INPUT TYPE=button VALUE="Start" onclick="document.animation.start()"> <INPUT TYPE=button VALUE="Stop" onclick="document.animation.stop()"> </FORM>
There are a couple of points to note about this example. First, the <APPLET> tag is given a NAME attribute, and the value of that attribute becomes the name of a property in the document object. We've seen this technique before with the <FORM> and <IMG> tags; in this case it allows us to refer to applets by names such as document.animation instead of numbers such as document.applets[0].
The second point to note about this example is that it calls the start() and stop() methods of the applet--these are standard methods that all applets define; they are the methods that the browser itself calls to start and stop the applet. But you needn't stop at calling the standard methods of the Java Applet class. If your applet defines other methods of its own, you can call any of these as well.[3] If you were working with a full-featured animation applet, for example, you might define an HTML form to serve as a complete control panel for the animation, with Fast-Forward and Reverse buttons, an input field for specifying speed, and so on. The buttons in this control panel could then control the applet by invoking special-purpose methods, such as fast_forward(), provided by the applet.
[3] In fact, it is safer and more portable to call your own custom methods than to call those that are intended to be called by the browser.
Another possibility to bear in mind is that you can write passive applets that take no action on their own, but exist simply to serve your JavaScript code. An applet might define various utility functions for popping up dialog boxes that are more complex than those provided by the alert(), confirm(), and prompt() methods, for example.
Just as the applets[] array of the Document object contains JavaObjects that represent the applets embedded in a document with the <APPLET> tag, the embeds[] array of the Document object contains JavaObjects that represent data embedded in a web page with the <EMBED> tag. This is data that is intended to be displayed by a Navigator plug-in. Do not confuse the Document.embeds[] array with the Navigator.plug-ins[] array. The first contains objects that represent a single piece of embedded data, and the second contains Plugin objects that represent the actual plug-ins that are installed in Navigator to display embedded data.
The JavaObject objects in the embeds[] array are all instances of some subclass of the netscape.plugin.Plugin class. Each Java-enabled plug-in defines its own subclass of netscape.plugin.Plugin, and creates an instance of that subclass for each piece of embedded data (each <EMBED> tag) that it displays. The purpose of these netscape.plugin.Plugin subclasses is to define an API through which Java applets and JavaScript programs can control the behavior of a plug-in, or of a particular instance of a plug-in.
Because the objects in the embeds[] array are provided by plug-ins, the properties and methods of any of these objects will depend on the particular plug-in in use. In general, you'll have to read the vendor's documentation for any given plug-in to determine how to control it through LiveConnect. If the plug-in that is displaying the data is not Java-enabled, then the corresponding object in the embeds[] array will be a JavaObject that represents a dummy Java object with no functionality.
Example 19.3 shows how you might use the LiveAudio plug-in (bundled with Navigator 3.0 on most platforms) and LiveConnect to automatically play a sound when the user clicks a button and when the mouse passes over a hyperlink. The example relies upon the play() method of the netscape.plugin.Plugin instance provided by the LiveAudio plug-in. This method, and many others, are detailed by Netscape in their LiveAudio documentation.
<!-- Here we embed some sounds in the browser, with attributes to --> <!-- specify that they won't be played when first loaded. In this --> <!-- example, we use sounds found locally on Windows 95 platforms. --> <EMBED SRC="file:///C|/windows/media/Tada.wav" HIDDEN=true AUTOSTART=false> <EMBED SRC="file:///C|/windows/media/Ding.wav" HIDDEN=true AUTOSTART=false> <EMBED SRC="file:///C|/windows/media/The Microsoft Sound.wav" HIDDEN=true AUTOSTART=false> <!-- Here are some buttons that play those sounds. Note the use of the --> <!-- embeds[] array and the play() method invoked through LiveConnect. --> <FORM> <INPUT TYPE=button VALUE="Play Sound #1" onClick="document.embeds[0].play()"> <INPUT TYPE=button VALUE="Play Sound #2" onClick="document.embeds[1].play()"> <INPUT TYPE=button VALUE="Play Sound #3" onClick="document.embeds[2].play()"> </FORM> <!-- Here's a hypertext link that plays a sound when the user passes over --> <A HREF="" onMouseOver="document.embeds[0].play()">Click Me</A>
Although the objects in the embeds[] array are all instances of subclasses of netscape.plugin.Plugin, there is one method that all subclasses share which you may find useful in your JavaScript code. The isActive() method returns true if the specified Plugin object is still active and false if it is not. Generally, a plug-in will only become inactive if it was on a page that is no longer displayed. This situation can only arise when you store references to the embeds[] array of one window in JavaScript variables of another window.