Introducing the JDesktop Integration Components

Integrate native OS features in your desktop applications with JDIC

This article introduces the JDesktop Integration Components (JDIC), an open source project that's building components that bridge the gap between native applications and their Java™ counterparts. JDIC's single Java API lets your applications tap into native OS features while maintaining cross-platform support. It currently offers native Web browser (Internet Explorer or Mozilla) support, system tray support, file-extension integration, and other desktop features.

Michael Abernethy, Team Lead, IBM

Author photoMichael Abernethy is an IBM employee who is currently the test team lead on the WebSphere System Management team based in Austin, TX. Prior to this assignment, he was a UI developer in Swing at multiple customer locations.



09 August 2005

One of the biggest complaints that developers and users have about Swing -- and the Java programming language in general -- is that client-side applications just don't feel like native applications. (A native application is an application written in a programming language that uses an OS's built-in libraries, such as a Visual C++ application that runs on Windows.) Although Java applications do a good job of appearing native, certain areas are missing that make users notice the difference. The underlying problem is that Java applications can't appear truly native, because native applications have an unfair edge: they can be written specifically for that OS, letting them take advantage of unique native OS functions. Java code is restricted by its "run anywhere" mantra, and calling native functions -- through the Java Native Interface (JNI) for example -- is a big no-no.

Bridging the gap

Since its inception, the Java language has stuck to the mantra of "write once, run everywhere." Unfortunately, that mantra has also translated to developers as "does not work at all on OS-specific things." Nowhere has this been more evident than in client-side applications. Users can see firsthand the inherent disadvantages that Java applications face compared to the native applications written to utilize every unique feature of the OS they run on. The JDIC project contains multiple components that aim to bridge the gap between Java applications and native applications by providing a new cross-platform solution. JDIC seeks to address each Java deficiency by providing a standard Java API that branches out to the individual OS's JNI calls. JDIC also ships with a native library file (.dll or .mo) that you use to link the Java calls to the native OS's built-in functionality. The result is a single Java API that calls different native code depending on the OS it's running on.

Until now, Java developers were willing to live with this shortfall in exchange for the advantages of writing software that runs on any OS. But with the release of Java SE 5, and especially Sun's push to reenergize the Java desktop, some developers wanted to make the distinction between Java applications and native applications nonexistent at last. The JDIC project was created to close this gap (see Resources). As the JDIC Web site claims, JDIC "aims to make Java technology-based applications ('Java applications') first-class citizens of current desktop platforms without sacrificing platform independence."

This article introduces you to the JDIC project and how it strives to make Java client-side applications appear more native. Through a series of examples, you'll take a look at the components that currently exist in JDIC, as well as some in the "incubator" (works in progress). We'll touch on nearly everything that JDIC offers and ideally pique your interest enough to include it in your applications, or even help convince you to contribute to the project itself.

One important note about JDIC: This is still a beta project, meaning that it is not supported in any JDK release and is subject to change at any time. So you must ship the required files with your JDIC-based application, because no Java Virtual Machine (JVM) will support it. And because the API could change from release to release, function names in this article could potentially be different at some point.

It's a wrap

The JDIC project has two goals: keep the Java API cross-platform to let programs run on any machine and support every OS that people use. Because the new functionality requires calling native functions on every OS, that's a seemingly difficult position to be in. JDIC accomplishes this by using its Java API as a wrapper for all these native calls. The JDIC component code itself figures out which OS the application is being run on and calls the appropriate JNI function. (You can just picture the if/else chains inside the code for each OS. Ah, the price for cross-platform compatibility.) Figure 1 illustrates how the JDIC wraps native calls:

Figure 1. How the JDIC wraps native calls
How the JDIC wraps native calls

Set 'em up

Setting up your machine to write and run applications that use JDIC is a little trickier than normal. In addition to the usual classpath requirements, you also must provide the OS libraries that the Java classes will call. There's a different OS library for each OS, so if you want to port your applications using JDIC to many different OSes, you must provide one library for each one. As of JDIC release 0.9, which this article is based on, JDIC works with Windows, Linux, and Solaris systems (sorry, Macintosh fans).

