Chapter 20. Applets

One of the original tenets of Java was that applications would be delivered over the network to your computer. Instead of buying a shrink-wrapped box containing a word processor, you would pay per use for a program available over the Internet. This revolutionary idea has been temporarily shelved by the realities of a slow Internet. But small downloadable applications called applets are practical and interesting.

An applet is part of a web page, just like an image or hyperlink. It “owns” some rectangular area of the user’s screen. It can draw whatever it wants and respond to keyboard and mouse events in that area. When the web browser loads a page that contains a Java applet, it knows how to load the classes of the applet and run them.

This chapter describes how applets work and how to put them in web pages. You’ll learn how to use Sun’s Java Plug-In to take advantage of the latest Java features. Finally, we’ll cover the details of creating signed applets, which can step outside the typical applet security restrictions to do useful things, like reading and writing files.

The JApplet Class

If you’ve been waiting for a more detailed discussion of the applet class, here it is. A JApplet is something like a Panel with a mission. It is a GUI container that has some extra structure to allow it to be used in an “alien” environment, such as a Web browser. Applets also have a lifecycle that lets them act more like an application than a static component, such as a paragraph of text or an image. Although applets tend to be relatively simple, there’s no inherent restriction on their complexity. There’s no reason you couldn’t write an air traffic control system (well, let’s be less ambitious—a word processor) as an applet.

Originally, the java.applet.Applet class defined the functionality of an applet. The javax.swing.JApplet class is a simple extension of Applet that adds the plumbing necessary for Swing.

Structurally, an applet is a sort of wrapper for your Java code. In contrast to a standalone graphical Java application, which starts up from a main( ) method and creates a GUI, an applet is itself a component that expects to be dropped into someone else’s GUI. Thus, an applet can’t run by itself; it runs in the context of a web browser or a special applet viewer program (which is described later). Instead of having your application create a JFrame to hold your GUI, you stuff your application inside a JApplet (which is itself a Container), and let someone else add the applet to their GUI.

Applets are placed on web pages with the <APPLET> HTML tag, which we’ll discuss later in this chapter. At its simplest, you just specify the name of the applet class and a size for the applet:

<APPLET code=AnalogClock width=100 height=100></APPLET>

Pragmatically, an applet is an intruder into someone else’s environment, and therefore has to be treated with suspicion. The web browsers that run applets impose restrictions on what the applet is allowed to do. The restrictions are enforced by an applet security manager, which unsigned applets are not allowed to change. The browser also provides an “applet context,” which is additional support that helps the applet live within its restrictions.

Aside from that top-level structure and the security restrictions, there is no difference between an applet and an application. If your application can live within the restrictions imposed by a browser’s security manager, you can easily structure it to function as an applet and a standalone application. (We’ll show an example of an applet that can also be run as a standalone shortly.) Conversely, if you can supply all of the things that an applet requires from its environment, you can use applets within your standalone applications and within other applets (though this requires a bit of work).

As we said a moment ago, a JApplet expects to be embedded in GUI (perhaps a document) and used in a viewing environment that provides it with special resources. In all other respects, however, applets are just ordinary Panel objects. As Figure 20.1 shows, an applet is a kind of Panel. Like any other Panel, a JApplet can contain user interface components and use all the basic drawing and event-handling capabilities of the Component class. We draw on a JApplet by overriding its paint( ) method; we respond to events in the JApplet’s display area by providing the appropriate event listeners. Applets have additional structure that helps them interact with the viewer environment.

The java.applet package

Figure 20-1. The java.applet package

Applet Control

The Applet class contains four methods an applet can override to guide it through its lifecycle. The init( ) , start( ), stop( ), and destroy( ) methods are called by the appletviewer or a web browser to direct the applet’s behavior. init( ) is called once, after the applet is created. The init( ) method is where you perform basic setup like parsing parameters, building a user interface, and loading resources. Given what we’ve said about objects, you might expect the applet’s constructor would be the right place for such initialization. However, the constructor is meant to be called by the applet’s environment, for simple creation of the applet. This might happen before the applet has access to certain resources, like information about its environment. Therefore, an applet doesn’t normally do any work in its constructor; it relies on the default constructor for the JApplet class and does its initialization in the init( ) method.

The start( ) method is called whenever the applet becomes visible; it shouldn’t be a surprise then that the stop( ) method is called whenever the applet becomes invisible. init( ) is only called once in the life of an applet, but start( ) and stop( ) can be called any number of times (but always in the logical sequence). For example, start( ) is called when the applet is displayed, such as when it scrolls onto the screen; stop( ) is called if the applet scrolls off the screen or the viewer leaves the document. start( ) tells the applet it should be active. The applet may want to create threads, animate, or otherwise perform useful (or annoying) activity. stop( ) is called to let the applet know it should go dormant. Applets should cease CPU-intensive or wasteful activity when they are stopped and resume it when (and if) they are restarted. However, there’s no requirement that an invisible applet stop computing; in some applications, it may be useful for the applet to continue running in the background. Just be considerate of your user, who doesn’t want an invisible applet dragging down system performance. There are user tools that help to monitor and squash rogue applets in a web browser.

