|
|
|||||||||||||||
by Joshua Marinacci
| |||||||||||||||
| |||||||||
If you have been a Java developer for a while you may have had the experience of being told that Java can't do everything that native C can. You may have struggled with the HMTLEditor pane while Windows developers down the hall embed Internet Explorer into their programs with just a few lines of code. I'll admit it: as great as Java is, there are times I long for the features and system access of native programming. Well, we don't have to wait any longer.
If you hang out on java.net at all, or read any of the JavaOne news coverage, you may have heard of the JDesktop Integration Components (JDIC). This new API lets Java developers finally do the sorts of things we've always envied of our native brethren. This article will give you a complete overview of the JDIC features, with a small example of each, and a list of what to download to get started. We will try out all of the APIs except for the SaverBeans sub-project, which I will cover separately in part two.
JDesktop Integration Components, or JDIC, is a catchall project for a set of modules that gives Java developers access to native features through cross-platform APIs. It was started by the Desktop group at Sun to let Java applications better integrate with the desktop on which they are running. They made JDIC open source to as a way to get rapid feedback from developers on desired features, as well as bug reports. While there are no current plans to do so, the JDIC team is looking into pulling some of the JDIC features into a future version of the core Java libraries.
JDIC is broken up into five components and one incubator project:
The Desktop component is the simplest and possibly most useful of the
JDIC components. Its entire existence is devoted to basic desktop services
like opening a file in the right editor, starting an email message, or
sending a URL to the default web browser. These are all things that require
a lot of work under the hood to build, but very little to use. If you want
to tell the OS to open a Microsoft Word document, then just call
Desktop.open(new File("resume.doc"));. It's that simple.
The org.jdesktop.jdic.desktop package only has three
classes: Desktop, Message, and
DesktopException. The Desktop class is static and cannot be
instantiated. It has methods for opening, editing, and printing files. You
can also open a new email and populate it with text. This is where the
Message class comes in, which lets you set the recipient,
body, attachments, and all of the other email parts.
The best thing about the Desktop components package is how easy it is to use. You don't have to register any special drivers or change configuration based on the current platform. That's all done for you under the hood. As long as the jdic.jar file is in your classpath and the correct native lib is in your library path (usually you just put it with the .jars) then the code will simply work. Here is a one-line example to launch a browser:
import org.jdesktop.jdic.desktop.*;
import java.net.*;
public class DesktopTest {
public static void main(String[] args)
throws Exception {
Desktop.browse(
new URL("http://www.yahoo.com/")
);
}
}
The next core component of JDIC is the Filetypes package, which sets file type associations. This means you can tell the operating system what program to use with what files, such as always opening text files using Word instead of Notepad. Using this API you can query, set, and delete file type associations based on file extensions and mime types.
Given that file type associations are usually quite operating-system-specific, this API is more useful for retrieving associations or registering
the application itself rather than for setting associations. For example,
the usual text file association under Windows is to call
notepad.exe in a well-known directory. Under Gnome, it might be
to call /usr/local/bin/gedit. Since this is system-specific it
probably isn't very useful to set associations except to tie a Java
application to its own file types. Still, no matter what you do
with it, the Filetypes component handles all of the heavy lifting for you,
dealing with the registry and MIME-type database.
Here is a short example of setting file associations:
import org.jdesktop.jdic.filetypes.*;
import java.net.*;
public class FileTypesTest {
public static void main(String[] args)
throws Exception {
Action action = new Action("open",
"C:\\WINDOWS\\system32\\notepad.exe %1");
Association assoc = new Association();
assoc.addFileExtension(".mchat");
assoc.setMimeType("application/mad-chatter");
assoc.addAction(action);
AssociationService svc = new AssociationService();
svc.registerUserAssociation(assoc);
}
}
The first two lines of the main
method create an Action that will
open the file (represented by %1)
with notepad.exe. The next four lines
create an association between the action and the
.mchat file extension. I threw the
MIME-type in there for good measure. In the past,
most operating systems relied exclusively on the
file extension or proprietary metadata to
determine the file type. These days, however, most
operating systems are moving towards MIME
settings for all file typing, so it's good to
start using them now. The last two lines actually
register the association with the system. As with
all JDIC APIs, as long as the native lib is in
your library path, you don't need to do anything
special to get it to work.
The third main component of JDIC is the Browser. Unlike the previous two, which just give you access to system services, this component gives you a real AWT widget to use in graphical applications. Previously, you could use third-party embedded components or all-Java browsers (see "HTML Renderer Shootout, Part 1"), but JDIC lets you embed the user's default web browser inside of your application, opening the door to many possibilities. Now writing things like RSS readers with full web support becomes possible. Downloading will also be faster, because you won't have to include the native browser with your application.
The Browser API gives you access to a few browser events and control over the history (forward, back, refresh). Future revisions of the API are expected to provide even more access to the browser and any loaded documents.
Using the browser from your application is really quite easy:
import org.jdesktop.jdic.browser.*;
import java.net.*;
import javax.swing.*;
public class BrowserTest {
public static void main(String[] args) throws Exception {
WebBrowser browser = new WebBrowser();
browser.setURL(new URL("http://java.net"));
JFrame frame = new JFrame("Browser Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(browser);
frame.pack();
frame.setSize(500,500);
frame.setVisible(true);
}
}
As you can see, the WebBrowser object is just an AWT component that you
can drop into a standard JFrame. The first line of the main method creates
a new WebBrowser and the second sets the URL you want to show. The
rest of the code creates a frame, adds the browser to it, and makes the
frame visible. Once running, its display looks like Figure 1.

Figure 1. Embedded WebBrowser
Remember that the WebBrowser is a native AWT component, so you may run into
issues combining it with Swing. The two rules for mixing them is 1) never
overlap Swing and AWT components, and 2) call
setLightWeightPopupEnabled(false)
on your menus or they will disappear behind the browser component. See this
Swing Connection article for more on mixing
AWT and Swing.
Right now, the Browser component will use the user's default web browser, which usually means Internet Explorer or Mozilla, and you can't bundle the necessary parts of Mozilla with your application like you can with JRex. This behavior is probably okay for Windows, where IE is pretty much guaranteed to be there, but this will be more problematic on Linux where, the default browser may not be Mozilla (it may be Konquorer in KDE, for example). Hopefully these issues will be resolved as the project matures, but right now it's still quite useful for a variety of projects.
Unlike the rest of JDIC, the Packager module is not an API. Instead, it
is a set of command-line tools that convert JNLP (Java Web Start)
applications into native installers. (rpms for Linux, pkgs for Solaris, and
msis for Windows). This doesn't mean your application is turned into an .exe
like with JSmooth or JExePack; it simply gives you a
one-click installer for a Web Start application. After the program is
installed, it will update itself over the Internet, use the JNLP descriptor,
and do all of the other things that Web Start applications do.
The Packager component requires J2SE 5.0 and
native tools. For Windows, you will also need to install Microsoft's MSI
SDK. Once your environment is set up, you can use the command-line tools
jnlp2msi, jnlp2rpm, and jnlp2pkg to
convert your Web Start application into a platform-specific installer.
The Tray Icon API used to be an incubator project, but due to the diligent efforts of the java.net community, it has matured and been promoted to a full JDIC component status. It's entire purpose is to create those little program state-icons in the lower-right-hand corner of your screen, assuming your operating system has a system tray concept. In practice, this means Windows and Linux. Mac OS X users are out of luck (or better off, depending on your point of view). It also supports pop-up menus and automatic tooltips for the icons. Like the rest of JDIC, system-tray support requires native code, but you can code against a Java API with a pre-compiled native library.
Since the API is pretty small in scope, there
are only two classes: SystemTray and
TrayIcon. The SystemTray class has a
static factory method for accessing the default
system tray. TrayIcon lets you attach a
JPopupMenu and an Icon
to the next available space on the system tray.
Finally, call
SystemTray.getDefaultSystemTray().addTrayIcon()
to get your pop-up to appear. Let's examine a small
example:
import org.jdesktop.jdic.tray.*;
import java.awt.event.*;
import javax.swing.*;
public class SystemTrayTest {
public static JMenuItem quit;
public SystemTrayTest() {
JPopupMenu menu = new JPopupMenu("My Menu");
menu.add(new JMenuItem("Test 1"));
menu.add(new JMenuItem("Test 2"));
quit = new JMenuItem("Quit");
quit.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent evt) {
System.exit(0);
}});
menu.add(quit);
ImageIcon icon = new ImageIcon("duke.gif");
TrayIcon tray_icon = new TrayIcon(icon, "System Tray Test!", menu);
SystemTray tray = SystemTray.getDefaultSystemTray();
tray.addTrayIcon(tray_icon);
}
public static void main(String[] args) {
new SystemTrayTest();
}
}
In the first few lines of the SystemTrayTest constructor we create a
JPopupMenu with three menu items. The last one, quit, adds an
ActionListener to quit the program. Now, instead of adding the menu to a menu bar or
JComponent, we put the menu into the constructor of a TrayIcon. The
ImageIcon for the system tray image is also passed into the TrayIcon,
along with text for a tooltip. Finally, we add the TrayIcon to the
default SystemTray and the program is done. Compile this with tray.jar
in your classpath and tray.dll in your library path (usually the working
directory). The icon and its menus are shown in Figure 2.

