Skip to content

Latest commit

 

History

History
268 lines (203 loc) · 10 KB

XMLPG.md

File metadata and controls

268 lines (203 loc) · 10 KB

XMLPG (XML Multi-Language Protocol Generator)

Introduction

XML Multi-Language Protocol Generator uses an abstract, XML language description of Protocol Data Units to quickly generate Java and C++ language protocol implementations that can match existing binary protocols.

The user writes a simple, XML-based description of the protocol data units, including the names and types of the protocol elements. XMLPG generates Java and C++ language classes with getters, setters, constructors, and marshaling and unmarshaling code.

The XML fragment below provides an abstract definition of a protocol class:

<class name="EntityID" inheritsFrom="root" comment="The identifier for entities in a DIS world. It consists of three unsigned short values, which together are unique.">
  
    <attribute name="application" comment="The application ID">
        <primitive type="unsigned short"/>
    </attribute>
  
    <attribute name="site" comment="The site ID">
        <primitive type="unsigned short"/>
    </attribute>  
  
    <attribute name="entity" comment="the entity ID">
        <primitive type="unsigned short"/>
    </attribute>
</class>  

Figure 1. XML Protocol Class Description

XMLPG reads this XML and generates an abstract description of the class. This abstract description is compiled to Java and C++ classes.

A fragment of the Java class generated is below:

/**
 * The identifier for entities in a DIS world. It consists of three unsigned short values, which together are unique.
 */
public class EntityID extends Object
{
   /** The application ID */
   protected int  application;

   /** The site ID */
   protected int  site;

   /** the entity ID */
   protected int  entity;

   public void setApplication(int pApplication)
   { application = pApplication;
   }

   public int getApplication()
   { return application; }
   }

Figure 2. Java Language Class Created by XMLPG

A fragment of the C++ header file generated is below:

class XML_DIS_EXPORT EntityID
{  
public:  
  unsigned short application;  // The application ID  
  unsigned short site;  // The site ID  
  unsigned short entity;  // the entity ID  
  
 public:  
    EntityID();
    ~EntityID();
  
