Comments
yourfanat wrote: I am using another tool for Oracle developers - dbForge Studio for Oracle. This IDE has lots of usefull features, among them: oracle designer, code competion and formatter, query builder, debugger, profiler, erxport/import, reports and many others. The latest version supports Oracle 12C. More information here.
Cloud Expo on Google News
SYS-CON.TV
Cloud Expo & Virtualization 2009 East
PLATINUM SPONSORS:
IBM
Smarter Business Solutions Through Dynamic Infrastructure
IBM
Smarter Insights: How the CIO Becomes a Hero Again
Microsoft
Windows Azure
GOLD SPONSORS:
Appsense
Why VDI?
CA
Maximizing the Business Value of Virtualization in Enterprise and Cloud Computing Environments
ExactTarget
Messaging in the Cloud - Email, SMS and Voice
Freedom OSS
Stairway to the Cloud
Sun
Sun's Incubation Platform: Helping Startups Serve the Enterprise
POWER PANELS:
Cloud Computing & Enterprise IT: Cost & Operational Benefits
How and Why is a Flexible IT Infrastructure the Key To the Future?
Click For 2008 West
Event Webcasts
Creating a Custom Launcher
Creating a Custom Launcher

The most frustrating and error-prone aspect of Java for the average user is starting a Java program. The monumental confusion of batch files, scripts, and command-line cut-and-paste that's necessary to start a Java program using the default launcher is an ongoing problem area even for veteran developers.

This article shows how you can wipe away the whole mess and easily write custom launchers for your applications. A custom launcher makes startup as simple as point-and-click and can be the difference between a program appearing professional or appearing unusable. The specifics on making launchers for all the major platforms are also covered.

A long-time barrier to user acceptance of Java has been the confusing and unfriendly default launcher. It requires long strings of command-line arguments before it will start a Java program. Both users and software developers constantly receive the java.lang.NoClassDefFound exception and other errors. Sun's noble response to this problem is to provide a public API, the invocation interface, that can be used to start the JVM and accompanying Java program. Although a few commercial applications use this API, it's woefully underutilized overall. I'll show how easy it is to create a custom launcher and provide templates that you can use to automate startup of your Java programs. There's even a generic configurable launcher that's ready to run, no compilation necessary.

I focus on the three major desktop platforms: Windows, Mac OS, and Unix. Each platform has its own quirks, but using a custom launcher brings benefits that are common to all three, such as:

  • Program startup is easier and more reliable.
  • Software identification and branding are better.
  • Greater customization and VM control is possible.
Given that a commercial-quality launcher requires only about 200 lines of code and templates are provided, there's no reason you can't get started today.

How Java Programs Are Launched
The complexity of launching a Java program is largely due to Java being an interpreted language. This makes startup and shutdown a multistep procedure (see Figure 1).

As the figure suggests, any native executable can start a Java program. A Java launcher is a native executable dedicated solely to starting Java programs. The most commonly used launchers are the ones Sun supplies in the /bin directory of the Java runtime distribution. In the case of the Windows platform, these programs are "java.exe" and "javaw.exe". The former opens two windows: a console that receives System.out/err and output from the launcher and the Java window itself. The latter, a windowless launcher, opens only the Java window. On J2SE/EE platforms the virtual machine is implemented as a dynamic link library that's also in the /bin directory. On Windows it's called "java.dll", on Unix "java.so". Loading the VM equates to loading this DLL.

Users specify options to the VM in two ways. They can put the options on the command line to the launcher and/or define environment variables with the desired settings. One of the options, the startup class, can only be specified on the command line. This bifurcation of the execution configuration is a common source of confusion that can be eliminated by using a custom launcher.

When the virtual machine has finished running the main() method of the startup class, the launcher calls destroy() on the VM to free any detachable resources and then exits. Note that there's no way to unload a VM once it's been loaded. This makes no difference to a launcher since it will exit as soon as the Java program is done; however, for a native application that embeds a VM, such as a browser, it means there's a permanent commitment of memory that can't be reclaimed.

Nuances of Creating a Windows Launcher
Once you understand the Java life cycle you're ready to code a launcher. Be aware that some of the generic code examples floating around on the Web and in books, such as The Java Native Interface by Sheng Liang (see Resources), won't work on a platform such as Windows without changes. The working example in C++ for Windows illustrates some of the nuances (see Listing 1).

First, use a WinMain() entry point as you would for most Windows applications. Also, you need to prototype CreateJavaVM() to use the stdcall calling convention by typedef'ing it as a pointer to CALLBACK. These are Windows-specific requirements. Another platform-specific nuance is loading the VM DLL. The most reliable way to load the VM is by an explicit call to LoadLibrary:

HINSTANCE hJVM = LoadLibrary(sJVMpath.c_str());

