Contents

OnRouteSend

The OnRouteSend event triggers before the publication contracts are created and allows you to remove or modify the contracts that are created programmatically. You can inspect the message content and override Service Operation routings. We use this OnRouteSend to override node publication and selectivity not publish to certain nodes at certain times. This is used for asynchronous service operations.

The comments in the interface definition have some good information:

/* This interface is the equivalent of the OnRouteSend  and OnRouteReceive
PeopleCode events in 8.4x tools. OnRouteSend will pass in a message to
your derived application class method. The return should be an integer.
%IntBroker_ROUTE_NONE = Do send this operation to any of the possible nodes
%IntBroker_ROUTE_SOME = Send this operation to a selected list of nodes.
The node list should be an array of strings in the property "destinationNodes".
%IntBroker_ROUTE_ALL = Send this operation to all nodes that have a valid routing.

OnRouteReceive will pass in a message to your derived application
class method. The return should be a Boolean.
FALSE = The Operation will not run locally
TRUE = The Operation will run locally.

If an error occurs the OnError method if implemented will be
automatically invoked. The type of exception can be viewed by using the
Message object to retrieve the Exception object (&Message.IBException).
Please see the PeopleCode Language Reference guide for
more information about the Exception class.
*/

interface IRouter
   method OnRouteSend(&message As Message) Returns integer;
   method OnRouteReceive(&message As Message) Returns boolean;
   method OnError(&request As Message);
   property array of any destinationNodes;
end-interface;

In my testing even if you return %IntBroker_ROUTE_NONE, local subscriptions will trigger still. You can’t use this to stop local subscriptions from processing in a local operation instance. You have to do something like this in the subscription handler.

If &_MSG.IsLocal And
         &_MSG.IBInfo.OrigNode <> &_MSG.IBInfo.SourceNode Then
              do not run code because this is a secondary operation instance that got triggered
  • OnRouteSend will pass in a message to your derived application class method. The return should be an integer.
    • %IntBroker_ROUTE_NONE = Do send this operation to any of the possible nodes
    • %IntBroker_ROUTE_SOME = Send this operation to a selected list of nodes
      • You must populate the destinationNodes property array of strings that reflect the real node name that should receive the message. So if the Integration broker routing table says that 4 nodes get the message and the code determines that there is one node that should NOT get the message then you need to insert the 3 nodes that should get the message.
    • %IntBroker_ROUTE_ALL = Send this operation to all nodes that have a valid routing.

Chunking Rules with OnRouteSend

The delivered FULLSYNC chunking rules work great with the FULLSYNC push processes. However, near real-time “SYNC” operations do NOT honor chunking rules by default. You can use OnRouteSend to apply chunking rules to SYNC operations.

In the following schematic, we have two different subscribers to the project table but each one only cares about certain business units:

FULLSYNC Chunking with Two Subscribers

Without an OnRouteSend handler, a vanilla SYNC operation publishes to ALL subscriber nodes:

SYNC Publishing to All Subscribers

The following OnRouteSend handler reads the Business Unit chunking rules from the EO_BUSUNT_EOC record and selectively publishes only to nodes that should receive that business unit:

import PS_PT:Integration:IRouter;

class onRouteSendBusUnitChunking implements PS_PT:Integration:IRouter
   property array of any destinationNodes;

   method OnRouteSend(&msgParm As Message) Returns integer;
   method getIBRoutings(&msgParm As Message) Returns array of string;
end-class;

method OnRouteSend
   /+ &msgParm as Message +/
   /+ Returns Integer +/
   /+ Extends/implements PS_PT:Integration:IRouter.OnRouteSend +/

   %This.destinationNodes = CreateArrayAny();

   Local string &BUSINESS_UNIT_IN_MESSAGE;
   &BUSINESS_UNIT_IN_MESSAGE = &msgParm.GetRowset().GetRow(1).GetRecord(1).BUSINESS_UNIT.Value;

   %This.destinationNodes = CreateArrayAny();

   Local array of string &aFullRoutingNodeList;
   &aFullRoutingNodeList = %This.getIBRoutings(&msgParm);

   Local integer &i;

   For &i = 1 To &aFullRoutingNodeList.Len
      Local Record &recBUToNodeMapping;
      &recBUToNodeMapping = CreateRecord(Record.EO_BUSUNT_EOC);
      &recBUToNodeMapping.CHUNK_RULE_ID.Value = "BUSINESS_UNIT";
      &recBUToNodeMapping.MSGNODENAME.Value = &aFullRoutingNodeList [&i];
      &recBUToNodeMapping.BUSINESS_UNIT.Value = &BUSINESS_UNIT_IN_MESSAGE;

      If &recBUToNodeMapping.SelectByKeyEffDt(%Date) Then
         %This.destinationNodes.Push(&aFullRoutingNodeList [&i]);
      End-If;
   End-For;

   If %This.destinationNodes.Len = 0 Then
      Return %IntBroker_ROUTE_NONE;
   Else
      Return %IntBroker_ROUTE_SOME;
   End-If;
end-method;

