Undoubtedly you’re familiar with
applets, Java programs that can be embedded on a web page and run in
a secure environment within a browser. All applets extend the
java.applet.Applet
class, which includes a number
of methods that perform network-related operations. These methods
allow an applet to find out where it came from, download images and
sounds from a web server, and track the progress of the download.
This chapter discusses the interaction between applets and the
network. It doesn’t provide an introduction to the
Applet
class as a whole; for that, see an
introductory book such as Niemeyer and Peck’s
Learning Java (O’Reilly & Associates,
Inc., 2000).
The
methods of the Applet
class discussed in this
section are really just thin veneers over equivalent methods in the
java.applet.AppletStub
and
java.applet.AppletContext
interfaces. These
interfaces describe services that the web browser or applet viewer
provides to applets. The exact classes that implement these
interfaces are undocumented and vary from implementation to
implementation. Applets that you instantiate yourself (for example,
an applet that also runs as an application by supplying a
main( )
method that calls the applet’s
init( )
and start( )
methods)
will generally have null AppletStub
and
AppletContext
members. Therefore, if you try to
use these methods in such an applet, a
NullPointerException
will be thrown.
Most often, applets retrieve image files or other data from one of
two directories: the directory the applet came from, or the directory
the HTML page in which the applet was embedded came from. These
directories are called the codebase and the
document base, respectively. To make it easy to
find other files, the Applet
class has methods
that return URL
objects referring to the current
page and the current applet. These methods are called
getDocumentBase( )
and getCodeBase( )
respectively.
The getDocumentBase( )
method returns the URL of the page containing the applet.
Example 9.1 is a simple applet that displays the URL
of the document in which it is embedded.
The getCodeBase( )
method returns the URL of the
directory where the applet is located. If the applet is in a JAR
archive, then the codebase is the URL of the directory where the JAR
archive is. If the applet is in a package (e.g.,
com.macfaq.applets.MyApplet
instead of just
MyApplet
), then the codebase is the directory or
JAR archive containing the outermost package such as
com
. Security restrictions in applets are
calculated relative to the codebase, not the document base. Example 9.2 is an applet that displays its document base
and its codebase.
Example 9-2. An Applet That Displays Its Document Base and Its Codebase
import java.applet.*; import java.awt.*; public class AppletBases extends Applet { public void paint(Graphics g) { g.drawString("Codebase: " + this.getCodeBase().toString( ), 10, 40); g.drawString("Document base: " + this.getDocumentBase().toString( ), 10, 65); } }
Figure 9.1 shows what happens when the applet runs;
the result depends on the URLs of the applet and the document.
It’s worth noting that getCodeBase( )
always
returns the URL of a directory, not the URL of the applet itself,
while getDocumentBase( )
always returns the URL of
a file.
In Chapter 7, you
learned how to download data from an HTTP URL by using the
getContent( )
and openStream( )
methods of the URL
class. These methods are useful
for text data such as an HTML file, but they don’t work as well
for binary data, which usually requires some knowledge of the
data’s structure. The Applet
class includes
several methods that understand more about what they’re
downloading. The getImage( )
methods download
image files and convert them into java.awt.Image
objects:
public Image getImage(URL url) public Image getImage(URL url, String name)
Like the other methods in this chapter, the two getImage( )
methods in the Applet
class rely on an
AppletContext
field that is null for applets you
instantiate yourself rather than being instantiated by a web browser
or an applet viewer. However, the java.awt.Toolkit
class includes identical getImage( )
methods that
do not rely on an AppletContext
. You can always
get a Toolkit
object by calling the static
java.awt.Toolkit.getDefaultToolkit( )
method or
the getToolkit( )
instance method of any subclass
of java.awt.Component
. Then you can use its
getImage( )
methods just as you use the
getImage( )
methods described here. The one
difference is that you’ll need to prefix the calls to
getImage( )
with a variable that refers to the
Toolkit
object. For example:
Toolkit t = java.awt.Toolkit.getDefaultToolkit( ); URL u = new URL("http://metalab.unc.edu/javafaq/cup.gif") Image theImage = t.getImage(u);
This method retrieves the image data at the specified URL and puts it
in a java.awt.Image
object. For example:
Image myLogo = getImage(new URL("http://metalab.unc.edu/java/cup.gif"));
The getImage( )
method relies on the
AppletContext
(provided by the web browser or
applet viewer) to retrieve and interpret the image. Thus this method
can get images only in formats understood by the
AppletContext
in which the applet is running.
Currently, all contexts that run in a graphical environment
understand the GIF format. (IBM’s Java environment for some of
its mainframes and minicomputers is completely nongraphical because
those platforms don’t support graphics.) Most contexts also
understand JPEG though JPEG support was omitted from some
vendors’ early alpha and beta releases. Finally, Java
implementations derived from Sun’s source code often understand
XBM. JDK 1.3 adds support for PNG. Example 9.3 is a
complete applet that loads and displays the image referenced by the
IMAGE
parameter, which comes from a
<PARAM>
tag in the HTML
file.
Example 9-3. Display an Image via a URL
import java.applet.*; import java.awt.*; import java.net.*; public class ImageView extends Applet { Image picture; public void init( ) { try { URL u = new URL(this.getCodeBase( ), this.getParameter("IMAGE")); this.picture = this.getImage(u); System.err.println(u); } catch (MalformedURLException e) { // shouldn't happen, the codebase is never malformed } } public void paint (Graphics g) { g.drawImage(this.picture, 0, 0, this); } }
The getImage( )
method returns immediately, even
before it knows whether the image actually exists. The image
isn’t loaded until some other part of the program actually
tries to draw it, or you explicitly force the image to start
loading—you’ll see how to do that shortly. At that point,
the virtual machine starts a separate thread to download and process
the image file.
This is similar to the previous method, except that it uses the
path
argument (a URL
) to find
the image’s directory and the filename
argument (a String
) to get the name of the image
file. For example:
Image logo = this.getImage(new URL("http://metalab.unc.edu/java/"), "cup.gif");
This version of getImage( )
is frequently used
with getCodeBase( )
or getDocumentBase( )
.
You would use getCodeBase( )
in an applet that
might be used on many different web servers but whose images would
always be in the same directory as the applet. For example:
Image logo = this.getImage(this.getCodeBase( ), "logo.gif"));
If the applet exists on only one web server but is embedded on many
different pages, each of which loads different images, you would use
getDocumentBase( )
to locate the images:
Image logo = this.getImage( this.getDocumentBase( ), "logo.gif"));
This technique would be useful in an animator applet; the applet
would probably read the names of some image files from parameters
included in the HTML. You can use the filename
argument to add to the path you get from the URL component. For
example, if the pictures are in a directory called
images
, which is in the same directory as the
HTML page, you would load the file logo.gif
like
this:
Image logo = this.getImage(this.getDocumentBase( ), "images/logo.gif"));
The
Applet
class has five methods that download sounds
from the web. The two play( )
methods download a
sound file and play it immediately. The two getAudioClip( )
methods and the static Applet.newAudioClip( )
method save a sound for later playing. The
AppletContext
, which is provided by the web
browser or applet viewer, does the actual work of downloading and
playing the sound file. Most Java 1.1 and earlier virtual machines
support only Sun’s .au
format and a very
restricted form at that (8-bit sampling, 8 kilohertz, mono, -law
encoded). Java 1.2 adds many more formats, including AIFF, WAV, MIDI
Type 0, MIDI Type 1, and Rich Music Format (RMF). Furthermore, it
supports 8- and 16-bit sampling, in both mono and stereo, with
sampling rates from 8 kHz to 48 kHz in linear, a-law, or -law
encoding. For pre-1.2 VMs, there are a number of freeware, shareware,
and payware tools that convert sounds to the .au
format, including SoX on Linux and Unix systems (http://home.sprynet.com/~cbagwell/sox.html );
SoundHack (http://shoko.calarts.edu/~tre/SndHckDoc/ ),
Ulaw (http://www.kagi.com/rod/ ),
and SoundEdit 16 (http://www.macromedia.com/software/sound/ )
on the Mac; and GoldWave on Windows (http://www.goldwave.com/ ).
The play( )
method looks for a sound file at the
URL u
. If the sound file is found, then it is
downloaded and played. Otherwise, nothing happens. For example:
try { URL soundLocation = new URL( "http://metalab.unc.edu/java/course/week9/spacemusic.au" ); play(soundLocation); } catch (MalformedURLException e) { System.err.println(e); }
Example 9.4 is a simple applet that plays a sound
file. The name of the file is taken from the parameter
sound
, which is supplied by a
<PARAM>
tag in the HTML file. The sound file
should be in the same directory as the applet.
This is similar to the presious method, except that it uses the
url
argument to find the sound file’s
directory and the filename
argument to get the
actual filename. For example:
play(new URL("http://www.macfaq.com/", "gong.au"));
The URL argument is frequently a call to getCodeBase( )
or getDocumentBase()
. You use
getCodeBase( )
if you know that the sound files will
always be in the same directory as the applet, even if you
don’t know in advance where the applet will be located. For
example:
this.play(this.getCodeBase( ), "gong.au"));
If the sound files are always located in the same directory as the
HTML file that loads the applet, you would use
getDocumentBase( )
. In this scenario, one applet,
residing in one directory, might be used by several web pages located
in different directories on that server; each page might use a
<PARAM>
tag to specify its own sound file.
Such an applet might call play( )
like this:
this.play(this.getDocumentBase( ), this.getParameter("sound")));
You can use the filename
argument to add to the
path you get from the URL
argument. For example,
if the sounds are in a directory called sounds
,
which is a subdirectory of the directory containing the HTML page,
you would call play( )
:
this.play(this.getDocumentBase( ), "sounds/gong.au"));
The
java.applet.AudioClip
interface represents a sound. You can
download a sound from a web site with the getAudioClip( )
method. Once you have an
AudioClip
object, play it at your leisure by
calling the clip’s play( )
and
loop( )
methods; play( )
plays
the file once, and loop( )
plays it repeatedly.
Both of these methods let you keep the audio clip around for future
use—unlike the play( )
method of the last
section, which discarded the audio data after it had finished.
Using the AudioClip
interface is simple. Make sure
you’ve imported java.applet.AudioClip
(many
programmers, out of habit, import only
java.applet.Applet
); declare an
AudioClip
variable, and call
getAudioClip( )
to retrieve the sound file. As
usual, the URL
constructor needs to be wrapped in
a try
block because of a potential
MalformedURLException
. For example:
AudioClip theGong; try { URL u = new URL(http://metalab.unc.edu/javafaq/gong.au); theGong = this.getAudioClip(u); } catch (MalformedURLException e) { System.err.println(e); }
This is similar to the previous method, except that it uses
url
to find the directory in which the sound file
is located and filename
to supply the name of the
audio file. For example:
AudioClip ac = getAudioClip(new URL("http://www.macfaq.com/", "gong.au"));
This version of getAudioClip( )
is frequently used
with getCodeBase( )
or getDocumentBase( )
.
For example, if you are writing an applet that will be stored on many
different servers but whose sound files will always be in the same
directory as the applet, you would call getAudioClip( )
like this:
AudioClip ac = this.getAudioClip(this.getCodeBase( ), "gong.au"));
Or, if you’re writing an applet that will reside on one server
but be used by many web pages with different sound files, you might
call getAudioClip( )
like this:
String filename = this.getParameter("sound"); if (filename != null) { // HTML included necessary PARAM tag AudioClip ac = this.getAudioClip(this.getDocumentBase( ), filename); }
In this case, getDocumentBase( )
returns the
location of the HTML file, and getParameter( )
retrieves the name of an audio file from a
<PARAM>
tag in the HTML. You can use the
filename
argument to getAudioClip( )
to add to the path supplied by the URL. For example, in
the following code, the sound file is located in the directory
sounds
, which is a subdirectory of the
document’s directory:
this.getAudioClip(this.getDocumentBase( ), "sounds/gong.au"));
Example 9.5 is a complete applet that downloads a
sound file called gong.au
, which is located in
the same directory as the applet, and then spawns a
Thread
to play the sound every five
seconds.
Example 9-5. Download a Sound via a Relative URL and Play It at Five-Second Intervals
import java.applet.*; import java.awt.*; public class RelativeBeep extends Applet implements Runnable { private AudioClip beep; private boolean stopped = false; public void init( ) { beep = this.getAudioClip(this.getDocumentBase( ), "sounds/beep.au"); if (beep != null) { Thread t = new Thread(this); t.start( ); } } public void start( ) { this.stopped = false; } public void stop( ) { this.stopped = true; } public void run( ) { Thread.currentThread( ).setPriority(Thread.MIN_PRIORITY); while (true) { if (!stopped) beep.play( ); try { Thread.sleep(5000); } catch (InterruptedException e) { } } } }
Java 1.2 adds the static Applet.newAudioClip( )
method so that applications can
download audio clips too. Why, you may ask, if this method is
intended for the use of standalone applications, is it in the
Applet
class? The only answer I can suggest is
that it was a quick hack designed to answer a long-standing request
and that nobody gave a lot of thought to exactly what a sensible API
for this would look like. Perhaps the underlying, undocumented
infrastructure on which the play( )
and
getAudioClip( )
methods depend was easily
accessible only from inside the Applet
class.
Regardless of the reason, the Applet
class is
where the newAudioClip( )
method resides, and
you’ll need to use that class even in non-applets that want to
load audio clips.
The Applet.newAudioClip( )
method returns an
AudioClip
, just like getAudioClip( )
. Therefore, you can invoke the same loop( )
and play( )
methods on it. For
example, this code fragment loads the sound file at http://metalab.unc.edu/java/course/week9/spacemusic.au
and plays it continuously. It can do this from an applet or an
application. It does not need a web browser or
AppletContext
:
try { URL sound = new URL("http://metalab.unc.edu/java/course/week9/spacemusic.au"); AudioClip ac = new AudioClip(sound); ac.loop( ); } catch (MalformedURLException e) { // shouldn't happen }
3.21.76.0