Java Applets Notes:
-------------------------------------------------------------------------------------

A program that is an applet must import the applet class Applet. This class is
located in the applet package. Therefore to import this class, the syntax is

	import java.applet.Applet;

When creating the applet's classname, you must use the 'extends Applet' syntax
within the declaration string. For example:

	public class Name extends Applet {
		...
	}

An applet class has four methods that are useful overriding by your applet
sub-class. These methods are:

	init
		To initialize the applet each time it's loaded (or reloaded).
	start
		To start the applet's execution, such as when the applet's
		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.

These methods are not always needed by an applet subclass. Many useful applets
do not call them at all, for example an applet that simply draws itself.

The init method is where most code that would normally go into a constructor
is used. An applet is not guaranteed to have full environment until the init
method is called, applets should not usually have a constructor for this
reason.

Every applet that does something after initialization (except in direct
response to user actions) must override the start method.

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.

-------------------------------------------------------------------------------------

The paint method is one of two display methods an applet can override: 

	paint
		The basic display method. Many applets implement the paint
		method to draw the applet's representation within a browser
		page.
	update
		A method you can use along with paint to improve drawing
		performance.

To react to an event, an applet must override either the appropriate
event-specific method or the handleEvent method. For example, adding
the following code to the Simple applet makes it respond to mouse clicks.

	import java.awt.event.MouseListener;
	import java.awt.event.MouseEvent;
	...
	public class SimpleClick extends Applet implements MouseListener {
		...
		public void init() {
			addMouseListener(this);
			...
		}
		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!... ");
		}
	}

-------------------------------------------------------------------------------------

Adding User Interface (UI) components:

The java programming language offers pre-made UI components. The following
is a list of these:

	Buttons (java.awt.Button)
	Checkboxes (java.awt.Checkbox)
	Single-line text fields (java.awt.TextField)
	Larger text display and editing areas (java.awt.TextArea)
	Labels (java.awt.Label)
	Lists (java.awt.List)
	Pop-up lists of choices (java.awt.Choice)
	Sliders and scrollbars (java.awt.Scrollbar)
	Drawing areas (java.awt.Canvas)
	Menus (java.awt.Menu, java.awt.MenuItem, java.awt.CheckboxMenuItem)
	Containers (java.awt.Panel, java.awt.Window and its subclasses)

Applet container methods (Applet inherits from the Container class):

	add		- Adds the specified Component.
	remove		- Removes the specified Component.
	setLayout	- Sets the layout manager.

To add a text field to the Simple applet, use the following code:

	//Importing java.awt.Graphics is no longer necessary
	//since this applet no longer implements the paint method.
	. . .
	import java.awt.TextField;
	public class ScrollingSimple extends Applet {
		//Instead of using a StringBuffer, use a TextField:
		TextField field;
		public void init() {
			//Create the text field and make it uneditable.
			field = new TextField();
			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);
			validate();
			addItem("initializing... ");
		}
		. . .
		void addItem(String newWord) {
			//This used to append the string to the StringBuffer;
			//now it appends it to the TextField.
			String t = field.getText();
			System.out.println(newWord);
			field.setText(t + newWord);
			repaint();
	}
	//The paint method is no longer necessary,
	//since the TextField repaints itself automatically.

After all this, the init method calls the validate method (which Applet inherits
from Component). Invoking validate once after adding one or more Components to an
applet is a bit of voodoo that ensures that the Components draw themselves onscreen.

-------------------------------------------------------------------------------------

Applet Security:

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.

	It cannot start any program on the host that's executing it.

	It cannot read certain system properties.

	Windows that an applet brings up look different than windows that an
	application brings up.

	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.

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.

	Although most applets stop running once you leave their page, they don't
	have to.

Loading executable code over the network is a classic security risk. For
Java applets, some of this risk is reduced because the Java language is
designed to be safe -- for example, it doesn't allow pointers to random
memory. In addition, Java-compatible browsers improve security by imposing
restrictions. These restrictions include disallowing applets from loading
code written in any non-Java language, and disallowing applets from reading
or writing files on the browser's host.

-------------------------------------------------------------------------------------

Browsers and Applets:

When a Java-enabled browser encounters an  tag, it reserves a display
area of the specified width and height for the applet, loads the bytecodes for
the specified Applet subclass, creates an instance of the subclass, and then
calls the instance's init and start methods.

When testing a java applet, a java enabled browser may not reload

-------------------------------------------------------------------------------------

Finding and loading data files:

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 Applet getCodeBase method, is a
URL that specifies the directory from which the applet's classes were loaded.
The document base, returned by the Applet getDocumentBase method, specifies
the directory of the HTML page that contains the applet.

To create an Image object using the a.gif image file under imgDir, the applet
can use the following code:

	Image image = getImage(getCodeBase(),"imgDir/a.gif");

Applets display status lines with the showStatus method. Here is an example
of it's use:

	showStatus("MyApplet: Loading image file " + file);

