RSS Feed Subscribe to RSS Feed

 

Swing, Webstart and Maven – An Example

Following my introductory rant on the subject, this post is a working example of using Swing and Webstart with a multi-module maven project.

Complete source can be downloaded from here.

Simplest possible example

I am posting the simplest possible example I could get working. It is a grossly over-simplified example designed to focus purely on getting the Swing/Webstart/Maven combination working.
For example:

  • The Swing client is the simplest possible Swing app you could possibly create (it just displays ‘Hello World’), since the focus is on the Swing/Webstart/Maven setup, not complex Swing coding
  • There are very few dependencies on other projects, to keep the poms simple. Obviously real apps are likely to be much more complicated
  • The example uses just 2 maven modules (client and web) when in reality, a real enterprise project would likely have many more (e.g. client, web, service, persist). The web module in this example could act as your entry point to those other modules.

Anyway, hopefully those simplifications keep the example easy to follow.

Basic overview

The example uses a simple 2 module (client and web) maven project, with the jnlp defined in the client module. You then need to build and deploy the artifacts (a zip containing the built jnlp bundle for the client module and a war for the web module) to a maven repository. The final piece of the puzzle is then downloading the client zip and web war to your app server of choice (e.g. tomcat).

Setup

Steps:

Note that the Maven project structure I am using here is (loosely) based on the maven multi module example from the maven docs. The dir structure is just the standard maven directory layout. We wont be using the test and resources folders for this simple example, but they are included as a placeholder.


1. Setup maven folder structure


I don’t know of a maven archetype for creating a multi-module project, so we need to do it manually. Create the following directory structure:

SwingWebstartMaven
-SwingWebstartMaven-Client
--src
---main
----java
----jnlp
----resources
---test
-SwingWebstartMaven-Webapp
--src
---main
----java
----resources
----webapp
-----WEB-INF
---test


2. Create a simple Swing app


For our simple Swing app, we are using the simplest example possible – HelloWorld. This code needs to be placed in our client project, here

SwingWebstartMaven\SwingWebstartMaven-Client\src\main\java\com\shaunabram\swingwebstartmaven\HelloWorldSwing.java

package com.shaunabram.swingwebstartmaven;

import javax.swing.JFrame;
import javax.swing.JLabel;

public class HelloWorldSwing {
  public static void main(String[] args) {
    JFrame frame = new JFrame("HelloWorldSwing");
    final JLabel label = new JLabel("Hello World");
    frame.getContentPane().add(label);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}


3. Create web.xml


Next, we create the simplest possible web.xml i.e. an empty one. For this example, we just need the webapp to serve our jnlp file (and associated jars). In a real application, the web module would be the interface your your server. For example, you might use Spring Remoting and HTTP invokers to allow your Swing client to communicate with a service layer via your web module.

JnlpDownladServlet

Note that our example does not use the JnlpDownloadServlet, purely to keep the example as simple as possible. You however, may want to configure our webapp’s web.xml to use the JnlpDownladServlet as it adds some extra benefits such as allowing you to use $$codebase instead of having to maintain hardcoded project URLs (e.g. the template.vm file in the next section would benefit from its use as it contains a hardcoded url). See some background info on the JnlpDownloadServlet here, and notes on how to configure your webapp to use JnlpDownloadServlet here.

Your web.xml should look something like below.
This file will be located here:

SwingWebstartMaven\SwingWebstartMaven-Webapp\src\main\webapp\WEB-INF\web.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC 
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>

</web-app>


4. Create the template.vm file


Next, create the template.vm file. This file is the template used to generate the jnlp file.
This file will be located here:

SwingWebstartMaven\SwingWebstartMaven-Webapp\src\main\jnlp\template.vm

<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="http://localhost:8080/SwingWebstartMaven-Web/webstart" href="$outputFile">
 <information>
    <title>Swing Webstart Maven Project</title>
    <vendor>ShaunAbram</vendor>
 </information>
 <security>
 <all-permissions/>
 </security>
 <resources>
    <j2se version="1.5+" initial-heap-size="32m" max-heap-size="128m" />
    <property name="jnlp.versionEnabled" value="false"/>
    $dependencies
 </resources>
 <application-desc main-class="$mainClass">
 </application-desc>
</jnlp>

Note the use of the hardcoded URL for the codebase. You may need to change this for your local environment. For more options how the codebase is used, see here. Also, as noted above, utilising the JnlpDownloadServlet would allow use to remove the hardcoded URL and use $$codebase instead.


5. Create our maven poms



5.1 Parent project pom


Next, we define the pom for our parent project, SwingWebstartMaven.
This file will be located here:

SwingWebstartMaven\SwingWebstartMaven\pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.shaunabram.swingwebstartmaven</groupId>
    <artifactId>SwingWebstartMaven</artifactId>
    <packaging>pom</packaging>
    <version>1.0</version>
    <name>SwingWebstartMaven Project</name>

