Thursday, February 12, 2009

Badly-coded PeopleCode Fails Invocation of User-defined methods Through Web Services

I wrote a user-defined method in a PeopleSoft component interface (i.e. USER_PROFILE) which was exposed as a web services. But when I called this method from a web service client, I received below error:

The key UserID was not found in the request. (158,16017) PT_INTEGRATION.CIDefinition.OnExecute Name:setKeys PCPC:16560 Statement:306Called from:PT_INTEGRATION.CIDefinition.OnExecute Name:invokeUserDefinedFunction Statement:97Called from:PT_INTEGRATION.CIDefinition.OnExecute Name:OnEvent Statement:34

By using PeopleCode debugging, I traced the error to method setKeys of PT_INTEGRATION:CIDefinition and concluded it is the badly-coded PeopleCode that has resulted in the error.

Let's investigate the PeopleCode(partial) of method setKeys:


/* set the keys */
For &i = 1 To &ciKeyCollection.Count

&currentKey = &ciKeyCollection.item(&i);
&keyNotFound = True;

/* is there a corresponding element in the input XML? */

For &j = 1 To &rootNode.ChildNodeCount
/* NOTE: This is the bad code that causes the error! */
If (Upper(&rootNode.GetChildNode(&j).LocalName) = &currentKey.name) Then

/* the key is present in the XML */
&keyNotFound = False;

Local string &keyValue = &rootNode.GetChildNode(&j).NodeValue;

If (&keyValue = "") Then
throw CreateException(&ibMsgSetNumber, &emsgKeyValueNotInRequest, "No value found for the key %1 in the request.", &currentKey.name);
End-If;

/* set the key data */
&ciInstance.SetPropertyByName(&currentKey.name, &keyValue);

End-If;
End-For;

If (&keyNotFound) Then
throw CreateException(&ibMsgSetNumber, &emsgKeyNotInRequest, "The key %1 was not found in the request.", &currentKey.name);
End-If;

End-For;

The logic of method setKeys is clear: it tries to search the SOAP request for the component interface search key values and sets key values if the search succeeds, or throws an exception if it fails. For example, the search key of component interface USER_PROFILE 'UserId', method setKeys should be able to extract key value 'TESTUSER1' from SOAP request


<Method__CompIntfc__USER_PROFILE>
<UserID>TESTUSER1</UserID>
...
</Method__CompIntfc__USER_PROFILE>


However, things don't go as expected because of the following statement:


If (Upper(&rootNode.GetChildNode(&j).LocalName) = &currentKey.name) Then


This If-Then statement tries to compare a SOAP node with a search key name. You may have noticed the SOAP node name (&rootNode.GetChildNode(&j).LocalName) is formatted to upper case while the search key name (&currentKey.name) is not. It seems that the programmer assumed that the search key name was always upper case and so required no formatting, but how could he/she made such an arbitary assumption?

For component interface USER_PROFILE which I was working with, since the search key name happens to be 'UserId' instead of 'USERID', above comparison always gives a 'false' and the codes setting key values will never be executed, that is the reason why I saw error "The key %1 was not found in the request."

The resolution is simple, after modifying above statement as


If (Upper(&rootNode.GetChildNode(&j).LocalName) = Upper(&currentKey.name)) Then


the web service has executed properly.

Alternatively, the code can also be


If (&rootNode.GetChildNode(&j).LocalName = &currentKey.name) Then


but it is less safe obviously.

This code persists until PeopleTools rel 8.49.08. Hopefully Oracle will correct it in later release.

Tuesday, February 10, 2009

Scripts Listing Processes and Memory Usage of PeopleSoft Application Server and Process Scheduler

Sometimes I want to list all processes belonging to a PeopleSoft app/process domain. Although PSADMIN does provide some options for this purpose, none can satisfy me fully. For example:

./psadmin -c sstatus -d DOMAIN

