Applet development with JavaFX Script and Java SE 6u10 Jeff Friesen puts the newer, faster applet to the test in this companion to his JavaWorld feature: “Are applets making a comeback?” Here you can get a short introduction to rich Internet applet development using JavaFX Script and key features of Java SE 6 update 10, including the Java Deployment Toolkit , Java Quick Starter, and the Java Kernel.The historic problems of applets have been well-documented and we’ve looked in-depth at some of the efforts currently underway to revitalize them for a new generation of Java Web developers (see this article’s companion “Are applets making a comeback?”). Still, it remains to be seen if the new technologies clustering under the umbrella of Java SE 6 update 10 beta (Java SE 6u10) are enough to improve applet performance and create a Java browser and desktop experience capable of competing with Flex and Silverlight.In this short companion to my investigation of the possible applet comeback, I take a more hands-on approach to understanding the viability of Sun’s efforts in the rich internet space, using JavaFX Script and Java SE 6u10 to create my own “rich Internet applet.” As I think you’ll learn by following this short development exercise with me, JavaFX Scrip and Java SE 6 update 10 do indeed make applet development and deployment a much better experience than the one many of us remember from the early days of Java. Note that this exercise in applet development is based on a Windows XP platform environment.Building a rich Internet appletIn my JavaWorld article “Ajax programming with the Java Scripting API,” I presented a small Java application that utilizes the Java Scripting API and a pair of JavaScript-based scripts to obtain an RSS document, which contains weather data (from Yahoo! Weather) corresponding to a user-entered zip code. After parsing out the data, the application presents this data to the user.For the purpose of learning, I’ve converted this rich Internet application (RIA) to an equivalent applet. Instead of writing the applet in Java, I wrote it using JavaFX Script (the compiled version of the language, whose syntax differs from the interpreted version), blending Java code with JavaFX Script’s simplifying declarative syntax and convenient binding capability. As Listing 1 testifies, the JavaFX Script approach results in much less code to write, especially for the user interface. Listing 1 Weather.fx// Weather.fx import java.lang.StringBuilder; import javafx.ui.Applet; import javafx.ui.BorderPanel; import javafx.ui.Canvas; import javafx.ui.Color; import javafx.ui.CompoundBorder; import javafx.ui.EmptyBorder; import javafx.ui.EtchedBorder; import javafx.ui.FlowPanel; import javafx.ui.Image; import javafx.ui.Label; import javafx.ui.SimpleLabel; import javafx.ui.StackPanel; import javafx.ui.TextField; import javafx.ui.canvas.ImageView; import javafx.xml.Document; import javafx.xml.DocumentBuilder; import javafx.xml.Element; class WeatherModel { private attribute weatherFeedURIBase = "http://weather.yahooapis.com/forecastrss?p="; private attribute docBuilder = DocumentBuilder { namespaceAware: true validating: true ignoringComments: false }; attribute labelHTML: String; function getRSSDocument (value: String): Void { var document = docBuilder.parseURI (weatherFeedURIBase.concat (value)); var elems = document.getElementsByTagName ("description"); var result = new StringBuilder (); result.append ("<html><center><b>"); result.append (elems [0].value); result.append ("</b><br /><br />"); if (elems [0].value.indexOf ("Error") == -1) { var desc = elems [1].value; var index = desc.indexOf ("<a"); if (index <> -1) desc = desc.substring (0, index); result.append ("<table class="legacyTable" border=1 bgcolor=#ffffff><tr><td>"); index = desc.indexOf ("<b>Current"); result.append (desc.substring (0, index)); result.append ("</td></tr></table><br />"); result.append (desc.substring (index)); } result.append ("</center></html>"); labelHTML = result.toString (); } } Applet { var wModel = WeatherModel {} content: BorderPanel { center: StackPanel { content: [ Canvas { content: [ ImageView { image: Image { url: "file:bg.jpg" } } ] } , BorderPanel { top: FlowPanel { border: CompoundBorder { borders: [ EmptyBorder { bottom: 10 left: 10 right: 10 top: 10 }, EtchedBorder {}, EmptyBorder { bottom: 5 left: 5 right: 5 top: 5 } ] } var t: TextField content: [ SimpleLabel { text: "Zip code" }, t = TextField { columns: 5 background: Color.WHITE action: function (): Void { wModel.getRSSDocument (t.value); } } ] } center: Label { border: CompoundBorder { borders: [ EmptyBorder { bottom: 10 left: 10 right: 10 top: 10 }, EtchedBorder {}, EmptyBorder { bottom: 5 left: 5 right: 5 top: 15 } ] } text: bind wModel.labelHTML } } ] } } } If you’re unfamiliar with JavaFX Script, you might find Listing 1 challenging to grasp. This code basically creates a model (WeatherModel) and a UI (Applet‘s content attribute), and binds the model to the UI via text: bind wModel.labelHTML. This binding updates the UI’s label component with labelHTML‘s content whenever this attribute is updated in response to wModel.getRSSDocument(t.value) calls.Learning Java FX ScriptJim Weaver’s article “Creating Rich Internet Applications With Compiled JavaFX Script Technology” is an excellent resource for learning about JavaFX Script fundamentals. You should also check out Jim’s Weblog “Helping you become a JavaFXpert.” While perusing this Weblog, keep in mind that older entries focus on interpreted JavaFX Script, which presents a syntax that differs in various ways from compiled JavaFX Script syntax. For example, you won’t find a var: self syntax (associate self with the current object) in compiled JavaFX Script. Listing 1 is problematic because it obtains RSS documents on the event-dispatching thread, which can cause the UI to become momentarily unresponsive. Compiled JavaFX Script doesn’t appear to offer a solution — it doesn’t even support interpreted JavaFX Script’s do {} syntax for executing code on a background thread, which would have solved this problem.I thought about using JavaFX Script’s keyframe animation framework to help solve my “need for a background thread” problem. However, I quickly discovered that code executed by this framework also runs on the event-dispatching thread, not on a background thread as I require. For example, the following code outputs Thread[AWT-EventQueue-0,6,main] when run on my XP platform: Timeline { keyFrames: [ KeyFrame { time: 1ms // The function() does not execute when 0 is assigned to this attribute. action: function() { // Would be nice to fetch RSS document here. System.out.println (Thread.currentThread ()); } } ] }.start (); Unless I’ve missed something, I don’t think that compiled JavaFX Script offers a SwingWorker-like Java solution for executing code on a background thread and updating the UI on the event-dispatching thread. However, I’m confident that this situation will be rectified as compiled JavaFX Script matures. Perhaps a solution will even emerge this week at JavaOne.Creating and testing the appletBefore creating the Weather applet, make sure that you have a Java SE 6 JDK installed. Also, download and unarchive a recent build of the openjfx compiler — I downloaded openjdk-compiler-weekly-2008-04-14.zip — and add its bin directory to your PATH environment variable. Finally, unarchive this article’s code archive and make sure that the directory containing Weather.fx is current.Complete the following steps to create the Weather applet: Compile the source code: javafxc Weather.fxCreate a JAR file for the Weather applet: jar cvf Weather.jar *.class bg.jpgAssuming that you’ve successfully created Weather.jar, you’re almost ready to test the Weather applet. First, however, you need to copy the compiled Java FX Script’s javafxrt.jar and Scenario.jar files from their lib directory to the current directory. After doing this, invoke the following command to launch the Weather applet from appletviewer:appletviewer -J-Djava.security.policy=my.policy Weather.html Figure 1 reveals the Weather applet running in the context of appletviewer.Figure 1. Type a zip code into the text field and press the Enter key to see the latest weather data associated with the zip code.The applet requires permission to access Yahoo! Weather. It gets this permission from the my.policy file presented in Listing 2. (You’ll also find my.policy in this article’s code archive.) Listing 2. my.policygrant { permission java.security.AllPermission; }; The code archive also contains a Weather.html file whose <applet> tag I’ve modified to account for JavaFX Script. This file’s HTML appears in Listing 3.Listing 3. Weather.html<html> <body> <applet code="javafx.ui.Applet" width=375 height=375 archive="javafxrt.jar,Scenario.jar,Weather.jar"> <param name="AppletClass" value="Weather"> </applet> </body> </html> For JavaFX Script-based applets, the <applet> tag must specify javafx.ui.Applet as the value of the code attribute, and this tag must include an AppletClass parameter whose value is set to the name of the applet’s main class (Weather). Also, the archive attribute must include the JavaFX Script runtime JAR files (javafxrt.jar and Scenario.jar) in addition to the applet’s JAR file (Weather.jar). How to digitally sign the Weather appletUnlike appletviewer, which recognizes policy files, Internet browsers require applets to be digitally signed. For the purpose of this article, a self-signed test certificate is sufficient. Carry out the following steps to create a new key and keystore on which the certificate is based, create this certificate, sign Weather.jar, and sign the javafxrt.jar and Scenario.jar files: Create a new key in a new keystore: keytool -genkey -keystore myKeyStore -alias meAlias “me” is arbitrary. It reminds you that the certificate based on the keystore (named myKeyStore) is self-signed so that you don’t accidentally put it into production.The keytool program prompts you for information about the new key: It asks you for a password to protect the keystore. Then it asks you for your first and last name, the name of your organizational unit, the name of your organization, the name of your city or locality, the name of your state or province, and the two-letter code of your country. If the values you’ve entered are correct, respond with yes to the “Is...correct?” prompt. Finally, press Enter to assign the keystore password as the password for the key.Create a self-signed test certificate based on the keystore: keytool -selfcert -alias me -keystore myKeyStoreEnter the keystore password when prompted.Sign the Weather applet’s JAR file with the testing certificate: jarsigner -keystore myKeyStore Weather.jar meEnter the keystore password when prompted.The jarsigner program updates the JAR file’s META-INF directory to contain certificate information and digital signatures for each entry in the archive. If all goes well, you end up with a signed Weather.jar file.Sign the JavaFX runtime JAR files with the testing certificate: jarsigner -keystore myKeyStore Scenario.jar me and jarsigner -keystore myKeyStore javafxrt.jar meFor each command, enter the keystore password when prompted.Before we explore applet deployment via the Java Deployment Toolkit, I recommend uninstalling any Java Runtime Environments (JREs) for Java SE 6 that are installed on your platform, because the expected behavior shown in the following section will probably differ if one of these JREs is present. You shouldn’t need to uninstall any installed Java SE 6 JDKs (with their private JREs).Applet deploymentThe Java Deployment Toolkit includes a deployJava.js JavaScript file whose runApplet(attributes, parameters, minimumversion) function simplifies the task of deploying an applet. Furthermore, this function ensures that an appropriate version of the Java runtime is installed before running the applet. Listing 4 demonstrates runApplet() in the context of the Weather applet.Listing 4. Weather2default.html<html> <head> <script src="http://java.com/js/deployJava.js"> </script> </head> <body> <script> var attributes = { code: 'javafx.ui.Applet', width: 375, height: 375, archive: 'javafxrt.jar,Scenario.jar,Weather.jar' }; var parameters = { AppletClass: 'Weather', image: 'title.jpg' }; var version = '1.6.0'; deployJava.runApplet (attributes, parameters, version); </script> </body> </html> The attributes parameter specifies the same <applet> tag attributes that were revealed in Listing 3. Similarly, parameters specifies the same AppletClass parameter, but also specifies an image parameter for replacing the startup Java animation (which is displayed before the applet loads) with a custom image (in title.jpg). Finally, parameter version identifies the minimum Java version needed to run the applet. To experiment with the default installer, point your browser to Weather2default.html. For example, after pointing Mozilla Firefox 3 to this file, this browser presented the content shown in Figure 2.Figure 2. In the absence of a suitable installed JRE, runApplet() requires users to manually download Java SE 6 update 5. (Click to enlarge.)Click the Download Now button to continue. In response, Firefox presents a message box for obtaining an installer program called jxpiinstall.exe, as Figure 3 reveals.Figure 3. jxpiinstall.exe takes care of installing Java SE 6 update 5 on Windows platforms.Click Save File to save jxpiinstall.exe to your desktop. Then double-click the icon that’s created on your desktop to begin the installation. Figure 4 presents the initial dialog box. Figure 4. To avoid intimidating users, the initial dialog box requires a button click to view the license agreement. (Click to enlarge.)Accept the license agreement by clicking the Accept button. Assuming that you haven’t checked the “Show advanced options” panel, this leads you to Figure 5’s Java Setup dialog box.Figure 5. The user must wait until Java SE 6 update 5 finishes installing. (Click to enlarge.)Click the Finish button on the final Java Setup – Complete dialog box to quit the installer. At this point, update 5 has been completely installed.Because the browser doesn’t automatically start running the applet, you need to once again point the browser to Weather2default.html. This time, you should see the content shown in Figure 6. Figure 6. Click the Run button to run the applet. (Click to enlarge.) Deploying the applet via the online and kernel installersThe Java Deployment Toolkit defaults to installing only general availability (GA) versions of Java SE — Java.com reports update 5 as the most recent GA version. To install update 10, you need to take advantage of a deployJava.js feature that lets you install a pre-GA — early access (EA), beta, or release candidate (RC) — version. Listing 5 demonstrates this feature.Listing 5. Weather2online.html<html> <head> <script src="http://java.com/js/deployJava.js"> </script> </head> <body> <script> var attributes = { code: 'javafx.ui.Applet', width: 375, height: 375, archive: 'javafxrt.jar,Scenario.jar,Weather.jar' }; var parameters = { AppletClass: 'Weather', image: 'title.jpg', centerimage: true, boxborder: false }; var version = '1.6.0'; deployJava.setEarlyAccess ('true'); deployJava.EarlyAccessURL = 'http://javadl.sun.com/webapps/download/GetFile/1.6.0_10-beta-b14/ windows-i586/jre-6u10-beta-windows-i586-p-iftw.exe'; deployJava.runApplet (attributes, parameters, version); </script> </body> </html> The feature consists of a setEarlyAccess(enabled) function, which must be invoked with a string argument set to "true", and an EarlyAccessURL attribute, which must be assigned the path and name of an appropriate installer. I’ve specified the URL for the Java SE 6 update 10 beta build 14 online installer.URLs in code snipsBecause the URL in Listing 5 is too long to fit on one line (for listing purposes), I’ve spread it across two lines. In contrast, the Weather2online.html file included in this article’s code archive specifies this URL on a single line. In addition to making it possible to install update 10 via the online installer, Listing 5 introduces the new Java Plug-in’s centerimage and boxborder parameters. These parameters let you center the starting image (title.jpg, for example) in the applet’s rectangular browser area, and remove the one-pixel border that’s drawn around this area to seamlessly merge the applet with surrounding content. Before installing update 10, remove update 5 from your platform (to prevent runApplet() from deferring to it). Then point your browser to Weather2online.html, which results in jre-6u10-beta-windows-i586-p-iftw.exe downloading to your desktop. Double-click this installer’s icon. In response, it starts downloading JRE installation files while displaying Figure 7’s dialog box.Figure 7. The progress bar reports the state of the download. (Click to enlarge.)This dialog box is followed by a sequence of dialog boxes beginning with those shown earlier in Figures 4 and 5. Click Finish on the “Java Setup – Complete” dialog box to complete the installation. In response, runApplet() automatically starts the Weather applet (which it couldn’t do in the context of update 5 because of the manual install). Figure 8 reveals the security dialog box and the starting image.Figure 8. Click the Run button to run the applet. (Click to enlarge.)Enter the Java Plug-inYou might also notice that the screenshot in Figure 8 reveals the presence of Java SE 6u10’s new Java Plug-in, which you can see by the effect of the plugin’s centerimage and boxborder parameters on the starting image. If you launch the Windows Task Manager, you’ll notice that update 10’s Java Quick Starter process jqs.exe is running, which results in faster applet startups. You’ll also discover the Deployment Toolkit Plugin, a browser plugin designed to interact with deployJava.js. The idea is for runApplet() to access the plugin to obtain a list of installed JREs, install a specific JRE or the latest JRE, and perform other tasks. In the future, runApplet() will probably, via the plugin, default to downloading and launching the kernel installer.Two Deployment Toolkit Plugin implementationsThere are two implementations of the Deployment Toolkit Plugin. The Mozilla Firefox Netscape API-based implementation is contained in npdeploytk.dll, which is located in the browser’s plugins directory, and is identified by MIME type application/npruntime-scriptable-plugin;DeploymentToolkit. Similarly, the Internet Explorer ActiveX Control-based implementation is contained in deploytk.dll, which is located in the windowssystem32 directory, and is identified by ClassID CAFEEFAC-DEC7-0000-0000-ABCDEFFEDCBA. Unlike the online installer, the kernel installer (Java Kernel) downloads only those JRE files needed to get the applet running. This installer then downloads the remaining files while the user interacts with the applet.You can try out the kernel installer by using the HTML file presented in Listing 6. This HTML file differs from its predecessor via the presence of the kernel installer’s URL, which is assigned to EarlyAccessURL, and via the presence of deployJava.setInstallerType ("kernel");, which sets the installer type to the kernel installer. Listing 6. Weather2kernel.html<html> <head> <script src="http://java.com/js/deployJava.js"> </script> </head> <body> <script> var attributes = { code: 'javafx.ui.Applet', width: 375, height: 375, archive: 'javafxrt.jar,Scenario.jar,Weather.jar' }; var parameters = { AppletClass: 'Weather', image: 'title.jpg', centerimage: true, boxborder: false }; var version = '1.6.0'; deployJava.setEarlyAccess ('true'); deployJava.EarlyAccessURL = 'http://javadl.sun.com/webapps/download/GetFile/1.6.0_10-beta-b14/ windows-i586/jre-6u10-beta-windows-i586-p-iftw-k.exe'; deployJava.setInstallerType ("kernel"); deployJava.runApplet (attributes, parameters, version); </script> </body> </html> Before installing update 10 via the kernel installer, remove the update 10 previously installed via the online installer. Then point your browser to Weather2kernel.html, which results in jre-6u10-beta-windows-i586-p-iftw-k.exe downloading to your desktop. Double-click this installer’s icon. You should experience a faster installation, and notice Figure 9’s dialog box periodically popping up.Figure 9. This dialog box pops up when additional JRE components are being downloaded and installed. (Click to enlarge.)Toward the futureAlthough it took me some time to adjust to JavaFX Script, I’ve found this technology to be helpful for developing applets. I especially appreciated the compiled version of JavaFX Script, its declarative syntax, and the language’s binding feature. Despite the threading problem I mentioned (which should be resolved as compiled JavaFX Script matures), I think that JavaFX Script will prove to be a very attractive alternative to Java for creating applets, especially as its documentation improves and rich media becomes accessible via this language.Overlooking some awkwardness that should be resolved in the future, I’ve found that the Java Deployment Toolkit makes it easier to deploy an applet and a suitable JRE. I also found that the Java Kernel offers faster deployment, and that Java Quick Starter results in faster applet startup times. While I didn’t do much with the new Java Plug-in, such as attempt to run applets via JNLP, it was nice to see the Java Plug-in’s support (via centerimage and boxborder) for integrating applets seamlessly into Web pages.For broader conclusions about using applets and other Java technology for consumer and rich internet application development, see this article’s companion piece: “Are applets making a comeback?” Jeff Friesen is a freelance software developer and educator who specializes in Java technology. Check out his javajeff.mb.ca website to discover all of his published Java articles and more. JavaSoftware DevelopmentTechnology IndustryDevelopment Approaches