skip to main content
OpenEdge Development: AppBuilder
Data-Communication Objects : The message-handling relationship: internal details
 
The message-handling relationship: internal details
The process for handling a message is very much the same regardless of whether the message is coming in or going out.
Outbound message and reply-handling process
Sending a message requires cooperation between the SmartProducer and an object serving as the OUTMESSAGE-SOURCE (OMS). Generally you would use either a SmartB2BObject or a SmartSender as OMS. Figure 46 illustrates the process.
Figure 46: Outbound message-handling process
The following steps describe the process shown in Figure 46.
1. When a message is to be sent, the OMS calls sendMessage in the SmartProducer.
2. The sendMessage() routine in the SmartProducer creates an empty message. It then calls sendHandler() in the OMS, passing the handle of the message it created.
3. The sendHandler() routine in the OMS sets the message header properties, adds a body to the message, and returns.
4. The sendMessage() routine in the SmartProducer now has a complete message to send and calls the relevant routines in the ABL-JMS API to start the message on its way.
5. When a reply comes in, replyHandler() in the SmartProducer calls replyHandler() in the OMS, passing it the handle of the reply.
6. The replyHandler() routine in the OMS gets the ID of the original message and the reply properties and body. It performs any desired processing on that information and returns.
Inbound message-handling and reply process
Receiving a message requires cooperation between the SmartConsumer and an object serving as the INMESSAGE-TARGET (IMT). Generally you would use either a SmartB2BObject or a SmartReceiver as IMT. Figure 47 illustrates this process.
Figure 47: Inbound message-handling process
If you use a SmartRouter to distribute incoming messages, the SmartRouter acts as an IMT proxy, accepting calls from the SmartConsumer and passing them on transparently to the real IMT. The brief description below ignores the role of the SmartRouter:
1. When a message is received, the messageHandler() routine in the SmartConsumer calls the receiveHandler() routine in the IMT, passing the handle of the received message.
2. The receiveHandler() routine in the IMT extracts header properties and the message body, performs any desired processing, and returns.
3. If the message requires a reply, the messageHandler() routine in the SmartConsumer creates an empty reply message and calls sendReplyHandler() in the IMT, passing the handle of the reply it created.
4. The sendReplyHandler() routine in the IMT sets the header properties, adds a body, and returns.
5. The messageHandler() routine in the SmartConsumer now has a complete reply message to send and calls the relevant routines in the ABL-JMS API to start it on its way.
Example of sendHandler code
The following code might be used to create a large text message in a SmartSender:
 
/* Declare a handle for the message */
DEFINE INPUT PARAMETER hMessage AS HANDLE NO-UNDO.
 
/* Set the message properties */
DYNAMIC-FUNCTION( ‘setBooleanProperty’:U IN hMessage,
  INPUT ‘backordered’:U, INPUT TRUE ).
DYNAMIC-FUNCTION( ‘setDoubleProperty’:U IN hMessage,
  INPUT ‘minorderamount’:U, INPUT 1500.00 ).
 
/* Append text blocks from tables to create message body */
FOR EACH table:
  DYNAMIC-FUNCTION( ‘appendText’:U IN hMessage, table.datafield ).
END.
Example of sendHandler override code
The following code might be used in a sendHandler() override in a SmartB2BObject:
 
DEFINE INPUT PARAMETER hMessage AS HANDLE NO-UNDO.
 
/* Set custom message properties (example only) */
DYNAMIC-FUNCTION('setStringProperty':U IN hMessage,
  INPUT 'city':U, INPUT cCity).
 
/* Run the SmartB2BObject's version of sendHandler to assign the body of the
   message. */
RUN SUPER.
Example of receiveReplyHandler code
Any object that acts as an OUTMESSAGE-SOURCE to a SmartProducer must include a receiveReplyHandler() procedure. That procedure handles replies from message recipients. It might perform some or all of these functions:
*Identify the original message.
*Extract any important properties from the reply.
*Identify the reply type and obtain the reply body in an appropriate format.
Example 1 shows code that performs those functions for some OUTMESSAGE-SOURCE object other than a SmartB2BObject, for example a SmartSender.
 
Example 1: receiveReplyHandler code
DEFINE INPUT PARAMETER hReply AS HANDLE NO-UNDO.
 
