About the Author
Roshan Shrestha is the Chief Software Architect at Qualtech Systems, Inc. He holds a Master Degree in Electrical Engineering from the University of Connecticut, and has been writing Java programs since JDK 1.0.
Spotlight Features

The Rich Engineering Heritage Behind Dependency Injection

Andrew McVeigh takes us on a tour of the rich heritage behind dependency injection, what it represents, and tells us why its here to stay.

NetBeans 6: Matisse Updates

NetBeans 6 delivers great updates to the Matisse GUI builder. Spend a few minutes with Roman Strobl and get an expert briefing on what's new and what has changed.

Introduction to Groovy Part 3

In this, the third and final installation of Andres' Introduction to Groovy series, you learn about how Groovy handles variable numbers of arguments, named parameters, currying, and more about Groovy operators. Including, some new operators.

Easier Custom Components with Swing Fuse

Swing Fuse (actually just Fuse), is a framework designed to make it easier to create your own custom desktop components. In this article, Daniel Spiewak shows you how to get started and provides sample source code you can download.

Benchmark Analysis: Guice vs Spring

Willam Louth shows how he uses JXInsight Probes to investigate probable performance issues with code bases that he is not familiar with. He also highlights possible pitfalls in creating a benchmark, as well as in the analysis of results.

Take Your Tomcat on the Road

Wouldn't it be great if the web application that you wrote to run on a server could be made to run on a regular desktop computer with minimal effort on the user's side? You start thinking about all the obstacles you have to overcome: First of all, the computer may not have JDK or JRE installed. You also need Tomcat to run your servlets. And finally, you need to direct the user to open a browser and navigate to your application's start page. In this article, I am going to show you how you can package your application together with all required components (JRE , Tomcat, and a few other free/open-source components) that the user can just unzip to his/her computer and then run by clicking on an executable file, no batch file required. The application size is small enough to fit on a portable USB drive, so you can even run your program without installing it on a computer! If your application requires a database, no problem - you can embed a pure Java database into your application.

Note: You can download the source code from Resources.

Tomcat Launcher

The entire application consists of just one Java source file! Everything else is downloadable from the web.

First, what application is complete without a flashy splash screen:

Splash Screen


// display the welcome splash screen
splash = Toolkit.getDefaultToolkit().getImage("images/splash.png");
splashWindow = SplashWindow.splash(splash);
Next, the tray icon is created:

// create the tray icon
WindowsTrayIcon.setWindowsMessageCallback(new WindowsMessageCallback());
Image logo=null;
logo = Toolkit.getDefaultToolkit().getImage("images/icon.png");
trayIcon = new WindowsTrayIcon(logo, 16, 16);
trayIcon.setToolTipText(tooltip);
trayIcon.setVisible(true);

From the tray icon, you may wish to display a few menu items if the user right clicks on it:


// create tray icon menu
TrayIconPopup popup = new TrayIconPopup();

// Menu to open the browser and display the start page
TrayIconPopupSimpleItem item = new TrayIconPopupSimpleItem("&Open");
item.addActionListener(new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        {
            TomcatLauncher.this.showHomePage();
        }
    }
);
popup.addMenuItem(item);

For debugging, you may even wish to have a menu to restart Tomcat, and to display its log file:


if(DEBUG)
{// menu for debug version
    // Menu to restart the application
    item = new TrayIconPopupSimpleItem("&Restart");
    item.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                TomcatLauncher.this.restart();
            }
        }
    );
    popup.addMenuItem(item);

    // Menu to display the tomcat logs
    item = new TrayIconPopupSimpleItem("&Show log");
    item.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent e)
            {
                TomcatLauncher.this.showLog();
            }
        }
    );
    popup.addMenuItem(item);
    sepItem = new TrayIconPopupSeparator();
    popup.addMenuItem(sepItem);
}

And lets not forget a way for the user to exit the application:


item = new TrayIconPopupSimpleItem("&Exit");
item.addActionListener(new ActionListener()
    {
	public void actionPerformed(ActionEvent e)
	{
            closeWindow();
	}
    }
);
popup.addMenuItem(item);

To embed Tomcat in your application, the folks at Apache has provided a version of Tomcat just for this purpose, which is a much smaller download. However, I could not get it to work! If someone can make it work, I would be very much interested to obtain the fix. For now, I am using the full-blown Tomcat engine.


Bootstrap bootStrap = new Bootstrap();
bootStrap.init();
bootStrap.start();
System.out.println("Tomcat started");
// display the start page
showHomePage();
// hide the splash window
splashWindow.hide();

We also need to make sure that the user does not start another instance of our application:


if (WindowsTrayIcon.isRunning("Tomcat"))
{
    // another instance already running
    JOptionPane.showMessageDialog(new Frame(),
        error,
        title,
        JOptionPane.INFORMATION_MESSAGE);
    System.exit(0);
}

The Tomcat output normally is printed on the console. To capture the logs so that it can be displayed to the user, one option would be to modify Tomcat's server.xml so that it dumps the logs to a file, and then display that file. Another option, which is used in this implementation, is to redirect  stdout and stderr to a file:

// redirect the stdout and stdin to create a log file
stdout = new PrintStream(new FileOutputStream(LOG_FILE));
System.setOut ( stdout );
System.setErr ( stdout );
Then, to display the log file, we simply open it in Notepad:

Runtime runtime = Runtime.getRuntime();
runtime.exec("notepad " + LOG_FILE);

The following line of code launches the user's default browser:

edu.stanford.ejalbert.BrowserLauncher.openURL(startPage);

To restart Tomcat, we launch another instance of Tomcat.exe, and exit from the currently running one:


