Sunday, October 23, 2011

REST-like PeopleSoft Services

As you survey the consumer web service landscape, you will notice a shift: fewer SOAP based services and more REST based services. I will refrain from sharing my true feelings about WSDL and SOAP to share with you the important stuff: how you can make REST-like calls into PeopleSoft. If you are not familiar with REST, then I suggest you read the Wikipedia REpresentational State Tranfer summary and then follow some of the external links for additional details.

While there are implementation differences, at its core, the difference between REST and SOAP is the focus. The focus of SOAP is the operation, not the data. The focus of REST is the data. I find this difference most evident when working with a Component Interface (CI). With a CI, you set key values, call Get (or Create), change values, and then call Save. The entire time you are working with that CI, you are working with a single transaction instance. The focus of the CI is the state of the data. The operations (get, create, save) are secondary. Service Operations are exactly opposite. Service Operations focus on method execution. The data (the transaction in this case) is just a parameter. OK, maybe this isn't the "core" of the REST specification, but as one who has tried working with a CI in a Web Service Data Control, it is enough for me to want to throw out web services. Don't misunderstand me at this point. I'm not blaming web services, the CI WSDL, or the Web Service Data Control. I'm sure they all have their place in development projects. It is my experience, however, that they mix together like chlorine bleach and ammonia (please, oh please don't mix these two chemicals!).

There are several implementation details that differ between REST and SOAP. As a user interface (think Ajax) developer, my preferred implementation detail is the ability to call services with a URL as an HTTP GET or POST. Yes, you can make SOAP calls with JavaScript, but I find it a lot more difficult to package up a SOAP envelope with JavaScript than to just make an HTTP GET or POST with jQuery.

As noted by the Cedar Hills Group PeopleSoft REST Wiki, there is a lot more to REST than just URL's, and a true REST URL doesn't use Query Strings for parameters. If you want more REST, then you will have to wait for PeopleTools 8.52 or build something yourself (stand-alone REST gateway, MyRestListeningConnector, etc). If, like me, your greatest interest is executing Service Operation Handlers from URL's, then review the PeopleBooks HTTP Listening Connector. It contains the URL call specification for PeopleSoft service operations. With an "Any to Local" routing, the basic form looks like this: http(s)://my.peoplesoft.server/PSIGW/HttpListeningConnector?Operation=EXECTHISOPERATION. If you prefer, you can pass transaction keys, etc as query string parameters, and then read those parameters in PeopleCode. Here is how (assuming &MSG is the message parameter to your OnRequest handler):

   Local &connectorInfo = &MSG.IBInfo.IBConnectorInfo;
   Local number &qsIndex = 0;
   Local string &qsValue;
   
   For &qsIndex = 1 To &connectorInfo.GetNumberOfQueryStringArgs()
      If (&connectorInfo.GetQueryStringArgName(&qsIndex) = "THE_QS_PARM_NAME") Then
         &qsValue = &connectorInfo.GetQueryStringArgValue(&qsIndex);
      End-If;
   End-For;

No, I'm not fond of having to iterate over each query string argument either, but that is what the API requires. I packaged this up in a Query String helper class and create an instance of it for each request that uses query string arguments. Here is my Helper class:

class IBQueryStringHelper
   method IBQueryStringHelper(&connectorInfo As IBConnectorInfo);
   method getParameterValue(&parameterName As string) Returns string;
   
private
   instance IBConnectorInfo &m_connectorInfo;
end-class;

method IBQueryStringHelper
   /+ &connectorInfo as IBConnectorInfo +/
   %This.m_connectorInfo = &connectorInfo;
end-method;

method getParameterValue
   /+ &parameterName as String +/
   /+ Returns String +/
   Local number &qsIndex = 0;
   
   For &qsIndex = 1 To &m_connectorInfo.GetNumberOfQueryStringArgs()
      If (&m_connectorInfo.GetQueryStringArgName(&qsIndex) = &parameterName) Then
         Return &m_connectorInfo.GetQueryStringArgValue(&qsIndex);
      End-If;
   End-For;
   Return "";
end-method;

What about the result? Does it have to be XML? No. I have used two ways to create non-XML results from Integration Broker. The first is by creating a JSON response directly in PeopleCode. It is this use case that prompted me to write the PeopleCode JSONEncoder. A service operation handler can return non-XML by wrapping the result in a psnonxml attribute like this:

   Local Message &result_msg = CreateMessage(Operation.MY_SERVICE_OPERATION, %IntBroker_Response);
   Local string &json;
   
   REM ** Do some processing to generate a json response;
   
   Local string &nonXmlData = "<?xml version=""1.0""?><data psnonxml=""yes""><![CDATA[" | &json | "]]></data>";
   Local XmlDoc &doc = CreateXmlDoc(&nonXmlData);
   
   &result_msg.SetXmlDoc(&doc);
   Return &result_msg;

The second method I use to create non-XML results is through a transformation. Using XSL, it is possible to transform an XML document into JSON -- although JSON-safe encoding might be more difficult.

If you use a debugging proxy (such as Fiddler) to inspect the results of an Integration Broker response, you will notice Integration Broker always returns the Content-Type header value text/xml. Unfortunately, this means you have to help jQuery understand the results because it won't be able to determine the response type based on the Content-Type header. When PeopleTools 8.52 arrives at your office, you will be able to specify different MIME types. For now, I find it satisfactory to just set the $.ajax dataType parameter to "json." If you absolutely need to set the Content-Type header and don't have PeopleTools 8.52, then I suggest looking into a reverse proxy with header rewrite capabilities (Apache, for example).

No, unfortunately, this post didn't show you true REST. If you are choosing REST for Ajax because it is easier to make a URL based request to a REST service than to build a SOAP header to send to a Web Service (like me), then this post hopefully offers you enough information to get started. If you require more of the REST specification than I've shown here, then you will probably have to wait for PeopleTools 8.52.

165 comments:

Dan said...

I've been hacking RESTful services in IScripts using JSON.Simple to create the JSON response string. It's a very low overhead approach. My client is HTML/jquery/javascript served from the PS webserver so the security is taken care of.

Jim Marion said...

@Dan, yes, exactly. It is very similar to this approach in its REST compliance, but iScripts require a lot less meta-data configuration.

Sudheer said...

Hi Jim,

Is there a possibity to get windows login into peoplesoft.

Thanks
Sudheer

Jim Marion said...

@Sudheer, yes, the best way is to use the PeopleTools Kerberos SDK. It is a Java ServletFilter for your PeopleSoft web server that sends your desktop the appropriate challenge/response to get the logged in user's token, and then verifies that token against your directory server.

jb said...

Jim, I am working on an issue in 8.9 HR Recruiting. I am trying to understand how the Service Framework is put together with the Interface registry. I have traced the code back to an App package called HHR_MANAGE_COMPTNCY_SERVICES:Person:GetPersonTrainingHist_v1_0:GetPersonTrainingHist.
From here though, I am lost as to what this is doing, besides instantiating an object. Eventually, if calls a Service Manager.LocateService. Can you shed some light on how this works?

Jim Marion said...

@jb, I know exactly what you are talking about: the HR services registry. I'm sorry, I have little to know experience with it. I've seen some of the code, but only from the same perspective as you: searching for a solution as to why something isn't working the way I think it should.

Juan Sarro said...

Hi Jim,

I'm trying to develop a client for a service published trough PS HttpListeningConnector. My customer has provided an XML file, they tested the service importing the file in SOAPUI and sending SOAP messages to the service. in PS side the service perform operations like create a new user or add role to an user.

Please point me How to develop a client for this service (maybe an HttpClient like in your post "Generating an AuthToken for SwitchUser") please help me

Regards
Juan Sarro

Jim Marion said...

@Juan, there are a couple of ways to build a client. If you are using a CI based service or some other type of PeopleSoft service that has WSDL, then you can use one of the many, many developer tools for consuming WSDL.

If you want to just write a simple/basic program that sends data over HTTP to Integration Broker, then start with the HTTP URL for your service. You can paste this into a web browser to access your service. Next, write a program that speaks HTTP. If you are using Java, then use the commons-httpclient or even just the lower level URL and http connections.

Chandra said...

Thanks Jim for your post and tips and tools book. I learned lot of concepts from. I am working with a third party vendor on a integration. they are asking us to HTTPS POST a form with Name&value pair, in return they will send me a xml response. I need to use the contents form the XML and redirect url to their site. How do i approach doing this in peoplesoft. we have 8.51 tools.


I wrote an Iscript which response and html and java script.with the submit button, i am able to post the form to thirdparty url, I am not sure how to collect their response.
Appreciate your comments

Thanks
Chandra

Jim Marion said...

@Chandra, I believe the approach you took is a great way to post to a third party, but, as you noticed, once your browser sends the post to an external domain, you lose all control. That technique won't allow you to do anything with the response. As an alternative, you may want to attempt a server side POST. With a server side POST, your will write PeopleCode to POST those key/value pairs to the external site (Sync Request). Your PeopleCode will then receive the XML response. Integration Broker's HttpTargetConnector can handle POST. An alternative is to use Commons HttpClient.

Chandra said...

Thanks Jim for your quick response. I will try and let you know how it went.

Chandra said...

Jim,

Let me tell my objective again: third party is asking us to post some name/value pairs to their URL,
they did not give us wsdl and it is not a service. in return they will respond me with token, I use that
token to redirect the user to their website.

Based on your suggestion earlier,

I was able to come up with below code and it is posting the data
to thirdparty successfully, However, It seems thirparyt is not able to proces the name/value's from IB's post.

Both the name/value pairs in my reqeust are correct, I have validated by submitting them in simple html form
from my browser and i got the valid tokens. However, when i post via IB i am not getting the same result.

I have reviewd the synchoronous xml request log, it looked fine there, just name/value paris no xml/SOAP.
I am suspecting that IB is not sending the correct contect-type. I have set the content-type=application/x-www-form-urlencoded
both on Node and routing.

Is there any Fiddler like tool that i can use to see what IB is sending in terms of message's http header and
body ?

Or there any better ways you can think off. Please suggest me.


&encoded = "ENTITY_ID=" | &ENTITY_ID | "&REGISTRATION_ID=" | &REGISTRATION_ID;


Local string &nonXmlData = "";
&xmlDoc1 = CreateXmlDoc(&nonXmlData);

&Msg_Reqst [1].SetXmlDoc(&xmlDoc1);

&MSG = %IntBroker.SyncRequest(&Msg_Reqst [1], &Nodes_Reqst [1]);

Jim Marion said...

@Chandra, you may be on to something with the content-type header. I don't recall any way to set that other than through a reverse proxy sitting in front of IB. With apache in front of IB, you can change just about anything (using mod_headers, etc). PT 8.52 added more support for content types, but I don't think you could set the content-type before that.

Anyway, your other question: Fiddler. I use Fiddler with IB. I was actually going to suggest it and then read that you were asking about it. Here is what you do: Install fiddler on a Windows OS that your IB server can access and open Fiddler's options so you can enable external connections. Copy the host and port #. Modify your integrationGateway.properties file to use Fiddler's host and port for IB's proxy server settings. You may have to restart the IB web server for the settings to take affect.

I find fiddler to be the best tool for debugging IB and the process scheduler report posting process.

Another option for setting headers... if you find that the headers are your problem and you are not able to use a reverse proxy server, then another solution is to write a ServletFilter to modify the IB response as it leaves your J2EE web server (weblogic or websphere). The ServletFilter would be very simple. In your servlet filter, you call FilterChain.doFilter, and then you set the Content-Type header so that you are overriding the default. Of course, you would want to make sure you only do this for your service operation, so you will want to make sure you test the request (URL parameters, or something that identifies your service).

Chandra said...

Thanks Jim for all your suggestion. every time i speak to you I realize that i how much i don't know :). On my Issue, I was able to resolve the issu by post the name/value pairs in my query string itself. I am lucky in this case, I don't have to post more than 256 chars.

Jim Marion said...

@Chandra, we are all students. I learn from my readers as well.

Yes, if you can use the query string GET form instead of an HTTP post, that is MUCH, MUCH easier.

DarkPadawan said...

@Jim I know this is and old Post but I have a few questions on 8.52 tools support for REST Services. First of all it looks like PeopleSoft only recognize HTTP status codes in the 200. Which does not make sense since HTTP status 401 is a valid response and if the 3rd Party service returns that I get a message saying there is a network problem accesing the URI. Second is the JSON Response. Is there a way for me to get the RAW Body of the message as a String? this might not be important since without the HTTP status codes I see the proxy in front IB as the best solution.

Thank you for your help and I love your blog an books ;)

