Thursday, September 23, 2010

Posting Data to IScripts

If you are a regular reader, you already know that I am a big fan of Ajax. Most of my PeopleSoft Ajax requests use HTTP GET operations to send query string parameters to iScripts. I have considered using POST to send structured data to iScripts (XML, JSON, etc), but have not found reason to do so. Considering my background in other web based languages, I just assumed the %Request object provided direct access to posted content. I didn't really look until I saw an IT Toolbox forum question from KCWeaver asking how to post data to an iScript. The Request object does have a GetContentBody() method that will return POST'd data. What PeopleBooks doesn't tell you is how to activate the GetContentBody method (Note: I don't think this is an oversight. I think it is because GetContentBody is designed for Business Interlinks, not for iScripts). Special thanks to Kevin for digging through the documentation and figuring out how to POST to an iScript. The trick is to add postDataBin=y to the end of your query string.

View the full IT Toolbox thread here: AJAX to iScript

44 comments:

Unknown said...

Jim

We have a page and trying to print the page using JS Print function; are there any features available that can help us to print in landscape mode ir control the print functions through PeopleCode? I see that we an use XML to get into PDF, but most of our page data is calculated data and we just want to use the simple Print option; Can you please provide the different options here and some examples ?

Thanks

Raj

Jim Marion said...

@Raj, I did some work with this several years ago using an ActiveX component named ScriptX. I see that the product is still around. I believe it is worth reviewing. I Googled for some other ideas and saw several postings on using CSS and @media to accomplish this, but I've never tried it. I know ScriptX works, but unfortunately, it only works with IE.

Generally speaking, browser settings are considered off limits for JavaScript and security. The only "good" print solution is to generate a PDF.

Chili Joe said...

That's good to know. Thanks for sharing.

Ketan Kothari said...

This parameter postDataBin=y is also used in ExcelToCI VBSCript Code. I

Anonymous said...

Hello Jim,

I'm reading your book Tips and Techniques. It is really a great book.

I would be glad if you could help me:

We use AddAttachment() function to upload the attachments to ftp server. However many a times users have a very large attachments (around 700Mb). When uploading such large attachments the AddAttachment() method takes time and the session gets expired.

I wanted to know what all can be done in peoplesoft so that i'm able to upload large attachments?
The uploading should happen in background, and the user should be able to do other tasks. How this could be achieved?

Java?
Javascript?
IScripts?
PS webservices?

-Sumegh

Jim Marion said...

@Sumegh, One idea is to increase your timeout :), but for security purposes, that may not be feasible. Another option is to use the Ajax approach I showed at OOW 2007 to keep the session active until a user closes his/her browser. Again, this might not be acceptable to your security team.

Alternative approach: HTTP allows you to upload files, but it is really bad at file uploads. It is very suitable and convenient for small files, but not for large files. FTP is the most common file transfer method for large files, but not secure. SFTP, FTPS, and SCP are good secure large file transfer alternatives. If your users are transferring large files, then you may want to use one of these alternate transfer mechanisms. This will happen outside PeopleSoft. Next, I'm sure you would like to get file attachment meta-data into PeopleSoft... If you are using an FTP protocol for your AddAttachment URL, then you just need to add the keys, attachsysfilename and attachuserfile values to PeopleSoft. If it is a record, then you need to use GetAttachment to import the file into your database. For this, you may use a scheduled batch job or an AE daemon to poll the contents of the file transfer directory.

These are just some ideas. How and what you implement will really depend on your architecture.

Anonymous said...

@Jim, thanks a lot for your opinion.

ammm.. outside peoplesoft? Seems to be tough.

I was searching on internet for such a code in Javascript which would upload the file to ftp server (in FTPS mode), but didn't found any. Do you have any such code? or any reference?
I may think of adding some AJAX to this upload process.

The thing is.. I get stucked in preparing the proof of concepts, and could not start.

Thanks in advance for your help
-Sumegh

Unknown said...