    unsigned short getApplication() const;  
    void setApplication(unsigned short x);  

Figure 3. C++ Language Class Generated by XMLPG

As can be seen, the XML description acts as a template for the generation of the Java and C++ programming language classes. The code appropriate to each language, including marshaling and unmarshaling code, is generated by XMLPG. The programmer can then compile the generated code.

XMLPG is an open source project with a BSD license.

XML Description Language

The XML syntax used to describe the protocol is relatively simple. The objective is to be able to describe either completly new protocols, or match an existing binary protocol, such as Distributed Interactive Simulation (DIS). The abstract XML description should be much easier, faster, and with generate fewer errors than writing the code to implement the protocol from scratch. New languages, if desired, can be added fairly easily.

The <classes> tag encloses one or more class descriptions.

The <class> tag is used to describe one class in the protocol.

<class name="Pdu" inheritsFrom="root" comment="The superclass for all PDUs">

In this case the Java and C++ class generated will be named Pdu and inherit from Object in the case of Java and nothing in the case of C++. A class can also inherit from another class defined in the XML file:

<class name="FirePdu" inheritsFrom="Pdu" comment="Information about someone firing something">

In this case the FirePdu will inherit from Pdu. The comment tag is optional; it will be included as a javadoc class comment or C++ comment.

The class tag contains one or more attribute tags. The attribute tags describe one field of the PDU. The simplest sort of attribute is a primitive, which corresponds to a programming language primitive type.

<attribute name="quantity" comment="how many">  
   <primitive type="unsigned short"/>  
</attribute>  

The attribute will cause a programming language instance variable to be created in the class. The ivar will appear in the same order as which it appears in the XML document. This is important for marshaling and unmarshaling. If you are reverse-engineering an existing protocol you should have attribute tags in exactly the same order in which the appear in the protocol.

There are four basic types of attributes: primitives, references to other classes defined in the same document, fixed lists (or arrays), and variable lists. Each of these are described below.

Primitive Types

These correspond to programming language primitive types. Legal values for these programming types include unsigned byte, unsigned short, unsigned int, long, byte, short, int, float, and double. The syntax for a primitive attribute description is as above.

Class References

A class may include other classes, for example an EntityStatePdu including a EntityID object as one of its attributes. This is very similar to describing a primitive type:

<attribute name="entityID" comment="Uniquely identifies an entity in the world">  
   <classRef name="EntityID"/>  
</attribute>  

The name attribute must contain the name of another class defined in the XML file. Getter and setter methods will be generated for the attribute, and the attribute will be marshaled and unmarshaled. In this case the name of the attribute is "entityID" and the class is of the type is "EntityID" (note capitalization).

The C++ ivar, getter and setter declarations look like this:

EntityID entityID;  // Uniquely identifies an entity in the world  
  
EntityID& getEntityID();
const EntityID& getEntityID() const;
void setEntityID(EntityID &x);

The Java code generated looks like this:

/** Uniquely identifies an entity in the world */  
protected EntityID  entityID = new EntityID();
  
public void setEntityID(EntityID pEntityID)
{ entityID = pEntityID;
}
  
public EntityID getEntityID()
{ return entityID; }

Fixed List

This corresponds to an array. The tags are as below:

<attribute name="marking">
   <list type="fixed" length="12">
     <primitive type="byte"/>
   </list>
</attribute>

The list tag defines a fixed length, which is used to generate an array in the source code. The list tag encloses either a primitive type or a classref field.

The C++ code generated looks like this:

char marking[12];
  
char* getMarking();
const char* getMarking() const;
void setMarking(char* x);

And the Java code like this:

protected byte[]  marking = new byte[12];
  
public void setMarking(byte[] pMarking)
{ marking = pMarking;
}  
  
public byte[] getMarking()
{ return marking; }

Variable List

While fixed lists are always the same length, variable lists may have more or fewer list elements, and are implemented as vectors that can grow or shrink. Variable lists must be tied to an attribute field that is used to determine how many elements are in the lists. This is needed for unmarshaling; when processing a binary format packet we must know how many elements of the list to read.

<attribute name="articulationParameters" comment="variable length list of articulation parameters">
   <list type="variable" countFieldName="articulationParameterCount">
     <classRef name="ArticulationParameter"/>
   </list>
</attribute>

This specifies a field called "articulationParameters" that has a variable number of ArticulationParameter objects in it. The number of objects should be held in the field called "articulationParameterCount". During the unmarshaling process that field will be read and the value used to read that many ArticulationParameter objects. This means that the number of articulation parameters specified in articulationParameterCount should be current at the time the PDU is marshaled.

Marshaling and Unmarshaling

The classes with get and set methods implements much of the code. However, a network protocol requires that these classes be able to marshal and unmarshal (aka serialize and deserialize) themselves to the network as PDUs. XMLPG is able to do this automatically. The order in which the ivars are marshaled and unmarshaled is determined by the order in which they appear in the XML description document. An example marshal method for the DIS Entity State PDU is shown below. All this code is generated automatically. Note that because ESPDU inherits from PDU the marshal method in the superclass is called first. Then each of the ivars is marshaled, in order. Primitive types are written directly, and embedded objects have their marshal method called. A similar method is generated to unmarshal the class from the network.

public void marshal(DataOutputStream dos)
{
    super.marshal(dos);
    try
    {
       entityID.marshal(dos);
       dos.writeByte( (byte)forceId);
       dos.writeByte( (byte)articulationParameterCount);
       entityType.marshal(dos);
       alternativeEntityType.marshal(dos);
       entityLinearVelocity.marshal(dos);
       entityLocation.marshal(dos);
       entityOrientation.marshal(dos);
       dos.writeInt( (int)entityAppearance);
       deadReckoningParameters.marshal(dos);
       for(int idx = 0; idx < marking.length; idx++)
       {
          dos.writeByte(marking[idx]);
       } // end of array marshaling
       dos.writeInt( (int)capabilities);
       for(int idx = 0; idx < articulationParameters.size(); idx++)
       {
          ArticulationParameter aArticulationParameter = (ArticulationParameter)articulationParameters.get(idx);
          aArticulationParameter.marshal(dos);
       } // end of list marshalling
    } // end try

Similar code is generated for the C++ implementation.