Jim Marion said...

@Dark, I'm not sure if your scenario has PeopleSoft as the producer or consumer.

I haven't worked with HTTP status codes. If PeopleSoft is the producer, I'm not sure how you would set a different response code. If PeopleSoft is the consumer, then you should be able to determine the HTTP response code from the message HTTPResponseCode property.

The message class has a handful of methods for accessing the message content. I think the most generic is the GetContentString method which returns the content of the message in plain text. This is most likely what you want if the response is JSON.

I have worked a LOT with JSON from PeopleCode. When PeopleSoft is configured as the producer, some other system sends a synchronous request to PeopleSoft. Your REST service operation will have an OnRequest handler and that OnRequest handler runs whenever PeopleSoft receives a request from an external system. This OnRequest handler can return any kind of data (JSON, XML, CSV... anything). One of the great features of PT 8.52 is the ability to set the response content type and use the SetContentString method to return a non XML response. With prior releases of PeopleTools, you have to wrap the response in XML with an XML tag that has the psnonxml attribute.

Unfortunately, as of 8.52 PeopleSoft does not yet natively produce JSON. You can produce JSON, it just isn't native. You have to string a JSON response together using your PeopleCode OnRequest handler. This is why I wrote a JSON Encoder PeopleCode App Class.

As far as consuming JSON, I find the easiest way to parse JSON is to use the json.simple JSON parser. It is my favorite, and the one that I document in my book. Another alternative is the json.org parser along with this App Class JSON helper.

I hope some of this helps. Let me know if I misunderstood the question.

Jim Marion said...

I received some feedback from @DarkPadawan saying if the external service returns anything other than a 20x code, the result/response message from the external system will be Null and Integration Broker will through an Integration Gateway - External System Contact Error (158,10721). That is too bad. I suggest someone enter an enhancement request to have IB send this information through to the PeopleCode.

Fortunately, IB isn't the only way to call external services. I haven't written a PeopleCode version of this, but here is some Java that shows how to make an HTTP Request: http://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html. You would just have to convert it to CreateJavaObject and GetJavaClass calls. Another option that I find easier is to use Apache Jakarta Commons HttpClient. No, this alternate solution does not have the queuing and management facilities of IB, but it does get you connected. I wish I had a better answer, but worst case, there is always the Java, Windows, or Linux API's.

Karthik said...

Hi Jim,

Hope all is well.

We have a req to do an HTTP Post to a third party system. I was able to do this with iScripts - Created a html form and in the post url - I gave the third party URL. Once we submit the form, it goes to their URL, our user is expected to enter some more parameters and when they finally hit Submit, the third party will do a POST back to a return_url which we sent in the first POST. So for the return URL, I gave them an iScript URL and used %Response.GetParameter function in the iSCript code to obtain the values.

Questions:
How secured is this method? Do you see any security concers with this approach?
As an alternate, I created a ASync Service Operation(with Any to Local routing) and gave this as the return_url for them to POST.On the OnNotify peoplecode, using &_MSG.IBInfo.IBConnectorInfo.GetNumberOfQueryStringArgs() I am able to get the values they were posting. But the issue is, once they submit the form, the browser returns the MIME XML response success message for the Service Operation. I dont think it makes sense to display this to the end user. Is there a way to take control of this and just print, "Posted Successfully", etc.,

So please let me know the recommended approach for this - iScript or the HTTP Listening Connector method..

Thanks so much...

Jim Marion said...

@Karthik, either approach is fine security-wise. The iScript uses the logged in user's PS_TOKEN cookie. Just make sure you have appropriate validation on query string parameters and that you appropriately secure the iScript or service operation through permission lists.

To gain control over the IB response, use a Sync rather than Async service operation. Sync is request/response and lets the PeopleCode finish before returning a response. This lets you build the response. Just be sure to use the psnonxml attribute as described in this blog post so you can return HTML.

suryavel said...

hi,
we are doing outlook integration proj.While we try to integrate peoplesoft CRM 9.1(PT8.52) with a 3rd party system(BDSS-business data synchronising server) through integration broker, in this process we provide web services.Now we are able to conect with exchange but not with peoplesoft.Is there any thing to b configured in IB so it connects with peoplesoft??

Jim Marion said...

@suryavel, you may want to post your question on the OTN forum or in ITToolBox.

Carl said...

My post relates to Jim and DarkPadawan's discussion regarding HTTP status codes. In my scenario, Peoplesoft is the consumer of a third party REST provider, and I agree it is too bad that IB reports an ERROR with any non 20X HTTP response code.

What's worse is that there is no way to access the response message once IB considers it an ERROR. I've created an enhancement request with Oracle to address this.

In the mean time, I suppose I will look into the Integration Broker Connector SDK despite my heavy anticipation of true REST support within 8.52.

Bijay Bhushan Singh said...

hi jim,
i am creating non ci based web service using application package. and i created some wsdl for some delivered peoplesoft campus solution.
for consuming i am using soap tool.can u just tell me how can we add role level security during the creation of wsdl.please suggest me how to add role level security in wsdl. thanks in advance

Jim Marion said...

@Bijay, did you mean row level instead of role level? All CI's are role level because you have to connect a CI to a permission list and role in order to execute it. Row level is handled by the component business and SQL logic behind the CI, not by the WSDL. A WSDL is just a definition identifying operations, parameters, target location, and type of authentication required to execute the service operations identified by the WSDL.

Bijay Bhushan Singh said...

thanks jim for reply,
sorry but really i am very new to web sevices.i want to provide role level(not row level) security in ci based and non ci based both type web services. for testing purpose i am using soapui tool. is there any way to give security like role is manager then he can see these data(in response).so in peoplesoft during creaton where we can assign security like this. as i read in xml message schema i think but i am not able to get it clearly
thanks in advance.

Jim Marion said...

@Bijay, not in the WSDL, but in the underlying component itself. In the RowInit event or other initialization event, you can determine what data to display based on IsUserInRole results. Likewise, you can join to security views to limit the data visible based on role membership.

Kedar said...

Jim,

I want to use ajax and send JSON from an external client to Peoplesoft, and then return a value back to the client from Peoplesoft, using a Message/Integration Broker.

