Showing posts with label application package. Show all posts
Showing posts with label application package. Show all posts

Saturday, April 25, 2020

XML Parser

XML related API has been around for some time now in PeopleSoft and this post is not discussing anything new. Just something that I wanted to pen down for future reference. 

So recently I have been working on a requirement where in I have to parse out a XML response and fetch data values in order to process them further. In this case the same tag element names repeat throughout the XML message and there are multiple levels in the message. The requirement was to traverse each "item" tag and fetch the value for "key" and "value" tags.

Format of the XML message is as shown below.

<?xml version="1.0" encoding="UTF-8"?> <root> <level1> <level2> <level3> <item> <key>FieldName1</key> <value>Value1</value> <type>String</type> </item> <item> <key>FieldName2</key> <value>Value2</value> <type>Date</type> </item> <item> <key>FieldName3</key> <value>Value3</value> <type>Number</type> </item> </level3> </level2> </level1> </root>



Wrote two methods, first one is way longer than the second one.
For both methods I am passing the "field_name_value" and getting back the &fieldvalue value.


Method one - longer.


Local XmlDoc &NewHireXMLDoc;
Local XmlNode &root, &level1, &level2, &level3, &item;
Local number &z, &y, &x, &w, &v;
Local string &sResp, &fieldvalue;
Local boolean &bRet;


rem &sResp is the XML message in string form;
   
&NewHireXMLDoc = CreateXmlDoc();
&bRet = &NewHireXMLDoc.ParseXmlString(&sResp);

&rootNode = &NewHireXMLDoc.DocumentElement;

For &z = 1 To &rootNode.ChildNodeCount
   If &root.GetChildNode(&z).NodeName = "level1" Then
      &level1= &root.GetChildNode(&z);
      For &y = 1 To &level1.ChildNodeCount
         If &level1.GetChildNode(&y).NodeName = "level2" Then
            &level2= &level1.GetChildNode(&y);
            For &x = 1 To &level2.ChildNodeCount
               If &level2.GetChildNode(&x).NodeName = "level3" Then
                  &level3 = &level2.GetChildNode(&x);
                  For &w = 1 To &level3.ChildNodeCount
                     If &level3.GetChildNode(&w).NodeName = "item" Then
                        &item = &level3.GetChildNode(&w);
                        For &v = 1 To &item.ChildNodeCount
                           If &item.GetChildNode(&v).NodeName = "key" And
                                 &item.GetChildNode(&v).NodeValue = "field_name_value" Then
                              &fieldvalue = &item.GetChildNode(&v + 1).NodeValue;
                              &v = &v + 1;
                           End-If;
                       End-For;
                     End-If;
                  End-For;
               End-If;
            End-For;
         End-If;
      End-For;
   End-If;
End-For;



Method two - shorter

Local XmlDoc &NewHireXMLDoc;
Local string &sResp, &fieldvalue;
Local boolean &bRet;

Local array of XmlNode &items;
Local number &y, &z;

rem &sResp is the XML message in string form;
   
&NewHireXMLDoc = CreateXmlDoc();
&bRet = &NewHireXMLDoc.ParseXmlString(&sResp);


&items = &NewHireXMLDoc.DocumentElement.FindNodes("level1/level2/level3/item");
   
   For &z = 1 To &items.Len
      For &y = 1 To &items [&z].ChildNodeCount
         
         If &items [&z].GetChildNode(&y).NodeName = "key" And
               &items [&z].GetChildNode(&y).NodeValue = "field_name_value" Then
            &fieldvalue = &items [&z].GetChildNode(&y + 1).NodeValue;
            Break;
         End-If;
      End-For;

   End-For;

Tuesday, April 21, 2020

Creating JSON request for REST web services

PeopleSoft provides Document technology to be used to generate JSON request messages but in my experience they are very restrictive especially when working on integrating with 3rd party web services. So following is what I did to generate a JSON request message to post to a 3rd party REST web service. 

The request that I have to generate is in the following form.
[
   {
      "attrib1":"value1",
      "attrib2":"value2",
      "attrib3":{
         "attrib3_1":"values3_1",
         "attrib3_2":"values3_2",
         "attrib3_3":"values3_3",
         "attrib3_4":"values3_4"
      }
   }
]

