Chapter 45

Network Programming and Java

by Jerry Ablan


CONTENTS

Years ago, programming network applications in any language was a real drag. Sometimes it involved writing specialized system software that talked directly to network drivers, or even the network cards themselves. Programming IPX/SPX applications in DOS or Windows used to require software interrupt handlers to be created. But with Java, creating network applications is a snap!

This chapter discusses the network classes in Java (in the java.net package). These make writing programs for communication over the Internet, intranets, or even local area networks, easier than in any other language.

The Java Socket Classes

Java has the same UNIX roots as the Internet. It's designed from the ground up as a networking language. We will quickly overview how Java makes network programming easier by encapsulating connection functionality in socket classes:

How the Internet Uses Sockets

You can think of any Internet server as a set of socket classes that provide additional capabilities-generally called services. Examples of services are electronic mail, telnet for remote logon, and File Transfer Protocol (FTP) for transferring files around the network. If the server to which you are attached provides Web access, then there is a Web service available as well.

Ports and Services

Each service is associated with a port. A port is a numeric address through which service requests (such as asking for a Web page) are processed. On a UNIX system, the particular services provided are in the /etc/services file. Here are a few lines from a typical /etc/services file:

daytime13/udp  
ftp21/tcp  
telnet23/tcp telnet
smtp25/tcp mail
www80/tcp  

The first column displays the system name of the service (daytime). The second column displays the port number and the protocol, separated by a slash (13/udp). The third column displays an alias to the service, if any. For example, smtp (the standard Simple Mail Transfer Protocol), also known as mail, is the implementation of e-mail service.

Communication of Web-related information takes place at Port 80 using the TCP protocol. To emulate this in Java, you use the Socket class. The daytime service occurs at Port 13 using the UDP protocol. To emulate this in Java a daytime server, use the DatagramSocket object.

The URL Class Revisited

The URL class contains constructors and methods for managing an URL: an object or service on the Internet. The TCP protocol requires two pieces of information: the IP address and the port number. So how is it possible that when you type

http://www.yahoo.com

you get Yahoo's home page?

First, Yahoo has registered its name, allowing yahoo.com to be assigned an IP address (say 205.216.146.71). This is resolved using your system's domain name resolution service.

Now what about the port number? If not specified, the server's port in /etc/services is used.

NOTE
The /etc/services is the file name on UNIX servers. On other platforms, the file name will probably be different. On a Windows 95 system, the file is called Services and is found in the Windows 95 directory.

The URL class allows for these variations in specification. There are four constructors:

public URL(String spec) throws MalformedURLException;
public URL(String protocol, String host, int port, String file) throws
     MalformedURLException;
public URL(String protocol, String host, String file) throws
     MalformedURLException;
public URL(URL context, String spec) throws MalformedURLException;

You can thus specify each piece of the URL, as in URL("http","www.yahoo.com",80,"index.html"), or enable the defaults to take over, as in URL("http://www.yahoo.com"), letting Yahoo figure out all the pieces.

Mapping Java Sockets to Internet Sockets

Sockets are based on a client/server model. One program (the server) provides the service at a particular IP address and port. The server listens for service requests, such as requests for Web pages, and fills the order. Any program that wants to be serviced (a client, such as a Web browser) needs to know the IP address and port to communicate with the server.

An advantage of the socket model over other forms of data communication is that the server doesn't care where the client requests come from. As long as the client is sending requests according to the TCP/IP protocol, the requests will reach the server-provided the server is up and the Internet isn't too busy. What the particular server program does with the request is another matter.

This also means that the client can be any type of computer. No longer are we restricted to UNIX, Macintosh, DOS, or Windows platforms. Any computer that supports TCP/IP can talk to any other computer that supports it through this socket model. This is a potentially revolutionary development in computing. Instead of maintaining armies of programmers to port a system from one platform to another, you write it once in Java. Any computer with a Java virtual machine can run it.

Java socket classes fit nicely into this picture. You implement a server by creating subclasses of Thread and overriding the run() method. The Java virtual machine can then perform the thread management without the program having to worry. So, with a few lines of code, you can write a server that can handle as many data communications sessions as you want. And data transmission is simply a matter of calling the Socket methods.

Creating a Telnet Server