I read your various posts about JSON in Peoplesoft. I kind of understood how to return the JSON in a CDATA section using psnonxml in the header, although I have not implemented it yet. But am still not sure how Peoplesoft Integration Broker would accept JSON, or non-xml data sent by the ajax on the client side.

Could you please explain or provide some help regarding this?

Thanks,
Kedar

Jim Marion said...

@Kedar, I have not yet had to post JSON data to Integration Broker. Fortunately, I've been able to fit everything into the query string.

Fortunately, integration broker accepts unstructured data. Just make sure to use an unstructured message for your service operation.

Your next hurdle will be reading the JSON data with PeopleCode. I For this, I recommend using JSON.simple.

Unknown said...

Hi Jim,

Thanks so much for keeping up the blog! I realize this is an old post but I thought I'd at least give it a try.

We have a requirement to send an http post that consists of a URL plus a number of parameters to be used as a query string. We have successfully accomplished this via iscript online but also have a nightly batch requirement via app engine.

We tried creating a REST service using the document message structure. Setup was an adventure as the service ended up defaulting to synchronous? When we try a .publish for example, we are getting a message that no queue exists - which is true. We have no way of adding a queue to the particular service.


When we use the service tester, it appears to work correctly. However when we run through an app engine, the logs generated appear to perform a GET - rather than a POST?

Are we overcomplicating this?

Any insight would be appreciated.

Thank you,


-Brian

Jim Marion said...

@Brian, By definition, REST is synchronous.

If you are posting from an App Engine to Integration Broker, then I think the easiest way would be to use standard/old 8.42 PeopleSoft rowset-based message structures. That way you don't have to figure out how to post or move data into message structures. You can just use CopyRowset.

Jim Marion said...

@Brian, I was going to ask you if you changed something to attempt to make a REST service asynchronous and that is why you were seeing a queue message. Queue's are only relevant for asynchronous service operations.

Unknown said...

Jim,

Thanks for responding so quickly. Yes we tried a peoplecode command reserved for asynch I believe (&msg.publish) once the message (&doc) tied to the Restful service we created was intantiated. That is when we got the queue message - and now I know why thanks to you.

Our issue is that our third party in this case cannot handle a standard integration message structure. They require a basic http post only.

Now understanding that RESTful by definition is synchronous, I assume that invoking that type of service in a batch program - i.e app engine would also not work.

I fear we may be faced with creating our own java class or target connector perhaps to solve what honestly we thought would be an easy problem.

As mentioned before we are able to post fine using iscript online. Now we need to batch up a number of files and post URL's to another system - a document repository for example. The post should be nothing more than a URL with query strings appended.

I really appreciate your taking the time to respond.

Thanks,

Brian

Jim Marion said...

@Brian, here are a couple of other options:

1. Use an XSL transform to convert the outgoing standard Async PeopleSoft XML document into a key=value form field pair.

2. Use a PeopleCode transform to do the same as #1, to make sure the result is www-form-urlencoded.

Also, what is wrong with using a Sync Request in your App Engine? It will block while waiting for a response, but that should be OK. This is how your browser works.

selvakumar said...

Hi Jim,

How can we call a third party REST based web service (via URL with query strings) and receive the response? We are in tools 8.49 and consume web services supports only SOAP based services.

Please bear with me as am new to web services.

Jim Marion said...

@selvakumar, You can make a synchronous request from PeopleCode using %IntBroker.ConnectorRequestURL. The link has a good example. The return value is a plain string.

M Asim said...

Hi Jim
I am new to web services and I am trying to publish Provide web Service(with SOAP). I have done all setting right as I know from oracle document.
But I am getting following error while testing it on SOAP service test tool.

Integration Broker Sync Handler: OnRequest for message CUSTOM2 could not run to completion on node PSFT_HR. (158,974)

Any Help related this error please.
Thanks

Jim Marion said...

@M Asim, run the test and then look in your app server log. If you don't find the answer there, then look in the PSIGW web app folder for msgLog.html and errorLog.html. If you still don't find the answer, then increase the log level from the domain advanced configuration page.

BS said...
This comment has been removed by the author.
Jim Marion said...

@bharat, I am not familiar with Qualtrics. Integration Broker has no problem creating HTTP requests with the HttpTargetConnector, so I would suspect it would have no trouble making requests.

ChicagoMom said...

Hello Jim,

I start to read your articles; read the responses/comments and realize how REALLY smart you are and how little I REALLY understand.

Thank you for sharing all that you know.

Yvonne

Thirumal said...

Hi Jim,
I was working on RESTful web services in PeopleSoft with Tools 8.52. Client wants JSON to and from PeopleSoft. We tried different options and finally using GetContentString([SegmentIndex])to get the JSON from the HTTP request. Just thought of sharing this so that it will be useful to others.

Regards,
Thirumal

Jim Marion said...

@Thirumal, thanks for sharing!!

SK said...

I am trying to send the response received from a punchout requisition to a third party application. I would like to capture the xml being returned by the direct connect service operation and then send it to a third party application even before the requisition is saved. Any ideas on this?

Jim Marion said...

@SK yes. Create a PeopleCode transform on the inbound routing. This will trigger before the handler. You don't actually have to transform something, just use it as a hook.

SK said...

@JIM When the response is generated by the punchout it transfers to PV_DC_Catcher page where the page activate code triggers to capture the response.It is a synchronous operation but I do not see a inbound routing for this. I can see the response in the code but trying to send this response as part of another service operation...Thanks

Jim Marion said...

@SK, I didn't think about it being synchronous. In that case, you set your transform on the synchronous outbound routing response message.

SK said...

I may not have asked the question correctly..

The synchronous service is as follows:
PS --> Vendor (request)
Vendor --> PS (response)

Need to catch the response and send a response to another third party system..The third party system uses IB in the backend to perform the punchout and capture the response.

I cannot set the transform on the outbound routing as it would not have the earlier response in the buffer..Sorry for the trouble..

Jim Marion said...

@SK, I understood. With a sync service (inbound or outbound) you only have one routing, but that routing has transforms for both the request and the response. In this case, I assume you have an outbound routing (Local to Any?) where sender is your default local node and the receiver is Any, or some other named node. In the routing Parameters, you will see a transform for the request and a transform for the response. You can capture the entire response in that response message transform and do whatever you want with it: send it somewhere else, change it, delete it... whatever.

SK said...

Hi Jim

Thanks for all the comments.

I am trying to close the response window once the service operation is successful. Can we accomplish this through peoplecode?

Jim Marion said...

@SK, I am not familiar with a response window.

SK said...

I was referring to the response window generated by IB for synchronous or asynchronous services. Can we close this window through Peoplecode?

Jim Marion said...

@SK, web services are transparent. There is a request and a response. I am not aware of a window that opens. web services don't even expect you to be running in a browser, so they have no way of determining how to open a window.

Perhaps you can post a screenshot somewhere and provide a link here?

NP said...

Dear All,

I wanted to send the Sync message. For that i created the message strcuture through CreateXMLDoc method, however got the Target connection error because the third party system requires soapenv: Envelope. Now i am using the SOAPDoc method but i am unable to construct the same structure through it. This is my structure:
+++++++++



















123


1

+++Plz help

Jim Marion said...

@Nitish, you have to escape XML before pasting it into the comment editor.

I've done the same thing as you, but the way I did it was to take the SOAP XML and place it in an HTML Definition with HTML bind parameters for real data values. Then you can just use GetHTMLText to replace the tokens.

Unknown said...

Jim,
We are integrating PS recruiting with external vendor for backgroundcheck process.
As the vendor is not peoplesoft certified I created xsl files to convert peoplesoft xml to vendor xml and vice versa. It works great for PreEmploymentCheck transaction as we able to send request and receive response.

I have an issue with PreEmploymentStatus as I don't understand if we provide query string with webserver port and to node and messagename will they be able to send their results xml to our PeopleSoft Node.
Is this a standard integration process or is it only because of OIF.

Jim Marion said...

@Kirthi, yes, in theory, if you provide someone a URL for them to execute a web service, they will be able to do so. PeopleSoft was designed for use in this manner. The part left to a customer's implementation is network access. Whether or not the vendor can send you data through this service depends on whether your vender has network access to your PeopleSoft instance.

Dave Horne said...

Jim, I've been trying to use REST web services by passing in a usertoken to be used for authentication without using Peoplesoft security like is defined in a SOAP request using the WS_Security model; but it appears that it's not available yet. I've been told by some Oracle engineers to put the information in the Request Header and then pull it out in Peoplecode in the app class. However, I can't seem to find a way to retrieve the REQUEST header information; there's one comment in Peoplebooks that says: Note: "No HTTP properties are currently applicable for REST and will be removed by Integration Broker." Does this mean there is no way to retrieve header info from the request msg? If this is correct, is there another way you can suggest in getting the usertoken through to Peoplecode without having the user token in the URI or in the Message Body?

Jim Marion said...

@Dave, I do not. I had heard at one point that it would read the PS_TOKEN cookie, but I just tested it and didn't find that to be the case. I also heard something about using the token with the authorization header, but haven't tested that either. Of course, as you know, as soon as you get the token into PeopleCode, you can use SwitchUser.

Dave Horne said...

