mil.navy.nps.dis
Class EntityDispatcher

java.lang.Object
  extended bymil.navy.nps.dis.EntityDispatcher
All Implemented Interfaces:
NetworkCommBadge, PduPublisher, java.lang.Runnable

public class EntityDispatcher
extends java.lang.Object
implements PduPublisher, java.lang.Runnable, NetworkCommBadge

EntityDispatcher is an independent thread that connects all EsdpuTransforms to the BehaviorStreamBuffer. A single EntityDispatcher object handles all routing of PDUs to & from the EspduTransform scripts which connect to individual entities in the VRML scene. The EntityDispatcher is static, meaning that only one copy can exist. EntityDispatcher is instantiated and threaded by the first EspduTransform encountered. In turn, the EntityDispatcher similarly instantiates and threads the static BehaviorStreamBuffer, which independently reads all network PDUs and then hands them over in a list.

The EntityDispatcher contains

EntityDispatcher responsibilities include

The VRML scene interrogates each entity at periodicities approximately equal to the author-provided values readInterval (or writeInterval). Defaults are set in EspduTransformPROTO.wrl

                 *--------------------------------------------------*
                /                                                  /|
               *--------------------------------------------------* |
     Browser   |            VRML Scene                            | |
    [threaded] |                                                  | |
               |                                                  | |
               |                                                  | |
               |  geometry              geometry                  | |
               |     :                     :            Radio     | |
               |EspduTransform     EspduTransform   Communications| |
               |   PROTO                 PROTO          PROTOs    | |
               |     :                     :              :       | *
               |(Script node)  ...  (Script node)  (Script node)  |/ 
               *-----+----------+----------+----------------------*
                  Entity 1     ...      Entity n    Radios 1..n
                     |          |          |             |
                     |          |          |             +----------------------+
                     |          |   *------+--------*                           |
                     |         ...  |EspduTransform | dead reckoning            |
                     |    *-----+---------------*   |  updates here             |
 multiple copies,    |    |EspduTransform       |   | (PDU posture              |
  one per entity  *--+----------------------*   |   |  extrapolation)  *-------+--------*
                  |EspduTransform           |   |---*                  | Radio          |
                  |                         |   |                      | Communications |
                  |                         |---*                      | PduScriptNode  |
                  *--+----------------------*                          *-------+--------*
                     ^          |          ^                                    ^
                     |          |          |                                    | Signal,
                     |          v          |                                    | Receiver,
                  *--+----------+----------+--*                                 | Transmitter
     singleton    |                           |    (separate subscribe loop)    | PDUs
    [threaded]    |     EntityDispatcher      |---------------------------------+
  if thread fails |                           |
  to start, runs  |         EntityHashTable   |
  single read per |            - Entity 1     |
  each draw loop  |            - Entity 2     |
                  |            - [...]        |
   single copy    |            - Entity n     |     (reads)
                  *-------------+-------------*         ^
                                |                       |
                                |               Entity State, Radio, other PDUs
                                |                             |
                  *-------------+-------------*               V
                  |                           |           (writes)
      static      |                           |
    [threaded]    |   BehaviorStreamBuffer    | 
    single copy   |                           |
                  |                           |
                  *-------------+-------------* 
                                |
                  *-------------+-------------*
       static     |                           | 
    [threadable]  |    org.web3d.vrtp.net.    |    browser-specific
 but not threaded |   DatagramStreamBuffer    |        security
    single copy   |                           |      permissions
                  |                           |
                  *----------+-----+----------* 
                             |     |
                             | ... |  multicast address(es)/port(s)
                             |     |  (area of interest management)
                             |     |
              Network 0======+=====+=====0
The behaviorStreamBuffer, an instance of a BehaviorStreamBuffer, reads PDUs from the wire. The EntityDispatcher occasionally pulls PDUs from the behaviorStreamBuffer. For each PDU, the simulation manager looks at the type.

If it's an ESPDU, the EntityDispatcher code looks at the EntityID triplet (site, application, ID) that uniquely identifies each entity, uses that aggregated triplet as a hash key to the Hashtable to find the appropriate EspduTransform reference, and then passes the PDU data via that EspduTransform to the correct entity. If the PDU has an unrecognized EntityID, we may optionally instantiate a local entity to reflect it, and insert it into the scene. The EspduTransform object is responsible for communications with the VRML scene. ESPDU culling may be performed either here or at the entity level. Since arrivals of PDUs for a given entity may occur out of order, it seems more logical to put PDU interpretation at the EspduTransform level, where there is a bit more information about update frequency and the like. In some special cases, it might make more sense to cull special PDUs early in to cut down on PDU handling overhead. That's an implementation and optimization detail.

