THIS chapter talks about the basics of applets, advantages of applets over applications, how to load applets in a Web page, how to convert applications to applets, and how applets work.
An applet is a special kind of Java program that a browser enabled with Java technology can download from the Internet and run. An applet is typically embedded inside a Web page and runs in the context of the browser. An applet must be a subclass of the java.applet.Applet
class, which provides the standard interface between the applet and the browser environment.
Swing provides a special subclass of Applet, called javax.swing.JApplet
, which should be used for all applets that use Swing components to construct their GUIs.
By calling certain methods, a browser manages an applet’s life cycle if an applet is loaded in a Web page.
• Life Cycle of an Applet
Basically, there are four methods in the Applet
class on which any applet is built:
init
. This method is intended for whatever initialization is needed for your applet. It is called after the param attributes of the applet tag.
start
. This method is automatically called after init method. It is also called whenever user returns to the page containing the applet after visiting other pages.
stop
. This method is automatically called whenever the user moves away from the page containing applets. You can use this method to stop an animation.
destroy
. This method is only called when the browser shuts down normally.
Thus, the applet can be initialized once and only once, started and stopped one or more times in its life, and destroyed once and only once.
For more information, please refer to The Life Cycle of an Applet section (page 547).
• When to Write Applets versus Applications
In the early days of Java, one of the critical advantages that Java applets had over Java applications was that applets could be easily deployed over the Web while Java applications required a more cumbersome installation process. Additionally, since applets are downloaded from the Internet, by default they have to run in a restricted security environment, called the “sandbox,” to ensure they don’t perform any destructive operations on the user’s computer, such as reading/writing to the filesystem.
However, the introduction of Java Web Start (see Chapter 17) has made it possible for Java applications to also be easily deployed over the Web, as well as run in a secure environment. This means that the predominant difference between a Java applet and a Java application is that an applet runs in the context of a Web browser, being typically embedded within an HTML page, while a Java application runs stand-alone, outside the browser. Thus, applets are particularly well suited for providing functions in a Web page that require more interactivity or animation than HTML can provide, such as a graphical game, complex editing, or interactive data visualization. The end user is able to access the functionality without leaving the browser.
• Loading Applets in a Web Page
In order to load an applet in a Web page, you must specify the applet class with appropriate applet tags. A simple example is below:
<applet code=AppletWorld.class width="200" height="200"> </applet>
For development and testing purposes, you can run your applet using the lightweight appletviewer
application that comes with the JDK. For example, if AppletWorld.html
is the HTML file name, then you run the command as:
appletviewer AppletWorld.html
Once you know your applet runs within the appletviewer
, it is important to test your applet running in a Web browser by loading the applet’s Web page into the browser window. The browser can retrieve the class files either from the Internet or from the local working directory used during development. If you make changes to your applet’s code while it is loaded in the browser, then you must recompile the applet and press the Shift + Reload button in the browser to load the new version.
This chapter is intended to get you started with applets and Java Plug-in, and it does not include all available documentation. For more information about applets, see the Java Plug-in Developer Guide.[1]
Run the HelloWorld applet[2] in the online tutorial or compile and run the applet yourself (Figure 18.1). It is a simple Java class that prints the string “Hello World” in small rectangle.
Following is the source code for the HelloWorld applet:[3]
import javax.swing.JApplet; import java.awt.Graphics; public class HelloWorld extends JApplet { public void paint(Graphics g) { g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); g.drawString("Hello world!", 5, 15); } }
An applet such as this is typically managed and run by Java Plug-in. Java Plug-in, which is automatically included when you download the Java SE Runtime Environment (JRE), extends the functionality of a Web browser, allowing applets to be run under Sun’s Java SE Runtime Environment (JRE) rather than the Java Runtime Environment that comes with the Web browser. It works with the Mozilla family of browsers and with Internet Explorer.
• Converting Applications to Applets
An application is a stand-alone program consisting of at least one class with a main
method. Applets differ significantly from applications. First, applets do not have a main
method that is automatically called to begin the program. Instead, several methods are called at different points in the execution of an applet. The difference between Java applets and applications lies in how they are run. Applications are usually run by loading the application’s main class file with a Java interpreter, such as the java tool in the JDK 6.
The basic steps to follow to convert an application program into an applet program are:
You need to create a subclass of java.applet.Applet
in which you override the init
method to initialize your applet’s resources the same way the main
method initializes the application’s resources.
init
might be called more than once and should be designed accordingly. Moreover, the top-level Panel
needs to be added to the applet in init
; usually it was added to a Frame in main
. That’s it!
You will understand how to convert an application program into an applet by going through a sample application program SwingUI.java
[4] and its corresponding applet program.[5]
When you compare these two programs, you may come up with the following major differences between the two:
The applet class is declared public
so appletviewer
can access it.
The applet class descends from Applet
/JApplet
, and the application class descends from Frame
/JFrame
.
The applet version has no main
method.
The application constructor is replaced in the applet by start
and init
methods.
GUI components are added directly to the Applet
, whereas in an application, GUI components are added to the content pane of its JFrame
object.
The first bold line of the following listing begins a block that defines the HelloWorld
class:
import javax.swing.JApplet; import java.awt.Graphics; public class HelloWorld extends JApplet { public void paint(Graphics g) { g.drawRect(0, 0, getSize().width - 1, getSize().height - 1); g.drawString("Hello world!", 5, 15); } }
Applets inherit a great deal of functionality from the Applet
or JApplet
class, including the abilities to communicate with the browser and to present a graphical user interface (GUI) to the user.
An applet that will be using GUI components from Swing (Java’s GUI toolkit) should extend the javax.swing.JApplet
base class, which provides the best integration with Swing’s GUI facilities.
JApplet
provides the same “RootPane” top-level component structure as Swing’s JFrame
and JDialog
components, whereas Applet
provides just a simple panel. See How to Use Root Panes[6] for more details on how to utilize this feature.
An applet may extend java.applet.Applet
when it makes no use of Swing’s GUI components. This may be the case if the applet does all its own rendering using the Java graphics libraries (such as with graphing or gaming) and/or uses only AWT components.
Run the Simple
applet[7] (Figure 18.2).
The following is the source code for the Simple
.[8] The Simple
applet displays a descriptive string whenever it encounters a major milestone in its life, such as when the user first visits the page that the applet is on. The pages that follow use the Simple
applet and build upon it to illustrate concepts that are common to many applets. If you find yourself baffled by the Java source code, you might want to go to Chapter 2 to learn about the language.
/* * Java SE 6 Version */ import java.applet.Applet; import java.awt.Graphics; // No need to extend JApplet, since we don't add // any components; we just paint. public class Simple extends Applet { StringBuffer buffer; public void init() { buffer = new StringBuffer(); addItem("initializing... "); } public void start() { addItem("starting... "); } public void stop() { addItem("stopping... "); } public void destroy() { addItem("preparing for unloading..."); } private void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint(Graphics g) { // Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); // Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } }
In this example, we extend the Applet
class, not the Swing JApplet
class, as we do not need to add Swing components to this applet.
You should see “initializing … starting … ” above, as the result of the applet being loaded. When an applet is loaded, here’s what happens:
An instance of the applet’s controlling class (an Applet
subclass) is created.
The applet initializes itself.
The applet starts running.
When the user leaves the page—for example, to go to another page—the browser stops the applet. When the user returns to the page, the browser starts the applet.
Some browsers let the user reload applets, which consists of unloading the applet and then loading it again. Before an applet is unloaded, it’s given the chance to stop itself and then to perform a final cleanup, so that the applet can release any resources it holds. After that, the applet is unloaded and then loaded again, as described in the Loading the Applet section (page 549).
If your browser or other applet viewer lets you easily reload applets, reload the applet. Look at the Displaying Diagnostics to the Standard Output and Error Streams section (page 583) to see what happens when you reload the applet. (See the Displaying Short Status Strings section, page 561, for information about the standard output.) You should see “stopping …” and “preparing for unloading …” when the applet is unloaded. You can’t see this in the applet GUI because the applet is unloaded before the text can be displayed. When the applet is reloaded, you should see “initializing …” and “starting …”, just like when you loaded the applet for the first time.
The Simple
applet, like every other applet, features a subclass of the Applet
class. The Simple
class overrides four Applet
methods so that it can respond to major events:
init
. To initialize the applet each time it’s loaded (or reloaded).
start
. To start the applet’s execution, such as when the applet is loaded or when the user revisits a page that contains the applet.
stop
. To stop the applet’s execution, such as when the user leaves the applet’s page or quits the browser.
destroy
. To perform a final cleanup in preparation for unloading.
Following is the interface for these methods:
public class Simple extends JApplet { ... public void init() { ... } public void start() { ... } public void stop() { ... } public void destroy() { ... } ... }
The init
, start
, stop
, and destroy
methods are discussed and used throughout this tutorial. For more information, you can also refer to the JApplet
API Specification.[9]
Not every applet needs to override every one of these methods. Some very simple applets override none of them. For example, the “Hello World” applet (page 6) doesn’t override any of these methods, since it doesn’t do anything except draw itself.
The “Hello World” applet just displays a string once, using its paint
method. (The paint
method is described on page 552.) Most applets, however, do more.
The init
method is useful for one-time initialization that doesn’t take very long. In general, the init
method should contain the code that you would normally put into a constructor. The reason applets shouldn’t usually have constructors is that an applet isn’t guaranteed to have a full environment until its init
method is called. For example, the Applet
image-loading methods simply don’t work inside of an applet constructor. The init
method, on the other hand, is a great place to call the image-loading methods, since the methods return quickly.
Some browsers sometimes call the init
method more than once after the applet has been loaded. See The Life Cycle of an Applet section (page 547) for more details.
Every applet that does something after initialization (except in direct response to user actions) must override the start
method. The start
method either performs the applet’s work or (more likely) starts up one or more threads to perform the work. You’ll learn more about threads in the Threads in Applets section (page 585). You’ll learn more about handling the events that represent user actions in the Methods for Drawing and Event Handling section (page 552).
Most applets that override start
should also override the stop
method. The stop
method should suspend the applet’s execution so that it doesn’t take up system resources when the user isn’t viewing the applet’s page. For example, an applet that displays animation should stop trying to draw the animation when the user isn’t looking at it.
Many applets don’t need to override the destroy
method, since their stop
method (which is called before destroy
) does everything necessary to shut down the applet’s execution. However, destroy
is available for applets that need to release additional resources.
To draw the applet’s representation within a browser page, you use the paint
method.
For example, the Simple
applet defines its onscreen appearance by overriding the paint
method:
public void paint(Graphics g) { // Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); // Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); }
Applets inherit the paint
method from the Abstract Window Toolkit (AWT) Container
class.
Applets inherit a group of event-handling methods from the Container
class.
The Container
class defines several methods, such as processKeyEvent
and processMouseEvent
, for handling particular types of events, and then one catch-all method called processEvent
.
To react to an event, an applet must override the appropriate event-specific method. For example, the following program, SimpleClick
,[10] implements a MouseListener
and overrides the mouseClicked
method:
/* * Java(TM) SE 6 version. */ import java.awt.event.MouseListener; import java.awt.event.MouseEvent; import java.applet.Applet; import java.awt.Graphics; // No need to extend JApplet, since we don't add // any components; we just paint. public class SimpleClick extends Applet implements MouseListener { StringBuffer buffer; public void init() { addMouseListener(this); buffer = new StringBuffer(); addItem("initializing... "); } public void start() { addItem("starting... "); } public void stop() { addItem("stopping... "); } public void destroy() { addItem("preparing for unloading..."); } void addItem(String newWord) { System.out.println(newWord); buffer.append(newWord); repaint(); } public void paint(Graphics g) { // Draw a Rectangle around the applet's display area. g.drawRect(0, 0, getWidth() - 1, getHeight() - 1); // Draw the current string inside the rectangle. g.drawString(buffer.toString(), 5, 15); } // The following empty methods could be removed // by implementing a MouseAdapter (usually done // using an inner class). public void mouseEntered(MouseEvent event) { } public void mouseExited(MouseEvent event) { } public void mousePressed(MouseEvent event) { } public void mouseReleased(MouseEvent event) { } public void mouseClicked(MouseEvent event) { addItem("click!... "); } }
Run the resulting applet[11] (Figure 18.3). When you click within its rectangle, it displays the word “click! …”.
The Simple
applet’s display code (implemented in its paint
method) is flawed: It doesn’t support scrolling. Once the text it displays reaches the end of the display rectangle, you can’t see any new text. Figure 18.4 shows an example of the problem.
The simplest cure for this problem is to use a pre-made user interface (UI) component that has the right behavior.
This section glosses over many details. To really learn about using UI components, read Creating a GUI with JFC/Swing.[12]
Swing supplies the following UI components (the class that implements each component is listed in parentheses):
Buttons (javax.swing.JButton
)
Checkboxes (javax.swing.JCheckBox
)
Single-line text fields (javax.swing.JTextField
)
Larger text display and editing areas (javax.swing.JTextArea
)
Labels (javax.swing.JLabel
)
Lists (javax.swing.JList
)
Pop-ups (javax.swing.Popup
)
Scrollbars (javax.swing.JScrollBar
)
Sliders (javax.swing.JSlider
)
Drawing areas (java.awt.Canvas
)
Menus (javax.swing.JMenu
, javax.swing.JMenuBar
, javax.swing. JMenuItem
, javax.swing.JCheckBoxMenuItem
)
Containers (javax.swing.JPanel
, javax.swing.JWindow
, and its subclasses)
Because the JApplet
class inherits from the AWT Container
class, it’s easy to add components to applets and to use layout managers to control the components’ onscreen positions. Here are some of the Container
methods an applet can use:
add
. Adds the specified Component
.
remove
. Removes the specified Component
.
setLayout
. Sets the layout manager.
To make the Simple
applet use a scrolling, non-editable text field, we can use the JTextField
class. Here is the revised ScrollingSimple class
:[13]
/* * Java(TM) SE 6 version. */ import javax.swing.JApplet; import javax.swing.JTextField; import javax.swing.SwingUtilities; // Since we're adding a Swing component, we now need to // extend JApplet. We need to be careful to access // components only on the event-dispatching thread. public class ScrollingSimple extends JApplet { JTextField field; public void init() { // Execute a job on the event-dispatching thread: // creating this applet's GUI. try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { createGUI(); } }); } catch (Exception e) { System.err.println("createGUI didn't " + "successfully complete"); } addItem(false, "initializing... "); } private void createGUI() { // Create the text field and make it uneditable. field = new JTextField(); field.setEditable(false); // Set the layout manager so that the text field will be // as wide as possible. setLayout(new java.awt.GridLayout(1,0)); // Add the text field to the applet. add(field); } public void start() { addItem(false, "starting... "); } public void stop() { addItem(false, "stopping... "); } public void destroy() { addItem(false, "preparing for unloading..."); cleanUp(); } private void cleanUp() { // Execute a job on the event-dispatching thread: // taking the text field out of this applet. try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { remove(field); } }); } catch (Exception e) { System.err.println("cleanUp didn't " + "successfully complete"); } field = null; } private void addItem(boolean alreadyInEDT, String newWord) { if (alreadyInEDT) { addItem(newWord); } else { final String word = newWord; // Execute a job on the event-dispatching thread: // invoking addItem(newWord). try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { addItem(word); } }); } catch (Exception e) { System.err.println("addItem didn't " + "successfully complete"); } } } // Invoke this method ONLY from the event-dispatching thread. private void addItem(String newWord) { String t = field.getText(); System.out.println(newWord); field.setText(t + newWord); } }
The createGUI
method creates an uneditable text field (a JTextField
instance). It sets the applet’s layout manager to one that makes the text field as wide as possible (you can learn about layout managers in Laying Out Components within a Container[14]) and then adds the text field to the applet.
Run the resulting applet[15] (Figure 18.5).
This section gives an overview of both the restrictions applets face and the special capabilities they have. You will find more details in the Security Restrictions section (page 578).
Every browser implements security policies to keep applets from compromising system security. This section describes the security policies that current browsers adhere to. However, the implementation of the security policies differs from browser to browser. Also, security policies are subject to change. For example, if a browser is developed for use only in trusted environments, then its security policies will likely be much more lax than those described here.
Current browsers impose the following restrictions on any applet that is loaded over the network:
An applet cannot load libraries or define native methods.
It cannot ordinarily read or write files on the host that’s executing it.
It cannot make network connections except to the host that it came from.
Each browser has a SecurityManager
object that implements its security policies. When a SecurityManager
detects a violation, it throws a SecurityException
. Your applet can catch this SecurityException
and react appropriately.
The java.applet
package provides an API that gives applets some capabilities that applications do not have.
Here are some other things that current browers and other applet viewers let applets do:
Applets can usually make network connections to the host they came from.
Applets running within a Web browser can easily cause HTML documents to be displayed.
Applets can invoke public methods of other applets on the same page.
Applets that are loaded from the local file system (from a directory in the user’s CLASSPATH
) have none of the restrictions that applets loaded over the network do.
The applet API lets you take advantage of the close relationship that applets have with Web browsers. The API is provided by the javax.swing.JApplet
class and the java.applet.AppletContext
interface.
Applets can use these APIs to do the following:
Be notified by the browser of milestones.
Load data files specified relative to the URL of the applet or the page in which it is running.
Display short status strings.
Make the browser display a document.
Find other applets running in the same page.
Play sounds.
Get parameters specified by the user in the <APPLET>
tag.
This section discusses each of these topics in turn, except for the milestone methods (init
, start
, and so on), which are explained in the Methods for Milestones section (page 550). For information about how to use non-applet-specific APIs in an applet, see the Practical Considerations When Writing Applets section (page 578).
Whenever an applet needs to load some data from a file that’s specified with a relative URL (a URL that doesn’t completely specify the file’s location), the applet usually uses either the code base or the document base to form the complete URL.
The code base, returned by the JApplet getCodeBase
method, is a URL that specifies the directory from which the applet’s classes were loaded.
The document base, returned by the JApplet getDocumentBase
method, specifies the directory of the HTML page that contains the applet.
Unless the <APPLET>
tag specifies a code base, both the code base and document base refer to the same directory on the same server.
Data that the applet might need, or needs to rely on as a backup, is usually specified relative to the code base. Data that the applet developer specifies, often by using parameters, is usually specified relative to the document base.
For security reasons, browsers limit the URLs from which untrusted applets can read. For example, most browsers don’t allow untrusted applets to use “..” to get to directories above the code base or document base. Also, since untrusted applets can’t read files except those on the applet’s originating host, the document base isn’t generally useful if the document and the untrusted applet are on different servers.
The JApplet
class defines convenient forms of image-loading and sound-loading methods that let you specify images and sounds relative to a base URL. For example, assume an applet is set up with one of the directory structures shown in Figure 18.6.
To create an Image
object using the a.png
image file under imgDir
, the applet can use the following code:
Image image = getImage(getCodeBase(), "imgDir/a.png");
All browsers allow applets to display a short status string. All applets on the page, as well as the browser itself, share the same status line.
You should never put crucial information in the status line. If many users might need the information, it should instead be displayed within the applet area. If only a few sophisticated users might need the information, consider displaying the information on the standard output (see the Displaying Diagnostics to the Standard Output and Error Streams section, page 583).
The status line is not usually very prominent, and it can be overwritten by other applets or by the browser. For these reasons, it’s best used for incidental, transitory information. For example, an applet that loads several image files might display the name of the image file it’s currently loading.
Applets display status lines with the showStatus
[16] method, inherited in the JApplet
class from the Applet
class.
Here’s an example of its use:
showStatus("MyApplet: Loading image file " + file);
Have you ever wanted an applet to display formatted HTML text? There’s an easy way to do it: Ask the browser to display the text for you.
With the AppletContext showDocument
methods, an applet can tell the browser which URL to show and in which browser window.
Here are the two forms of showDocument
:
public void showDocument(java.net.URL url) public void showDocument(java.net.URL url, String targetWindow)
The one-argument form of showDocument
simply tells the browser to display the document at the specified URL, without specifying the window to display the document in.
In this discussion, frame refers not to a Swing JFrame
, but to an HTML frame within a browser window.
The two-argument form of showDocument
lets you specify which window or HTML frame to display the document in. The second argument can have the values listed below:
"_blank"
. Display the document in a new, nameless window.
"
windowName
"
. Display the document in a window named windowName. This window is created if necessary.
"_self"
. Display the document in the window and frame that contain the applet.
"_parent"
. Display the document in parent frame of the applet’s frame. If the applet frame has no parent frame, this acts the same as "_self"
.
"_top"
. Display the document in the top-level frame. If the applet’s frame is the top-level frame, this acts the same as "_self"
.
Run an applet[17] that lets you try every option of both forms of showDocument
(Figure 18.7). The applet brings up a window that lets you type in a URL and choose any of the showDocument
options (Figure 18.8). When you press Return or click the Show document button, the applet calls showDocument
.
Below is the applet code that calls showDocument
:[18]
...// In an Applet subclass: urlWindow = new URLWindow(getAppletContext()); ... class URLWindow extends Frame { ... public URLWindow(AppletContext appletContext) { ... this.appletContext = appletContext; ... } ... public boolean action(Event event, Object o) { ... String urlString = /* user-entered string */; URL url = null; try { url = new URL(urlString); } catch (MalformedURLException e) { ...// Inform the user and return... } if (url != null) { if (/* user doesn't want to specify the window */) { appletContext.showDocument(url); } else { appletContext.showDocument(url, /* user-specified window */ ); } } ...
Applets can find other applets and send messages to them, with the following security restrictions:
Many browsers require that the applets originate from the same server.
Many browsers further require that the applets originate from the same directory on the server (the same code base).
The Java API requires that the applets be running on the same page, in the same browser window.
Some browsers let applets invoke methods on other applets—even applets on different pages in the same browser—as long as all of the applets come from the same code base. This method of interapplet communication isn’t supported by the Java API, so it’s possible that it will not be supported by all browsers.
An applet can find another applet either by looking it up by name (using the AppletContext getApplet
method) or by finding all the applets on the page (using the AppletContext getApplets
method). Both methods, if successful, give the caller one or more Applet
objects. Once the caller finds an Applet
object, the caller can invoke methods on the object.
The getApplet
method looks through all of the applets on the current page to see if one of them has the specified name. If so, getApplet
returns the applet’s Applet
object.
By default, an applet has no name. For an applet to have a name, one must be specified in the HTML code that adds the applet to a page. You can specify an applet’s name in two ways:
By specifying a NAME
attribute within the applet’s <APPLET>
tag. For example:
<APPLET CODEBASE=example/ CODE=Sender.class
WIDTH=450
HEIGHT=200
NAME="buddy" >
...
</APPLET>
By specifying a NAME
parameter with a <PARAM>
tag. For example:
<APPLET CODEBASE=example/ CODE=Receiver.class
WIDTH=450
HEIGHT=50>
<PARAM NAME="name" value="old pal">
...
</APPLET>
Although at least one browser enabled with Java technology conducts a case-sensitive search, the expected behavior is for the getApplet
method to perform a case-insensitive search. For example, getApplet("old pal")
and getApplet("OLD PAL")
should both find an applet named “Old Pal”.
Two applets[19] illustrate lookup by name (Figures 18.9 and 18.10). The first, the Sender, looks up the second, the Receiver. When the Sender finds the Receiver, the Sender sends a message to the Receiver by invoking one of the Receiver’s methods (passing the Sender’s name as an argument). The Receiver reacts to this method call by changing its leftmost text string to “Received message from sender-name!”.
Click the Send message button of the first applet (the Sender). Some status information will appear in the Sender’s window, and the Receiver will confirm (with its own status string) that it received a message, After you’ve read the Receiver status string, press the Receiver’s Clear button to reset the Receiver. In the Sender’s text field labeled “Receiver name:,” type in buddy
and press Return. Since “buddy” is the Sender’s own name, the Sender will find an applet named buddy but won’t send it a message, since it isn’t a Receiver instance.
The code the Sender program[20] uses to look up and communicate with the Receiver is listed below. Code that you can use without change in your own applet is in bold font:
Applet receiver = null; String receiverName = nameField.getText(); // Get name // to search for. receiver = getAppletContext().getApplet(receiverName);
The Sender goes on to make sure that the Receiver was found and that it’s an instance of the correct class (Receiver
[21]). If all goes well, the Sender sends a message to the Receiver:
if (receiver != null) { // Use the instanceof operator to make sure the applet // we found is a Receiver object. if (!(receiver instanceof Receiver)) { status.appendText("Found applet named " + receiverName + ", " + "but it's not a Receiver object. "); } else { status.appendText("Found applet named " + receiverName + ". " + " Sending message to it. "); // Cast the receiver to be a Receiver object // (instead of just an Applet object) so that the // compiler will let us call a Receiver method. ((Receiver)receiver).processRequestFrom(myName); } } ...
From an applet’s point of view, its name is stored in a parameter named NAME
. It can get the value of the parameter using the Applet getParameter
method. For example, Sender gets its own name with the following code:
myName = getParameter("NAME");
For more information on using getParameter
, see the Writing the Code to Support Parameters section (page 573).
The example applets in this section perform one-way communication—from the Sender to the Receiver. If you want your receiver to be able to send messages to the sender, then you just need to have the sender give a reference to itself (this
) to the receiver. For example:
((Receiver)receiver).startCommunicating(this);
The getApplets
method returns a list (an Enumeration
,[22] to be precise) of all the applets on the page. For security reasons, many browsers and applet viewers implement getApplets
so that it returns only those applets that originated from the same host as the applet calling getApplets
. Run an applet that simply lists all the applets it can find on this page (Figure 18.11).[23]
Below are the relevant parts of the method that calls getApplets
:[24]
public void printApplets() { // Enumeration will contain all applets on this page // (including this one) that we can send messages to. Enumeration e = getAppletContext().getApplets(); ... while (e.hasMoreElements()) { Applet applet = (Applet)e.nextElement(); String info = ((Applet)applet).getAppletInfo(); if (info != null) { textArea.appendText("- " + info + " "); } else { textArea.appendText("- " + applet.getClass().getName() + " "); } } ... }
The JApplet
class in the Java Swing package (javax.swing
) and the AudioClip
[25] interface in the Java Applet package (java.applet
) provide basic support for playing sounds. Currently, the Java API supports only one sound format: 8 bit, ν-law, 8000 Hz, one-channel, Sun “.au” files. You can create these on a Sun workstation using the audiotool
application. You can convert files from other sound formats using an audio format conversion program.
Below are the sound-related Applet
methods. The two-argument form of each method takes a base URL, which is usually returned by either getDocumentBase
or getCodeBase
, and the location of the sound file relative to the base URL:
getAudioClip(URL)
, getAudioClip(URL, String)
. Return an object that implements the AudioClip
interface.
play(URL)
, play(URL, String)
. Play the AudioClip
corresponding to the specified URL.
The AudioClip
interface defines the following methods:
loop
. Starts playing the clip repeatedly.
play
. Plays the clip once.
stop
. Stops the clip. Works with both looping and one-time sounds.
Run an applet called SoundExample[26] that illustrates a few things about sound (Figure 18.12). Note that, for instructional purposes, the applet adds up to 10 seconds to the load time for each sound. If the sounds were larger or the user’s connection slower than ours, these delays might be realistic.
The SoundExample applet provides an architecture for loading and playing multiple sounds in an applet. For this reason, it is more complex than necessary. Essentially, the sound loading and playing code boils down to this:
AudioClip onceClip, loopClip; onceClip = applet.getAudioClip(getCodeBase(), "bark.au"); loopClip = applet.getAudioClip(getCodeBase(), "train.au"); onceClip.play(); // Play it once. loopClip.loop(); // Start the sound loop. loopClip.stop(); // Stop the sound loop.
Since there’s nothing more annoying than an applet that continues to make noise after you’ve left its page, the SoundExample applet stops playing the continuously looping sound when the user leaves the page and resumes playing it when the user comes back. It does this by implementing its stop
and start
methods as follows:
public void stop() { // If one-time sound were long, we'd stop it here, too. // looping is a boolean instance variable that's initially // false. It's set to true when the "Start sound loop" button // is clicked and to false when the "Stop sound loop" or // "Reload sounds" button is clicked. if (looping) { loopClip.stop(); // Stop the sound loop. } } public void start() { if (looping) { loopClip.loop(); // Restart the sound loop. } }
The SoundExample applet features three classes:
A JApplet
subclass, SoundExample
,[27] that controls the applet’s execution.
A Hashtable
subclass, SoundList
,[28] that holds AudioClip
s. This is overkill for this applet, but if you were to write an applet that used lots of sound files, a class like this would be useful.
A Thread
subclass, SoundLoader
,[29] each instance of which loads an AudioClip
in the background. During the applet’s initialization, the applet preloads each sound by creating a SoundLoader
for it.
Preloading the sounds in a background thread (with SoundLoader
) improves the perceived performance by reducing the amount of time the user has to wait to be able to interact with the applet. It does this by reducing the amount of time spent in the init
method. If you simply called getAudioClip
in the applet’s init
method, it could take quite a while before getAudioClip
returned, meaning that the applet couldn’t perform the other statements in its init
method, and that the applet’s start
wouldn’t get called. (For this SoundExample applet, a delay in calling the start
method doesn’t matter.)
Another advantage of loading the sounds in a background thread is that it enables the applet to respond appropriately (and immediately) to user input that would normally cause a sound to play, even if that sound hasn’t been loaded yet. If you simply use the Applet play
method, for example, then the first time the user does something to make the applet play a particular sound, the applet’s drawing and event handling are frozen while the sound is loaded. Instead, this applet detects that the sound hasn’t been loaded yet and responds appropriately.
This example is discussed in more detail in the Threads in Applets: Examples section (page 586).
Parameters are to applets what command-line arguments are to applications. They allow the user to customize the applet’s operation. By defining parameters, you can increase your applet’s flexibility, making your applet work in multiple situations without recoding and recompiling it.
The next few sections discuss parameters from the applet programmer’s point of view. To learn about the user view of parameters, see the Specifying Parameters section (page 575).
This section guides you through the four questions you should ask as you implement parameters:
• | What should the applet let the user configure? |
• | What should the parameters be named? |
• | What kind of value should each parameter take? |
• | What should the default value of each parameter be? |
It ends with a discussion of the parameters defined in a sample <APPLET>
tag.
The parameters your applet should support depend on what your applet does and on how flexible you want it to be. Applets that display images might have parameters to specify the image locations. Similarly, applets that play sounds might have parameters to specify the sounds.
Besides parameters that specify resource locations (such as image and sound files), applets sometimes provide parameters for specifying details of the applet’s appearance or operation. For example, an animation applet might let the user specify the number of images shown per second. Or an applet might let the user change the strings the applet displays. Anything is possible.
Once you decide what parameters your applet will support, you need to figure out their names. Here are some typical parameter names:
SOURCE or SRC. For a data file such as an image file.
XXXSOURCE (for example, IMAGESOURCE). Used in applets that let the user specify more than one type of data file.
XXXS. For a parameter that takes a list of XXXs (where XXX might be IMAGE
, again).
NAME. Used only for an applet’s name. Applet names are used for interapplet communication, as described in the Sending Messages to Other Applets section (page 564).
Clarity of names is more important than keeping the name length short. Do not use names of <APPLET>
tag attributes, which are documented in the Using the applet
Tag section (page 595).
Although this tutorial usually refers to parameter names using ALL UPPERCASE, parameter names are case-insensitive. For example, IMAGESOURCE
and imageSource
both refer to the same parameter. Parameter values, on the other hand, are case-sensitive unless you take steps to interpret them otherwise, such as by using the String toLowerCase
method before interpreting the parameter’s value.
Parameter values are all strings. Whether or not the user puts quotation marks around a parameter value, that value is passed to your applet as a string. However, your applet can interpret the string in many ways.
Applets typically interpret a parameter value as one of the following types:
A URL
An integer
A floating-point number
A boolean value—typically “true”/“false” or “yes”/“no”
A string—for example, the string to use as a window title
A list of any of the above
Applets should attempt to provide useful default values for each parameter, so that the applet will execute even if the user doesn’t specify a parameter or specifies it incorrectly. For example, an animation applet should provide a reasonable setting for the number of images it displays per second. This way, if the user doesn’t specify the relevant parameter, the applet will still work well.
Here’s what a typical <APPLET>
tag looks like.
<APPLET CODE=SampleApplet.class CODEBASE=example WIDTH=350 HEIGHT=60> <PARAM NAME=windowClass VALUE=BorderWindow> <PARAM NAME=windowTitle VALUE="BorderLayout"> <PARAM NAME=buttonText VALUE="Click here to see a BorderLayout in action"> </APPLET>
When the user doesn’t specify a value for a parameter, the applet uses a reasonable default value. For example, if the user doesn’t specify the window’s title, the applet uses the window’s type as the title.
The next section shows you how to get parameter values from the user.
Applets use the Applet getParameter
method to get user-specified values for applet parameters. The getParameter
method is defined as follows:
public String getParameter(String name)
Your applet might need to convert the string that getParameter
returns into another form, such as an integer. The java.lang
package provides classes such as Integer that you can use to help with converting strings to primitive types. Here’s an example of converting a parameter’s value into an integer:
int requestedWidth = 0; ... String windowWidthString = getParameter("WINDOWWIDTH"); if (windowWidthString != null) { try { requestedWidth = Integer.parseInt(windowWidthString); } catch (NumberFormatException e) { // Use default width. } }
Note that if the user doesn’t specify a value for the WINDOWWIDTH
parameter, the above code uses a default value of 0, which the applet interprets as “use the window’s natural size.” It’s important that you supply default values wherever possible.
Besides using the getParameter
method to get values of applet-specific parameters, you can also use getParameter
to get the values of attributes of the applet’s <APPLET>
tag. See the Using the applet
Tag section (page 595) for a list of <APPLET>
tag attributes.
Now that you’ve provided all those nice parameters to the user, you need to help the user set the parameter values correctly. Of course, your applet’s documentation should describe each parameter and give the user examples and hints about setting them. Your job doesn’t stop there, though. You should also implement the getParameterInfo
method so that it returns information about your applet’s parameters. Browsers can use this information to help the user set your applet’s parameter values.
Below is an example of implementing the getParameterInfo
method:
public String[][] getParameterInfo() { String[][] info = { // Parameter Name Kind of Value Description {"imagesource", "URL", "a directory"}, {"startup", "URL", "displayed at startup"}, {"background", "URL", "displayed " + "as background"}, {"startimage", "int", "start index"}, {"endimage", "int", "end index"}, {"namepattern", "URL", "used to generate " + "indexed names"}, {"pause", "int", "milliseconds"}, {"pauses", "ints", "milliseconds"}, {"repeat", "boolean", "repeat or not"}, {"positions", "coordinates", "path"}, {"soundsource", "URL", "audio directory"}, {"soundtrack", "URL", "background music"}, {"sounds", "URLs", "audio samples"}, }; return info; }
As you can see, the getParameterInfo
method must return an array of three-String
arrays. In each three-String
array, the first string is the parameter name. The second string gives the user a hint about what general kind of value the applet needs for the parameter. The third string describes the meaning of the parameter.
This section tells you most of what you need to know to use the <APPLET>
tag. It starts by showing you the tag’s simplest form. It then discusses some of the most common additions to that simple form: the <PARAM>
tag, alternate HTML code and text, the CODEBASE
attribute, and the ARCHIVE
attribute. For a detailed description of the <APPLET>
tag, refer to the Using the applet
Tag section (page 595).
You should already have seen the simplest form of the <APPLET>
tag:
<APPLET CODE=AppletSubclass.class WIDTH=anInt HEIGHT=anInt> </APPLET>
This tag tells the browser to load the applet whose Applet
subclass is named AppletSubclass
, displaying it in an area of the specified width and height.
Some applets let the user customize the applet’s configuration with parameters, as described in the Defining and Using Applet Parameters section (page 570). For example, AppletButton
(an applet used throughout this tutorial to provide a button that brings up a window) allows the user to set the button’s text by specifying the value of a parameter named BUTTONTEXT
.
The developer provides the value of a parameter using a <PARAM>
tag. The <PARAM>
tags should appear just after the <APPLET>
tag for the applet they affect:
<APPLET CODE=AppletSubclass.class WIDTH=anInt HEIGHT=anInt> <PARAM NAME=parameter1Name VALUE=aValue> <PARAM NAME=parameter2Name VALUE=anotherValue> </APPLET>
Here’s an example of the <PARAM>
tag in use.
<APPLET CODE="Animator.class" WIDTH=460 HEIGHT=160> <PARAM NAME="imageSource" VALUE="images/Beans"> <PARAM NAME="backgroundColor" VALUE="0xc0c0c0"> <PARAM NAME="endImage" VALUE=10> <PARAM NAME="soundSource" VALUE="audio"> <PARAM NAME="soundtrack" VALUE="spacemusic.au"> <PARAM NAME="sounds" VALUE="1.au|2.au|3.au|4.au|5.au|6.au|7.au|8au|9.au|0.au"> <PARAM NAME="pause" VALUE=200> ... </APPLET>
Note the ellipsis points (“...
”) in the previous HTML example. What did the example leave out? It omitted alternate HTML code-HTML code interpreted only by browsers that don’t understand the <APPLET>
tag. Alternate HTML code is any text that appears between the <APPLET>
and </APPLET>
tags, after any <PARAM>
tags. Browsers enabled with Java technology ignore alternate HTML code.
To specify alternate text to browsers enabled with Java technology and other browsers that understand the <APPLET>
tag, use the ALT
attribute. If the browser can’t display an applet for some reason, it can display the applet’s ALT
text.
We use alternate HTML code throughout the online version of this tutorial to tell readers about the applets they’re missing. Often, the alternate HTML code includes one or more pictures of the applet. Here’s the complete HTML code for the Animator
example shown previously:
<APPLET CODE="Animator.class" WIDTH=460 HEIGHT=160 ALT="If you could run this applet, you'd see some animation"> <PARAM NAME="imageSource" VALUE="images/Beans"> <PARAM NAME="backgroundColor" VALUE="0xc0c0c0"> <PARAM NAME="endImage" VALUE=10> <PARAM NAME="soundSource" VALUE="audio"> <PARAM NAME="soundtrack" VALUE="spacemusic.au"> <PARAM NAME="sounds" VALUE="1.au|2.au|3.au|4.au|5.au|6.au|7.au|8au|9.au|0.au"> <PARAM NAME="pause" VALUE=200> Your browser is completely ignoring the <APPLET> tag! </APPLET>
A browser that doesn’t understand the <APPLET>
tag ignores everything in the previous HTML code except the line that starts with “Your”. A browser that does understand the <APPLET>
tag ignores everything on that line. If the applet-savvy browser can’t run the applet, it might display the ALT
text.
By default, a browser looks for an applet’s class and archive files in the same directory as the HTML file that has the <APPLET>
tag. (If the applet’s class is in a package, then the browser uses the package name to construct a directory path underneath the HTML file’s directory.) Sometimes, however, it’s useful to put the applet’s files somewhere else. You can use the CODEBASE
attribute to tell the browser in which directory the applet’s files are located:
<APPLET CODE=AppletSubclass.class CODEBASE=aURL WIDTH=anInt HEIGHT=anInt> </APPLET>
If aURL
is a relative URL, then it’s interpreted relative to the HTML document’s location. By making aURL
an absolute URL, you can load an applet from just about anywhere—even from another HTTP server.
This book uses CODEBASE="
someDirectory
/"
frequently, since we group the examples for each chapter in subdirectories. For example, here’s the <APPLET>
tag that includes the Simple applet in The Life Cycle of an Applet section (page 547):
<APPLET CODE=Simple.class CODEBASE="example/" WIDTH=500 HEIGHT=20> </APPLET>
Figure 18.13 shows the location of the class file, relative to the HTML file, when CODEBASE
is set to "example/"
.
Figure 18.14 shows where the applet class can be if you specify an absolute URL for the value of CODEBASE
.
If your applet has more than one file, you should consider providing an archive file that bundles the applet’s files into a single file. Whether archive files make sense for your applet depends on several factors, including your applet’s size, performance considerations, and the environment you expect your users to have.
Archive files reduce your applet’s total download time. Much of the time saved comes from reducing the number of HTTP connections that the browser must make. Each HTTP connection can take several seconds to start. This means that for a multifile applet, connection time can dwarf transfer time. You can further reduce transfer time by compressing the files in your archive file.
If you specify one or more archive files, then the applet class loader looks for the archive files in the same directory that it would search for the applet class file. The applet class loader then looks for the applet’s class files in the archive files. If a file isn’t in the archive, then the applet class loader generally tries to load it in the browser just as it would if the archive file weren’t present.
The standard Java archive format, called JAR, was introduced in JDK 1.1 and is based on the ZIP file format. You specify JAR files using the ARCHIVE
attribute of the <APPLET>
tag. You can specify multiple archive files by separating them with commas:
<APPLET CODE="AppletSubclass.class" ARCHIVE="file1, file2" WIDTH=anInt HEIGHT=anInt> </APPLET>
Unfortunately, not all browsers understand the same archive format or use the same HTML code to specify the applet archive. Watch this page for the latest information about browser support for archives. To learn how to create a JAR file, see the Creating a JAR File section (page 490).
This section didn’t discuss every attribute of the <APPLET>
tag. Other attributes—which might seem familiar, since the <IMG>
HTML tag uses them—include ALIGN
, VSPACE
, and HSPACE
. The <APPLET>
tag also allows you to load a serialized (saved) applet by specifying the OBJECT
attribute instead of specifying a class file with CODE
. Finally, you can name an applet using the NAME
attribute. For a detailed description of the <APPLET>
tag, see the Using the applet
Tag section (page 595).
The first two sections in this chapter discussed all of the applet-specific API. However, most applets rely on a lot of API that isn’t specific to applets. This section gives you hints about using the Java API, covering the areas that are affected by applets’ close relationships with browsers.
One of the main goals of the Java environment is to make browser users feel secure running any applet. To achieve this goal, we’ve started out conservatively, restricting capabilities perhaps more than necessary. As time passes, applets will probably get more and more abilities.
This section tells you about the current applet security restrictions, from the point of view of how they affect applet design. For more information on applet security, you should refer Frequently Asked Questions—Applet Security.[30]
Each applet viewer has a SecurityManager
object that checks for applet security violations. When a SecurityManager
detects a violation, it creates and throws a SecurityException
object. Generally, the SecurityException
constructor prints a warning message to the standard output. An applet can catch SecurityException
s and react appropriately, such as by reassuring the user and by resorting to a “safer” (but less ideal) way of accomplishing the task.
Some applet viewers swallow some SecurityException
s, so that the applet never gets the SecurityException
. For example, the JDK Applet Viewer’s implementation of the AppletContext getApplet
and getApplets
methods simply catches and ignores any SecurityException
s. The user can see an error message in the standard output, but at least the applet gets a valid result from the methods. This makes some sense, since getApplets
should be able to return any valid applets it finds, even if it encounters invalid ones. (The Applet Viewer considers an applet valid if it’s loaded from the same host as the applet that’s calling getApplets
.)
To learn about security managers and the kinds of security violations they can check for, see The Security Manager section (page 455).
Existing applet viewers (including Web browsers) impose the following restrictions:
Applets cannot load libraries or define native methods. Applets can use only their own Java code and the Java API the applet viewer provides. At a minimum, each applet viewer must provide access to the API defined in the java.*
packages.
An applet cannot ordinarily read or write files on the host that is executing it. The JDK Applet Viewer actually permits some user-specified exceptions to this rule, but older browsers generally do not. Applets in any applet viewer can read files specified with full URLs, instead of by a filename. A workaround for not being able to write files is to have the applet forward data to an application on the host the applet came from. This application can write the data files on its own host. See the Working with a Server-Side Application section (page 589) for more examples.
An applet cannot make network connections except to the host that it came from. The workaround for this restriction is to have the applet work with an application on the host it came from. The application can make its own connections anywhere on the network. See the Using a Server to Work Around Security Restrictions section (page 591) for an example.
An applet cannot start any program on the host that is executing it. Again, an applet can work with a server-side application instead.
An applet cannot read certain system properties. See the Getting System Properties section (page 583) for more information.
Windows that an applet brings up look different than windows that an application brings up. You can identify the Applet window by the name “Java Applet Window,” which is displayed at the bottom of the window. The application window would not have any name at its bottom. This helps the user distinguish applet windows from those of trusted applications.
Figures 18.15 and 18.16 show a window brought up by a program that can run either as an applet or as an application. Figure 18.15 shows what the window looks like when the program is run as an application on the Microsoft Windows platform. Figure 18.16 shows the window when the program runs as an applet on the Windows platform within the Mozilla browser.
As you can see, the applet window has a label informing the user that it is running as an applet.
Most applets have a graphical user interface (GUI). This is a natural consequence of the fact that each applet appears within a browser window. Because the JApplet
class is a subclass of the Applet
class, which is a subclass of the AWT Panel
class and thus participates in the AWT event and drawing model, creating an applet’s GUI is just as easy as creating an application’s GUI. It’s easier, actually, since the applet’s window (the browser window) already exists.
In addition to its graphical UI, an applet can use several other UI types, depending on the kind of information it needs to give or get. Some applets play sounds, either to give the user feedback or to provide ambiance. Applets can get configuration information from the user through parameters that the applet defines. To give text information to the user, an applet can use its GUI, display a short status string (for text that’s not crucial), or display to the standard output or standard error stream (for debugging purposes).
For information about sound, parameters, and status strings, see the Taking Advantage of the Applet API section (page 559).
This section discusses the few issues that are particular to applet GUIs. Some of the information in this section might not make sense until you’ve read the Creating a GUI with JFC/Swing and, in particular, the How to Make Applets section.[31] That trail discusses all the GUI concepts referred to in this section:
Applets appear in preexisting browser windows. This has two implications. First, unlike GUI-based applications, applets don’t have to create a window in which to display themselves. They can, if they have a good reason, but they often just display themselves within the browser window. Second, depending on the browser implementation, your applet’s components might not be shown unless your applet calls validate
after adding components to itself. Fortunately, calling validate
can’t hurt.
The applet background color might not match the page color. By default, applets have a white background color. HTML pages, however, can have other background colors and can use background patterns. If the applet designer and page designer aren’t careful, the applet’s different background color can cause it to stick out on the page or cause noticeable flashing when the applet is drawn. One solution is to define an applet parameter that specifies the applet’s background color. The JApplet
class can use JComponent
’s setBackground
method to set the applet’s background to the color specified in the Web page. Using the background color parameter, the page designer can choose an applet color that works well with the page colors. You’ve learned about parameters in the Defining and Using Applet Parameters section (page 570).
Each applet has a user-specified, predetermined size. The <APPLET>
tag requires that the applet’s width and height be specified. The Web designer can set an applet’s size by pixels or by indicating a percentage of the browser window. Note that even if the amount of space is ideal for one platform, the platform-specific parts of the applet (such as buttons) might require a different amount of space on another platform. You can compensate by recommending that pages that include your applet specify a little more space than might be necessary, and by using flexible layouts, such as the GridBagLayout
and BorderLayout
classes, that adapt well to extra space.
Applets load images using the Applet getImage
methods. The Applet
class provides a convenient form of getImage
that lets you specify a base URL as one argument, followed by a second argument that specifies the image file location, relative to the base URL. The Applet getCodeBase
and getDocumentBase
methods provide the base URLs that most applets use. Images that an applet always needs, or needs to rely on as a backup, are usually specified relative to where the applet’s code was loaded from (the code base). Images that are specified by the applet user (often with parameters in the HTML file) are usually relative to the page that includes the applet (the document base).
Applet classes (and often the data files they use) are loaded over the network, which can be slow. Applets can do several things to decrease the perceived startup time. The Applet
subclass can be a small one that immediately displays a status message. If some of the applet’s classes or data aren’t used right away, the applet can preload the classes or data in a background thread.
For example, the AppletButton
[32] class start
method launches a thread that gets the Class
[33] object for the window the button brings up. The applet’s main purpose in doing so is to make sure the class name that the user specified is valid. An added benefit is that getting the Class
object forces the class file to be loaded before the class is instantiated. When the user requests that the window be created, the applet instantiates the window class much quicker than if the applet still had to load the window class file.
Displaying diagnostics to the standard output can be an invaluable tool when you’re debugging an applet. Another time you’ll see messages at the standard output is when an uncaught exception occurs in an applet. Applets also have the option of using the standard error stream.
Where exactly the standard output and error are displayed varies, depending on how the applet’s viewer is implemented, what platform it’s running on, and (sometimes) how you launch the browser or applet viewer. When you launch the Applet Viewer from a UNIX shell window, for example, strings displayed to the standard output and error appear in that shell window, unless you redirect the output. When you launch the Applet Viewer from an X Windows menu, the standard output and error go to the console window.
Applets display to the standard output stream using System.out.print(
String
)
and System.out.println(
String
)
. Displaying to the standard error stream is similar; just specify System.err
instead of System.out
. Here’s an example of displaying to the standard output:
// Where instance variables are declared: boolean DEBUG = true; ... // Later, when we want to print some status: if (DEBUG) { System.out.println("Called someMethod(" + x + "," + y + ")"); }
Displaying to the standard output and error streams is relatively slow. If you have a timing-related problem, printing messages to either of these streams might not be helpful.
You should be sure to disable all debugging output before you release your applet.
To find out about the current working environment, applets can read system properties. System properties are key/value pairs that contain information such as the operating system that the applet is running under. System properties are covered in detail in the Properties section (page 443).
Applets can read some, but not all, system properties.
Applets can read the system properties listed in Table 18.1.
Table 18.1. Valid System Properties
Key | Meaning |
---|---|
| File separator (for example, “ |
| Java class version number |
| Java vendor-specific string |
| Java vendor URL |
| Java version number |
| Line separator |
| Operating system architecture |
| Operating system name |
| Path separator (for example, “ |
To read a system property from within an applet, the applet uses the System
class method getProperty
. For example:
String newline = System.getProperty("line.separator");
Run an applet[34] which reads all of the properties available to all applets (Figure 18.17).
You can find the source code in GetOpenProperties.java
.[35]
For security reasons, no existing browsers or applet viewers let applets read the system properties listed in Table 18.2.
This section assumes that you know what a thread is. If you don’t, please read the Processes and Threads section (page 369) before reading this section.
Every applet can run in multiple threads. The applet’s GUI is created on the event-dispatching thread. The threads that the major milestone methods—init
, start
, stop
, and destroy
—are called from depends on the application that’s running the applet. But no application ever calls them from the event-handling thread.
Many browsers allocate a thread for each applet on a page, using that thread for all calls to the applet’s major milestone methods. Some browsers allocate a thread group for each applet, so that it’s easy to kill all the threads that belong to a particular applet. In any case, you’re guaranteed that every thread created by any of an applet’s major milestone methods belongs to the same thread group.
Run a PrintThread
applet[36] (Figure 18.18). PrintThread
is a modified version of SimpleApplet
that prints the thread and thread group that its init
, start
, stop
, destroy
, and update
methods are called from.[37]
As usual, to see the output for the methods such as destroy
that are called during unloading, you need to look at the standard output. For standard output for an applet run in a browser, open the Java Console from the browser’s Tools menu. See the Displaying Diagnostics to the Standard Output and Error Streams section (page 583) for information about the standard output stream.
So why would an applet need to create and use its own threads? Imagine an applet that performs some time-consuming initialization—loading images, for example—in its init
method. The thread that invokes init
cannot do anything else until init
returns. In some browsers, this might mean that the browser can’t display the applet or anything after it until the applet has finished initializing itself. So if the applet is at the top of the page, for example, then nothing would appear on the page until the applet has finished initializing itself.
Even in browsers that create a separate thread for each applet, it makes sense to put any time-consuming tasks into an applet-created thread, so that the applet can perform other tasks while it waits for the time-consuming ones to be completed.
If an applet performs a time-consuming task, it should create and use its own thread to perform that task.
Applets typically perform two kinds of time-consuming tasks: tasks that they perform once and tasks that they perform repeatedly. The next section gives an example of both.
This section discusses two examples of using threads in applets. The first applet, AnimatorApplet, shows how to use a thread to perform repeated tasks. The second applet this page discusses, SoundExample, shows how to use threads for one-time initialization tasks. SoundExample is featured in the Playing Sounds section (page 568).
This section does not explain basic thread code. To learn about the Java implementation of threads, refer to the Defining and Starting a Thread section (page 371).
An applet that performs the same task over and over again typically should have a thread with a while
(or do…while
) loop that performs the task. A typical example is an applet that performs timed animation, such as a movie player or a game. Animation applets need a thread that requests repaints at regular intervals. Another example is an applet that reads data supplied by a server-side application. (See the Using a Server to Work Around Security Restrictions section, page 591, for such an example.)
Applets typically create threads for repetitive tasks in the applet start
method. Creating the thread there makes it easy for the applet to stop the thread when the user leaves the page. All you need to do is implement the stop
method so that it stops the applet’s thread. When the user returns to the applet’s page, the start
method is called again, and the applet can again create a thread to perform the repetitive task.
Below is AnimatorApplet
’s implementation of the start
and stop
methods:
public void start() { if (frozen) { // Do nothing. The user has requested that we // stop changing the image. } else { // Start animating! if (animatorThread == null) { animatorThread = new Thread(this); } animatorThread.start(); } } public void stop() { animatorThread = null; }
The this
in new Thread(this)
indicates that the applet provides the body of the thread. It does so by implementing the java.lang.Runnable
interface, which requires the applet to provide a run
method that forms the body of the thread. We’ll discuss AnimatorApplet
’s run
method more a little later.
Notice that nowhere in the AnimatorApplet
class is the Thread stop
method called. This is because calling the Thread stop
method is like clubbing the thread over the head. It’s a drastic way to get the thread to stop what it’s doing. Instead, you can write the thread’s run
method in such a way that the thread will gracefully exit when you tap it on the shoulder. This shoulder tap comes in the form of setting to null an instance variable of type Thread
.
In AnimatorApplet
, this instance variable is called animatorThread
. The start
method sets it to refer to the newly created Thread
object. When the applet needs to kill the thread, it sets animatorThread
to null. This kills the thread not by making it be garbage collected—it can’t be garbage collected while it’s runnable—but because at the top of its loop, the thread checks animatorThread
, continuing or exiting depending on the value of animatorThread
. Here’s the relevant code:
public void run() {
...
while (Thread.currentThread() == animatorThread) {
...// Display a frame of animation and then sleep.
}
}
If animatorThread
refers to the same thread as the currently executing thread, the thread continues executing. If, on the other hand, animatorThread
is null, the thread exits. If animatorThread
refers to another thread, then a race condition has occurred: start
has been called so soon after stop
(or this thread has taken such a long time in its loop) that start
has created another thread before this thread reached the top of its while
loop. Whatever the cause of the race condition, this thread should exit.
For more information about animation applets, see Threads in Applets, a section in Creating a GUI with JFC/Swing.
If your applet needs to perform some initialization task that can take a while, you should consider ways of performing the initialization in a thread. For example, anything that requires making a network connection should generally be done in a background thread. Fortunately, GIF, PNG, and JPEG image loading is automatically done in the background using threads that you don’t need to worry about.
Sound loading, unfortunately, is not guaranteed to be done in the background. In current implementations, the Applet getAudioClip
methods don’t return until they’ve loaded all the audio data. As a result, if you want to preload sounds, you might want to create one or more threads to do so.
Using a thread to perform a one-time initialization task for an applet is a variation of the classic producer/consumer scenario. The thread that performs the task is the producer, and the applet is the consumer. The Synchronization section (page 377) discusses how to use Java threads in a producer/consumer scenario.
SoundExample adheres closely to the model presented in Synchronizing Threads. Like the Synchronizing Threads example, SoundExample features three classes:[38]
The producer: SoundLoader
, a Thread
subclass.
The consumer: SoundExample
, an Applet
subclass. Unlike the Synchronizing Threads consumer example, SoundExample
is not a Thread
; it doesn’t even implement the Runnable
interface. However, the SoundExample
instance methods are executed by at least two threads, depending on the application that executes the SoundExample
applet.
The storage object: SoundList
, a Hashtable
subclass. Unlike CubbyHole
in the Synchronizing Threads example, SoundList
can return null values if the sound data hasn’t been stored yet. This makes sense for this applet because it needs to be able to react immediately to a user request to play the sound, even if the sound hasn’t been loaded yet.
For more information on SoundExample
, refer to the Playing Sounds section (page 568).
Applets, like other Java programs, can use the API defined in the java.net
package to communicate across the network. The only difference is that, for security reasons, the only host an applet can communicate with is the host it was delivered from.
Depending on the networking environment an applet is loaded into, and depending on the browser that runs the applet, an applet might not be able to communicate with its originating host. For example, browsers running on hosts inside firewalls often cannot get much information about the world outside the firewall. As a result, some browsers might not allow applet communication to hosts outside the firewall.
It’s easy to find out which host an applet came from. Just use the Applet getCodeBase
method and the java.net.URL getHost
method, like this:
String host = getCodeBase().getHost();
Once you have the right host name, you can use all the networking code that is documented in the Custom Networking trail in the online tutorial.[39]
Not all browsers support all networking code flawlessly. For example, one widely used browser compatible with Java technology doesn’t support posting to a URL.
This section talks about the client to be an applet.[40] The client has been written not only to communicate with the host the applet came from, but also to have a graphical UI, and to have a loop so that it can get as many quotes as you like. You can run the applet by including it in a page with the following HTML code:
<APPLET CODE=QuoteClientApplet.class WIDTH=500 HEIGHT=100> </APPLET>
The quoteApplet.html
page[41] contains the above HTML code. By saving this page to a file on your local HTTP server, you can use it to communicate with the server-side application that will be running on the HTTP server. You must also save the compiled form of the applet to the same directory.
Before the applet can get quotes, you need to run the server on the host that the applet came from. You then need to note the number of the port that the server is listening on. After you enter this port number into the applet, it will hook up with the server and you’ll be able to get one-line quotations. Below are detailed instructions, followed by pictures of the server and the applet in action:
Compile QuoteServer.java
[42] and QuoteServerThread.java
.[43] A text file (one-liners.txt
[44]) should be in the same directory as the resulting class files.
On the computer that serves the applet class file (through HTTP), invoke the interpreter on the QuoteServer
class. For example, if you view the applet’s page with the URL http://mymachine/quoteApplet.html, then you need to run the server on the host named mymachine.
Record the port number that the quote server displays.
Enter this number into the applet’s text field.
Press the Send button to request a quote from the server. You should see a quote appear in the text area.
Figure 18.19 shows a picture of the applet in action.
As the What Applets Can and Can’t Do section (page 558) explains, applets are subject to many security restrictions. For example, they can’t perform file I/O, they can’t make network connections except to their original host, and they can’t start programs.
One way of working around these restrictions is to use a server application that executes on the applet’s host. The server won’t be able to get around every applet restriction, but it can make more things possible. For example, a server probably can’t save files on the host the applet’s running on, but it will be able to save files on the host the applet originated from.
This section features an example of a server that allows two applets to communicate with each other. The applets don’t have to be running on the same page, in the same browser, or on the same computer. As long as the applets originate from the same computer, they can communicate through the server that’s running on that originating computer. The example uses sockets, which are documented in All About Sockets.[45]
Here are the source files:
TalkClientApplet.java
[46]. The source file for the client applet. After you compile it, you can run it by including it in an HTML page with this tag:
<APPLET CODE=TalkClientApplet.class WIDTH=550 HEIGHT=200> </APPLET>
The talk.html
page[47] includes the above HTML code. After saving this page to a file on your local HTTP server, you can use it to communicate with the talk server.
TalkServer.java
[48] and TalkServerThread.java
[49]. The source files for the server applet. After compiling both files, you can run the server on the applets’ originating host by invoking the interpreter on the TalkServer
class.
The instructions for running the server are just like those for the previous example (see the A Simple Network Client Applet section, page 590). Run the server on the applets’ originating host, recording the port number that the applets should rendezvous on. Then initialize both applets (which can be running on different machines) to talk to the server port number. After this initialization is complete, type a string into each applet’s text field. Then press the Return key to send the message to the other applet.
Here’s the server in action:
www% java TalkServer
TalkServer listening on rendezvous port: 36567
Figures 18.20 and 18.21 show pictures of the applets in action.
Stop! Before you let the whole world know about your applet, make sure the answer to all of the following questions is yes:
Have you removed or disabled debugging output? | |
Debugging output (generally created with | |
Does the applet stop running when it’s offscreen? | |
Most applets should not use CPU resources when the browser is iconified or is displaying a page that doesn’t contain the applet. If your applet code doesn’t launch any threads explicitly, then you’re OK. If your applet code launches any threads, then unless you have a really good excuse not to, you should implement the | |
If the applet does something that might get annoying—play sounds or animation, for example—does it give the user a way of stopping the annoying behavior? | |
Be kind to your users. Give them a way to stop the applet in its tracks, without leaving the page. In an applet that otherwise doesn’t respond to mouse clicks, you can do this by implementing the boolean frozen = false; // an instance variable public boolean mouseDown(Event e, int x, int y) { if (frozen) { frozen = false; start(); } else { frozen = true; stop(); } return true; } |
The previous section lists some of the ways you can avoid making your applet’s users want to throttle you. This section tells you about some other ways that you can make dealing with your applet as pleasant as possible:
Make your applet as flexible as possible.
You can often define parameters that let your applet be used in a variety of situations without any rewriting. See the Defining and Using Applet Parameters section (page 570) for more information.
Make your applet accessible.
You can design your applet so that it is accessible to all. See the Swing chapter in the How to Support Assistive Technologies[50] section of the tutorial for more information.
Implement the getParameterInfo
method.
Implementing this method now might make your applet easier to customize in the future. Currently, no browsers use this method. Soon, however, we expect browsers to use this method to help generate a GUI that allows the user to interactively set parameter values. See the Giving Information about Parameters section (page 573) for information on implementing getParameterInfo
.
Implement the getAppletInfo
method.
This method returns a short, informative string describing an applet. Although no browsers currently use this method, we expect them to in the future. Here’s an example of implementing getAppletInfo
:
public String getAppletInfo() { return "GetApplets by Kathy Walrath"; }
This section explains to HTML authors how and when to use the applet
, object
, and embed
tags to add Java applets to Web pages, and provides guidelines for deploying applets on the Internet and Intranets and for use with different browsers.
How you deploy an applet depends on whether users access the Web page through the Internet or an Intranet, and the type of browser they use. Note this information about your users, then follow the general guidelines below.
When deploying applets:
Use the applet
tag if the Web page is accessed through the Internet or if it is accessed through an Intranet in which people use different browsers.
Use the object
or embed
tag if the Web page is accessed through an Intranet and you know which browser people use.
When deploying applets:
For Internet Explorer only, use the object
tag.
For the Mozilla family of browsers only, use the embed
tag.
If you must deploy an applet in a mixed-browser environment, follow the guidelines in the Deploying Applets in a Mixed-Browser Environment section (page 598).
You use the applet
tag to deploy applets to a multi-browser environment.
For complete details on the applet
tag, read the W3 HTML specification.[51]
The HTML specification states that the applet
tag is deprecated and that you should use the object
tag instead. However, the specification is vague about how browsers should implement the object
tag to support Java applets, and browser support is currently inconsistent. It is therefore recommended that you continue to use the applet
tag as a consistent way to deploy Java applets across browsers on all platforms.
Following is an example of the applet
tag:
<applet code=Applet1.class width="200" height="200"> Your browser does not support the applet tag. </applet>
For both Internet Explorer and the Mozilla family of browsers, if Java Plug-in is installed (version 1.3.1_01a or later) then the latest installed version of Java Plug-in is invoked to run the applet.
You use the object
tag to deploy applets that are to be used only with Internet Explorer.
For complete details on the object
tag, read the W3 HTML specification.
Following is an example of the object
tag:
<OBJECT classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="200" height="200"> <PARAM name="code" value="Applet1.class"> </OBJECT>
The classid
attribute identifies which version of Java Plug-in to use.
The example shown below is the most commonly used form of the classid
attribute. This example instructs Internet Explorer to use the latest installed version of Java Plug-in:
classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"
Following is an alternative form of the classid
attribute:
classid="clsid:CAFEEFAC-xxxx-yyyy-zzzz-ABCDEFFEDCBA"
In this form, “xxxx
”, “yyyy
”, and “zzzz
” are four-digit numbers that identify the specific version of Java Plug-in to be used.
For example, to use Java Plug-in version 1.6.0, you specify:
classid="clsid:CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA"
You use the optional codebase
attribute to specify the location to download JRE from in case it is not installed on the system.
The codebase attribute has two forms:
codebase=<URL>
. With this form, if the JRE specified by the classid
attribute is not installed locally, then the user is prompted to download the JRE from the URL specified.
codebase=<URL>#Version=major,minor,micro,update
. With this form, Java Plug-in compares the classid
of the locally installed JRE with the required version of JRE, and if the required version is higher, prompts the user to download and install the newer version of the JRE.
Following is an example of how to use the codebase
attribute to set up automatic downloads from the Sun Java Web site:
<object classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="200" height="200" codebase="http://java.sun.com/update/1.6.0/ jinstall-6-windows-i586.cab#Version=6,0,0,99"> <param name="code" value="Applet1.class"> </object>
In this example, the codebase=http://java.sun.com …
line is broken for readability. In the actual HTML file it would be one long line.
Sun has packaged each version of the JRE installer in Microsoft cabinet (.cab) file format. You can view a list of these releases and the corresponding .cab file names.[52]
You use the embed
tag to deploy applets that are to be used only with the Mozilla family of browsers.
Following is an example of the embed
tag:
<embed code="Applet1.class" width="200" height="200" type="application/x-java-applet;version=1.6.0" pluginspage="http://java.sun.com/javase/downloads"/>
The type
attribute can have one of two forms:
type="application/x-java-applet;version=1.6.0"
. With this form, the highest installed JRE that supports the MIME type
application/x-java-applet;version=1.6.0
is invoked to run the applet. If a JRE with a version number equal to or greater than the version number specified is installed locally, then that JRE is invoked. Otherwise the user is directed to the URL specified as the value of the pluginspage
attribute and is prompted to download and install the required JRE.
type="application/x-java-applet;jpi-version=1.6.0_01
. With this form, a JRE with the exact version given by the the value of jpi-version
(in this example, 1.6.0_01) is invoked to run the applet. Otherwise the user is directed to the URL specified as the value of the pluginspage
attribute and is prompted to download and install the required JRE.
You can deploy applets for users of both Internet Explorer and the Mozilla family of browsers in one of two ways:
Through pure HTML
Through JavaScript
When using a pure HTML approach to deploy applets in a mixed-browser environment, note the following:
Consider the following example code from an HTML page:
<object classid="clsid:CAFEEFAC-0016-0000-0000-ABCDEFFEDCBA" <param name="code" value="Applet1.class"> <comment> <embed code="Applet1.class" type="application/x-java-applet;jpi-version=1.6"> <noembed> No Java Support. </noembed> </embed> </comment> </object>
Instead of using the pure HTML approach described above, you can use JavaScript to deploy applets in a mixed-browser environment.
Through JavaScript, you:
Detect the user’s browser through the appName
variable.
Use the document.write()
method to write a tag based on the value of the appName
variable:
If the browser name equals “Netscape”, write the embed
tag.
If the browser name equals “Microsoft Internet Explorer”, write the object
tag.
In the following example, the document.write()
method outputs either an embed
or object
tag for each user “on the fly”:
<html> <script language="Javascript"> var _app = navigator.appName; if (_app == 'Netscape') { document.write('<embed code="Applet1.class"', 'width="200"', 'height="200"', 'type="application/x-java-applet;version=1.6">'), } else if (_app == 'Microsoft Internet Explorer') { document.write('<OBJECT ', 'classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"', 'width="200"', 'height="200">', '<PARAM name="code" value="Applet1.class">', '</OBJECT>'), } else { document.write('<p>Sorry, unsupported browser.</p>'), } </script> </html>
You can use the HTML Converter tool[53] to help with generating object
and embed
tags for mixed environments.
This section covers some common problems that you might encounter when writing Java applets. After each problem there is a list of possible solutions.
Problem: Applet Viewer says there is no <APPLET>
tag on my HTML page, but it really is there.
Check whether you have a closing applet tag: </APPLET>
Problem: I recompiled my applet, but my applet viewing application would not show the new version even though I told it to reload it.
In many applet viewers (including browsers), reloading is not reliable. This is why we recommend that you simply use the JDK Applet Viewer, invoking it anew every time you change the applet.
If you get an old version of the applet, no matter what you do, make sure that you don’t have an old copy of the applet in a directory in your CLASSPATH
. See the Managing Source and Class Files section (page 191) for information about the CLASSPATH
environment variable.
Problem: The background color of my applet causes the applet not to match or flicker when it is drawn on a page of a different color.
You need to set the background color of the applet so that it works well with the page color. See the Creating a GUI section (page 581) for details.
Problem: The Applet getImage
method doesn’t work.
Make sure you’re calling getImage
from the init
method or a method that’s called after init
. The getImage
method does not work when it is called from a constructor.
Problem: Now that I have copied my applet’s class file onto my HTTP server, the applet doesn’t work.
Does your applet define more than one class? If so, make sure that the class file (ClassName
.class
) for each class is on the HTTP server. Even if all the classes are defined in one source file, the compiler produces one class file per class.
Did you copy all the data files for your applet—image and sound files, for example—to the server?
Make sure all the applet’s class and data files can be read by everyone.
Make sure the applet’s class and data files weren’t garbled during the transfer. One common source of trouble is using the ASCII mode of FTP (rather than the BINARY mode) to transfer files.
Problem: Applet is not loaded in my Web page. I see the error “java.lang.UnsupportedClassVersionError: Bad version number in .class file” in my Java Console.
The problem is that the source for the applet is compiled with a newer version of Java than the one installed on your system. Which JRE version are you using? If it is not the latest version, make sure you install the latest Java SE Runtime Environment (JRE).[54]
[1] docs/technotes/guides/plugin/developer_guide/contents.html
[2] tutorial/deployment/applet/examples/helloWorld.jar
[3] tutorial/deployment/applet/examples/HelloWorld.java
[4] tutorial/deployment/applet/SwingUI.java
[5] tutorial/deployment/applet/ApptoAppl.java
[6] tutorial/uiswing/components/rootpane.html
[7] tutorial/deployment/applet/examples/simple.jar
[8] tutorial/deployment/applet/examples/Simple.java
[9] docs/api/javax/swing/JApplet.html
[10] tutorial/deployment/applet/examples/SimpleClick.java
[11] tutorial/deployment/applet/examples/simpleClick.jar
[12] tutorial/uiswing/index.html
[13] tutorial/deployment/applet/examples/ScrollingSimple.java
[14] tutorial/uiswing/layout/index.html
[15] tutorial/deployment/applet/examples/scrollingSimple.jar
[16] docs/api/java/applet/Applet.html
[17] tutorial/deployment/applet/examples/showDocument.jar
[18] tutorial/deployment/applet/examples/ShowDocument.java
[19] tutorial/deployment/applet/examples/sender.jar
[20] tutorial/deployment/applet/examples/Sender.java
[21] tutorial/deployment/applet/examples/Receiver.java
[22] docs/api/java/util/Enumeration.html
[23] tutorial/deployment/applet/examples/getApplets.java
[24] tutorial/deployment/applet/examples/GetApplets.java
[25] docs/api/java/applet/AudioClip.html
[26] tutorial/deployment/applet/examples/sound.jar
[27] tutorial/deployment/applet/examples/SoundExample.java
[28] tutorial/deployment/applet/examples/SoundList.java
[29] tutorial/deployment/applet/examples/SoundLoader.java
[31] tutorial/uiswing/components/applet.html
[32] tutorial/uiswing/layout/example-swing/AppletButton.java
[33] docs/api/java/lang/Class.html
[34] tutorial/deployment/applet/examples/properties.jar
[35] tutorial/deployment/applet/examples/GetOpenProperties.java
[36] tutorial/deployment/applet/examples/threads.jar
[37] tutorial/deployment/applet/examples/PrintThread.java
[39] tutorial/networking/index.html
[40] tutorial/deployment/applet/examples/QuoteClientApplet.java
[41] tutorial/deployment/applet/examples/quoteApplet.html
[42] tutorial/deployment/applet/examples/QuoteServer.java
[43] tutorial/deployment/applet/examples/QuoteServerThread.java
[44] tutorial/deployment/applet/examples/one-liners.txt
[45] tutorial/networking/sockets/index.html
[46] tutorial/deployment/applet/examples/TalkClientApplet.java
[47] tutorial/deployment/applet/examples/talk.html
[48] tutorial/deployment/applet/examples/TalkServer.java
[49] tutorial/deployment/applet/examples/TalkServerThread.java
[50] tutorial/uiswing/misc/access.html
[52] docs/technotes/guides/deployment/deployment-guide/autodl-files.html
[53] docs/technotes/guides/plugin/developer_guide/html_converter.html
3.145.76.250