When to use Integration Broker Synchronous Versus Asynchronous and why?

 There are different times when you create either a Synchronous or Asynchronous service. There are pros and cons to each side and there is no “correct” way to do it. It all depends on what you are building and the capabilities of the systems involved.

You also have consider if PeopleSoft is acting as the client (i.e. calling another web service) or the server (i.e. providing the web service).

  • Synchronous service is a request/reply where the providing server responds in real-time to the message call.
    • REST services can only be synchronous.
  • An Asynchronous service is more like a “drop box” where the client sends a message and responds that the message was received. However, the processing of the message contents will happen at some later point.
    • PeopleSoft REST service cannot be asynchronous

Asynchronous Provider

  • When the client sends a message in, PeopleSoft will “store” the message content in some PeopleSoft IB tables and provide a response to the client that the message was received. However, PeopleSoft has not done anything with the message yet. This last point is extremely important to understand.

  • The message is a request to potentially make something happen in PeopleSoft. At some point in the future, some handler code will get run to process the actually message content. The request sent by the client gets pushed to a “queue” and it will get processed when the integration broker has time to get to it.

  • There is no guarantee that anything will actually happen with the message content.

    • There may be no handler code defined to run.
    • The queues could be paused and no action will be taken on the message.
    • Some administrator cancels the message.
    • An OnRouteReceive handler may inspect the message and decide it should not be processed.
    • The queue is very backlogged and it could take days for the message to be processed.
  • The client has zero visibility into what happens to the message once it posts the message.

Synchronous Services

Again, Synchronous web service in PeopleSoft are the typical “request/reply” message style where some code executes on the providing server while the client waits for a response. The client sends the “request” and “waits” until it gets a reply. This is very different from the asynchronous model. This is like a phone conversation where both sides must talk back and forth for a conversation to occur.

Synchronous Provider

If you are creating a web service for another system to act as the client and that client needs real-time information back then you need to go with synchronous service. Let’s imagine that you need to provide a web service to an external system that maintains email addresses for employees. That system may want to make a web service call to PeopleSoft when a new email address is created or changed. In this case, the web service may want to know if the update was successful before continuing. This is the request/reply model.

  • The external system sends a request to PeopleSoft.
  • PeopleSoft will take the request and process it while the client waits.
  • Once the database is updated with the new email address, a response is given back to the client that it was successful.

When to use Sync Versus Async

If you are going to be the client of a web service you don’t have a choice on how the interaction style is designed. So I don’t have a decision tree for you there. However, if you are creating new web service in PeopleSoft to other system to invoke then I can provide some guidance based on the points below.

  • Does your client need the PeopleSoft data updated in real-time while it waits?
    • Yes - Use Synchronous
  • Is your web service providing real-time queries of data in PeopleSoft?
    • Yes - Use Synchronous
  • Will the system send a large amount of “events”/changes to PeopleSoft and they are “expensive” to process?
    • Yes - Use Asynchronous
  • Do multiple pieces of code need to trigger in response to a message from a client?
    • Yes - Consider using Asynchronous with more than one handler.
  • Does your client need a specific response message format?
    • Yes - Use Synchronous
  • Do you have a “source” system that needs to notify many different systems about data changes?
    • Yes - Use Asynchronous because it has “fan out” functionality

This diagram illustrates the integration components that reside on the integration engine and the types of processing it performs.

Integration engine architecture

Operation Type

Routing

Actions

Asynchronous — One Way.

Outbound.

  1. The application generates and sends a request.

  2. One or more target system receives and processes the request.

Asynchronous — Request/Response.

Outbound.

  1. The application generates and sends a request.

  2. The target system receives and processes the request.

  3. Sometime later the target system sends a response which contains the transaction ID from the original request. This ID serves as the correlation ID.

  4. The application processes the response using the correlation ID to map it back to the original request. The message sent back is a response in the form of a request.

Asynchronous to Synchronous.

Outbound.

  1. The application generates and sends a request.

  2. A single target system receives and processes the request, then generates and sends a response.

  3. The application receives and processes the response.

Synchronous.

Outbound.

  1. The application generates and sends a request.

  2. The application suspends activity and waits for a response.

  3. A single target system receives and processes the request, then generates and sends a response.

  4. The application resumes its activity and receives and processes the response.

Asynchronous — One way.

Inbound.

  1. A source system generates and sends a request.

  2. The application receives and processes the request.

Asynchronous — Request/Response.

Inbound.

  1. A source system generates and sends a request.

  2. The application receives and processes the request.

  3. Sometime later the application sends a response back to the source system. The response includes a unique identifier from the original request, which serves as a correlation ID.

  4. The source system processes the response using the correlation ID to map it back to the original request.

Asynchronous to Synchronous.

Inbound.

  1. A source system generates and sends a request.

  2. The application receives and processes the request, then generates and sends a response.

  3. The source system receives and processes the response.

Synchronous.

Inbound.

  1. A source system generates and sends a request.

  2. The source system suspends activity and waits for a response.

  3. The application receives and processes the request, then generates and sends a response.

  4. The source system resumes its activity and receives and processes the response.

This example illustrates the flow of an outbound request through PeopleSoft Integration Broker.

Flow of an inbound request through PeopleSoft Integration Broker

This example illustrates and outbound request through PeopleSoft Integration Broker to an external system.

Outgoing request through PeopleSoft Integration Broker to an external system

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 interfac


Handling Inbound Asynchronous Transactions

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

Message Class Inbound Asynchronous Example 1

The following example implements the OnNotify method.

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

Message Class Inbound Asynchronous Example 2

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

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

Message Class Inbound Asynchronous Example 3

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

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

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

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

Message Class Inbound Asynchronous Example 4

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 5

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 6

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

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

XmlDoc Class Inbound Asynchronous Example

The following example uses the GetXmlDoc method.

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

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

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

Message Class Inbound Synchronous Example

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

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

XmlDoc Class Inbound Synchronous Example

The following example uses the GetXmlDoc method:

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

SoapDoc Class Inbound Synchronous Example

The following example uses the GetXmlDoc method.

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

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

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

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

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

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

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

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

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

No comments:

Post a Comment

PeopleCode to retrieve Google map between two addresses

  PeopleCode Example: /* Define constants for the API request */ Local string &origin = "123 Main St, Anytown, USA";   /* ...