3D PLM Enterprise Architecture |
Middleware Abstraction |
Sending a Backbone Data Message to an ApplicationUsing the backbone to send a message with data |
Use Case |
AbstractThis article shows how to make two applications communicate, and how one of them can send a data message, that is, a message that conveys data, to the other. |
This use case is intended to show you how an application can declare that it will send or receive messages, how to filter the messages to receive, and how to send and receive messages using the backbone objects of the System framework. The messages convey data with them. Another use case also shown by CAASysBackboneBasic uses messages that don't convey any data [1].
[Top]
CAASysBackboneBasic is a use case of the CAASystem.edu framework that illustrates the System framework capabilities.
[Top]
This use case illustrates two applications seen as processes. One behaves as a message sender, and the other as a message receiver. The message sender creates and sends a data message. The message receiver receives it, and just acknowledge receipt of it using a trace. Both the message sender and the message receiver are simple processes launched from a main program.
The message sender connects to the backbone bus, declares itself, instantiates the message component and sends it. The message receiver needs to instantiate a message handler to receive the message. Such a message handler is a component that implements the CATIMessageReceiver interface. The message receiver connects to the backbone bus, declares itself, instantiates the message handler, associates itself with the message to receive and with the message handler, enters a loop thanks to the CATICommunicator interface implemented by the backbone bus that the receiver can use to create the loop, and waits for the message. As soon as the message is sent, it is retrieved by the message handler that prints a trace to acknowledge receipt of the message.
The message is an instance of a component named CAASysDataMessage that implements the CAAISysDataRequest and CATICommMsg interfaces, among others [2].
[Top]
To launch CAASysBackboneBasic, you will need to set up the build time environment, then compile CAASysBackboneBasic along with its prerequisites, set up the run time environment [3] in two different windows, and then execute the use case.
To execute the use case, type in the first window command line:
CAASysBackboneBasic receiver
And type in the second window command line:
CAASysBackboneBasic sender
[Top]
The CAASysBackboneBasic use case is made of several classes located in the CAASysBackboneBasic.m module of the CAASystem.edu framework:
Windows | InstallRootDirectory\CAASystem.edu\CAASysBackboneBasic.m\ |
Unix | InstallRootDirectory/CAASystem.edu/CAASysBackboneBasic.m/ |
where InstallRootDirectory
is the directory where the CAA CD-ROM
is installed.
[Top]
To create applications that send and receive a data message, there are six main steps:
# |
Step |
---|---|
1 | Create the message sender |
2 | Send the message |
3 | Create the message handler component |
4 | Create the message receiver |
5 | Receive the message |
6 | Remove the message handler |
[Top]
The message sender is a process whose main program is contained in the CodeForSenderCase
global function.
int CodeForSenderCase() { // Retrieves an instance of a backbone bus (default bus) CATICommunicator * pICommunicator = NULL; pICommunicator = ::CATGetBackboneConnection(); ... // return if the backbone bus cannot be retrieved ... |
First, a connection to the backbone bus must be established. This is possible
thanks to the global function CATGetBackboneConnection
that returns
a pointer to the CATICommunicator interface.
... // Declares CAASysSenderAppli CATApplicationClass SenderApplicationId = "CAASysSenderAppli"; HRESULT rc = pICommunicator->Declare(SenderApplicationId); ... // return if the declaration fails CATApplicationClass ReceiverApplicationId = "CAASysReceiverAppli"; ... |
Once the connection is established, the message sender sets its application
class identifier and declares it to the backbone bus using the method Declare
.
[Top]
... if ( SUCCEEDED(rc) ) { CAAISysDataRequest * pIRequest = NULL; rc = ::CATInstantiateComponent("CAASysDataMessage", IID_CAAISysDataRequest, (void **)&pIRequest); if ( SUCCEEDED(rc) ) { int Nb = 2; float Radius = 1.9f; float Sags[3]; Sags[0] = 1.0f; Sags[1] = 0.5f; Sags[2] = 0.02f; pIRequest->SetData(Sags,Nb,"Red",Radius); CATICommMsg * pICommMsg =NULL; rc = pIRequest->QueryInterface(IID_CATICommMsg,(void**)&pICommMsg); if ( SUCCEEDED(rc) ) { rc = pICommunicator->SendRequest(ReceiverApplicationId, pICommMsg); pICommMsg->Release(); pICommMsg = NULL; } pIRequest->Release(); pIRequest = NULL; } } pICommunicator->Release(); pICommunicator = NULL; ... // return } |
Now, the message sender can send a message. It first creates an instance of
the message component using the CATInstantiateComponent
global
function, feeds the message with data using the SetData
method of
the CAAISysDataRequest interface, and retrieves a pointer to CATICommMsg
on the message component. Then it sends the message using the SendRequest
method of CATICommunicator, specifying the target message receiver and
the message to send.
[Top]
#include "CATBaseUnknown.h" //Needed to derive from CATBaseUnknown class CATICommMsg; class CAASysDataMessageHandler : public CATBaseUnknown { CATDeclareClass; public: CAASysDataMessageHandler(); virtual ~CAASysDataMessageHandler(); // CATIMessageReceiver Interface void HandleMessage(CATICommMsg * iMessage); private: CAASysDataMessageHandler(const CAASysDataMessageHandler &iObjectToCopy); }; |
The CAASysDataMessageHandler class belongs to a component, thanks to
the CATDeclareClass
macro, C++ derives from CATBaseUnknown,
and implements CATIMessageReceiver, whose single method is HandleMessage
.
Note that the copy constructor is set as private, and is not implemented in the
source file. This prevents the compiler from creating the copy constructor as
public without you know.
#include "CAASysDataMessageHandler.h" extern int EndConditionLoop; #include "TIE_CATIMessageReceiver.h" TIE_CATIMessageReceiver(CAASysDataMessageHandler); CATImplementClass(CAASysDataMessageHandler, Implementation, CATBaseUnknown, CATNull); CAASysDataMessageHandler::CAASysDataMessageHandler() {} CAASysDataMessageHandler::~CAASysDataMessageHandler() {} void CAASysDataMessageHandler::HandleMessage(CATICommMsg* iMessage) { if ( NULL != iMessage ) { CAAISysDataRequest * pIRequest = NULL; HRESULT hr = iMessage->QueryInterface(IID_CAAISysDataRequest,(void**) &pIRequest); if ( SUCCEEDED(hr) ) { float Radius; int Nb; float * Sags = NULL; char * Color = NULL; pIRequest->GetData(&Sags,Nb,&Color,Radius); pIRequest->Release(); pIRequest = NULL; ... // Use the data retrieved } } // The process can be stopped EndConditionLoop ++; } |
The CAASysDataMessageHandler class states that it implements the CATIMessageReceiver
interface thanks to the TIE_CATIMessageReceiver
macro. The CATImplementClass
macro declares that the CAASysDataMessageHandler class is a component
main class thanks the Implementation
keyword, and that the
component OM-derives [4] from CATBaseUnknown.
Any component main class declared as an Implementation
must
C++-derive and OM-derive from the same class. HandleMessage
is
called by the backbone bus and a pointer to the message is passed. HandleMessage
retrieves a pointer to CAASysDataRequest interface on the message, and
can then get the message data. Then, it makes the receiver get out of the loop
by incrementing EndConditionLoop
.
Top]
The message receiver is a process whose main program is contained in the CodeForReceiverCase
global function.
int CodeForReceiverCase() { int ReturnCode = 1; CATIMessageReceiver * pIMessageReceiver2 = NULL; CATApplicationClass ReceiverApplicationId = "CAASysReceiverAppli"; CATMessageClass DataMessClassName = "CAASysDataMessage"; HRESULT rc= E_FAIL; // Retrieves an instance of a backbone bus (default bus) CATICommunicator * pICommunicator = NULL; pICommunicator = ::CATGetBackboneConnection(); ... // return if the backbone bus cannot be retrieved ... // Declares CAASysReceiverAppli on the backbone bus rc = pICommunicator->Declare(ReceiverApplicationId); ... // return if the declaration fails ... |
First, a connection to the backbone bus must be established. This is possible
thanks to the global function CATGetBackboneConnection
that returns
a pointer to the CATICommunicator interface. Once the connection is
established, the message sender sets its application class identifier and
declares it to the backbone bus using the method Declare
.
... if ( SUCCEEDED(rc) ) { CAASysDataMessageHandler * pHandler = NULL; pHandler = new CAASysDataMessageHandler(); if ( NULL != pHandler ) { rc = pHandler->QueryInterface(IID_CATIMessageReceiver, (void**)&pIMessageReceiver2); if ( SUCCEEDED(rc) ) { rc=pICommunicator->AssociateHandler(ReceiverApplicationId, DataMessClassName, pIMessageReceiver2); ... // error if the association fails } pHandler->Release(); pHandler = NULL; } } ... |
The message receiver instantiates the message handler, asks the message
handler for an pointer to CATIMessageReceiver, and declares to the
backbone bus that it will receive the declared messages using the designated
handler, thanks to the AssociateHandler
method.
[Top]
Now the message receiver can create and enter a loop to wait for messages.
... if ( SUCCEEDED(rc) ) { CATICommunicatorLoop * pILoop = NULL; pICommunicator->QueryInterface(IID_CATICommunicatorLoop, (void**)&pILoop); if ( SUCCEEDED(rc) ) { EndConditionLoop = -2; pILoop->WaitingLoop(-1, 6000 , &EndConditionLoop); pILoop ->Release(); pILoop = NULL; // OK ReturnCode = 0; } } ... |
A pointer to CATICommunicatorLoop is retrieved from the backbone bus
using the pointer to CATICommunicator retrieved when establishing the
connection. Then, a loop is created by calling WaitingLoop
of CATICommunicator.
The first parameter must be set to -1, the second is the maximum waiting time
expressed in milliseconds, and the third is a flag to get out of the loop before
the time set is over. This flag must be set to a non null value. Setting it to
null makes the process get out of the loop.
[Top]
The message receiver is a process whose main program is contained in the CodeForReceiverCase
.
... if ( NULL != pIMessageReceiver2 ) { // No more need of the handler for the first event pICommunicator->RemoveHandler(ReceiverApplicationId, DataMessClassName, pIMessageReceiver2); pIMessageReceiver2->Release(); pIMessageReceiver2 = NULL; } ... if ( NULL != pICommunicator ) { pICommunicator->Release(); pICommunicator = NULL; } return ReturnCode; } |
Once a message is received, or once the time set is over, the process gets
out of the loop, removes its handler thanks to the RemoveHandler
method that uses the same arguments than the AssociatedHandler
method, and stops.
[Top]
This use case shows how two processes or applications can communicate using data messages, that is, messages that convey data.
[Top]
[1] | Sending a Simple Message to an Application |
[2] | Creating a Backbone Data Message |
[3] | Building and Launching a CAA V5 Use Case |
[4] | Object Modeler Component and Implementation Inheritance |
[Top] |
Version: 1 [Jul 2000] | Document created |
[Top] |
Copyright © 2000, Dassault Systèmes. All rights reserved.