Start by downloading the cross-platform JDIC package, which includes:

  • jdic.jar: This JAR file contains all the Java classes you need for any JDIC development. It must be in your classpath for compilation.
  • jdic.dll and tray.dll: On Windows installations, both of these files need to go into the C:\Windows directory (or your equivalent). These contain the "bridge" methods between the jdic.jar Java methods and the native OS methods.
  • libjdic.so and libtray.so: On Solaris and Linux systems, both of these files must go into the LD_LIBRARY_PATH folder.

Setting these files up should get you up and running. If it doesn't, read the documentation in the JDIC download's README file to check on any specific OS needs. Once you're all set and ready to roll, read on to get started on the examples.


Fill in the gaps

I'll show you a small example application for each JDIC component, each of which addresses a specific gap that exists in the Java language now.

The WebBrowser component

The first component in the JDIC project (and the initial inspiration for the project) is WebBrowser, which gives you a way to tap into the OS's built-in browser. Anyone familiar with Swing knows all too well that it's difficult to view Web pages in a Java application. The existing Swing components, JEditorPane for example, do a poor job of displaying all but the simplest Web pages. If any DHTML scripts are involved, forget about it -- the existing Swing components can't display it. This leaves Swing developers without the option of displaying HTML pages in an application -- a serious handicap now that the Web is so important in any desktop application (for help pages and README files).

Especially frustrating for Swing developers is the fact that a fully functional browser is available on every machine now but has remained unusable to their applications. The built-in browser (Internet Explorer in Windows or Mozilla on Linux machines) is even used by other native applications. This big gap in functionality in Swing, and easy access to a solution, made WebBrowser a good starting point for the JDIC project.

The WebBrowser class lets a Swing application embed the native browser into any application. It's important to note though, that WebBrowser is only the rendering portion of the Web browser application. The component does not include the Back button, the address bar, the status bar, or anything else that is not part of the application's rendering portion. But, as you'll see in a moment, WebBrowser does include methods that let you implement these common browser features.

The WebBrowser component inherits from the java.awt.Canvas class, meaning that it is an Abstract Windowing Toolkit (AWT) component. This should raise some concern with Swing developers, who are familiar with the problems of mixing AWT and Swing components, including repainting problems. The WebBrowser component overrides the java.awt.Canvas.paint() method to render the HTML directly onto the Canvas itself, keeping performance optimal. What does all this mean to a Swing developer? It means you must contain a WebBrowser in a JPanel to use it in Swing. This isn't as bad as it might sound. A JPanel is the logical component to contain a WebBrowser, and other Swing components already have built-in HTML support.

But why keep talking about visual components when you can watch them in action? The example to run is one that ships with the JDIC download, repackaged with the rest of this article's examples so you can get them all in one download (see Download). To see the WebBrowser example in action, run the demo.Browser.Browser main class. Figure 2 shows the WebBrowser example in action:

Figure 2. WebBrowser in action
WebBrowser in action

Now that you've seen WebBrowser in action, take a look at some of the methods in the WebBrowser class that let you create a full-featured browser:

  • The four expected functions of every browser:
    • back()
    • forward()
    • refresh()
    • stop()
  • Methods to let an application change the URL:
    • getURL()
    • setURL()
  • Methods to let an application pass in HTML directly:
    • getContent()
    • setContent()
  • Methods to let an application listen for WebBrowserEvents, which I'll explain later in this section:
    • addWebBrowserListener()
    • removeWebBrowserListener()
  • And the newest method:
    • executeScript()

The executeScript() method lets programs execute a scriptlet in JavaScript and execute it on the loaded Web page or HTML content. This function is cool because you can use it to change the way a Web site looks, even a third-party site. Try adding the following line to the demo application after a page loads:

webBrowser.executeScript("document.bgColor='blue';");

This gives every Web site loaded a blue background, overriding the site's default background color.

The WebBrowserEvent/WebBrowserListener framework works in the exact same way as every event/listener framework in Swing, but in this case involves all of the WebBrowser-related actions that a WebBrowser can fire. Classes that are interested in the events that WebBrowser is firing should add themselves as listeners to WebBrowser though its addWebBrowserListener() method.

