A shastra collaborative java applet is composed of the following primary objects:
We see from the picture that network events for collaboration are received from and sent to the Session manager. These network events when received by the application are processed by Services within the CommFront object. These services generate Service Events which are directed to application listeners which are application specific code and also to Service listeners which are other services within the CommFront object, allowing for inter-Service communication and the creation of sophisticated coordinated service activity.

The following sections work through the source code of the actual collaborative
chat Applet and explain its operation.
First the necessary packages are imported into the applet:
import netscape.security.*; // Needed to extend the privileges of the applet. import java.applet.*; import java.io.PrintStream; import java.awt.*; import shastra.gui.*; // prebuilt shastra graphic user interface tools import shastra.data.*; // a collection of network ready data objects import shastra.service.*; // predefined basic services, distributed not collaborative import shastra.collab.*; // all basic collaboration support objects, services, fronts import shastra.mediaservice.ChatService; // a specialized service for text based chat.Now we define the actual applet and its methods. The ChatApp is a subclass of CommAplet which provides automatic privilege extension from Netscape.
public class ChatApp extends CommApplet
{
ChatService mychat; // declare our network service object.
chatPanel chatwindow; // the specific user interface for this application.
public void start()
{
System.err.println("ChatApp::start");
chatwindow = new chatPanel(mystream); // create the user interface
Create the service and set its application listener to the chat GUI.
This way the chat window receives all applications events generated by
the ChatService.
mychat = new ChatService(mystream, chatwindow);Pass the service object to the gui so it can direct the service to transmit network events based on user input.
chatwindow.setChat(mychat);Add the ChatService to the CommFront built into the CommApplet
addService(mychat);Add the Chat GUI to the CommApplet GUI
add(chatwindow); } }
What all has been accompished once the start method has been called?
Now we will go through the code of ChatService:
First specify that this object is part of the mediaservice objects. Mediaservice objects are responsible for various media types, text, audio, video, etc.
package shastra.mediaservice;Now include the other needed packages.
import java.util.Enumeration; import java.io.*; import shastra.network.*; // include network communication objects import shastra.data.*; // include network data objects import shastra.service.*; // include needed service superclasses import shastra.collab.*; // include needed collaborative objects including Session ServiceNow we define the ChatService class,properties, and methods:
public class ChatService extends SessionService // extend SessionService so can be a Group based Service
{
public svEventListener mylisten; // application event listener object
public DataNetworkId myid; // this applications unique network wide identifier.
private PrintStream mystream; // a printstream for sending debugging and error messages.
The following are basic constructor methods:
public ChatService(PrintStream debug)
{
super();
mystream = debug;
mylisten = null;
myid = null;
}
public ChatService(PrintStream debug, svEventListener alisten)
{
super();
mystream = debug;
mylisten = alisten;
myid = null;
}
public void setListener(svEventListener ave) // method to set the application listener object.
{
mylisten = ave;
}
The following methods are collection of predeclared methods that every service must implement
to properly interface with other services and applications over the network.
public String GetName()
{
return("CHATSERVICE");
}
public String ListOperations()
{
return "RECVMSG";
}
This next method is very important it is the method called by the
Front object whenever a network event for this particular service has
been received from the network. Its job is to process network events
and translate them into service and application events. In this
parcticular case it only responds to a single event, RECVMESSAGE,
which means that a text message has been received from a remote
application. The response to this is to call the recvMsg method which
will process the message.
Three arguments are passed to the CallOperation. The first argument
is the Port object that the network event was received from. The
second argument is the name of the Service operation the network event
is to be delivered to. The third argument is the complete network
event message. The port object can be used to retrieve more data from
the site generating the network event, or sending a network event back
to that application. The operation name is used by the service to
determine which operation to perform. The network event itself may
contain operation specific data that can be retrieved from a data
array stored within the message object.
public void CallOperation(PortImpl p, String OpName, Message m )
throws OperationNotFoundException
{
String mop = m.getOperationName();
Data anid[] = (Data [])m.getData();
if (mop.compareTo("RECVMESSAGE") == 0)
{
recvMsg((DataString)anid[0]);
}
else throw new OperationNotFoundException("No Such NameService Operation");
}
The recvMsg method receives a text message and generates an
application event to be sent to the application listener. In this
particular case the listener is the chatwindow object and will display
the received message in the common text window of the GUI.
public void recvMsg(DataString ast)
{
svEvent e; // application event
e = new svEvent(ast);
e.myservice = "CHATSERVICE";
e.myevent = "RECVMESSAGE";
if (mylisten != null)
{
mylisten.svAction(e,ast);
}
}
This method is used to have the Chat service send a text message to
the current session that the Front is involved in. It uses the port
retrieved from the current session to send the message. The
mysession instance variable is a member of the SessionService
superclass. It is maintained and managed automaticaly using methods
defined in the SessionService and the use of Service events between
service's in the Front object. If there is no current session active
then it simply calls recvMessage to generate a local application
event. This allows for text to be displayed in the common area even
when the service is not involved in a session.
public void sendMsg(DataString ast)
{
DataString aservice = new DataString();
DataString aop = new DataString();
try {
PortImpl mdp;
DataString temp[] = new DataString[3];
aservice.setValue("CHATSERVICE");
aop.setValue("RECVMESSAGE");
temp[0] = aservice;
temp[1] = aop;
temp[2] = ast;
Message amess = new Message("SESSIONSERVICE","BROADCAST", temp);
if (mysession != null)
{
mdp = mysession.getTarget();
mdp.writeObject(amess);
mystream.println("Sent Chat Message");
}
else
{
recvMsg(ast);
}
}
catch (IOException e)
{
mystream.println("Chat Service IOException\n");
}
}
}
class chatPanel extends Panel implements svEventListener
{
public statusPanel myspanel; // the common output area
public TextField myfield; // the input field
public PrintStream mystream; // debug output stream
public PrintStream tstream; // output stream to the common area
public GridBagLayout gbl; // layout manager
ChatService mychat; // local copy of the ChatService
This is the constructore for the chaPanel GUI. It creates the input and
output text fields.
public chatPanel(PrintStream debug)
{
super();
GridBagConstraints gbc;
gbl = new GridBagLayout();
setLayout(gbl);
mystream = debug;
The next two lines create the common output area and retrieve a stream
for writing information to that output area.
myspanel = new statusPanel(); tstream = myspanel.getPrintStream();The next line creates the input field.
myfield = new TextField();The remaining lines set up layout constraints and add the the widgets into the main panel.
gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.BOTH; gbl.setConstraints(myspanel,gbc); add(myspanel); gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 1; gbc.weightx = 1.0; gbc.fill = GridBagConstraints.BOTH; gbl.setConstraints(myfield,gbc); add(myfield); }The action method is called whenever the user hits return in the input text field. It retrieves the text message, clears the input field and then calls the ChatService method to send the message to the current session.
public boolean action(Event e, Object o)
{
DataString mast;
if (e.target instanceof TextField)
{
PrivilegeManager.enablePrivilege("UniversalFileAccess");
PrivilegeManager.enablePrivilege("UniversalConnect");
PrivilegeManager.enablePrivilege("UniversalMulticast");
PrivilegeManager.enablePrivilege("Debugger");
mystream.println(myfield.getText());
mast = new DataString(myfield.getText());
myfield.setText("");
mychat.sendMsg(mast);
}
return true;
}
The svAction method catches application events generated by the
ChatService object. It displays the text component of these
messages in the common text output area by printing them to the
output stream retrieved from the text widget, created when this object was
created.
public boolean svAction(svEvent e, Object o)
{
tstream.println((DataString)o);
return true;
}
public void setChat(ChatService achat)
{
mychat = achat;
}
}