Finally, the destroy( ) method is called to give the applet a last chance to clean up before it’s removed—some time after the call to stop( ). For example, an applet might want to close down suspended communications channels or remove graphics frames. Exactly when destroy( ) is called depends on the browser; Netscape calls destroy( ) just prior to deleting the applet from its cache. This means that although an applet can cling to life after being told to stop( ), how long it can go on is unpredictable. If you want to maintain your applet as the user progresses through other activities, consider putting it in an HTML frame, so that it remains visible and won’t be told to stop( ).

The Applet Security Sandbox

Applets are quarantined within the browser by an applet SecurityManager. The SecurityManager is part of the web browser or applet viewer. It is installed before the browser loads any applets and implements the basic restrictions that let the user run untrusted applets safely. Remember, aside from basic language robustness, there are no inherent security restrictions on a standalone Java application. It is the browser’s responsibility to install a special security manager and limit what applets are allowed to do.

Most browsers impose the following restrictions on untrusted applets:

  • Untrusted applets cannot read or write files on the local host.

  • Untrusted applets can open network connections (sockets) only to the server from which they originated.

  • Untrusted applets cannot start other processes on the local host.

  • Untrusted applets cannot have native methods.

The motivation for these restrictions should be fairly obvious: you clearly wouldn’t want a program coming from some random Internet site to access your files or run arbitrary programs. Although untrusted applets cannot directly read and write files on the client side or talk to arbitrary hosts on the network, applets can work with servers to store data and communicate. For example, an applet can use Java’s RMI (Remote Method Invocation) facility to do processing on its server. An applet can communicate with other applets on the Net by proxy through its server.

Trusted applets

Newer versions of Java make it possible to sign archive files that contain applets. Because a signature identifies the applet’s origin unambiguously, we can now distinguish between “trusted” applets (i.e., applets that come from a site or person you trust not to do anything harmful) and run-of-the-mill “untrusted” applets. In browser environments that support signing, trusted applets can be granted permission to “go outside” of the applet security sandbox. Trusted applets can be allowed to do most of the things that standalone Java applications can do: read and write files, open network connections to arbitrary machines, and interact with the local operating system by starting processes. Trusted applets still can’t have native methods, but including native methods in an applet would make it unportable, and would therefore be a bad idea.

Chapter 3, discussed how to package your applet’s class files and resources into a JAR file. Later in this chapter, I’ll show you how to sign an applet with your digital signature.

Getting Applet Resources

An applet must communicate with its browser or applet viewer. For example, it must get its parameters from the HTML document in which it appears. An applet may also need to load images, audio clips, and other items. It may also want to ask the viewer about other applets on the same HTML page in order to communicate with them. To get resources from the environment, applets use the AppletStub and AppletContext interfaces. Unless you’re writing a browser or some other application that loads and runs applets, you won’t have to implement these interfaces, but you do use them within your applet.

Applet parameters

An applet gets its parameters from the <PARAM> tags placed inside the <APPLET> tag in the HTML document, as we’ll describe later. Inside the applet, you can retrieve these parameters using Applet’s getParameter( ) method. For example, the following code reads the imageName and sheep parameters from its HTML page:

String imageName = getParameter( "imageName" );  
try  { 
    int numberOfSheep = Integer.parseInt(getParameter( "sheep" ));  
} catch ( NumberFormatException e ) { /* use default */ }

A friendly applet will provide information about the parameters it accepts through its getParameterInfo( ) method. getParameterInfo( ) returns an array of string arrays, listing and describing the applet’s parameters. For each parameter, three strings are provided: the parameter name, its possible values or value types, and a verbose description. For example:

public String [][] getParameterInfo( ) { 
  String [][] appletInfo =  {
      {"logo",   "url",  "Main logo image"},
      {"timer", "int",   "Time to wait before becoming annoying"}, 
      {"flashing", "constant|intermittant", "Flag for how to flash"}
  };
  return appletInfo;
}

Applet resources

An applet can find where it lives by calling the getDocumentBase( ) and getCodeBase( ) methods. getDocumentBase( ) returns the base URL of the document in which the applet appears; getCodeBase( ) returns the base URL of the Applet’s class files. An applet can use these to construct relative URLs from which to load other resources like images, sounds, and other data. The getImage( ) method takes a URL and asks for an image from the viewer environment. The image may be pulled from a cache or loaded asynchronously when later used. The getAudioClip( ) method, similarly, retrieves sound clips.

The following example uses getCodeBase( ) to construct a URL and load a properties configuration file, located in the same remote directory as the applet’s class file:

Properties props = new Properties( );  
try { 
  URL url = new URL(getCodeBase( ), "appletConfig.props"); 
  props.load( url.openStream( ) );  
} catch ( IOException e ) { /* failed */ }

A better way to load resources is by calling the getResource( ) and getResourceAsStream( ) methods of the Class class, which search the applet’s JAR files (if any) as well as its codebase. The following code loads the properties file appletConfig.props:

