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:
Post a Comment