It's no secret that Java has not been successful as a client-side platform. We often use HTML/Ajax or Flash/Flex on the browser and Java on the server. Maintaining 2 distinct platforms has a major disadvantage: it's hard to share code.
Imagine this scenario: you have built a beautiful UI for the browser, and like any respectable shop you maintain your business logic in Java on the server. Suppose you design a screen where your user can do what-if analysis by fiddling with sliders and watching pretty graphs and numbers change in real time. Unfortunately, the code that does all that complex computation is in Java on your server. Your options:
- Write a parallel ActionScript codebase that duplicates the Java logic. You have the burden of keeping both codebases correct and in sync, and there could be subtle inconsistencies in the resulting logic.
- Keep the logic on the server, and execute the computation there. Every time the user jiggles a slider, the Flex app bundles all the relevant data and transmits it to the server. The server in turn does the computation and sends back the results.
Implementing an invisible Java applet to provide services to your UI code via JavaScript is surprisingly easy. Your applet tag needs a MAYSCRIPT attribute to enable the Java-to-JavaScript interface:
<applet ...="" height="0" id="myapplet" mayscript="" width="0">
...
</applet>
Note that this is a 1x1 box. If the applet is zero size or wrapped in a hidden div, the applet won't start. Once your applet is running you can call public methods in your Applet class directly from JavaScript:
document.getElementById('myapplet').myJavaMethod();
Conversely, you can call your JavaScript methods from within your applet. Since JavaScript is single-threaded, for longer operations you might want to use an asynchronous call/callback pattern where the Java code would spawn a separate thread that returns the result by way of a callback into your JavaScript code. You can do it like this:
JSObject.getWindow(applet).call("myJsMethod", new Object[] { arg });
One odd behavior I found when calling Java methods from JavaScript is that even when the applet is signed, the Java code executes in a thread with reduced privileges. Jumping onto the Swing event thread will gain you the signed privileges, but now you are tying up the event thread. If you want privileged, multithreaded execution, you could do something like this (looks bizarre, I know):
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new Thread() {
public void run() {
doWhatIReallyWantToDo();
}
}.start();
}
});
That seems easy enough, but there still aren't many situations that justify using Java on the client side. The dominance and ubiquity of Ajax and Flash on the browser means you need a really good reason to burden your users with the Java runtime. Deployment remains Java's big weakness on the client. Some possible reasons:
- To share logic on both client and server.
- To use functionality from some complex third-party library on the client side.
- Get multithreaded, fast execution.
- Need for extensive filesystem access.
- Some combination of the above.