The procedure for creating a server is to create a ServerSocket object, which listens on a particular port for client requests. When it recognizes a valid request, it creates a Socket object through which the data conversation can take place. This socket is like a pipe through which data can pass back and forth. In fact, it's very similar to a UNIX pipe. The stream classes are used to route data back and forth efficiently.

Listing 45.1 is a prototype for a line-oriented telnet server, enabling remote logons to a network on the Internet. The server prompts the client for ID and password and, if the user is authorized, prints a welcome message. For our network, the telnet service is on port 23.


Listing 45.1  TelnetServer.java-A Prototype Telnet Server
//***********************************************************************
//* Imports                                                             *
//***********************************************************************

import           java.net.*;
import           java.io.*;

//***********************************************************************
//* TelnetServer                                                        *
//***********************************************************************

public class
TelnetServer
extends Thread
{

//***********************************************************************
//* Constants                                                           *
//***********************************************************************

     public static final int           TELNET_PORT = 23;

//***********************************************************************
//* Variables                                                           *
//***********************************************************************

     protected     ServerSocket          listener;

//***********************************************************************
//* main                                                                *
//***********************************************************************

     public static void
     main( String args[] )
     {
          new TelnetServer();
     }

//***********************************************************************
//* fail                                                                *
//***********************************************************************

     public static void
     fail( Exception e, String msg )
     {
          System.err.println( msg + "." + e );
          System.exit( 1 );
     }

//***********************************************************************
//* Constructor                                                         *
//***********************************************************************

     public
     TelnetServer()
     {
          //     Try and create the socket...
          try
          {
               listener = new ServerSocket( TELNET_PORT, 5 );
          }
          catch ( IOException e )
          {
               fail( e, "Could not start Telnet server" );
          }

          //     Show something to the user...
          System.out.println( "Telnet server started" );

          //     Start up the thread...
          start();
     }

//***********************************************************************
//* run                                                                 *
//***********************************************************************

     public void
     run()
     {
          try
          {
               while ( true )
               {
                    Socket client = listener.accept();
                    TelnetThread c = new TelnetThread( client );
               }
          }
          catch ( IOException e )
          {
               fail( e, "Unable to accept incoming client connection" );
          }
     }
}

//***********************************************************************
//* TelnetThread                                                        *
//***********************************************************************

class
TelnetThread
extends Thread
{

//***********************************************************************
//* Variables                                                           *
//***********************************************************************

     protected     Socket                    sClient;
     protected     DataInputStream          disIn;
     protected     PrintStream               psOut;

//***********************************************************************
//* Constructor                                                         *
//***********************************************************************

     public
     TelnetThread( Socket client )
     {
          try
          {
               //     Save a copy of our client socket...
               sClient = client;

               //     Don't cross the streams!
               disIn = new DataInputStream( client.getInputStream() );
               psOut = new PrintStream( client.getOutputStream() );

               //     Start up the client...
               start();
          }
          catch ( IOException e )
          {
               try
               {
                    client.close();
               }
               catch ( IOException ioe )
               {
                    System.err.println( "Error creating streams: " +
                        ioe );
}
          }
     }

//***********************************************************************
//* run                                                                 *
//***********************************************************************

     public void
     run()
     {
          String          user, password;
          int               len;

          try
          {
               while ( true )
               {
                    //     Get the user name...
                    psOut.print( "Login: " );
                    user = disIn.readLine();
                    psOut.println( "\r" );

                    if ( user == null )
                         break;

                    //     Get the password...
                    psOut.print( "Password: " );
                    password = disIn.readLine();
                    psOut.println( "\r" );

                    if ( password == null )
                         break;

                    /*
                    *
                    * You'll want to do some user/password checks here.
                    * If all is cool, let the user know:
                    */

                    psOut.print( "\n\rWelcome! You're now connected." +
                         " Please enter a command: " );

                    /*
                    * Here you can do all your functionality. When
                    * you are done, break out of this loop
                    */
               }
          }
          catch ( IOException e )
          {
               // Handle any errors
          }

          finally
          {
               try
               {
                    sClient.close();
               }
               catch ( IOException ioe )
               {
                    System.err.println( "Error closing client socket: " +
                        ioe );
}
          }
     }
}

Okay, now let's take a close look at our server source code.

Classes Used by the Server Program

From java.net, we use the ServerSocket class (to create a socket where the server listens for remote logon requests) and the Socket class (to create the socket through which the telnet conversation occurs).

