Sunday, April 3, 2011

Exploratory Project Component Specified Verification Function Update

Exploratory Project Component Specified Verification Function Update


That was easy.  In one morning I modified the topic Valid and component supplied Verify function interfaces to avoid supplying the address of the data directly to prevent the reader from modifying the data.  This corrects the deficiency noted in yesterday’s post.

With the change, the registration key is passed to the topic’s Valid function and the component’s Verify function rather that the address of the data.  Any of these validation functions can then instantiate a Verify reader using the supplied key as will be illustrated below in modifications to the examples of yesterday’s post.  Using the read-only pointer supplied by the Verify reader, the data can then be examined to verify its usability.

The address of the instance of the topic’s data buffer is only available to the Verify reader while the Topic Validation invoked by the topic Reader is active.  Therefore, a topic’s Verify function or a component’s Verify function cannot be called directly by a user since the pointer returned by the instantiation of the Verify reader will be null.

Instead, these user defined functions can only be invoked as callbacks via the Message Controller framework when the user instantiates the topic Reader.

With the modifications, yesterday’s example is as follows.

One, the registration of a topic consumer by a component to also provide a Verify function is unchanged as follows.
  procedure Install is

    Deliver_Id_List
    --| Treat all widgets with ids between 100 and 199
    : constant mC.Itf_Types.Delivery_Id_Array_Type
    := ( ( 100, 199 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ), ( 0, 0 ) );

    Delivery_Id
    --| Deliver topic when identifier is between 100 and 199
    : constant mC.Itf_Types.Delivery_List_Type
    := ( Count => 1,
         List  => Deliver_Id_List );

  begin – Install

    ...

    --| Logic_Step:
    --|   Register to consume all delivery (widget) ids of the "Topic Widget
    --|   Event" One-of-N message between 100 and 199.

    mT.Topic_Widget_Event_Layer1.Data.Register
    ( Participant => Component_Key,
      Detection   => mC.Itf_Types.Event_Driven,
      Role        => mC.Itf_Types.Consumer,
      Delivery_Id => Delivery_Id,
      Callback    => Treat_Widget_Event'access,
      Verify      => Verify_Delivery_Event'access,
      Access_Key  => Topic_Widget_Event_Access_Key,
      Status      => Data_Status );

    ...

  end Install;
where  the Verify parameter provides the callback to the Verify_Delivery_Event function. 

This function has the same characteristics as the Verify_Filter_Entry_Point_Type access type that has been changed as follows:
  type Verify_Filter_Entry_Point_Type
  --| Callback to execute component and topic specific verify/filter function
  -- ++
  --| Overview:
  --|   This function is a component specific verify/filter function to be
  --|   executed when the component instantiates the reader for a topic.
  --|   If the component includes a verify/filter function callback when it
  --|   registers to consume a topic, the component supplied function will
  --|   be executed following after the Valid function of the topic.  Both
  --|   must be successful for pointer to the instance of the topic data
  --|   to be returned to the component to enable the data to be examined.
  -- --
  is access function
  ( Key : in Key_Type
    --| Access key
  ) return Boolean;

Two, an example of a topic package specification (visible part) and body (implementation) follow where only the Valid function is different.