The methods in the WebBrowserListener interface that must be implemented are:

  • documentCompleted(): Invoked when the document loading has been completed.
  • downloadComputed(): Invoked when a download operation finishes, is halted, or fails.
  • downloadError(): Invoked when an error occurs during a download operation.
  • downloadProgress(): Invoked when the progress of a download operation is updated.
  • downloadStarted(): Invoked when a download operation is beginning.
  • statusTextChange(): Invoked when the status bar text is changed.
  • titleChange(): Invoked when the title of a document is changed.

And that, in a nutshell, is the WebBrowser component. All the methods in the WebBrowser class and the WebBrowser event/listener framework let you create a complete and functional Web browser application. It might not quite rival Internet Explorer or Firefox, but Swing developers are no longer handicapped by the library's poor support for Web pages and HTML. You can safely count on full Web support -- even for displaying the most difficult Web sites -- in any application. As the inspiration for the JDIC project, WebBrowser started the ball rolling in the right direction.

The SystemTray component

The SystemTray component is one of the neatest additions to JDIC. It lets Java applications place icons in the system tray (in Windows, the area in the lower-right corner of the screen containing icons such as the Volume icon). A growing trend in Windows applications is to add a large amount of functionality to system-tray icons. Instant-messaging applications are a good example. They often give users access to many choices, such as closing the application, only through their system-tray icons. Until now, Java applications were unable to participate in this trend.

Like most items in JDIC, the API for this component is straightforward and easy to use. In fact, the entire org.jdesktop.jdic.tray package has only two classes: SystemTray, which abstracts the system tray itself, and TrayIcon, which abstracts the individual icons in the system tray.

Run the example application -- the demo.jdic.TrayDemoFrame class -- to see how an application can use JDIC's system-tray features (see Download). When you run the application, you should see the yin-yang icon, like the one in the upper-left corner of Figure 3, in your Windows system tray. (Its appearance in Linux and Solaris will of course be different. And even in Windows, it won't look exactly as in Figure 3, because it's impossible to take a screen capture of the menus from the system tray, so this is a re-created image.)

Figure 3. SystemTray in action
SystemTray in action

The interesting part of the example isn't the JFrame itself but how it handles the interaction with the system tray. Take a look at the code in the example application that set this up. The first step is to get an instance of the machine's system tray:

SystemTray tray = SystemTray.getDefaultSystemTray();

The next few steps create the tray icon:

final TrayIcon trayIcon = new TrayIcon(getTrayIcon(), "Tray Demo", getPopupMenu());
trayIcon.setIconAutoSize(true);

trayIcon.addActionListener(new ActionListener() 
{
   public void actionPerformed(ActionEvent e) 
   {
      setVisible(true);
   }
});

The TrayIcon class (unfortunately) currently hard codes how it interacts with mouse clicks. (JDIC users are clamoring for this to change.) TrayIcon fires an ActionEvent on a single left mouse click and displays the pop-up menu on a single right mouse click.

Finally, you add the new TrayIcon to the system tray:

tray.addTrayIcon(trayIcon);

That's it -- you've created a nifty system-tray icon that gives your Java application a very native feel to it.

The JDIC project recently added a displayMessage() function to the TrayIcon class. It lets TrayIcon show the familiar "bubble message" familiar to Windows users. By clicking the Alert button in the example application, you can see this bubble message in action. Here's the code that implements it:

getBtnAlert().addActionListener(new ActionListener() 
{
   public void actionPerformed(ActionEvent e) 
   {
      trayIcon.displayMessage("Alert", "This is an Alert Message", TrayIcon.INFO_MESSAGE_TYPE);
   }
});

Native file support

Currently, Java applications have no way of using default applications to open files. For example, a Java application can't open a .doc file in Microsoft Word. It doesn't know the path to Word on each machine, and on top of that, it has no way of knowing if Microsoft Word is the preferred application for working with .doc files. And there's no easy way to print this .doc file from a Java application.

The Desktop class in JDIC solves these problems by creating some straightforward static methods that let a Java application interact with system applications. These system applications are built into the OS -- only the OS knows which application should open a .doc file.

This component isn't as useful overall as the SystemTray component, but it does fill a nice niche. Any Java application that deals with a variety of file types, such as a file browser, can use the Desktop class's methods:

  • Desktop.browse(URL url): Opens a Web site in the system browser.
  • Desktop.edit(File f): Uses the program associated with the edit command of the file type to open the file.
  • Desktop.open(File f): Uses the program associated with the open command of the file type to open the file.
  • Desktop.print(File f): Prints the file.
  • Desktop.mail(Message m): Automatically opens the system's preferred e-mail program with some of the fields filled in.

You can see the functions in action in the example program demo.jdic.FileExtensionDemo. The top part of the application lets you to browse for a file and then open it, as you can see in Figure 4:

Figure 4. Native file support
Native file support

When you click the Open button, the Desktop class invokes the system's default PDF viewer, as you can see in the following code:

else if (e.getSource() == getOpenButton())
{
   try
   {
      Desktop.open(new File(getTxtFile().getText()));
   }
   catch (DesktopException ex) 
   {
      ex.printStackTrace();
   }
}

The FileTypes component

The final piece to the JDIC project at this time is FileTypes. This component might not seem important at first glance, but after I describe it, you'll see that it's a very important part of creating an overall Java desktop application. The fundamental problem that FileType solves is the inability of existing Java programs to register file extensions and associate them with an application. When you double-click on a file with a .doc extension, Windows automatically knows to open that file in Word. Java applications have no way to do this. You can't write a Java application that opens automatically when you double-click on a file with a new extension. You can't register a file extension such as "jexx" to open your own Java application. This is a severe setback to Java application developers because it keeps their applications from feeling like a part of the native operating system. Tell me -- when users double-click on a file, do you want them to have to navigate the Open with... dialog, or would you rather that the application simply open?

The three classes in the org.jdesktop.jdic.filetypes package fill this gap by letting Java applications register file extensions and associate them with open, edit, and print actions. You can choose to have different applications do the opening and the editing. For example, your application can open an XML file with a browser and edit it with a text editor. After linking the action to the association, you can register it with the OS.

Start exploring the demo.jdic.FileExtensionDemo class (the same example application discussed in the previous section, Native file support). This time, you'll use the bottom half of the dialog to create your FileType. Figure 5 shows how the example looks with the fields filled in:

Figure 5. FileTypes demonstration
FileTypes demonstration

After clicking the Register button, you can open the File Types tab in the Windows Folder Options dialog and see what you've just created, as shown in Figure 6:

Figure 6. Association registration
Association registration

Now take a look at the code for relevant portion of the example application:

else if (e.getSource() == getRegisterButton())
{
   String verb = getTxtVerb().getText();
   String command = getTxtCommand().getText();
   String fileExt = getTxtExt().getText();

   // Create the Action object that will store the 
   // verb (in this example "open" with the command "in this case the 
   // link to the java.exe
   Action action = new Action(verb, command);

   // Next we need to create the Association which we'll use to 
   // register in the operating system
   // You can link the action we just created to the 
   // association and a corresponding file extension.
   Association association = new Association();
   association.addAction(action);
   association.addFileExtension(fileExt);

   // Finally, after we have created our Association, we use the 
   // AssociationService, which will talk directly to the operating system to 
   // register the file type
   AssociationService associationService = new AssociationService();
   try
   {
      associationService.registerSystemAssociation(association);
   }
   catch (RegisterFailedException ex)
   {
      ex.printStackTrace();
   }
   catch (AssociationAlreadyRegisteredException ex)
   {
      ex.printStackTrace();
   }
}

The example shows you how straightforward it is to create and register a file type in the OS Some additional methods of interest in the Association class can enhance the file types:

  • setIconFileName(): Lets an application set an icon on a file type.
  • setMimeType(): Lets an application set a Mime type on a file type.

