CONTENTS |
One of the original tenets of Java was that applications could be delivered over the network to your computer as needed. Instead of buying a shrink-wrapped box containing a word processor, installing it, and upgrading it every few years, it should be possible to use the software directly from the Internet, safely and on any platform. This new model of software distribution would be a boon for both free software and for commercial products that could offer a new pay-per-use sales model. Unfortunately, this revolutionary idea has been hampered by the realities of a slow Internet and the uneven progress of Java on browsers (for reasons both technical and political). Even so, Java has maintained a toehold in this arena through small downloadable applications called applets.
An applet is part of a web page, just like an image or hyperlink. It "owns" some rectangular area of the user's screen. It can draw whatever it wants and respond to keyboard and mouse events in that area. When the web browser loads a page that contains a Java applet, it knows how to load the classes of the applet and run them.
This chapter describes how applets work and how to put them in web pages. We'll also describe how to use Sun's Java Plug-In to take advantage of the latest Java features. Finally, we'll cover the details of creating signed applets, which can step outside the typical applet security restrictions to do client-side things, such as reading and writing files.
The potential for applets to add dynamic content to web pages was one of the driving forces behind the spread of the Java programming language. Prior to Java's introduction in 1994, there was really no standard way to do this; even the now ubiquitous animated GIF images were not yet widely supported. Sun's HotJava Java-based web browser was the first to support applets. It was Java's original "killer application." Later, in 1995, Netscape announced that it would support the Applet API in its browsers, and soon after that Microsoft jumped on the bandwagon. For a while it seemed that Java would flourish on the Web. But there have been some bumps along the road.
Many problems, both technical and political, plagued the early years of Java's use in client-side applications. Performance issues were to be expected in such a young language. But what really crippled Java early on was the nonportable and buggy AWT, Java's original GUI toolkit. Many people overlook the fact that Java's success as a portable language is in large part a result of just how much of the Java API is implemented in Java. You might be surprised to learn just how many Java internals involve no native code—everything from cryptography to DNS has been done in Java—requiring no porting for new platforms. The renaissance of Java GUI applications seen in recent years (since Java 1.2) is due almost entirely to the introduction of the pure Java Swing GUI toolkit. In contrast, the original AWT system was based on native code, which had to be ported to each new system, taking into account subtle and tricky platform dependencies. AWT was effectively a large, graphical C program that Java talked to through a set of interfaces and Java was, to some extent, unfairly painted as nonportable and buggy by association.
Java faced other, less technical obstacles as well. Netscape forced the original AWT upon the world when it insisted that Java be released with "native look and feel" in lieu of a less capable, but portable initial toolkit. Later, Microsoft effectively stuck us with this by freezing the level of the Applet API in its browsers at Java 1.1 for many years. Applets have thus been stuck with AWT while lawsuits between Sun and Microsoft have dragged on. The result is that support for Applets in web browsers is a mess. There are a lot of applets on the Web today, but they only hint at Java's original promise. There is, however, some light on the horizon.
Sun has made an attempt to insulate Java from the browser battles with the introduction of the Java Plug-in. The Plug-in allows applets to run in an up-to-date Java VM, identically, in all major browsers. But for most browsers it requires installation by the user, which is less than desirable. More recently, Netscape 6 supports versions of Java using the Plug-in directly. If Netscape 6 sees wide distribution, we may finally have an up-to-date platform for applets. Newer APIs such as Java Web Start also offer the alternative of simple, zero administration, local installation of Java applications. It will be interesting to see if these catch on.
A JApplet is something like a JPanel with a mission. It is a GUI container that has some extra structure to allow it to be used in an "alien" environment, such as a browser. Applets also have a life cycle that lets them act more like an application than a static component, such as a paragraph of text or an image. Although applets tend to be relatively simple, there's no inherent restriction on their complexity, other than download speed. There's no reason you couldn't write a big application like a word processor as an applet.
The java.applet.Applet class defines the core functionality of an applet. It was used early on with AWT. The javax.swing.JApplet class is a simple extension of Applet that adds the plumbing necessary for Swing.
Structurally, an applet is a sort of wrapper for your Java code. In contrast to a standalone graphical Java application, which starts up from a main() method and creates a GUI, an applet is itself a component that expects to be dropped into someone else's GUI. Thus, an applet can't run by itself; it runs in the context of a web browser or a special applet-viewer program (which we'll talk about later). Instead of having your application create a JFrame to hold your GUI, you stuff your application inside a JApplet (which is itself a Container) and let someone else add your applet to their GUI.
Applets are placed on web pages with the <APPLET> HTML tag, which we'll cover later in this chapter. At its simplest, you just specify the name of the applet class and a size for the applet:
<APPLET code="AnalogClock" width="100" height="100"></APPLET>
Pragmatically, an applet is an intruder into someone else's environment and therefore has to be treated with suspicion. The web browsers that run applets impose restrictions on what the applet is allowed to do. The restrictions are enforced by an applet security manager. The browser provides everything the applet needs through an applet context—the API the applet uses to interact with its environment.
A JApplet expects to be embedded in a GUI (perhaps a document) and used in a viewing environment that provides it with resources. In all other respects, however, applets are just ordinary Panel objects. As Figure 22-1 shows, an applet is a kind of Panel. Like any other Panel, a JApplet can contain user-interface components and use all the basic drawing and event-handling capabilities of the Component class. You can draw on a JApplet by overriding its paint() method and respond to events in the JApplet's display area by providing the appropriate event listeners. Applets have additional structure that helps them interact with the viewer environment.
Aside from the top-level structure and the security restrictions, there is no difference between an applet and an application. If your application can live within the limits imposed by a browser's security manager, you can easily structure it to function as an applet and a standalone application. Normally you'll use the your applet class only as a handle to manage the life cycle and appearance of your application—create the GUI, start, and stop. So the bulk of your code should be easily adaptable to either a standalone or applet deployment.
The Applet class contains four methods that can be overridden to guide it through its life cycle. The init(), start(), stop(), and destroy() methods are called by the appletviewer or web browser to direct the applet's behavior. init() is called once, after the applet is created. The init() method is where you perform basic setup such as parsing parameters, building a user interface, and loading resources.
By convention applets don't provide an explicit constructor to do any setup. The reason for this is that the constructor is meant to be called by the applet's environment, for simple creation of the applet. This might happen before the applet has access to certain resources, such as information about its environment. Therefore, an applet doesn't normally do any work there; instead it relies on the default constructor for the JApplet class and does its initialization in the init() method.
The start() method is called whenever the applet becomes visible; it shouldn't be a surprise then that the stop() method is called whenever the applet becomes invisible. init() is called only once in the life of an applet, but start() and stop() can be called any number of times (although always in the logical sequence). The start() method is called when the applet is displayed, such as when it scrolls onto the screen; stop() is called if the applet scrolls off the screen, or the viewer leaves the document. start() tells the applet it should be active. The applet may want to create threads, animate, or otherwise perform useful (or annoying) activity. stop() is called to let the applet know it should go dormant. Applets should cease CPU-intensive or wasteful activity when they are stopped and resume it when (and if) they are restarted. However, there's no requirement that an invisible applet stop computing; in some applications, it may be useful for the applet to continue running in the background. Just be considerate of your user, who doesn't want an invisible applet dragging down system performance.
Finally, the destroy() method gives the applet a last chance to clean up before it's removed—some time after the last call to stop(). For example, an applet might want to close down suspended communications channels or remove graphics frames. Exactly when destroy() is called depends on the browser; Netscape calls destroy() just prior to deleting the applet from its cache. This means that although an applet can cling to life after being told to stop(), how long it can go on is unpredictable. If you want to maintain your applet as the user progresses through other pages of activities, you may have to put it in an HTML frame, so that it remains visible and won't be told to stop(). See Section 22.2.3.5 later in this chapter.
If you've been through the rest of this book you've already seen a couple of applets that snuck in among other topics. In Chapter 8, we created a simple clock applet, and in Chapter 12, we used an applet to send packets of information from a web browser. Now let's try a simple Swing-based example using JApplet. The following example, shown in Figure 22-2, ShowApplet , does nothing special, but you can use it to test the version of Java that's running in your browser (and see if the Plug-in is installed) and to see when the applet is started and stopped. It's a good reference.
import javax.swing.*; import java.awt.event.*; public class ShowApplet extends JApplet { JTextArea text = new JTextArea( ); int startCount; public void init( ) { JButton button = new JButton("Press Me"); button.addActionListener( new ActionListener( ) { public void actionPerformed( ActionEvent e ) { text.append("Button Pressed!\n"); } } ); getContentPane( ).add( "Center", new JScrollPane( text ) ); JPanel panel = new JPanel( ); panel.add( button ); getContentPane( ).add( "South", panel ); text.append( "Java Version: " +System.getProperty("java.version")+"\n" ); text.append( "Applet init( )\n" ); } public void start( ) { text.append( "Applet started: "+ startCount++ +"\n" ); } public void stop( ) { text.append( "Applet stopped.\n" ); } }
After compiling the applet, we have to create an HTML page in which to embed it. The following will do:
<html><head><title>ShowApplet</title></head> <body> <applet code="ShowApplet" WIDTH="300" HEIGHT="300"> Your browser does not understand Java.</applet> </body> </html>
We'll discuss the APPLET tag and other issues related to embedding applets in documents in detail later in this chapter. For now, just save this in a file called showapplet.html. Now load the file with your favorite web browser (we suggest Netscape 6.2 or later, which comes with a recent version of Java) and see what happens. If you have access to a web server you can use it. Otherwise you may have to use a URL like the following to point to your file:
file://localhost/c:/somedirectory/showapplet.html
The applet shows the version of Java running it and prints messages when its button is pressed. It also prints messages when its start() and stop() methods are called, along with a count. You can use this to experiment with different browsers and page-layout configurations to see when your applet is reloaded or restarted. If your browser fails to display the applet, don't despair. Later in this chapter we'll talk about how to convert the HTML to force the browser to use the Java Plug-in.
Applets are quarantined within the browser by an applet SecurityManager. The SecurityManager is part of the web browser or appletviewer. It is installed before the browser loads any applets and implements the basic restrictions that let the user run untrusted applets (loaded over the Internet) safely. Remember, there are no inherent security restrictions on a standalone Java application. It is the browser that limits what applets are allowed to do using a security policy.
Most browsers impose the following restrictions on untrusted applets:
Untrusted applets can't read or write files on the local host.
Untrusted applets can open network connections (sockets) only to the server from which they originated.
Untrusted applets can't start other processes on the local host.
Untrusted applets can't have native methods.
The motivation for these restrictions should be fairly obvious: you clearly wouldn't want a program coming from some random Internet site to access your files or run arbitrary programs. Although untrusted applets can't directly read and write files on the client side or talk to arbitrary hosts on the network, applets can work with servers to store data and communicate. For example, an applet can use Java's RMI facility to do processing on its server. An applet can communicate with other applets on the Net by proxy through its server.
We've been using the term untrusted applet, so it should come as no surprise that it is also possible to have such a thing as a trusted applet. Applets become trusted through the use of digital signatures, by signing the JAR file containing your applet code.Because a signature identifies the applet's origin unambiguously, we can now distinguish between trusted applets (i.e., applets that come from a site or person you trust not to do anything harmful) and run-of-the-mill untrusted applets. In browser environments that support signing, trusted applets can be granted permission to "go outside" of the applet security sandbox. Trusted applets can be allowed to do most of the things that standalone Java applications can do: read and write files, open network connections to arbitrary machines, and interact with the local operating system by starting processes. Trusted applets still can't have native methods, but including native methods in an applet would destroy its portability anyway.
Chapter 3 discussed how to package your applet's class files and resources into a JAR file. Later in this chapter we'll show you how to sign an applet with your digital signature.
An applet must communicate with its browser or applet viewer. For example, it may need configuration parameters from the HTML document in which it appears. An applet may also need to load images, audio clips, and other items. It may also want to ask the viewer about other applets on the same HTML page in order to communicate with them. To get resources from the environment, applets use the AppletStub and AppletContext interfaces, provided by the browser.
An applet gets its parameters from <PARAM> tags placed inside the <APPLET> tag in the HTML document, as we'll describe later. You can retrieve these parameters using Applet's getParameter() method. For example, the following code reads parameters called imageName and sheep from its HTML page:
String imageName = getParameter( "imageName" ); try { int numberOfSheep = Integer.parseInt(getParameter( "sheep" )); } catch ( NumberFormatException e ) { /* use default */ }
There is an API that allows an applet to provide information (help) about the parameters it accepts. The applet's getParameterInfo() can return an array of string arrays, listing and describing the applet's parameters. For each parameter, three strings are provided: the parameter name, its possible values or value types, and a verbose description. For example:
public String [][] getParameterInfo( ) { String [][] appletInfo = { {"logo", "url", "Main logo image"}, {"timer", "int", "Time to wait before becoming annoying"}, {"flashing", "constant|intermittant", "Flag for how to flash"} }; return appletInfo; }
However it's unclear who, if anyone, uses this API.
An applet can find out where it lives using the getDocumentBase() and getCodeBase() methods. getDocumentBase() returns the base URL of the document in which the applet appears; getCodeBase() returns the base URL of the Applet's class files (these two are often the same). An applet can use these methods to construct relative URLs from which to load other resources from its server like images, sounds, and other data. The getImage() method takes a URL and asks for an image from the viewer environment. The image may be pulled from a cache or loaded asynchronously when later used. The getAudioClip() method, similarly, retrieves sound clips.
The following example uses getCodeBase() to construct a URL and load a properties configuration file, located in the same remote directory as the applet's class file:
Properties props = new Properties( ); try { URL url = new URL(getCodeBase( ), "appletConfig.props"); props.load( url.openStream( ) ); } catch ( IOException e ) { /* failed */ }
A much better way to load resources is by calling the getResource() and getResourceAsStream() methods of the Class class, which search the applet's JAR files (if any) as well as its codebase. The following code loads the same properties file in a more portable way:
Properties props = new Properties( ); try { props.load( getClass( ).getResourceAsStream("appletConfig.props") ); } catch ( IOException e ) { /* failed */ }
An applet can ask its viewer to retrieve an image by calling the getImage() method. The location of the image to be retrieved is given as a URL, either absolute or fetched from an applet's resources:
public class MyApplet extends javax.swing.JApplet { public void init( ) { try { // absolute URL URL monaURL = new URL( "http://myserver/images/mona_lisa.gif"); Image monaImage = getImage( monaURL ); // applet resource URL URL daffyURL = getClass( ).getResource("cartoons/images/daffy.gif"); Image daffyDuckImage = getImage( daffyURL ); } catch ( MalformedURLException e ) { // unintelligable url } } // ... }
Again, using getResource() is preferred; it looks for the image in the applet's JAR file (if there is one), before looking elsewhere in the server's filesystem.
The status line is a blurb of text that usually appears somewhere in the web browser's display, indicating a current activity. An applet can request that some text be placed in the status line with the showStatus() method. (The browser isn't required to do anything in response to this call, but most browsers will oblige you.)
An applet can also ask the browser to show a new document. To do this, the applet makes a call to the showDocument(url) method of the AppletContext. You can get a reference to the AppletContext with the applet's getAppletContext() method. Calling showDocument(url) replaces the currently showing document, which means that your currently running applet will be stopped.
Another version of showDocument() takes an additional String argument to tell the browser where to display the new URL:
getAppletContext( ).showDocument( url, name );
The name argument can be the name of an existing labeled HTML frame; the document referenced by the URL is displayed in that frame. You can use this method to create an applet that "drives" the browser to new locations dynamically but keeps itself active on the screen in a separate frame. If the named frame doesn't exist, the browser creates a new top-level window to hold it. Alternatively, name can have one of the following special values:
Show in the current frame
Show in the parent of our frame
Show in outermost (top-level) frame
Show in a new top-level browser window
Both showStatus() and showDocument() requests may be ignored by a cold-hearted viewer or web browser.
Applets that are embedded in documents loaded from the same location on a web site can use a simple mechanism to locate one another (rendezvous). Once an applet has a reference to another applet, it can communicate with it, just as with any other object, by invoking methods and sending events. The getApplet() method of the applet context looks for an applet by name:
Applet clock = getAppletContext( ).getApplet("theClock");
Give an applet a name within your HTML document using the name attribute of the <APPLET> tag. Alternatively, you can use the getApplets() method to enumerate all the available applets in the pages.
The tricky thing with applet communications is that applets run inside the security sandbox. An untrusted applet can "see" and communicate only with objects that were loaded by the same class loader. Currently, the only reliable criterion for when applets share a class loader is when they share a common base URL. For example, all the applets contained in web pages loaded from the base URL of http://foo.bar.com/mypages/ should share a class loader and should be able to see each other. This includes documents such as mypages/foo.html and mypages/bar.html, but not mypages/morestuff/foo.html.
When applets do share a class loader, other techniques are possible too. As with any other class, you can call static methods in applets by name. So you could use static methods in one of your applets as a "registry" to coordinate your activities.
One of the biggest shortcomings of the Applet API is the lack of a real context for coordinating their activities during navigation across a multi-page document or web application. The Applet API simply wasn't designed for this. Although an applet's life cycle is well-defined in terms of its API, it is not well-defined in terms of management by the browser or scope of visibility. As we described in the previous section, applets loaded from the same code base can rendezvous at runtime using their name attributes. But there are no guarantees about how long an applet will live—or whether it will be stopped as opposed to being destroyed—once it is out of view. If you experiment with our ShowApplet in various browsers and in the Java Plug-in (which we'll discuss later), you'll see that in some cases the applet is stopped and restarted when the user leaves the page, but more often the applet is reinitialized from scratch. This makes designing multipage applications difficult.
One solution has been to use static methods as a shared "registry," as mentioned earlier. However the details governing how classes loaded by applets are managed are even less well-defined than the management of the applet's themselves. In Java 1.4, a new pair of methods was added to the AppletContext to support short-term applet persistence: setStream() and getStream(). With these methods, an applet can ask the context to save a stream of byte data by a key value and return it later. The notion of providing the state to the context as a stream is a little odd but easy enough to accommodate. Here is an example:
getAppletContext.setStream("myStream", new ByteArrayInputStream( "This is some test data...".getBytes( ) ) );
Later, the stream data can be retrieved:
InputStream in = getAppletContext.getStream( "myStream" );
Currently the data is retained only as long as the browser is running. But it's possible that a longer term persistence API will come about in the future. If you need more complex state and navigation capabilities, you might consider using a signed applet to write to a file or taking advantage of the new Java Web Start API to install your application locally.
The following lists summarize the methods of the Applet API. The first is from the AppletStub interface:
boolean isActive( ); URL getDocumentBase( ); URL getCodeBase( ); String getParameter(String name); AppletContext getAppletContext( ); void appletResize(int width, int height);
The second is from the AppletContext interface:
AudioClip getAudioClip(URL url); Image getImage(URL url); Applet getApplet(String name); Enumeration getApplets( ); void showDocument(URL url); public void showDocument(URL url, String target); void showStatus(String status);
These are the methods provided by the applet-viewer environment. If your applet doesn't happen to use any of them, or if you can provide alternatives to handle common cases (such as loading images), your applet can function as a standalone application as well as an applet. The basic idea is to add a main() method that provides a window (JFrame) in which the applet can run. Here's an outline of the strategy:
//file: MySuperApplet.java import java.applet.Applet; import java.awt.*; import javax.swing.*; public class MySuperApplet extends JApplet { // applet's own code, including constructor // and init( ) and start( ) methods public static void main( String [] args ) { // instantiate the applet JApplet theApplet = new MySuperApplet( ); // create a window for the applet to run in JFrame theFrame = new JFrame( ); theFrame.setSize(200,200); // place the applet in the window theFrame.getContentPane( ).add("Center", theApplet); // start the applet theApplet.init( ); theApplet.start( ); // display the window theFrame.setVisible(true); } }
Here we get to play "applet viewer" for a change. We have created an instance of the class, MySuperApplet, using its constructor—something we don't normally do—and added it to our own JFrame. We call its init() method to give the applet a chance to wake up and then call its start() method. In this example, MySuperApplet doesn't implement init() and start(), so we're calling methods inherited from the Applet class. This is the procedure an applet viewer would use to run an applet. (If we wanted to go further, we could implement our own AppletContext and AppletStub and set them in the JApplet before startup.)
Trying to make your applets into applications as well often doesn't make sense and is not always trivial. We show this example only to get you thinking about the real differences between applets and applications.
Applets are embedded in HTML documents with the <APPLET> tag. The <APPLET> tag resembles the HTML <IMG> image tag. It contains attributes that identify the applet to be displayed and, optionally, give the web browser hints about how it should be shown.[1]
The standard image tag sizing and alignment attributes, such as height and width, can be used inside the applet tag. However, unlike images, applets have both an opening <APPLET> and a closing </APPLET> tag. Sandwiched between these can be any number of <PARAM> tags that contain data to be passed to the applet:
<APPLET attribute attribute ... > <PARAM parameter > <PARAM parameter > ... </APPLET>
Attributes are name/value pairs that are interpreted by a web browser or applet viewer. Attributes of the <APPLET> tag specify general features that apply to any applet, such as size and alignment.[2] The definition of the <APPLET> tag lists a fixed set of recognized attributes; specifying an incorrect or nonexistent attribute should be considered an HTML error.
Three attributes are required in the <APPLET> tag. Two of these attributes, width and height, specify the space the applet occupies on the screen. The third required attribute must be either code or object; you must supply one of these attributes, and you can't specify both. The code attribute specifies the class file from which the applet is loaded; the object attribute specifies a serialized representation of an applet. Most often, you'll use the code attribute; the tools for creating serialized applets aren't quite there yet.
The following is an HTML fragment for a hypothetical simple clock applet that takes no parameters and requires no special HTML layout:
<APPLET code="AnalogClock" width="100" height="100"></APPLET>
The HTML file that contains this <APPLET> tag must be stored in the same directory as the AnalogClock.class class file. The applet tag is not sensitive to spacing, so the previous code is therefore equivalent to:
<APPLET code="AnalogClock" width="100" height="100"> </APPLET>
Which is a bit more readable.
Parameters are analogous to command-line arguments; they provide a way to pass information to an applet. Each <PARAM> tag contains a name and a value that are passed as strings to the applet:
<PARAM name = "parameter_name" value = "parameter_value">
Parameters provide a means of embedding application-specific data and configuration information within an HTML document. Our AnalogClock applet, for example, might accept a parameter that selects between local and universal time:
<APPLET code="AnalogClock" width="100" height="100"> <PARAM name="zone" value="GMT"> </APPLET>
Presumably, this AnalogClock applet is designed to look for a parameter named zone with a possible value of GMT.
Parameter names and values should be quoted and can contain spaces and other whitespace characters.
The parameters a given applet expects are, of course, determined by the developer of that applet. There is no standard set of parameter names or values; it's up to the applet to interpret the parameter name/value pairs that are passed to it. Any number of parameters can be specified, and the applet may choose to use or ignore them as it sees fit.
Web browsers are supposed to ignore tags they don't understand; if the web browser doesn't know about the <APPLET> or <PARAM> tags, we would expect them to disappear, and any HTML between the <APPLET> and </APPLET> tags to appear normally. By convention, Java-enabled web browsers ignore any extra HTML between the <APPLET> and </APPLET> tags. Combined, this means we can place some alternative HTML inside the <APPLET> tag, which is displayed only by web browsers that can't run the applet.
For our AnalogClock example, we could display a small text explanation and an image of the clock applet as a teaser:
<APPLET code="AnalogClock" width="100" height="100"> <PARAM name="zone" value="GMT"> <strong>If you see this you don't have a Java-enabled Web browser. Here's a picture of what you are missing.</strong> <img src="clockface.gif"> </APPLET>
We can now spell out the syntax for the full-blown <APPLET> tag:
<APPLET code = class_name or: object = serialized_applet_name width = pixels_high height = pixels_wide [ codebase = location_URL ] [ archive = comma_separated_list_of_archive_files ] [ name = applet_instance_name ] [ alt = alternate_text ] [ align = style ] [ vspace = vertical pad pixels ] [ hspace = horizontal pad pixels ] > [ <PARAM name = parameter_name value = parameter_value> ] [ <PARAM ... ] [ HTML code for non-Java-aware browsers ] </APPLET>
Either the code attribute or the object attribute must be present to specify the applet to run. The code attribute specifies the applet's class file; you'll see this most frequently. The object attribute specifies a serialized (pickled) representation of an applet. When you use the object attribute to load an applet, the applet's init() method is not called. However, the serialized applet's start() method is called.
The width, height, align, vspace, and hspace attributes determine the preferred size, alignment, and padding, respectively. The width and height attributes are required.
The codebase attribute specifies the base URL to be searched for the applet's class files. If this attribute isn't present, the browser looks in the same location as the HTML file. The archive attribute specifies a list of JAR or ZIP files in which the applet's class files are located. To put two or more files in the list, separate the filenames with commas; for example, the following attribute tells the browser to search three archives for the applet:
archive="Part1.jar,Part2.jar,Utilities.jar"
The archive files listed by the archive tag are loaded from the codebase URL. When searching for classes, a browser checks the archives before searching any other locations on the server.
The alt attribute specifies alternate text that is displayed by browsers that understand the <APPLET> tag and its attributes but can't actually run applets. This attribute can also describe the applet because, in this case, any alternate HTML between <APPLET> and </APPLET> is, by convention, ignored by Java-enabled browsers.
The name attribute specifies an instance name for the executing applet. This is a name specified as a unique label for each copy of an applet on a particular HTML page. For example, if we include our clock twice on the same page (using two applet tags), we should give each instance a unique name to differentiate them:
<APPLET code="AnalogClock" name="bigClock" width="300" height="300"> </APPLET> <APPLET code="AnalogClock" name="smallClock" width="50" height="50"> </APPLET>
Applets can use instance names to recognize and communicate with other applets on the same page. We could, for instance, create a "clock setter" applet that knows how to set the time on an AnalogClock applet and pass it the instance name of a particular target clock on this page as a parameter. This might look something like:
<APPLET code="ClockSetter"> <PARAM name="clockToSet" value="bigClock"> </APPLET>
The code attribute of the <APPLET> tag should specify the name of an applet. This is either a simple class name or a package path and class name. For now, let's look at simple class names; we'll discuss packages in a moment. By default, the Java runtime system looks for the class file in the same location as the HTML document that contains it. This location is known as the base URL for the document.
Consider an HTML document, clock.html, that contains our clock applet example:
<APPLET code="AnalogClock" width="100" height="100"></APPLET>
Let's say we retrieve the document at the following URL:
http://www.time.ch/documents/clock.html
Java tries to retrieve the applet class file from the same base location:
http://www.time.ch/documents/AnalogClock.class
The codebase attribute of the <APPLET> tag specifies an alternative base URL for the class file search. Let's say our HTML document now specifies codebase, as in the following example:
<APPLET codebase="http://www.joes.ch/stuff/" code="AnalogClock" width="100" height="100"> </APPLET>
Java now looks for the applet class file at:
http://www.joes.ch/stuff/AnalogClock.class
For "loose" applet class files that are not packaged into archives, Java uses the standard package name to directory path mapping to locate files on the server. The only difference is that the requests are not local file lookups but requests to the web server at the applet's codebase URL. Before a class file is retrieved from a server, its package-name component is translated by the client into a relative path name under the applet's codebase.
Let's suppose that our AnalogClock has been placed into a package called time.clock (a subordinate package for clock-related classes, within a package for time-related classes). The fully qualified name of our class is time.clock.AnalogClock. Our simple <APPLET> tag would now look like:
<APPLET code="time.clock.AnalogClock" width="100" height="100"></APPLET>
Let's say the clock.html document is once again retrieved from:
http://www.time.ch/documents/clock.html
Java now looks for the class file in the following location:
http://www.time.ch/documents/time/clock/AnalogClock.class
The same is true when specifying an alternative codebase:
<APPLET codebase="http://www.joes.ch/stuff/" code="time.clock.AnalogClock" width="100" height="100"> </APPLET>
Java now tries to find the class in the corresponding path under this base URL:
http://www.joes.ch/stuff/time/clock/AnalogClock.class
Sun's SDK comes with an applet-viewer program, aptly called appletviewer. To use appletviewer, specify the URL of the document on the command line. For example, to view our (still only theoretical) AnalogClock at the URL shown earlier, use the following command:
% appletviewer http://www.time.ch/documents/clock.html
appletviewer retrieves all applets in the specified document and displays each one in a separate window. appletviewer isn'tt a web browser; it doesn't attempt to display HTML. It's primarily a convenience for testing and debugging applets. If the document doesn't contain <APPLET> tags, appletviewer complains and does nothing.
The disadvantage of the <APPLET> tag is that you have to rely on the browser's Java interpreter. This is bad for two reasons:
The version of Java that is included in popular browsers lags the current version of Java by years. It was a painfully long time, for instance, between the release of Java 1.1 and the time that version was supported in Netscape and Internet Explorer. As a matter of fact, it hasn't ever been fully supported in Internet Explorer. Only Netscape 6.x now supports an up-to-date version of Java out of the box (using the Plug-in that we'll talk about in this section).
Historically Microsoft's version of Java has had its own bugs and idiosyncrasies, which were different from the bugs and idiosyncrasies of Sun's version. This effectively meant that testing had to be done on each platform, contrary to Java's write-once, run-anywhere proposition.
At the time of this writing, most popular versions of Netscape and Internet Explorer are moderately stable for Java 1.1 development. As a developer, though, you will want to use modern features of Java including Swing, Collections, and so on. So what can we do?
We might take the state of Java in the browser to indicate that applets are dead. But wait! A clever technology called the Java Plug-in saves the day. A plug-in is simply a loadable application module that is used to support new content types in a web browser. Both Navigator and Internet Explorer have a plug-in mechanism that allows the browser to be extended in this way.
Microsoft calls this technique ActiveX custom controls. But it's exactly the same concept: the browser gives control for a part of a web page to another piece of code. For example, you can view movies in your browser using Apple's QuickTime plug-in. You can view interactive multimedia with Macromedia's Shockwave plug-in. The idea is very similar to applets; basically the browser hands-off responsibility for some rectangular area on the screen to someone else's code. The Java Plug-in is simply a Java runtime environment implemented as a browser plug-in.
Applets that use the Java Plug-in can take advantage of the very latest Java platform features. With the Plug-in, Java developers can specify the version of Java they require, and their applets should run in exactly the same way in any browser using it. The browser isn't even really running the applet anymore; the Plug-in takes care of it.
This is nifty technology, but it does come at a price. Users who want to use the Java Plug-in to run applets have to download and install it first. While this is not a huge burden, it is a barrier to universal acceptance. Netscape 6.x comes with the Java Plug-in installed and uses it automatically. Netscape also supports the automated download of new Plug-in versions as they become available. But with the wide installed base of browser versions by both Microsoft and Netscape, installation will be an issue for some time to come.
The HTML for web pages that contain Plug-in applets is much messier than the <APPLET> tag you've already seen. Part of the problem is that you have to use specialized tags for Internet Explorer and Navigator. Navigator uses the <EMBED> tag for plug-ins, while Internet Explorer uses the <OBJECT> tag. However if you are clever about fitting the <EMBED> tag inside the <OBJECT> tag, you'll end up with some HTML that both browsers recognize and run correctly.
These tags have their own little syntax, but basically you're still providing the same information to the browser. You specify the size of the applet, the class name to use, the location of additional classes, and parameters that should be passed to the applet itself. Fortunately, you don't have to worry too much about the details. Sun provides a handy utility, the HTML Converter, which converts <APPLET> tags to the appropriate <EMBED> and <OBJECT> tags. Assuming you've set up your <APPLET> tag correctly, you should have no trouble converting your HTML page to use the Java Plug-in. This utility is available for download at http://java.sun.com/products/plugin/index-1.4.html
Suppose, for example, that you create a web page called ShowOff.html. Once you have the <APPLET> tag set up the way you want (you can test it with appletviewer), you can use the HTML Converter to set up your web page to use the Plug-in. The HTML Converter runs as a Swing application. To run it, navigate to the directory where you installed the HTML Converter and type the following:
C:\> java HTMLConverter
The window is pretty self-explanatory. You can convert all HTML files in a directory or just convert a single HTML file. The conversion is done "in-place," which means that your original HTML is overwritten with the new stuff. The Converter automatically backs up your old files unless you tell it otherwise.
You can perform different kinds of conversions, represented by different templates. By default, the HTML Converter uses the "standard" template that produces a page that works with Navigator and Internet Explorer on Windows and Solaris. If you choose "extended," it tries to produce a more elaborate version that should work on a wider set of browsers. In addition to adding the <EMBED> and <OBJECT> tags, the "extended" template preserves the original <APPLET> tag. This has the added benefit that you'll still be able to test your applet with appletviewer.
We should also note that in version 1.4, the Java Plug-in has a new feature: once installed, the Plug-in takes over control of the regular <APPLET> tag (at least for Internet Explorer) so that, by default, all applets begin to use the Plug-in. Once the Plug-in installation is boot-strapped, all applets benefit from it, regardless of whether the page uses the special tags. This is a major coup for Sun, and it will be interesting to see if it is supported in the future.
What actually happens when users browse to a page with a Plug-in applet? It depends, of course, on which browser you're using and what has been installed. If you are on a "virgin" system, Internet Explorer asks the user for permission to download and run the Java Plug-in to display the applet. Older versions of Netscape Navigator direct the user to the Java Runtime Environment (JRE) download page. (The Java Plug-in is distributed as part of the JRE.) In either case, the download and installation times vary, depending on network speed and user comfort level. You can expect that most Internet users will have to spend five to ten minutes downloading and installing the JRE.
The good news is that the installation needs to be done only once. When JRE is installed and running, you can view Plug-in applets immediately (at least as soon as the browser loads the Plug-in). The only time the user needs to install a new Plug-in is when a new version of Java comes out.
Despite the price of installation and HTML tag messiness, the Plug-in is powerful medicine indeed. No longer do you have to wait for browser vendors to implement the latest Java platform features; the Plug-in makes the latest Java releases available to applets immediately, and it provides a more hospitable environment for applets, regardless of what browser displays them.
The Java Web Start API is an interesting alternative to using applets. Java Web Start uses the Java Network Launching Protocol (JNLP) to transparently download and install Java applications locally. All the user has to do is to click on the install link on a web page. The installed applications can then be launched just like any installed application, by clicking on an icon on the desktop or through the Start menu, but they continue to be managed by the Java security policy and to be checked for automatic upgrades. Java Web Start is a form of zero administration client installation, which implies that the client doesn't have to do any work to install or maintain the application. JNLP applications may be signed, allowing the user to grant them fine-grained privileges, or unsigned. But even unsigned JNLP applications can take advantage of standard APIs that prompt the user for permission to perform basic operations such as opening files and printing.
Packaging your application to use JNLP is relatively easy, but we won't get into it here. The process mainly involves creating a JNLP deployment file that lists your JARs and specifies any special permission they require. You must then include an appropriate link in your web page that uses Web Start. The first time a user tries to install a JNLP application, they will have to install the Web Start plug-in (just like the Java Plug-in is installed). Thereafter, the plug-in manages all JNLP installs. See http://java.sun.com/products/javawebstart/ for more information.
Digital signatures provide a way to authenticate documents and other data. They solve one of the Internet's biggest problems: given that you've received a message from Ms. X, how do you know that the message really came from Ms. X and not an imposter? Just as important for Java, let's say that you've downloaded a great new applet written by your favorite author, Pat Niemeyer, and you'd like to grant it some additional privileges, so that it can do something cool for you. You trust that this particular author wouldn't intentionally distribute something harmful. But how do you know that this person really is who he says he is? And what if you downloaded the applet from a third-party location, like an archive? How can you be sure that someone hasn't modified the applet since the author wrote it? With Java's default security policies for web browsers, such an applet can't do anything serious, but when we're talking about configuring your browser to grant additional privileges to applets coming from trusted sites, you would be in for trouble—if it weren't for digital signatures.
Like their inky analogs, digital signatures associate a name with an item in a way that is difficult to forge. In reality, a digital signature is much more difficult to forge than a traditional signature. Furthermore, digital signatures provide another benefit: they allow you to authenticate a document, proving that it hasn't been altered in transit. In other words, you know who the sender is, and that the data you received is exactly what the sender sent. Some malicious person can't clip out a digital signature, modify the original document (or applet), and attach the old signature to the result. And he can't generate a new signature; at least, he can't generate a signature claiming that the document came from its original sender. (He could, of course, attach his own signature, but that would be like signing the stick-up note you hand to the bank teller.)
Digital signatures are based on public-key cryptography, which is beyond the scope of this book. However, the basics are important and interesting.[3] In a public-key system, there are two pieces of information: a public key and a private one. The keys have a special, asymmetric relationship, such that a message encrypted with one key can only be decrypted with the other key. Furthermore, if you know only one key, it is very difficult to compute the other. Therefore, if I give you my public key, you can use it to create an encrypted message that only I can read. No one else, including you, has enough information to go through the process of decrypting the encoded message, so it's safe to send it over untrusted networks. Furthermore, I can (and probably will) give my public key to anyone in the world, since the public key only lets people send me messages; it doesn't let them read my messages.
Digital signatures are based on the reverse process. If I encrypt something with my private key, anyone can use my public key to read the message. That may not sound very useful, since I already said that I'd give my public key away to anyone who wants it. But in this case, we're not trying to keep the message secret, we're trying to prove that I'm the only one who could have sent the message. And that's exactly what we've done. No one else has my private key, so no one else can send a message that can be decrypted with my public key. Therefore, only the real me could have sent the message.
We've simplified the process in one crucial way. Encrypting a large message with complex algorithms takes a long time, even with fast computers. And some public-key algorithms just aren't suitable for encrypting large amounts of data for other reasons, as well. For digital signatures, then, we don't usually encrypt the entire message. First, we use a standard algorithm to create a "hash" or "message digest." To produce the signature, we then encrypt the (relatively small) message digest with the private key. The recipient can then decrypt the signature with the public key and check whether the resulting message digest matches the message he received. If it does, the recipient knows the message hasn't been altered, and the sender is who he claims to be.
Digital signatures can be used to authenticate Java class files and other types of data sent over the network. The author of an object signs the data with his or her digital signature, and we use the author's public key to authenticate that signature after we retrieve it. We don't have to communicate with anyone in order to verify the authenticity of the data. We don't even have to make sure that the communications by which we received the data are secure. We simply check the signature after the data arrives. If it is valid, we know that we have the authentic data and that it hasn't been tampered with. Or do we?
Well, there is a larger problem digital signatures alone don't solve: verifying identity. If the signature checks out, we know that only the person (or entity) that published the public key could have sent the data. But how do we know that the public key really belongs to whomever we think it does? How do we associate an identity with that public key in the first place? We've made it more difficult to counterfeit a message, but it's not impossible. A forger could conceivably create a counterfeit Java class, sign it with his own private key, and try to trick you into believing that his public key is that of the real author or the trusted web site. In this case, you'll download the bad applet, then use the wrong public key to verify the applet, and be tricked into thinking that there's nothing wrong. This is where certificates and certificate authorities come into play.
A certificate is a document that lists a name and a public key. By a name, we mean some real-world information describing a person or entity. For example, a certificate might contain your full name and address or the name of a company and the location of its headquarters. We'll consider the combination of a name and a public key in this way to make up an identity. If we have valid information for a particular identity, we can verify data that the identity has signed.
A certificate is signed with the digital signature of a certificate authority (CA)—the entity that issued the certificate. The certificate is, in effect, a proclamation by the CA that the identity listed is valid—in other words, that the listed public key really does belong to the entity named. If we decide to trust the CA, we can then believe the identities contained in the certificates it issues are valid. The certificate acts as a sort of electronic ID card, backed up by the credentials of the CA. Of course, we no longer issue certificates on fancy vellum scrolls, as shown in Figure 22-3; the digital format for modern certificates is described by a standard called X.509.
This is all well and good, but the original problem remains: in order to verify the authenticity of a certificate, we need to verify its signature. Now, to do that, we need to know the CA's public key; rather than solving the problem, we simply seem to have shifted the problem to a new front. If a counterfeiter could substitute her public key for the public key of one entity, she might be able to do the same for the CA. But shifting the problem helps quite a bit. We have reduced the number of public keys we need to know from an unlimited number (all the identities we might ever encounter) to a very small number: one for each CA. We have chained our trust of the identity to the trust of the CA's identity. Chaining can be allowed to extend further, to an arbitrary depth, allowing CAs to back up lower CAs, and so on. At some point, of course, the chain has to stop, and that usually happens with a "self-signed" or certificate authority certificate; that is, a certificate that is issued by the CA for itself, containing its own public key. "What good is that?" you might ask.
As for the authenticity of the top-level CAs themselves, we have to rely on strong, well-known certificates that we have acquired by very secure or perhaps very tangible means. Web browsers, such as Netscape Navigator and Microsoft Internet Explorer, come with CA certificates for several popular CAs. Netscape Navigator and MSIE are, for example, shipped with a CA certificate for Verisign (http://www.verisign.com), so that you can safely verify any certificates signed by Verisign, wherever you encounter them. So, if all is working, we've reduced the problem to just that of your getting your copy of the web-browser software securely the first time. As far as maintenance goes, browsers like Netscape let you download new CA certificates dynamically, using a secure connection.
Certificates are presented to your web browser for verification when you encounter signed objects (signed JAR files). They are also issued by web servers when you make a secure connection using the HTTPS (HTTP Secure Sockets Layer) protocol. Browsers like Netscape and Internet Explorer may save these certificates encountered from third-party locations so that you can assign privileges or attributes to those identities and so that they can be recognized again. We'll call these certificates site certificates—though they may belong to any third party, like a person or an organization. For example, you might declare that objects signed by a certain site are allowed to write local files. The browser then saves that site's certificate, marking it with the privileges (writing local files) that it should grant.
Finally, you, the user, can have your own identity and your own certificates to validate your identity. Browsers such as Netscape Navigator store user certificates that can identify you to third parties. A user certificate is associated with a private key—the private key that goes with the public key in the certificate. When you use a private key to sign an object, the corresponding certificate is shipped as part of the signature. Remember, the recipient needs the public key in your certificate to validate your signature. The certificate says on whose authority the recipient should trust that public key.
So, where do you get private keys, public keys, and certificates validating your public keys? Well, as for the keys, you generate those yourself. No other party should ever have access to your private key, much less generate it for you. After you generate a public and private key pair, you send your public key to the CA to request that they certify you. The CA can make you jump through whatever hoops are necessary; when they are satisfied that you are who you say you are, they grant you a certificate.
In Netscape Navigator, this entire process can be accomplished by the user, within the browser, using the KEYGEN extension to HTML. You can then use Netscape tools to sign JAR files, send secure email, etc. The general Java tools are not quite as slick. The Java SDK supplies the keytool utility to manage keys and certificates.
keytool is the standard Java utility for managing a database of identities. With it, you can generate or import key pairs and certificates. You can then use these keys and certificates to sign JAR files.
The packages that implement cryptography in Java are part of the Java Cryptography Extension (JCE). As of Java 1.4, the JCE is bundled with the standard edition of Java. Prior to that it was an optional package (and subject to export restrictions). The JCE provides both framework and implementations of algorithms. The implementations are called "provider" packages; Sun's security provider package comes with the SDK by default. Other packages can be installed to provide additional or alternate implementations of the cryptographic algorithms. By default, keytool uses the implementations found in Sun's provider package, though it can use other packages if any are available.
The user interface to keytool is awkward. It's a good bet that someone will implement a key management utility with a friendlier GUI; maybe it will be supplied with a future version of Java. In any event, we won't spend a great deal of time discussing the details of keytool; it's more important to understand the concepts.
Before the debut of the Java Plug-in, Netscape and Microsoft both invented their own code-signing schemes. As a result, signed applets in the Java 1.1 world were a disaster. There were three different ways to sign and deploy code, one each for Netscape Navigator, Sun's HotJava, and Microsoft's Internet Explorer. Unless you knew in advance that you had only one kind of browser worry about, you were pretty much out of luck.
The Java Plug-in levels the field for signed applets, because the packaging and deployment strategy is the same for all browsers.
Before we dive into the details, let's take a look at an example, just to show that the process really works with the Java Plug-in. Use your browser to navigate to http://examples.oreilly.com/learnjava2/TestWrite/Unsigned.html. You'll see the applet shown in Figure 22-4. When you push the button, this applet attempts to write a harmless file on the local host. Give it a try. The applet should fail with a security exception and display a message.
Now try a web page that displays the same applet: http://examples.oreilly.com/learnjava2/TestWrite/Signed.html. The only difference is that we've signed the JAR file containing the applet, with a key and certificate generated using keytool.
When the Java Plug-in loads the applet's JAR file, it examines the signature. What happens next depends on whether you're using the latest Java Plug-in. With Java 1.4, the Plug-in prompts the user to decide whether or not to trust the code. In that case you get a dialog like Figure 22-5.
The dialog informs you that the applet is signed, in this case by Pat Niemeyer, and asks if you want to grant access to it. You can get information about the certificate used to sign the JAR by clicking on View Certificate. The two fields of interest are Issuer and Subject. In this case, we have signed the JAR file with our own self-issued certificate; the issuer and subject (or signer) are both identified as "Pat Niemeyer." After pondering our trustworthiness, you can grant the TestWrite applet permissions or deny them. You can also specify whether the permissions last for one session or are remembered until the certificate expires. If you deny permissions, the applet may still run; it depends on what it tries to do and how it handles being denied access. In this case, the applet prints the security exception when it tries to write the file. If you granted the applet permissions, hitting the button should show a successful write. In the next section, we'll look at how we created our certificate and signed this JAR.
If you have an older version of the Plug-in (Java 1.3 or lower) Java informs you it can't verify the signature. This is because Java doesn't know about our certificate, and older versions didn't prompt the user to accept unknown signers. We could manually install our certificate in the local Java environment, but this procedure is complicated. Fortunately with the Plug-in, we can specify the version required if we want to. (If you are interested in learning how to install keys manually for older versions of Java, you can find out all about it in the expanded material included on the accompanying CD-ROM; view CD content online at http://examples.oreilly.com/learnjava2/CD-ROM/.)
The SDK supports keystores that hold identities along with their public keys, private keys, and certificates. It includes the utility we covered earlier, keytool. We'll use this database as a repository while we create and work with our identity locally.
An identity can be a person, an organization, or perhaps a logical part of an organization. Before it can be used, an identity must have a public key and at least one certificate validating its public key. keytool refers to entities in the local database by IDs or aliases. These names are arbitrary and are not used outside the keystore (and possibly local Java security policy files that reference the keystore). Identities that have a private key stored locally in the keystore, as well as a public key, are called signers. These identities can be used to sign JAR files.
The default location for a keystore is the file .keystore in the user's home directory. On a single user system, the Java installation directory is used instead of the user's home directory. The default keystore location is used by keytool unless you specify another keystore with the -keystore option.
If you are going to maintain any private keys in a keystore (if you will have any signers), you must take special care to keep the keystore file safe (and not publicly readable). Private keys must be kept private.
We can create a new entry in the default keystore, complete with a key pair, with the following keytool command:
C:\> keytool -genkey -alias Pat -keyalg DSA -keysize 1024 -dname "CN=Pat Niemeyer, OU=Technical Publications, O=O'Reilly & Associates, C=US" -keypass secure -storepass boofa
There are a lot of options to explain. The most important one is -genkey, which tells keytool to create a new key pair for this entry. A key pair enables this entry to sign code. The -alias option supplies an alias for this entry, Pat. The -keyalg argument, DSA, is the algorithm for which we are going to generate the keys. The current release of Java supports only DSA, the Digital Signature Algorithm, which is a U.S. government standard for signing. The -keysize argument is the key length in bits. For most algorithms, larger key sizes provide stronger encryption. DSA supports keys of either 512 or 1024 bits. You should use the latter, unless you have a specific reason to do otherwise.
keytool generates the keys and places them in the default keystore. Private keys are specially protected using the -keypass option. To retrieve Pat's private key, you need the correct key password. The integrity of the keystore as a whole is protected by the -storepass option. You need to supply the same keystore password to retrieve data from this keystore later.
Once we've created a keystore entry, we can display it with the command:
C:\> keytool -list -alias Pat -storepass boofa
To see more detail, add the -v option (for "verbose"):
C:\> keytool -list -alias Pat -v -storepass boofa
We can also list the entire contents of the database:
C:\> keytool -list -storepass boofa
Now that we have keys, we want a certificate in which to wrap our public key for distribution. Ideally, at this point, we'd send a public key to a trusted CA and receive a certificate in return. keytool can generate such a request in a standard format called a Certificate Signing Request (CSR). To generate a signing request for the entry we just created, you would do this:
C:\> keytool -csr -alias Pat -file Pat.csr -keypass secure -storepass boofa
You need to specify the alias for the entry you want, a filename where the CSR will be written, and the password for the private key. The output file will contain the public key, along with the name and organizational information you provided. Once you've generated the CSR file, you can send it off to your favorite Certificate Authority. After they've performed some identity checks on you, and once you pay them, they will send a certificate back to you. Suppose they send it back in a file called Pat.x509. You can then use keytool to import this certificate as follows:
C:\> keytool -import -alias Pat -file Pat.x509 -keypass secure -storepass boofa
To demonstrate the features of keytool, we can serve as our own authority (as we did in the example) and use our own self-signed certificate. It turns out that keytool already did this for us when we created keys! A self-signed certificate already exists in the keystore; all we have to do is export it as follows:
C:\> keytool -export -alias Pat -file Pat.cer -storepass boofa
If we have a signer keystore entry, initialized with its private and public keys, we are ready to sign JAR files. This is accomplished using another command-line utility, jarsigner. All we need to do is specify which keystore entry should do the signing, which JAR needs to be signed, and the keystore password:
C:\> jarsigner -storepass boofa testwrite.jar Pat
If we now list the archive, we see that jarsigner has added two files to the META-INF directory: PAT.SF and PAT.DSA. PAT.SF is the signature file; it's like the manifest file for this particular signature. The signature file lists the objects that were signed and the signature algorithms. PAT.DSA is the actual binary signature.
In this chapter, we covered the events that led to the current, fractured applet world and set the scene for what's to come. The Java Plug-in is currently our best hope for Java in the browser to succeed, but newer technologies such as Java Web Start are making inroads. It's an exciting time for Java as it begins to bloom on the client side just as it has on the server side for a number of years.
[1] If you aren't familiar with HTML or other markup languages, you may want to refer to HTML and XHTML: The Definitive Guide by Chuck Musciano and Bill Kennedy (O'Reilly) for a complete reference on HTML and structured web documents.
[2] Many HTML tags besides <APPLET> have attributes.
[3] See Bruce Schneier's encyclopedic Applied Cryptography (John Wiley & Sons) or Jonathan Knudsen's Java Cryptography (O'Reilly).
CONTENTS |