Sending and Receiving Messages

This chapter discusses how to:

Click to jump to parent topicUnderstanding Sending and Receiving Messages

To send and receive messages you use PeopleCode to:

Note. You can also send messages directly to the integration gateway, thereby bypassing processing on the integration engine.

Click to jump to top of pageClick to jump to parent topicPrerequisites for Sending and Receiving Messages

Before you can define PeopleCode to generate, send, receive, and process messages, you must define the message in PeopleSoft Internet Architecture.

Note. Once you create PeopleCode, you must also define nodes, services and service operations to implement a complete integration.

See Understanding PeopleSoft Integration Broker Metadata.

Click to jump to top of pageClick to jump to parent topicMessaging Process Flows

The integration engine uses asynchronous request processes and synchronous request processes to manage outbound and inbound messages. These processes examine the messaging elements that you create to determine how to treat each message.

Outbound Message Processing Flow

This section discusses message processing flow for outbound messages. In this section, the term process is used, and refers to either the integration engine's asynchronous request process or its synchronous request process, depending on the type of integration you are preforming.

Outbound messages you send go through the following steps.

  1. The application triggers the sending PeopleCode that you developed.

  2. The PeopleCode program populates and sends the message by using an asynchronous or synchronous method.

  3. The method that the PeopleCode uses to send the message triggers a request process in the application’s integration engine.

  4. The process searches the outbound routings that are associated with that service operation to determine the valid target nodes for the message.

    The asynchronous process examines only asynchronous routings, and the synchronous process examines only synchronous routings. If for synchronous processing, a valid single outbound routing cannot be found, the sending method returns an error.

    Note. Only active routings are considered for processing.

  5. For each outbound routing that it finds, the process submits the message to the local gateway, along with transaction information about the node and the target connector that should be used to send the message.

  6. The local gateway transmits the message to the specified target node through the specified target connector.

  7. If this is a synchronous message, the process waits for the target node to pass a response message back through the gateway, then returns it to the calling PeopleCode method.

Inbound Message Processing Flow

Each received message goes through the following steps:

  1. The application’s gateway receives a request message from a remote node or gateway, which specifies the application as its target node.

  2. The gateway submits the message to the application’s integration engine, which searches for any inbound request routing parameter which has the same alias name as the external operation name passed in.

  3. If a matching routing alias name isn’t found, the integration engine returns an error message through the gateway to the sending node.

    If a routing alias name is found, the integration engine invokes either the asynchronous request process or the synchronous request process, as appropriate, to handle the message.

    Note. Any inbound routing alias that is found must have the proper permissions for that service operation for the process to proceed.

  4. The process accesses the service operation that matches the routing alias name and passes the message to the service operation's handler associated with receiving PeopleCode.

  5. If this is a synchronous transaction, the process waits for the receiving PeopleCode to generate and return a response message, then passes it back to the sending node through the gateway.

Click to jump to parent topicUnderstanding Integration PeopleCode

This section discusses the PeopleCode used for integrations and describes:

Click to jump to top of pageClick to jump to parent topicSending and Receiving PeopleCode

This section discusses the PeopleCode you use for sending messages from PeopleSoft Integration Broker to other systems, and the PeopleCode you use for receiving messages from other systems.

Sending PeopleCode

PeopleCode for sending messages can be located in PeopleCode events associated with records, record fields, and components, and in application engine programs.

The PeopleCode method used to send messages is highlighted in the following table.

Transmission Type

Sending PeopleCode

Comments

Synchronous

SyncRequest method.

The SyncRequest method belongs to the IntBroker class.

Asynchronous

Publish method.

The Publish method belongs to the IntBroker class.

To work with rowset-based messages in SOAP format, transform the SOAP documents into XML documents and then use the IntBroker class SyncRequest or Publish methods. To work with nonrowset-based messages in SOAP format use the SOAPDoc class.

Receiving PeopleCode

The PeopleCode that you use to receive a message must be associated with the message definition. The transmission type of the message determines the location of the PeopleCode program.

Implement the OnRequest method for synchronous messages. Implement the OnNotify method for asynchronous messages. Both methods are located in the PS_PT application package, in the Integration sub-package, in the IRequestHandler and INotificationHandler classes, respectively.

Transmission Type

Message Structure

Receiving PeopleCode

Comments

Synchronous

Rowset-based

Message is passed into the method.

Implement the OnRequest method in the IRequestHandler application interface.

Synchronous

Nonrowset-based

Message is passed into the method.

Implement the OnRequest method in the IRequestHandler application interface.

Asynchronous

Rowset-based

Message is passed into the method.

Implement the OnNotify method in the INotificationHandler application interface.

Asynchronous

Nonrowset-based

Message is passed into the method.

Implement the OnNotify method in the INotificationHandler application interface.

To get content data out of a request message, use the following guidelines.

Message Structure

PeopleCode

Comments

Rowset-based

GetRowSet method.

None.

Nonrowset-based

GetXMLDoc method.

You can also use Message class functionality with nonrowset-based messages.

See Using Message Object Functionality With Nonrowset-Based Messages.

Click to jump to top of pageClick to jump to parent topicApplication Classes

Application classes house the processing logic for asynchronous and synchronous messages. By implementing the Integration Broker application classes, you can reuse code and access other benefits of application classes.

The following application classes exist for PeopleSoft Integration Broker. See the individual applicable application class interfaces for more information about the methods contained in an application class.

To access these application classes, in PeopleSoft Application Designer, open the PS_PT application package and open the Integration subpackage.

Note. All of the Integration Broker application classes are defined as interfaces. This means that there is no native implementation of them: you must import them to your program and implement them if you want to use them.

Application Class

Methods Contained in Application Class

Comments

INotificationHandler

  • OnNotify

  • OnError

This interface is the equivalent of the Subscription Message event PeopleTools releases prior to PeopleTools 8.48.

IReceiver

  • OnAckReceive

  • OnError

This interface is the equivalent of the OnAckReceive Message event in PeopleTools releases prior to PeopleTools 8.48.

IRequestHandler

  • OnRequest

  • OnError

This interface is the equivalent of the OnRequest Message event in PeopleTools releases prior to PeopleTools 8.48.

IRouter

  • OnRouteSend

  • OnRouteReceive

  • OnError

This interface is the equivalent of the OnRouteSend and OnRouteReceive Message events in PeopleTools releases prior to PeopleTools 8.48.

ISend

  • OnRequestSend

  • OnError

This interface is the equivalent of the OnSend Message event in PeopleTools releases prior to PeopleTools 8.48.

Each of the methods contained in these application classes is described in this section.

Click to jump to top of pageClick to jump to parent topicRouting Methods

Routing methods determine how a message is routed to or from PeopleSoft Integration Broker.

OnRouteSend Method

Implement the OnRouteSend method for outbound synchronous and asynchronous service operations to specify to what node PeopleSoft Integration Broker routes a message. The implementation of this method enables you to apply PeopleCode that filters the destination nodes to which PeopleSoft Integration Broker routes messages.

The OnRouteSend method is contained in the IRouter application class, which is contained in the PS_PT application package, in the Integration subpackage.

When the application PeopleCode is invoked to send a message, the routing definitions in the local database provide a list of target nodes to which PeopleSoft Integration Broker can route the message. The integration engine’s request handler invokes the service operation's OnRouteSend event. You can implement the OnRouteSend method in the application package associated with the handler for this service operation, which enables you to apply additional PeopleCode that determines the final target nodes.

You can use OnRouteSend to validate the outbound service operation's target node list, prevent the message from transmitting, or redirect it to a completely different set of targets.

The following table lists the PeopleCode built-in constants that you can use with the OnRouteSend method:

Constant

Description

%IntBroker_ROUTE_NONE

Do not send this operation to any of the possible nodes.

%IntBroker_ROUTE_SOME

Send this operation to a selected list of nodes. The node list should be an array of strings in the property destinationNodes.

%IntBroker_ROUTE_ALL

Send this operation to all nodes that have a valid routing.

OnRouteSend enables you to account for multiple synchronous targets. Only one target node at a time can receive a request message sent with a synchronous transaction. Even though you can define the same outbound synchronous transaction for multiple nodes, you must make sure the transaction resolves to a single target node or the transaction fails.

The following pseudo code shows an implementation of this class:

import PS_PT:Integration:IRouter; class RoutingHandler implements PS_PT:Integration:IRouter method RoutingHandler(); property array of any destinationNodes; method OnRouteSend(&_MSG As Message) Returns integer; end-class; /* constructor */ method RoutingHandler end-method; method OnRouteSend /+ &_MSG as Message +/ /+ Returns Integer +/ /+ Extends/implements PS_PT:Integration:IRouter.OnRouteSend +/ /* Variable Declaration */ Local any &aNodeList; Local any &rootNode; Local any &xmlDoc; /* Check the message for the instructions on how to execute the OnRouteSend.*/ &xmlDoc = &_MSG.GetXmlDoc(); &rootNode = &xmlDoc.DocumentElement; &aNodeList = &rootNode.GetElementsByTagName("OnRouteSend"); If (&aNodeList.Len <> 1) Then /* No Nodes are in the list, therefore exit. */ Exit; Else /* check the value of the node to determine the action to take. */ Evaluate &aNodeList [1].NodeValue When "True" Return (%IntBroker_ROUTE_ALL); Break; When "False" Return (%IntBroker_ROUTE_NONE); Break; When-Other /* assume that this is to be routed to the node given */ Local array &nodeArray; &nodeArray = CreateArray(); &nodeArray.Push(&aNodeList [1].NodeValue); Local string &sIBVariableTest = GetCurrentType(&nodeArray); Evaluate &sIBVariableTest When "Array" &destinationNodes = &nodeArray.Clone(); Return %IntBroker_ROUTE_SOME; When "BooleanTrue" Return %IntBroker_ROUTE_ALL; When "BooleanFalse" Return %IntBroker_ROUTE_NONE; End-Evaluate; Break; End-Evaluate; End-If; end-method;

OnRouteReceive Method

Implement the OnRouteReceive method for inbound synchronous and asynchronous service operations to apply PeopleCode that determines whether the default local node accepts inbound messages.

The OnRouteReceive method is contained in the IRouter application class, which is contained in the PS_PT application package, in the Integration subpackage.

When the integration engine receives a message, the transaction definitions in the local database provide a list of source nodes from which the application can accept the message. The integration engine’s request handler invokes the service operation's OnRouteReceive event. You can implement the OnRouteReceive method in the application package associated with the handler for this service operation, which enables you to apply PeopleCode that determines whether the default local node accepts the inbound message. You can employ this event regardless of the message transmission type.

The following is an example implementation of this method:

