Best Practices For Applet Development

Applet Developer's Guide > Java Plug-in and Applet Architecture > Best Practices For Applet Development

Contents


Introduction

Applets have a complex runtime environment and several issues need to be considered to ensure that applets run predictably on various browsers and versions of Java Plug-ins. This document describes the best practices for applet development and deployment .

Avoid Static State

Values stored in the applet could persist between invocations, if the memory acquired by the class loader cache isn't needed for other purposes. But you can't depend on that behavior. In general, applets should be stateless. If persistent storage is needed, use browser cookies.

Return from the start method as quickly as possible

If start doesn't terminate, stop can't be called. That's important, because garbage collection occurs after the destroy method terminates. If the applet lingers in the start method, then the applet may not be torn down properly. (It will be torn down, and garbage collection will occur, but resources acquired during applet initialization may not be properly released.)

For a computationally-intensive app like the Clock demo, the trick is to implement the Runnable interface, do the heavy lifting in the run method it requires, and launch a separate thread to do the actual work, as shown in this abstract from the source code:

public class Clock extends Applet implements Runnable { 
  private volatile Thread timer;    // The thread that displays the clock
  ... 
  public void start() {
    timer = new Thread(this);       // Create the thread and start it
    timer.start();
  }
   
  public void stop() {
    timer = null;                   // Release the thread resource
  }

  public void run() {
    Thread me = Thread.currentThread();
    while (timer == me) {
      try {
        Thread.currentThread().sleep(100);
      } 
      catch (InterruptedException e) { 
      }
      repaint();
    }
  } 
  ...

Here, the action is to pause the Clock instance that's running in the new thread (hence the need to store a pointer to it.) Applets that don't need to do all that can simply put their processing code into the run method.

For an interactive app like the spreadsheet demo, that goal is easily achieved, since the majority of time is spent in the event-processing thread, as shown in this abstract from the source code:

public class SpreadSheet extends Applet
  implements MouseListener, KeyListener  // Event processing
{
  public void init() {
    ...
    addMouseListener(this);
    addKeyListener(this);
  } 
  ...
  public void start() {
        isStopped = false;
  }

  public void stop() {
         isStopped = true;
  }

  public void keyTyped(KeyEvent e) {    // Invoked when an event occurs
    ...
  }
  public void mousePressed(MouseEvent e) {
    ...
  }
  
  ...
class CellUpdater extends Thread {
  ... 
  public void run() {
    ...
      if (!target.app.isStopped && !target.paused) {
                        target.app.repaint();
      }

In this particular implementation, each cell has it's own update thread. Updating is paused when a cell is selected, and only stops completely when the applet terminates. The important point is that the applet's start and stop methods only keep track of applet state. Most of the time is spent in the underlying event-processing thread, waiting for the user's keystroke or mouseclick. The applet's real work then occurs in response to one of those events.

Provide an ID for the Applet

An ID defines the namespace, and ensures proper naming at all levels of the data hierarchy:

<applet 
  id="myApplet" 
  name="myApplet"
  ...

Disable the Classloader Cache

Truly stateless applets don't depend on values previously stored in static variables. Since you can't depend on those values to be retained, it's a good idea to create stateless applets. But the user can still store state. It's just that store the data where it belongs--with the user, rather than in the applet code.

To implement a stateless app, access browser cookies or launch with JNLP to use Java Web Start muffins, so the applet gets it's initial settings from persistent storage, rather than using values stored in the program.

To ensure that your applet is stateless, use the classloader_cache attribute to disable the cache. For example:

<applet
  ... 
  classloader_cache="false" 

That setting ensures that the applet is stateless, and that it is truly decoupled from the remainder of the system and from other instances of the applet. It also ensures that the applet runs the exact same way every time, since it won't be affected by state that has been inadvertently retained.

Note:
In the rare case that you expect your users to re-run the same applet repeatedly, you might consider leaving the cache enabled for production for the sake of performance, but disable it during development to ensure quality.

Set up a Proxy to Manipulate the Applet GUI from JavaScript

To prevent thread contention, don't update the Swing or AWT GUI from javascript directly. Instead, set up a proxy that forwards the request to the appropriate dispatch thread:

Keep Inter-process Calls Short

Minimize the time taken to call from Java into javascript, and from javascript into Java. Don't do long-running work in such calls, or you risk a deadlock. To keep the calls short:

  1. In Java method that is invoked from javascript, launch a separate thread to do the work.
  2. If a javascript function has a lot to do, move the code to the Java process and do the work in a separate thread to offload work from the browser.

Avoid Roundtrip Inter-process Calls

When calling into Java, don't make calls back into javascript if you can possibly help it, and vice versa. In that original plugin, doing so used to lock up the browser. That shouldn't happen anymore, but round-trip calls do introduce significant delays in processing time.

When a javascript function needs the applet to do something, the best practice is to return a value that tells the applet to do it, and then call back with the results, or else use invokeLater to minimize traffic tie ups.

Take Advantage of Java's Multi-Threading

The Java platform has powerful multi-threading capabilities that you can take advantage of with classes like Thread, Swing invokeLater, and AWT invokeLater, as well as the new ThreadPoolExecutor class that maintains a background thread pool.




Copyright © 1993, 2011, Oracle and/or its affiliates. All rights reserved.