3D PLM Enterprise Architecture

Middleware Abstraction

The Send/Receive Communication Protocol

Sending notifications from command to command
Technical Article

Abstract

To convey end user intents to the object that can do the requested job, CAA V5 uses specific objects called commands that build a tree structure. Events issued by the end user are converted into CAA V5 notifications that are sent from command to command upwards in the command tree structure until a command executes the job. A given command can send notifications, and when receiving one, it can either be transparent to, enrich, or process the received notification, depending on the notification type and the command purpose.


How It Works

The send/receive communication protocol uses the SendNotification, AnalyseNotification, and ReceiveNotification methods of the CATCommand class, and sends notifications along the command tree structure to perform the event propagation from the command that detected the event to the command that can process it.

CAASysSendReceive1.gif (6839 bytes)

The command 1 receives the system event as a CAA V5 notification, instance of the CATNotification class. It sends the notification to its father, the command 2, using the CATCommand's SendNotification method:

SendNotification(MyFather, Notification);

Each command knows its father by means of a pointer stored as a private data member and passed as an input parameter of the command constructor.

This command 2 is not designed to process events, that is it does not override the AnalyseNotification method. Thus the CATCommand's AnalyseNotification method is used and returns CATNotifTransmitToFather to the command 1 which then resends the notification to the command 3, father of the command 2 in the command tree structure. This command 3 is designed to process such events and overrides the AnalyseNotification method to catch that expected notification by returning CATNotifDontTransmitToFather to the sending command 1 which stops the event propagation. Otherwise, it returns CATNotifTransmitToFather, thus leaving this notification goes on propagating. Depending on what the command 3 developer intends to do, two possibilities exist:

  1. Process the notification from the end user standpoint, that is perform the user intent. To do this, the SendCommandSpecificObject method can be overridden, and used possibly several times, to query about the object(s) involved.
  2. Enrich the notification, that is creates a new notification that can be processed by another command above in the tree structure and send it to its father or directly to this specific command if it is known. The SendNotification first parameter allows for this. In this case, pay attention to a possible loop between the sending command and the target command.

If no command is found, the root command is reached. This root command, a CATCommandSelector instance, plays a specific role. When it receives a notification, meaning that no command below in the command tree structure path, from the command which first receives the event and the CATCommandSelector instance, has been able to process the event, it sends back the notification to the active dialog command. This active dialog command can then decide what to do. The figure below shows the command tree structure and the event propagation along it.

CAASysSendReceive2.gif (7287 bytes)

Once the appropriate receiving command is reached, a dialog can begin between this receiving command and the sending command, to get more information about the event, that is generally which object is concerned with the event. In its AnalyseNotification method, the receiving command requests the sending command for that object, beginning with the expected type(s). The sending command returns that object if the type is matched, or NULL otherwise. The receiving command can then loop on all the types it expects until whether an object is returned, or the type list end is reached.

The CATCommand's SendObject method is used by the receiving command against the sending command to ask for an object type, and this SendObject method calls the sending command's SendCommandSpecificObject method, if this one exists, to return the expected object, or returns NULL otherwise.

Below is an OMT-like figure that shows the main objects and methods used.

CAASysSendReceive3.gif (5131 bytes)

[Top]

What Should I Do?

As soon as you intend to create a command, you should know if your command is transparent for notifications, that is leave notifications pass through it, is a sending command, process some of the possible notifications that can reach it, and/or enrich some of them.

[Top]

My Command Is Transparent for Notifications

This is the case, for example, of some intermediate dialog objects that contains others, such as a frame in a window that contains a graphic viewer. The frame is an instance of a class which derives from CATCommand, as well as the viewer it contains, and as well as the window that contains both. The frame is there to accommodate the viewer, but has no real possibilities regarding the user intents, and is thus transparent for notifications.

In this case, you have nothing to do. The CATCommand class instance created when your command is instantiated provides your command with this transparent behavior, takes care of receiving the notifications, and replies always CATNotifTransmitToFather to the sending command.

[Top]

My Command Is a Sending Command

Your command detects a user intent, and plays the role of converting the system event into a CAA V5 notification. This notification is sent thanks to the CATCommand's method SendNotification you can use as is.

In this case, you have nothing to do. The CATCommand class instance created when your command is instantiated provides your command with this transparent behavior, takes care of receiving the notifications, and replies always CATNotifTransmitToFather to the sending command.

SendNotification(MyFather, Notification);

But this is generally not enough. If the user intent is valid in the current context, that is can be turned into a task that an available command can perform, and if this command is reached by the notification, sure this command will request more information from your sending command using the SendObject method. To reply, your sending command must override the SendCommandSpecificObject method called by the SendObject method. This method should return a pointer to the object belonging to the requested class and managed by your command, and NULL otherwise.