import PS_PT:Integration:IRouter; class RoutingHandler implements PS_PT:Integration:IRouter method RoutingHandler(); property array of any destinationNodes; method OnRouteReceive(&_MSG As Message) Returns boolean; end-class; /* constructor */ method RoutingHandler end-method; method OnRouteReceive /+ &_MSG as Message +/ /+ Returns Boolean +/ /+ Extends/implements PS_PT:Integration:IRouter.OnRouteReceive +/ /* Variable Declaration */ Local any &aNodeList; Local any &rootNode; Local any &xmlDoc; /* Check the message for instructions on how to execute the OnRouteReceive.*/ &xmlDoc = &_MSG.GetXmlDoc(); &rootNode = &xmlDoc.DocumentElement; &aNodeList = &rootNode.GetElementsByTagName("OnRouteReceive"); If (&aNodeList.Len <> 1) Then /* A single node must be present. */ Exit; Else /* check the value of the node to determine the action to take. */ Evaluate &aNodeList [1].NodeValue When "True" Return ( True); Break; When "False" Return ( False); Break; When-Other /* don't recognize the value. */ Exit; End-Evaluate; End-If; end-method;

Click to jump to top of pageClick to jump to parent topicMessaging Methods

This section describes methods used in messaging and the application classes in which they are contained.

Outbound Messaging Methods

This section describes methods used on outbound messages from PeopleSoft to other systems.

OnRequestSend

Implement for outbound synchronous and asynchronous service operations to override connector properties before sending a message to the integration gateway.

This method is contained in the ISend application class.

The OnRequestSend method passes in a message to your derived application class method. The returned value needs to be a message.

The following is an example implementation of this method.

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. +/ /+ OnRequest Send +/ /* Variable Declaration */ Local any &tempNode; Local any &rootNode; Local any &xmlDoc; Local any &msg; &msg = &_MSG; &xmlDoc = &msg.GetXmlDoc(); /* Add a node to the doc to prove that we can edit it in this event. */ &rootNode = &xmlDoc.DocumentElement; &tempNode = &rootNode.AddElement("OnSend"); &tempNode.NodeValue = "If you see this, then the Sync OnSend PCode has altered the message"; /* and write the data back into the message */ &msg.SetXmlDoc(&xmlDoc); Return (&msg); end-method;

See Setting and Overriding Target Connector Properties at Runtime.

When using the ISend handler with message parts, specifically with rowset-based message parts, the rowsets of the parts must be retrieved in the order that the content data will be sent.

The following is an example that can be used for ISend events that use rowset-based parts (even for the cases where one is just overriding the connectors):

method OnRequestSend /+ &MSG as Message +/ /+ Returns Message +/ /+ Extends/implements PS_PT:Integration:ISend. +/ /+ OnRequestSend +/ If (&MSG.IsPartsStructured) Then Local number &i; Local Rowset &rs; For &i = 1 To &MSG.PartCount &rs = &MSG.GetPartRowset(&i); End-For; End-If; Return &MSG; end-method;

OnAckReceive

Implement for outbound asynchronous service operations to access the body of a message acknowledgement to check for SOAP faults.

This method is contained in the IReceiver application class.

The following is an example implementation of this method.

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.OnAck Receive +/ /* Variable Declaration */ /* /* We return a hardcoded value. In this case, a message error.*/ Return (%Operation_Error); end-method;

See Handling Inbound Asynchronous Transactions.

Inbound Messaging Methods

This section describes methods used on inbound messages to PeopleSoft from other systems.

OnRequest

Implement for inbound synchronous service operations.

This method is contained in the IRequestHandler application class.

The following is an example implementation of this method:

class RequestHandler implements PS_PT:Integration: IRequestHandler method RequestHandler(); method OnRequest(&_MSG As Message) Returns Message; end-class; /* constructor */ method RequestHandler end-method; method OnRequest /+ &_MSG as Message +/ /+ Returns Message +/ /+ Extends/implements PS_PT:Integration:+/ /+ IRequestHandler.OnRequest +/ /* Variable Declaration */ Local any &tempNode; Local any &descNode; Local any &rootNode; Local any &xmlDoc; Local any &xmldata; Local any &msg; &msg = CreateMessage(Operation.QE_IB_SYNC_RESP,
%IntBroker_response); &xmldata = "<?xml version='1.0'?> <QE_IB_PeopleCode_Test⇒/>"; &xmlDoc = CreateXmlDoc(&xmldata); &rootNode = &xmlDoc.documentelement; &descNode = &rootNode.AddElement("Description"); &descNode.NodeValue = "Sync test of OnRouteSend."; &tempNode = &rootNode.addelement("OnRequest"); &tempNode.NodeValue = "If you see this, then the On Request PCode created the response message"; &msg.SetXmlDoc(&xmlDoc); Return &msg;

OnNotify

Implement for inbound asynchronous service operations. This method can be used for code that does subscription processing, and for validating and loading message data.

This method is contained in the INotificationHandler application class.

The following is an example implementation of this method:

import PS_PT:Integration:INotificationHandler; class NotificationHandler implements PS_PT: Integration:INotificationHandler method NotificationHandler(); method OnNotify(&_MSG As Message); end-class; /* constructor */ method NotificationHandler end-method; method OnNotify /+ &_MSG as Message +/ /+ Extends/implements PS_PT:Integration: INotificationHandler.OnNotify +/ /* Variable Declaration */ Local Rowset &rs; &rs = &MSG.GetRowset(); /* process data from rowset */ end-method;

OnResponse

Implement for inbound response asynchronous service operations.

This method can be used for code that does response subscription processing. This method is contained in the INotificationHandler application class.

The following is an example implementation of this method and shows how to get the request TransactionID.

import PS_PT:Integration:INotificationHandler; class RESPONSE_NOTIFICATION implements PS_PT: Integration:INotificationHandler method RESPONSE_NOTIFICATION(); method OnNotify(&MSG As Message); end-class; /* constructor */ method RESPONSE_NOTIFICATION %Super = create PS_PT:Integration: INotificationHandler(); end-method; method OnNotify /+ &MSG as Message +/ /+ Extends/implements PS_PT:Integration:+/ /+ INotification Handler.OnNotify +/ Local Rowset &rs; Local boolean &Ret; Local string &TransactionID; &rs = &MSG.GetRowset(); If &MSG.IsSourceNodeExternal Then /* if the request came from an external non PeopleSoft System then you can get the original TransactionID from the WSA_MessageID from the request message. */ &TransactionID = &MSG.IBInfo.WSA_MessageID; Else /* if the request came from a PeopleSoft System then get the original TransactionID from the nReplyToID */ &TransactionID = &MSG.IBInfo.InReplyToID; End-If; end-method;

Error-Handling Methods

Each application class contained in the Integration application subpackage contains an OnError method that you can use for custom error handling.

Custom error handling can include sending an email notification or entering data in a log when an error occurs.

For the IRequestHandler application class, the OnError function returns a string. This enables you to send back custom error messages, for example SOAP faults, to non-PeopleSoft consumers. If the message consumed was a SOAP message and the custom error message is already wrapped in SOAP, it will not be modified and is sent as-is. However, if the OnError message is not SOAP, it is wrapped as a standard SOAP fault and returned to the sender.

If the message consumer is another PeopleSoft system the message set/message ID framework applies.

If an error occurs the OnError method, if implemented, is automatically invoked. The type of exception can be viewed by using the Message object to retrieve an Exception object populated with information about the error, using the message class IBException property.

The following is an example of the OnError method implementation:

/*On Error Implementation */ method OnError /+ &MSG as Message +/ /+ Returns String +/ /+ Extends/implements PS_PT:Integration:IRequestHandler.OnError +/ Local integer &nMsgNumber, &nMsgSetNumber; Local string &sText; &nMsgNumber = &MSG.IBException.MessageNumber; &nMsgSetNumber = &MSG.IBException.MessageSetNumber; rem &sText = &exception.DefaultText; &sText = &MSG.IBException.ToString(); /* ADD SPECIFIC ERROR INFO HERE */ Return &sText; end-method;

See Exception Class.

See IBException.

Click to jump to top of pageClick to jump to parent topicMessaging PeopleCode

Messaging PeopleCode enables you to manipulate message content. The messaging PeopleCode classes you can use for this are:

Message classes

Use for rowset or nonrowset-based messages.

SOAPDoc class

Use for SOAP-compliant messages.

XMLDoc classes

Use for XML messages.

XML and SOAP-compliant messages are nonrowset-based messages. You can use their respective classes to manipulate message content, or use the Message classes.

See Also

Using Message Object Functionality With Nonrowset-Based Messages

Message Classes

SOAPDoc Class

XmlDoc Classes

Click to jump to top of pageClick to jump to parent topicDocument PeopleCode

PeopleSoft provides a Document API for populating and retrieving document data that includes several built-in functions and classes.

The built-in functions are:

CreateDocument

Use this built-in function to instantiate a Document object.

CreateDocumentKey

Use this built-in function to instantiate a Document Key object

The classes are:

The Document API is discussed in the PeopleTools 8.51 PeopleBook: PeopleCode API.

Examples of populating and retrieving document data are provided elsewhere in this chapter.

Click to jump to parent topicGenerating and Sending Messages

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

Click to jump to top of pageClick to jump to parent topicUnderstanding Outbound Messaging

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 PeopleTools 8.51 PeopleBook: Integration Broker Service Operations Monitor

You can also test handler code using the Handler Tester utility.

See PeopleTools 8.51 PeopleBook: Integration Testing Utilities and Tools

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 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]]>

Click to jump to top of pageClick to jump to parent topicHandling Outbound Asynchronous Message Transmission

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

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.

See Also

XmlDoc Classes

Click to jump to top of pageClick to jump to parent topicHandling Outbound Synchronous Transactions

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

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();

See Also

XmlDoc Classes

Click to jump to top of pageClick to jump to parent topicReading Exceptions for Outbound Synchronous Integrations

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;

See Also

Defining General Routing Information

Click to jump to top of pageClick to jump to parent topicOverriding Synchronous Timeout Intervals at Runtime

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();

See Also

Setting and Overriding Target Connector Properties at Runtime

PeopleSoft Timeout Settings

Click to jump to top of pageClick to jump to parent topicHandling Cookies

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);

Click to jump to top of pageClick to jump to parent topicSetting and Overriding Target Connector Properties at Runtime

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.

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 Event

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;

See Also

IBInfo Class

IBConnectorInfo Collection

Message Classes

Click to jump to parent topicReceiving and Processing Messages

This section discusses how to handle:

Note. The OnRouteReceive method can be implemented to apply PeopleCode that determines whether the default local node accepts the inbound message.

Click to jump to top of pageClick to jump to parent topicHandling Inbound Asynchronous Transactions