Jim, That's exactly what I want to do, but as you see; there seems to be no way to access the header. I have found that it is coming through the IB and being stored in the IBInfo Blob, but I can't see anyway to retrieve it. If I retrieve the log for the synchronous message (blob) I can see all of the &ltheader&gt tags, but I just can't seem to find a way to read it while in Peoplecode. Without this functionality we can't switch from SOAP to REST. Hope to find a solution soon.

Jim Marion said...

@Dave, I checked with an Integration Broker expert. Since you are already doing this with SOAP, I suspect you already checked IbConnectorInfo's GetConnectorPropertiesName, GetConnectorPropertiesValue, GetConnectorPropertiesType, GetNumberOfConnectorProperties properties? You have to iterate over them until you find the right one.

Jim Marion said...

@Dave, I just watched a presentation from David Bain given to the Quest user group. He showed a screenshot of service operation security that included PeopleSoft Token and PeopleSoft Token w/SSL as security options. Perhaps that is targeted for a future release? I don't have that option in my PeopleTools 8.53 instance.

Jason said...

Jim,

I'm trying to set up an integration scenario where PeopleSoft trusts my external authentication source (through some signed or shared secret method) and will execute the service operation in the context of a user I specify in the message (HTTP Header or some such). With SOAP I'd use Signed UsernameToken or SAML for this, but the service I'm calling is delivered as REST. There is a SOAP equivalent, but I'm also using a delivered client that expects REST and don't want the maintenance of translating back and forth.

Any options you'd suggest for trusting that the user has been externally authenticated on a REST service?

Jim Marion said...

@Jason, REST uses the Authorization header. Usually this is implemented as basic auth over SSL. You will see this option in the REST service operation definition. Then you use the authorization header to pass credentials. Most libraries, etc will have an option for a username and password. If they don't, you just base64 encode username:password. You can find plenty of examples online.

Unknown said...

@Jason - We are attempting you have stated above regarding having a third party Authentication and trust that throughout the REST service. Can you share if you managed to get that working and the steps you used?

Jason said...

@Jim - Unfortunately I've been unsuccessful so far and have fallen back to allowing Peoplesoft to directly authenticate the username/password through custom signon peoplecode. I'm also working an SR with Oracle that I believe is trending in the direction of an enhancement request as we've not found any way to access any of the HTTP context (headers, cookies, extra path info, etc) from the context of signon peoplecode when calling a REST service.

Jim Marion said...

@Jason, that is correct, Integration Broker does not give access to the HTTP transactional information. I find this regretful. There are many times where I wish I could access the HTTP request and response headers.

Syed Usman said...

@Jason -- Could you put some light on how are you using custom signon PeopleCode(PC)for authentication, as I am also trying to authenticate user via custom signon PC for REST web service.
My user is being prompt for user name & pwd on browser but it is being authenticate from PSFT PSOPRDEFN table, not from our custom signon PC.
Any hint?

Jason said...

@Syed - From what I've found there could be a couple of issues here.

The ability to execute SOPC for IB web service calls was not working if the username you're trying to use doesn't exist in the PSOPRDEFN table on some tools versions. My understanding is 8.53.12 and 8.52.21 have a fix for this and that it will also be fixed in 8.54 when that is released. If you're not on one of these later tools versions, the OPRID has to exist in PSOPRDEFN for the SOPC to even get called.

Beyond that, ensure that you have set the Invoke As user in your Signon Peoplecode setup. Without this set, SOPC will attempt to execute in the context of the user who's logging in - which won't work if the username isn't in PSOPRDEFN.

Hope that helps

Syed Usman said...

@Jason - Thank you for this insight.In my case userid does exist in PSOPRDEFN table and the pwd is not matched with PSOPRDEFN that is why our SOPC fired when user login via common PIA login page but for REST web service prompt user/pwd page it won't go in SOPC. Does tool version issue means PT only auth from PSOPRDEFN table and then stop further verification like SOPC?

Jason said...

@Syed - I believe the tools version issue would cause this issue. When I turned on appserver tracing I never saw the SOPC execute on a rest call before we installed the proper patch version.

Because my application's usernames don't exist in PSOPRDEFN though I can't recall if I replicated your test exactly. I'd suggest turning on an appserver trace (has to be for the whole appserver - I haven't found a way to just turn this on for IB) and see what you get. If you're not on one of the recommended tools versions though you may want to try that in a sandbox first - pretty easy to do now with the PUM images being released on VirtualBox.

Unknown said...

Hi Jim,

I do not have prior experience working with PS IB. However, in an attempt to create an opportunity to learn it, I am trying to build an integration between LinkedIn and PS Recruiting, wherein an applicant's profile information is obtained from LinkedIn as an XML via HTTP POST. (LinkedIn Plugin called "Apply with LinkedIn"). In its basic form the code is as below (provided by LinkedIn)

HTML Header - loading the LinkedIn Javascript:

src="//platform.linkedin.com/in.js" type="text/javascript">
api_key:


HTML Body invoking script:

type=IN/Apply data-url="http://my.company.com/rest/jobPostingXml" data-urlFormat="xml" data-jobTitle="Test" data-companyID="xxxx"

If instead of data-url I used the data-email parameter, I would receive an email with the applicant's LinkedIn profile. How can we receive this JSON or XML from LinkedIn to store within our PS DB? What would the data-url be? I'd like to ultimately create an applicant a profile within PS DB and refine the profile/resume parsing function. I know this is pretty basic, but a push in the right direction or a high level idea of how to solve this, would really help.

Jim Marion said...

@Pratiba, do you have an external facing URL for Integration Broker? Have you created a service operation and handler? If so, the URL would be the service operation's URL. Alternatively, you can send it to an e-mail and use the POP3/IMAP connector to access information from an inbox.

rajchek said...

@Jim - Can we send Query String Arguments via URL for a PUT method?

I am sending Parameters via Url and unable to read these using &_MSG.IBInfo.IBConnectorInfo.GetNumberOfQueryStringArgs()method in peoplecode. This method returns 0. Used SOAPUI for testing the PUT. I put a return msg showing the Query args passed in the url and the return message shows blanks for the query string ars.
Any idea about this? Thanks for your help.
http://xyz.com/PSIGW/RESTListeningConnector/DAIDUpdPut.v1/?DAID=123456,ACTIVE=Y,EMAIL=xyz@xyz.com

Jim Marion said...

@Rajcheck, what tools release? Is this before PeopleSoft REST support? I'm not sure PUT was supported before tools supported REST. Did you try GET and POST?

rajchek said...

Thanks for the response Jim. We are using tools 8.52. I used URI Document function. GetURIDocument().GetElement and is working after bouncing the server. Intially both were returing blanks. The &_MSG.IBInfo.IBConnectorInfo.GetNumberOfQueryStringArgs()method still does't work. not sure why. But for now I am moving on with GetURIDocument.

Thili said...

Jim - We are implementing REST services for a requirement. We are facing some certification issues when we try to connect our target server. So we plan to Ignore if there are any invalid certification errors. Is there any way we can do?

Thanks
Thilipan

FoggyRider said...

Jim,

Can ci-based web services (non-rowset) have node to node routings or are they limited to any/local?

Thanks,
Gary

Jim Marion said...

@FoggyRider, yes, they can have node based routings. You can disable the Any to local and just use node specific routings. This would be more secure.

Dave Horne said...

Jim, here is a followup on accessing the REST Header information. As the entire IBInfo information is stored in a CLOB field; I was able to extract it into an XML document. You can add header information on the REST Get request which is stored in the IBInfo package. You can then search for header info after it is moved from the CLOB to the XML document. This has been working well as we can also use the header information for security as well as adding other header parameters like allowing the Accept parameter to allow the user to choose how they want the response document returned, xml, json, text, etc.

However, we have now run into a snag. This appears to only work for the GET operation as when defining a POST information it appears that somewhere along the line PeopleSoft is removing the information all together from the IBInfo log document. The Header information is there if you do a POST with no content; however, if you do a POST and supply content in the body of the message, PeopleSoft, or something along the way, maybe the Gateway, is removing the Header so all that you have in the IBInfo document is the tag. Seems strange that this critical piece of information would be removed when you provide content in the body. Where else would you put the content for a POST?

Do you have any ideas what could be causing the removal of the header info in this case?

Jim Marion said...

I did not think you could get at header information such as accepts, authorization, etc, so I am not surprised. I wonder if a custom listening connector would pass the headers through.

Kunal Masurkar said...

Hello Jim,

I have a requirement where we just need to consume response from an external system into peoplesoft.

External system is non peoplesoft and is a system that process a request form initiated by user via web portal. Once system has done what it is suppose to it will send a response to peoplesoft and i want to store that response into peoplesoft.

Any help around this as to how to do that would help. External system folks tell me there wont be any request from peoplesoft since they will be sending response as soon as they are done with processing in their system.

Also is peoplesoft able to receive and parse spml response....?

Thanks,
Kunnu

Jim Marion said...

@Kunnu, It is my understanding that SPML is just XML. If that is the case, then yes, you can process that with PeopleCode and Integration Broker.

Unknown said...

Hi Jim,

Can you please let me know how I would be able to Create a REST based web service with JSON Response, through Document Type Request and Document Type Response, without using the function like GenJsonString()and SetContentString().

As for the Non-rowset based response I am able to publish the response JSON Message through the using of these two functions, but when I am using Document type Response I am not able to publish the integration broker response through Application Package OnRequest method.

What would be the best possible approach for doing it.

Jim Marion said...

@Arnab, if I understand correctly, you want to use the Document object in PeopleCode to avoid using SetContentString. First, define your service operation to return JSON and make sure it is based on a Document. In your OnRequest handler, use PeopleCode like this:

Local Message &response = CreateMessage(
Operation.BMA_PERS_DIR_SEARCH_GET, %IntBroker_Response);
Local Compound &responseCom =
&response.GetDocument().DocumentElement;
Local Collection &items = &responseCom.GetPropertyByName("RESULTS");
Local Compound &resultItem;
Local boolean &result;

...

While &cursor.Fetch(&emplid, &name, &nameSrch);
&resultItem = &items.CreateItem();
&resultItem.GetPropertyByName("EMPLID").Value = &emplid;
&resultItem.GetPropertyByName("NAME").Value = &name;
&resultItem.GetPropertyByName("LAST_NAME_SRCH").Value =
&nameSrch;
&result = &items.AppendItem(&resultItem);
End-While;
Return &response;

Note: This code comes from chapter 8 of my latest book PeopleSoft PeopleTools: Mobile Applications Development (Oracle Press)

Unknown said...

Hi Jim,

Thank you for the quick response.

I am following the same process as you have mentioned but I am getting an error like :


Error Message :

"Integration Broker Sync Handler: OnRequest for message xxxxxxxxxxxx_GET could not run to completion on node" .


Description :

"The OnRequest event for the specified message could not run to completion on the specified node. See logs for details."



Below is the code snippet I am using :

{For My code there is no compound or collection peer, all of them are primitive peer (as for initial test case)}


For Request : I am having emplid and

For Response : I am populating State and Country from the database of the respective employee.


Code Snippet in the OnRequest Method of the Application Package :


Local Document &DOC_REQ, &DOC_RES;
Local Compound &COM_REQ, &COM_RES;
Local string &COUNTRY, &STATE, &EMPLID;
Local Message &response;



/* For Reading data from the input*/

&DOC_REQ = &MSG.GetURIDocument();
&COM_REQ = &DOC_REQ.DocumentElement;
&EMPLID = &COM_REQ.GetPropertyByName("EMPLID").Value;

/*Getting the values from the Database using SQLExec as per the data entered*/

xxxxxxxxxxxxxxxxxxxxxxxxxxxxx


/* Service Operations Name */

&response = CreateMessage(Operation.xxxxxxxx_GET, %IntBroker_Response);

&DOC_RES = &response.GetDocument();

/* Generate the element of the document type RESPONSE MESSAGE*/
&COM_RES = &DOC_RES.DocumentElement;

/* Populate Document Template RESPONSE MESSAGE with the data*/

&COM_RES.GetPropertyByName("EMPLID").Value = &EMPLID;
&COM_RES.GetPropertyByName("STATE").Value = &STATE;
&COM_RES.GetPropertyByName("COUNTRY").Value = &COUNTRY;


Return &response;



For the response message in the service operation I am using the content-Type as "Application/Json".

Could you please let me know how I would be able to handle it.

Jim Marion said...

@Arnab, your code looks normal. Try printing to a log file so you can identify the location of the error. You will want to check your &EMPLID and the SQLExec.

Unknown said...

Ok Jim, I will print the error to a log file and let you know. Thank you.

Mark said...

Hi @Dave,

Would you be able to provide some more information on how you were able to transform the IBInfo into an xml document and then search this to get the header info?

"Jim, here is a followup on accessing the REST Header information. As the entire IBInfo information is stored in a CLOB field; I was able to extract it into an XML document. You can add header information on the REST Get request which is stored in the IBInfo package. You can then search for header info after it is moved from the CLOB to the XML document. This has been working well as we can also use the header information for security as well as adding other header parameters like allowing the Accept parameter to allow the user to choose how they want the response document returned, xml, json, text, etc."

We are also trying to access a request http header value provided as part of a GET REST request but are currently unable to do so even though we can see the header value in IBInfo.

Any help would be greatly appreciated.

Thanks,
Mark

Shiva said...

Hi Jim,

Hope you are doing good.
Can you please guide me to resolve an issue which i am facing?

Issue is I am trying to connect to a third party REST service which is having a "https" protocal, for this I am getting a generic IB error "Integration Gateway - External System Contact Error". But, if I open the same URL which is prepared by peoplesoft in a browser I am getting the response. So, I thought the problem lies in the peoplesoft server.

1) Do we have to install SSL certificates for this?
2) Enable the https target location for the same in service configuration?