Hi Jim,
My Question:
How to find the webserver is up or down through peoplecode

Reason behind the question:
We have instances like PORTAL,HRMS,CRM,FINANCE. But PORTAL instance is the single window for other applications and instances(HRMS,CRM,FINANCE).

In portal there are many pagelets from all instances. For Example we have window with pagelets from portal,hrms,finance.
when HRMS is down, we want to show message- "HRMS is currently down" in that particular pagelet alone.

Tried using pingnode function it checks for the appserver is down or not,
how to find the webserver is down or not.

If there is any other solutions please provide.

Thanks
Vignesh

Unknown said...

Hi Jim,
My Question:
How to find the webserver is up or down through peoplecode

Reason behind the question:
We have instances like PORTAL,HRMS,CRM,FINANCE. But PORTAL instance is the single window for other applications and instances(HRMS,CRM,FINANCE).

In portal there are many pagelets from all instances. For Example we have window with pagelets from portal,hrms,finance.
when HRMS is down, we want to show message- "HRMS is currently down" in that particular pagelet alone.

Tried using pingnode function it checks for the appserver is down or not,
how to find the webserver is down or not.

If there is any other solutions please provide.

Thanks
Vignesh

Jim Marion said...

@Vignesh, that is a good question. What I've been doing is making an http request to the application's Integration Broker PeopleSoftListeningConnector URL. This assumes the Integration Broker gateway is running in the same web server instance as the app.

Another alternative is to hit some other URL for the app.

You can do this with the PeopleSoft HttpTargetConnector, but for a pagelet, you can also do it with Ajax. It is up to you, your comfort level with the technologies, and what you are trying to accomplish.

kayal said...

Jim,
I am looking to have student information from campus solutions to post inside a pagelet in the portal.

We have a web service that we use for displaying student grades on iPhone. But I would like to use web service or java script to post grades in a nice format in a portal pagelet.

How can i achieve this? Any snippets would be very helpful and much appreciated.

Thank you,
Kayal Asokan

Jim Marion said...

@Kayal, it sounds like you are on the right track.

If you are just displaying data, then the easiest way is to create a query and then use the Pagelet Wizard to format the results of that query. Pagelet Wizard will convert the query results to XML and then you can write XSL to reformat the data.

Another option is to reuse the web service you already created. If your Integration Broker handler returns HTML, JSON, or even XML, you can write a pagelet wizard HTML pagelet that uses jQuery and Ajax to get the data from integration broker, and then display it on the page.

KK said...

Jim,
We are implementing third party single signon and I have a single sign people code to read the emplid from from a cookie sent by thirdparty and validate it against the PSOPRDEFN. Based on the existance of the empid, I am setting the authetication. But I am not able to redirect the response or add a cookie to response in that peoplecode, the peoplecode is not executing that code. Since I dont have any luck there, I am trying to call a custom HTML object in the default tab. But I am having where to place the code for this. I tried couple of places in WEBLIB_PORTAL and WEBLIB_PT_NAV, but no success. Can you give me some direction on this.

Jim Marion said...

@KK, Signon PeopleCode has no response object, that is why you aren't able to set cookies, etc.

Homepages are a composite of several HTML definitions: PORTAL_HP_USER_TEMPLATE, PORTAL_HP_3COL_LAYOUT, etc.

Adding your HTML to any of those will put it on every homepage tab.

KK said...

Jim,
Thanks for the reply. What I am trying to do here is if the sigton pepople code detremines that the userid is not in PSOPRDEFN, then I want to show the user a page which has a my company logo and the message that the user dont have access to peoplesoft. I already created a no access HTML objec in Ptools meeting the requirements. I want to use this new html object in place of the homepage. I am not able to figure out where I can attach this html to response. Am I going in right direction or is there a better way to to this.

Thanks,
KK

Jim Marion said...

