Question:
I have two applets running on the same page, one in each of two frames. I want them to communicate, but when I do a getAppletContext.getApplet()
call, the second applet can’t find the first. I’ve gone through the enumeration returned by getApplets()
, and only the applet that makes the call is found.
Is there a special syntax I have to use to find an applet running in another frame?
Answer:
First a little background for newcomers:
For security reasons, there are many restrictions on the ability of an applet to communicate with other processes. However, an applet can communicate with other applets running on the same Web page. How is this done?
One way is to give names to each applet on a Web page using aNAME specifier in the applet tag. Here’s a sample HTML filecontaining two applets named “senderapplet” and “receiverapplet.”Note that the names MUST be in lowercase letters:
Information about the Web page containing an applet is represented in an**********************************Test This applet sends outputs to the applet below.
This applet receives inputs from the applet above.
**********************************
AppletContext
object, which an applet can obtain using its getAppletContext
method:AppletContext context = getAppletContext();
Among other things, this context contains references to all other appletson the Web page. These references can be accessed from the applet’sname (given by the NAME specifier above) using the getApplet
method. Forexample, if an instance of Sender.class
wants a reference to the instance of the Receiver.class
residing on the same Web page, it can call:Applet recApp = context.getApplet(“receiverapplet”);
Communication with the Receiver applet is possible if the Receiver appletprovides a special public method that can process messages. Assume the Receiver object has a method called ProcessInput
, which expectsa String input. Then the Sender object can invoke this method throughthe reference obtained above (after the appropriate cast):((Receiver)recApp).processInput(“your message here”);
Now the problem:A frame is an HTML element that contains a Web page. Thus, using frames it is possible to nest Web pages. Although not yet a standard HTML feature, framesare supported by Netscape. Assume the Sender and Receiver applets above residein separate HTML files called “send.html” and “rec.html,” respectively. Using theframe feature, they can appear in separate frames on the same Web page:
Unfortunately, the**********************************Parent Frame **********************************
AppletContext
of the Sender applet represents send.html,the Web page within the Sender frame. Since the Receiver applet resides inrec.html, it will not be among the applets represented inside the Senderapplet’s AppletContext
. Thus, the technique outlined above fails.And now the solution:
I wish I could take all the credit for this idea, but alas, I stand onthe shoulders of giants. My inspiration was a “Tip of the Week” submitted to JavaWorld by Greg Williams.
My strategy is this: Since Sender’s AppletContext
doesn’t hold areference to the Receiver applet, why not create our own class and call it a MetaContext
, containing references to all registered applets? Receiver and Sender applets can register themselves with theMetaContext
during initialization. The MetaContext
can provide itsown getApplet
method to allow applets to access registered applets.
But how will applets running on different pages obtain references to a common MetaContext
? This should be possible if everything in the MetaContext
is static.
Here’s my definition of MetaContext
. Registered applets are held in a hash table, where they are indexed by their names:
As an example, my Sender and Receiver applets each contain two**********************************import java.applet.*;import java.util.*;public class MetaContext { // registered applets live here private static Hashtable applets = new Hashtable(10); // to access registered applets public static Applet getApplet(String s) { return (Applet)applets.get(s); } // to register applets public static void regApplet(String s, Applet a) { applets.put(s, a); } // etc.}**********************************
TextFields
, one showing the applet’s input, the other showingits output. The user enters a number x
into the Sender’s inputfield, x
is sent to the Receiver, x
appears in the Receiver’s input field, the Receiver computes y = x * x
, places y
in its outputfield, then sends y
back to the Sender. The Sender computes z = y + 1
,then displays z
in its output field. The example is silly, but itdoes show a non-trivial, two-way communication between Sender and Receiver.To receive inputs, both Sender and Receiver provide a method:
public void processInput(String s) { … }
To access the Receiver’s processInput()
method, the Sender firstobtains a reference to the Receiver applet through the MetaContext
:Applet recApp = MetaContext.getApplet(“receiverapplet”);
Then invokes the Receiver’s processInput
method:((Receiver)recApp).processInput(sendField.getText());
Here’s the complete code for Sender and Receiver:To complete the picture, here are send.html and rec.html:**********************************// Sender.javaimport java.awt.*;import java.applet.*;public class Sender extends Applet { private TextField sendField; // input field private TextField receiveField; // output field public void init() { setLayout(new FlowLayout()); sendField = new TextField(“SEND”, 7); add(sendField); receiveField = new TextField(“RECEIVE”, 7); add(receiveField); // register with MetaContext MetaContext.regApplet(“senderapplet”, this); } public boolean action (Event e, Object arg) { if (e.target instanceof TextField && e.target == sendField) { AppletContext context = getAppletContext(); context.showStatus(“***** ” + sendField.getText() + ” sent!”); // get reference to receiver applet: // Applet recApp = context.getApplet(“receiverapplet”); Applet recApp = MetaContext.getApplet(“receiverapplet”); // send message to receiver applet: if (!recApp.isActive()) receiveField.setText(“Error!”); else { receiveField.setText(” “); ((Receiver)recApp).processInput(sendField.getText()); } } else return false; // event not handled return true; // event handled } // s = number sent by receiver applet public void processInput(String s) { double y = (Double.valueOf(s)).doubleValue(); double z = doSomething(y); receiveField.setText(String.valueOf(z)); repaint(); } private double doSomething(double z) { return z + 1; }} // Sender**********************************// Receiver.javaimport java.awt.*;import java.applet.*;public class Receiver extends Applet { private TextField sendField; // input field private TextField receiveField; // output field public void init() { setLayout(new FlowLayout()); sendField = new TextField(“SEND”, 7); add(sendField); receiveField = new TextField(“RECEIVE”, 7); add(receiveField); // register with MetaContext MetaContext.regApplet(“receiverapplet”, this); } // s = number sent by sender public void processInput(String s) { receiveField.setText(s); repaint(); AppletContext context = getAppletContext(); context.showStatus(“***** ” + s + ” received!”); // get reference to sender applet // Applet senderApp = context.getApplet(“senderapplet”); Applet senderApp = MetaContext.getApplet(“senderapplet”); double x = (Double.valueOf(s)).doubleValue(); double y = doSomething(x); String t = String.valueOf(y); sendField.setText(t); repaint(); // send message back to sender applet ((Sender)senderApp).processInput(sendField.getText()); } private double doSomething(double z) { return z * z; }} // Receiver**********************************
**********************************Sender The applet in this frame sends outputs to the applet in the other frame.
**********************************Receiver The applet in this frame receives inputs from the applet in the Sender frame.
**********************************