Even if try to ping the URL using ConnectorRequestUrl method am getting the same issue.

where can be the problems lies?

Thanks,
Shiva.

Jim Marion said...

@Shiva, great question. Even though your web browser can connect, it doesn't mean your server can. Your web browser may be configured to use a proxy server and your workstation likely has network routes that let you connect outside your corporate firewall. That isn't necessarily true of a server in your data center.

If you are able to connect and it is just an SSL issue, then you will see something about SSL Handshake failure or some other clue about SSL in the Integration Broker error log. Be sure to turn up logging in integrationGateway.properties before testing.

Unknown said...

Hi Jim,

I would like to get a help on Rest based web service in Peoplesoft.
I have used the GET and POST method using content type as xml and json.
But here a different scenario where I need to pass the values as form-url encoded to third party Java Systems.
I have created the Service Operation with Post method as follows:
1)gave the last word of URL in the URI field since it is a required field.
2)I have entered the URL gave by third party in the URL field provided
3)Nothing in document template
4)Entered the Request and Response message with xml content type and tried with plain Content Type.The Content type url-encode was not there in the drop down.
5) I have entered the header property as Content type as application/x-www-form-urlencoded

I have tried passing the values through peoplecode and used SyncRequest methos.
I am getting the error 401-UnAuthorized followed by 403.
Please provide me your valuable comments

rajchek said...

Hi Jim,

Is possible to implement SAML security for REST WS using JASON? If so how do we pass the authentication tokens. We are on peopletools 8.54. Peoplebooks only talks about implementing using SOAP. Thanks for your help.

Raj

Jim Marion said...

@Rajcheck, You may want to ask this question in the PeopleSoft OTN discussion forum.

savvy said...

Hi Jim,
I have a requirement where my client is trying to access some Peoplesoft HCM pages on an android mobile device through an app created by a 3rd party. I am responsible for providing the web services to that 3rd party. There's a page for viewing Payslips that has hyperlink to show payslip in pdf format. The pdf are stored on an ftp server. Now, I need to provide the web service for this page so that the pdf can be downloaded on the mobile device. How can this be done without compromising on the security of the page as client doesn't want 3rd party to have unauthorized access to payslips being generated. (PT 8.52)
Thanks in advance.

Jim Marion said...

@savvy, I do not have a simple answer for you. Securing pay slips is very important. I suggest you think about how to secure the REST service (username/password over SSL/TLS or PeopleSoft token?) and also how to transfer the PDF through the REST service response. Next, you will want to consider the security of the PDF file on the device.

Unknown said...

Hi Jim,

I am using actual REST services to respond with HTML.

I am trying to get the response to include a URL for another REST service.

Within my code, I am doing the following:

Local Document &docLink;
Local Compound &compLink;

&docLink = CreateDocument("PT_Lookup", "XLAT_Lookup", "V1");
&compLink = &docLink.DocumentElement;
&compLink.GetPropertyByName("LookupFieldName").value = "RUNSTATUS";
&compLink.GetPropertyByName("LookupFieldValue").value = "7";
&sLink = %IntBroker.GetURL(Operation.PTLOOKUPXLAT_REST_GET, 1, &docLink);

However, the %IntBroker.GetURL line seems to be causing me some issues.

The above code causes me to receive a "500 Internal Server Error", but if I comment out the %IntBroker.GetURL line, then the code works just fine (obviously I don't end up with a URL I can pass into my HTML in that case).

I am not sure what is causing this issue. Do you have any ideas?

I should probably mention that we are on PT 8.54.15.

Thanks,
Uffe

Jim Marion said...

@Uffe, looks good from here. I suggest posting your question in the PeopleSoft OTN forum where more eyes will see it.

Unknown said...

Hi Jim,

We are on PT 8.53 and I am integrating with a third party using JSON and RESTapi's and its an Inbound Intergration with Peoplesoft 9.2.
I am able to parse the data to some extent..thanks to your posts :)

But I want to download file from there system through their API which sends the response header as follows:
Headers
cache-control : private
content-disposition : attachment; filename="c-v_7294794.pdf"
content-transfer-encoding : binary
Content-Type : application/pdf
Date : Thu, 05 May 2016 17:47:38 GMT
Server : Apache/2.2.22 (Ubuntu)

The response just say downloaded files but I am not sure of the way how to get the file in Peoplesoft. I tried looking some functions but it has addattachment but not get attachment function in the IB class.

Any help in this case ..highly appreciate it!!

Thanks
Kawal

Jim Marion said...

@Kawal, If I understand correctly, you are attempting to use Integration Broker to download a file. The HTTP headers you posted look like standard HTTP headers for downloading a file. This may be a problem for Integration Broker because standard HTTP with IB is only designed for text, not binary. There is binary support with MTOM, but that would be different. You may want to post this on the OTN PeopleSoft General Discussion forum. I know some people use commons http-client with PeopleSoft. Others use raw socket connections via the JRE installed with PeopleSoft.

Unknown said...

Thanks Jim..yes I am trying to download a file using IB..I will Post as per your direction!!