Properties props = new Properties( );  
try { 
  props.load( getClass( ).getResourceAsStream("appletConfig.props") );
} catch ( IOException e ) { /* failed */ }

Driving the browser

The status line is a blurb of text that usually appears somewhere in the viewer’s display, indicating a current activity. An applet can request that some text be placed in the status line with the showStatus( ) method. (The browser isn’t required to do anything in response to this call, but most browsers will oblige you. )

An applet can also ask the browser to show a new document. To do this, the applet makes a call to the showDocument(url) method of the AppletContext. You can get a reference to the AppletContext with the applet’s getAppletContext( ) method. Calling showDocument(url) replaces the currently showing document, which means that your currently running applet will be stopped.

Another version of showDocument( ) takes an additional String argument to tell the browser where to display the new URL:

getAppletContext( ).
                  
                  showDocument( url, name );

The name argument can be the name of an existing labeled HTML frame; the document referenced by the URL will be displayed in that frame. You can use this method to create an applet that “drives” the browser to new locations dynamically, but keeps itself active on the screen in a separate frame. If the named frame doesn’t exist, the browser will create a new top-level window to hold it. Alternatively, name can have one of the following special values:

self

Show in the current frame

_parent

Show in the parent of our frame

_top

Show in outermost (top-level) frame

_blank

Show in a new top-level browser window

Both showStatus( ) and showDocument( ) requests may be ignored by a cold-hearted viewer or web browser .

Inter-applet communication

Applets that are embedded in documents loaded from the same location on a web site can use a simple mechanism to locate one another (rendezvous). Once an applet has a reference to another applet, it can communicate with it, just as with any other object, by invoking methods and sending events. The getApplet( ) method of the applet context looks for an applet by name:

Applet clock = getAppletContext( ).getApplet("theClock");

Give an applet a name within your HTML document using the name attribute of the <APPLET> tag. Alternatively, you can use the getApplets( ) method to enumerate all of the available applets in the pages.

The tricky thing with applet communications is that applets run inside of the security sandbox. An untrusted applet can only “see” and communicate with objects that were loaded by the same class loader. Currently, the only reliable criterion for when applets share a class loader is when they share a common base URL. For example, all of the applets contained in web pages loaded from the base URL of http://foo.bar.com/mypages/ should share a class loader and should be able to see each other. This would include documents such as mypages/foo.html and mypages/bar.html, but not mypages/morestuff/foo.html.

When applets do share a class loader, other techniques are possible too. As with any other class, you can call static methods in applets by name. So you could use static methods in one of your applets as a “registry” to coordinate your activities. There are also proposals that would allow you to have more control over when applets share a class loader and how their life cycles are managed.

Applets versus standalone applications

The following lists summarize the methods of the applet API. From the AppletStub interface:

boolean isActive( ); 
URL getDocumentBase( ); 
URL getCodeBase( ); 
String getParameter(String name); 
AppletContext getAppletContext( ); 
void appletResize(int width, int height);

From the AppletContext interface:

AudioClip getAudioClip(URL url); 
Image getImage(URL url); 
Applet getApplet(String name); 
Enumeration getApplets( ); 
void showDocument(URL url); 
public void showDocument(URL url, String target); 
void showStatus(String status);

These are the methods that are provided by the applet viewer environment. If your applet doesn’t happen to use any of them, or if you can provide alternatives to handle special cases (such as loading images), then your applet could be made able to function as a standalone application as well as an applet. The basic idea is to add a main( ) method that provides a window (JFrame) in which the applet can run. Here’s an outline of the strategy:

//file: MySuperApplet.java
import java.applet.Applet;
import java.awt.*;
import javax.swing.*;

public class MySuperApplet extends JApplet { 

    // applet's own code, including constructor
    // and init() and start( ) methods

    public static void main( String [] args ) { 
        // instantiate the applet
        JApplet theApplet = new MySuperApplet( ); 

        // create a window for the applet to run in
        JFrame theFrame = new JFrame( ); 
        theFrame.setSize(200,200); 

        // place the applet in the window
        theFrame.getContentPane( ).add("Center", theApplet); 

        // start the applet
        theApplet.init( ); 
        theApplet.start( ); 

        // display the window
        theFrame.setVisible(true); 
    } 
}

Here we get to play “applet viewer” for a change. We have created an instance of the class, MySuperApplet, using its constructor—something we don’t normally do—and added it to our own JFrame. We call its init( ) method to give the applet a chance to wake up and then call its start( ) method. In this example, MySuperApplet doesn’t implement init( ) and start( ), so we’re calling methods inherited from the Applet class. This is the procedure that an applet viewer would use to run an applet.(If we wanted to go further, we could implement our own AppletContext and AppletStub and set them in the JApplet before startup.)

Trying to make your applets into applications as well often doesn’t make sense and is not always trivial. We show this example only to get you thinking about the real differences between applets and applications. It is probably best to think in terms of the applet API until you have a need to go outside it. Remember that trusted applets can do almost all of the things that applications can. It may be wiser to make an applet that requires trusted permissions than an application.

Get Learning Java now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.