Figure 2. Tray API Example
The Tray API also supports animated GIF icons and left-click actions. With this API, you can make your application completely disappear into the taskbar until needed.
From the start, JDIC was designed to actively encourage and develop new APIs. To facilitate project growth they created an incubator project, where developers can commit code and try out ideas. If they ideas are good enough and the implementations mature, the project can be promoted to a full JDIC module or even spun out into its own complete project.
The JDIC team wants more contributors, so please join in. You will have to sign and fax in the JCA (Joint Copyright Agreement), since parts of JDIC may eventually be pulled into future versions of Java. They are looking for cross-platform APIs with native implementations. This means that Java bindings to Gnome would not be appropriate, since they are specific to Gnome, but a cross-platform API for drawing non-rectangular windows (my personal wish) would be very welcome.
I've saved my favorite API for last. JDIC has one major incubator project right now: a toolkit to create cross-platform screensavers called SaverBeans. Like the rest of JDIC, you can code entirely in Java, letting a pre-built native library handle the messy details. The project consists of an API for handling callbacks, an XML file for configuration, and an Ant task that produces the platform-specific screensaver executables (.scrs for Windows and shell scripts for Unix) with their support files.
Writing a screensaver is a bit more complicated than using the other APIs, so I have saved this one for part two of this series. However, if you want to get started right away, you can download the SDK and a collection of community-built screensavers.
Though JDIC is still beta, it shows great promise. Changes have been coming fast and furious as open source developers embrace and extend it. Work is already under way to fold in older projects, fix the bugs, support the Mac, and eventually migrate parts of JDIC to the core runtime.
Though it seemed to come out of nowhere, JDIC is something that many Java developers have been wanting for a long time. Now that it's here, we can really develop Java applications that do everything native programs do. I'll see you in a few weeks, when we will convert a particle simulator into a top-notch screensaver.
Joshua Marinacci first tried Java in 1995 at the request of his favorite TA and has never looked back.
Java Sketchbook: The HTML Renderer Shootout, Part 1
HTML is everywhere; not just on the Web, but also as a styled-text and hyperlinking standard for help systems, online stores, email, and many other applications. And for these many needs, there are many Java-based HTML rendering toolkits. Part 1 of Joshua Marinacci's two-part series looks at the free offerings in the HTML rendering space.
View all java.net Articles.
Showing messages 1 through 3 of 3.
|
|