@KK, I think you have to use SetAuthenticationResult to set the result to false, so the user doesn't gain access. In the signon.html template and other templates, you will see variables. You may want to use one of them and some JavaScript to display the appropriate message.

KK said...

Jim,
I already has the same login in place now. Whenever the user is not found in PSOPRDEFN, I set the authetication false and the user will be redirected to signin.html. Thats the reason I tried to add a cookie to the response in sigon peoplecode so that I can use java script and identify that the user do not exist in peoplesoft. Now I am stuck with how to identify that the redirect is due to the setauthentication failure from sigon peoplecode.

Jim Marion said...

@KK, I don't have any "good" recommendations for you. The inability to access the Response object has limited us in several ways: primarily Cookies and Redirects.

KK said...

Thanks Jim for all the reponses. A final question, is there a way to replace the default homepage to a new custom html page?

Thanks,
KK

Jim Marion said...

@KK, do you mean the one with a URL ending in ?tab=DEFAULT? The HTML for that is in App Designer. In fact, a homepage tab is a composition of several HTML definitions, all prefixed with PORTAL_HP. The recommended way to change these values is to create attributes on the homepage tab CREF in structure and content. The attribute name is the original HTML definition name, and the value is the new HTML definition name (likely a clone of the original).

KK said...

Jim,
Yes, I mean the URL ending in ?tab=DEFAULT?. but changing the attibute values changes for all the users. I want to change the home page for only one user. Is that possible?

Jim Marion said...

@KK, "... for one user..." Yes, of course, anything is possible :).

It really depends on how dramatic your change. If you want a full layout change, then you will need something like Enterprise Portal's role based branding. If it is a minor change, then you can get by with just some JavaScript/HTML in a pagelet.

KK said...

Jim,
I am trying to replace the homepage with a custom html object for one user and i dont have enterprise portal license in my application to do branding based on role. How I can acheive this?

Thanks,
KK

Jim Marion said...

@KK, Enterprise Portal's Role based branding is an app class that overrides the core PeopleTools PT_BRANDING:BrandingBase App class. What you could do is create a new app class that subclasses PT_BRANDING:BrandingBase and implements the functionality you desire. When you are finished, go to PeopleTools > Utilities > Administration > PeopleTools Options and change the Branding App Package and Class to match your new package and class.

Note: Even though this is a configuration and you have not modified any delivered objects, you may need to rework your custom branding package after upgrades. The PT_BRANDING:BrandingBase interface is subject to change.

VirtualMadman said...

Hi Jim,

I googled my way into this post trying to find a way to capture the web server name through peoplecode. Since there is no "Ask Jim" section in your blog, I thought I would just post it here as a comment.

Basically I'm trying to print debug code as HTML comments that would display the App server and web server used in each request. We have several web servers behind a load balancer and just printing the domain name (%Request.ServerName) would not resolve our issue.

Do you know if there is a way to do this?

Thanks for the help and great job on the book!

-Eduardo Monteiro

Jim Marion said...

@VirtualMadman,