If it's a SimulationManagement PDU, it will be handled by a different block of code. SimulationManagement PDUs include Start Simulation PDU, Stop Simulation PDU, Create Entity PDU, EventReport PDU, Query PDU and Data PDU. Each of these will probably require some special handling, and perhaps some state changes in the EntityDispatcher object. Some of them will require that PDUs be sent in response.

Cardinality: there is one and only one instance of a EntityDispatcher per DIS application. The EntityDispatcher is instantiated and operated through class (static) methods.

More functionality might be integrated into this object as well. Deciding which functionality goes where is the objective of the vrtp streaming stack.

History:
29 Oct 97 Don McGregor New
19 Oct 98 Don Brutzman & Don McGregor integrate revised EspduTransform and Javadoc updates for jdk1.2b4, fix threading, remove references to SimulationManager and EntityState classes.
12 Nov 98 Don McGregor Added PduPublisher and PduSubscriber interfaces.
14 Feb 99 Don Brutzman Added Fire and Collision PDU dispatching to EspduTransform.
20 Feb 99 Don McGregor Added MulticastTunnelServer connectivity.
4 Apr 99 Don Brutzman Thread shutdown and various trace fixes.
10 Sep 99 Don McGregor & Don Brutzman Security strategy
28 Sep 99 Don Brutzman Added Comment and CreateEntity PDUs
3 September 2000 Don Brutzman Changed dis.PduTypeEnum to disEnumerations.PduTypeField
18 September 2000 Don Brutzman and Dave Laflam Added, tested RadioCommunicationFamily PDUs

Location:
~/mil/navy/nps/dis/EntityDispatcher.java
Web: http://www.web3d.org/WorkingGroups/vrtp/mil/navy/nps/dis/EntityDispatcher.java
Hierarchy Diagram:

Author:
Don McGregor (mcgredo@nps.navy.mil), Don Brutzman (brutzman@nps.navy.mil)
See Also:
EspduTransform, BehaviorStreamBuffer, DatagramStreamBuffer, SecurityStrategy

Nested Class Summary
protected  class EntityDispatcher.TunnelManager
           
 
Field Summary
protected static BehaviorStreamBuffer behaviorStreamBuffer
          Handles communication with the wire, collecting PDUs from the packets received by a DatagramStreamBuffer.
protected  java.lang.Thread behaviorStreamBufferThread
          Thread for BehaviorStreamBuffer
protected static boolean DEBUG
          Flag for debugging/diagnostic output enabled
protected static java.util.Hashtable pduSubscriberScriptNodesHashtable
          Contains references to all EspduTransforms, RadioCommunicationsFamily nodes and other Script nodes in the VRML world, using the entity-unique site-ID/applicationID/entityID triplet as the hash key.
protected  SecurityStrategy strategy
          platform-specific security strategy
protected static EntityDispatcher.TunnelManager tunnelManager
          Internal threadable class that handles tunnel communications with a MulticastRelayServer if no native multicast traffic heard on local LAN.
 
Method Summary
 void addListener(PduSubscriber pSubscriber, EntityID pEntityID)
          Adds a subscribing Scipt node to the pduSubscriberScriptNodesHashtable being maintained.
 void adviseSleepInterval(float anotherReadWriteInterval)
          Somewhat careful accessor method that decides how long to let the thread sleep, so that it doesn't steal excessive cycles from the VRML 3D graphics rendering process(es).
 void checkForTrafficAndFallBackToTunnel(java.lang.String pTunnelAddress, int pTunnelPort, int pLocalPort)
          Test for the existence of multicast (or unicast) and, if not found, open up a tunnel to the tunnel server, and replace the original BSB with this new one.
 void createMulticastBehaviorStreamBuffer(java.lang.String pMcastAddress, java.lang.Integer pPortNumber)
          Creates multicast BehaviorStreamBuffer.
 void createUdpUnicastBehaviorStreamBuffer(java.lang.Integer pPortNumber)
          Creates unicast UDP BehaviorStreamBuffer.