From java.io, you use the IOException class (to handle errors). The DataInputStream class handles traffic from the client to the server (that is, input to the server). The PrintStream class handles traffic from the server to the client ("printing" to the client).

Creating the Telnet Server Class

Note that our telnet server is a subclass of Thread. A ServerSocket object (server_listening_object) is declared in our variable declaration section. It will later do the work of listening for client telnet requests.

Our error-handling routine, called fail(), takes two arguments: an Exception object and a String object. It prints an error message if there is any problem starting the server, and exits.

The constructor creates and starts a ServerSocket thread. An error message is produced if there's a problem. Note the statement that actually constructs the server socket:

listner = new ServerSocket( TELNET_PORT, 5 );

This form of the ServerSocket constructor takes two integer arguments. The first argument, the port number, is a constant that we've defined. It is set to 23 because that is the well-known telnet port.

The second argument is a count of the number of concurrent telnet services that we want to allow. We will allow five telnet sessions in this example. The actual setting is a server configuration issue. If we allow more sessions, we also allocate more server memory. The potential for overloading the server exists because each session requires additional memory.

The run() Method: Listening for Client Requests

The server's run() method is where the work is done. In this case, the server goes into an infinite loop and "listens" for client requests. When the server "hears" the client, the server calls the ServerSocket's accept() method, which accepts the connection. Then the server creates a TelnetClient thread, passing it a Socket object where the telnet conversation actually occurs.

The main() Method: Starting the Server

The main() method is very simple. It simply creates an instance of our server class, TelnetServer. This method is required to run non-Applet programs.

The Telnet Thread: The Work Gets Done

The TelnetThread class is where the conversation actually takes place. TelnetThread creates a DataInputStream object (disIn), which retrieves input from the client using the GetInputStream() method, and a PrintStream object (psOut), which enables the server to write output to the client using the GetOutputStream() method. Thus, a two-way conversation can occur. If this happens successfully, the telnet session starts.

After the server connects, it issues the Login: prompt by printing it to the client using the print() method of the psOut object. Next, the server uses the readLine() method to store the logon ID in the string variable, user. The server now needs the password, so it uses the print() method again to issue the Password: prompt. Then the server issues another readLine(), storing the user's entry in another string variable, password.

From this point, it's up to the program to verify the logon ID and password. You could implement a password table, which contains the user names and their passwords. If the password is stored in encrypted format, this would be the place to decrypt it.

TIP
When encrypting passwords for user entries, never store the unencrypted version of the password. You really don't have to. This is because when a user enters his or her password, you simply encrypt their entry and compare it to the stored encrypted version.

If the user is authorized, the session can begin using the stream objects that have been set up. Typically, the server prompts for a command and uses a case statement to either perform the command or deny access.

When it's time to log off, the server issues a break to exit the loop. This causes the finally statement to execute, closing the client socket. Closing the socket is critical because, otherwise, you'll exhaust server memory before long. The finally clause ensures that the client socket is closed. You can't count on Java's garbage collection to close the socket.

CAUTION
The 32-bit Windows implementation of the JDK version 1.0.2 does not correctly close sockets. This is a bug that Sun is aware of and will fix in the JDK version 1.1 release.

Note that the server is multithreaded, as each client that connects gets its own thread in the server. This is quite an impressive result in so few lines of code!

Writing a Client Program to Communicate with the Server

Listing 45.2 is a prototype for a client program that talks to our telnet server.


Listing 45.2  TelnetClient.java-A Prototype Telnet Client
//***********************************************************************
//* Imports                                                             *
//***********************************************************************

import          java.net.*;
import          java.io.*;

//***********************************************************************
//* TelnetClient                                                        *
//***********************************************************************

public class
TelnetClient
{

//***********************************************************************
//* main                                                                *
//***********************************************************************

     public static void
     main( String[] args )
     {
          new TelnetClient();
     }

//***********************************************************************
//* Constructor                                                         *
//***********************************************************************

     public
     TelnetClient()
     {
          Socket      s = null;

          try
          {
               //     Create a new socket...
               s = new Socket( "localhost", TelnetServer.TELNET_PORT );

               //     Convert the streams...
               DataInputStream disIn = new DataInputStream(
                   s.getInputStream() );
PrintStream psOut = new PrintStream(
                   s.getOutputStream() );

               //     Convert the System.in (stdin) to a DataInputStream...
               DataInputStream stdin = new DataInputStream( System.in );

               String     line;

               while ( true )
               {
                    line = disIn.readLine();

                    if ( line == null )
                         break;

                    System.out.println( line );

                    line = stdin.readLine();

                    if ( line == null )
                         break;

                    psOut.println( line );
               }
          }
          catch ( IOException e )
          {
               System.out.println( e );
          }

          finally
          {
               try
               {
                    if ( s != null )
                         s.close();
               }
               catch ( IOException e2 )
               {
                    //     Handle any errors...
               }
          }
     }
}

