Generating and Sending Messages

This section provides an overview of outbound messaging and discusses how to:

  • Handle outbound asynchronous message transmission.

  • Handle outbound asynchronous request/response message transmission.

  • Handle outbound synchronous message transmission.

  • Read exceptions for outbound synchronous integrations.

  • Handle cookies in messages.

Successful outbound messaging relies on sending messages in the proper order and on testing the messages. Messages containing non-XML data have special considerations.

Message Order

PeopleSoft Integration Broker guarantees that messages are delivered in the order in which you send them and that they are single-threaded at the PeopleSoft receiving node. However, message order is not part of the queue definition. You must send messages in the proper order.

Note: You can modify this behavior by using queue partitioning.

See Applying Queue Partitioning.

Message Testing

Make sure that you adequately unit-test and system-test your messages.

Unit-test a message by triggering the PeopleCode that sends the message and then view the message details in Service Operations Monitor. From the Service Operations Monitor, you can view the contents of each field to verify that the message data is formatted correctly.

See the product documentation for Integration Broker Service Operations Monitor.

You can also test handler code using the Handler Tester utility. See the product documentation for Integration Broker Testing Utilities and Tools for more information.

Message Class Outbound PeopleCode

Use the record class SelectByKey method whenever possible to get data that isn’t in the component buffer.

If the record names are the same, use the standard record methods, such as SelectByKey, Insert, and Update, on the message records.

There are no automatic checks for message size. You must do it programmatically. Use the following code at level 0 to control message size when dealing with multiple transactions:

If &Msg.Size > %MaxMessageSize

Note: The OnRouteSend method enables you to apply PeopleCode that filters the destination nodes.

See Understanding Record Class.

Non-XML Data

If you’re generating a non-XML outbound message, it’s up to you to insert the message content into a special XML section containing a CDATA tag:

<xml psnonxml="yes">
  <![CDATA[nonXML_message_data]]>

Outbound Messaging and Global Variables

When you invoke a SyncRequest method the system clears any declared global variables after OnRouteSend or OnSend PeopleCode events are fired. If a component attempts to access any of the global variables after the SyncRequest method, a context error occurs.

OnRouteSend and OnSend events are primarily used for asynchronous messaging, however they can be use for synchronous messages.

To avoid context errors when using OnRouteSend or OnSend events for synchronous messaging, following these guidelines:

  1. Do not use global variables.

  2. If you must use global variables, save them as temporary variables prior to executing a SyncRequest event, then after the event is fired re-assign them back to the globals.

  3. Run OnRouteSend or OnSend logic prior to the SyncRequest and after the node is obtained use sender-specific routing. In sender-specific routing you pass the node as part of the SyncRequest call. This will send the request to the node as long as there is an active routing. Any connector overrides can be performed prior to the SyncRequest call and set on the message.

To send a message asynchronously, use the IntBroker class Publish method in:

  • A record field PeopleCode event.

  • A component PeopleCode event.

    When publishing from a component, publish messages only from the SavePostChange event, using the deferred mode property.

  • An Application Engine program.

  • An implementation of the OnNotify method.

  • An implementation of the OnRequest method .

    The OnRequest service operation event is triggered only when an inbound transaction occurs. However, when the receiving PeopleCode runs, the program can also send messages.

Message Class Outbound Asynchronous Example

The following example uses the Publish method in the PeopleCode IntBroker class:

Local Message &MSG;
Local Rowset &SALES_ORDER, &RS;

 /*Get a pointer to the component buffer rowset */
&SALES_ORDER = GetLevel0();
/*Create an instance of the SALES_ORDER_ASYNC message object */
&MSG = CreateMessage(OPERATION.SALES_ORDER_ASYNC);

/*Copy the rows from the rowset to the message object */
&MSG.CopyRowset(&SALES_ORDER);
/*Send the message */
%IntBroker.Publish(&MSG);

XmlDoc Class Outbound Asynchronous Example

The following example uses the Publish method:

Local XmlDoc &xmlRequestDoc;
Local Message &MSG;

/*Create an XmlDoc Object */
&xmlRequestDoc = CreateXmlDoc();

/* Parse a URL or input XML file into an XmlDoc */

&bool = &xmlRequestDoc.ParseXmlFrom URL("C:\pt\appserv\files\
input.xml");

/* Populate message with XML data */
&MSG = CreateMessage(OPERATION.XmlRequest);

&MSG.SetXmlDoc(&xmlRequestDoc);

/* Sent request */

%IntBroker.Publish(&MSG);

Identifying SOAP Faults