First determine the path of the JVM's DLL and then explicitly load it. This differs from the example in The Java Native Interface, which uses implicit loading. The problem with implicit loading is that it makes assumptions about the location of the DLL that might not be true for all environments. By explicitly loading the JVM you can place it anywhere you like in your distribution and verify that it's really there before attempting to load it. Once you load the JVM, obtain a function pointer to CreateJavaVM() by using the kernel call GetProcAddress() and then calling that pointer to start the VM.

The next nuance in the listing is that the separators used in the startup class identifier are slashes, not dots. So in the listing the startup class is "javabunny/JavaBunny", not "javabunny.JavaBunny". This is because FindClass() is a virtual machine call and the virtual machine internally uses the slash as its package separator. By the way, the example hard codes the startup class (and other values). This may be appropriate for a shrink-wrapped product release, but in a development environment you'll probably want to pull this value from a configuration file. Later, I'll describe a more generic template that does this.

The example determines the startup method ID by using the JNI call GetStaticMethodID(). This call requires the method name ("main") and the type descriptor "([Ljava/lang/String;)V". This type descriptor means the method takes an array of strings as an argument and has a return type of void. For more information on type descriptors see The Java Virtual Machine Specification (see Resources). Notice that when you create a custom launcher you're not restricted to using a static void method called "main". You can start with any method at all, even an instance method or constructor.

The last tricky point of a launcher is hidden behind the following line at the end of the listing:

jvm->DestroyJavaVM();

This statement looks like optional cleanup added as an afterthought to program execution. Not true! If the Java program is multithreaded, it will still be executing during this call. For example, if a Swing program runs and its main method exits, this line will execute and block until all nondaemon threads have completed. This blocking behavior makes it critical that you include this line. If you omit it, the program will exit as soon as the main thread terminates, even if other threads (like the event loop of your GUI) are still running.

Launcher Configuration
In Listing 1 I hard code some of the key parameters such as the startup class. Notice, however, that none of the paths are hard coded. This is part of the beauty of a custom launcher ­ all the paths are relative, so you can drag the application folder to another drive (or computer) and it will run flawlessly. Try doing that with a batch file. Listing 1 always uses a JRE located in a subfolder of the application folder. By distributing a JRE with your application, like this, you guarantee runtime compatibility and make your application totally independent of the user's environment. The extra disk space used by adding yet another JRE to the user's disk drive is meaningless compared to the increased reliability. When writing your own launchers you may want to use different directory layouts than the one in Listing 1. As long as all the paths are relative to the native executable's location, you're fine.

Resource paths can be made flexible enough that they don't need to be configured, but some values will need to be configurable outside of the launcher, especially in an oft-changing development environment. These include:

  • The startup class
  • The class path
  • Special VM parameters such as "-verbose"
The best way to specify these parameters is to load them from a configuration file located in the same directory as the launcher executable. (The source code for this article can be downloaded from www.sys-con.com/java/sourcec.cfm and includes code for a launcher that configures itself this way.) By using a resource editor to replace the icons in this launcher's binary with your own, you can use it repeatedly for all your applications without ever needing to compile.

Mac Launchers
In the Macintosh universe, life is much easier. Java development on the fruit boxes is divided into two scenarios: OS X and pre-OS X ("Classic Mac OS"). OS X has strong Java support compared to Classic Mac. For example, Classic Mac supports only 1.1.8, so for many developers it will be irrelevant. Swing support on Classic Mac is available if the user downloads and installs MRJ 2.2.5, but for anything more recent like J2EE, forget about it.

If these restrictions don't faze you, create a native launcher on Classic Mac by using Apple's old native toolkit called JDirect (don't confuse this with the obsolete "J/Direct" that worked with Microsoft's J++). A much easier way to create a clickable icon, however, is to use a special Apple tool called "JBindery". This tool creates a distribution that so closely resembles a native application that writing a native launcher is unnecessary. You can completely configure your distribution package using JBindery, including defining security settings and the appearance of the Java window. When you're done, use ResEdit to add a custom icon to the package and it's ready to run. Apple considers Mac Classic, JBindery, and this whole methodology obsolete, but if you want to support the many users who are sticking with OS 9.1/2, it's your best option.

The new Mac world is all OS X. In OS X the application layer is called "Cocoa" and you access it with Objective-C. Is that retro or what? Despite how weird it sounds, Java support is excellent because an interface called the "Java Bridge" wraps the Java Native Interface (including the invocation interface) and makes a seamless connection between your native code and Java code.

As with the Classic OS, writing a native launcher is unnecessary, since Apple has provided a great bundling tool, MRJAppBuilder. If your Objective-C skills are a little rusty and you're working solely in Java, the best approach is to use MRJAppBuilder. Apple has designed this bundler especially for packaging Java applications. Note that the bundling framework the tool uses is the standard way to deploy all Cocoa applications, not just Java applications. This enlightened approach to application distribution means that on OS X, a bundled Java application is externally indistinguishable from an Objective-C application and behaves in all ways like a native executable.

