Back to article index

Packaging web applications for desktop use

2007-06-20Sami Ekblad


Desktop web applications – but why?

There are some situations when you would like to run a web application on your local computer just like a desktop application. For example, you might need an offline version of a serve application or maybe you are primarily a web programmer and would like to use familiar tools to build desktop applications. Also, creating a server application allows you for instance to have remote control if needed.

In all these situations it is handy to package a web application into a single package that can be run on a local machine. In this article I build up an environment that is suitable for running Java servlet based web applications more like on a machine and simulate desktop application behaviour.

Limitations of web applications on desktop

We are pushing the boundaries of web technology here. Some things were definitely not designed for this kind of stuff, and we must accept some limitations in application design.

First, web applications are accessed using a web browser. Therefore, you must have one. This is not an issue usually, since all modern operating systems come bundled with a browser.

Second, we need a server to be running that must be bundled, but when talking about a Java based servlet container, we also come across the requirement for Java virtual machine installation. This is something that might be a problem. There are tools and workarounds to overcome this problem, but they are out of the scope of this article. See the last chapter for pointers.

Third, running a server application limits your possibilities to interact with other desktop applications. User interface is presented inside a browser that has its own security limitations.

Create a web application

I won’t go too deep into this. You probably already have an application you’d like to use or at least you have an idea of that. I only assume that you have created a Java servlet application that can be deployed into a standard servlet container as a WAR-file.

As an example I use the Example applications from IT Mill Toolkit that can be packaged into a single WAR. Take a look at Environment Setup using Winstone on how to get your application up and running or just download this full Eclipse project here.

 

general-project-structure.jpg

 

Screenshot: General project structure


About the application’s structure:

  • Make sure the application is self-contained and does not require any external files.

  • Define the servlet-mapping in web.xml so that all requests go to your application

  • Winstone does not support JSP so you should bundle some extra jar-files in case you need it. See Winstone Website for details.


Package the web application as a WAR file

I have used the Sysdeo Tomcat Plugin to create the application. It comes with a handy “Export to WAR file” feature. There is also an Ant build file bundled with Toolkit Example Project that creates the application from an Eclipse project.

Use the right tools for packaging and deployment

There are several things you should take into account before trying to create a desktop-runnable servlet application:

  1. A servlet is a server application. It requires a servlet container (i.e. a server) to run.

  2. Not all computers have a servlet container.

  3. A servlet is a Java application. It requires Java (JRE) to run.

  4. Not all computers have correct JRE – or correct version of it.

The first two things can be solved easily but the JRE might prove to be a bigger problem. Let’s start with the easy one.

Creating a standalone application installation

If you created the web application the same way as I did, you already have a web application project in Eclipse that can be executed as a Java application. It uses a simple launcher of Winstone servlet container to run the project. It can be extended to better suit our desktop purposes.

Winstone comes with a nice built-in feature that allows you to wrap a server and a WAR-file into a single JAR file. Simply unpack the winstone-<version>.jar into a directory and copy the WAR-file you created into the same directory. Rename the war as “embedded.war”. And then re-package the directory content (make sure you package the content of directory and not the directory itself). I used the name “DesktopSample.jar” here.

For convenience I also extended the original ANT script that creates exactly this by one single command.

 <target name="install-embedded-war" depends="war">
<copy tofile="build/winstone-temp/embedded.war"
file="build/${ant.project.name}.war" />
</target>

<target name="unjar-winstone" depends="init">
<unjar src="${winstone.jar}" dest="build/winstone-temp" />
<copy todir="build/winstone-temp">
<fileset dir="WEB-INF/classes"
includes="**/ServerRunner.class,**/BrowserControl.class,**/DesktopServer*.class" />
</copy>
</target>

<target name="update-manifest" depends="unjar-winstone">
<manifest file="build/winstone-temp/META-INF/MANIFEST.MF">
<attribute name="Main-Class" value="${server.main.class}" />
</manifest>
</target>

<target name="copy-server-classes">
<copy todir="build/winstone-temp">
<fileset dir="WEB-INF/classes"
includes="**/ServerRunner.class,**/BrowserControl.class,**/DesktopServer*.class" />
</copy>
</target>

<target name="package"
depends="unjar-winstone, install-embedded-war, copy-server-classes, update-manifest">
<jar destfile="build/${ant.project.name}.jar"
basedir="build/winstone-temp"
manifest="build/winstone-temp/META-INF/MANIFEST.MF" />
</target>

 

Try to run the application

Now you are ready to test the package. Simply open the console and go to the directory where the DesktopSample.jar resides and run the command:

java -jar DesktopSample.jar

The application starts:

C:\TOOLKIT>java -jar DesktopSample.jar
[Winstone 2007/05/04 15:34:30] - Beginning extraction from war file
[Winstone 2007/05/04 15:34:31] - Winstone Servlet Engine v0.9.8 running: controlPort=disabled
[Winstone 2007/05/04 15:34:31] - HTTP Listener started: port=8001
[Winstone 2007/05/04 15:34:38] - Control thread shutdown successfully
[Winstone 2007/05/04 15:34:38] - Winstone shutdown successfully

As you see here the default port is 8001 and you can access the application at http://localhost:8001/

 

running-examples.jpg

 

Screenshot: Applications running on local server


The original Toolkit example project contained a simple browser launcher that could be used to run the default web browser. This was used to open the browser automatically into the correct address.

Finishing touches

Both methods above are suitable for starting the server, but neither of them handles the closing of the server when the user no longer uses the application.

To handle the application closing of applications something must be done so I ended up in creating a simple (Swing) dialog that opens up when the server is started and closing the window also stops the background server.

 

server-window.jpg

 

Screenshot: Server window


The final jar size for these applications is about 2MB (without the JVM), which is quite satisfactory.

Creating executable files for Windows

What we have so far is an application that can be started from the command line or in some systems by double clicking it. If your target platforms are predefined, and you wish to make things even smoother for end-users, you might want to create a native binary out of the JAR.

I tested this using a tool called Launch4j, which promises to create Windows executable files from executable JAR files – exactly what I needed.

launch4j-interface.jpg

Screenshot: Launch4j user interface


Just select the JAR file which to use and enter the name for the exe-file. There are numerous other options to configure (for example Java version checking, splash screen, etc), but I did not test them.


Where to go from here

There are still some issues left unsolved:

  • Other operating systems than Windows are not described here. To create a startup script similar to Windows should be pretty simple though. I leave them to OSX and Linux experts.

  • Hiding the browser’s standard navigation might be useful in some cases. This makes your application look like a desktop application. You could for example bundle a browser like PortableFirefox with the application and customize it to meet your needs.

  • A more sophisticated way of creating a seamless desktop experience would be using embedded Java browser or JDIC.

  • Application startup might take some time and cause an error to appear. This could be avoided by presenting a temporary page while loading the server starts.

  • SWT dialog could be used instead of Swing dialog to provide a more native look and feel. However, this would increase the size of distribution significantly.

Conclusion

We have created here an Eclipse environment that can be used to build executable JAR-files that actually run a servlet application and open the web browser automatically. From the end-user’s point of view this is very close to normal desktop applications, although there are some things that could be more seamless.

 Resources





Back to article index


Add Your Comment

Comments, corrections and suggestions about the content of this article are always welcome.