protected  void debug(java.lang.String pDiagnostic)
          Debugging output.
 void doRun()
          After the behaviorStreamBuffer thread is started, doRun loops endlessly to pull unordered lists of PDUs from the behaviorStreamBuffer, sending the PDUs one-by-one to the appropriate EspduTransform matching the entity.
 boolean getDEBUG()
          Get debugging flag
static EntityDispatcher getEntityDispatcher(java.lang.String pAddress, int pPort)
          getEntityDispatcher returns the single, shared instance of the EntityDispatcher object.
 float getSleepInterval()
          Accessor method.
 void removeListener(PduSubscriber listenerToRemove, EntityID pEntityID)
          addListener and removeListener are the two methods that implement the PduPublisher interface.
 void run()
          run() switches on platform-secific security, gets the thread running using doThread (), then calls doRun () which does the actual work of reading from the network.
 void sendPdu(ProtocolDataUnit pPdu)
          Example of delegation of writing a PDU to the single static behaviorStreamBuffer.
 void sendPdu(ProtocolDataUnit pdu, java.lang.String pDestinationHost, int pDestinationPort)
          Example of delegation of writing a PDU to the single static behaviorStreamBuffer.
 void setDEBUG(boolean pDEBUG)
          Set debugging flag
 void shutdown()
          shutdown() is called when VRML scene exits.
 void singleReadLoop()
          singleRunLoop() is called via doRun when threading, or via the invoking application if not threading (e.g.
 void startBehaviorStreamBufferThread()
          startBehaviorStreamBufferThread starts the behaviorStreamBuffer thread.
protected  void trace(java.lang.String pDiagnostic)
          Guaranteed trace output.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

behaviorStreamBuffer

protected static BehaviorStreamBuffer behaviorStreamBuffer
Handles communication with the wire, collecting PDUs from the packets received by a DatagramStreamBuffer.


behaviorStreamBufferThread

protected java.lang.Thread behaviorStreamBufferThread
Thread for BehaviorStreamBuffer


tunnelManager

protected static EntityDispatcher.TunnelManager tunnelManager
Internal threadable class that handles tunnel communications with a MulticastRelayServer if no native multicast traffic heard on local LAN.


pduSubscriberScriptNodesHashtable

protected static java.util.Hashtable pduSubscriberScriptNodesHashtable
Contains references to all EspduTransforms, RadioCommunicationsFamily nodes and other Script nodes in the VRML world, using the entity-unique site-ID/applicationID/entityID triplet as the hash key.


strategy

protected SecurityStrategy strategy
platform-specific security strategy


DEBUG

protected static boolean DEBUG
Flag for debugging/diagnostic output enabled

Method Detail

getDEBUG

public boolean getDEBUG()
Get debugging flag


setDEBUG

public void setDEBUG(boolean pDEBUG)
Set debugging flag


getEntityDispatcher

public static EntityDispatcher getEntityDispatcher(java.lang.String pAddress,
                                                   int pPort)
getEntityDispatcher returns the single, shared instance of the EntityDispatcher object. This is known as the Singleton pattern; see Mark Grand, "Patterns in Java", p. 127. Rather than creating an entityDispatcher by calling new, you should call getEntityDispatcher. This handles creation of a single, shared instance for all callers.

Note that using null for the multicast address will, the first time, return a unicast EntityDispatcher. If, later, the getEntityDispatcher method is called with anything other than the original parameters, the program is stopped and an error message printed.

Parameters:
pAddress - string format multicast address, usually in dotted decimal format (eg, 225.7.8.10).
pPort - port in integer format, eg 6025.

sendPdu

public void sendPdu(ProtocolDataUnit pPdu)
Example of delegation of writing a PDU to the single static behaviorStreamBuffer.


sendPdu

public void sendPdu(ProtocolDataUnit pdu,
                    java.lang.String pDestinationHost,
                    int pDestinationPort)
Example of delegation of writing a PDU to the single static behaviorStreamBuffer.


debug

protected void debug(java.lang.String pDiagnostic)
Debugging output. Pass in a string, and it gets printed out on the console. You can pass in strings such as "foo " + bar.getName().


trace

protected void trace(java.lang.String pDiagnostic)
Guaranteed trace output. Pass in a string, and it gets printed out on the console. You can pass in strings such as "foo " + bar.getName().


createUdpUnicastBehaviorStreamBuffer

public void createUdpUnicastBehaviorStreamBuffer(java.lang.Integer pPortNumber)
Creates unicast UDP BehaviorStreamBuffer. This should be called by the appropriate security strategy first; eg, the constructor calls the security strategy, which, after the appropriate security calls have been made, calls this. Passes in datagramPort indirectly.


createMulticastBehaviorStreamBuffer

public void createMulticastBehaviorStreamBuffer(java.lang.String pMcastAddress,
                                                java.lang.Integer pPortNumber)
Creates multicast BehaviorStreamBuffer. This should be called by the appropriate security strategy first; eg, the constructor calls the security strategy, which, after the appropriate security calls have been made, calls this. Passes in datagramPort indirectly.


startBehaviorStreamBufferThread

public void startBehaviorStreamBufferThread()
startBehaviorStreamBufferThread starts the behaviorStreamBuffer thread.

Called by run(); this is the essential setup portion of the run loop. run() has enabled platform-specific security at this point, so startBehaviorStreamBufferThread doesn't have to worry about network sandboxes.


addListener

public void addListener(PduSubscriber pSubscriber,
                        EntityID pEntityID)
Adds a subscribing Scipt node to the pduSubscriberScriptNodesHashtable being maintained. Once an EspduTransform (or other Script node) has been added to the list, it can receive PDUs addressed to that EntityID triplet. This method is invoked by the Script node to record its reference when it is constructed. Availability of all the Script node references in the Hashtable means that PDUs can be delivered when ready by this EntityDispatcher thread.

This is synchronized to ensure serial access. (This might not actually be neccesary; I think hashtable is synchronized internally, but can't confirm that.) addListener and removeListener are the two methods that implement the PduPublisher interface. Clients subscribe via this mechanism. Note that more than one object may subscribe to an entityID.

Specified by:
addListener in interface PduPublisher

removeListener

public void removeListener(PduSubscriber listenerToRemove,
                           EntityID pEntityID)
addListener and removeListener are the two methods that implement the PduPublisher interface. Clients unsubscribe from EntityDispatcher via this mechanism. Note that more than one object (i.e. more than one Script node in the VRML scene) may subscribe using the same entityID.

This process is repeated for each subscribing Scipt node in the VRML scene.

removeListener is synchronized to ensure serial access. If an object has subscribed multiple times, this will remove only one instance of the subscription. This is probably bad.

Specified by:
removeListener in interface PduPublisher

checkForTrafficAndFallBackToTunnel

public void checkForTrafficAndFallBackToTunnel(java.lang.String pTunnelAddress,
                                               int pTunnelPort,
                                               int pLocalPort)
Test for the existence of multicast (or unicast) and, if not found, open up a tunnel to the tunnel server, and replace the original BSB with this new one. The algorithm here is to listen on the default BSB port for some amount of time; if nothing is received, create a new BSB that points to the tunnel server, and get packets from that, instead. If we do fall back to the tunnel, we need to initiate some housekeeping with the tunnel server, mostly sending keepalive packets to it on a regular basis.


getSleepInterval

public float getSleepInterval()
Accessor method.


adviseSleepInterval

public void adviseSleepInterval(float anotherReadWriteInterval)
Somewhat careful accessor method that decides how long to let the thread sleep, so that it doesn't steal excessive cycles from the VRML 3D graphics rendering process(es). This is synchronized to ensure serial access, and make sure multiple instances of clients don't step on themselves.


run

public void run()
run() switches on platform-secific security, gets the thread running using doThread (), then calls doRun () which does the actual work of reading from the network.

This is the implementation of the runnable interface. Each method invocation is two-step process -- run calls SecurityStrategy's invokePrivilege(), which in turn calls back to this object -- which is required because some platforms require the security calls to be "above" in the stack. Just switching on the security parameters in strategy, and then returning and attempting to read from a socket, is not enough.

Specified by:
run in interface java.lang.Runnable

doRun

public void doRun()
After the behaviorStreamBuffer thread is started, doRun loops endlessly to pull unordered lists of PDUs from the behaviorStreamBuffer, sending the PDUs one-by-one to the appropriate EspduTransform matching the entity.

Called by run(); this is the essential portion of the run loop. run() has enabled platform-specific security at this point, so doRun doesn't have to worry about network sandboxes.


singleReadLoop

public void singleReadLoop()
singleRunLoop() is called via doRun when threading, or via the invoking application if not threading (e.g. due to IE security restrictions).


shutdown

public void shutdown()
shutdown() is called when VRML scene exits.