The powerful capabilities of the bundlers (JBindery for Mac Classic and MRJAppBuilder for OS X) eliminate the need for a custom launcher on the Macintosh unless you're doing something offbeat such as starting from an instance method. If you really need to go native on the Macintosh, the article's download package has some code examples that will get you started. Otherwise, stick with the bundlers and you can sit back and laugh at the PC programmers while they fiddle endlessly with batch files.

Unix Launchers
Unix (or Linux) is the inverse of OS X ­ it has no explicit support for Java or even for native application packaging. For example, on Unix desktops the icons live separately from their applications and the relationships between them are managed by configuration files or scripts. Issues like compiling icon resources into the launcher binary don't exist under Unix. This means an easy and reliable startup mechanism is more a function of your installation script than anything else.

Even so, a custom launcher still has many benefits under Unix. For example, in a process listing, the Java command line is usually so long it gets truncated, and on a server machine running multiple VMs it can be a pain to identify which process is which. You can create a custom launcher that simplifies and shortens these startup commands and thus make the process listing more meaningful.

One of the advantages of Unix's simplicity is that its launcher code is the easiest of all the platforms. The basic Unix launcher is the same as the Windows example shown in Listing 1 without the Windows-specific type conversions and Windows configuration issues (see the download package for an example). Another advantage is that a Unix launcher will generally work in any Unix environment as long as it's recompiled ­ once again, something that the installation script manages.

The disadvantage of this simplicity as compared to other OSs is that you are more or less obliged to use scripts of some sort even if you do implement a custom launcher. Good thing Unix has such great scripting capabilities.

Conclusion
By mastering the art of creating custom launchers for your Java applications, you can ramp up their convenience, professionalism, and reliability. The ease of creating launchers along with the use of configuration files makes them ideal for use in development environments as well as in release distributions. Do yourself a favor: learn to code a launcher and say goodbye to java.lang.NoClassDefFound.

Resources

  • Liang, S. (1999). The Java Native Interface: Programmer's Guide and Specification. Addison-Wesley.
  • Lindholm, T., and Yellin, F. (1999). The Java Virtual Machine Specification. Addison-Wesley.
    About John Chamberlain
    John Chamberlain is a developer in the Boston area who works at OPeNDAP.org. He holds a master's degree in computer science, is a frequent contributor to technical journals and has spoken at JavaOne. He can be reached by email at jdj@johnchamberlain or stop by his web site at http://johnchamberlain.com

  • In order to post a comment you need to be registered and logged in.

    Register | Sign-in

    Reader Feedback: Page 1 of 1

    I followed this article from a link in the JDC Forum at Sun. Interesting topic! and I agree with the author, it frustrates the pros as well as the newbies, however when I attempt to read the next page ie "1 of 15 >next" all I get is a bombardment of adverts ... hmmm, not good, not at all good ...

    I see an other solution to avoid these java.lang.NoClassDefFound errors: a self-executable ".jar" file.

    Julien Messer

    (to reply to this message, please remove "NS")


    Your Feedback
    Scotty wrote: I followed this article from a link in the JDC Forum at Sun. Interesting topic! and I agree with the author, it frustrates the pros as well as the newbies, however when I attempt to read the next page ie "1 of 15 >next" all I get is a bombardment of adverts ... hmmm, not good, not at all good ...
    Julien Messer wrote: I see an other solution to avoid these java.lang.NoClassDefFound errors: a self-executable ".jar" file. Julien Messer (to reply to this message, please remove "NS")
    Latest Cloud Developer Stories
    DXWorldEXPO | CloudEXPO are the world's most influential, independent events where Cloud Computing was coined and where technology buyers and vendors meet to experience and discuss the big picture of Digital Transformation and all of the strategies, tactics, and tools they need t...
    Enterprise architects are increasingly adopting multi-cloud strategies as they seek to utilize existing data center assets, leverage the advantages of cloud computing and avoid cloud vendor lock-in. This requires a globally aware traffic management strategy that can monitor infra...
    Disruption, Innovation, Artificial Intelligence and Machine Learning, Leadership and Management hear these words all day every day... lofty goals but how do we make it real? Add to that, that simply put, people don't like change. But what if we could implement and utilize these e...
    The deluge of IoT sensor data collected from connected devices and the powerful AI required to make that data actionable are giving rise to a hybrid ecosystem in which cloud, on-prem and edge processes become interweaved. Attendees will learn how emerging composable infrastructur...
    In this Women in Technology Power Panel at 15th Cloud Expo, moderated by Anne Plese, Senior Consultant, Cloud Product Marketing at Verizon Enterprise, Esmeralda Swartz, CMO at MetraTech; Evelyn de Souza, Data Privacy and Compliance Strategy Leader at Cisco Systems; Seema Jethani,...
    Subscribe to the World's Most Powerful Newsletters
    Subscribe to Our Rss Feeds & Get Your SYS-CON News Live!
    Click to Add our RSS Feeds to the Service of Your Choice:
    Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
    myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
    Publish Your Article! Please send it to editorial(at)sys-con.com!

    Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021



    SYS-CON Featured Whitepapers
    ADS BY GOOGLE