The following is intended to outline my experience and exposure to PeopleSoft’s Technologies. This is not a training document. References in this blog have been compiled from various sources like Oracle webcasts, blogs, and prototypes that I have developed over time.
Monday, January 6, 2025
Taleo Web API - managing user groups in a user profile
Thursday, October 17, 2024
Uploading files to SharePoint Online
Here are the steps to upload files to SharePoint Online using PeopleSoft's services/service operations.
I am running PeopleTools 8.61.x and there are some properties that are discussed below that are only available in the latest tools release.
At a high level there are three steps
1. Generate Access Token
2. Using the access token generate Form Digest
3. Finally using both the access token and form digest upload file to SPO.
Service and Service Operation build
1. Created a Document Template (N_SPO_URI_TEMPLATE) with the following primitives defined as text.
TenantID, TenantName, SiteName, SPOFolder and FileName
2. Defined two non-rowset based messages - N_SPO_REQUEST and N_SPO_RESPONSE
3. Created a consumer REST service called as N_SPO.
4. Created three service operations all with REST method as POST -
N_SPO_ACCESSTOKEN_POST, N_SPO_FORMDIGEST_POST and N_SPO_UPLOADFILES_POST
For the service operation N_SPO_ACCESSTOKEN_POST the REST base URL is
https://accounts.accesscontrol.windows.net/ and template is {TenantID}/tokens/OAuth/2
For the service operation N_SPO_FORMDIGEST_POST the REST base URL is https:// and
template is {TenantName}.sharepoint.com/sites/{SiteName}/_api/ContextInfo as we cannot provide any variables in the base URL.
Finally for the N_SPO_UPLOADFILES_POST service operation, the REST base URL is https:// and template is {TenantName}.sharepoint.com/sites/{SiteName}/_api/web/GetFolderByServerRelativeURL('/sites/{SiteName}/{SPOFolder}/')/Files/add(url='{FileName}',overwrite=true)
All other settings are default settings.
5. Updated the integrationGateway.properties file as follows - (this parameter may be available only in the latest tools release)
ig.UseDomainName.ExternalOperationNames=N_SPO_FORMDIGEST.v1,N_SPO_UPLOADFILES.v1
Had to provide external operational service name for these two. The first one related to access token generation worked without having to define it here.
6. For the SPO site to which I want to upload the file, I need a Client ID and Secret, which is kind of like the user ID/password to make the connection. SharePoint admin can generate this. Value for &ApplicationID, &TenantID also provided by SharePoint admin. Value for variables like &TenantName, &SiteName, &SPOFolder derived by parsing the SPO URL to which I had to upload the file. &attachFileName is derived from the complete file path of the file to be uploaded.
7. Now comes the peoplecode part to invoke these service operations.
&Doc_Tmpl = &reqMsg.GetURIDocument();
&COM_Tmpl = &Doc_Tmpl.DocumentElement;
&reqMsg.URIResourceIndex = 1;
&COM_Tmpl.GetPropertyByName("TenantID").Value = &TenantID;
&bRet = &reqMsg.SetContentString("grant_type=client_credentials&client_id=" | EncodeURLForQueryString(&ClientID | "@" | &TenantID) | "&client_secret=" | EncodeURLForQueryString(&ClientSecret) | "&resource=" | EncodeURLForQueryString(&ApplicationID | "/" | &TenantName | ".sharepoint.com@" | &TenantID));
&bRet = &reqMsg.IBInfo.IBConnectorInfo.AddConnectorProperties("Disable_URLEncodingBody", "True", %HttpProperty);
&sResp = &respMsg.GenXMLString();
Tuesday, April 21, 2020
Creating JSON request for REST web services
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 message &request, &response;
Local boolean &bRet;
&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, December 23, 2018
JSON Parser
/* for Response 1, following will get status tag and its value */
/* for Response 2, following will get import_set, staging_table and its values */
/* this will return status and error_message which are in Response 2 */
/* this will return message and detail which are in Response 1 */
Wednesday, April 4, 2018
PeopleSoft web service response namespace issue
Request
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing/" xmlns:xsd="http://www.w3.org/2001/XMLSchema/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance/">
<soapenv:Header xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
</soapenv:Header>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<HelloWorld xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/HELLOWORLD.V1"></HelloWorld>
</soapenv:Body>
</soapenv:Envelope>
Response via PeopleSoft SOAP message template
<soapenv:Envelope xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsa="http://schemas.xmlsoap.org/ws/2003/03/addressing/" xmlns:xsd="http://www.w3.org/2001/XMLSchema/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance/">
<soapenv:Header xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
</soapenv:Header>
<soapenv:Body xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<HelloWorldResponse xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/HELLOWORLDRESPONSE.V1">
<HelloWorldResult>XYZ</HelloWorldResult>
</HelloWorldResponse>
</soapenv:Body>
</soapenv:Envelope>
Actual response via SOAPUI or Postman
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<HelloWorldResponse xmlns="http://peoplesoft.com/HelloWorldResponseResponse">
<HelloWorldResult>Success</HelloWorldResult>
</HelloWorldResponse>
</soapenv:Body>
</soapenv:Envelope>
As you see the the problem is the namespace value returned for the root tag "HelloWorldResponse".
<HelloWorldResponse xmlns="http://peoplesoft.com/HelloWorldResponseResponse">
PeopleSoft puts the default value (not sure where this is stored)
http://peoplesoft.com/HelloWorldResponseResponse
instead of what is defined in the WSDL which is
http://xmlns.oracle.com/Enterprise/Tools/schemas/HELLOWORLDRESPONSE.V1
I have a very basic synchronous service operation, with a request and response message and the handler OnRequest peoplecode is doing all the work.
Following was my application package peoplecode initially.
&response = CreateMessage(Operation.HELLOWORLD_SVCOP, %IntBroker_Response);
&xmldata = "<?xml version='1.0'?><HelloWorldResponse/>";
&xmlresponsedoc = CreateXmlDoc(&xmldata);
&HWResponseNode = &xmlNode.AddElement("HelloWorldResult");
&HWResponseNode.NodeValue = "Success";
&response.SetXmlDoc(&xmlresponsedoc);
Return &response;
So when creating the XmlDoc I was not specifying any namespace and I was hoping PeopleSoft will add it based on the schema definition.
Instead following is what I had to do to correct the issue. (only displaying the change, no change to rest of the code)
&xmlresponsedoc = CreateXmlDoc("");
&docTypeNode = &xmlresponsedoc.CreateDocumentType("", "", "");
&rootNode = &xmlresponsedoc.CreateDocumentElement("HelloWorldResponse", "http://xmlns.oracle.com/Enterprise/Tools/schemas/HELLOWORLDRESSPONSE.V1", &docTypeNode);
&xmlNode = &xmlresponsedoc.DocumentElement;
So I have to use the CreateDocumentElement method of CreateXmlDoc in order to define the namespace. In order to use this method I had to first initialize the &docTypeNode variable by using the CreateDocumentType method.
After making the above change the response comes back correctly.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Body>
<HelloWorldResponse xmlns="http://xmlns.oracle.com/Enterprise/Tools/schemas/HELLOWORLDRESSPONSE.V1">
<HelloWorldResult>Success</HelloWorldResult>
</HelloWorldResponse>
</soapenv:Body>
</soapenv:Envelope>
Saturday, March 26, 2016
Sending and Receiving MTOM-encoded binary data
&request = CreateMessage(Operation.SEND_OPERATION);
&MTOMFile = GetFile("C:\temp\document.xml", "R", %FilePath_Absolute);
&request.CreateNextSegment();
If (&request.SetContentString(&theBase64encodedString)) Then
&response = %IntBroker.SyncRequest(&request);