As one last step, to show the power of the native file support and FileTypes in action together, create a file called example.jexx on the desktop, as in Figure 7:

Figure 7. Desktop file
Desktop File

Now, instead of double-clicking on the example.jexx file (which wouldn't prove anything), open it through the FileExtensionDemo application using the JDIC code you learned about in Native file support.

Figure 8. FileType and native file support demonstration
FileType and native file support demonstration

When you click the Open button, you'll see this file launch Notepad. The combination of native file support and the FileType component is a key addition to the Java application developer's toolbox. Natively supported double-click support for Java applications arrived with the executable JAR file. Now users can finally open your Java application by double-clicking on the application's associated files. This small but distinct addition lets Java applications seem like an ingrained part of the OS.


In the incubator

The components I've outlined so far are completed and functioning parts of the JDIC project. JDIC also includes a set of components under construction, called incubator projects (a.k.a. the Sandbox). You'll find many degrees of completeness among the incubator projects, ranging from a component that's finished and awaiting entry into the JDIC packages to a component that's still just an idea on paper.

As part of a public project that's open to the ideas and hard work of anyone who is willing to contribute, the incubator offers a chance to test drive new ideas. Only components that have been tested and whose API and functionality meet with approval will be promoted to the distributed JDIC packages. Keep this in mind as you read about the incubator components in this section -- very cool, but incomplete. It could be a few months before they are ready for prime time.

IconService

The IconService class performs the singular task of converting an icon name (which often comes in a difficult-to-understand form like C:\Program Files\IBM\eclipse.exe,1) into a java.awt.Image object. Once the Image object is obtained, it can be manipulated -- so you can manipulate the icon itself. The icon name is obtained from another JDIC class, the Association class, by calling the getIconFileName() method. Here's the method for converting an icon into an Image object:

Image i = IconService.getIcon(Association.getIconFileName(), 1);

SystemInfo

The SystemInfo class attempts to provide information on the OS itself. This includes items like the system idle time and whether the user's session is locked. As of this writing though, that's all it provides, and no API exists to browse it or read about the methods. It appears that this class is still in its true infancy stage, so stay tuned to see if updates are in the works.

FloatingDock

The FloatingDock class aims to mimic the Windows Taskbar, by both allowing components to be added to it and by docking itself to a region of the screen. FloatingDock is basically a JPanel that is tied to a region (left, right, bottom, or top). For the most part, it contains the same functions as a JPanel, letting you change the layout and add and remove components. FloatingDock also lets the application change the region at any time, much like dragging the Windows Taskbar to a new location on the screen.

Don't be misled into believing that FloatingDock provides exactly the same functionality as the Taskbar. It only enables docking to a screen's region. It is up to you, if you wish to mimic the Taskbar, to add the functionality for displaying JToggleButtons, resizing them, and so on.

Here's how to create a FloatingDock object on the bottom of the screen and add a JButton to it:

FloatingDock dock = new FloatingDock();
dock.setLocation(FloatingDock.BOTTOM);
dock.add(new JButton("Window 1"));

Misc package

The Misc incubator package contains an eclectic collection of one-task components. These components contain only one or two static methods that seek to fill a simple gap in the Java-to-native conversion. Only Macintosh is supported for the classes in this package as of this writing, because the developers felt that the Mac wasn't getting the attention it deserved in this project. At this point, there's nothing to deploy because the project hasn't done a build yet for the Mac. So for now, you'll have to be happy enough with reading about the methods and what they can do, and then crossing your fingers in the hope that a release is published in the near future.

Volume

A member of the Misc package, the Volume class controls the volume level on the computer. public float Volume.getInstance().getVolume() gets the current volume, and public void Volume.getInstance().setVolume(float vol) sets the volume.

This class also lets users register for changes in the volume by providing an addPropertyChangeListener() function that notifies interested classes when the volume changes on the computer (but not necessarily through the Volume class itself).

Wallpaper

Another member of the Misc package, the Wallpaper class, along with its counterpart the WallpaperFactory class, lets a Java application change the wallpaper (the image on the desktop that displays in the background) on an OS. Here's some example code for changing the wallpaper:

Wallpaper wall = WallpaperFactory.createWallpaper();
wall.setBackground(new File("/background.jpg"), Wallpaper.CENTER);

Alerter

Another member of the Misc package, the Alerter class addresses a very small niche by letting an application that isn't in focus (i.e., is behind other windows) notify a user that some action needs to be taken. On Macs, where this class is currently supported, this Alert "bounces" the dock icon. On Windows, when it becomes supported, it will flash the Taskbar icon until it is selected. Here's a code example:

Alerter.newInstance().alert();

DockMenu

The final class in the Misc package addresses the Dock Menu, a component that only exists in Macs and has no parallel in Windows or Linux systems. The DockMenu class lets a user attach a menu to the Dock Menu in Mac applications Here's the example of how to use the DockMenu class:

JMenu menu = new JMenu("Exit");
DockMenu.newInstance().setMenu(menu);

FileUtil

The newest addition to the JDIC incubator is FileUtil, a class that provides a few new functions to supplement the java.io.File class in the JDK. The public java.math.BigInteger getFreeSpace(File dir) method returns the free space in a directory, and public boolean recycle(File f) puts a file in the OS's recycle bin, instead of simply deleting it.


A wish list

The list of components in JDIC and its incubator is pretty thorough, but it by no means closes all the gaps between Java applications and native applications. This section is a wish list of components that I, and many other developers, would love to see implemented in JDIC. For those ambitious readers out there, keep in mind that JDIC is an open project and that anyone can contribute at any time -- so feel free to take these ideas and run with them.

Natively supported nonrectangular windows

Nonrectangular frames are becoming very popular in applications (Microsoft Media Player, for example). Swing developers have been clamoring for years about support for nonrectangular windows across multiple OSes. If developers ever add support for this in JDIC, the entire Swing community will vault them instantly to the highest pantheon of geekdom. (Existing attempts at a solution include a Windows-only solution from the L2FProd.com project and my own IFrame, which is an "almost there" solution; see Resources.)

Desktop "New" support

When users right-click on the Windows desktop, they see a New menu choice that contains a submenu with common file types that a user can create. The Java language, at this point, has no access to this menu.

File-specific right-click support

Users who right-click on a file in Windows are presented with choices for the file. Some applications have changed their default behavior to be in these lists of choices automatically at all times. (Notice how WinZip, for example -- if you have it installed on your machine -- is always a choice when you right-click on any file type.) The Java language has no means of permanently adding a program or choices to this menu.

Additional functionality in the SystemInfo class

Additional functionality in the SystemInfo class would be useful, including support for finding process names and numbers, networks status, network connection speed, and battery life.

User and group management

It would be great if a Java application could manage the OS's user and access groups, including handling password management.

Time and date

How about letting a Java program change the time, calendar, and time zone on the OS?


Conclusion

The JDIC project fills a major gap that has existed in Swing and in the Java programming language in general. With the continued work of others, it will bridge the gap further and some day make it impossible for a user to tell the difference between Java applications and native applications.

As you've seen, JDIC (as of this writing) consists of both mature, ready-for-production projects and the incubator, which contains projects in various stages of development. The incubator provides some interesting projects that might come to fruition in the near future. The important thing to remember if you decide to take a risk and include an incubator project in your application is that it could change at any time, could be buggy, and might not even work at all.

My best advice, if you like what you've seen in this article, is to get involved with the JDIC project. The project is open to anyone who is interested in participating, and like most open source projects, it can only do as much as people are willing to contribute (see Resources for a direct link to the site where you can sign up to get involved). Whether you want to help complete some of the projects in the incubator, decide to follow up on an idea in my wish list, or have an idea of your own that you want to see come to fruition, the development community will greatly appreciate your help. Don't think that you need to be an expert in native code or JNI or must know every OS. The incubator project lets you hash out your ideas and get feedback and help from other volunteers.


Download

DescriptionNameSize
Sample codej-jdic.jar12 KB

Resources

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology
ArticleID=91216
ArticleTitle=Introducing the JDesktop Integration Components
publish-date=08092005