    <modules>
        <module>SwingWebstartMaven-Client</module>
        <module>SwingWebstartMaven-Web</module>
    </modules>

    <build>
        <pluginManagement>
            <plugins>
                
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>1.5</source>
                        <target>1.5</target>
                    </configuration>
                </plugin>
                
            </plugins>
        </pluginManagement>
    </build>

</project>


5.2 Client module pom


Next, we define the pom for our client module.
This file will be located here:

SwingWebstartMaven\SwingWebstartMaven-Client\pom.xml

This pom is the most important part of this example as it is where we specify the details for the jnlp file generation. See here for JNLP File generation details.

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.shaunabram.swingwebstartmaven</groupId>
        <artifactId>SwingWebstartMaven</artifactId>
        <version>1.0</version>
    </parent>
    <artifactId>SwingWebstartMaven-Client</artifactId>
    <packaging>jar</packaging>
    <name>SwingWebstartMaven Client</name>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo.webstart</groupId>
                <artifactId>webstart-maven-plugin</artifactId>
                <version>1.0-beta-2</version>

                <executions>
                    <execution>
                        <id>package</id>
                        <phase>package</phase>
                        <goals>
                            <goal>jnlp-inline</goal>
                        </goals>
                    </execution>
                </executions>

                <configuration>
                    <jnlp>
                        <outputFile>launch.jnlp</outputFile>
                        <mainClass>com.shaunabram.swingwebstartmaven.HelloWorldSwing</mainClass>
                    </jnlp>

                    <libPath>lib</libPath>

                    <sign>
                        <keystore>SwingWebstartMavenExample-KeyStore</keystore>
                        <keypass>YourPassword</keypass>
                        <storepass>YourPassword</storepass>
                        <alias>SwingWebstartMavenExample</alias>
                        <validity>3650</validity>

                        <dnameCn>Your Name</dnameCn>
                        <dnameOu>Organizational Unit</dnameOu>
                        <dnameO>Organization</dnameO>
                        <dnameL>City or Locality</dnameL>
                        <dnameSt>State or Province</dnameSt>
                        <dnameC>US</dnameC>

                        <verify>true</verify>
                        <keystoreConfig>
                            <delete>true</delete>
                            <gen>true</gen>
                        </keystoreConfig>
                    </sign>

                    <pack200>false</pack200>
                    <gzip>true</gzip>
                    <outputJarVersions>false</outputJarVersions>
                    <verbose>true</verbose>

                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


5.3 Webapp module pom


Next, we define the pom for our webapp module.
This file will be located here:

SwingWebstartMaven\SwingWebstartMaven-Webapp\pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
                             http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.shaunabram.swingwebstartmaven</groupId>
        <artifactId>SwingWebstartMaven</artifactId>
        <version>1.0</version>
    </parent>

    <artifactId>SwingWebstartMaven-Web</artifactId>
    <packaging>war</packaging>
    <name>SwingWebstartMaven Web</name>

