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.

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 local gateway receives a request message from a remote node or gateway, which specifies the application as its target node.

  2. The local 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 messages in SOAP format, transform the SOAP documents into XML documents and then use the IntBroker class SyncRequest or Publish methods.

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 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. 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 transaction 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.

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 is 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 /* 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 (%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 return 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 ISendHandler 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 when a response is required.

This method is contained in the IRequestHandler application class.

The following is an example implementation of this method:

import PS_PT:Integration:IRequestHandler; class RequestHandler implements PS_PT:Integration: IRequest Handler 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:+/ /+ IRequest Handler.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); &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; end-method;

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 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:INotification Handler(); 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 DOM-compliant messages.

XML DOM-compliant 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 Class

Click to jump to parent topicMessaging Handlers

Messaging handlers, or handlers are associated with a service operation on the Handlers tab of the Service Operations page.

Handlers define additional programming to be used with processing the message associated with the service operation.

The following are the different types of handlers:

See Also

Adding Handlers to Service Operations

Click to jump to top of pageClick to jump to parent topicSelecting Handlers

The availability of each handler type depends on the type of service operation you are using. The following table lists the message structures used for each service operation type and the handler types available for use.

Service Operation Type

On Notify Handler Type

On Receive Handler Type

On Request Handler Type

On Response Handler Type

On Route Handler Type

On Send Handler Type

Asynchronous one-way

Request message

Request message

NA

NA

Request message

Request message

Asynchronous request/response

Request message

Request message

NA

Response message

*Request message

*Response message

Request message

Asynchronous to synchronous

Request message

NA

Request message

Response message

*Request message

*Response message

Request message

Synchronous

NA

NA

Request message

NA

Request message

Request message

Note. * For On Route with On Send, the message structure is a request message. For On Route with On Receive, the message structure is a response message.

The On Response handler type is used to identify the type of OnNotify event to be fired. For example, assume there are four OnNotify handlers that are to be fired—three are general OnNotify events, that is, the message is processed as part of the request, and the fourth is a response to the original asynchronous request. The fourth one is specified with a handler type of On Response, and the application class selected is the base class OnNotify.

Click to jump to top of pageClick to jump to parent topicImplementing Handlers

You can implement handlers using application classes, component interfaces, data mover scripts or pre-PeopleTools 8.48 integration PeopleCode constructs.

The following table lists the handlers you can implement using application classes, component interfaces and data mover scripts:

Implementation

On Notify Handler

On Receive Handler

On Route Handler

On Send Handler

On Request Handler

On Response Handler

Application class

Y

Y

Y

Y

Y

Y

Component interface

Y

N

N

N

Y

Y

Data mover script

Y

N

N

N

N

N

Implementing Handlers Using Application Classes

You can specify an application class as a handler for a service operation. This is the most typical implementation of a handler.

For application class handlers, the names that populate the drop down used for selecting the appropriate method must have the exact signature required for the method.

Handler Type

Input Parameter to Method

Method Output Parameter

OnNotify

Message

Void (none)

OnResponse

Message

Void (none)

OnReceive

message

Int

OnRequest

Message

Message

OnSent

Message

Message

OnRoute

Message

Integer or Boolean

Note. For OnRoute: if you select a method that returns as integer, the handler type is OnRouteSend. If you select a method that returns as Boolean, the handler type is OnRouteReceive.

To implement a handler using an application class:

  1. Select the Integration Broker method that you want to implement based on the type of service operation you are creating.

  2. Create a new application class, and import the appropriate Integration Broker application class. For example:

    import PS_PT:Integration:INotificationHandler;

  3. Define a class that implements the Integration Broker application class.

  4. Define the method that implements the Integration Broker method, with the appropriate signature. In the following example, the OnNotify method would be available as a handler method.

    class RESPONSE_NOTIFICATION implements PS_PT:Integration:INotificationHandler method RESPONSE_NOTIFICATION(); method OnNotify(&MSG As Message); end-class;

  5. In the definition of the class, create the program-specific code to be used for this handler.

  6. When you define the service operation, select the application package, class and method you created as part of the handler details.

Implementing Handlers Using Component Interfaces

You can implement a component interface as a handler to access extant business rules and processes to be used with the message data.

You can only use a component interface for On Notify, On Request and On Response messaging handler types.

Component interfaces can be used as handlers for both asynchronous as well as synchronous messages. Asynchronous messages should only be used with methods that do not require a response, such as Update or Insert.

You must define a component interface as a service before you can use implement any of the methods as handlers.

The standard methods for a component interface (such as Find, Get, Save, Update, and so on) are automatically available for a handler. However, if you want to use a user-defined method, you must include the keyword Doc as part of the signature.

See Creating Component Interface-Based Services.

Implementing Handlers Using Data Mover Scripts

You can implement a handler using a data mover script (DMS) to bulk load large amounts of data into a local table. DMS can only be selected for asynchronous one way service operations, and can only be used with rowset-based request messages.

Use DMS as a handler type for large messages.

When the OnNotify event is fired, the message data is inserted into the tables defined in the message using data mover script constructs.

Data Mover doesn't perform any data validations.

Click to jump to parent topicGenerating and Sending Messages

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

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 Using the Service Operations Monitor.

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

See Enterprise PeopleTools 8.49 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 programatically. 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 IntBrokerclass:

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 an 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 GetXMLString 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 Integration Broker Monitor for the Publication Contract.

The following code example shows how to use GetXmlDoc and GetXMLString 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 Class

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 string &xmlString; Local XmlDoc &xmlRequestDoc; Local XmlDoc &xmlResponseDoc; Local Field &DescrLong; &DescrLong = GetLevel0().GetRow(1).GetRecord(Record.QE_FUNCLIB_IB). DESCRLONG; /* Get the input XML string */ &xmlString = &DescrLong.Value; /* Parse the input XML string into an XmlDoc */ &MSG = CreateMessage(OPERATION.XMLSYNCREQ); /* Send request */ &ResponseMsg = %IntBroker.SyncRequest(&MSG); &xmlResponseDoc = &ResponseMSG.GetXmlDoc(); /* Display the output XML string */ &DescrLong.Value = &xmlResponseDoc.GenXmlString();