- No JSH and WSH, also no PID (process id, which is important to me)

./psadmin -c pslist -d DOMAIN

- Shows PID, but no BBL, JSH and WSH

./psadmin -p status -d DBNAME

- No PID

Besides, I am also interested in the memory usage each process, but PSADMIN doesn't provide this kind of information too.

Therefore, I wrote 2 scripts in order to self-help. One is a shell script (view) runnable at Solaris. The other one is a VB script (view) runnable at Windows. A bat file (view) is provided as a wrapper to make the VB script run on and output to DOS commandline, it must reside at the same directory as the VB script.

Both scripts have similar syntax:

pl [-f] {-c-p-c -p} [-m [-h]] instance
Options: -f force execution even appserv domain doesn't exsit
      -c print processes of application server
      -p print processes of process scheduler
      -m print memory usage
      -h print memory usage in human readable format (only applicable to solaris version)


Sample output for running shell script:

$ ~/bin/pl -cmh DOMAIN
PID  PROCESS               VSIZE             RSS
---  -------               -----             ---
6431  PSSUBDSP             107.7M           92.5M
6430  PSPUBDSP             345.2M          161.5M
6397  BBL                   10.9M            8.9M
6407  PSSUBHND              99.7M           84.4M
6446  JREPSVR                8.9M            7.0M
6403  PSAPPSRV             514.7M          306.3M
8105  PSWATCHSRV            15.0M           11.9M
6429  PSBRKDSP             107.7M           92.5M
6402  PSAPPSRV             513.8M          297.5M
6442  JSL                   10.4M            8.4M
6401  PSAPPSRV             533.9M          317.6M
19680  PSMONITORSRV         102.4M           87.2M
6440  WSL                    9.4M            7.6M
6405  PSBRKHND             107.7M           92.5M
6406  PSPUBHND              99.9M           84.6M
6404  PSSAMSRV              97.4M           82.3M
6444  JSH                   12.8M           11.0M
6445  JSH                   16.0M           14.3M
6443  JSH                   16.0M           14.3M


Sample output for running VB script:
C:\WINDOWS\system32>pl -c -p -m DOMAIN
PID     Command         VSize   Working Set
---     -------         -----   -----------
5640    BBL             22.3M   5.8M
1764    PSAPPSRV        114.5M  43.1M
1692    PSAPPSRV        324.5M  81.3M
5856    PSAPPSRV        114.0M  42.5M
2448    PSSAMSRV        104.4M  40.4M
7060    PSANALYTICSRV   107.6M  41.0M
6556    PSANALYTICSRV   107.6M  41.0M
6364    PSANALYTICSRV   107.6M  41.0M
3348    PSDBGSRV        101.5M  37.3M
4592    PSRENSRV        79.4M   17.4M
8112    PSMONITORSRV    101.5M  37.6M
3984    WSL(7000)       24.3M   4.6M
4540    JSL(9000)       25.0M   4.6M
5452    JREPSVR         19.9M   3.9M
7292    PSSAMSRV        100.9M  37.2M
740     PSWATCHSRV      25.1M   6.7M

3840    WSH(7001)       23.9M   4.9M
820     JSH(9001)       24.0M   4.7M
6256    JSH(9002)       26.1M   5.5M
3164    JSH(9003)       24.0M   4.7M
6064    JSH(9004)       26.1M   5.0M
7732    JSH(9005)       24.0M   4.7M

PID     Command         VSize   Working Set
---     -------         -----   -----------
5552    BBL             21.7M   2.7M
5572    PSAESRV         109.9M  14.4M
5616    PSAESRV         109.9M  14.4M
5748    PSPRCSRV        130.8M  21.7M
7112    PSAESRV         303.4M  63.0M
7488    PSDSTSRV        282.0M  50.5M
5812    PSMONITORSRV    100.9M  37.6M


Update on 02/Oct/2009: the enhanced version of pl script (for solaris) is available here