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">

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)

{

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:

jsapi00090000.gif JavaScript chat represented by the form "chat",

jsapi00090000.gif Java applet Chat named "a1", and

jsapi00090000.gif 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:

jsapi00090000.gif messages starting with 't' - to pass chat text;

jsapi00090000.gif messages starting with 'r' - to notify about master readiness;

jsapi00090000.gif messages starting with 'q' - to ask if master applications are ready.

Application's initialization state is remembered by two variables:

jsapi00090000.gif numAppReady is incremented each time a sub-application calls appletReadyJS(), and

jsapi00090000.gif 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.