Ramnath said...

Hi Jim,


We are trying to parse the XML from third party system.
We use PeopleSoft Documents for IB message. The message is received and parsed by parent-child relationship properly.

However, when there is missing tag in the transaction, then it fetches the value of the previous line which has the same tag. The issue is occurring both at parent and child level. I have used Clear() Method of compound class, but still the assigns previous value instead of blank.

Below is code and input XML

&reqDoc = &MSG.GetDocument();
&COM = &reqDoc.DocumentElement;

&parent_COL = &COM.GetPropertyByName("EMPLOYEE");

For &i = 1 To &parent_COL.Count

&PARENT_ITEM = &parent_COL.GetItem(&i);
For &parFldnum = 1 To parent_REC.FieldCount
&PAR_STR = &parent_REC.GetField(&parFldnum).Name;
&parent_REC.emplid.Value = &PARENT_ITEM.GetPropertyByName(&PAR_STR).Value;
End-For;

&child_COL = &PARENT_ITEM.GetPropertyByName("JOB");

For &j = 1 To &child_COL.Count
&child_ITEM = &child_COL.GetItem(&i);

For &chldFldnum = 1 To child_REC.FieldCount
&PAR_STR = &child_REC.GetField(&chldFldnum).Name;
&child_REC.jobid.Value = &child_ITEM.GetPropertyByName(&chldFldnum).Value;
End-For;

&SQL.Execute(&child_REC);

&ret = &child_ITEM.Clear();
End-For;

&SQL.Execute(&parent_REC);
&ret = &PARENT_ITEM.Clear();

End-For;

Input XML


1612
Simon
simon.jose@gmail.com

541
Steve
New York


621
Robert




output
1612, Simon, simon.jose@gmail.com
541, Steve, Newyork
621, Robert, Newyork

Even parent record faces similar issue, if tag is not available in current , it picks values from previous parent's tag.

Is this a tools issue, any solution to this.

Thanks & Regards,
Raghu

Jim Marion said...

@Ramnath, have you considered using the raw XMLDoc with node traversal or with XPath? It looks like you are basically doing the same thing, but using the Compound and Document object. You will have more flexibility with the XmlDoc.

Ramnath said...

Thanks Jim! I will try that but is there any specific reason for this issue. It would be great it I solve the above issue without alternate method. Is there a way to clear the compound items buffer / previous values?

Thanks & Regards,
Raghu

Jim Marion said...

@Ramnath, you should not need to clear values. If you do, then it sounds like a bug and you should file a support ticket. I'm not sure there is a work around.

Ramnath said...

Thanks Jim! It is a code mistake. I didn't clear the record object inside the loop. After I placed the Createrecord() inside, it works fine. Thanks for giving an idea.

Tina said...

Hi Jim,
I have setup a REST consume web service in PS (https url). I am sending application/json POST to the external client & receive HTTPS code as response (json).
If I change the outbound message format as application/xml I get response 500 but if I set the outbound message to application/json I get "HttpTargetConnector:ExternalSystemContactException ; IOException: The host couldn't be resolved." error.

I have imported the digital certificate. We do not have proxy server.
I have setup following routing connector HEADER properties:
Accept: application/json
URL:
Content-Type: application/json
Content-Encoding: UTF-8
sendUncompressed: Y
method: POST

Basic authentication is setup in WS security.

Can you please help resolve this.

Dave Horne said...

Hi Jim,

I wanted to give you an update on where we are with our REST service authentication issue and ask another question:

Previously we talked about the lack of access to the REST Header in order to obtain a user token in order for us to process security within the handler. You provided a thought about creating our own listener. We did this and it works. In the listener we can read the headers and pull out the user token and set the IBInfo.ExternalUserName. When the message comes into the PeopleSoft node the oprid is the ExternalUser; therefore we can now use this user to manage security through the PeopleSoft security roles, permission lists, etc. This has worked great for self service APIs and it works for both the GET and POST methods. We also took advantage of this by taking the Accept header value which is used for responses and putting it in the IBInfo.ExternalMessageID. This allows us to configure the response document for xml or json dynamically on the fly. In our model we only use one REST Operation with two operations; one GET and one POST each with their own handler. The handler takes care of security and translation out to xml or json based on the header Accept value. It also accepts both JSON and XML on the payload coming in for a POST method and then executes an app class object for the API being requested.

This is where my next question comes in: When we execute the application class we call it with two parameters: 1) an xml document and 2) the user id.

Example: ObjectDoMethod(&class_object, "Execute", &data_doc, &_username);
Where &class_object is the application class object
Where &data_doc is of type XmlDoc
Where &_username is the oprid

The receiving application class object receives the doc as:
method Execute(&POST_data As XmlDoc, &web_service_oprid As string);

We've been getting the node values out of the XmlDoc with the following statement:

Local array of XmlNode &fieldlist;
&fieldlist = &POST_data.GetElementsByTagName("internet_address");
%This.Internet_address = &fieldlist [1].NodeValue;

And so on for each level and node in the xmldoc.

Question: Is there a way to create a ROWSET directly from the XML doc and have it populate the values? An example XmlDoc might look like the following:



0.0.0.0
40.252571
-111.657675
MBL

1
X
X



We have tried a number of methods but have been unsuccessful.

Thanks,

Dave

Jim Marion said...

@Dave, first, Nice work! Second, to answer your question, yes, it is possible to create a rowset from XML. You really need to get the XML into PeopleSoft XML Rowset format to make this work, though. Probably the easiest way to do this is with an XSL transform on your routing. That way the XML is in rowset format before your subscription attempts to process it.

Dave Horne said...

Jim,

It doesn't look like my xml doc example came through correctly. Let me try it again:

This should be the way the xml doc already looks like so what would be the PepleSoft XML Rowset format so we can make this work?




0.0.0.0
40.252571
-111.657675
MBL

1
X
X





Thanks,

Dave

Dave Horne said...

Still not working; How can I embed the xml document here in your blog so that all of the xml tags will be displayed?

Jim Marion said...

@Dave, unfortunately, you can't. Some people change the leading "less-than" symbol with some other symbol.

Dave Horne said...

@Jim, ok; here's a try:

-
-
-0.0.0.0
-40.252571
--111.657675
-MBL
-
-1
-X
-X
-
-

Johanna said...

Hi guys,
I see you all are talking about RESTful services. And
I am working on a project consuming a restful service and I get a response back from the vendor. Part of the parsed response is the file's name I need to download.
The file name is a url that has everything blended in it; like the basic url path, connection information and the physical file name. I am trying to use the ‘GetAttachment’ function but it is not working at all.
I am able to see the file if I use the ‘viewContentURL’ function.
I need to open the file and save it via an application engine.
Any idea??

This is an URL example:
'https://webadmit-production.s3.amazonaws.com/export_files/reports/000/098/005/900b6ef10e3792881648ee5f21ef631f_original.txt?AWSAccessKeyId=AKIAIT7746UHRBGHSHEA&Expires=1467121475&Signature=O2Ch48o0olD9D9LzOsd3Tkyi3sM%3D&response-content-disposition=attachment%3B%20filename%3DUNTHSCSPH-Main.txt&response-content-type=text%2Fplain'

blazer said...

Thanks Jim for your post and tips and tools book. I learned lot of concepts from. I am working with a third party vendor on a integration with REST services.
I have to consume a REST service with POST method.
I'm able to post data to thirdparty using POSTMAN and SOAPui program.However, It seems thirparty is not able to proces the name/value's from IB's post.

The content-type must be application/x-www-form-urlencoded, so I am suspecting that IB is not sending the correct contect-type.

I have set the content-type on Routing.

Please, do you have an idea for this issue?


Thanks
blazer

Vikas Bhartiya said...

Hi Jim,
Our requirement is to integrate PeopleSoft with Zendesk - and they expect to have json data submitted to their API. First - we are on Tools 8.50 - is it even possible through IB?

Additionally -
I was trying to see if I can do an http post using your commment on writing to a url -

"Fortunately, IB isn't the only way to call external services. I haven't written a PeopleCode version of this, but here is some Java that shows how to make an HTTP Request: http://docs.oracle.com/javase/tutorial/networking/urls/readingWriting.html. You would just have to convert it to CreateJavaObject and GetJavaClass calls."

The problem for the third party I have is that it requires authentication - is that possible using this approach.

Vikas

Jim Marion said...

@Vikas, IB should be possible. You just have to create the JSON yourself and put it in a psnonxml block. The Java method should work also. Either way, how you authenticate depends on the security protocol. For example, if it is basic authorization, then that is a header.

Vikas Bhartiya said...

Hi Jim,
thanks for your response - hate to do this to you, but here is my code as far as the java approach is concerned. I have two issues with this code -

1. where does my authentication data go on the url?
2. My browser throws a java error when this code on a Peoplesoft page.
************ERROR*****************************************************************************
Java Exception: javax.net.ssl.SSLKeyException: RSA premaster secret error: during call of java.net.URLConnection.getOutputStream. (2,763)
************ERROR*****************************************************************************

**********************ACTUAL CODE ************************************************************