Implement the OnNotify method in the PS_PT application package, in the Integration sub-package, to handle inbound asynchronous transactions. All the examples in this section are assumed to be implementations of the OnNotify method.

Message Class Inbound Asynchronous Example 1

The following example implements the OnNotify method.

import PS_PT:Integration:INotificationHandler; class FLIGHTPROFILE implements PS_PT:Integration:INotificationHandler method FLIGHTPROFILE(); method OnNotify(&_MSG As Message); end-class; /* constructor */ method FLIGHTPROFILE end-method; method OnNotify /+ &_MSG as Message +/ /+ Extends/implements PS_PT:Integration:INotificationHandler.+/ /+ OnNotify +/ /* Variable Declaration */ Local any &outstring; Local any &i; Local any &CRLF; Local Message &MSG; Local Rowset &rs, &rs1; Local Record &FLIGHTDATA, &REC; Local string &acnumber_value, &msi_sensor_value, &ofp_value, &actype_value, &callsign_value, &squadron_value, &comm1_value, &comm2_value, &ecm_value; Local XmlDoc &xmldoc; Local string &return_string_value; Local boolean &return_bool_value; &CRLF = Char(13) | Char(10); &MSG = &_MSG; &rs = &MSG.GetRowset(); &REC = &rs(1).QE_FLIGHTDATA; &FLIGHTDATA = CreateRecord(Record.QE_FLIGHTDATA); &REC.CopyFieldsTo(&FLIGHTDATA); /* Parse out Message Data */ &acnumber_value = &FLIGHTDATA.QE_ACNUMBER.Value; &msi_sensor_value = &FLIGHTDATA.QE_MSI_SENSOR.Value; &ofp_value = &FLIGHTDATA.QE_OFP.Value; &actype_value = &FLIGHTDATA.QE_ACTYPE.Value; &callsign_value = &FLIGHTDATA.QE_CALLSIGN.Value; &squadron_value = &FLIGHTDATA.QE_SQUADRON.Value; &comm1_value = &FLIGHTDATA.QE_COMM1.Value; &comm2_value = &FLIGHTDATA.QE_COMM2.Value; &ecm_value = &FLIGHTDATA.QE_ECM.Value; &outstring = "Send Async FLight test"; /* Construct Output String */ &outstring = &outstring | &acnumber_value | &CRLF | &msi_sensor_value | &CRLF | &ofp_value | &CRLF | &actype_value | &CRLF | &callsign_value | &CRLF | &squadron_value | &CRLF | &comm1_value | &CRLF | &comm2_value | &CRLF | &ecm_value; /* Log Output String into page record */ &FLIGHTDATA.GetField(Field.DESCRLONG).Value = &outstring; SQLExec("DELETE FROM PS_QE_FLIGHTDATA"); &FLIGHTDATA.Insert(); end-method;

Message Class Inbound Asynchronous Example 2

The following example shows notification PeopleCode that checks the PSCAMA to determine the audit action code and that examines the language code to determine whether related language processing is needed:

method OnNotify /+ &MSG as Message +/ /* Simple PeopleCode Notifcation- - Check the PSCAMA*/ Local Rowset &MSG_RS; Local Record &REC_NAME_PREFIX, &REC, &REC_RL; Local integer &I; Local string &ACTION, &LNG, &BASE_LNG, &RELLNG, &KEY1, &KEY2; &MSG_RS = &MSG.GetRowset(); For &I = 1 To &MSG_RS.RowCount /* Loop through all transactions */ &REC = &MSG_RS.GetRow(&I).GetRecord(Record.NAME_PREFIX_TBL); /* Get Audit Action for this transaction */ &ACTION = &MSG_RS.GetRow(&I).PSCAMA.AUDIT_ACTN.Value; /* Get Language code for this transaction */ &LNG = &MSG_RS.GetRow(&I).PSCAMA.LANGUAGE_CD.Value; &BASE_LNG = %Language; Evaluate &ACTION /*****************************/ /******** Add a Record *******/ /*****************************/ When "A" /* Add the base language record */ &REC_NAME_PREFIX = CreateRecord(Record.NAME_PREFIX_TBL); &REC.CopyFieldsTo(&REC_NAME_PREFIX); &REC_NAME_PREFIX.ExecuteEdits(); If &REC_NAME_PREFIX.IsEditError Then /* error handling */ Else &REC_NAME_PREFIX.Insert(); /* Need error handling here if insert fails */ If &LNG <> %Language Then /* add related language record */ &RELLNG = &REC.RelLangRecName; &REC_RL = CreateRecord(Record.NAME_PREFIX_LNG); &REC.CopyFieldsTo(&REC_RL); &REC_RL.LANGUAGE_CD.Value = &LNG; &REC_RL.Insert(); /* Need error handling here if insert fails */ End-If; End-If; /*****************************/ /***** Change a Record *******/ /*****************************/ /**** Using record objects ***/ When "C" /* Get the Record - insert it */ &KEY1 = &REC.GetField(Field.NAME_PREFIX).Value; &REC_NAME_PREFIX = CreateRecord(Record.NAME_PREFIX_TBL); &REC_NAME_PREFIX.NAME_PREFIX.Value = &REC.GetField(Field. NAME_PREFIX).Value; If &REC_NAME_PREFIX.SelectByKey() Then &REC.CopyFieldsTo(&REC_NAME_PREFIX); &REC_NAME_PREFIX.ExecuteEdits(); If &REC_NAME_PREFIX.IsEditError Then /* error handling */ Else &REC_NAME_PREFIX.Update(); End-If; Else &REC.CopyFieldsTo(&REC_NAME_PREFIX); &REC_NAME_PREFIX.ExecuteEdits(); If &REC_NAME_PREFIX.IsEditError Then /* error handling */ Else &REC_NAME_PREFIX.Insert(); End-If; End-If; /*****************************/ /****** Delete a Record ******/ /*****************************/ /*** Using SQLExec ***********/ When "D" /* Get the Record using SQLExec- error */ &KEY1 = &REC.GetField(Field.NAME_PREFIX).Value; SQLExec("Select NAME_PREFIX from PS_NAME_PREFIX_TBL where NAME_PREFIX = :⇒1", &KEY1, &KEY2); If None(&KEY2) Then /* Send to error log */ Else SQLExec("Delete from PS_NAME_PREFIX_TBL where NAME_PREFIX = :1", &KEY1); SQLExec("Delete from PS_NAME_PREFIX_LNG where NAME_PREFIX = :1", &KEY1); End-If; End-Evaluate; End-For; end-method;

Message Class Inbound Asynchronous Example 3

The following example shows OnNotify PeopleCode with multiple transactions:

method OnNotify /+ &MSG as Message +/ Local Rowset &HDR_RS, &LN_RS; Local Record &HDR_REC, &hdr_rec_msg, &LN_REC, &LN_REC_MSG; Local integer &I, &J; /*This notification peoplecode processes messages that may*/ /*contain multiple Header (MSR_HDR_INV) transactions that may*/ /*have multiple line (DEMAND_INF_INV) transactions. The data */ /*is inserted into identically structured header/line tables*/ /*(MSR_HDR_INV2 and DEMAND_INF_INV2)*/ /* Create record objects for the Header and Lines that will be */ /* inserted into */ &HDR_REC = CreateRecord(Record.MSR_HDR_INV2); &LN_REC = CreateRecord(Record.DEMAND_INF_INV2); /* Create an App. Message Rowset that includes the MSR_HDR_INV (Header) and DEMAND_INF_INV (Line)*/ &HDR_RS = &MSG.GetRowset(); /* Clear out all the Headers and Lines */ SQLExec("DELETE FROM PS_MSR_HDR_INV2 WHERE BUSINESS_UNIT = ’M04A1’"); SQLExec("DELETE FROM PS_DEMAND_INF_INV2 WHERE BUSINESS_UNIT = ’M04A1’"); /* Loop through all the headers in the message */ For &I = 1 To &HDR_RS.ActiveRowCount /* Instantiate the row within the Header portion of the /* App Message rowset to which data will be copied */ &hdr_rec_msg = &HDR_RS.GetRow(&I).GetRecord(Record.MSR_HDR_INV); /* Copy data from the level 0 (Header portion) of /* &STOCK_MSG message structure into the Header record object */ &hdr_rec_msg.CopyFieldsTo(&HDR_REC); &HDR_REC.Insert(); /* Create Rowset that includes the DEMAND_INF_INV (Line) portion of the App Message Rowset */ &LN_RS = &HDR_RS(&I).GetRowset(1); /* Loop through all the lines within this header transaction */ For &J = 1 To &LN_RS.ActiveRowCount /* Instantiate the row within the Line portion of the /* App Message rowset to which data will be copied */ &LN_REC_MSG = &LN_RS.GetRow(&J).GetRecord(Record. DEMAND_INF_INV); /* copy data into the Level 1 (Line portion) of &STOCK_MSG*/ /* object */ &LN_REC_MSG.CopyFieldsTo(&LN_REC); &LN_REC.Insert(); End-For; End-For; end-method;

Message Class Inbound Asynchronous Example 4

There’s a practical limit to how large a message can be, and this can be controlled by a system-wide variable called %MaxMessageSize. The system administrator can change this size in the PSOPTIONS settings. This size can be set only for all messages, not for individual definitions.

PeopleCode that populates a Message object should include code that is similar to the following example to check the message size before inserting a new Level 0 row.

Note. Always code the %MaxMessageSize checkpoint at the Level 0 record. A batch of transactions can be split across multiple messages, but do not split a single transaction (logical unit of work) into multiple messages.

