Shastra Introductory Tutorial for Java

This document explains how to create a simple shastra collaborative aware application.

A shastra collaborative java applet is composed of the following primary objects:

Collaborative Chat

Below is a picture of the basic architectore of a collaborative chat application.

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.
 

ChatApp

The following is a step by step walk through of the collaborative chat application.

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?
  1. The Chat Graphical user interface has been created and displayed.
  2. The Chat Service object has been created and installed in the front.  This makes it automaticaly notified whenever any network events are received for the ChatService.
  3. The chatwindow has been set as the application listener for the Chat service thus allowing the chat window to be notified by the ChatService whenever the service generates application events such as a text message being received.
  4. The chatwindow has been given the ChatService which allows it to call methods of the service to transmit network events such as sending a text message.
  5. Finally the chatwindow has been added to the general GUI.

ChatService

The ChatService object is a subclass of the SessionService object class.  As such it can engage in session (group) based collaborative activities with other Shastra collaborative applications.  The ChatService is responsible for receiving and processing all text chat network events, service events,  and application events.  It also provides to the application all needed methods for sending text messages, and any control information.

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 Service
Now 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");
    }


  }  
}

Chat Graphical User Interface

The following object is the user interface for the Chat application. It has a single text field where the user types in his input and a large common text area. The text field is where the user inputs there messages. The common text area is where all messages are displaye from the local and remote participants.
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;
   }
}