&JsonData = "{" | """" | "user " | """" | " : " | "{" | """" | "name" | """" | " : " | """" | "Roger Wilco" | """" | ", " | """" | "email" | """" | ": " | """" | "roge@example.com" | """" | "}}" | """";

rem &JsonData = {"user": {"name": "Roger Wilco", "email": "roge@example.org"}}";


&Zendesk_URL = "https://xyz.zendesk.com/api/v2/users/create_or_update.json";

Local JavaObject &Zen_URL = CreateJavaObject("java.net.URL", &Zendesk_URL);
Local JavaObject &URL_Source_Writer = &Zen_URL.openConnection();
&URL_Source_Writer.setDoOutput( True);
Local JavaObject &Outputstream = &URL_Source_Writer.getOutputStream();
Local JavaObject &outputStreamWriter = CreateJavaObject("java.io.OutputStreamWriter", &Outputstream);

&outputStreamWriter.write(&JsonData);
&outputStreamWriter.close();
**********************ACTUAL CODE ************************************************************

Vikas Bhartiya said...

Hi Jim,
I have modified the code a little bit and using the setproperty to set the authentication - the Java error also seems to be on my unix server - so currently shifter to Windows appserver for testing purposes.

My biggest issue right now is how to typecast urlconnection to httpurlconnection (since it looks like http post in Java is only going to work if we use httpurlconnection and setproperty to Post?).

Httpurlconnection is an abstract class and hence no constructor seems to be available publicly.

Jim Marion said...

@Vikas, you are exactly right. You can't cast in PeopleCode. There are only two ways to invoke methods on HttpUrlConnection:

1. Use Java Reflection
2. Use JavaScript to interact with Java rather than PeopleCode.

Personally, I like option 2. You can store the JavaScript in a message catalog entry, an HTML definition, or a custom table. I have a couple of blog posts on invoking JavaScript (and Java) from PeopleCode.

Another way to make an Http connection using PeopleCode is to use the Apache HttpClient. This open source Java library takes care of a lot of the low level work for you (including cookie handling). The reason I didn't suggest this before is because you have to install the library into your app and/or process scheduler server.

The other issue may be related to your Java key store.

Vikas Bhartiya said...

Hi Jim,
I am now using Java reflection and I think it should work. The only piece of code I am hazy about now is calling the write function to write &json string to the url -

&outputStreamWriter.write(&JsonData);
&outputStreamWriter.close();

Is this the way to do it given that &JsonData variable above just contains a string in a valid json format? Or is the syntax different?

Thanks a ton for your help!!

Vikas

Jim Marion said...

"Roger Wilco" Clever name.

Yes, that should work (as long as it is OutputStreamWriter). PeopleCode should be able to marshal &JsonData between a PeopleCode string and a Java String. If you need to manually convert to a Java string then use something like this:

CreateJavaObject("java.lang.String", &JsonData);

If you need to convert it to bytes, then try this:

CreateJavaObject("java.lang.String", &JsonData).getBytes();

Dave Horne said...

Hi Jim,

Having another issue calling a 3rd party Provider with their REST Service. We got through the authentication part based on the information above; however, it turns out that the data being returned is being returned in what appears to be encoded with base64. The only way we have figured out to consume the data is to use the WriteBase64StringToBinary file option to write it to a file; then write another process to open and read the file and load the rowset. Is there a PeopleCode function or Java function that we can convert the data on the fly from variable to variable so we don't have to write it out to the file and then read the file for loading into a rowset?

Following is the code snippit:
&response = %IntBroker.SyncRequest(&request);

rem Get the xmldoc from the response message;
&responseXMLDoc = &response.GetXmlDoc();

rem &output = &output | &lf | &lf | &responseXMLDoc.GenXmlString() | &lf;

REM Read the response XML;
&errors = &responseXMLDoc.GetElementsByTagName("a:Errors");
&fileData = &responseXMLDoc.GetElementsByTagName("a:FileData");
&fileName = &responseXMLDoc.GetElementsByTagName("a:FileName");

If Len(&errors.Get(1).NodeValue) > 0 Then
&output = &output | &lf | &errors.Get(1).NodeValue;
Else
If Len(&fileData.Get(1).NodeValue) > 0 And
Len(&fileName.Get(1).NodeValue) > 0 Then
&F1 = GetFile("/tmp/" | &fileName.Get(1).NodeValue, "W", %FilePath_Absolute);
If &F1.IsOpen Then
&F1.WriteBase64StringToBinary(&fileData.Get(1).NodeValue);
&F1.Close();
rem &output = &output | &lf | &fileData.Get(1).NodeValue;
&output = &output | &lf | "Saved the file: " | &fileName.Get(1).NodeValue | " to disk";
End-If;
End-If;
End-If;

Jim Marion said...

@Dave, I have a handful of base64 encoding options documented on this blog. Here is a list: http://jjmpsj.blogspot.com/search?q=base64. Of course, you want to go the other direction. The "PeopleSoft way" would be to use pluggable encryption. I documented base64 encoding here: http://jjmpsj.blogspot.com/2009/05/base64-encoding-with-pluggable.html. Just change the steps a little for decoding. The comments on this post contain a lot more information: http://jjmpsj.blogspot.com/2009/05/base64-encoding-for-peoplesoft.html.

Jim Marion said...

@Vikas, looks like you are on the right track. 401 is an authentication issue. I think everything else is good. 'm not familiar with that authentication syntax. I'm sure you reviewed the Curl documents already.

Nagesh said...

Hi Jim,

I looking to read response headers in Peoplecode. Is there any way we can read response header which we will receive as part rest request response.

Thanks.

Syed Usman said...

Hi Jim and Nagesh,

I am also facing the same problem, please share if there is a solution. For short term, we decided to send header information in response payload.

Thanks,
Syed

Yadav said...

Hi Jim,

We are using Asynchronous One way service(non-REST service) to publish messages to third party system as we do not need to wait for response message from them.
For this service we do not have an option to select the content-type : application/JSON.
If we use REST services , if we select POST/PUT method, we need to add both request and response for it. In this case if we don’t receive any response from third party system, all messages are in queued until we receive the response.
For REST services we have an option to select the content-type : application/JSON.

How do we publish message content as application/JSON in Asynchronous one way service ( non REST )?

Please help me out.

Thank you,
Yadav

Gaurav Rajput said...

Hi,

i have created one REST Based web service and in service operation response content-type is set as application/json and want to enable the application/xml as additional content type in response message in case any user wants the response in that format.

but whenever third party user is sending request with additional accept tag as application/xml in request header, response must go in xml format but same is not working response message is getting generated in json only.

can you please help here..

Jim Marion said...

@Gaurav, is the third-party sending both content types in accepts header or just the XML type?

Gaurav Rajput said...

Hi Jim, third party application want to send the content type dynamically... like they want to consume the same web service in 2 application and one application accept json and one accept XML. so is there any way to handle the same, like third party will send one more attribute in header for content type and accordingly webservice will generate the response message with that content type only.?

Anonymous said...

Jim,
This turned out to be exactly what I wanted to do, but I'm having some trouble getting it to work from external parties, from "the outside".

I'm essentially doing this, except I'm using SOAP UI client instead of a Python script:

https://www.cedarhillsgroup.com/knowledge-base/kbarticles/simple-python-post-to-integration-broker-script/


From my machine on the internal network, I can use SOAP UI to create an Http Post and send it to:
https://server/PSIGW/HttpListeningConnector?&Operation=MyServiceOperation&From=FromNode&To=ToNode

I can see the messages in the IB monitor, it all works as expected.

But when I send the same post to the same URL when I'm not on the internal network (from home, or from some api testing site), I'm getting this:
Integration Gateway failed while processing the message

Our DBA explained that when I'm using that URL from home, I'm using an EXTERNAL gateway, that path is not routed externally, and the connection dies.

I also found this Oracle Doc:

E-IB: Configuring Integration Broker Gateways to Combine Protected Internal Network and Inbound Messaging from External Parties (Doc ID 2001014.1)

(which a lot of it goes over my head, so I'm sort of wary of the issues that we'd run into.)

"Goal:
... What IB gateway configuration(s) would work in this architecture to both keep the internal IB traffic as before, and also receive inbound IB traffic from outside?"

Then it gives 3 solutions (I can copy and paste but it's a bit lengthy, this is where it goes over my head), but it says:

"Guiding non-standard implementations is out of support scope, but some general ideas can be shared, you may use them at your own risk...Note: Remember that the above are just general ideas, not something that Support would specially recommends or back."

I'm wondering if you would have anything else to offer than the above?

I'm not sure I understand the point of an HttpListeningConnector if we need non-standard implementations for it to work from the outside... feel like I'm missing something.

Unknown said...

Hi Jim,
We are trying to use REST API to consume data from 3rd party app. We used CI via API to save data in PeopleSoft but impacts the overall performance when concurrent users log in. We tried App Package method to do same, though performance was good but risk of mising out key validations which happens in CI is there when we do via App Package.
Pl suggest any other method to acheive this without compromising on data and performance.

THanks
Ramky

Jim Marion said...

@Jwalant, of course! You will just need to write the PeopleCode to read the file and package it correctly.

Jim Marion said...

@Ramky you are correct. CI performance is not great. Maybe someday PeopleSoft will use App Class API objects instead of CIs, but for now that is all we have and performance is not so great.

Unknown said...

Hi Jim,

Currently we are doing the User Profile integration using PeopleSoft standard generated WSDL operations. We noticed that the Update operations does not able to do the Role Name update. Do you have any idea on this issue? Or is there another way for us to do the Role Name update in PeopleSoft via the web services?

Thanks,
Nicholas

Jim Marion said...

@AndyTest22 it sounds like you are experiencing the typical Integration Broker firewall issues. Often a network is configured to use a proxy for external connections, and no proxy for internal. If that is your case, then use non-proxy hosts setting to bypass the proxy for internal connections and configure IB to use the external proxy, which is what it will use for all hosts that are not in the non-proxy hosts setting.

Jeya Prakash said...

Hi Jim,

as per the latest client requirement , i have Published a REST Service when i try to invoke Operation from Provider REST Template getting below error.
Error with Request. Status - Integration Gateway - External System Contact Error (158,10721).

if i try to open the URL from browser, getting below error.

500 Internal Server Error
The server encountered an unexpected condition which prevented it from fulfilling the request.

We are completely stuck here,please advise.

Jim Marion said...

@Jeya,

This is incredibly hard to troubleshoot because it basically gives you no information about the problem. You can try reviewing your IB and app server logs, but may not find more information there either. I assume you have handler PeopleCode? You can try commenting it out to see if that is the problem. You will also have to work backward through the configuration to make sure all pieces are enabled and configured.

Unknown said...

Hi Jim,

Is there a way to include the token in soap ui response header?

Jim Marion said...

@Mark, great question! Yes, it is possible to set headers, but I'm not sure about getting the PS_TOKEN.

BS said...

Hi,
I have one doubt on REST PATCH method. We don't have REST PATCH method in PeopleSoft 8.56
Is there any alternate option for the same. Thanks.

BBUNES said...

Hi Jim,

I'm integrating with a 3rd party using a JSON REST API. The API is using the Document model to define the message structure. I'm populating the document values via App Engine PC. One requirement is to populate a couple fields on the API with a null. I can populate it with "" if the fields are defined as text, but the fields are defined as non-negative numeric integers. Is there a way to do this?

Syed Usman said...

@BBUNES, Not sure what you mean by non-negative numeric integers, But if you want to initialize the null values then use non-rowset message (its a lot easier and flexible) and populate the message with JsonBuilder delivered class. For example:

Local JsonBuilder &jbldr = CreateJsonBuilder();
&jbldr.AddNullProperty("field_name");

Note: We are on PT 8.56.

Ace said...

Hi,

We have designed an Get API where we are providing the client with a list of dates. The current format is shown below:

"minimumEffectiveDate": "2018-03-01",
"availableDates": [
{
"date": "2018-03-02"
},
{
"date": "2018-03-03"
},
{
"date": "2018-03-04"
},
{
"date": "2018-03-07"
}

Client requires the dates to show in the following format:

"minimumEffectiveDate": "2018-03-01"
"availableDates": [
"2018-03-02"
"2018-03-03"
"2018-03-07"
]
Any recommendation how this can be achieved? Thanks in advance

Jim Marion said...

@Ace, this was such a great question, I decided to create a video describing how to create this structure. You may watch it online here: https://youtu.be/g_rzjzdibgg

srikanth said...

Hi Jim, we have recently developed PeopleSoft Rest GET API to provide payment details to source system based on requested days. For certain days we have large number of payment details and the rest webservice is failing not able to handle large response data to send. When I chunk the data its working fine. Is there any solution that I can use to prevent the issue?

Jim Marion said...

@Srikanth, do you think you are running out of memory when you process large amounts of data? This is very possible. Are you able to increase the amount of available RAM and process larger documents?

HGH said...

Hello Jim, I need a help how to get a connection with 3 rd party with using curl command on peoplecode. I have tried but not have any solution to that. Curl command is working good on command line but I need to execute through peoplecode and get the response. Please provide me some solutions or method to follow to achieve

Jim Marion said...

@HGH, moving from Curl to IB is too complicated to answer here. The mechanics are the basics of Integration Broker, so it isn't hard. It is just a lot of steps. Actually, I take that back. It is potentially a one-liner PeopleCode, but generally speaking, it involves creating a service, service operation, possibly Documents and messages, and of course, PeopleCode. But the one-liner would be %IntBroker.ConnectorRequestURL. If you require Authorization Header or POST data, then it is much more effort. We cover this in great detail in our integration tools update 3-day class: https://ibupdate.jsmpros.com/.

Unknown said...

Is it possible to get the following POST structure by using PeopleSoft document feature ? I created a dcoument but unable to attached to a service operation beacuse of the child structure and I looked at the lookup view and it is filtering the child dependency documents. Any suggestions ?

$ curl --request POST 'api.test.com/v3/subscriber' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer {ACCESS_TOKEN}' \
--data-raw '{
"template": {
"version": "3.0",
"data": [
{
"first_name": "Jerry",
"last_name": "Garcia",
"email": "jerry@street.com",
"subscriber_status": {
"id": 4
},
"subscriber_privacy_level": {
"id": 1
}
}
]
}
}'

Unknown said...

Hello Jim,

Looking for your input to generate the following output ,I am using PeopleSoft IB message services to get an authentication token from vendor.

$ curl -v https://api.test.com/v3/oauth/Token \
-H "Accept: application/json" \
-H "Accept-Language: en_US" \
-u "{client_id}:{client_secret}" \
-d "grant_type=client_credentials"

Jim Marion said...

From the -d in the command, I am assuming this is a POST. It also looks like URL encoded form data, although that isn't specified. We just showed how to do something different to connect to Twilio in our Integration Day and our Developer Day webinars (2021 editions). Of course, the start is to create the SErvice and Service Operation metadata as a REST service and uncheck the "Is Provider" checkbox. When you call the service, you will need to set the SegmentContenType property if you are using URL Encoded Form Data. Otherwise, the rest is just a matter of setting HTTP Request Headers through IBConnectorInfo.AddConnectorProperties.

Jim Marion said...

@Unknown, it may be possible by using the JSON tab of the documents module to show/hide the root node and using compound children. But I would just use JsonObject directly

Riya said...

Hi Jim, I am working on outbound third-party interface with one of our PeopleSoft systems. I have set up synchronous service for data transfer. The response message is Document type with response code set up as an element.
When I test my service operation, I get GetMessageText: No default message. (0,0) error. Any insight?
Thanks

Will said...

Jim

I have been playing with rest messages and found that using Documents is very restricive. So Ended up using generic Measges set as Application/Json and I am able to read and Send JSON Easily....

But having a Small issue.. with CI.. Especially where the PS uses %request to pull info... But thru a message %request is not defined...

My Question instead of bypassing code based on CI name or something (Touching PS Code) .. Is there a way to create or instantiate %request so I can control instead or at least Bypass the errors

Yusuf said...

Hi Jim,

We have an REST API which calls the service operation using synchronous messaging to fetch the data in JSON format using SOAPUI.
When we trigger the API to fetch approx. 25k rows with all columns selected in the criteria field, the API continues to run in SOAP UI for 20 mins with a dedicated transaction ID (Guid) and after that it automatically re-fire with another transaction ID which will take another 20 mins to complete.

Eventually we are not getting any data in SOAP UI but could only see 2 transaction ID with DONE status (under monitor synchronous services) which runs 20 mins each for a single API call.
Could please help us why the single API call gets re-fire after 20 mins with different transaction ID and don't return any data.

Also we tried to fetch only 500 row with all columns selected and API call got completed without any re-fire and able to get JSON response.

Thanks!

Jim Marion said...

@Will, context-specific PeopleCode is one of my greatest frustrations. I am not aware of any way to work around the issue you mentioned.

Jim Marion said...

@Riya, it sounds like PeopleSoft is the Synchronous Service provider. Is this REST or SOAP? Either way, if PeopleSoft is the provider, then make sure you are populating the response's document (Response.GetDocument()).

Jim Marion said...

@Yusuf, that seems very strange. I am suspicious about SoapUI possibly timing out and trying again? That is a lot of data to send/receive through Integration Broker. Integration Broker is a DOM solution (in-memory). The larger your document, the more it loads into memory. It is not a "stream" solution. For large amounts of data, I think you would be better off with a stream-based solution.

Jim Marion said...

@Yusuf, it could also be that the data set is so large in memory that it is crashing the server (running out of memory), and SoapUI is attempting to recover.

Will said...

Jim

I Have been playing with Rest for a while... And found the Document concept is a Pain. So I have been using Generic Messages and just Adjusting the Ib adjustments and using PS new JSOn methods Works great..

But now the third Party want to have us send them Documents (PDF..ect) on a Multi form rest message so we can send the PDF Documents....
I know I can adjust Content Type

&info.IBConnectorInfo.AddConnectorProperties("Content-Type", "application/json", %Header);

But not sure how the body should be loaded for the Actual Document

W

Jim Marion said...

@Will, first, PeopleSoft doesn't do binary very well, so this may be a challenge. Second, take a look at PeopleSoft MTOM.

Andy said...

Hi Jim,
I have a REST service that is working from a third party application, I can see the test calls coming into the synch services monitor. So I think the REST Base URL and URI templates are set up correctly. eg.
[server:port]PSIGW/RESTListeningConnector/DEV/TEST_GET.v1/

Template Index 1: EMPLID

My endpoint URL in PostMan: [server:port]PSIGW/RESTListeningConnector/DEV/TEST_GET.v1/EMPLID

But when I test the service or another service that I've created from PostMan or a similar tool, the request times out.

Any ideas on what to check?

Jim Marion said...

@Andy, a timeout is either a network issue or a really long running OnRequest handler. If the problem were the template or the URL, PeopleSoft would return an error message immediately.