You can implement the OnAckReceive method to access IBInfo data. This enables you to read the content of acknowledgements returned by recipient systems of asynchronous SOAP messages. The ability to access acknowledgement content is useful when sending SOAP messages, since although there may be no HTTP protocol errors while sending them, SOAP faults may occur.

If the message is nonrowset-based, use the message class GetXmlDoc method to get the response data. This returns an XmlDoc object.

If the message is rowset-based, use the message class GenXMLString method to get the response data. This returns a string object which you can load into an XmlDoc object.

If SOAP faults are found, you can set the status equal to Error so that the errors appear in the Service Operations Monitor for the publication contract.

The following code example shows how to use GetXmlDoc and GenXMLString in an implementation of the OnAckReceive method. Valid status overrides are %Operation_Done, %Operation_Error, and %Operation_Retry:

import PS_PT:Integration:IReceiver;

class AckReceiveHandler implements PS_PT:Integration:IReceiver
   method AckReceiveHandler();
   method OnAckReceive(&_MSG As Message) Returns integer;
end-class;

/* constructor */
method AckReceiveHandler
end-method;

method OnAckReceive
   /+ &_MSG as Message +/
   /+ Returns Integer +/
   /+ Extends/implements PS_PT:Integration:IReceiver.OnAckReceive +/
   /* Variable Declaration */
   
If &MSG.IsStructure Then 

/* if message is rowset-based */
&str = &MSG.GenXMLString();

Else
/* if message is nonrowset-based */
&xmldoc = &MSG.GetXmlDoc();

End-If;

 Return (%Operation_Done);

end-method;

You can also implement the OnAckReceive method to read response content data returned from third-party systems when using the HTTP target connector.

To transmit an outbound asynchronous request/response message, send the message asynchronously using the Publish method.

See Handling Outbound Asynchronous Message Transmission.

Use the IntBroker class SyncRequest method for handling outbound synchronous transfers. To send a message synchronously, you can employ SyncRequest in:

  • The record field SavePreChange PeopleCode event.

  • The record field SavePostChange PeopleCode event.

  • The record field Workflow PeopleCode event.

  • The record field FieldChange PeopleCode event.

  • An implementation of the OnRequest method.

  • An implementation of the OnNotify method.

Note: The OnRequest and OnNotify events are triggered only when an inbound transaction occurs, however, when the receiving PeopleCode runs, it can also send messages.

The response message that is returned from an outbound synchronous transaction is no different from an inbound request message. Once you have it in a Message, XmlDoc, or SoapDoc object, it has the same properties as any other object of that type and can, therefore, be treated exactly the same way.

See Receiving and Processing Messages.

Message Class Outbound Synchronous Example 1

The following example uses the IntBroker class SyncRequest method:

Local Message &MSG, &response;
Local Rowset &SALES_ORDER;
 
&SALES_ORDER = GetLevel0();
&MSG = CreateMessage(OPERATION.SALES_ORDER_SYNC);
&MSG.CopyRowsetDelta(&SALES_ORDER);
 
/* send the synchronous request; the return value is the response 
message object */
&response = %IntBroker.SyncRequest(&MSG);
 
/* check the response status; 0 means OK */
If (&response.ResponseStatus = 0) Then
  /* process the response */
  MY_SALES_ORDER_SYNC.ORDER_ID = &response.GetRowset().GetRow(1)
.GetRecord(Record.SO_RESPONSE).GetField(Field.ORDER_ID).Value);
else
 
  /* do error handling */
 
End-If;

Message Class Outbound Synchronous Example 2

The following example shows the use of CopyTo to get the data back from the response and into the component buffer, and therefore the page:

Local Message &msgZipRequest, &msgZipResponse;
Local Rowset &RS, &rsMessageRowset;


&RS = GetLevel0();
&msgZipRequest = CreateMessage(OPERATION.ZIP_REQUEST);
&msgZipRequest.CopyRowset(&RS);
/* send the synchronous request; the return value is the response 
message object */

&msgZipResponse = %IntBroker.SyncRequest(&msgZipRequest,
Node.ZIPTOCITYANDSTATE);

/* check the response status; 0 means OK */
If (&msgZipResponse.ResponseStatus = 0) Then
   /* process the response */
   &rsMessageRowset = &msgZipResponse.GetRowset();
   &rsMessageRowset.CopyTo(&RS);
else
   /* do error handling */
End-If;

XmlDoc Class Outbound Synchronous Example

The following example uses the IntBroker class SyncRequest method:

Local Message &MSG, &RESP_MSG;
Local XmlDoc &flightplan_xmldoc, &xmldocReturn;
Local XmlNode &ac_number, &msi_sensor, &ofp;

&flightplan_xmldoc = CreateXmlDoc("");