Local SQL &hdr_sql, &ln_sql; Local Message &MSG; Local Rowset &hdr_rs, &ln_rs; Local Record &hdr_rec, &ln_rec, &hdr_rec_msg, &ln_rec_msg; /* This PeopleCode will publish messages for a simple Header/ Line record combination. Multiple Header/Lines are copied to the message until the %MaxMessageSize is exceeded at which point a new message is built. This references MSR_HDR_INV (Header) and DEMAND_INF_INV (Line) records */ /* Create an instance of the STOCK_REQUEST message */ &MSG = CreateMessage(OPERATION.STOCK_REQUEST); /* Create an App. Message Rowset that includes the MSR_HDR_INV (Header) and DEMAND_INF_INV (Line)*/ &hdr_rs = &MSG.GetRowset(); /* Create a SQL object to select the Header rows */ &hdr_sql = CreateSQL("Select * from PS_MSR_HDR_INV WHERE BUSINESS_UNIT='M04A1' AND ORDER_NO LIKE 'Z%' ORDER BY BUSINESS_UNIT,ORDER_NO"); &I = 1; /* Create record objects for the Header and Lines */ &ln_rec = CreateRecord(Record.DEMAND_INF_INV); &hdr_rec = CreateRecord(Record.MSR_HDR_INV); /* Loop through each Header row that is fetched */ While &hdr_sql.Fetch(&hdr_rec) /* Publish the message if its size exceeds the MaxMessageSize /* specified in Utilities/Use/PeopleTools Options */ If &MSG.Size > %MaxMessageSize Then %IntBroker.Publish(&MSG); &I = 1; /* Create a new instance of the message object */ &MSG = CreateMessage(OPERATION.STOCK_REQUEST); &hdr_rs = &MSG.GetRowset(); End-If; If &I > 1 Then &hdr_rs.InsertRow(&I - 1); End-If; /* Instantiate the row within the Header portion of the App Message rowset to which data will be copied */ &hdr_rec_msg = &hdr_rs.GetRow(&I).GetRecord(Record.MSR_HDR_INV); /* Copy data into the level 0 (Header portion) of /* &MSG message structure */ &hdr_rec.CopyFieldsTo(&hdr_rec_msg); /* Publish the last message if it has been changed*/ If &hdr_rec_msg.IsChanged Then %IntBroker.Publish(&MSG); End-If; End-While;

Message Class Inbound Asynchronous Example 5

The following code example shows how to get data out of the IBInfo object for a rowset-based message.