/* Declare storage for obtaining the properties */
DEFINE VARAIBLE cCharProp      AS CHARACTER NO-UNDO.
DEFINE VARIABLE cOriginalMsgID AS CHARACTER NO-UNDO.
DEFINE VARIABLE cProperty      AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPropertyNames AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPropType      AS CHARACTER NO-UNDO.
DEFINE VARIABLE cReplyType     AS CHARACTER NO-UNDO.
DEFINE VARIABLE fDecProp       AS DECIMAL   NO-UNDO.
DEFINE VARIABLE iIntProp       AS INTEGER   NO-UNDO.
DEFINE VARIABLE iThisProp      AS INTEGER   NO-UNDO.
DEFINE VARIABLE lLogicProp     AS LOGICAL   NO-UNDO.
DEFINE VARIABLE mReplyBody     AS MEMPTR    NO-UNDO.
 
/* Identify the original message using the reply handle, get property names */
cOriginalMsgID = DYNAMIC-FUNCTION('getJMSCorrelationID':U IN hReply).
cPropertyNames = DYNAMIC-FUNCTION(‘getPropertyNames’:U IN hReply).
 
/* Loop through all properties, extracting their values according to type */
DO iThisProp = 1 TO NUM-ENTRIES(cPropertyNames):
  ASSIGN
    cProperty = ENTRY(iThisProp, cPropertyNames)
    cPropType = DYNAMIC-FUNCTION(‘getPropertyType’:U IN hReply, 
                  INPUT cProperty).
 
  CASE cPropType:
    WHEN ‘String’:U THEN DO:
      cCharProp = DYNAMIC-FUNCTION(‘getCharProperty’:U IN hReply, 
                    INPUT cProperty).
    /* Insert code here to process this character property */
    END. 
 
    WHEN ‘Boolean’:U THEN DO:
      lLogicProp = DYNAMIC-FUNCTION(‘getLogicalProperty’:U IN hReply,
                     INPUT cProperty).
    /* Insert code here to process this logical property */
    END.
    WHEN ‘Byte’:U OR WHEN ’Short’ OR WHEN ‘Int’ THEN DO:
      iIntProp = DYNAMIC-FUNCTION(‘getIntProperty’:U IN hReply, 
                   INPUT cProperty).
      /* Insert code here to process this integer property */
    END.
    WHEN ‘Long’:U OR WHEN ’Float’ OR WHEN ‘Double’ THEN DO:
      fDecProp = DYNAMIC-FUNCTION(‘getDecProperty’:U IN hReply, 
                   INPUT cProperty).
      /* Insert code here to process this decimal property */
    END.
  END CASE. /* cPropType */
END. /* DO iThisProp */
 
/* Identify the reply type */
cReplyType = DYNAMIC-FUNCTION(‘getMessageType’:U IN hReply).
 