&ac_number = &flightplan_xmldoc.CreateDocumentElement("flightplan");

&msi_sensor = &ac_number.AddElement("msi_sensor");
&msi_sensor.NodeValue = "flir";
&ofp = &ac_number.AddElement("ofp");
&ofp.NodeValue = "8.44";

&MSG = CreateMessage(Message.SYNC_REQUEST_EXAMPLE);

&MSG.SetXmlDoc(&flightplan_xmldoc);

&RESP_MSG = &MSG.SyncRequest();

&xmldocReturn = &RESP_MSG.GetXmlDoc();

&return_data = &xmldocReturn.GenXmlString();

The Routing – Routings Definition page features a User Exception check box that enables you to capture Integration Broker exceptions for outbound synchronous integrations using PeopleCode.

Note: Do not use Try/Catch PeopleCode to attempt to read exceptions on outbound SyncRequest calls.

The following code example shows how to read captured exceptions:

&Return_MSG = %IntBroker.SyncRequest(&MSG);
If &Return_MSG.ResponseStatus = %IB_Status_Success Then

/* process the response message */
 &RS = &MSG.GetPartRowset();
        
Else

 /* evauate the error and either throw a PeopleCode exception or continue    processing */
   &error_string = &Return_MSG.IBException.ToString());
   &nErrorMsgNumber = &Return_MSG.IBException.MessageNumber;
   &nErrorMsgSetNumber = &Return_MSG.IBException.MessageSetNumber;

End-If;

For long-running outbound synchronous transactions, you can override the default timeout period the transaction at runtime using the SyncServiceTimeout property. The default synchronous timeout period is five minutes.

The HTTP header file is modified to take this parameter. The value you set is sent to the integration gateway where it is used for the HTTP timeout.

The SyncServiceTimeout property takes a time (in seconds). The property is read-write.

The following code example shows how to use the property. To use this property, note that you must override and setup the target connector properties for the transaction. As the example demonstrates, there are helper methods that load properties based on node or transaction.

&MSG.SetXmlDoc(&xmlReq);
&MSG.IBInfo.LoadConnectorPropFromNode(Node.EAI);
&MSG.IBInfo.SyncServiceTimeout = 360000;
&MSG.IBInfo.ConnectorOverride = True;
&MSG_Resp = %IntBroker.SyncRequest(&MSG, Node.EAI);
&xmlResponseDoc = &MSG_Resp.GetXmlDoc();

PeopleSoft Integration Broker provides basic cookie handling for exchanges that are initiated by your PeopleSoft application. You can accept a synchronous response message containing cookies, save those cookies in a global variable, and later return them to the remote node in an outbound synchronous or asynchronous request message. This is a typical application of cookies in a web interaction.

Cookies are implemented as an IBInfo class property, Cookies. You can access this property only in an inbound synchronous response message or an outbound request message.

Receiving Cookies Example

The following example retains the cookies from a response message to a global variable:

Local Message &SalesRequest, &SalesResponse;
Local Rowset &SALES_ORDER;
Global string &SalesCookies;
 
&SALES_ORDER = GetLevel0();
&SalesRequest = CreateMessage(OPERATION.SALES_ORDER_SYNC);
&SalesRequest.CopyRowsetDelta(&SALES_ORDER);
 
/* Send the synchronous request; the return value is the response 
message object */
&SalesResponse = %IntBroker.SyncRequest(&SalesRequest);
 
/* Retrieve cookies from the response message */
&SalesCookies = &SalesResponse.IBInfo.IBConnectorInfo.Cookies;

Returning Cookies Example

The following example retrieves the previously retained cookies from the global variable and inserts them into a new request message:

Local Message &SalesRequest, &SalesResponse;
Local Rowset &SALES_ORDER;
Global string &SalesCookies;
 
&SALES_ORDER = GetLevel0();
&SalesRequest = CreateMessage(OPERATION.SALES_ORDER_SYNC);
&SalesRequest.CopyRowsetDelta(&SALES_ORDER);
 
/* Insert the cookies in the request message */
&SalesRequest.IBInfo.IBConnectorInfo.Cookies = &SalesCookies;
 
/* Send the asynchronous request */
%IntBroker.Publish(&SalesRequest);

PeopleSoft Integration Broker enables you to dynamically override target connector properties at runtime that have previously been set at the node, connector and transaction levels. To set or override target connectors at runtime, use the PeopleCode IBInfo object, the Connector Info object and implement the OnRequestSend method.

Note: Properties set at the PeopleCode level take precedence over those set at the node, connector and routing level.

Field or Control

Definition

IBInfo object

An IBInfo object is instantiated from a message object.