Getting the app server name is pretty easy because your PeopleCode runs at the app server. Likewise, when the app server connects to the database (Oracle DB, at least, not sure about MSFT), the database keeps the name of the server that connected (client). In Oracle, you can see this in v$session, and you can use one of the SYS_CONTEXT variables to determine the client name. If you have the app server name in an environment variable, then you can use the GetEnv function to get the value of an environment variable. If you have a shell program (for example, Unix/Linux, etc), then you can exec a shell program and get output using Java (see Exec Processes while Controlling stdin and stdout.

The web server is a different story. There may be a way to get the web server info, but it isn't exposed through PeopleCode. Basically, if it isn't in the Request object as a header, then it isn't available. If you don't have an existing header that satisfies your needs, then you can add one by using a ServletFilter. I have an example of a ServletFilter that adds a header in my post Desktop Integrated Signon.

About "Ask Jim..." I have definitely given that some thought, but haven't come up with a way to do that yet.

I refer back to my book regularly. I am glad that you find it useful as well.

James said...

Jim,

I have an external website where I would like to consume an iScript that was created. I keep getting "Security Authorization errors", or PeopleSoft delivered signin screens. I imagine there should be a way to "deep link" into an iScript to expose it to an external webpage without having to login to PeopleSoft. Do you know if this is possible? If so, do you know how I go about doing this?

Thanks,

James B

Jim Marion said...

@James, iScripts require an authenticated session. Without a PS_TOKEN cookie, it is impossible to execute an iScript. There are several ways around this, and it really depends on what you are trying to accomplish. For example, if all of these iScripts are guest services, then you can set the guest user information in your web profile. Another solution would be to use some type of sso/ticket with another security provider (like one of Oracle's identity products) so that the user is automatically authenticated.

Since you just need a PS_TOKEN cookie generated in the same domain as your PeopleSoft web profile's AuthTokenDomain, you can even have the non-PeopleSoft application make an HTTP request into PeopleSoft's signon page with some generic credentials, and then write the cookie back to the client (along with any other PS cookies that seem appropriate see Generating an AuthToken for SwitchUser for a sample Java program that creates a PS_TOKEN).

An alternative to iScripts is to use Integration Broker's HttpListeningConnector. With this alternative, you convert your iScript PeopleCode to an IB OnRequest handler and make HTTP GET/POST requests through the IB Gateway. My REST-like PeopleSoft Services post uses the same concept. It is this alternate approach that I recommend. Using Integration Broker for non-PeopleSoft requests gives you a lot of architecture flexibility.

Frank Staheli said...

Jim:

Thanks for this gem of an insight! This helped us make a major breakthrough on some things we're working on at BYU.

Frank Staheli

Jim Marion said...

@Frank, I am very glad you found it helpful!

hemanth kumar said...

Hi Jim,

I need help on Iscripts

I have a requirement where I have to post the data to Iscripts on condition.

For instance

1)If an order has hold on header data should be posted to iscript and should be
displayed.

Please let me know If you any questions

Jim Marion said...

@Hemanth, you may need consulting assistance with this.

Unknown said...

Hi Jim,

Its a wonderful journey of thoughts and shares helped to me to work on iscripts.
Now I would like to achieve
to refresh the iscript dynamically without page refresh and display related alert to referring iframe template based on page field condition.
Thanks,
Hemanth.

Jim Marion said...

@Hemanth, I suggest you look into jQuery and Ajax. Ajax is the design pattern that will help you refresh your page content dynamically. jQuery is a JavaScript library that makes Ajax easier.

Chandra said...

Jim,

I have posted the questions yesterday, somehow, i am unable to locate your answer.I re-posting it.

We have requirement to change email link generated in emails for AWE via Generic templates. Per your previous blog post, I have looked at
EOAW_CORE.DEFN.AWTxn. Looks like it is generating the code somewhere there. However, without changing delivered code, is there anyway to achieve the links in the email.

Thanks,
Chandra

Jim Marion said...

@Chandra, I'm assuming you already considered adding the links to the email template? Other than that, modifying the code is the only other way I know of to add links to an email template.

Unknown said...

Hi Jim,

I am trying to post an encoded artifact from peoplesoft to thirdparty url via iScript using %response.write(); From the third party i am unable to get the response (return values) to peoplesoft. How to achieve this. Please advise.

For achieving this. i have followed the following steps.

Created a HTML object. the code in HTML is as follows


form target="_self" method="post" action="%BIND(:1)"
input type="hidden" name="eID" value="%BIND(:2)"



The iscript coding is as follows

&sHTML = GetHTMLText(HTML.A_TEST, &URL, &eID);

&values = %Response.Write(&sHTML);

How to retrieve the return values from third party?

Jim Marion said...

@Giridharan, I think I'm misunderstanding something. %Response.Write is used to send data to a browser. So you could use %Response.Write with an iScript IF the third-party has an authenticated session and is fetching data from PeopleSoft. That is not usually the case, however. It sounds like you want to send data to a third party (POST). In that case, you would not use %Response.Write, you would use %IntBroker.ConnectorRequestURL or some other Integration Broker mechanism to send data to a third party.

PeopleSoft HCM Dev Blog said...

I just want to say "Many thanks"..This postDataBin=y helps..

Andytest2221 said...

Jim,
I am able to successfully post data to an iScript. But I also want the iSCript to insert a row into a table, and remote call a Cobol that will use the inserted row.

Remote call is a think-time function so it errors because my cursor is still open from the SQLExec.

I tried Commitwork and SQLExec Commit, and neither worked.

I'm trying to avoid using the process scheduler because this iScript could be hit dozens of times a day.

Any ideas?

Jim Marion said...

@Andytest2221, I think you are going to have to get the remote call outside of the iScript processing. The only way I can think of to do that is to use the process scheduler. IB Full Syncs use a similar strategy.

If you expect multiple hits per day, then you may want to schedule the App Engine and have it mark the rows you are processing with the Process instance or copy from a staging table into the table the Cobol will process. If there is a potential for data conflicts, perhaps there is a flag that tells the next scheduled instance to skip if the current one is still processing, etc.

Andytest2221 said...

Thanks, Jim.
I left that open as an option, but I also started going down a different path. Instead of using an iScript, I created a web service.
When I use an application class handler for the web service, it allows me to do a Commitwork and I was able to get around the open cursor issue that way.

My other concern with using the iScript was that during a system outage/production upgrade, the third party wouldn't be able to hit the URL, and we would lose those transactions.

So, to try to resolve both issues, I created an async request/response service operation so that the transactions queue during an outage.

But I'm a little skeptical of this solution. Most of the service operations for third-party integration that I've worked with (such as third-party vendors in ePro) are synchronous. I don't know that the third-party needs a response at all, and the order in which messages are processed don't matter. Is there anything wrong with creating it as async?

Also, I'm unsure of how to return a response message with an async operation because the available handler types (on request, on notify, etc.) change depending on the operation type.
For example, for synchronous ops I can use OnRequest, and the IRequestHandler interface returns a Message.
But for async, I'm not sure what to use. I've been using On Notify, which doesn't return anything.






Jim Marion said...

@Andytest2221, perfect. The general rule is to use Async unless you have to use sync. The reason is because Async can queue and allows for better resource balancing. Connection established, payload delivered, connection dropped. As you noted, however, sending a response is tricky. Async works best when no response is expected. If a response is expected, then there are two approaches:

1. Initiator includes a callback URL with transaction ID or something. When process completes, your process invokes that callback to deliver response.

2. Initiator periodically polls your PeopleSoft system to determine status and pick up a response if one exists.

Barti said...

Hi Jim,

I'm fairly new to Javascript. I'm trying to write a javascript(Portal) using Ajaxrequest to call an Peoplecode Iscript(which is base instance) that updates the database and just returns a null String value.


I tried different ways and none of them are working. I couldn't even call my Iscript. Could you please help on this?

var URL_PATH = https://Portal_URL/Record.ISCRIPT.Fieldformula.Iscript_test;

function sendXYZAjaxRequest(url) {
loader = new net2.ContentLoader(url,null, null, "GET", function() {
var respData = this.req.responseText;
}, null, null, "application/x-www-form-urlencoded");
// loader = null;
//window.location = respData;
}

sendXYZAjaxRequest(URL_PATH);
==================================
2nd way-
SSCHK= {}; SSCHK.xyzcheck= function () {
iAjaxRequest("GET", PU_SSS, function (o) {
var pu_content = iParseTargetContent(o);
//var SSheck = document.getElementById('CREF_NAME_THAT Is created in HUB');
//alert("sun :" + o.responseText)
//alert(SSheck)
SSheck.innerHTML = pu_content;
});
}

SSCHK.xyzcheck();
============================================================


Thanks!