/* Extract the reply body in the appropriate format. */
CASE cReplyType:
  WHEN ‘BytesMessage’:U THEN
    mReplyBody = DYNAMIC-FUNCTION(‘getMemptr’:U IN hReply).
  WHEN ‘TextMessage’:U OR WHEN ‘XMLMessage’:U THEN DO:
    DO WHILE (DYNAMIC-FUNCTION(‘endOfStream’:U IN hReply) = FALSE:
      cReplyBody = DYNAMIC-FUNCTION(‘getTextSegment’:U IN hReply).
 
      /* Insert code here to put returned text segments into a form, such as
         temp-table records, that can be read by the routine that will process
         the body of this reply.*/
    END. /* DO WHILE */
  END. /* WHEN textmessage */
END CASE. /* cReplyType */
Example of receiveHandler code
Example 2 shows code that might be used in an INMESSAGE-TARGET object other than a SmartB2BObject, for example a SmartReceiver. Note the similarities to the receiveReplyHandler code:
 
Example 2: receiveHandler code
DEFINE INPUT PARAMETER hMessage AS HANDLE NO-UNDO.
 
/* Declare storage */
DEFINE VARAIBLE cCharProp      AS CHARACTER NO-UNDO.
DEFINE VARIABLE cMessageID     AS CHARACTER NO-UNDO.
DEFINE VARIABLE cMessageType   AS CHARACTER NO-UNDO.
DEFINE VARIABLE cProperty      AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPropertyNames AS CHARACTER NO-UNDO.
DEFINE VARIABLE cPropType      AS CHARACTER NO-UNDO.
DEFINE VARIABLE fDecProp       AS DECIMAL   NO-UNDO.
DEFINE VARIABLE iIntProp       AS INTEGER   NO-UNDO.
DEFINE VARIABLE iThisProp      AS INTEGER   NO-UNDO.
DEFINE VARIABLE lLogicProp     AS LOGICAL   NO-UNDO.
DEFINE VARIABLE mMessageBody   AS MEMPTR    NO-UNDO.
 
/* Loop through all properties, identifying types and extracting values
   appropriately. */
cPropertyNames = DYNAMIC-FUNCTION(‘getPropertyNames’:U IN hMessage).
 
DO iThisProp = 1 TO NUM-ENTRIES(cPropertyNames):
  ASSIGN
    cProperty = ENTRY(iThisProp, cPropertyNames)
    cPropType = DYNAMIC-FUNCTION(‘getPropertyType’:U IN hMessage,
                  INPUT cProperty).
 
  CASE cPropType:
    WHEN ‘String’:U THEN DO:
      cCharProp = DYNAMIC-FUNCTION(‘getCharProperty’:U IN hMessage, 
                    INPUT cProperty).
      /* Insert code for processing a string property */
    END.
  
    WHEN ‘Boolean’:U THEN DO:
      lLogicProp = DYNAMIC-FUNCTION(‘getLogicalProperty’:U IN hMessage, 
                     INPUT cProperty).
      /* Insert code for processing a logical property */
    END.
  
    WHEN ‘Byte’:U OR WHEN ‘Short’:U OR WHEN ‘Int’:U THEN DO:
      iIntProp = DYNAMIC-FUNCTION(‘getIntProperty’:U IN hMessage,
                   INPUT cProperty).
      /* Insert code for processing an integer property */
    END.
    WHEN ‘Long’:U OR WHEN ‘Float’:U OR WHEN ‘Double’:U THEN DO:
      fValue = DYNAMIC-FUNCTION(‘getDecProperty’:U IN hMessage,
                 INPUT cProperty).
      /* Insert code for processing a decimal property */
    END. /* Long, Float, Double */
  END. /* CASE cPropType */
END. /* DO iThisProp */
 
/* Determine message type; extract body appropriately */
cMessageType = DYNAMIC-FUNCTION(‘getMessageType’:U IN hMessage).
 
CASE cMessageType:
  WHEN ‘BytesMessage’:U THEN
    mMessageBody = DYNAMIC-FUNCTION(‘getMemptr’:U IN hMessage).
 
  WHEN ‘TextMessage’:U OR WHEN ‘XMLMessage’:U THEN DO:
    DO WHILE (DYNAMIC-FUNCTION(‘endOfStream’:U IN hMessage) = FALSE:
      cMessageBody = DYNAMIC-FUNCTION(‘getTextSegment’:U IN hMessage).
 
      /* Insert code here to put extracted text segments into a form, such as
         temp-table records, that can be read by the routine that will process
         the body of this message. */
    END. /* DO WHILE */
  END. /* WHEN textmessage */
END CASE. /* cMessageType */
Example of receiveHandler override code
The following code might be used in a receiveHandler override in a SmartB2BObject:
 
DEFINE INPUT PARAMETER hMessage AS HANDLE NO-UNDO.
 
/* Declare storage */
DEFINE VARIABLE lBackOrdered AS LOGICAL NO-UNDO.
 
/* Get a specific property value */
lBackOrdered = DYNAMIC-FUNCTION(‘getCharProperty’:U IN hMessage).
 
RUN SUPER.
Example of sendReplyHandler code
The following code might be used in the sendReplyHandler procedure of some INMESSAGE-TARGET object other than a SmartB2BObject, for example a SmartReceiver:
 
DEFINE INPUT PARAMETER hReplyMessage AS HANDLE NO-UNDO.
 
/* Set message properties */
DYNAMIC-FUNCTION(‘setBooleanProperty’:U IN hMessage,
  INPUT ‘backordered’:U, INPUT TRUE).
DYNAMIC-FUNCTION(‘setDoubleProperty’:U IN hMessage,
  INPUT ‘minorderamount’:U, INPUT 1500.00).
 
/* Assign the message body */
RUN setMemptr IN hReplyMessage
  (INPUT mMessage, INPUT 1, INPUT 200).
Example ofsendReplyHandler override code
The following code might be used in a SmartB2BObject’s sendReplyHandler override:
 
DEFINE INPUT PARAMETER hReplyMessage AS HANDLE NO-UNDO.
 
/* Set custom message properties */
DYNAMIC-FUNCTION(‘setStringProperty’:U IN hMessage,
  INPUT ‘city’:U, INPUT cCity).
 
/* Run the SmartB2BObject’s version of sendReplyHandler to assign the body of
   the message. */
RUN SUPER.