Contents | Index | Previous | Next
Chapter 5: Communicating applets with Tango through JavaScript
Applets can be directly connected to Tango using Java API. However, if
multiple applets want to participate in the same session they all have to use a single
Tango proxy: instance of TAgent class in Java or Tango_agent in JavaScript. Because Tango_agent is in fact an instance of TAgent it can also be used inside Java applications as is TAgent in Java API for Tango. To make it happen the reference on Tango_agent must be passed to the applet. Moreover, message streams of different
applications must be channeled so they can be delivered to their appropriate counterparts.
We create a simple chat - Java applet - that uses Tango capabilities via
JavaScript. For those knowing Java API: this applet looks as written for Tango Java
API, except that TAgent is imported from JavaScript rather than created internally. Here is the code
in the file Chat.java:
Chat.java
import java.awt.*;
import java.applet.Applet;
import netscape.javascript.JSObject;
import webwisdom.tango.*;
public class Chat extends Applet implements TDataListener
{
TextField text;
private TAgent agent=null;
private int channelId=0;
public void init()
{
super.init();
setLayout(new BorderLayout());
text=new TextField("Uninitialized");
add("North",text);
JSObject jsWin=JSObject.getWindow(this);
Object[] args=new Object[1];
args[0]=this;
jsWin.call("appletReadyJ",args);
}
public void initTangoJS(TAgent a,Number ch)
{
agent=a;
channelId=((Number)ch).intValue();
if(agent!=null)
agent.addTDataListener(channelId,this);
}
public boolean handleEvent(Event evt)
{
if(evt.id==Event.ACTION_EVENT)
if(evt.target==text)
if(agent!=null)
agent.send(channelId,stringToBytes(text.getText()));
return super.handleEvent(evt);
}
public void receive(byte[] b)
{
text.setText(bytesToString(b));
}
private String bytesToString(byte t[])
{
return new String(t,0);
}
private byte[] stringToBytes(String s)
{
int l=s.length();
byte[] t=new byte[l];
s.getBytes(0,l,t,0);
return t;
}
}
Important in this Applet is that it uses send() and addTDataListener() functions with the channel number as the first of their arguments. Channel
number, together with TAgent, is received from JavaScript application in initTangoJS() call. This is JavaScript applications who decides which application should
use which channel so the data of possibly multiple applications using the same TAgent does not interfere. Neither initTangoJS() function, nor mechanism of passing information from JavaScript application to
Java applet is a part of Tango API - this is an interface between a JavaScript
application and its applet sub-components. Other details of Java programming
for Tango are covered by Tango API in Java manual.
Let's now take a look how this chat application makes part of the JavaScript
application:
ex51.html
<html>
<body onUnload="Tango_exit()">
<script language="javascript">
function Tango_register(win)
{
Tango_agent=Packages.webwisdom.tango.TAgentJS.createTAgentJS(win);
if(Tango_agent!=null)
Tango_agent.setDbgModeJS(true);
}
function Tango_exit()
{
if(Tango_agent!=null)
Tango_agent.exitJS();
}
Tango_register(window);
function appletReadyJ(a)
{
a.initTangoJS(Tango_agent,57);
}
</script>
<applet name="app" code="Chat.class" width=200 height=33 mayscript>
</applet>
</body>
</html>
Applet Chat is placed on the page and identified by the name "app". Function appletReadyJ() is exposed by the script and called by chat when the applet finishes its
initialization (see Chat.init() function). Call to this method signifies that the applet is ready to be used
and its interface functions can now be called. In particular, initTangoJS() method of the applet is invoked to pass Tango specific arguments. For the
applet it is equivalent of creating its own TAgent, so the applet can start effectively using the Tango communication framework.
Number '57' has no special meaning - it just identifies a channel.
Next example will show how multiple applets, in addition to script's own
messages are all connected to Tango_agent. Effectively, JavaScript here plays a role of an integration platform for
applets:
ex52.html
<html>
<body onUnload="Tango_exit()">
<script language="javascript">
- ar numAppReady=0;
- ar masterReady=false;
ar Tango_agent=null;
function Tango_register(win)
{
Tango_agent=Packages.webwisdom.tango.TAgentJS.createTAgentJS(win);
if(Tango_agent!=null)
{
Tango_agent.setDbgModeJS(true);
Tango_agent.addTDataListenerJS(window);
}
Tango_send('q');
}
function Tango_exit()
{
if(Tango_agent!=null)
Tango_agent.exitJS();
}
function Tango_send(data)
{
if(Tango_agent!=null)
Tango_agent.sendJS(data);
}
function Tango_receive(data)
{
- ar tag=data.substring(0,1);
if(tag=='t')
{
document.forms.chat.tty.value=data.substring(1,data.length);
}
else if(tag=='r')
{
masterReady=true;
if(numAppReady==2)
initApplets();
}
else if(tag=='q')
{
if((Tango_agent.isMaster())&&(masterReady==true))
Tango_send('r');
}
}
Tango_register(window);
function appletReadyJ(a)
{
numAppReady++;
if(numAppReady==2)
{
if(Tango_agent.isMaster())
{
initApplets();
masterReady=true;
Tango_send('r');
}
else
{
if(masterReady)
initApplets();
}
}
}
function initApplets()
{
document.applets.a1.initTangoJS(Tango_agent,57);
document.applets.a2.initTangoJS(Tango_agent,58);
}
</script>
<form name="chat">
<input type="text" name="tty" size=16 onclick="Tango_send('t'+tty.value)">
<input type="button" value="send">
</form>
<applet name="a1" code="Chat.class" width=200 height=33 mayscript>
</applet>
<applet name="a2" code="Chat.class" width=200 height=33 mayscript>
</applet>
</body>
</html>
This application is made of three independent sub-applications:
JavaScript chat represented by the form "chat",
Java applet Chat named "a1", and
Java applet Chat named "a2".
Each of these applications uses the same Tango_agent created by the JavaScript application. JavaScript chat was described in the
Chapter 2; Java chats were introduced earlier in this chapter. Messages of these
three applications are sent by different channels: JavaScript chat goes by
implicit and unnamed default channel; Java chats use channels 57 and 58. The
choice of channels is arbitrary and has no other meaning than to distinguish several
applications.
Special care is taken to assure proper initialization. Because applets may be
not activated instantly when the JavaScript application registers with Tango,
their creation should be synchronized. These precautions can be omitted if
applets are stateless. Our example, however, implements special protocol to ensure
connection of slave applets to Tango after the applets on the master side are
connected. The protocol consists of three message types:
messages starting with 't' - to pass chat text;
messages starting with 'r' - to notify about master readiness;
messages starting with 'q' - to ask if master applications are ready.
Application's initialization state is remembered by two variables:
numAppReady is incremented each time a sub-application calls appletReadyJS(), and
masterReady turns to true when 'r' message from master is received.
Slave can be connected to Tango when numAppReady equals 2 - the number of applets - and masterReady flag is true.
The protocol 'r' notification could be implemented per applet rather than once
per all applets.