The client program is simpler and similar to the TelnetThread class. We create a Socket object, specifying the host address and port. The client must know both of these before connecting to the server. We'll assume that the host is localhost. The telnet port as we already know is port 23, and we reuse the constant that was created in our server class.

After connecting successfully with the server, we create two DataInputStream objects: one to get data from the server and the other to get data from the user (System.in). We also create a PrintStream object so we can "print" to the server. The client goes into a read/write loop until it receives no more input from the server, at which time it closes the socket.

Classes Used by the Client Program

The client only needs the Socket class from the java.net package. The client uses the getInputStream() method to receive data from the server and the getOutputStream() method to send data to the server. These methods support TCP, ensuring reliable data communication across the network.

From the java.io package, the program imports IOException (for I/O error handling), DataInputStream (for reading input from a stream), and DataOutputStream (for writing to a stream).

The main() Function

This function simply creates an instance of our TelnetClient class.

The Constructor

TelnetClient consists only of a constructor. In it, a Socket object is created. Socket takes two arguments: the Internet address ("localhost") and the telnet port (TelnetServer.TELNET_PORT). After the Socket object is created, the following three streams are created:

The program then goes into an infinite loop. Within the loop, we read input from the server. If our request for data from the server returns a null value, we know that the connection has been lost. At this point we exit the program.

If data is available, we retrieve it and print it to the screen or terminal. After the socket was established, the server printed out Login: using the print() method on its PrintStream object (remember? From the TelnetServer class?). Here in our loop, we read that in and print it out.

After we've retrieved any received data from the server, our class retrieves data from the user. We get this using the readLine() method. It waits for a carriage return before continuing. Once this returns with our input string, we use the println() method on its PrintStream object (attached to the same socket as the server) to print back to the server.

The exchange continues until the socket is closed. We have established a line-oriented conversation between client and server. What happens after that depends on the particular application's requirements and is beyond the scope of this discussion.

Communicating with Datagram Sockets

Communication using datagram sockets is simpler than using the TCP-based sockets (Socket and ServerSocket) that we used for our telnet server. Communications are also faster because there is no connection overhead. There's also no attempt to send packets again if an error occurs, or sequencing of multiple packets, as occurs in TCP/IP transmissions.

A datagram packet is simply sent as an array of bytes to a receiving program, presumably listening at a particular IP address and port. If the receiving program gets the datagram and wants to send a reply, it becomes the sender that is addressing a datagram back to a known IP address and port. The conversation style is a bit like those old movies in which the pilot sends a message, says "over," and waits for ground control to respond.

You might use datagram socket communication if you're writing an interactive game or, as in many UNIX systems, for returning a small piece of information (such as the time), when you don't want the overhead of establishing a connection or (in the case of the time server) when the communication takes place locally.

Sending a Datagram Packet

Listing 45.3 is a prototype program for sending a datagram packet. It will send a 27-byte message ("I'm a datagram and I'm Okay") to the IP address mapped to "localhost" at port number 6969. When you try this, use an IP address and port that you know is available. These values should work on most machines. Error handling is notably absent from this example. You should insert the appropriate try blocks and catch statements to handle errors gracefully.


Listing 45.3  DatagramSend.java-A Prototype Program to Send a Datagram Packet
//***********************************************************************
//* Imports                                                             *
//***********************************************************************

import           java.net.*;

//***********************************************************************
//* DatagramSend                                                        *
//***********************************************************************

public class
DatagramSend
{
     public static void
     main( String args[] )
     throws Exception
     {
          String           strToSend = "I'm a datagram and I'm Okay";

          byte[]           bArray = new byte[ strToSend.length() ];
          int           port = 6969;

          //     Suck the bytes out of the string into our byte array...
          strToSend.getBytes( 0, strToSend.length() - 1, bArray, 0 );

          //     Get the IP address of our destination...
          InetAddress inetAddr = InetAddress.getByName( "localhost" );

          //     Create the packet...
          DatagramPacket packet = new DatagramPacket( bArray,
               strToSend.length(),
               inetAddr,
               port );

          //     Now send that bad fella...
          DatagramSocket socket = new DatagramSocket();
          socket.send( packet );
          socket.close();
     }
}

We only need to use one socket: the DatagramSocket. There is no concept of the server listening for client requests. The idea is just to establish a DatagramSocket object and then send and receive messages. The messages are sent in a DatagramPacket object. An additional object, InetAddress, is needed to construct the IP address to send the packet.

The DatagramSend class has only one method, main(), so it's a stand-alone Java program. This demonstration program only sends one message. You can, of course, modify main() to pass any message to any IP address and port. Because main() throws Exception, we have declared that we're not handling errors in this class.

The DatagramPacket constructor that we use has the following four arguments:

Another form of the constructor requires only the first two arguments. It's designed for local communication when the IP address and port are already known. You'll see it in action in the next section, "Receiving a Datagram Packet."

We first create a string (strToSend) that contains the string we want to send. We then create a byte array that is as long as our string. We use the String class's length() method to do this. The port variable is used to store our port, 6969.

The getBytes() instance method of the java.lang.String class converts strings into byte array form. We store this in our byte array bArray.

The getByName() method of InetAddress converts a string into an Internet address in the form that the DatagramPacket constructor accepts.

Next, an instance of DatagramPacket is created with the above arguments. Finally, the packet is sent using the send() instance method of the DatagramPacket.

Receiving a Datagram Packet

The packet is on its way, so it's time to receive it. Listing 45.4 creates the receiving program.


Listing 45.4  DatagramReceive.java-A Prototype Program to Receive a Datagram Packet
//***********************************************************************
//* Imports                                                             *
//***********************************************************************

import          java.net.*;

//***********************************************************************
//* DatagramReceive                                                     *
//***********************************************************************

public class
DatagramReceive
{
     public static void
     main( String args[] )
     throws Exception
     {
          String           rxString;
          byte[]          rxBuffer = new byte[ 2048 ];

          //     Create a packet to receive into...
          DatagramPacket rxPacket = new DatagramPacket( rxBuffer,
              rxBuffer.length );

          //     Create a socket to listen on...
          DatagramSocket rxSocket = new DatagramSocket( 6969 );

          //     Receive a packet...
          rxSocket.receive( rxPacket );

          //     Convert the packet to a string...
          rxString = new String( rxBuffer, 0, 0, rxPacket.getLength() );

          //     Print out the string...
          System.out.println( rxString );

          //     Close the socket...
          rxSocket.close();
     }
}

The DatagramReceive class, like the DatagramSend class, uses the DatagramSocket and DatagramPacket classes from Java.net. First, create a buffer large enough to hold the message. Our buffer (rxBuffer) is a 2K byte array. Your buffer size may vary. Just make sure it will hold the largest packet you'll receive.

Then, create a datagram packet. Note that the receive program already knows its IP address and port, so it can use the two-argument form of the constructor. The DatagramSocket is set up to receive data at port 6969.

The receive() method of Datagram receives the packet as a byte array. The String (rxString) is constructed out of the byte array, and it is printed on the terminal once received. Finally, the socket is closed, freeing memory instead of waiting for Java's garbage collection.

TIP
To alternately get the IP address of the host you're running on, call the getLocalHost() and getAddress() methods of the class java.net.InetAddress. First, getLocalHost() returns an INetAddress object. Then, you use the getAddress() method, which returns a byte array consisting of the four bytes of the IP address, as in the following example:
InetAddress internet_address = InetAddress.getLocalHost();
   byte[] ipaddress = internet_address.getAddress();
If the IP address of the network you're running on is 221.111.112.23, then
ipaddress[0] = 221
ipaddress[1] = 111
ipaddress[2] = 112
ipaddress[3] = 23

Customized Network Solutions

The Internet provides no transactional security whatsoever. Nor do the socket-oriented communications methods we've discussed verify whether any particular request for reading or writing data is coming from a source that should have such access. To do this, you need a customized network protocol.

These protocols sit as a layer between your network protocol (that is, TCP/IP) and your application. They encrypt outgoing packets and decrypt incoming packets, while verifying that you're still talking to who you think you're talking to.