With the AppletContext showDocument methods, an applet can tell the browser
which URL to show and in which browser window. (By the way, the JDK Applet
Viewer ignores these methods, since it can't display documents.) 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.

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.

	"windowName"
		Display the document in a window named windowName.
	"_blank"
		Display the document in a new, nameless window.
	"_self"
		Display the document in the window and frame that contain the applet.
	"_parent"
		Display the document in the applet's window but in the 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 applet's window but in the top-level
		frame. If the applet's frame is the top-level frame, this acts the
		same as "_self".

The following is the applet code that calls the showDocument method:

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

Applet Interaction:

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.

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  tag.
	For example:

		
			. . .
		

	By specifying a NAME parameter with a  tag.
	For example:

		
			. . .
		

		myName = getParameter("NAME");

The getApplet should (on most browsers) be case insensitive.

The sender applet code:

	Applet receiver = null;
	String receiverName = nameField.getText(); //Get name to search for.
	receiver = getAppletContext().getApplet(receiverName);

The receiver applet code:

	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.\n");
		} else {
			status.appendText("Found applet named " + receiverName + ".\n"+ "  Sending message to it.\n");
			//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);
		}
	}
	. . .

For the receiver to communicate back, it needs this code:

	((Receiver)receiver).startCommunicating(this);

The getApplets method returns a list 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.

Below are the relevant parts of the method that calls getApplets:

	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 + "\n");
			} else {
				textArea.appendText("- " + applet.getClass().getName() + "\n");
			}
		}
		. . .
	}

-------------------------------------------------------------------------------------

Applets And Sound:

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.

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.
		}
	}

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 methods, 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.

-------------------------------------------------------------------------------------

Applet Parameters:

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.

When implementing parameters, you must answer four questions:

	What should the applet let the user configure?

		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.

	What should the parameters be named?
		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.

	What kind of value should each parameter take?

	What should the default value of each parameter be?
		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.

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)

Here is an example:

	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.

Below is the AppletButton code that gets the applet's parameters:

	String windowClass;
	String buttonText;
	String windowTitle;
	int requestedWidth = 0;
	int requestedHeight = 0;
	. . .
	public void init() {
		windowClass = getParameter("WINDOWCLASS");
		if (windowClass == null) {
			windowClass = "TestWindow";
		}
		buttonText = getParameter("BUTTONTEXT");
		if (buttonText == null) {
			buttonText = "Click here to bring up a " + windowClass;
		}
		windowTitle = getParameter("WINDOWTITLE");
		if (windowTitle == null) {
			windowTitle = windowClass;
		}
		String windowWidthString = getParameter("WINDOWWIDTH");
		if (windowWidthString != null) {
			try {
				requestedWidth = Integer.parseInt(windowWidthString);
			} catch (NumberFormatException e) {
				//Use default width.
			}
		}
		String windowHeightString = getParameter("WINDOWHEIGHT");
		if (windowHeightString != null) {
			try {
				requestedHeight = Integer.parseInt(windowHeightString);
			} catch (NumberFormatException e) {
				//Use default height.
			}
		}

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 of 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.

-------------------------------------------------------------------------------------

Practical Considerations When Writing Applets:

Using the Java API:

if(DEBUG) {
	System.out.println("Called someMethod(" + x + "," + y + ")");
}
if(DEBUG) {
	System.err.println("Called someMethod(" + x + "," + y + ")");
}

Applets can read the following system properties: 

	KEY			MEANING
	"file.separator"	File separator (for example, "/")
	"java.class.version"	Java class version number
	"java.vendor"		Java vendor-specific string
	"java.vendor.url"	Java vendor URL
	"java.version"		Java version number
	"line.separator"	Line separator
	"os.arch"		Operating system architecture
	"os.name"		Operating system name
	"path.separator"	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");

Forbidden System Properties

For security reasons, no existing browsers or applet viewers let applets read
the following system properties:

	KEY			MEANING
	"java.class.path"	Java classpath
	"java.home"		Java installation directory
	"user.dir"		User's current working directory
	"user.home"		User home directory
	"user.name"		User account name

A thread - (sometimes called an execution context or a lightweight process)
is a single sequential flow of control within a process. Even the simplest
applets run in multiple threads, although it's not always apparent. Many
applets create and use their own threads so that they perform well without
affecting the performance of the browser they run in or the performance of
other applets.

Rule of Thumb: If an applet performs a time-consuming task, it should create and
use its own thread to perform that task.

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.

	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.

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.

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 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.

-------------------------------------------------------------------------------------

Before You Ship That Applet

Stop! Before you let the whole world know about your applet, make sure the answer
to all of the following questions is yes.

1. Have you removed or disabled debugging output?

	Debugging output (generally created with System.out.println), while
	useful to you, is generally confusing or annoying to users. If you
	need to give textual feedback to the user, try to do it inside the
	applet's display area or in the status area at the bottom of the window.

2. 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 stop method so that it stops
	and destroys (by setting to null) the threads you launched.

3. If the applet does something that might get annoying, 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 mouseDown method so that
	a mouse click suspends or resumes the annoying thread.
	For example:

		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;
		}

Implement your applet with parameters for flexibility.

Implement the getParameterInfo method.

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";
		}

-------------------------------------------------------------------------------------

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's called from
a constructor.

-------------------------------------------------------------------------------------