I am running PT 8.57.x and at this time its not possible to build a document with the root node as an array as shown in the example below. Also I have nested compounds which is also a challenge, the parent compound does not have a label where as the child does. 
So to build something like above I am using the CreateJsonBuilder API provided by PeopleSoft.

Local JsonBuilder &jbldr = CreateJsonBuilder();
Local JsonArray &jArray;
Local string &json;
Local message &request, &response;
Local boolean &bRet;

&jbldr.StartArray(""); /* no label */
 &jbldr.StartObject(""); /* no label */
  &jbldr.AddProperty("attrib1", "value1");
  &jbldr.AddProperty("attrib2", "value2");
   &jbldr.StartObject("attrib3"); /* need a label */
    &jbldr.AddProperty("attrib3_1", "value3_1");
    &jbldr.AddProperty("attrib3_2", "value3_2");
    &jbldr.AddProperty("attrib3_3", "value3_3");
    &jbldr.AddProperty("attrib3_4", "value3_4");
   &jbldr.EndObject("attrib3"); /* closing out the compound or JSONObject */
 &jbldr.EndObject("");
&jbldr.EndArray("");


/* this will return the array just like what I want */
&jArray = &jbldr.GetRootNode().GetJsonObject().GetJsonArray("");
&json = &jArray.ToString();

Created a basic non-rowset based message and assigned that as the request message in my service operation. Use this method to set the content for the message segment for a non-rowset-based message only.

&bRet = &request.SetContentString(&json);
&response = %IntBroker.SyncRequest(&request);

That's it, works like a charm.

Sunday, March 8, 2020

Event Mapping (managing customizations)

Event Mapping is a PeopleSoft delivered framework that helps applications and customers adapt PeopleSoft to meet their business needs with minimum upgrade impact. It introduces business logic as a configuration instead of customization. Event mapping allows the user to develop reusable code and artifacts and ensures that the customer’s code will not be overwritten by PeopleSoft delivered code during an upgrade.

Following is what I have tried in PeopleTools 8.56.07 and 8.57.08 on HCM 9.2 (PUM 31 and beyond). For this POC I am going to call my custom application package peoplecode on SavePostChange event on the DEPARTMENT_TBL component to perform something like sending out a notification. In the absence of the event mapping functionality I would have written this code in SavePostChange event of the DEPARTMENT_TBL component thus customizing the delivered object.

So, step one is to build the application package peoplecode. Import of PT_RCF:ServiceInterface is the key. The class name can be anything but the method name has to be "Execute".

import PT_RCF:ServiceInterface;

class FoundationDataNotify extends PT_RCF:ServiceInterface
   method Execute();
end-class;

method Execute
   /+ Extends/implements PT_RCF:ServiceInterface.execute +/

   /* custom logic to send out notification goes here */
end-method;
  
Once the package is developed navigate to PeopleTools > Portal > Related Content Service > Define Related Content Service. Create a new definition and select "URL Type" as application class and then provide the package details. For this POC I selected "Public Access" under security options. Save the service definition.

Then navigate to PeopleTools > Portal > Related Content Service > Manage Related Content Service, Event Mapping tab. Click on the "Map Application Classes to Component Events" link and then navigate the portal tree to find the component on which this event would be based on or associated with. In my case it would be the department table component located under Set Up HCM > Foundation Tables > Organization > Departments.

Under "Component Level Event Mapping" section, select "enable" check-box, event name would be SavePostChange and select the Service ID created in the earlier step. Set sequence number to 1 and processing sequence as "Post Process". Save the page and that is it. 

Navigate to the department component make a change and save the page and verify that the custom application package peoplecode fires.


The PeopleCode Editor provides an Event Mapping button in the dynamic Application Designer toolbar. For an application developer, the Event Mapping button is a visual indicator of custom PeopleCode programs mapped to events of a component, component page, component record, or component record field. This button is not available for page level event mapping.







So opened component peoplecode of component DEPARTMENT_TBL and clicked on the button to produce the following output.
















Right-clicking on the application package code and selecting "Event Mapping References" in the pop-up menu as shown below should display the component but that did not work.













"Event Mapping References" tab is empty as shown below.












So I guess this might work in future releases or maybe I don't have something configured correctly for this to work.