.. _`Proto message for a DDS system`:

##############################
Proto message for a DDS system
##############################


Individual declarations in a ``.proto`` file can be annotated with a number
of options. Options do not change the overall meaning of a declaration,
but may affect the way it is handled in a particular context.

Options can be defined at different levels:

  - File-level options: meaning they should be written at the top-level
    scope, not inside any message, enum, or service definition.
  - Message-level options: meaning they should be written inside message
    definitions.
  - Field-level options: meaning they should be written inside field
    definitions. Enum types, enum values, service types, and service
    methods.

Use case: Person
================

In this use case example, a system capable of describing the personal
data of persons must be built using the GPB data-model

The layout can be::

  string name
  integer age
  sequence phone-number + type
  sequence friends

Proto file for the Person example
=================================

This use case is described in this ``.proto`` file:

.. code-block:: protobuf

   import "omg/dds/descriptor.proto";
   package address;

   message Person {
      required string name = 1;
      required int32 age = 2;
      optional string email = 3;

      enum PhoneType {
         UNDEFINED = 0;
         MOBILE    = 1;
         HOME      = 2;
         WORK      = 3;
      }

      message PhoneNumber {
         required string number = 1;
         optional PhoneType type  = 2 [default = HOME];
      }

   repeated PhoneNumber phone = 4;
   repeated Person friend = 5;
   }


GPB labels every field as either a *required* or an *optional* field.
Required fields are *always* used/filled; optional fields may or may not
be.

Different data models are compatible if all *required* fields are the same.
Data models can be extended with extra fields; if those new fields are all
*optional*, then the new model will still be compatible with older applications
using the old data model.

In our example the *name* and *age* are always required. The *email* string
is optional, as extra information for this person. The sequences with phone
numbers and friends are allowed to be empty.

Detailed explanation for the layout of a ``.proto`` file can be found in
the Google Protocol buffer documentation on
https://developers.google.com/protocol-buffers/docs/proto


Annotating a proto message for use as a type in DDS
===================================================

For the GPB message to be able to be handled correctly in a DDS system,
some options are needed in the ``.proto`` file which define how the GPB
message shall behave in the DDS system.

At the message level there is an extra option ``.omg.dds.type``.
This tells the protocol buffer compiler that this message is also a dds type message.
This type option has a optional extra parameter for giving this type a dds type name.
By default it has the same name in the DDS domain as it has in GPB.

The Person example with this option:

.. code-block:: protobuf

   import "omg/dds/descriptor.proto";

   package address;

   message Person {
    option (.omg.dds.type) = {};
    required string name = 1;
    required int32 age = 2;

   enum PhoneType {
     UNDEFINED = 0;
     MOBILE    = 1;
     HOME      = 2;
     WORK      = 3;
   }

   message PhoneNumber {
      required string number = 1;
     optional PhoneType type  = 2 [default = HOME];
    }
    repeated PhoneNumber phone = 4;
    repeated Person friend = 5;
   }


Proto file with omg.dds.member.key option
-----------------------------------------

For support of a key value in the datamodel, the option ``key`` can be given as a
field-member option. One or more fields containing this option will indicate that
these members make a unique key identifier in the data model. A field
indicated as a key field must always be a *required* field for GPB. Also a key
field is automatically a filterable field, as described below.

The Person example with *name* as a unique key (this means that each unique value
of the name will lead to a separate instance in DDS with its own history):

.. code-block:: protobuf

   import "omg/dds/descriptor.proto";

   package address;

   message Person {
      option (.omg.dds.type) = {};
      required string name = 1 [(.omg.dds.member).key = true];
      required int32 age = 2;
      optional string email = 3;
   }
   enum PhoneType {
      UNDEFINED = 0;
      MOBILE = 1;
      HOME = 2;
      WORK = 3;
   }
   message PhoneNumber {
      required string number = 1;
      optional PhoneType type = 2 [default = HOME];
   }

   repeated PhoneNumber phone = 4;
   repeated Person friend = 5;


Proto file with omg.dds.member.filterable option
------------------------------------------------

For support of filterable fields in the datamodel, the option ``filterable`` can be
given as a field-member option.

One or more fields with this option indicates that these members are available
for dynamic querying and filtering by means of a ``QueryCondition`` or
``ContentFilteredTopic`` in DDS.

A field marked as a filterable field must always be a *required* field in GPB.
A key field is always filterable, by definition.

The Person example with *age* as a filterable attribute:

.. code-block:: protobuf

   import "omg/dds/descriptor.proto";

   package address;

   message Person {
    option (.omg.dds.type) = {};
    required string name = 1 [(.omg.dds.member).key = true];
    required int32 age = 2 [(.omg.dds.member).filterable = true];
    optional string email = 3;

   enum PhoneType {
     UNDEFINED = 0;
     MOBILE    = 1;
     HOME      = 2;
     WORK      = 3;
   }

   message PhoneNumber {
      required string number = 1;
     optional PhoneType type  = 2 [default = HOME];
    }
    repeated PhoneNumber phone = 4;
    repeated Person friend = 5;
   }

Proto file with omg.dds.member.name option
------------------------------------------

The previous examples will result in a DDS type with the directly-mapped fields in
IDL with the same name as in proto. (Key fields and filterable fields are directly
mapped.)

If a different name is needed in the DDS domain for a fieldname in the generated
IDL and dds type, a name can be given as an ``omg.dds.member`` option.

Example where the *age* field will be named ``AgeInYears`` in the DDS domain:

.. code-block:: protobuf

   import "omg/dds/descriptor.proto";

   package address;

   message Person {
    option (.omg.dds.type) = {};
    required string name = 1 [(.omg.dds.member).key = true];
    required int32 age = 2   [(.omg.dds.member) = { name: "AgeInYears" filterable: true }];
    optional string email = 3 ;

   enum PhoneType {
     UNDEFINED = 0;
     MOBILE    = 1;
     HOME      = 2;
     WORK      = 3;
   }

   message PhoneNumber {
      required string number = 1;
     optional PhoneType type  = 2 [default = HOME];
    }
    repeated PhoneNumber phone = 4;
    repeated Person friend = 5;
   }



.. |caution| image:: ./images/icon-caution.*
            :height: 6mm
.. |info|   image:: ./images/icon-info.*
            :height: 6mm
.. |windows| image:: ./images/icon-windows.*
            :height: 6mm
.. |unix| image:: ./images/icon-unix.*
            :height: 6mm
.. |linux| image:: ./images/icon-linux.*
            :height: 6mm
.. |c| image:: ./images/icon-c.*
            :height: 6mm
.. |cpp| image:: ./images/icon-cpp.*
            :height: 6mm
.. |csharp| image:: ./images/icon-csharp.*
            :height: 6mm
.. |java| image:: ./images/icon-java.*
            :height: 6mm