You can use this object in publishing or synchronous request PeopleCode. You can also use it in your implementation of the OnRequestSend method.

ConnectorInfo object

A ConnectorInfo object is instantiated from an IBInfo object. Use this object for reading and writing connector name/value pair information to and from the IBRequest.

You can use this object in publishing or synchronous request PeopleCode. You can also use it in your implementation of the OnRequestSend method.

OnRequestSend Method

The OnRequestSend method is included in the ISend application class. Use your implementation of this method to override target connector properties at runtime for a subscribing node transaction.

This event associated with the service operation executes before any transformations are processed.

You can use this event for asynchronous and synchronous messages.

Since data is always carried with the message, you can use the IBInfo object, ConnectorInfo object and your implementation of the OnRequestSend method to populate connector information in the publishing PeopleCode and then override it for a specific node.

Setting and Overriding Target Connector Properties Using the OnRequestSend Method

You can use implement the OnRequestSend method to override IBInfo and connector properties at runtime for a subscribing node transaction.

Any content data that is changed on the message or XMLDoc is sent to the subscribing node or used within a transformation.

To override the properties of a target connector, you must set the following statement to true:

&MSG.IBInfo.ConnectorOverride=true

If a publication contract fails as a result of using an implementation of the OnRequestSend method to override connector properties at runtime, correct the PeopleCode in your implementation and resubmit the message.

Example: Setting Target Connector Properties Using the OnRequestSend Method

The following example shows loading all connectors that exist for the node and adding one additional property, FileName.

import PS_PT:Integration:ISend;

class SendHandler implements PS_PT:Integration:ISend
   method SendHandler();
   method OnRequestSend(&Msg As Message) Returns Message;
end-class;

/* constructor */
method SendHandler
end-method;

method OnRequestSend
   /+ &MSG as Message +/
   /+ Returns Message +/
   /+ Extends/implements PS_PT:Integration:ISend.OnRequestSend +/
   /* Variable Declaration */
   Local Any &Bo;
   Local Message &Msg;
   
&Bo = &MSG.IBInfo.LoadConnectorPropFromNode("nodename");

&Bo = &MSG.IBInfo.IBConnectorInfo.AddConnectorProperties 
      ("FileName", "temp", %Property);
&MSG.IBInfo.ConnectorOverride = True;

Return (&Msg);
   
end-method;

Example: Overriding Connector Properties Using the OnRequestSend Method

The following example demonstrates overriding target connector properties using an implementation of the OnRequestSend method for a rowset-based asynchronous message.


import PS_PT:Integration:ISend;

class SendHandler implements PS_PT:Integration:ISend
   method SendHandler();
   method OnRequestSend(&Msg As Message) Returns Message;
end-class;

/* constructor */
method SendHandler
end-method;

method OnRequestSend
   /+ &MSG as Message +/
   /+ Returns Message +/
   /+ Extends/implements PS_PT:Integration:ISend.OnRequestSend +/
   /* Variable Declaration */
Local Boolean &bRet;


&bRet= &MSG.IBInfo.LoadConnectorProp("FILEOUTPUT"); 
&MSG.IBInfo.ConnectorOverride = True;  
&bRet= &MSG.IBInfo.IBConnectorInfo.AddConnectorProperties
      ("sendUncompressed", "Y", %Header);
&bRet= &MSG.IBInfo.IBConnectorInfo.AddConnectorProperties
      ("FilePath", "c:\temp", %Property);

Return (&Msg);

End-Method;

The following example demonstrates overriding target connector properties using an implementation of the OnRequestSend method for a nonrowset-based asynchronous message.

import PS_PT:Integration:ISend;

class SendHandler implements PS_PT:Integration:ISend
   method SendHandler();
   method OnRequestSend(&Msg As Message) Returns Message;
end-class;

/* constructor */
method SendHandler
end-method;

method OnRequestSend
   /+ &MSG as Message +/
   /+ Returns Message +/
   /+ Extends/implements PS_PT:Integration:ISend.OnRequestSend +/
   /* Variable Declaration */

Local XmlDoc &xmldoc;
Local Boolean &bRet;


// if you have to access the content data for content based 
// decisions, do this
&xmldoc = &MSG.GetXmlDoc();

&bRet= &MSG.IBInfo.LoadConnectorProp("FILEOUTPUT"); 
&MSG.IBInfo.ConnectorOverride = True;  
&bRet= &MSG.IBInfo.IBConnectorInfo.AddConnectorProperties 
      ("sendUncompressed", "Y", %Header);
&bRet= &MSG.IBInfo.IBConnectorInfo.AddConnectorProperties 
      ("FilePath", "c:\temp", %Property);

Return (&MSG);

End-Method;