method getIBRoutings
   /+ &msgParm as Message +/
   /+ Returns Array of String +/

   Local array of string &targetNodes = CreateArrayRept("", 0);
   Local Rowset &IBroutes = CreateRowset(Record.PSIBRTNGDEFN_VW);
   Local number &index, &rowCount;

   &rowCount = &IBroutes.Fill("WHERE FILL.IB_OPERATIONNAME = :1 AND FILL.EFFDT = (SELECT MAX(B.EFFDT) FROM PSIBRTNGDEFN_VW B WHERE B.IB_OPERATIONNAME = FILL.IB_OPERATIONNAME AND B.EFF_STATUS = 'A') AND FILL.EFF_STATUS = 'A'", &msgParm.OperationName);

   For &index = 1 To &rowCount
      &targetNodes.Push(&IBroutes(&index).PSIBRTNGDEFN_VW.RECEIVERNODENAME.Value);
   End-For;

   Return &targetNodes;

end-method;

Configure it by placing a handler on the Service Operation definition page:

OnRouteSend Handler Setup

A SETID version of this handler (onRouteSendSETIDChunking) works the same way but reads from EO_SETID_EOC and filters on SETID instead of BUSINESS_UNIT.

For more information on setting up the chunking rules themselves, see FULLSYNC Chunking Rules.

Stop Boomerang Example

The following is an example handler where the client was setup in a very specific way. Each PeopleSoft NODE had a different OPRID attached. It was trying to stop PERSON_BASIC_SYNC messages from being published outbound that were created by other inbound messages. Basically, this handler says: “If the message was created by the current integration broker user then do NOT publish outbound because the external system already sent it and this message was created from the CI update.”

Do NOT put this code in use unless you fully understand what it is doing.

import PS_PT:Integration:IRouter;


class stopBoomerang implements PS_PT:Integration:IRouter
   property array of any destinationNodes;

   method OnRouteSend(&msgParm As Message) Returns integer;
   method getIBRoutings(&msgParm As Message) Returns array of string;
end-class;

method getIBRoutings
   /+ &msgParm as Message +/
   /+ Returns Array of String +/

   Local array of string &targetNodes = CreateArrayRept("", 0);
   Local Rowset &IBroutes = CreateRowset(Record.PSIBRTNGDEFN_VW);
   Local number &index, &rowCount;

   &rowCount = &IBroutes.Fill("WHERE FILL.IB_OPERATIONNAME = :1 AND FILL.EFFDT = (SELECT MAX(B.EFFDT) FROM PSIBRTNGDEFN_VW B WHERE B.IB_OPERATIONNAME = FILL.IB_OPERATIONNAME AND B.EFF_STATUS = 'A') AND FILL.EFF_STATUS = 'A'", &msgParm.OperationName);

   For &index = 1 To &rowCount
      &targetNodes.Push(&IBroutes(&index).PSIBRTNGDEFN_VW.RECEIVERNODENAME.Value);
   End-For;

   Return &targetNodes;

end-method;


method OnRouteSend
   /+ &msgParm as Message +/
   /+ Returns Integer +/
   /+ Extends/implements PS_PT:Integration:IRouter.OnRouteSend +/

   /***********************************************************************\
   * Send to all, none or some destinationNodes:                           *
   * %IntBroker_ROUTE_SOME; must then set array of any destinationNodes    *
   * %IntBroker_ROUTE_ALL                                                  *
   * %IntBroker_ROUTE_NONE                                                 *
   /***********************************************************************/



   Local string &sReceiverNodeName;


   %This.destinationNodes = CreateArrayAny();
   Local boolean &bByPassingAReceiverNode = False;

   Local array of string &aFullRoutingNodeList;
   &aFullRoutingNodeList = %This.getIBRoutings(&msgParm);
   Local integer &i;
   Local string &sGetNodeUser, &sNodeUser;
   &sGetNodeUser = "SELECT USERID FROM PSMSGNODEDEFN WHERE MSGNODENAME = :1";
   For &i = 1 To &aFullRoutingNodeList.Len


      SQLExec(&sGetNodeUser, &aFullRoutingNodeList [&i], &sNodeUser);

      If &sNodeUser = %OperatorId Then
         &bByPassingAReceiverNode = True;
         Local string &sMsg;
         &sMsg = "Bypassing node: " | &aFullRoutingNodeList [&i] | " because the node sent the orignal update.";
         MessageBox(%MsgStyle_OK, "", 0, 0, &sMsg);
      Else
         %This.destinationNodes.Push(&aFullRoutingNodeList [&i]);
      End-If;
   End-For;

   &aFullRoutingNodeList = Null;
   If %This.destinationNodes.Len = 0 Then

      Return %IntBroker_ROUTE_NONE;
   Else
      If &bByPassingAReceiverNode = False Then
         /* No Boomerange condition found */

         Return %IntBroker_ROUTE_ALL;
      Else

         Return %IntBroker_ROUTE_SOME;
      End-If;
   End-If;

end-method;

Author Info
Chris Malek

Chris Malek s a PeopleTools® Technical Consultant with over two decades of experience working on PeopleSoft enterprise software projects. He is available for consulting engagements.

Work with Chris