package mT.Topic_Widget_Event_Layer1 is
-- ++
--| Overview:
--|   This package declares the widget event topic where the producer
--|   component mimics one that receives ARINC-661 events from a display
--|   processor / application and then publishes these events as a 1-of-N
--|   topic to notify the particular consumer component that registered
--|   to be notified of the topic when the ARINC-661 event identifier
--|   matches the Delivery Identifier for which it registered.
--|
--|   This topic is delivered such that the consumer receives each update
--|   rather than the most recent as for Data Flow and Event Driven.
--|   Therefore, multiple buffers may be needed to retain past updates that
--|   the consumer, due to its relative priority or processing time, the
--|   nature of the producer component, or other reasons prevent it from
--|   treating each update before another is produced.  The registering
--|   consumer component is able to specify the number of additional buffers
--|   that it needs.  If an insufficient number are specified (or the
--|   consumer component is no longer able to read the topic) the producer
--|   will fail to obtain a new write buffer until a new buffer is again
--|   available.
-- --

  Id
  : constant mC.Message.Topic_Id_Type
  := mC.Message.Topic_Widget_Event_Layer1_Id;

  Name
  : constant String(1..25) := "Topic Widget Event Layer1";

  type Data_Type is
  record

    Widget_Id : Display_Interface.Widget_Id_Type;
    --| Identifier of widget that sent the event

    Event_Tag : Display_Interface.Widget_Event_Type;
    --| Identifier of the type of event

    Text      : String_Tools.Variable_String_Type;
    --| Any text associated with the event

  end record;
  for Data_Type'size use 67*32; -- bits
  for Data_Type'alignment use mC.Message.Message_Alignment; -- bytes

  type Topic_Type
  is record
    Header : mC.Message.Message_Header_Type;
    Data   : Data_Type;
  end record;
  for Topic_Type'alignment use mC.Message.Message_Alignment; -- bytes
  for Topic_Type'size use mC.Message.Message_Header_Size*8+(67*32); -- bits

  ---------------------------------------------------------------------------

  function Valid
  ( Key : in mC.Message.Key_Type
    --| Access key
  ) return Boolean;
  --| Validate the Topic Data
  -- ++
  --| Overview:
  --|   This function returns TRUE if Message data can be accessed by its
  --|   pointer and passes the validation.
  --| Limitations:
  --|   This function must ONLY be used to validate data following the
  --|   instantiation of a topic Reader.  It must NOT be used after the
  --|   instantiation of a topic Writer since it will overwrite the Valid
  --|   flag of the instantiation parameter causing the lack of the
  --|   assignment of a write buffer pointer to appear to be valid.
  -- --

  ---------------------------------------------------------------------------

  package Data
  --| Accessor to topic data
  is new mC.Message.Topic( Id         => Id,
                           Name       => Name,
                           Protocol   => mC.Itf_Types.Point_to_Point,
                           Permanence => mC.Itf_Types.EP,
                           Exchange   => mC.Itf_Types.Delivery_Identifier,
                           Kind       => mC.Itf_Types.Request,
                           Data_Type  => Topic_Type,
                           Validation => Valid'access );

end mT.Topic_Widget_Event_Layer1;

package body mT.Topic_Widget_Event_Layer1 is
-- ++
--| Overview:
--|   This package declares the widget event topic where the producer
--|   component mimics one that receives ARINC-661 events from a display
--|   processor / application and then publishes these events as a 1-of-N
--|   topic to notify the particular consumer component that registered to be
--|   notified of the topic when the ARINC-661 event identifier matches the
--|   Delivery Identifier for which they registered.
-- --

  ---------------------------------------------------------------------------

  function Valid
  ( Key : in mC.Message.Key_Type
    --| Access key
  ) return Boolean is
  -- ++
  --| Logic_Flow:
  --|   Validate the data and return True if successful.
  -- --

    package Data is new Data.Verify( Access_Key => Key );

  begin -- Valid

    if not Data.Valid then
      return False;
    else

      -- example
      if Data.Ptr.Data.Widget_Id > 0 and then
         Data.Ptr.Data.Widget_Id < 10000
      then
        return True;
      else
        return False;
      end if;

    end if;

  end Valid;

end mT.Topic_Widget_Event_Layer1;
Instead of the check of Data.Valid, a check that Data.Ptr is non-null could have been done.

Three, the instantiation of a Reader by a topic consumer is unchanged.  Note, Treat_Widget_Event is the callback registered above in the Install to be executed when the event occurs.
  procedure Treat_Widget_Event
  ( Topic : in mC.Topic_Name_Type
  ) is

    package Widget_Event_Data
    is new mT.Topic_Widget_Event_Layer1.Data.Reader
           ( Access_Key => Topic_Widget_Event_Access_Key,
             Fresh_Data => True );

  begin -- Treat_Widget_Event

    --| Logic_Step:
    --|   Check if data is usable.

    if Widget_Event_Data.Valid then

      --| Logic_Stop:
      --|   Act upon the received event.

      Create_Response
      ( Widget_Id => Widget_Event_Data.Ptr.Data.Widget_Id,
        Event     => Widget_Event_Data.Ptr.Data.Event_Tag,
        Text      => Widget_Event_Data.Ptr.Data.Text );

--  else -- not Widget_Event_Data.Valid
    end if; -- Widget_Event_Data.Valid

  end Treat_Widget_Event;
Instead of the check of Widget_Event_Data.Valid, a check that Widget_Event_Data.Ptr is non-null could have been done.  Any use of the topic data fields accessible via the Widget_Event_Data.Ptr.Data pointer could have been done.

No validation of the data had to be done in the above procedure because it had all been accomplished by the framework and the component’s Verify_Delivery_Event function when package Widget_Event_Data was instantiated (such as can occur using the constructor of a C++/C# class).

When the above topic Reader was instantiated, the data buffer was located and then the common validation was performed.  Only the parameter passed via the two callbacks is changed.
function Topic_Validation
( Validation : in Validation_Access_Type;
  Data       : in mC.Message.Data_Address_Type;
  Access_Key : in Key_Type
) return Boolean is

  Header_Ptr
  --| Pointer to topic header
  : Message_Header_Ptr_Type
  := Address_to_Header_Ptr( System.Address(Data) );

  Valid
  --| True if topic data is valid and contains the data values that the
  --| component needs to treat the topic
  : Boolean;

  use type Apps.Component_Selector_Type;

begin -- Topic_Validation

  --| Logic_Step:
  --|   Do any general validation of the header.
  --| Notes:
  --|   o For remote messages, the CRC checked when received as well as a
  --|     valid, expected Source for the topic.
  --|   o For local messages, the header really doesn't mean anything.

  -- The following is an illustration of examining the header.
  if Integer(Header_Ptr.Source.User_Id) = Integer(Local_App.Id) or else
     ( Header_Ptr.Source.User_Id = 0 and then
       Header_Ptr.Source.Com_Id  = 0 and then
       Header_Ptr.Source.Sub_Id  = 0 )
  then
    Console.Write( "Local Topic instance" );
  else
    Console.Write( "Remote Topic instance",
                   Integer(Header_Ptr.Source.User_Id),
                   Integer(Header_Ptr.Source.Com_Id),
                   Integer(Header_Ptr.Source.Sub_Id) );
  end if;

  --| Logic_Step:
  --|   Do general validation for the particular topic.

  if Validation /= null then
    Valid := Validation( Key => Access_Key );
  else
    Valid := True; -- no validation routine to modify the original validity
  end if;

  if Valid then

    --| Logic_Step:
    --|   Do any component specific validation or filtering of the consumer.

    if Key_Type(Access_Key).User_Record.Verify /= null then
      Valid := Key_Type(Access_Key).User_Record.Verify( Key => Access_Key );
    end if;

  else
    Console.Write_Error("Topic_Validation Valid of False");
  end if;

  return Valid;

end Topic_Validation;

In the above, the topic header is first checked.  If no problems are found, other general validation could be done.  Next, the supplied Validation callback for the topic is executed.  If that returns Valid of True, any Verify callback of the component of the Reader is executed.  If Valid is returned as True, the reader will make the data pointer available to the topic consumer.

The above function is called by supplying the Data address located by the Reader.  This address is set to null upon the return from the above function.  Therefore, it remains unusable until the Reader is again instantiated.

Last, the Verify / Filter function of the topic consumer as invoked by the last step of Topic_Validation.
  function Verify_Delivery_Event -- of Verify_Filter_Entry_Point_Type access
  ( Key : in mC.Message.Key_Type
  ) return Boolean is
  -- ++
  --| Logic_Flow:
  --|   Verify/filter the topic when instantiate the Reader.
  -- --

    package Data is new mT.Topic_Widget_Event_Layer1.Data.Verify
                        ( Access_Key => Key );

  begin -- Verify_Delivery_Event

    if Data.Valid and then
       ( Data.Ptr.Data.Widget_Id = abc or else
         ( Data.Ptr.Data.Widget_Id >= xyz and then
           Data.Ptr.Data.Widget_Id <= zyx ) )
    then
      return True;
    else
      return False;
    end if;

  end Verify_Delivery_Event;

No comments: