With so many people networking at espresso bars, it's a natural that Java programs can be connected to a network. Okay, bad pun; let's move on. To enable your Java applets and applications to access files on another system, you use the classes in the
java.net package.
These classes provide cross-platform abstracts for simple network operations, such as connecting to other systems and performing file read, write, and copy operations. To create and maintain the link to the other system on the network, the classes use
basic UNIX-like sockets and common Web protocols. Using the java.net classes in conjunction with input and output streams (which you'll learn much more about later this week), makes reading and writing files over a network as easy as reading or writing
files on a local disk.
Of course, there are restrictions due to the security implementation in Java. Even though your applet may use the network classes, the Java applet will not be allowed to read or write disk files on the user's machine, unless the user gives applets
explicit permission. Moreover, depending on the browser being used, the user may not even be allowed to re-configure applet permissions. Microsoft Internet Explorer 3.0 and Netscape Navigator 2.0x both allow the user to configure applet settings.
COM (and ActiveX, discussed on Day 15) do allow your applet to connect to another system. Only standard plain-vanilla Java does not. This chapter deals with the standard Java implementation of network access.
Although you may not (that is, aren't allowed to) connect to another system, you may still use the network classes to link to the same system in which the applet was stored. Even given these restrictions, you can still accomplish a great deal and use
the Web or any other network to your advantage.
Throughout this section, we'll be discussing networks, the Internet, and the Web. All the same principles apply, regardless of whether your applet is running on the Internet or an intranet. The added benefit of an intranet is that you may have more control of the runtime environment (that is, which browser(s) are being used and how they are configured to work with applets). Keep these ideas in mind as you work with this section.
This section describes three ways you can communicate with systems on a network:
Probably the easiest way to implement a network connection inside an applet is to tell the browser running that applet to load a new page. This technique is used frequently to create an animated image map that loads a new page when clicked.
To link to a new page, you create a new instance of the class URL. You saw some of this when you worked with images, but let's go over it a little more thoroughly here.
The URL class defines a Uniform Resource Locator. To create a new URL object, you can use one of four different forms:
For that last one (creating a URL from a string), you have to catch a malformed URL exception (we'll do Exceptions in more detail on Day 19), so surround the URL constructor with a try...catch:
String url = "http://www.yahoo.com/"; try { theURL = new URL(url); } catch ( MalformedURLException e) { System.out.println("Bad URL: " + theURL); }
Because using these methods is so easy, identifying the URL object is the hardest part. Once you identify one, all you have to do is pass it to the browser. You do this by using the following single line of code, where theURL is the URL object to link
to:
getAppletContext().showDocument(theURL);
getAppletContext() returns the document (environment) where the applet is running. showDocument(theURL) replaces the Web page currently being viewed with the one located at that URL.
Listing 16.1 shows an applet that displays three buttons. An image of the running applet is shown in Figure 16.1. Clicking on one of the buttons causes the document to be loaded from the location to which the button refers.
Listing 16.1. Bookmark buttons.
1:import java.applet.*; 2:import java.awt.*; 3:import java.net.URL; 4:import java.net.MalformedURLException; 5:import DlgButtons; 6: 7:public class ButtonLink extends Applet implements Runnable 8:{ 9: Thread m_ButtonLink = null; 10: Bookmark bmlist[] = new Bookmark[3]; 11: DlgButtons m_dlgButtons; 12: 13: public void init() 14: { 15: bmlist[0] = new Bookmark("Microsoft's Home Page", 16: "http://www.microsoft.com"); 17: bmlist[1] = new Bookmark("Yahoo", 18: "http://www.yahoo.com"); 19: bmlist[2]= new Bookmark("VJ++ Updates", 20: "http://www.microsoft.com/visualj/updates/"); 21: m_dlgButtons = new DlgButtons( this ); 22: m_dlgButtons.CreateControls(); 23: m_dlgButtons.ID_B1.setLabel(bmlist[0].name); 24: m_dlgButtons.ID_B2.setLabel(bmlist[1].name); 25: m_dlgButtons.ID_B3.setLabel(bmlist[2].name); 26: resize(320, 240); 27: } 28: 29: public void start() 30: { 31: if (m_ButtonLink == null) 32: { 33: m_ButtonLink = new Thread(this); 34: m_ButtonLink.start(); 35: } 36: } 37: 38: public void stop() 39: { 40: if (m_ButtonLink != null) 41: { 42: m_ButtonLink.stop(); 43: m_ButtonLink = null; 44: } 45: } 46: 47: public void run() 48: { 49: while (true) 50: { 51: try 52: { 53: repaint(); 54: Thread.sleep(50); 55: } 56: catch (InterruptedException e) 57: { 58: stop(); 59: } 60: } 61: } 62: 63: public boolean action(Event evt, Object arg) 64: { 65: if (evt.target instanceof Button) 66: { 67: LinkTo((String)arg); 68: return true; 69: } 70: else return false; 71: } 72: 73: void LinkTo(String name) 74: { 75: URL theURL = null; 76: for (int i = 0; i < bmlist.length; i++) 77: { 78: if (name.equals(bmlist[i].name)) 79: { 80: theURL = bmlist[i].url; 81: } 82: } 83: if (theURL != null) 84: { 85: getAppletContext().showDocument(theURL); 86: } 87: } 88:} 89: 90:class Bookmark 91:{ 92: String name; 93: URL url; 94: Bookmark(String name, String theURL) 95: { 96: this.name = name; 97: try 98: { 99: this.url = new URL(theURL); 100: } 101: catch ( MalformedURLException e) 102: { 103: System.out.println("Bad URL: " + theURL); 104: } 105: } 106:}
Three classes make up this applet: The first implements the actual applet itself called ButtonLink, the second is a class representing a bookmark called BookMark, and the third is generated by the Java Resource Wizard to display the buttons and is
called DlgButtons.
The DlgButtons dialog box resource is a very simple resource. The dialog box has only three buttons on it, which have IDs (not the captions) of ID_B1, ID_B2, and ID_B3 respectively. The captions for these three buttons are irrelevant at design time,
since lines 15, 17, and 19 set the button captions.
This particular applet creates three bookmark instances and stores them in an array of bookmarks. (This applet could be easily modified to accept bookmarks as parameters from an HTML file.) For each bookmark, the label of one of the buttons in the
DlgButtons instance, m_dlgButtons, is set to the value of the bookmark's name.
When the buttons are pressed, the action method calls the linkTo() method, which tells the browser to load the URL referenced by that bookmark.
Figure 16.1. Bookmark buttons in Internet Explorer.
Sometimes, instead of simply having a browser load a Web page, you might want to get hold of that file's contents, so that your applet can use it. If the file you want to grab is stored on the Web, and can be accessed using the URL forms (HTTP, FTP,
and so on from the last exercise), use them in your applet to get the file's contents. However, when the URL form won't do, the following methods might work for you.
Remember, due to Java's security implementation, applets can, by default, connect back only to the same host from which they were originally loaded. This means that if you have your applets stored on a system called www.myhost.com, the only machine your applet can open a connection to will be www.myhost.com (and that same hostname), so be careful with host aliases. If the file the applet wants to retrieve is on that same system, using URL connections is the easiest way to get it.
URL defines a method called openStream(), which opens a network connection using the given URL and returns an instance of the class InputStream (part of the java.io package). If you convert that stream to a DataInputStream (with a BufferedInputStream
in the middle for better performance), you can read characters and lines from that stream. (You'll learn all about streams on Day 20.) For example, these lines open a connection to the URL stored in the variable theURL, and then read and echo each line of
the file to the standard output:
try { InputStream in = theURL.openStream(); DataInputStream data = new DataInputStream(new BufferedInputStream(in); String line; while ((line = data.readLine()) != null) { System.out.println(line); } } catch (IOException e) { System.out.println("IO Error: " + e.getMessage()); }
You need to wrap all those lines in a try...catch statement to catch IOExceptions generated.
Here's an example of an applet that uses the openStream() method to open a connection to a Web site, reads a file from that connection (Edgar Allen Poe's poem "The Raven"), and displays the result in a text area. Listing 16.2 shows the code;
Figure 16.2 shows the result after the file has been read.
Listing 16.2. The GetRaven class.
1: import java.awt.*; 2: import java.io.DataInputStream; 3: import java.io.BufferedInputStream; 4: import java.io.IOException; 5: import java.net.URL; 6: import java.net.URLConnection; 7: import java.net.MalformedURLException; 8: 9: public class GetRaven extends java.applet.Applet implements Runnable 10:{ 11: 12: URL theURL; 13: Thread runner; 14: TextArea ta = new TextArea("Getting text...", 30, 70); 15: 16: public void init() 17: { 18: String url = "http://www.lne.com/Web/Java/raven.txt"; 19: try 20: { 21: this.theURL = new URL(url); 22: } 23: catch 24: ( MalformedURLException e) 25: { 26: System.out.println("Bad URL: " + theURL); 27: } 28: add(ta); 29: } 30: 31: public Insets insets() 32: { 33: return new Insets(10,10,10,10); 34: } 35: 36: public void start() 37: { 38: if (runner == null) 39: { 40: runner = new Thread(this); 41: runner.start(); 42: } 43: } 44: 45: public void stop() 46: { 47: if (runner != null) 48: { 49: runner.stop(); 50: runner = null; 51: } 52: } 53: 54: public void run() 55: { 56: InputStream conn; 57: DataInputStream data; 58: String line; 59: StringBuffer buf = new StringBuffer(); 60: 61: try 62: { 63: conn = theURL.openStream(); 64: data = new DataInputStream(new BufferedInputStream(conn)); 65: 66: while ((line = data.readLine()) != null) 67: { 68: buf.append(line + "\n"); 69: } 70: 71: ta.setText(buf.toString()); 72: } 73: catch 74: (IOException e) 75: { 76: System.out.println("IO Error:" + e.getMessage()); 77: } 78: } 79: }
Figure 16.2. The GetRaven class.
The init() method (lines 16 to 29) sets up the URL and the text area in which that file will be displayed. The URL could be easily passed into the applet via an HTML parameter; here, it's just hard-coded for simplicity.
Because it might take some time to load the file over the network, you should put that routine into its own thread and use the familiar start(), stop(), and run() methods to control that thread.
Inside run() (lines 54 to 78), the work takes place. Here, you initialize a bunch of variables and then open the connection to the URL (using the openStream() method in line 63). Once the connection is open, you set up an input stream in lines 64 to 68
and read from it, line by line, putting the result into an instance of StringBuffer (a string buffer is a modifiable string).
After all the data has been read, line 71 converts the StringBuffer object into a real string and then puts that result in the text area.
One other thing to note about this example is that the part of the code that opened a network connection, read from the file, and created a string is surrounded by a try and catch statement. If any errors occur while you're trying to read or process
the file, these statements enable you to recover from them without the entire program crashing (in this case, the program exits with an error, because there's little else to be done if the applet can't read the file). try and catch give you the capability
of handling and recovering from errors. You'll learn more about exceptions on Day 19.
URL's openStream() method is actually a simplified use of the URLconnection class. URLconnection provides a way to retrieve files by using URLson Web or FTP sites, for example. URLconnection also enables you to create output streams if the
protocol allows it.
To use a URL connection, you create a new instance of the class URLconnection, set its parameters (whether it enables writing, for example), and then use the connect() method to open the connection. Keep in mind that, with a URL connection, the class
handles the protocol for you based on the first part of the URL, so you don't have to make specific requests to retrieve a file; all you have to do is read it.
For network applications beyond what the URL and URLconnection classes offer (for example, for other protocols or for more general network applications), Java provides the Socket and ServerSocket classes as an abstraction of standard socket programming
techniques.
I won't provide you with a full explanation of how socket programming works because there isn't enough space here to do it. See whether openStream() will meet your needs. If it doesn't and you haven't worked with sockets before, procure a book dedicated to socket programming. Hopefully, it will give you the background you need to work with Java's sockets.
The Socket class provides a client-side socket interface similar to standard UNIX sockets. To open a connection, create a new instance of Socket (where hostname is the host to connect to, and portnum is the port number):
Socket connection = new Socket(hostname, portnum);
If you use sockets in an applet, you are still subject to the Java security restrictions.
Once the socket is open, you can use input and output streams to read and write from that socket. (You'll learn all about input and output streams on Day 20.)
DataInputStream in = new DataInputStream( new BufferedInputStream(connection.getInputStream())); DataOutputStream out= new DataOutputStream( new BufferedOutputStream(connection.getOutputStream()));
When you're done with the socket, don't forget to close it. (When you close the socket, you also close all the input and output streams you may have set up for that socket.)
connection.close();
Server-side sockets work similarly, with the exception of the accept() method. A server socket listens on a TCP port for a connection from a client; when a client connects to that port, the accept() method accepts a connection from that client. By
using both client and server sockets, you can create applications that communicate with each other over the network.
To create a server socket and bind it to a port, create a new instance of ServerSocket with a port number:
ServerSocket sconnection = new ServerSocket(8888);
To listen on that port (and to accept a connection from a client if one is made), use the accept() method:
sconnection.accept();
Once the socket connection is made, you can use input and output streams to read from and write to the client.
See the java.net package for more information about Java sockets.
On this, the shortest day, let's finish with some small hints that didn't fit in anywhere else: using showStatus() to print messages in the browser's status window, providing applet information, and communicating between multiple applets on the same
page.
The showStatus() method, available in the applet class, enables you to display a string in the status bar of the browser. You can use this for printing error, link, help, or other status messages:
getAppletContext().showStatus("Change the color");
The getAppletContext() method enables your applet to access features of the browser that contains it. You already saw a use of this with links, wherein you could use the showDocument() method to tell the browser to load a page. showStatus() uses that
same mechanism to print status messages.
Even though showStatus() is a useful way of communicating optional information to your user, it may not be supported in all browsers, so don't depend on it for your applet's functionality or interface. If you need a more reliable method of communication, set up a label in your applet and update it with messages.
The AWT gives you a mechanism for associating information about your applet. Usually, there is a mechanism in most browsers to view the information you embed in your applet. You can use this mechanism to include your name or your organization, version,
date, or any other pertinent information in your applet. When you use the VJ++ Applet Wizard, this information is captured (on screen 7) and the method is automatically overridden.
To provide information about your applet, override the getAppletInfo() method:
public String getAppletInfo() { return "Name: ButtonBookmarks\r\n" + "Author: Patrick J Winters\r\n" + "Created with Microsoft Visual J++ Version 1.0"; }
You might want to have an HTML page that has several different applets on it. To do this, include several different iterations of the applet tag; the browser will create different instances of your applet for each one that appears on the HTML page.
But, what if you also want communication between those applets? What if you want a change in one applet to affect the other applets?
The best way to do this is to use the applet context to get access to the different applets on the same page. You've already seen several uses of the getAppletContext() method; you can also use it to get a hold of the other applets on the page. For
example, to call the sendMessage() method in all the applets on a page (including the current applet), use the getApplets() method and a for loop that looks something like the following:
for (Enumeration e = getAppletContext().getApplets(); e.hasMoreElements();) { Applet current = (Applet)(e.nextElement()); current.sendMessage(); }
The getApplets() method returns an Enumeration object with a list of the applets on the page. Iterating over the Enumeration object in this way enables you to access each element in the Enumeration in turn.
If you want to call a method in a specific applet, it's only slightly more complicated: Give each of your applets a name in the HTML file and then refer to them by their name inside the body of the applet code.
To give an applet a name, use the NAME parameter in the HTML file:
<P>This applet sends information: <APPLET CODE="MyApplet.class" WIDTH=100 HEIGHT=150 NAME="sender"> </APPLET> <P>This applet receives information from the sender: <APPLET CODE="MyApplet.class" WIDTH=100 HEIGHT=150 NAME="receiver"> </APPLET>
To get a reference to another applet on the same page, use the getApplet() method from the applet context using the name of that applet. This gives you a reference to the applet of that name. You can then refer to that applet as if it were just another
objectcall methods, set its instance variables, and so on:
// get ahold of the receiver applet Applet receiver = getAppletContext().getApplet("receiver"); // tell it to update itself. reciever.update(text, value);
In this example, you use the getApplet() method to get a reference to the applet with the name receiver. Given that reference, you can then call methods in that applet as if it were just another object in your own environment. Here, for example, if
both applets have an update() method, you can tell receiver to update itself by using the information the current applet has.
Naming your applets and then referring to them by using the methods described in this section enables your applets to communicate and stay in sync with each other, providing uniform behavior for all the applets on your page.
Today and yesterday have been full of useful information about connecting to a network using Java and COM, and using Java methods for socket sessions.
Today you had a brief introduction to Java network connections through some of the classes in the java.net package. Applet network connections include things as simple as pointing the browser to another page from inside your applet, but can also
include retrieving files from the Web by using standard Web protocols (HTTP, FTP, and so on). For more advanced network session capabilities, Java provides basic socket interfaces that can be used to implement many basic network-oriented applets:
client/server interactions, chat sessions, and so on.
Finally, you finished up with the tidbitssmall features of the Java AWT and of applets that didn't fit anywhere else, including showStatus(), providing information about your applet, and communicating between multiple applets on a single page.
Q: showStatus() doesn't work in my browser. How can I give my readers status information?
A: As you learned in the section on showStatus(), whether or not a browser supports showStatus() is up to that browser. If you must have status-like behavior in your applet, consider creating a status label in the applet itself. Then update the
label with the information you need to present.
Q: It looks like the openStream() method and the Socket classes implement TCP sockets. Does Java support UPD (datagram) sockets?
A: The JDK 1.0 provides two classes, DatagramSocket and DatagramPacket, which implement UDP sockets. The DatagramSocket class operates similarly to the Socket class. Use instances of DatagramPacket for each packet you send or receive over the
socket.
See the java.net package in the API documentation for more information.
Q: I've seen something called applet properties in the Java documentation. What are properties?
A: Properties are features of applets and the applet environment that you can test for and make decisions in your code based on their values.