3D PLM Enterprise Architecture

Middleware Abstraction

Sending a Backbone Simple Message to an Application

Using the backbone to send a message without data
Use Case

Abstract

This article shows how to make two applications communicate, and how one of them can send a simple message, that is, a message that doesn't convey any data, to the other.


What You Will Learn With This Use Case

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 don't convey any data with them. Another use case also shown by CAASysBackboneBasic uses messages that convey data [1].

[Top]

The CAASysBackboneBasic Use Case

CAASysBackboneBasic is a use case of the CAASystem.edu framework that illustrates the System framework capabilities.

[Top]

What Does CAASysBackboneBasic Do

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 simple 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, and 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 CAASysSimpleMessage that implements the CATICommMsg interface, among others [2].

[Top]

How to Launch CAASysBackboneBasic

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]

Where to Find the CAASysBackboneBasic Code

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]

Step-by-Step

To create applications that send and receive a simple 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]

Creating the Message Sender

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]

Sending the Message

  ...
  if ( SUCCEEDED(rc) )
  {
    CATICommMsg * pICommMsg =NULL;  
    rc = ::CATInstantiateComponent("CAASysSimpleMessage",
                                   IID_CATICommMsg,
                                   (void**)&pICommMsg);
    if ( SUCCEEDED(rc) )
    {
      rc = pICommunicator->SendRequest(ReceiverApplicationId, pICommMsg);
      pICommMsg->Release();
      pICommMsg = NULL;
    }
  }
  pICommunicator->Release();
  pICommunicator = NULL;
  ... // return
}

Now, the message sender can send a message. It first creates an instance of the message component and retrieves a pointer to CATICommMsg on the message component  thanks to the CATCreateClassInstance global function. Then it sends the message using the SendRequest method of CATICommunicator, specifying the target message receiver and the message to send.

[Top]

Creating the Message Handler

#include "CATBaseUnknown.h"   //Needed to derive from CATBaseUnknown

class CATICommMsg;

class  CAASysSimpleMessageHandler : public CATBaseUnknown
{
  CATDeclareClass;
  public:
    CAASysSimpleMessageHandler();
    virtual ~CAASysSimpleMessageHandler();

    // CATIMessageReceiver Interface
    void HandleMessage(CATICommMsg * iMessage);

  private:
    CAASysSimpleMessageHandler(const CAASysSimpleMessageHandler &iObjectToCopy);
};

The CAASysSimpleMessageHandler 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 "CAASysSimpleMessageHandler.h"

extern int EndConditionLoop;

#include "TIE_CATIMessageReceiver.h"
TIE_CATIMessageReceiver(CAASysSimpleMessageHandler);

CATImplementClass(CAASysSimpleMessageHandler, Implementation, CATBaseUnknown, CATNull);

CAASysSimpleMessageHandler::CAASysSimpleMessageHandler() {}

CAASysSimpleMessageHandler::~CAASysSimpleMessageHandler() {}

void CAASysSimpleMessageHandler::HandleMessage(CATICommMsg* iMessage)
{
  // The process can be stopped
  EndConditionLoop ++;
}

The CAASysSimpleMessageHandler class states that it implements the CATIMessageReceiver interface thanks to the TIE_CATIMessageReceiver macro. The CATImplementClass macro declares that the CAASysSimpleMessageHandler 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 needs only a simple implementation. It is called by the backbone bus and a pointer to the message is passed. The action undertaken is to simply to make the receiver get out of the loop by incrementing EndConditionLoop.

Top]

Creating the Message Receiver

The message receiver is a process whose main program is contained in the CodeForReceiverCase global function.

int CodeForReceiverCase()
{
  int ReturnCode = 1;

  CATIMessageReceiver        * pIMessageReceiver  = NULL;
  CATApplicationClass ReceiverApplicationId   = "CAASysReceiverAppli";
  CATMessageClass     SimpleMessClassName     = "CAASysSimpleMessage";
  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) )
  {
    CAASysSimpleMessageHandler * pHandler  = NULL;
    pHandler = new  CAASysSimpleMessageHandler();

    if ( NULL != pHandler )
    {
      rc = pHandler->QueryInterface(IID_CATIMessageReceiver,
                                    (void**)&pIMessageReceiver);
      if ( SUCCEEDED(rc) )
      {
        rc=pICommunicator->AssociateHandler(ReceiverApplicationId, 
                                            SimpleMessClassName,
                                            pIMessageReceiver);
        ... // 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]

Receiving the Message

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]

Removing the Message Handler

  ...
  if ( NULL != pIMessageReceiver )
  {
    // No more need of the handler for the first event
    pICommunicator->RemoveHandler(ReceiverApplicationId,
                                  SimpleMessClassName,
                                  pIMessageReceiver);
    pIMessageReceiver->Release();
    pIMessageReceiver = 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]


In Short

This use case shows how two processes or applications can communicate using simple messages, that is, messages that don't convey any data.

[Top]


References

[1] Sending a Data Message to an Application
[2] Creating a Backbone Simple Message
[3] Building and Launching a CAA V5 Use Case
[4] Object Modeler Component and Implementation Inheritance
[Top]

History

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

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