Once two applets have located each other, their means of communication is the same as for any two objects in the system. This means they can invoke each other's methods, share common arrays between them, or send data over stream pipes.
A stream pipe is a pair of streams: One is an input stream; the other is an output stream. Any data written to the input stream can be read from the output stream it is connected to. You can use this mechanism to pass data between two applets or any two objects in the system. One object creates both a PipedInputStream and a
PipedOutputStream class, and then passes one end of the pipe to the other object. Whichever object has the output end of the pipe can then start writing to the pipe, while the object that has the input side can start reading.
Tip
Since stream pipes are subclasses of FileInputStream and
FileOutputStream, you can use the existing stream filters to pass different kinds of data. The DataInputStream and DataOutputStream classes are good for passing simple data types over pipes, while the
ObjectInputStream and ObjectOutputStream are excellent for passing whole objects.
Stream pipes are useful for doing sequenced messaging between objects. Sometimes one object needs to tell another object to perform several tasks in sequence. If some of the tasks take a long time, you don't want the requesting object to have to wait for all the tasks to be performed, yet you want to ensure that they are done in the proper sequence. If the requests are made by sending messages over a stream pipe, the sequencing problem is solved, as is the waiting problem. The requesting object can write all its requests to the PipedOutputStream and continue on. The object performing the tasks reads each message from its PipedInputStream, performs the requested task, and then reads the next message from the pipe. The messages are guaranteed to be read in the same sequence they were written.
Listing 10.2 shows an applet that creates a stream pipe and passes one end of the pipe to another applet. It demonstrates how to create a pipe and how to wait for an applet to appear. The SenderApplet first looks for its companion applet- ReaderApplet. Since the sender may be loaded before the reader, it must retry the search if it can't find the reader the first time it checks. It tries once every second for 30 seconds before deciding that the reader isn't going to be loaded.
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/ch10.htm
Once the sender finds the reader, it passes one end of the stream pipe to the reader through a simple method call. If you find that you frequently need to pass stream pipes this way, you should define an interface line this:
public interface StreamPipeClient {
public void setInputStream(InputStream); }
This frees the sender from having to know the exact class name of the reader. As you can see in Listing 10.2, the sender knows that the reader is an instance of ReaderApplet.
Listing 10.2 Source Code for SenderApplet.java
import java.applet.*; import java.io.*;
// This applet creates a stream pipe and uses it to pass // data to another applet. It waits for the other applet to // be loaded, then invokes a method on that applet to pass it // the input side of the pipe.
public class SenderApplet extends Applet implements Runnable {
protected PipedInputStream inStream; protected PipedOutputStream outStream; Thread appletThread;
public void init() {
// Create the pipe. It doesn't matter which end you create first, you just // pass the first end to the constructor of the other end.
try {
inStream = new PipedInputStream();
outStream = new PipedOutputStream(inStream); } catch (Exception e) {
e.printStackTrace(); }
}
public void run() {
Applet app = null;
AppletContext context = getAppletContext();
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/ch10.htm
// Start looking for the reader applet while (app == null) {
// Try to locate an applet named "reader" try {
app = context.getApplet("reader");
// If we get here and app isn't null, we've found it, break out // of this while loop
if (app != null) break; } catch (Exception e) {
}
// We couldn't find the applet. If we've tried 30 times (at once per second) // we assume it isn't coming up.
tries++;
if (tries > 30) {
return; // time out after 30 seconds }
// Sleep for a second before looking again try {
Thread.sleep(1000);
} catch (Exception insomnia) { }
}
// Now that we found the applet, cast it to a ReaderApplet so // we can invoke setInputStream
ReaderApplet reader = (ReaderApplet) app; // Give the ReaderApplet the input end of the stream reader.setInputStream(inStream);
while (true) {
// Write byte values of 0-9 to the stream pipe over and over for (int i=0; i < 10; i++) {
try {
outStream.write(i); Thread.sleep(1000); } catch (Exception ignore) { }
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/ch10.htm
} }
}
public void start() {
appletThread = new Thread(this); appletThread.start();
}
public void stop() {
appletThread.stop(); appletThread = null; }
}
Listing 10.3 shows the reader portion of the pipe demonstration. The sender applet had to perform a loop to wait for the reader to become active. The reader has a similar problem-it has to wait for the sender to give it the input end of the pipe. It looks at the input stream once every second, and once the input stream is no longer null, it starts reading data.
Tip
Rather than continually polling to see when the input stream is no longer null, the reader could use the wait/notify mechanism. Basically, if the input stream is null, the run method calls wait,which puts its thread to sleep. Then, the setInputStream method could call notify to wake the run method back up so it can start reading again.
Listing 10.3 Source Code for ReaderApplet.java
import java.applet.*; import java.awt.*; import java.io.*;
// This applet is the companion to the SenderApplet. It receives // an input stream from the sender and begins reading one byte at
// a time, changing a label on the screen to the string representation // of each byte read so you can see it in action.
public class ReaderApplet extends Applet implements Runnable {
protected InputStream inStream; protected Thread appletThread;
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/ch10.htm
protected Label label; public void init() {
label = new Label("X"); add(label);
}
// This method will be called by the SenderApplet when it locates this // applet.
public void setInputStream(InputStream inStream) {
this.inStream = inStream; }
public void run() {
// Wait for the input stream
while(inStream == null) {
try {
Thread.sleep(1000);
} catch (Exception insomnia) { }
}
// Start reading bytes while (true) { try {
int ch = inStream.read();
// If ch < 0, we hit EOF, indicating some type of shutdown if (ch < 0) return;
// Update the label with the byte we just read label.setText(""+ch); } catch (Exception e) { return; } } }
public void start() {
appletThread = new Thread(this); appletThread.start();
}
file:///E|/Java%20Professor/Hacking%20Java%20Professional%20Resource%20Kit/ch10.htm
public void stop() {
appletThread.stop(); appletThread = null; }
}