See Also

XmlDoc Class

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.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 = &SalesRequest.SyncRequest(); /* Retrieve cookies from the response message */ &SalesCookies = &SalesResponse.IBInfo.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(Message.SALES_ORDER_SYNC); &SalesRequest.CopyRowsetDelta(&SALES_ORDER); /* Insert the cookies in the request message */ &SalesRequest.IBInfo.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 transaction 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

ConnectorInfo 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; &return_bool_value = &MSG.IBInfo.ConnectorOverride; For &i = 1 To &MSG.IBInfo.IBConnectorInfo. GetNumberOfConnectorProperties() &return_string_value = &MSG.IBInfo.IBConnectorInfo. GetQueryStringArgName(&i); &return_string_value = &MSG.IBInfo.IBConnectorInfo. GetQueryStringArgValue(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearConnectorProperties(); &return_string_value = &MSG.IBInfo.IBConnectorInfo.ConnectorName; &return_string_value = &MSG.IBInfo.IBConnectorInfo.ConnectorClass Name; &return_string_value = &MSG.IBInfo.IBConnectorInfo.Remote FrameworkURL; &return_string_value = &MSG.IBInfo.IBConnectorInfo.PathInfo; &return_string_value = &MSG.IBInfo.IBConnectorInfo.Cookies; For &i = 1 To &MSG.IBInfo.IBConnectorInfo.GetNumberOfQuery StringArgs() &return_string_value = &MSG.IBInfo.IBConnectorInfo. GetConnectorPropertiesName(&i); &return_string_value = &MSG.IBInfo.IBConnectorInfo. GetConnectorPropertiesValue(&i); &return_string_value = &MSG.IBInfo.IBConnectorInfo. GetConnectorPropertiesType(&i); End-For; &MSG.IBInfo.IBConnectorInfo.ClearQueryStringArgs(); &return_string_value = &MSG.IBInfo.MessageType; &return_string_value = &MSG.IBInfo.RequestingNodeName; &return_string_value = &MSG.IBInfo.OrigUser; &return_string_value = &MSG.IBInfo.OrigNode; &return_string_value = &MSG.IBInfo.AppServerDomain; &return_string_value = &MSG.IBInfo.OrigProcess; &return_string_value = &MSG.IBInfo.OrigTimeStamp; &return_string_value = &MSG.IBInfo.DestinationNode; &return_string_value = &MSG.IBInfo.FinalDestinationNode; &return_string_value = &MSG.IBInfo.SourceNode; &return_string_value = &MSG.IBInfo.MessageName; &return_string_value = &MSG.IBInfo.MessageVersion; &return_string_value = &MSG.IBInfo.VisitedNodes; &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 messagis 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(); &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(); 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 &BIGMAN; Local XmlNode &node, &root; Local string &outstring; Local Rowset &LEVEL0; Local Record &SALES_ORDER_INFO, &REC; &CRLF = Char(13) | Char(10); &BIGMAN = &MSG.GetXmlDoc(); &root = &BIGMAN.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 OnNotify method in the PS_PT application package, in the Integration sub-package, to handle inbound synchronous transactions. All the examples in this section are assumed to be implementations of the OnNotify method.

Message Class Inbound Synchronous Example

The following example implements both the OnNotify 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.CopyRowset(&rs); %IntBroker.InBoundPublish(&MSG_REMOTE, Node.REMOTE_NODE);

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; &rs = &MSG.GetRowset(); /*create the message to be re-published from a simualted remote node*/ &MSG_REMOTE = CreateMessage(OPERATION.QE_FLIGHTPLAN); /* populate the &xmldoc 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 Class.

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 Integration Broker 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 Integration Broker 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

Using the 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 Enterprise PeopleTools 8.49 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.

DeleteOrphaned

Segments

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

Enterprise PeopleTools 8.49 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 Integration Broker Monitor.

See Using the Service Operations Monitor.

Chunking Asynchronous Segmented Messages

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

When using chunking, messages instances display in Hold status in Integration Broker 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

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

To receive a segmented message, use notification PeopleCode or the implement the OnRequest method.

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 Integration Broker Monitor Message Details page provides information about messages that contain segments.

See Also

Using the 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

Enterprise PeopleTools 8.49 PeopleBook: PeopleSoft Application Engine