cmd = "./tomcat.exe";
WindowsTrayIcon.cleanUp();
// start another instance of the program
runtime.exec(cmd);
// shutdown Tomcat
Bootstrap bootStrap = new Bootstrap();
bootStrap.init();
bootStrap.destroy();
// give Tomcat  a chance to clean up
Thread.sleep(2500);
//exit from this process
System.exit(0);

We also add a ShutdownHook to handle abrupt shutdown, e.g., if the user kills the Java process from the Task Manager.


// handle abrupt shutdown
public void RegisterShutdownHook()
{
	this.shutdownThread = new Thread("myhook")
	{
		public void run()
		{
			if(readyToExit == false)
			{// abnormal exit
				cleanUp();
			}
		}
	};
	Runtime.getRuntime().addShutdownHook(this.shutdownThread);
}

And that's pretty much the meat of our code. Now we could create a batch file to run our program, but we can do better. Using the library from the good people at JSmooth, we can wrap our code in a native windows executable. The jsmooth project file, and the ant build script to compile the code and create an executable can be downloaded from Resources.

Compiling the application

You can download a fully compiled, ready to run version (although you do have to download and copy Tomcat, as well as the JRE) from Resources. To compile the program, you will need to download and install Apache ant. Also, download Apache Tomcat and set the variable CATALINA_HOME. Assuming that the ant binary is in the path, open a Console window, navigate to the application root directory (where the build.xml is located), and issue the command ant. The output files will get created in the directory called bin. The main executable is called tomcat.exe. All paths are resolved relative to the executable, so the directory structure needs to be laid out in a certain manner:

Directory structure 

Copy the entire Tomcat directory into the bin directory, and rename the tomcat directory (e.g.jakarta-tomcat-5.0.25) to jakarta-tomcat. Similarly, copy the JRE folder to the bin directory, and rename the JRE directory (e.g.j2re1.4.2_06) to jre. Your software distribution now is the entire content inside the bin directory. Note: You need not copy and distribute the JRE if the target computer has Java installed - the application will work without the JRE distribution, making the size of our application much smaller. To test our application, double click on tomcat.exe. you should see a splash screen for a few seconds, then a browser will pop-up and display the Tomcat index page. If you look at the right hand corner of your Taskbar, you should see our application as a small icon with the Tomcat logo.

Tray icon

Plug-and-play Tomcat

Copy the entire directory content to a USB flash-drive, plug it to another computer that has no Java installed, and try running it directly from the USB drive! Note: Ensure that you are using USB 2.0 port - the JRE and Tomcat distribution contain a lot of small files, and it will be slow copying all the files to the USB drive. Also, on a USB 1.0 port, the performance isn't going to be that great. Unfortunately, Windows does not support autorun for USB drives, so to run the application you have to double click on the executable manually.

Debugging:

If things don't work as described, you can create a debug version of tomcat.exe. To do this, open tomcat.jsmooth, and change these two lines:

Change



<skeletonName>Windowed Wrapper</skeletonName>

to

<skeletonName>Console Wrapper</skeletonName>

and change

<key>Debug</key>
<value>0</value>

to

<key>Debug</key>
<value>1</value>

Recompile the application, then open a console window, and run tomcat.exe.  On the console window, you will see plenty of messages to help you with debugging.

Using a database:

No full-blown application is complete without a database backend. For this, use a pure Java database (such as HSQL) that can be embedded. You can also package a Microsoft Access file. The connection parameters can be specified as (assuming we name our database as my_database):


driver=org.hsqldb.jdbcDriver
url=jdbc:hsqldb:file:DB/my_database
user=my_user
password=my_password

Note the use of relative path to describe the HSQL data files. Create a directory called DB under the root application directory, and copy the HSQL files there (there will be a minimum of two files: my_database.sql, and my_database.properties).

Enhancements

This application could use a few enhancements. For one, the start page URL (http://localhost:8080) could be externalized to a property file, so that it can be customized without having to recompile. Similarly, the Tomcat port number is hardcoded to 8080. If this port number is in use, the user should be given the option of changing it to another value. This can be achieved by adding a menu item to the tray icon, and providing a pop-up swing dialog box where the user can type in the a port number. Someone also needs to figure out how to use the embedded version of Tomcat instead of the full-featured version. The application keeps running in the background, even when the user closes the browser. We could make the application exit when the session times out. Another way would be to have an "Exit" or a "Logout" button on the web pages - clicking on this button causes the application to exit (before exiting, the application could redirect the browser to a static "goodbye" page (or display a "goodbye" page and then exit after a few seconds).

If you want to add a desktop shortcut to your application, create menu items on the Windows Start menu, or add an entry to the quick launch bar, you can easily do all that by using Roxes ant task (see Resources).

Resources

  1. Download the source code.
  2. Download the binaries.
  3. Create Desktop Applications with Java-Based Web Technologies: http://www.onjava.com/pub/a/onjava/2003/09/17/macosxjava.html
  4. Open a default web browser in Java: http://browserlauncher.sourceforge.net/
  5. Windows Tray Icon: http://jeans.studentenweb.org/java/trayicon/trayicon.html
  6. Jakarta Tomcat: http://jakarta.apache.org/tomcat/index.html
  7. Java Executable Wrapper: http://jsmooth.sourceforge.net/
  8. HSQL database: http://hsqldb.sourceforge.net/
  9. How to do a fast Splash screen in Java: http://www.randelshofer.ch/oop/javasplash/javasplash.html
  10. Apache ant: http://ant.apache.org/
  11. Roxes Ant Tasks: http://www.roxes.com/produkte/rat.html