Framing and message headers

Each SBE packet can include two service headers:

  • SOFH (Simple Open Framing Header);
  • message header (defined in SBE template).

These headers carry packet metadata required for correct decode flow.

Simple Open Framing Header (SOFH)

SOFH usually includes:

  • total message size;
  • optional byte-order marker.

Exact format depends on venue.

SOFH selection during schema creation

SOFH policy is set when MessageSchema is created. You can use implicit or explicit selection.

Implicit SOFH selection

Implicit mode supports two built-in variants:

  • standard SBE framing header;
  • CME MDP3 framing header.

Standard SBE header is default:

// Standard SBE header
MessageSchema schema = new MessageSchema(ParseUtil.parse(new File("SbeTemplate.xml")));

Explicitly selecting standard header:

// Standard SBE header
MessageSchema schema = new MessageSchema(ParseUtil.parse(new File("SbeTemplate.xml")), false);

Selecting CME MDP3 header:

// MDP3 SOFH
MessageSchema schema = new MessageSchema(ParseUtil.parse(new File("CmeTemplate.xml")), true);

Explicit SOFH selection

Explicit mode is recommended for new integrations. You pass framing header specification directly to schema constructor.

Example with B3 header:

// Custom header
MessageSchema schema = new MessageSchema(ParseUtil.parse(new File("B3Template.xml")),
        FramingHeaderPolicy.getCustomPolicy(FramingHeaderSpecification.B3_FRAMING_HEADER));

Predefined SOFH specifications

The library includes predefined specifications for known venues:

Name Description
SBE_BE_FRAMING_HEADER Standard SBE header in big-endian format.
B3_FRAMING_HEADER B3 SBE header.
CMEILINK3_FRAMING_HEADER CME iLink3 SBE header.
CMEMDP3_FRAMING_HEADER CME MDP3 SBE header.

Creating custom SOFH

Before creating custom SOFH, define:

  • field list and field offsets;
  • byte order of each field;
  • signed/unsigned type traits.

Current SOFH limitations:

  • two fields only: size field and optional endian marker field;
  • no extra user-defined fields.

Example SOFH:

  • header byte order is little-endian;
  • field 1: message size (uint16);
  • field 2: standard 2-byte SBE endian marker.

Specification code:

    public final static FramingHeaderSpecification MY_FRAMING_HEADER = new FramingHeaderSpecification(
            // Size field specification
            new FramingHeaderSpecification.FieldSpecification(
                    0, // Offset in the header
                    2, // Size of the field
                    false, // Unsigned
                    MessageSchema.Endianess.LittleEndian // Byte order of this field
            ),

            // Message byte order marker specification
            new FramingHeaderSpecification.EndianessFieldSpecification(
                    2, // Offset in the header
                    2, // Size of the field
                    false, // Unsigned
                    MessageSchema.Endianess.LittleEndian, // Byte order of the field
                    FramingHeaderSpecification.SBE_1_0_LE_LITTLEENDIAN_SIGN, // Mark for little-endian byte order of the message.
                    FramingHeaderSpecification.SBE_1_0_LE_BIGENDIAN_SIGN // Mark for big-endian byte order of the message.
            )
    );

Use custom SOFH in MessageSchema:

// Custom header
MessageSchema schema = new MessageSchema(ParseUtil.parse(new File("MyTemplate.xml")),
        FramingHeaderPolicy.getCustomPolicy(MY_FRAMING_HEADER));

Message header

Message header stands before message body and defines service values like template ID and version. The base structure is declared in the XML template.

If the message header has only standard fields, encoder/decoder handles it automatically. If you add custom header fields, your code must read/write them explicitly.

Recommended APIs for custom header fields:

ByteDecoder always initializes required header fields during encoding.

Example: update custom message-header field via virtual ID

Resolve virtual field ID for custom header member:

        String[] headerSequenceNoFieldPath = new String[] {
                // Message header composite pseudo-name
                SpecialFieldIds.MESSAGE_HEADER_FIELD_NAME,
                
                // The message header field name
                "SequenceNo"
        };

        // Get virtual ID of the 'SequenceNo' message header field
        int seqNumID = schema.queryVirtualFieldId(headerSequenceNoFieldPath);

Create message and update/read this field:

byte[] data1 = new byte[SIZE_ENOUGH_TO_ENCODE];
IMessage msg1 = decoder.encode(data, 0, data.length, 1);
// Set the 'SequenceNo' message header field
msg1.setInt(seqNumID, 12345);
// Get the 'SequenceNo' message header field
int seqNum1 = msg1.getInt(seqNumID);