Netscape has proposed the Secure Sockets Layer (SSL) protocol. SSL is a protocol that resides between the services, such as telnet, FTP, and http, and the TCP/IP connection sessions that have been illustrated. SSL would check that the client and server networks are valid, provide data encryption, and ensure that the message does not contain any embedded commands or programs. SSL would thus provide for secure transactions to occur across the Internet.

Another proposal is to write a server that provides security from the start. This is the idea behind Secure Hypertext Transport Protocol (S-HTTP), developed by Enterprise Information Technologies (EIT), RSA Labs, and the National Center for Supercomputer Applications (NCSA).

NOTE
NCSA is the group that developed Mosaic, the first graphical Web browser. The Mosaic design team went on to fame and fortune by completely rewriting Mosaic to create a new and original Web browser. The result was Netscape Navigator. 

ON THE WEB
http://www.commerce.net:80/software/Shttpd  This is the site where you can find the specifications of S-HTTP.

In your organization, you might want to provide a firewall between the public and private areas of your network; thus, there are a number of reasons you might need more protection for your network than TCP/IP provides.

Java provides a set of methods for implementing either of these strategies, called SocketImpl, an abstract class. To use it, you create a subclass and implement its methods, such as connecting to the server, accepting client requests, getting file information, writing to local files, and so on. Even if you've never written your own server or created a custom socket class, it's nice to know that it's possible to do it in Java. Java's own Socket and ServerSocket classes use the SocketImpl class as a base. The source code for these two classes can provide you with an excellent example of how to implement your own custom socket class.

Will Security Considerations Disable Java Applets?

Imagine a world in which Java applets on any network can set up client/server communications of the type discussed in this chapter. Perhaps an applet on my network can call a method in an applet on your network or run a program on your network remotely. For example, an applet connects to a quote server, determines that the price of a certain stock has reached the target price, and then connects to a user's machine on a network, displaying a message and requesting permission to buy. Or perhaps the applet can run an Excel spreadsheet macro to update the portfolio every 10 minutes. Many powerful applets could be written.

With this power comes potential danger. How can we prevent the applet from deleting files, downloading unauthorized data, or even being aware of the existence of such files? In this world of distributed objects, there's a profound tension between enabling more capabilities for an applet and fear of unwanted use.

This is why the debate on object access is fierce. The main stage is a standard called Common Object Request Broker Architecture.

ON THE WEB
http://www.acl.lanl.gov/CORBA  This is the site where you can find the CORBA documentation and specifications.

CORBA is a consortium of many computer companies that allow requests and responses to be made securely from distributed objects. Microsoft is, of course, one of the participants. They have a protocol for requesting objects called Object Linking and Embedding (OLE). OLE's main purpose is for one Windows application to access information in another Windows application. OLE is more platform-specific than CORBA. It's worth watching the progress of the debate. Will Java applets be allowed to run Windows DLLs so they can communicate with Windows objects? How open will OLE become?

Currently, applets loaded from a network cannot run Windows DLLs on the local machine, and they are forbidden to run local commands, such as the DOS DIR command, that would find out the names of files on the client. In addition, applets cannot make network connections, except to the network they're on.

NOTE
These limitations apply only to applets loaded from a network. Locally loaded applets are not restricted in this manner.

The debate between power and security seems to be veering towards the security side. An example is a "bug" that Drew Dean, Ed Felten, and Dan Wallach of Princeton University found in Netscape Navigator 2.0, running a Java applet. They were able to trick the domain name server (DNS) (the program that resolves host names, such as www.yahoo.com, into IP addresses) into disguising their origin. They were able to make the DNS believe they were actually from another computer and then were able to breach its security. Netscape acknowledged the situation and quickly provided an update (version 2.01) that provided more close control over how an IP address is resolved.

This situation caused a real stir. Concerns about Internet security were rampant. Also, concerns were rampant that applet access would be restricted to the point that usefulness of the applications would be greatly diminished.

Sun has suggested a naming convention for running applets across networks. The convention would be based on the IP address of the network where the applet resides. Perhaps in the future, digital signatures will be attached to applets before they run. For more information about Java and applet security, take a look at

http://www.sun.com/sfaq

(Frequently Asked Questions about Java and applet security) for developments. You may also want to look at Chapter 46, "Java and Security."