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.
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 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( ).
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.
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.
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.
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; }
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 */ }
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
.
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.
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.