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.

1 comment:

Anonymous said...

Nice fill someone in on and this fill someone in on helped me alot in my college assignement. Say thank you you for your information.