mil.navy.nps.dis
Class ProtocolDataUnit

java.lang.Object
  extended bymil.navy.nps.dis.PduElement
      extended bymil.navy.nps.dis.ProtocolDataUnit
All Implemented Interfaces:
java.lang.Cloneable, SerializationInterface
Direct Known Subclasses:
CollisionPdu, DetonationPdu, EntityStatePdu, FirePdu, RadioCommunicationsFamily, SimulationManagementFamily

public abstract class ProtocolDataUnit
extends PduElement

Top-level abstract (uninstantiated) class for all PDUs.

Version:
1.0
Author:
Don McGregor (http://www.npsnet.org/~mcgredo)
Location:
Web: http://www.web3d.org/WorkingGroups/vrtp/mil/navy/nps/dis/ProtocolDataUnit.java
or locally: ~/mil/navy/nps/dis/ProtocolDataUnit.java
Hierarchy Diagram:
Summary:
This is an abstract class that actual PDUs inherit from. The ProtocolDataUnit includes the header information that is present in every PDU. Centralizing this information in one class prevents us from having to re-declare it in every class.
Explanation:
This class in turn inherits from PduElement, the abstract class that defines a high-level interface to the "things" that make up a PDU.

I generally declare instance variables to be protected, which means that they are directly accessible from this class and all subclasses. Those who believe in full-jackboot mode will want them declared private, so subclasses can't access them either.

The accessor methods (getProtocolVersion et al) are declared public, so that anyone, including those outside this package, can access them. You should always go through accessor methods when setting values inside an object. Direct access from outside the class can cause mysterious errors that are very hard to track down.

Note that, due to garbage collection, we don't have to worry about the status of orphaned instance variables. For example, this operation will cause memory leaks in C++ or Obj-C:

    protocolVersion = newProtocolVersion;
In C++, this operation would leave an orphaned object; the _old_ object that was held by protocolVersion would have no valid pointers to it, but would still take up memory. With GC, the old, orphaned protocolVersion's memory will be scavanged and returned to use.

Accessor methods return a copy of the thing they're getting, not the actual thing. This prevents violations of encapsulation. If this weren't the case, we might see something like this:

myLength = aPdu.getLength();
myLength.addOne();
this would return another pointer to the same object contained inside of aPdu. addOne() would modify the value inside of aPdu, a violation of encapsulation. So instead we implement getLength() like this:

public UnsignedByte getLength()
{ return (UnsignedByte)length.clone();
}
this creates an identical copy of length and returns that. The calling method can modify that to its heart's content without affecting aPdu. For the same reason, the clone() method should make copies of all the instance variables. Otherwise, the "new" object will have pointers shared with the old object. The clone() operation also helps prevent big dependency meshes for GC.

Serialization should make a call to the superclass before it does its own instance variables.

Note that we do not include the padding variables in the instance variables of objects. Padding is used only in the serialized, external representation of a PDU. The user would have no reason to do anything with padding in an object. Since it is only an artifact of serialization, references to padding are limited to the serialization/deserialization methods.

Also, the length, a field in the header portion, is calculated on the fly rather than saved and set. The header has a fixed length, 18 bytes. To find the size of a PDU, implement the length() method in all the subclasses. This should make a call to super, do any local calculations required, then return the correct number. Your code might look like :

    public int length() {
	return super.length() + 110 + aVector.size * anElement.length();
    }

This adds up the length of the superclass, such as the PDU header, the basic length of the subclass (such as the entity state PDU), and adds the length of any variable number of parameters attached to the PDU.

History:
10Oct96 /Don McGregor /New
15Oct96 /Don McGregor /setter methods with "primitive" types, minor changes as suggested in class.
28Oct96 /Don McGregor /changed length() implementation
17Nov96 /Don McGregor /retrofitted in EntityID object for site, application, entity fields, kept old external interface, added new interface for setting and getting entityID as one object
18Nov96 /Don McGregor /Moved entityID into subclasses of ProtocolDataUnit
10Mar97 /Don McGregor /changes for javadoc
16Apr97 /Don McGregor /PrintStream passed to printValues
8Dec97 /Ronan Fauglas /changes for documentation templates + complements in documentation
11Dec97 /Ronan Fauglas /changed access methods to class variables to "getVariable"
30Nov99 /Don Brutzman /partially implemented several simulation management PDUs
5Aug2000 /Don Brutzman /numerous PDU types now supported
References:
DIS Data Dictionary :PDU Header Record
DIS-Java-VRML Working Group: http://www.web3d.org/WorkingGroups/vrtp/dis-java-vrml/
DIS specification : IEEE 1278.1, 4.4.1
See Also:
PduElement, SerializationInterface

Field Summary
static boolean DEBUG
          Debugging flag; when set true, turns on verbose diagnostic, statements that prints in the java console.
protected  UnsignedByte exerciseID
          Exercise Identifier Field.
protected  UnsignedByte pduType
          Type of PDU (entity state, message, etc).
protected  UnsignedByte protocolFamily
          Indicates the family of protocols which the PDU belongs to.
protected  UnsignedByte protocolVersion
          Current version of the protocol being used.
static int sizeOf
          Constant value--size of a PDU header when written out; sizeOf = 12 bytes.
protected  long timeReceived
          timeReceived is the time since 1970.
protected  UnsignedInt timestamp
          Time Stamp, either relative or UTC This field shall specify the time which the data in the PDU is valid.
 
Constructor Summary
ProtocolDataUnit()
          Constructor for a default protocol data unit.
 
Method Summary
static ProtocolDataUnit byteArrayToPdu(byte[] pByteArray)
          Returns a PDU completely read in from the byte array in parameter.
 java.lang.Object clone()
          Makes deep copies of all the instance variables, so we don't have two objects pointing to the same data.
static ProtocolDataUnit datagramToPdu(java.net.DatagramPacket pDatagramPacket)
          Legacy compatability method
protected static void debug(java.lang.String pDiagnostic)
          Debugging output.
 void deSerialize(java.io.DataInputStream inputStream)
          Deserialize our data from the input stream.
 UnsignedByte getExerciseID()
           
static java.lang.StringBuffer getPaddingOfLength(int pIndent)
          In a number of places we need to generate strings of a specific length of spaces.
 UnsignedByte getPduType()
           
 UnsignedByte getProtocolFamily()
           
 UnsignedByte getProtocolVersion()
           
 boolean getRtpHeaderEnabled()
           
 long getTimeReceived()
          get the time the PDU was received.
 UnsignedInt getTimestamp()
           
 double getVRMLTimestamp()
          Returns the timestamp, INTERPRETED IN THE VRML DEFINITION OF TIME.
 int length()
          Returns the length of the PDU header.
 void makeTimestampCurrent()
          This methods sets the Timestamp to the current Time.
abstract  java.lang.String pduName()
          Returns the name of the PDU--eg, Entity State, Fire, Comment, etc-- as a String.
 void printValues(int indentLevel, java.io.PrintStream printStream)
          Prints the generated serialized object for debugging.
 void serialize(java.io.DataOutputStream outputStream)
          Serialize our data out to the stream.
 void setExerciseID(int pExerciseID)
           
 void setExerciseID(UnsignedByte pExerciseID)
           
 void setPduType(short pPduType)
           
 void setPduType(UnsignedByte pPduType)
           
 void setProtocolFamily(int pProtocolFamily)
           
 void setProtocolFamily(UnsignedByte pProtocolFamily)
           
 void setProtocolVersion(int pProtocolVersion)
           
 void setProtocolVersion(UnsignedByte pProtocolVersion)
           
 void setRtpHeaderEnabled(boolean pRtpHeaderEnabled)
           
static void setSimulationStartTime(long pStartTime)
          Accessor method that sets the simulation start time.
 void setTimeReceived(long pTimeReceived)
          Set the time the PDU was received
 void setTimestamp(long pTimestamp)
           
 void setTimestamp(UnsignedInt pTimestamp)
           
 void stampTimeReceived()
          Stamp the current time into the timeReceived field
 java.lang.String toString()
           
protected static void trace(java.lang.String pDiagnostic)
          Guaranteed debugging output.
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

DEBUG

public static final boolean DEBUG
Debugging flag; when set true, turns on verbose diagnostic, statements that prints in the java console. It is by default set to TRUE.

See Also:
Constant Field Values

protocolVersion

protected UnsignedByte protocolVersion
Current version of the protocol being used. It is now 2.0 which should be mapped to protocolVersion=5 No default value is set.
References:
DIS Data Dictionary: Protocol Version Field
DIS specification : IEEE 1278.1, 4.4.1.1


exerciseID

protected UnsignedByte exerciseID
Exercise Identifier Field. Exercise Identification shall be unique to each exercise being conducted simultaneously on the same communications medium. No default value.
References:
DIS Data Dictionary :Exercise Identifier Field
DIS specification : IEEE 1278.1, 4.4.1.2


pduType

protected UnsignedByte pduType
Type of PDU (entity state, message, etc).
References:
DIS Data Dictionary: PDU Type Field
DIS specification : IEEE 1278.1, 4.4.1.3

See Also:
PduTypeField

protocolFamily

protected UnsignedByte protocolFamily
Indicates the family of protocols which the PDU belongs to.
References:
DIS Data Dictionary: Protocol Family Field
DIS specification : IEEE 1278.1, 4.4.1.3


timestamp

protected UnsignedInt timestamp
Time Stamp, either relative or UTC This field shall specify the time which the data in the PDU is valid.
References:
DIS Data Dictionary: Time Stamp Field
DIS specification : IEEE 1278.1, paragraph 5.2.31 page 71.
Note:
TimeStamp is initialized on creation of the Pdus.
DIS specification excerpt:
5.2.31 Timestamp. Timestamping shall be used to indicate the time at which the data contained in the PDU was generated. For simulations using absolute timestamps, this time is the exact UTC. For simulations using relative timestamps, this time is the time that the simulation application assumes the event or state occurred in the synthetic environment relative to its own host clock. This timestamp shall be speciŽed using a 32-bit unsigned integer representing units of time passed since the beginning of the current hour. The least signiŽcant bit shall indicate whether the timestamp is absolute or relative.
5.2.31.1 Absolute timestamp. An absolute timestamp shall be used when simulation application clocks are synchronized to UTC. The use of the absolute timestamp shall be signiŽed by the least signiŽcant bit set to one.
5.2.31.2 Relative timestamp. A relative timestamp shall be used when simulation application clocks are not synchronized. Each simulation application shall keep time beginning with an arbitrary starting point. The time indicated by the timestamp shall be relative to the simulation application issuing the PDU. The use of the relative timestamp shall be signiŽed by the least signiŽcant bit set to zero.
5.2.31.3 Scale. The scale of the time value contained in the most significant 31 bits of the timestamp shall be determined by setting one hour equal to (2 31 Š1), thereby resulting in each time unit representing 3600 s/(2 31 Š1) = 1.676 µs.


timeReceived

protected long timeReceived
timeReceived is the time since 1970. This field holds the time the PDU was received, ON THE CLIENT. Note that this is not a serialized field; it is not in the DIS spec, and cannot be sent over the wire.


sizeOf

public static final int sizeOf
Constant value--size of a PDU header when written out; sizeOf = 12 bytes.

See Also:
Constant Field Values
Constructor Detail

ProtocolDataUnit

public ProtocolDataUnit()
Constructor for a default protocol data unit. No field is initialized.

Method Detail

getRtpHeaderEnabled

public boolean getRtpHeaderEnabled()

setRtpHeaderEnabled

public void setRtpHeaderEnabled(boolean pRtpHeaderEnabled)

debug

protected static 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 static void trace(java.lang.String pDiagnostic)
Guaranteed debugging output. Pass in a string, and it gets printed out on the console. You can pass in strings such as "foo " + bar.getName().


clone

public java.lang.Object clone()
Description copied from class: PduElement
Makes deep copies of all the instance variables, so we don't have two objects pointing to the same data. The accessor methods make copies of the objects, rather than returning the objects themselves. The runtime provides the right object type with the call to super.clone(), and we cast it to our type. Subclasses should do the same thing, and all these ivars will be taken care of automatically.

Overrides:
clone in class PduElement
Returns:
a clone of this instance
See Also:
Object

getPaddingOfLength

public static java.lang.StringBuffer getPaddingOfLength(int pIndent)
In a number of places we need to generate strings of a specific length of spaces. this does that. This could probably be more efficent.... Fun fact: new String(char array of spaces) generates garbage


printValues

public void printValues(int indentLevel,
                        java.io.PrintStream printStream)
Description copied from class: PduElement
Prints the generated serialized object for debugging.

Specified by:
printValues in class PduElement
Parameters:
indentLevel - number of spaces to indent for visibility

makeTimestampCurrent

public void makeTimestampCurrent()
This methods sets the Timestamp to the current Time.
Explanation:
Sets the timestamp field to a current value. THIS USES THE VRML DEFINITION OF TIME RATHER THAN THE DIS DEFINITION OF TIME. VRML uses a double to hold the number of seconds since January 1, 1970. That takes 64 bits, though, and we have only 32 in the PDU. We get around this, sort of, by adopting the convention of having the start time equal to midnight on the day the simulation started up. With 32 bits, we can run for about 50 days before the number of milliseconds in the field rolls over. When we return the VRML timestamp, we can just add the start time (saved in a class variable) to the timestamp and cast it to a double.


getVRMLTimestamp

public double getVRMLTimestamp()
Returns the timestamp, INTERPRETED IN THE VRML DEFINITION OF TIME. VRML uses the number of seconds since January 1, 1970, in a double, as the definition of absolute time. DIS uses an unsigned int with some absurdly irrelevant definition of time.


setSimulationStartTime

public static void setSimulationStartTime(long pStartTime)
Accessor method that sets the simulation start time. Ordinarily this is set to midnight of the day that the simulation is started. See timestamp for details.


pduName

public abstract java.lang.String pduName()
Returns the name of the PDU--eg, Entity State, Fire, Comment, etc-- as a String.
References:
See PDU Name

Returns:
the name of the PDU as a String

toString

public java.lang.String toString()

getProtocolVersion

public UnsignedByte getProtocolVersion()

setProtocolVersion

public void setProtocolVersion(UnsignedByte pProtocolVersion)

setProtocolVersion

public void setProtocolVersion(int pProtocolVersion)

getExerciseID

public UnsignedByte getExerciseID()

setExerciseID

public void setExerciseID(UnsignedByte pExerciseID)

setExerciseID

public void setExerciseID(int pExerciseID)

getPduType

public UnsignedByte getPduType()
See Also:
for legal values

setPduType

public void setPduType(UnsignedByte pPduType)
See Also:
for legal values

setPduType

public void setPduType(short pPduType)
See Also:
for legal values

getProtocolFamily

public UnsignedByte getProtocolFamily()

setProtocolFamily

public void setProtocolFamily(UnsignedByte pProtocolFamily)

setProtocolFamily

public void setProtocolFamily(int pProtocolFamily)

getTimestamp

public UnsignedInt getTimestamp()

setTimestamp

public void setTimestamp(UnsignedInt pTimestamp)

setTimestamp

public void setTimestamp(long pTimestamp)

length

public int length()
Returns the length of the PDU header.

Specified by:
length in class PduElement
Returns:
the length of the PDU header (currently 12 bytes). Note that this should NOT include the length of the RTP header.

serialize

public void serialize(java.io.DataOutputStream outputStream)
Description copied from class: PduElement
Serialize our data out to the stream. Subclasses of us should call super.Serialize() to make sure the superclasse's data is serialized out. The order in which instance variables are serialized is significant. They must be serialized in the same order they appear in the DIS spec. Prints out some information during execution if debugging flag is set.

Specified by:
serialize in interface SerializationInterface
Specified by:
serialize in class PduElement
Parameters:
outputStream - the stream to which this object is serialized

deSerialize

public void deSerialize(java.io.DataInputStream inputStream)
Description copied from class: PduElement
Deserialize our data from the input stream. Subclasses of us should call super.deSerialize to make sure the superclass's data are properly affected. The order in which instance variables are serialized is significant. They must be deSerialized in the same order as they have been serialized as specified by the DIS spec.

Specified by:
deSerialize in interface SerializationInterface
Specified by:
deSerialize in class PduElement
Parameters:
inputStream - the stream from which this object is initialized

datagramToPdu

public static ProtocolDataUnit datagramToPdu(java.net.DatagramPacket pDatagramPacket)
Legacy compatability method


byteArrayToPdu

public static ProtocolDataUnit byteArrayToPdu(byte[] pByteArray)
Returns a PDU completely read in from the byte array in parameter.
Explanation:
This can't be a constructor, since we don't know what type of object we're going to instantiate before it fires. This is a static (class) method. This gets a bit convoluted, but it makes the external interface nice. We have to decide what type of PDU to instantiate, but we don't know the PDU type until we've read some of it. So we read the first few bytes of the byte array in the datagram packet, and find the PDU type. Then we reset the stream, and tell the new object to deserialize itself. It does this by making a call to super.deserialize as the first executable statement of the deserialize method. This causes the data to be read in the correct order--the data for the PDU header is at the front of the datagram, and that's the first data that's deserialized. Then the subclass deserialize method fires, and that deserializes the next data in the stream, corresponding to that subclass. The process looks something like this:
          ProtocolDataUnit
                 |
                 ^
           EntityStatePDU
  
The deserialize message goes first to the EntityStatePdu. The ESPDU immediately calls the deserialize method in its superclass, ProtocolDataUnit. PDU deserializes the first few instance variables, then returns. The ESPDU then deserializes its ivars. Prints out some information during exectuion if debugging flag is set.

Parameters:
pByteArray - The data packet of bytes
Returns:
the PDU as identified in the datagam (with default initialization)
Throws:
java.lang.RuntimeException - if an IO error occurs.

getTimeReceived

public long getTimeReceived()
get the time the PDU was received. Note that this may be off a bit due to buffering in the behavior stream buffer.


setTimeReceived

public void setTimeReceived(long pTimeReceived)
Set the time the PDU was received


stampTimeReceived

public void stampTimeReceived()
Stamp the current time into the timeReceived field