    <dependencies>

    </dependencies>

</project>


6. Build, deploy and run

Build

To build, simply do:

mvn clean install

Deploy

Deploying is a slightly trickier matter…

Web module

For the web module, you can simply build and ensure the generated war is placed in your tomcat webapps dir, by whichever mechanism suits you best.
For example,
1) Manually copy the war from the target dir to your tomcat dir (although if doing is manually like this, you may want to remove any version number i.e. it should be named SwingWebstartMaven-Webapp.war rather than SwingWebstartMaven-Webapp-1.0.war).
2) Add the following to the build/pluginManagement/plugins section of your parent pom (SwingWebstartMaven\SwingWebstartMaven\pom.xml)

                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>tomcat-maven-plugin</artifactId>
                    <configuration>
                        <url>http://localhost:8080/manager</url>
                        <username>your-tomcat-username</username>
                        <password>your-tomcat-password</password>
                    </configuration>
                </plugin>

And the simply do

mvn clean tomcat:redeploy

3) Write a script on your server than will pull the generated war from your maven repository (e.g. using wget to download from Nexus) and place it in your tomcat dir.

Client module

For the client module however, deploying it is a slightly trickier matter.
My preferred approach is to to utilise the script approach mentioned in step 3) above to also pull down the client zip (e.g. SwingWebstartMaven\SwingWebstartMaven-Client\target\SwingWebstartMaven-Client-1.0.zip), and extract the contents into the tomcat webapps dir (I like to put it in a webstart folder e.g. tomcat\webapps\SwingWebstartMaven-Web\webstart).
For example, the script could, among other things,

  • Stop tomcat
  • Determine the latest version of the project available in the maven repository
  • Pull down the web module’s war tomcat/webapps
  • Start tomcat (so the war will be extracted and deployed)
  • Pull down the client module’s zip
  • Unzip to (for example) tomcat/webapps/SwingWebstartMaven-Web/webstart

These are all just suggestions for deployment of course – how you do it is up to you. But my point is that I found extracting the client module’s generated zip file (containing the jnlp bundle) to be the easiest way to deploy a JNLP project to an app server to make it easily accessible for users.

Run

Whatever build and deployment method you choose, you should now be able to access your Webstart enabled Swing app from a URL like this:

http://localhost:8080/SwingWebstartMaven-Web/webstart/launch.jnlp

Tags: , , , , ,

6 Responses to “Swing, Webstart and Maven – An Example”

  1. Jörg |

    Thanks for this guide, helped me a lot!

  2. sabram |

    Thanks Jörg, glad you found it useful…

    Shaun

  3. Martin |

    Great guide. Thanks for it.
    Unfortunately I encountered a problem when running downloaded example. After deploying my web browser opens address http://localhost:8080/SwingWebstartMaven-Web/ successfully, but http://localhost:8080/SwingWebstartMaven-Web/webstart/launch.jnlp gives 404 error. What should I check? Thanks in advance

  4. sabram |

    Hi Martin,
    Sorry for the delay in responding – your comment got blocked by the spam filter. Are you still having problems?

    Shaun

  5. Heet |

    Shaun,

    Could you maybe attach a screenshot of your final directory structure and all of the files near the end of the post? Some parts of this guide are a little confusing. For example, the text-based directory diagram appears to show that SwingWebstartMaven-Webapp is located within SwingWebstartMaven-Client, which I’m guessing it’s not; and the guide says to put template.vm inside SwingWebstartMaven-Webapp/src, even though that directory structure doesn’t exist in the original diagram. Otherwise, this has been really, really helpful!

    Heet

  6. sabram |

    Hey Heet,
    Thanks for the pointers. I updated the directory diagram – it now reflects the zipped project I linked to at the start of the post. I’m afraid it’s been a long time since I worked on this though, so I don’t have a final version to post…

    Shaun

Leave a Reply