void * SendCommandSpecificObject(
           const char      * ClassOfExpectedObject,
           CATNotification * Notification)
{
  if (TheObjectIManage->IsAKindOf(ClassOfExpectedObject)
    return ((void *) TheObjectIManage);
  else
    return NULL;
}

Of course, you can loop on the different objects you command manages, if any.

[Top]

My Command Processes Some Notifications

Your command is there to process some user intents, and you need to code what to do when the end user asks to do what your command expects. Two ways are offered:

  1. Override the AnalyseNotification method to code or call the appropriate methods that perform the job
  2. Set a callback on notification reception, for the notification you expect, by means of the AddAnalyseNotificationCB method.

Both can be used in the same command, but not for the same notification, since the callback is searched for first.

[Top]

Overriding the AnalyseNotification Method

You simply need to catch the notifications you expect, and resend the others. A skeleton for such a overridden AnalyseNotification method could be:

CATNotifPropagationMode MyCommand::AnalyseNotification
         (CATCommand* SendingCommand,
          CATNotification* ReceivedNotification)
{
  if (ReceivedNotification->IsAKindOf(      // Catch expected notifications
                 ExpectedNotification::ClassName())
  {

  // provide here the code to process the notification
  
    return (CATNotifDontTransmitToFather);
  }
  else                                         // Resend the others
    return (CATNotifTransmitToFather);
}

In this skeleton, SendingCommand is the command that sends the notification named ReceivedNotification. If this ReceivedNotification is an instance of the ExpectedNotification class, or of one of its derived classes, then you can process ReceivedNotification, and stops the notification propagation by returning CATNotifDontTransmitToFather. Otherwise, leave the notification propagation goes on by returning CATNotifTransmitToFather.

[Top]

Setting Callbacks on Notification Reception

You can set a callback for each expected notification, for example in the command constructor, as follows:

...
AddAnalyseNotificationCB(                      // Set the callback for the
          ExpectedSendingCommand,              // expected notifications
          ExpectedNotification,
          (CATCommandMethod)&MyCommand::MethodToCallBack,
          PointerToUsefulData);
...

MyCommand::MethodToCallBack(                   // Code the callback
          CATCommand* ExpectedSendingCommand,
          CATNotification * ExpectedNotification,
          CATCommandClientData PointerToUsefulData) {

// provide here the code to process the notification

}
...

Setting a callback, and providing the method for the callback, stops the notification propagation along the command tree structure.

[Top]

Requesting an Object To Be Sent

If your command requests input from the end user, such as the object selected under the mouse, use the SendObject method to request the sending command, which should know this object, to send it to your command, as follows:

...
SendObject(ClassOfExpectedObject, Notification);
...

where ClassOfExpectedObject is the class from which the object you expect is an instance, and Notification the notification which reaches your command.

[Top]

My Command Enriches Some Notifications

You may want to add information to a received notification without processing it by your command. In this case, you can either override the AnalyseNotification method, or set a callback, as described above, but instead of processing the notification, you instantiate a new notification and you send it to the appropriate command, generally the father of your command.

The following code should then be inserted in the code skeleton above in place of the comment for processing the notification.

...
MyEnrichedNotification = new CATEnrichedNotification();
SendNotification(Father, MyEnrichedNotification);
...

[Top]

A Send/Receive Example

This example relies on the following command tree:

CAASysSendReceive4.gif (5994 bytes)

The command 1 detects an end user intent and converts it as a notification sent along the command tree structure. The command 2 is transparent for notifications, and the notification reaches the command selector which resends it to the active dialog command. This command expects such notification, and request from the sending command 1 an expected object to be sent.

The first step is for the command 1 to send the notification. This is coded as follows in the appropriate method, that is the one which turns the system event into a CAA V5 notification:

...
  CATNotification* NotifToSend = new MyNotification();
  SendNotification (GetFather(), NotifToSend);
...

The appropriate notification is instantiated, and sent to the command's father. Note that this father can be retrieved using the GetFather method.

Then the notification goes along the command tree structure. It meets the command 2 which has not overridden the AnalyseNotification method and which uses the CATCommand's AnalyseNotification method to return CATTransmitToFather to the command 1. Since this father is the command selector, the notification propagation stops and is sent by this command selector to the command 3, the active dialog command. This command has overridden the AnalyseNotification method as follows:

CATNotifPropagationMode Command3::AnalyseNotification
       (CATCommand* SendingCommand,
        CATNotification* ReceivedNotification)
{
  if (ReceivedNotification->IsAKindOf(
                 ExpectedNotification::ClassName())
  {
    ExpectedObject* TheExpectedObject = (ExpectedObject*)
    SendingCommand->SendObject(
      ExpectedObject::ClassName(), ReceivedNotification);
    if (TheExpectedObject)
      return (CATNotifDontTransmitToFather);
    else
      return (CATNotifTransmitToFather);
  }
  else
    return (CATNotifTransmitToFather);
}

The active command knows the notification it expects, and the method compares its class to the one of the received notification. If the two classes match, it creates an expected object instance and request from the sending command to such object using the SendObject method. If the expected object is returned, the method returns successfully with CATNotifDontTransmitToFather, and with CATNotifTransmitToFather otherwise.

The sending command should have overridden the SendCommandSpecificObject as follows:

void *Command1::SendCommandSpecificObject(
                  const char * ExpectedObject,
                  CATNotification* ReceivedNotification)
{
  if ( _TheHandledObject->IsAKindOf(ExpectedObject) &&
       (ReceivedNotification == _NotifSent) )
      return ((void *) _TheHandledObject);
    else
      return (NULL);
}

The SendCommandSpecificObject method has the same arguments than the SendObject method. The sending command has keep track of the notification sent, for example in the _NotifSent data member, and handles _TheHandledObject instance. If the class of which _TheHandledObject is an instance is a kind of the ExpectedObject class, that is the two classes are the same or _TheHandledObject's class derives from the ExpectedObject class, _TheHandledObject is returned, and is also returned by the calling SendObject command as TheExpectedObject pointer to the active dialog command, which can now uses it appropriately. Otherwise, NULL is returned.

[Top]


In Short

The CAA V5 commands build a tree structure whose root command is the CATCommandSelector instance. The Send/Receive communication protocol enables a notification sent by one of these commands to propagate up to the appropriate command, that is the command able to execute the job requested by the notification.

Each command on top of the sending command can in turn either participate to the notification propagation or process the notification. If the root command is reached, it sends the notification to the active command which can decide to process the notification, or to stop its propagation.

[Top]


References

[1] xxx
[Top]

History

Version: 1 [Jan 2000] Document created
[Top]

Copyright © 2000, Dassault Systèmes. All rights reserved.