Local Rowset &rs, &rs1; Local Record &FLIGHTDATA, &REC; Local string &acnumber_value, &msi_sensor_value, &ofp_value, &actype_value, &callsign_value, &squadron_value, &comm1_value, &comm2_value, &ecm_value, &datetime; Local XmlDoc &xmldoc; Local string &data; Local boolean &return_bool_value; &CRLF = Char(13) | Char(10); /* this is how one would access data from IBinfo and /* IBConnectorInfo objects*/ &return_bool_value = &MSG.IBInfo.ConnectorOverride; For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfConnector Properties() &data = &MSG.IBInfo.IBConnectorInfo.GetQueryStringArgName(&i); &data = &MSG.IBInfo.IBConnectorInfo.GetQueryStringArgValue(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearConnectorProperties(); &data = &MSG.IBInfo.IBConnectorInfo.ConnectorName; &data = &MSG.IBInfo.IBConnectorInfo.ConnectorClassName; &data = &MSG.IBInfo.IBConnectorInfo.RemoteFrameworkURL; &data = &MSG.IBInfo.IBConnectorInfo.PathInfo; &data = &MSG.IBInfo.IBConnectorInfo.Cookies; For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfQueryStringArgs() &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesName(&i); &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesValue (&i); &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesType(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearQueryStringArgs(); &data = &MSG.IBInfo.MessageType; &data = &MSG.IBInfo.RequestingNodeName; &data = &MSG.IBInfo.OrigUser; &data = &MSG.IBInfo.OrigNode; &data = &MSG.IBInfo.AppServerDomain; &data = &MSG.IBInfo.OrigProcess; &data = &MSG.IBInfo.OrigTimeStamp; &data = &MSG.IBInfo.DestinationNode; &data = &MSG.IBInfo.FinalDestinationNode; &data = &MSG.IBInfo.SourceNode; &data = &MSG.IBInfo.MessageName; &data = &MSG.IBInfo.MessageVersion; &data = &MSG.IBInfo.VisitedNodes; /* get the content data from the message rowset*/ &rs = &MSG.GetRowset(); &REC = &rs(1).QE_FLIGHTDATA; &FLIGHTDATA = CreateRecord(Record.QE_FLIGHTDATA); &REC.CopyFieldsTo(&FLIGHTDATA); /* Parse out Message Data */ &acnumber_value = &FLIGHTDATA.QE_ACNUMBER.Value; &msi_sensor_value = &FLIGHTDATA.QE_MSI_SENSOR.Value; &ofp_value = &FLIGHTDATA.QE_OFP.Value; &actype_value = &FLIGHTDATA.QE_ACTYPE.Value; &callsign_value = &FLIGHTDATA.QE_CALLSIGN.Value; &squadron_value = &FLIGHTDATA.QE_SQUADRON.Value; &comm1_value = &FLIGHTDATA.QE_COMM1.Value; &comm2_value = &FLIGHTDATA.QE_COMM2.Value; &ecm_value = &FLIGHTDATA.QE_ECM.Value; &datetime = &FLIGHTDATA.ACTIONDTTM.Value; &outstring = "Send Async FLight test"; /* Construct Output String */ &outstring = &outstring | &acnumber_value | &CRLF | &msi_sensor_value | &CRLF | &ofp_value | &CRLF | &actype_value | &CRLF | &callsign_value | &CRLF | &squadron_value | &CRLF | &comm1_value | &CRLF | &comm2_value | &CRLF | &ecm_value | &datetime; /* Log Output String into page record */ &FLIGHTDATA.GetField(Field.DESCRLONG).Value = &outstring; SQLExec("DELETE FROM PS_QE_FLIGHTDATA"); &FLIGHTDATA.Insert();

Message Class Inbound Asynchronous Example 6

The following code example shows how to get data out of the IBInfo object for a nonrowset-based message.

Local XmlDoc &xmldoc; Local XmlNode &node, &root, &acct_id_node, &acct_name_node, &address_node, &phone_node; Local string &outstring, &CRLF; Local Record &FLIGHT_DATA_INFO, &REC; Local string &data; Local boolean &return_bool_value; /* this is how one wouild access data from IBinfo and /* IBConnectorInfo objects*/ &return_bool_value = &MSG.IBInfo.ConnectorOverride; For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfConnector Properties() &data = &MSG.IBInfo.IBConnectorInfo.GetQueryStringArgName(&i); &data = &MSG.IBInfo.IBConnectorInfo.GetQueryStringArgValue(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearConnectorProperties(); &data = &MSG.IBInfo.IBConnectorInfo.ConnectorName; &data = &MSG.IBInfo.IBConnectorInfo.ConnectorClassName; &data = &MSG.IBInfo.IBConnectorInfo.RemoteFrameworkURL; &data = &MSG.IBInfo.IBConnectorInfo.PathInfo; &data = &MSG.IBInfo.IBConnectorInfo.Cookies; For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfQueryStringArgs() &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesName(&i); &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesValue (&i); &data = &MSG.IBInfo.IBConnectorInfo.GetConnectorPropertiesType(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearQueryStringArgs(); &data = &MSG.IBInfo.MessageType; &data = &MSG.IBInfo.RequestingNodeName; &data = &MSG.IBInfo.OrigUser; &data = &MSG.IBInfo.OrigNode; &data = &MSG.IBInfo.AppServerDomain; &data = &MSG.IBInfo.OrigProcess; &data = &MSG.IBInfo.OrigTimeStamp; &data = &MSG.IBInfo.DestinationNode; &data = &MSG.IBInfo.FinalDestinationNode; &data = &MSG.IBInfo.SourceNode; &data = &MSG.IBInfo.MessageName; &data = &MSG.IBInfo.MessageVersion; &data = &MSG.IBInfo.VisitedNodes; &xmldoc = &MSG.GetXmlDoc(); &CRLF = Char(13) | Char(10); &root = &xmldoc.DocumentElement; /* Get values out of XMLDoc */ &node_array = &root.GetElementsByTagName("actype"); &ac_type_node = &node_array.Get(1); &ac_type_value = &ac_type_node.NodeValue; &node_array = &root.GetElementsByTagName("msi_sensor"); &msi_sensor_node = &node_array.Get(1); &msi_sensor_value = &msi_sensor_node.NodeValue; &node_array = &root.GetElementsByTagName("callsign"); &callsign_node = &node_array.Get(1); &callsign_value = &callsign_node.NodeValue; &node_array = &root.GetElementsByTagName("ofp"); &ofp_node = &node_array.Get(1); &ofp_value = &ofp_node.NodeValue; &outstring = "GetDataout of xmldoc Test"; &outstring = &outstring | &CRLF | &ac_type_value | &CRLF | &msi_sensor_node | &CRLF | &callsign_value | &CRLF | &ofp_value; /* Write out the result string */ SQLExec("DELETE FROM PS_QE_FLIGHT_DATA"); &FLIGHT_DATA_INFO = CreateRecord(Record.QE_FLIGHT_DATA); &FLIGHT_DATA_INFO.GetField(Field.DESCRLONG).Value = &outstring; &FLIGHT_DATA_INFO.Insert();

Message Class Inbound Asynchronous Example 7

The following example show a notification that could be an implementation of the OnNotify method, using a component interface in the notification. This example shows error trapping and has multilanguage support:

Component string &PUBNODENAME; /* save pubnodename to prevent circular publishes */ Local Message &MSG; Local Rowset &MSG_ROWSET, &cur_rowset; Local ApiObject &oSession; Local ApiObject &CONTACT_CI; Local number &I; Local string &KEY1; Local Record &REC; Local boolean &BC_CREATE, &ADD; Local boolean &TRANSACTION_ERROR, &MSG_ERROR; /** Transaction/Message Error Flags**/ Function errorHandler() Local ApiObject &oPSMessageColl; Local ApiObject &oPSMessage; Local string &strErrMsgSetNum, &strErrMsgNum, &strErrMsgText, &strErrType; &oPSMessageColl = &oSession.PSMessages; For &I = 1 To &oPSMessageColl.Count &oPSMessage = &oPSMessageColl.Item(&I); &strErrMsgSetNum = &oPSMessage.MessageSetNumber; &strErrMsgNum = &oPSMessage.MessageNumber; &strErrMsgText = &oPSMessage.Text; &LogFile.WriteLine(&strErrType | " (" | &strErrMsgSetNum | "," | &strErrMsgNum | ") - " | &strErrMsgText); End-For; rem ***** Delete the Messages from the collection *****; &oPSMessageColl.DeleteAll(); End-Function; Function DO_CI_SUBSCRIBE() &oSession = %Session; &CONTACT_CI = &oSession.GETCOMPONENT(CompIntfc.CONTACT); If (&CONTACT_CI = Null) Then /* Replace this message with Tools message set when available */ Error MsgGet(91, 58, " Unable to get the Component Interface."); Exit (1); End-If; /** Set Component Interface Properties **/ &CONTACT_CI.GetHistoryItems = True; &CONTACT_CI.Interactivemode = False; /** set this to True while debugging **/ rem Send messages to the PSMessage Collection; &oSession.PSMessagesMode = 1; &MSG_ERROR = False; For &I = 1 To &MSG_ROWSET.ActiveRowCount /** Set Session Language Code Property **/ &REGIONALSETTINGS = &oSession.RegionalSettings; &REGIONALSETTINGS.LanguageCd = &MSG_ROWSET(&I).PSCAMA. LANGUAGE_CD.Value; &TRANSACTION_ERROR = False; &BC_CREATE = False; /** Instantiate Component Interface **/ &KEY1 = &MSG_ROWSET(&I).CONTACT_TBL.PERSON_ID.Value; &CONTACT_CI.PERSON_ID = &KEY1; Evaluate &MSG_ROWSET(&I).PSCAMA.AUDIT_ACTN.Value When = "A" When = "N" &ADD = True; /* Check if Keys already exist. */ &CONTACT_CIColl = &CONTACT_CI.Find(); /*If None(&EXISTS) Then*/ If &CONTACT_CIColl.Count = 0 Then If &CONTACT_CI.Create() Then &BC_CREATE = True; Else /* Replace this message with Tools message set when available */ Warning MsgGet(18022, 56, "Error creating Component Interface for transaction %1", &I); &TRANSACTION_ERROR = True; End-If; Else If Not &CONTACT_CI.Get() Then /* Replace this message with Tools message set when available */ Warning MsgGet(18022, 59, "Could not Get Component Interface for transaction %1", &I); &TRANSACTION_ERROR = True; End-If; End-If; Break; When = "C" &ADD = False; If Not &CONTACT_CI.Get() Then /* Replace this message with Tools message set when available */ Warning MsgGet(18022, 59, "Could not Get Component Interface for transaction %1", &I); &TRANSACTION_ERROR = True; End-If; Break; When = "D" When = "K" When-Other /* delete and old key action codes not allowed at this time */ &TRANSACTION_ERROR = True; Warning MsgGet(18022, 61, "Audit Action 'D' not allowed on transaction %1", &TRANSACTION); Break; End-Evaluate; &CONTACT_CI.CopyRowset(&MSG_ROWSET, &I); If Not &TRANSACTION_ERROR Then If Not &CONTACT_CI.save() Then /* Replace this message with Tools message set when available */ Warning MsgGet(18022, 57, "Error saving Component Interface for transaction %1", &TRANSACTION); &TRANSACTION_ERROR = True; End-If; End-If; /** close the last Component Interface in preparation for getting the next **/ If Not &CONTACT_CI.Cancel() Then /* Replace this message with Tools message set when available */ Warning MsgGet(18022, 58, "Error Canceling Component Interface for transaction %1", &TRANSACTION); Exit (1); End-If; /* Reset &TRANSACTION_ERROR to "False" for &BusComp.Save() to execute if no /* Transaction Error found in the next Transaction. */ &TRANSACTION_ERROR = False; End-For; If &TRANSACTION_ERROR Then &MSG_ERROR = True; End-If; End-Function; /**** Main Process ****/ &MSG.ExecuteEdits(%Edit_Required + %Edit_TranslateTable); If &MSG.IsEditError Then &MSG_ERROR = True; Else &PUBNODENAME = &MSG.PubNodeName; &MSG_ROWSET = &MSG.GetRowset(); /* Do Component Interface subscribe */ DO_CI_SUBSCRIBE(); End-If; If &MSG_ERROR Then Exit (1); End-If;

XmlDoc Class Inbound Asynchronous Example

The following example uses the GetXmlDoc method.

Local XmlDoc &Document; Local XmlNode &node, &root; Local string &outstring; Local Rowset &LEVEL0; Local Record &SALES_ORDER_INFO, &REC; &CRLF = Char(13) | Char(10); & Document = &MSG.GetXmlDoc(); &root = & Document.DocumentElement; &child_count = &root.ChildNodeCount; /* Get values out of XmlDoc */ &node_array = &root.GetElementsByTagName("QE_ACCT_ID"); &acct_id_node = &node_array.Get(2); &account_id_value = &acct_id_node.NodeValue; &node_array = &root.GetElementsByTagName("QE_ACCOUNT_NAME"); &acct_name_node = &node_array.Get(2); &account_name_value = &acct_name_node.NodeValue; &node_array = &root.GetElementsByTagName("QE_ADDRESS"); &address_node = &node_array.Get(2); &address_value = &address_node.NodeValue; &node_array = &root.GetElementsByTagName("QE_PHONE"); &phone_node = &node_array.Get(2); &phone_value = &phone_node.NodeValue; &outstring = "GetMessageXmlDoc Test"; &outstring = &outstring | &CRLF | &account_id_value | &CRLF | &account_name_value | &CRLF | &address_value | &CRLF | &phone_value; &SALES_ORDER_INFO = CreateRecord(Record.QE_SALES_ORDER); &SALES_ORDER_INFO.GetField(Field.QE_ACCT_ID).Value = &account_id_value; &SALES_ORDER_INFO.GetField(Field.DESCRLONG).Value = &outstring; &SALES_ORDER_INFO.Update();

Click to jump to top of pageClick to jump to parent topicHandling Inbound Synchronous Transactions

Implement the OnRequest method in the PS_PT application package, in the Integration subpackage, to handle inbound synchronous transactions. All the examples in this section are assumed to be implementations of the OnRequest method.

Message Class Inbound Synchronous Example

The following example implements both the OnRequest method and the OnError method

import PS_PT:Integration:IRequestHandler; class RequestMan implements PS_PT:Integration:IRequestHandler method RequestMan(); method OnRequest(&MSG As Message) Returns Message; method OnError(&MSG As Message) Returns string; end-class; /* constructor */ method RequestMan %Super = create PS_PT:Integration:IRequestHandler(); end-method; method OnRequest /+ &MSG as Message +/ /+ Returns Message +/ Local Message &response; &response = CreateMessage(Operation.SYNC_REMOTE, %IntBroker_Response); &response.GetRowset().GetRow(1).GetRecord(Record.QE_FLIGHTDATA). GetField (Field.DESCRLONG).Value = &MSG.GenXMLString(); Return &response; end-method; method OnError /+ &MSG as Message +/ /+ Returns String +/ /+ Extends/implements PS_PT:Integration:IRequestHandler.OnError +/ Local integer &nMsgNumber, &nMsgSetNumber; Local string &sText; &nMsgNumber = &MSG.IBException.MessageNumber; &nMsgSetNumber = &MSG.IBException.MessageSetNumber; rem &sText = &exception.DefaultText; &sText = &MSG.IBException.ToString(); /* ADD SPECIFIC ERROR INFO HERE */ Return &sText; end-method;

XmlDoc Class Inbound Synchronous Example

The following example uses the GetXmlDoc method:

Local XmlDoc &xmlRequestDoc; Local XmlDoc &xmlResponseDoc; Local XmlNode &select; Local Message &Return_MSG; Local array of XmlNode &whereClause; Local string &recordName; Local string &fieldName; Local string &fieldValue; Local Rowset &outputRowset; Local boolean &return_bool_value; &xmlRequestDoc = &MSG.GetXmlDoc(); &select = &xmlRequestDoc.DocumentElement; &recordName = &select.GetAttributeValue("record"); &outputRowset = CreateRowset(@("Record." | &recordName)); &whereClause = &select.GetElementsByTagName("where"); If &whereClause <> Null And &whereClause.Len <> 0 Then &fieldName = &whereClause.Get(1).GetAttributeValue("field"); &fieldValue = &whereClause.Get(1).GetAttributeValue("value"); &outputRowset.Fill("WHERE " | &fieldName | "= :1", &fieldValue); Else &outputRowset.Fill(); End-If; &Return_MSG = CreateMessage(OPERATION.EXAMPLE, %IntBroker_Response); &xmlResponseDoc = &Return_MSG.GetXmlDoc(); &b = &xmlResponseDoc.CopyRowset(&outputRowset); Return &Return_MSG;

SoapDoc Class Inbound Synchronous Example

The following example uses the GetXmlDoc method.

Note. Because GetXmlDoc returns an XmlDoc object, you must receive the inbound request message as an XmlDoc object, then convert it to a SoapDoc object to process it with SOAP methods.

Local XmlDoc &request, &response; Local string &strXml; Local SoapDocs &soapReq, &soapRes; Local Message &Response_Message; &soapReq = CreateSoapDoc(); &request = &MSG.GetXmlDoc(); &soapReq.XmlDoc = &request; &OK = &soapReq.ValidateSoapDoc(); &parmN = &soapReq.GetParmName(1); &parmV = &soapReq.GetParmValue(1); &Response_Message = CreateMessage(OPERATION.SoapExample, %IntBroker_Response); &response = &Response_Message.GetXmlDoc(); &soapRes = CreateSoapDoc(); &soapRes.AddEnvelope(0); &soapRes.AddBody(); &soapRes.AddMethod("StockPrice", 1); &soapRes.AddParm(&parmN, &parmV); &soapRes.AddParm("Price", "29"); &OK = &soapRes.ValidateSoapDoc(); &response = &soapRes.XmlDoc; Return &Response_Message;

Click to jump to top of pageClick to jump to parent topicSimulating Receiving Messages from External Nodes

You can use PeopleCode to simulate receiving asynchronous messages from external nodes, including running transformations.

Use can use the IntBroker class InboundPublish method to work with rowset-based and nonrowset-based messages.

The following example shows an inbound publish as part of an OnNotify method implementation with a rowset-based message:

Local Message &MSG_REMOTE; Local Rowset &rs; &rs = &MSG.GetRowset(); /*create the message to be re-published from a simualted remote node*/ &MSG_REMOTE = CreateMessage(OPERATION.QE_FLIGHTPLAN); &MSG_REMOTE.IBInfo.RequestingNodeName = "QE_IBTGT"; &MSG_REMOTE.IBInfo.ExternalOperationName = &MSG_REMOTE.OperationName | "." | &MSG_REMOTE.OperationVersion; &MSG_REMOTE.CopyRowset(&rs); &Ret = %IntBroker.InBoundPublish(&MSG_REMOTE);

The following example shows an inbound publish as part of an OnNotify implementation with a nonrowset-based message:

Local Message &MSG_REMOTE; Local XmlDoc &xmldoc; Local Rowset &rs; &xmldoc = &MSG.GetXmlDoc(); /*create the message to be re-published from a simualted remote node*/ &MSG_REMOTE = CreateMessage(OPERATION.QE_FLIGHTPLAN); /* populate the Remote Message with data to be re-published*/ &MSG_REMOTE.SetXmlDoc(&xmldoc); %IntBroker.InBoundPublish(&MSG_⇒ REMOTE, Node.REMOTE_NODE);

Click to jump to parent topicProcessing Inbound Errors

This section discusses how to:

Click to jump to top of pageClick to jump to parent topicValidating Data

You validate data differently depending on the PeopleCode class that you’re using to receive the message.

XMLDoc Class Validation

You can validate incoming XML DOM-compliant messages by using the XmlDoc document type definition (DTD) that is delivered with your PeopleSoft application.

See XmlDoc Classes.

SoapDoc Class Validation

You can validate SOAP-compliant messages by using the ValidateSoapDoc method in the PeopleCode SoapDoc class.

See SOAPDoc Class.

Message Class Validation

Have a message receiving process validate incoming data by:

The ExecuteEdits method uses the definitional edits to validate the message. You can specify the following system variables alone or in combination. If you don’t specify a variable, all of the edits are processed.

The following example processes all edits for all levels of data in the message structure:

&MYMSG.ExecuteEdits();

The following example processes the Required Field and Prompt Table edits:

&RECPURCHASEORDER.ExecuteEdits(%Edit_Required + %Edit_PromptTable);

ExecuteEdits uses set processing to validate data. Validation by using a component interface or a PeopleCode built-in function is usually done with row-by-row processing. If a message contains a large number of rows per rowset, consider writing the message to a staging table and calling an Application Engine program to do set processing if you want additional error checking.

ExecuteEdits sets several properties on several objects if there are any errors:

If you don’t want to use ExecuteEdits, you can set your own errors by using the field properties. Setting the EditError property to True automatically sets the IsEditError message property to True. You can also specify your own message number, message set number, and so on, for the field. If you use the Exit(1) built-in function, the message status changes to Error when you finish setting the fields that are in error.

Click to jump to top of pageClick to jump to parent topicUsing the Exit Built-in Function

Use the Exit built-in function to invoke a messaging error process when the application finds an error. This works only when you use the PeopleCode Message class to process inbound transactions. The same error processing is invoked automatically if PeopleTools finds an unexpected error, such as a Structured Query Language (SQL) error. The Exit built-in function has an optional parameter that affects how the error is handled.

To handle error processing in application tables, use the Exit built-in function with no parameter, or just let the notification process finish normally. This marks the message receipt as successful and commits the data.

To handle the error tracking and correction with PeopleSoft Integration Broker, use the Exit built-in function with 1 as a parameter to log the errors, perform a rollback, and stop processing.

Using the Exit Built-in Function Without Parameters

In the Exit( ) form (that is, Exit without any parameters specified), all data is committed and the message is marked as complete. Use this to indicate that everything processed correctly and to stop program processing. Note, though, that the message status is set to Complete; therefore, you can’t detect or access errors in the Service Operations Monitor. If errors did occur, the subscription code should write them to a staging table, and then you must handle all of the error processing.

The Exit built-in function:

Following is an example of using Exit without a parameter:

&MSG.ExecuteEdits(); If &MSG.IsEditError then App_Specific_Error_Processing(); Exit(); Else Specific_Message_Processing(); End-if;

Using the Exit Built-in Function with Parameters

When you supply a 1 as a parameter for the Exit built-in function, the function:

You can view all errors that have occurred for this message in the Service Operations Monitor, even those errors that are detected by ExecuteEdits.

Following is an example of using the Exit function with 1 as a parameter:

&MSG.ExecuteEdits(); If &MSG.IsEditError then Exit(1); Else Process_Message(); End-if;

See Also

PeopleTools 8.51 PeopleBook: Integration Broker Service Operations Monitor

Click to jump to parent topicUsing Message Object Functionality With Nonrowset-Based Messages

Prior to the PeopleTools 8.44 release, there were two distinct paths for writing and executing PeopleCode for PeopleSoft Integration Broker which were based on whether you were working with rowset-based XML messages or nonrowset-based XML messages.

For rowset-based XML messages, you could use a rowset and all the properties and methods associated with the Message class. For nonrowset-based XML messages, you could not use the Message class, but instead used built-in functions such as PublishXmlDoc and GetMessageXmlDoc. In addition, when working with nonrowset-based messages and these built-in functions, you could only access content data.

Effective with the PeopleTools 8.44 release, when working with nonrowset-based XML messages you can use all of the functionality of the Message object using two new methods, SetXMLDoc and GetXMLDoc.

SetXMLDoc

Use this method to load and pass nonrowset-based data into the Message object.

GetXMLDoc

Use this method to get nonrowset-based data out of the message object.

Click to jump to top of pageClick to jump to parent topicUsing the SetXMLDoc Method

The following example shows how to use SetXMLDoc to use the Message object to publish a nonrowset-based message.

//&XmlDoc holds the nonrowset-based data as before. // create an instance of the Message object &MSG = CreateMessage(OPERATION.QE_F18_ASYNC_XMLDOC); // Load the Message object with the xmldoc data. &MSG.SetXmlDoc(&XmlDoc); // perform a publish for the nonrowset-based message %IntBroker.Publish(&MSG);

Click to jump to top of pageClick to jump to parent topicUsing the GetXMLDoc Method

The following code example shows how to use GetXMLDoc to get nonrowset-based XML out of the Message object.

Local XMLDOC &XmlDoc; // get an xmldoc object loaded with the content data. &XmlDoc = &MSG.GetXmlDoc();

See Also

Message Classes

Click to jump to parent topicGenerating Test Messages

Use the Handler Tester utility to generate test messages.

See PeopleTools 8.51 PeopleBook: Integration Testing Utilities and Tools

Click to jump to parent topicWorking With Message Segments

This chapter provides an overview of message segments and discusses how to:

Click to jump to top of pageClick to jump to parent topicUnderstanding Message Segments

When you create message segments, you can divide rowset-based and nonrowset-based messages into multiple data containers, or segments, for sending. Depending on the order in which you send a message that contains message segments, the receiving system can process the message as a whole, or process one segment at a time while the others are compressed in memory or held in the application database.

As a result creating message segments can enhance system performance and message exchange, especially when you are working with large messages that exceed one gigabyte (1 GB).

To create and manage message segments, you use several methods and properties of the PeopleCode Message class.

Click to jump to top of pageClick to jump to parent topicUnderstanding PeopleCode used to Work with Message Segments

This section discusses:

Methods Used with Message Segments

The following table lists the PeopleCode methods you can use when you work with message segments.

Method

Class

Description

CreateNextSegment

Message

Designates the end point of one segment and the beginning of a new segment.

DeleteOrphanedSegments

IntBroker

Used to delete segments that might have been orphaned if you were processing message segments using a PeopleSoft Application Engine program that had to be restarted.

DeleteSegment

Message

Deletes a segment.

GetSegment

Message

Gets the segment specified by the passed value. The passed value is the segment number.

UpdateSegment

Message

Use this method to update data within the current segment.

Note. Use the DeleteSegment and UpdateSegment methods only when storing segments data in memory. These methods do not function when segment data is stored in the database.

Properties Used with Message Segments

The following table lists PeopleCode properties that you can use when you work with message segments.

Property

Class

Description

CurrentSegment

Message

Returns a number, indicating which segment is the current segment.

SegmentsUnOrder

IBInfo

Determines whether to process message segments in order or unordered. This property pertains to asynchronous messages only.

The values are:

  • True: Process message segments unordered.

  • False: Process message segments in order. (Default.)

SegmentCount

Message

Returns the total number of segments in a message.

SegmentsByDatabase

Message

Enables you to override where message segment data is stored for a message.

The values are:

  • True: Store message segments awaiting processing in the application database.

  • False: Store message segments awaiting processing in memory. (Default.)

See Also

PeopleTools 8.51 PeopleBook: PeopleCode API Reference

Click to jump to top of pageClick to jump to parent topicConfiguring Nodes to Handle Segmented Messages

This section describes how to configure nodes to handle segmented messages.

Understanding Configuring Nodes to Handle Segmented Messages

Before you can send segmented messages, you must configure the remote node defined on the local system to handle segmented messages by setting the Segment Aware option on the Node Definitions page in the PeopleSoft Pure Internet Architecture.

Warning! Do not set the Segment Aware option for remote PeopleSoft 8.45 or earlier nodes, or for third-party systems. If you do so, the receiving system will consume only the first segment of the messages and ignore any subsequent segments.

Configuring a Node to Handle Segmented Messages

To configure a node to handle segmented messages:

  1. Select PeopleTools, Integration Broker, Integration Setup, Node Definitions.

  2. Select a node with which to work and click OK.

    The Node Definitions page appears.

  3. Select the Segment Aware box.

  4. Click the Save button.

Click to jump to top of pageClick to jump to parent topicCreating Message Segments

This section provides an overview of creating message segments and message segment numbers and discusses how to:

Understanding Creating Message Segments

By default every message has one segment.

To create multiple message segments use the CreateNextSegment method in the location in the message where you want one segment to end and next segment to begin. Continue this process until you have created the desired number of segments for the message.

Segments can contain any number of rowsets of data (rowset-based messages) or rows of data (nonrowset-based messages).

Understanding Message Segment Numbers

When you create a message segment, PeopleSoft Integration Broker assigns a message segment number to the segment.

The first message segment has a message segment number or 1, and message segment numbers are increment by one sequentially thereafter. As an example, if you break a message into three segments, the first segment number is 1, the second segment number is 2, and the third segment number is 3.

Creating Message Segments

The following example shows using the CreateNextSegment method to create three segments in the message QE_FLIGHTPLAN, populating each segment with data from the component buffer.

&MSG = CreateMessage(OPERATION.QE_FLIGHTPLAN); &rs=&MSG.GetRowset(); //Now populate rowset // End of first segment. Beginning of second segment. &MSG.CreateNextSegment(); &rs=&MSG.GetRowset(); //Now populate rowset //End of second segment. Beginning of third segment. &MSG.CreateNextSegment(); &rs=&MSG.GetRowset(); //Now populate rowset %IntBroker.Publish(&MSG);

Counting the Number of Segments in Messages

You might have the need to determine the number of segments in a message. Use the SegmentCount property to determine this information.

Storing Message Segments Awaiting Processing

By default, message segments awaiting processing are stored in memory until all segments are processed. Once all segments are processed, PeopleSoft Integration Broker sends all data as one message.

Use the MessageSegmentFromDB parameter in PSAdmin to specify the number of segments to keep in memory before writing segmented messages to the database. The default value is 10.

For synchronous messages, if the number of segments sent for processing exceeds the set for the MessageSegmentsFromDB parameter, an error occurs.

Overriding Where to Store Message Segments Awaiting Processing

You can override the number of segments to keep in memory before writing segmented messages to the database for a single message using the SegmentsByDatabase property of the Message class.

Storage Location

Description

Memory

When message segments are stored in memory, PeopleSoft Integration Broker writes all segments as one message to the database when you send the message.

To store message segment data in memory, set the SegmentsByDatabase property to False. (Default.)

Application database

When message segments are stored in the database, PeopleSoft Integration Broker writes the segments to the database individually. When you store message segments in the database you can have an infinite number of segments in a message.

To store message segment data in the application database, set the SegmentsByDatabase property to True.

When you store message segments in memory, the number of segments is limited by the value set in the MessageSegmentFromDB parameter in PSAdmin in the Setting for PUB/SUB servers section of the file.

When working with asynchronous messages, if you create more message segments then the value set, all segments are written to the database automatically and the SegmentsByDatabase property will automatically be set to True.

For synchronous messages, attempting to create more segments then the specified value will result in an error message.

Specifying the Order in Which to Process Message Segments

When you work with segmented asynchronous messages you can specify that PeopleSoft Integration Broker process the segments in order or unordered, using the SegmentsUnOrder property of the Message class.

Message Segment Processing

Description

In order

When Integration Broker processes message segments in order, it decompresses all message segments sequentially and then processes the message as a whole. In this situation, only one publication or subscription contract is created.

To process message segment in order, set the SegmentsUnOrder property to False.

Unordered

When Integration Broker processes message segments unordered, it decompresses and processes all segments in parallel. In this situation, the system creates one publication or subscription contract for each message segment.

To process message segment unordered, set the SegmentsUnOrder property to True.

If you attempt to send ordered segmented messages to a node that is not segment aware an error message will be created and can be viewed on the Message Errors tab on the Message Details page in Service Operations Monitor.

See PeopleTools 8.51 PeopleBook: Integration Broker Service Operations Monitor

Chunking Asynchronous Segmented Messages

Chunking asynchronous segmented messages sends message in blocks to the receiving node.

When using chunking, message instances display in Hold status in the Service Operations Monitor until all chunks are received. Once all chunks are received, the message status switches to New.

Note. Chunking applies to ordered asynchronous messages only.

The number of segments to chunk for an asynchronous message is determined by the value you set for the MessageSegmentByDatabase parameter in PSAdmin. The default value is 10.

As an example, if a message has 20 segments and you set MessageSegmentByDatabase to 5, PeopleSoft Integration Broker will send four groups (array of messages) of segments to the integration gateway, and each group will contain five segments.

Click to jump to top of pageClick to jump to parent topicDeleting Message Segments

You can delete message segments in a message only before you publish the message.

Use the DeleteSegment method of the Message class to perform the action.

You cannot delete the first segment in a message.

The following example demonstrates using the DeleteSegment method in an implementation of the OnRequestSend method.

import PS_PT:Integration:ISend; class Send implements PS_PT:Integration:ISend method Send(); method OnRequestSend(&message As Message) Returns Message; method OnError(&message As Message) end-class; /* constructor */ method Send %Super = create PS_PT:Integration:ISend(); end-method; method OnRequestSend /+ &message as Message +/ /+ Returns Message +/ /+ Extends/implements PS_PT:Integration:ISend.OnRequestSend +/ Local integer &segment_number, &i; Local Rowset &rs; For &i = 1 To &message.SegmentCount &rs = Null; &message.GetSegment(&i); &rs = &message.GetRowset(); /* determine that segment 3 needs to be deleted. */ &segment_number = &i; End-For; &message.DeleteSegment(&segment_number); Return &message; end-method; method OnError /+ &message as Message +/ /+ Extends/implements PS_PT:Integration:ISend.OnError +/ end-method;

Click to jump to top of pageClick to jump to parent topicSending and Receiving Segmented Messages between PeopleSoft Systems

This section discusses how to:

Sending Segmented Messages to PeopleSoft Systems

To send a segmented message, use sending PeopleCode and events as you would with any other message.

Use the PeopleSoft target connector when the receiving node is a PeopleSoft system. The PeopleSoft target connector automatically handles message segments, and no additional configuration is required on the connector.

Before sending a transaction with message segments, on the sending PeopleSoft system, be sure that the Segment Aware box is selected for the remote node that represents the receiving system.

Receiving Segmented Messages from PeopleSoft Systems

To receive segmented message from PeopleSoft systems, use notification PeopleCode or implement the OnRequest method.

Use the PeopleSoft listening connector to receive transactions that contain message segments from other PeopleSoft systems. The PeopleSoft listening connector automatically handles message segments, and no additional configuration is required on the connector.

Click to jump to top of pageClick to jump to parent topicSending and Receiving Segmented Messages to/from Third-Party Systems

This section discusses how to:

Understanding DataChunkCount and DataChunk Properties

PeopleSoft Integration Broker uses two properties to communicate to sending and receiving systems the number of message segments that are contained in a transaction:

DataChunkCount

Indicates the total number of data chunks or message segments contained in the transaction.

DataChunk

Indicates the number of the data chunk or message segment that you are sending.

For example, if there are a total of seven data chunks in the transaction, and the current segment is the third chunk, the DataChunk value for the current message is 3.

Note that when you are sending and receiving message segments between PeopleSoft systems these properties are not used. The PeopleSoft target and listening connectors perform all necessary processing.

Sending Segmented Messages to Third-Party Systems

To send segmented messages from PeopleSoft systems to third-party system, use one of the following target connectors:

No additional target connector configuration is required to send segmented messages. These connectors read the messaging PeopleCode on the integration gateway and determine the number of segments contained in the transaction. They then populate the DataChunkCount and DataChunk parameters and include this information with each outbound segment sent. All of these connectors except for the HTTP target connector send the DataChunkCount and DataChunk information in the message header of each outbound message segment. The HTTP target connector includes the DataChunkCount and DataChunk parameter information in the HTTP header of each outbound message segment.

Before sending a transaction with message segments, on the PeopleSoft system, be sure that the Segment Aware box is selected for the remote node that represents the third-party integration partner.

Receiving Segmented Messages from Third-Party Systems

At this time, only the HTTP listening connector can be used to receive message segments from third-party systems.

To receive segmented messages with third-party integration partners, the third-party must specify the following DataChunkCount and DataChunk parameters in the HTTP properties, query arguments, or SOAP header:

The receiving PeopleSoft system must use the HTTP listening connector as only this connector monitors transactions for these parameters.

After the third party sends in the first segment, the PeopleSoft system sends an acknowledgement to the third-party system. The acknowledgment contains a transaction ID that the third-party integration partner must include with all subsequent segments.

The following bullet points describe sample processing for a third-party integration partner sending a transaction to a PeopleSoft system that contains three segments:

  1. First segment processing:

    1. The third-party integration partner prepares the first message/segment of the transaction. In the HTTP properties, query string, or SOAP header, it sets the DataChunk equal to 1 indicating the first chunk, and sets the DataChunkCount equal to 3 indicating total number of chunks to be sent for the transaction.

    2. When the request is received by the PeopleSoft system the data chunk is saved in the database as a segment.

    3. In the Service Operations Monitor the transaction displays a status of Hold.

    4. The PeopleSoft system sends an acknowledgement to the third-party system, which includes a transaction ID.

      Note. The third-party integration partner must include the transaction ID as part of all subsequent requests for the transaction. The PeopleSoft system uses the transaction ID to identify the segments that belong to the transaction.

  2. Second segment processing:

    1. The third-party integration partner prepares the second message/segment of the transaction. In the HTTP properties, query string, or SOAP header, it sets the DataChunk equal to 2 indicating that the message is the second chunk, and sets the DataChunkCount equal to 3 indicating total number of chunks to be sent for the transaction. It also specifies the transaction ID sent by the PeopleSoft system in the acknowledgement for the first segment.

    2. When the request is received by the PeopleSoft system the data chunk is saved in the database as a segment.

    3. In the Service Operations Monitor the transaction displays a status of Hold.

  3. Third segment processing:

    1. The third-party integration partner prepares the third message/segment of the transaction. In the HTTP properties, query string, or SOAP header, it sets the DataChunk equal to 3 indicating that the message is the third chunk, and sets the DataChunkCount equal to 3 indicating total number of chunks to be sent for the transaction. It also specifies the transaction ID sent by the PeopleSoft system in the acknowledgement for the first segment.

    2. When the request is received by the PeopleSoft system the data chunk is saved in the database as a segment.

    3. Since the PeopleSoft system has received all of the segments in the transaction, in the Service Operations Monitor the transaction displays a status of New.

    4. The PeopleSoft system processing the transaction like any other transaction at this point.

The PeopleCode to read the data chunks/segments is the Message Segment API.

Click to jump to top of pageClick to jump to parent topicAccessing Segments in Messages

After you receive a segmented message, use the GetSegment method of the Message class to access message segment data.

After you access a message segment, use the Message class GetRowset or GetXmlDoc methods to work with the contents of the segment.

Warning! You can access only one segment in a message at a time. When you access a message segment, PeopleSoft Integration Broker removes the previously accessed message segment from memory.

When you access a message segment, set the existing rowset to null to eliminate storing multiple rowsets in the data cache.

The following example shows using the GetSegment method to access a message segment in the message QE_FLIGHTDATA.

For &i = 1 To &MSG.SegmentCount &rs = Null; //Null the rowset to remove it from memory &MSG.GetSegment(&i); &rs = &MSG.GetRowset(); &REC = &rs(1).QE_FLIGHTDATA; &FLIGHTDATA = CreateRecord(Record.QE_FLIGHTDATA); &REC.CopyFieldsTo(&FLIGHTDATA); /* Parse out Message Data */ &acnumber_value = &FLIGHTDATA.QE_ACNUMBER.Value; &msi_sensor_value = &FLIGHTDATA.QE_MSI_SENSOR.Value; &ofp_value = &FLIGHTDATA.QE_OFP.Value; &actype_value = &FLIGHTDATA.QE_ACTYPE.Value; &callsign_value = &FLIGHTDATA.QE_CALLSIGN.Value; &squadron_value = &FLIGHTDATA.QE_SQUADRON.Value; &comm1_value = &FLIGHTDATA.QE_COMM1.Value; &comm2_value = &FLIGHTDATA.QE_COMM2.Value; &ecm_value = &FLIGHTDATA.QE_ECM.Value; &outstring = "Send Async Flight test"; /* Construct Output String */ &outstring = &outstring | &acnumber_value | &CRLF | &msi_sensor_value | &CRLF | &ofp_value | &CRLF | &actype_value | &CRLF | &callsign_value | &CRLF | &squadron_value | &CRLF | &comm1_value | &CRLF | &comm2_value | &CRLF | &ecm_value; /* Log Output String into page record */ &FLIGHTDATA.GetField(Field.DESCRLONG).Value = &outstring; SQLExec("DELETE FROM PS_QE_FLIGHTDATA"); &FLIGHTDATA.Insert(); End-For;

Click to jump to top of pageClick to jump to parent topicViewing Message Segment Data

The Service Operations Monitor Message Details page provides information about messages that contain segments.

See Also

PeopleTools 8.51 PeopleBook: Integration Broker Service Operations Monitor

Click to jump to top of pageClick to jump to parent topicUsing Restartable Processing for Publishing Large Messages in Batch

This section provides an overview, prerequisites and setup steps for using restartable processing for publishing large asynchronous segmented messages in batch.

Understanding Using Restartable Processing

PeopleSoft provides a PeopleSoft Application Engine library module, IB_SEGTEST, that you can use as a template to create a module to aid in processing large messages and messages in batch for outbound asynchronous PeopleSoft Integration Broker segment data with restart capability.

With restart capability, if there is an abnormal program termination, you can correct any data errors and continue processing from the point of the last commit without having to reload message segment data from the beginning.

Understanding the IB_SEGTEST Application Engine Library Module

This section provides overview information for using the IB_SEGTEST

The IB_SEGTEST library module consists of three sections:

Prerequisites

To use the information provided in this section, you should have a thorough understanding of PeopleSoft Application Engine.

Using the IB_SEGTEST Library Module

This section provides an overview of the high-level list of tasks to perform to set up a PeopleSoft Application Engine program to perform restartable message processing.

  1. Make a copy of IB_SEGTEST, including all sections and PeopleCode.

    From here on, the copy of the application engine library module is referred to as IB_SEGTEST1, but you can use any name you choose.

  2. In the State Records tab of IB_SEGTEST1, verify that PSIBSEGRSTR_AET is the default state record. Replace PT_EIP_ERR_AET with whatever state record is used in the main application engine program that will be calling the Library module.

    Note that IB_SEGTEST1 is flagged as not restartable. Since database commits will be performed in the middle of PeopleCode processing, the only way the commits can take effect is if the module is flagged as not restartable.

  3. The application engine program used to call IB_SEGTEST1 should be restartable.

    Always issue a commit in the step prior to calling the library module IB_SEGTEST1.

  4. In the application engine program that will be calling IB_SEGTEST1, insert a step to call IB_SEGTEST1, section Section1. Insert the step at the point in time when you want to do the message publish. You must issue a commit prior to calling this section, otherwise there will be a ‘Unable to Process Commit’ error issued from within IB_SEGTEST1.

  5. Add PSIBSEGRSTR_AET as an additional state record to the calling application engine program.

  6. Since both programs now share state records, when IB_SEGTEST1 is called, all state record values will be passed on to the called module. Presumably all application values needed to extract application data would be stored in the application state record.

  7. Modify the PeopleCode in IB_SEGTEST1.Section1. Several comments have been added to the code to aid in the modifications. Note the following:

See Also

PeopleTools 8.51 PeopleBook: Application Engine

Click to jump to parent topicPopulating and Retrieving Document Data

This section discusses how to:

Click to jump to top of pageClick to jump to parent topicUnderstanding Populating and Retrieving Document Data

This section provides guidelines for instantiating Document objects, and populating and retrieving document data from document message types.

Memory Management in Message Segments that Use Documents

Following these guidelines when populating or retrieving document data from message segments:

Click to jump to top of pageClick to jump to parent topicInstantiating Document Objects

This section discusses and provides examples for how to:

Instantiating Document Objects Using Package, Name, and Version

You can instantiate a Document object using the CreateDocument built-in function. Using this approach, you use the Create Document built-in function, and then specify the document package name, the document name, and the document version, as shown in the following example:

&DOC = CreateDocument("Purchasing", "PurchaseOrder", "v1");

Instantiating Document Objects Using Document Keys

The following pseudo code shows instantiating a Document object using the a document key. This approach uses the CreateDocumentKey and CreateDocument built-in functions.

First you instantiate a Document Key object, using the CreateDocumentKey built-in function and passing in the document package name, document name, and document version. You then instantiate a Document object using the CreateDocument built-in function, and pass in the document key.

&DOCKEY = CreateDocumentKey("Purchasing", "PurchaseOrder", "v1"); &DOC = CreateDocument(&DOCKEY);

Instantiating Document Objects for Document Message Types

The following example shows how to instantiate a document object when the document is being used as a message type.

&DOC = &MSG.GetDocument();

Click to jump to top of pageClick to jump to parent topicPopulating Document Data

This section discusses and provides examples for how to:

Populating Documents from Messages

The following example shows how to use the CreateMessage built-in function to populate a document from a message:

&MSG = CreateMessage(Operation.PURCHASE_ORDER); &DOC = &MSG.GetDocument();

Populating Documents Using Rowsets

The following example shows using the CreateMessage built-in function and the Document class to populate a document using a rowset:

Local Message &MSG; Local Document &DOC; &MSG = CreateMessage(Operation.PURCHASE_ORDER); &DOC = &MSG.GetDocument(); /* Get Rowset */ &Rowset = &DOC.GetRowset(); /* populate rowset like any other rowset /* update document with popualted rowset * / &nRet = &DOC.UpdateFromRowset(&Rowset); If (&nRet) = True Then %IntBroker.Publish(&MSG); End-If;

Populating Message Segments with Documents

The following example shows pseudo code for populating message segments with documents.

After you code to populate a segment, set the following statement to NULL to release memory:

&DOC = null;

Then, set the following statement to TRUE to manage memory and guarantee that only one segment is in memory at a given time:

&DOC = &MSG.GetDocument(true);

If you do not following these coding guidelines, memory will get filled with data from all segments in the message.

The previous statements are in emphasis in the following example:

Declare Function PopulateDocument PeopleCode QE_FLIGHTDATA.QE_ACNUMBER Field⇒ Formula; Local Document &DOC; &MSG = CreateMessage(Operation.FLIGHTPLAN_DOC); /*pass in true to get ownership of the object*/ / ​&DOC = &MSG.GetDocument(true); /*popualte the docment with data */ PopulateDocument(&DOC, 1); /*create a new segment */ &MSG.CreateNewSegment(); /* null out object to release memory */ ​&DOC = null;&DOC = &MSG.GetDocument(true); PopulateDocument(&DOC, 2); &MSG.CreateNewSegment(); ​&DOC = null; ​&DOC = &MSG.GetDocument(true); ​PopulateDocument(&DOC, 3); /* publish segmented Message (3 segments) */ %IntBroker.Publish(&MSG);

Click to jump to top of pageClick to jump to parent topicRetrieving Document Data

This section discusses and provides pseudo code examples for how to:

Retrieving Document Data from the Message Object

The following pseudo code provides and example of how to retrieve a document from the Message object:

Local Message &MSG; Local Document &DOC; Local Primitive &PRIM; Local Compound &COM, &COM_ID, &COM_BILL, &COM_SHIP, &COM_ITEM; Local Collection &COL_ITEM; &MSG = CreateMessage(Operation.PURCHASE_ORDER); &DOC = &MSG.GetDocument(); &COM = &DOC.DocumentElement; &COM.GetPropertyByName("LanguageCode").Value = "ENG"; /* Populate TransactionID Compound */ &COM_ID = &COM.GetPropertyByName("TransactionId"); &COM2.GetPropertyByIndex(1).value = "KAC"; &COM2.GetPropertyByIndex(1).value = "12345678"; /* Populate BillTo Compound */ &COM_BILL = &COM.GetPropertyByName("BillTo"); &COM5.GetPropertyByName("name").Value = "RobbyNash"; &COM5.GetPropertyByName("number").Value = 713; &COM5.GetPropertyByName("street").Value = "High Wind"; &COM5.GetPropertyByName("unit").Value = ""; &COM5.GetPropertyByName("city").Value = "Paia"; &COM5.GetPropertyByName("state").Value = "Maui HI"; &COM5.GetPropertyByName("zipcode").Value = "96779"; /* Populate item_collection Collection (2 rows) */ &COL_ITEM = &COM.GetPropertyByName("item_collection"); &COM_ITEM = &COL_ITEM.CreateItem(); &PRIM = &COM_ITEM.GetPropertyByName("item"); &PRIM.Value = "mast"; &PRIM = &COM_ITEM.GetPropertyByName("sku"); &PRIM.Value = "123322"; &PRIM = &COM_ITEM.GetPropertyByName("price"); &PRIM.Value = 300; &PRIM = &COM_ITEM.GetPropertyByName("quantity"); &PRIM.Value = 12; &nRet = &COL_ITEM.AppendItem(&COM_ITEM); &COM_ITEM = &COL_ITEM.CreateItem(); &COM5.GetPropertyByName("item").Value = "boom"; &COM5.GetPropertyByName("sku").Value = "123334"; &COM5.GetPropertyByName("price").Value = 270; &COM5.GetPropertyByName("quantity").Value = 10; &nRet = &COL_ITEM.AppendItem(&COM_ITEM); %IntBroker.Publish(&MSG);

Retrieving Document Data from Message Segments

The following pseudo code shows an example of retrieving document data from message segments. As discussed elsewhere in this section, the pseudo code shows setting the following statement to NULL :

&DOC = Null;

Setting the statement to NULL clears memory between segment loops:

import PS_PT:Integration:INotificationHandler; class DOCUMENT_TESTER implements PS_PT:Integration:INotificationHandler method FLIGHTDATA(); method OnNotify(&MSG As Message); end-class; /* constructor */ method FLIGHTDATA end-method; method OnNotify /+ &MSG as Message +/ /+ Extends/implements PS_PT:Integration:INotificationHandler.OnNotify +/ /* Variable Declaration */ Local Rowset &rs; Local Document &DOC; Local Record &FLIGHTDATA, &REC; Local integer &i; /* get each segment of data via a Document and proces it */ For &i = 1 To &MSG.SegmentCount /* null out object to release memory */ ​&DOC = Null; &MSG.GetSegment(&i); /* pass true to GetDocument method to take ownership of object */ ​&DOC = &MSG.GetDocument( True); /* process Document data for each segment */ End-For; end-method;

Retrieving Document Data within a Notification Event Using Message Segments

The following pseudo code provides an example that demonstrates how to retrieve document data within an Notification event using message segments.

As discussed elsewhere in this section, the pseudo code shows setting the following statement to NULL :

&DOC = Null;

Setting the statement to NULL clears memory between segment loops:

For &i = 1 To &MSG.SegmentCount ​ &DOC = Null; ​ &MSG.GetSegment(&i); &DOC = &MSG.GetDocument(); &COM = &DOC.DocumentElement; &str = &COM.GetPropertyByName("LanguageCode").Value; &COM_ID = &COM.GetPropertyByName("TransactionId"); &str = &COM_ID.GetPropertyByIndex(2).Value; &COM_BILL = &COM.GetPropertyByName("BillTo").Value; &str = &COM_BILL.GetPropertyByName("name").Value; &COL_ITEM = &COM.GetPropertyByName("item_collecion"); For &j = 1 To &COL_ITEM.count &COM_ITEM = &COL_ITEM.GetItem(&j); &str = &COM_ITEM.GetPropertyByName("item").Value; End-For; End-For;