Sunday, October 14, 2012

Deploying Scala Desktop Applications via Java Web Start

[Last update on 04/08/2013]

Java Web Start is a great technology to deploy Java applications. It can be used to deploy Scala applications as well. This tutorial shows how to do it.

The Example Application

Our example Scala application is a simple Scala Swing desktop GUI, shown as Listing 1. Compile it and package the produced class files in a jar file. Let's name the jar file scala-gui.jar. To compile and run it, we need two scala libraries: scala-library and scala-swing. In this tutorial, we use scala-library-2.9.2.jar and scala-swing-2.9.2.jar.

Listing 1 - The Example Application

package simple.scala.swing.gui

import scala.swing._

object HelloWorld extends SimpleGUIApplication {
    def top = new MainFrame {
        title = "Scala Swing"
        contents = new Label {
            text = "Hello World!"
        }
    }
}

When runs, the application shows a simple window with text "Hello World!" as its content, as in the figure below.

Figure 1 - Example Scala Application


Host Web Server

To deploy the Scala application via Java Web Start, we have to host it on a web server. In this tutorial, we use Tomcat as our web server.

In Tomcat, create a simple web application named scala-gui. The figure below shows the directory structure of the Tomcat home directory.

Figure 2 - Directory Structure of Tomcat Home





Library Jar Files

Sign scala-gui.jar, scala-library-2.9.2.jar, and scala-swing-2.9.2.jar with a private key. (If need, see the appendix later for the how-to). Copy the above three jar files to webapps/scala-gui/lib under the Tomcat home directory.

jnlp Files

Create two jnlp files - scala-gui.jnlp and lib.jnlp, and place them under webapps/scala-gui under the Tomcate home directory. Content of the two jnlp files are in Listing 2 & 3. The IP of our web server is 192.168.241.128.

Listing 2 - scala-gui.jnlp

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"
    codebase="http://192.168.241.128/scala-gui/"
    href="scala-gui.jnlp">
    <information>
          <title>Scala GUI</title>
          <vendor>xxx</vendor>
          <homepage href="http://192.168.241.128/scala-gui/" />
          <description>A simple Scala Swing GUI application to demo Web Start Deployment</description>
    </information>

    <security>
        <all-permissions />
    </security>

    <resources>
        <jar href="lib/scala-gui.jar" />
        <extension href="lib.jnlp"/>
    </resources>
    
    <application-desc main-class="simple.scala.swing.gui.HelloWorld" />
</jnlp>
 
 
Listing 3 - lib.jnlp 

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+"
    codebase="http://192.168.241.128/scala-gui/"
    href="lib.jnlp">
    <information>
          <title>Scala GUI Library</title>
          <vendor>scala.org</vendor>
          <homepage href="http://192.168.241.128/scala-gui/" />
          <description>Scala language and Swing libraries</description>
    </information>

    <security>
        <all-permissions />
    </security>
    
    <resources>
        <jar href="lib/scala-library-2.9.2.jar" />
    </resources>
    
    <resources>
        <jar href="lib/scala-swing-2.9.2.jar" />
    </resources>

    <component-desc/>
</jnlp>

The Web Page 

Finally, create our web page for users to download the Scala application. It is a simple HTML file, as shown in Listing 4.  

Listing 4 - index.html 

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <title>Scala GUI</title>
        
        <script src="http://www.java.com/js/deployJava.js"></script>
    </head>
    
    <body>
      <H1>Scala GUI</H1>
  
  Click this button to start the Scala GUI:
  <script>
                 var url = "http://192.168.241.128/scala-gui/scala-gui.jnlp";
          deployJava.createWebStartLaunchButtonEx(url, '1.7.0');
  </script>
    </body>
</html>


The web page will be shown in a web browser as in the figure below.

Figure 3 - Download Page of the Applicatio

When a user click the Launch button on the web page, if Java Web Start has been installed on the client machine, a dialog as in the figure below will be shown to the user.

Figure 4 - Open JNLP with Java Web Start


If the user takes the default option, i.e. "Open with Java(TM) Web Start Launcher", a Security Warning dialog will be shown next, as in Figure 5. It is because we signed the jar files with a self-signed certificate. If we had signed the jar files with a certificate signed by a certificate authority trusted by the user, there would not be such warning. If the user accept the unverified signature, Java Web Start will download the Scala application and run it on the user's machine, as shown in Figure 1.

Figure 5 - Security Warning

Troubleshooting

Java Web Start may log/trace many useful information that can be used to troubleshoot deployment problems.

To enable Java Web Start log/trace on a Windows machine, do the following:

  1. Go to the Control Panel, and click the Java Control Panel. On the Java Control Panel dialog, choose the Advanced tab. Under Setting / Debugging, check both Enable tracing and Enable logging, as shown in Figure 6.
  2. Find the deployment.properties file. (On a Windows 7 machine, it is under C:\users\${username}\AppData\LocalLow\Sun\Java\Deployment, where ${username} should be replaced by concrete username.) Make sure the deployment.properties file has the following configuration lines:
    • deployment.trace=true
    • deployment.trace.level=all

Figure 6 - Java Control Panel    





On a Windows 7 machine, the log and trace files can be found under C:\users\${username}\AppData\LocalLow\Sun\Java\Deployment\log.




Appendix - Using Java keytool & jarsigner


Generate Keys

The example below shows how to generate keys using Java keytool.

keytool -genkey -alias tedkey -keypass tedpass -dname "cn=Ted Gao, ou=, o=, l=Mason, s=Ohio, c=US" -keystore C:\web-start-tutorial\ted.keystore -storepass tedpass -validity 1825 -keyalg RSA -keysize 2048 -storetype JCEKS -v

The command above has to be in one line. It generates a pair of RSA private key and certificate with 2048 bit strength, and stores them in a keystore file named ted.keystore under C:\web-start-tutorial. Alias for this key pair is "tedkey". The alias is to be used to specify which key (pair) to use later. The keystore and the private key are protected with a password "tedpass". The password for the private key is required to read the private key; the password for the keystore is required to write to the keystore. They do not have to be the same password. In this example, we just use the same password for both.

Sign  Jars

The example below shows how to sign java files using Java jarsigner.

jarsigner -keystore C:\web-start-tutorial\ted.keystore -storepass tedpass -keypass tedpass -storetype JCEKS -verbose scala-gui.jar tedkey

The command above has to be in one line. It use a keystore named ted.keystore under C:\web-start-tutorial. Alias of the key to use is "tedkey". Both the private key and the keystore are protected by password "tedpass". The example above signs a jar file named scala-gui.jar.