//******************************************************************************
// AwtPduViewer.java: Applet
//
//******************************************************************************
package mil.navy.nps.awt;
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import java.util.*;
import mil.navy.nps.dis.BehaviorStreamBufferUDP;
import mil.navy.nps.dis.*; // DIS Library
/**
AwtPduViewer is an applet that reads Pdus and displays their values on the
screen. It is configured with a socket, which allows the applet to read
data from the wire; it uses the package mil.navy.nps.dis, which implements
the DIS protocol.
This file was generated by Microsquish J++, which is something of an
experiment. We'll see how it works out. It's also my first applet that
isn't completely trivial, so be a little gentle.
This is compliant with the JDK 1.02 spec; it makes use of deprecated aspects
of that API rather than use JDK 1.1. This is primarily to get it working with
Netscape 3.01. 1.1 browser implementations should be compatible, at least for
the next release.
Netscape bitches & moans about doing a thread.suspend(), complaining about
the possibility of deadlock. Not sure what this is all about, but it seems
to work. (Note: JavaSoft has deprecated thread.suspend() and friends in 1.1
because of inherent problems w/ deadlock. This needs to be reworked.
This takes two parameters from the HTML file, "PduSocket" and"MulticastGroup".
The first is the socket the applet listens on. The second is a multicast group,
a feature that is not implemented right now since Netscape doesn't do multicast.
Testing: sent ESPdus to host (madison) from both madison and pinafore using
mil.navy.nps.dis.Benchmark.
HISTORY
10Apr97 DMcG New
@author Don McGregor ( http://www.npsnet.org/~mcgredo)
@version 1.0
@see UpdateThread
@see TextAreaStream
*/
public class AwtPduViewer extends Applet implements Runnable, java.awt.event.ItemListener, java.awt.event.ActionListener
{
// Members for applet parameters
// =
private static String m_PduSocket = "3111";
private static String m_MulticastGroup = null; // no default value; unicast by default
private static final String DEFAULT_MCAST_GROUP = "224.2.181.145";
private static final String DEFAULT_PORT = "62040";
// Parameter names. To change a name of a parameter, you need only make
// a single change. Simply modify the value of the parameter string below.
private static final String PARAM_PduSocket = "PduSocket";
private static final String PARAM_MulticastGroup = "MulticastGroup";
private static BehaviorStreamBufferUDP behaviorStreamBufferUDP = null; // Reads packets & stores them up
private static Vector pduPool = null; // data structure that keeps list of arrived Pdus
private static UpdateThread updateThread = null; // thread that updates screen display
private static TextArea textArea = null; // scrolling text area where data is displayed
private static java.awt.List list = null; // List of Pdus to choose from
private static Button startButton = null; // start button
private static Button stopButton = null; // stop button
private static Button flushButton = null; // flush button
private static PrintStream textAreaPrintStream = null; // print stream, sent to text area above
private static SocketReadUI socketInfo = null; // UI widget with several fields relating to reading
// from a socket in it
public AwtPduViewer()
{
pduPool = new Vector();
updateThread = new UpdateThread(this);
}
public String getAppletInfo()
{
return "Name: AwtPduViewer\r\n" +
"Author: Don McGregor\r\n" +
"GNU Copyleft 1997";
}
// The getParameterInfo() method returns an array of strings describing
// the parameters understood by this applet.
public String[][] getParameterInfo()
{
String[][] info =
{
{ PARAM_PduSocket, "String", "Socket we listen to for Pdus" },
{ PARAM_MulticastGroup, "String", "Multicast Group (Java 1.1 only)" },
};
return info;
}
/**
Applet initialization code
*/
public void init()
{
System.out.println ("AwtPduViewer init() starting...");
String param; // a parameter passed into the applet
TextAreaStream textAreaStream = null;
Thread aThread = null;
// Get parameters, if any, from the HTML file. If not parameters passed in,
// use the defaults.
// Dead code; this uses the UI to input parameters now, so there's no
// need to pass them in from the html file.
/*
This is no longer used.....is set by UI in applet instead of via HTMl file
param = getParameter(PARAM_MulticastGroup);
if (param != null)
m_MulticastGroup = param;
else
m_MulticastGroup = DEFAULT_MCAST_GROUP;
// Parameter retrieval: socket to listen on.
// Dead, done from UI now.
param = getParameter(PARAM_PduSocket);
if (param != null)
m_PduSocket = DEFAULT_PORT;
*/
socketInfo = new SocketReadUI(); // buch UI code
add(socketInfo);
socketInfo.setAddress(DEFAULT_MCAST_GROUP);
socketInfo.setPort(Integer.parseInt(DEFAULT_PORT));
// List box, contains scrolling display of arrived Pdus
list = new java.awt.List(10, false);
list.addItemListener(this);
Dimension dim = new Dimension(20,40);
list.setSize(dim);
add(list);
//System.out.println("AwtPduViewer: list size is " + list.size().width + " " + list.size().height);
// scrolling text area to display output (lines, width)
textArea = new TextArea(25,40);
add(textArea);
// Start and stop buttons to turn on or off socket. Initially, the
// socket and thread are configured to be in the reading state, so
// the start button is off, the stop button is on, and the flush
// button is always on.
startButton = new Button("Start");
startButton.setEnabled(true);
add(startButton);
startButton.addActionListener(this);
stopButton = new Button("Stop");
add(stopButton);
stopButton.addActionListener(this);
stopButton.setEnabled(false);
flushButton = new Button("Flush Pdus");
add(flushButton);
flushButton.addActionListener(this);
flushButton.setEnabled(true);
// Wrap an output stream around the TextArea, so that we can
// send stuff streaming to the display with a printf().
textAreaStream = new TextAreaStream(textArea);
textAreaPrintStream = new PrintStream(textAreaStream);
// Start up the thread that updates the display
updateThread.start();
System.out.println ("AwtPduViewer init() starting...");
return;
}
/**
Handles button presses
*/
public void actionPerformed(ActionEvent e)
{
Object source = e.getSource();
Thread aThread;
if (source instanceof Button)
{
Button b = (Button) source;
// Start button; start up reading threads, turn off button, toggle on "stop" button.
if(b.getLabel() == "Start")
{
startButton.setEnabled(false);
stopButton.setEnabled(true);
socketInfo.setIsEnabled(false);
if(behaviorStreamBufferUDP != null)
behaviorStreamBufferUDP.cleanup(); // Close down sockets....
if(socketInfo.getMulticastSocket() == false) // Unicast socket
{
System.out.println("AwtPduViewer: instantiating unicast BehaviorStreamBufferUDP, " +
"port " + socketInfo.getPort());
behaviorStreamBufferUDP = new BehaviorStreamBufferUDP(socketInfo.getPort());
}
else // multicast socket
{
System.out.println("AwtPduViewer: instantiating multicast BehaviorStreamBufferUDP, " +
socketInfo.getAddress() + "/" + socketInfo.getPort());
behaviorStreamBufferUDP = new BehaviorStreamBufferUDP(socketInfo.getAddress(),
socketInfo.getPort());
}
aThread = new Thread(behaviorStreamBufferUDP);
aThread.start();
updateThread = new UpdateThread(this);
updateThread.start();
this.repaint();
}
// Stop button; suspend threads, turn off button, toggle on "start" button.
if(b.getLabel() == "Stop")
{
startButton.setEnabled(true);
stopButton.setEnabled(false);
socketInfo.setIsEnabled(true);
if(behaviorStreamBufferUDP != null)
behaviorStreamBufferUDP.cleanup();
behaviorStreamBufferUDP = null;
this.repaint();
}
// Flush Pdu button hit--remove all the Pdus from the list, clear out
// GUI display.
if(b.getLabel() == "Flush Pdus")
{
int textLength = -1;
// Lock access to pduPool, since this is also used in another thread,
// and we don't want two people writing/modifiying it.
synchronized(pduPool)
{
pduPool = new Vector(10); // everyting should be GC'd.
}
// Ditto for the GUI list; don't want to be adding to it in the updateDisplay
// method at the same time we're flushing it.
synchronized(list)
{
list.removeAll();
}
// wipe out all the data in the TextArea
textArea.selectAll();
textLength = textArea.getSelectionEnd();
// Deprecated; change for 1.1
textArea.replaceRange(new String(""), 0, textLength);
}
}
return;
}
// Place additional applet clean up code here. destroy() is called when
// when you applet is terminating and being unloaded.
//-------------------------------------------------------------------------
public void destroy()
{
// TODO: Place applet cleanup code here
}
// ANIMATION SUPPORT:
// Draws the next image, if all images are currently loaded
//--------------------------------------------------------------------------
private void displayImage(Graphics g)
{
}
// AwtPduViewer Paint Handler
//--------------------------------------------------------------------------
public void paint(Graphics g)
{
}
// The start() method is called when the page containing the applet
// first appears on the screen. The AppletWizard's initial implementation
// of this method starts execution of the applet's thread.
//--------------------------------------------------------------------------
public void start()
{
}
// The stop() method is called when the page containing the applet is
// no longer on the screen. The AppletWizard's initial implementation of
// this method stops execution of the applet's thread.
//--------------------------------------------------------------------------
public void stop()
{
}
// THREAD SUPPORT
// The run() method is called when the applet's thread is started. If
// your applet performs any ongoing activities without waiting for user
// input, the code for implementing that behavior typically goes here. For
// example, for an applet that performs animation, the run() method controls
// the display of images.
//--------------------------------------------------------------------------
public void run()
{
// Threads are started from the init() method in this case, since
// the behaviorStreamBufferUDP needs parameters passed in to work, updateThread
// needs behaviorStreamBufferUDP, and init() is called after run().
repaint();
}
/**
Updates the display by querying the BehaviorStreamBufferUDP, returning any Pdus that
have arrived since the last time we asked, and updating the display. This
is kicked off by its own thread, so it runs asyncronously from the app.
the display is updated every X seconds.
We need to lock access to pduPool, since this is global data used elsewhere
in the applet in another thread. Not sure about the requirement to lock list,
the GUI element that displays the scrolling list. This is the only place we
do a _write_ to it, so I think it's OK.
*/
public void updateDisplay()
{
Vector receivedPdus = null; // list of Pdus we get back from network monitor;
// those that have arrived since the last time we asked
Enumeration pduEnumeration; // Loop through list
String PduNameAndTime = null; // string that has name of Pdu & timestamp
String time = null; // string representation of 32-bit timestamp on Pdu
while(stopButton.isEnabled()) // update until we stop stop getting pdus.
{
if(behaviorStreamBufferUDP != null)
{
receivedPdus = behaviorStreamBufferUDP.receivedPdus();
//System.out.println("AwtPduViewer: got " + receivedPdus.size() + " Pdus this cycle");
// Add the new Pdus to the existing pool of Pdus and to the end of the
// GUI list, and place the name of the Pdu type in the display list. This
// could probably be faster, but it's OK for now.
pduEnumeration = receivedPdus.elements();
while(pduEnumeration.hasMoreElements())
{
ProtocolDataUnit aPdu = (ProtocolDataUnit)pduEnumeration.nextElement();
// lock access to pduPool, since this may be used elsewhere in the program
// at the same time.
synchronized(pduPool)
{
pduPool.addElement(aPdu);
}
// add the name of the Pdu (eg, "Entity State", "Fire", etc) and the
// 32-bit timestamp to the scrolling list
PduNameAndTime = aPdu.pduName();
time = String.valueOf(aPdu.getTimestamp().longValue()/1000.0);
PduNameAndTime = PduNameAndTime.concat(new String(" "));
PduNameAndTime = PduNameAndTime.concat(time);
list.add(PduNameAndTime);
}
this.repaint();
try
{
updateThread.sleep(250); // sleep for 0.25 seconds
}
catch (InterruptedException intException)
{
throw new
RuntimeException("Exception in AwtPduViewer; fitful sleep");
}
} // if networkmonitor != null
} // while getting pdus
}
/**
itemStateChanged is the interface for ItemListener. When this object is
added as a listener to an object, such as a awt.List, this gets the
event when something is selected. We act on that by dumping out the
contents of the selected item.
*/
public void itemStateChanged(ItemEvent ie)
{
int itemIndex = list.getSelectedIndex();
ProtocolDataUnit aPdu;
Object source = ie.getSource();
// Scrolling list hit; print out selected PDU to text area
if (ie.getStateChange() == ItemEvent.SELECTED)
{
int textLength = -1;
String parameters;
textArea.setText(new String(""));
// Print the new data. Double protections on out-of-bounds indexes,
// which can occur if the incoming PDUs are stopped, then flushed,
// then some clicks on the list.
itemIndex = list.getSelectedIndex();
if(itemIndex >=0) // Have something selected in list & list exists
{
aPdu = (ProtocolDataUnit)pduPool.elementAt(itemIndex);
if(aPdu != null) // Have a PDU at that site
aPdu.printValues(5,textAreaPrintStream);
}
} // if
} // itemStateChanged
} // end of class AwtPduViewer