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.

Thursday, October 20, 2011

Slideshow News Publications

This post follows my Accordion Navigation Collections post and contains the XSL I used at OpenWorld to convert an Applications (formerly Enterprise) Portal news publication into a slideshow. The XSL assumes you have images associated with your news content. Even though the XSL and JavaScript will operate fine with images of different sizes, I recommend that each of the images used with this XSL be of the same size. Here is the XSL: slideshow-hosted.xsl

All of the usual disclaimers apply. Don't trust anyone else's code -- Understand what it is doing before you use it. You take full responsibility for the code once you download it. Don't delegate your responsibility, especially to someone that offers you code for free.

Disclaimer: I make no warranty regarding the use of this XSL.

Security Warning: To make sure the XSL will work "out of the box," I pointed the JavaScript at Google's hosted JavaScript API's and the jQuery Cycle download site. Since this code is used on your enterprise home pages, I suggest you replace these references with references to your own site's versions of these libraries. The thought of allowing some external service to run code on my pages makes me a bit nervous.

Wednesday, October 05, 2011

Changing the Search Page Operator

I just posted about Monkey Patching, a technique used in chapter 7 of my book PeopleTools Tips and Techniques to set the default search page operator on advanced search pages (Note: only 8.50 and later required Monkey Patching). As I was looking over the "Changing Search Operators" section of chapter 7, I noticed the code was missing a few lines (pages 293 - 296). Here is my revision:

<script type="text/javascript">
  // C style include protection
  if(!window.apt.setSearchOp) {
    window.apt.setSearchOp = true;
    
    if(window.net) {
      // pt 8.50
      (function($) {
        var originalContentLoader = net.ContentLoader;
        net.ContentLoader = function(url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt) {
          var originalOnLoad = onload;
          if(name == "#ICAdvSearch") {
            onload = function() {
              if (typeof originalOnLoad == "undefined" || !originalOnLoad) {
                this.processXML();
              } else {
                originalOnLoad.call(this);
              }
      
              // The value for "between" is 9. Change this to your desired
              // search operator value.
              var newValue = 9;

              // The name of the search key field is APT_UI_SCRIPTS_MENUNAME.
              // Generally speaking, PeopleSoft creates HTML element names by
              // combining record and field names with an underscore as in
              // RECORD_FIELD. Change the following value to the name of your
              // search key record_field
              var coll = $("select[name='APT_UI_SCRIPTS_MENUNAME$op']");
              if(coll.val() != newValue) {
                coll.val(newValue).change();
              }
            }
          }
          return new originalContentLoader (url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt);
        }
      })(window.jQuery);
    } else {
      // pt 8.4x, $(document).ready below will handle pt 8.4x
    }
  
    // just in case advanced is the initial view
    $(document).ready(function() {
      var newValue = 9;
      var coll = $("select[name='APT_UI_SCRIPTS_MENUNAME$op']");
      if(coll.val() != newValue) {
        coll.val(newValue).change();
      }
    });
  }
</script>

Tuesday, October 04, 2011

Monkey Patching PeopleSoft

As a PeopleSoft developer responsible for upgrades and maintenance, I work extra hard up front to avoid changing delivered code. My potential reward is less work at patch, bundle, or upgrade time. One way I deliver new user interface features without modifying delivered code is by writing Monkey Patches. Monkey Patching is a term used with dynamic languages for modifying runtime behavior without changing design time code. Dynamic languages, such as JavaScript support this by allowing developers to override, extend, or even redefine objects and methods at runtime. Let me set up a scenario:

In PeopleTools 8.49 and earlier, I could tell when an action happened in a component (FieldChange, Save, Prompt, etc) by listening for the window load and unload and document ready events. PeopleTools 8.50, however, triggers these events through Ajax requests, which means the page state doesn't change. With 8.50, I had to find an alternative JavaScript mechanism for identifying these same actions, and the PeopleTools net.ContentLoader JavaScript object seemed just the ticket. By wrapping this JavaScript object with my own implementation, I can hook into the PeopleTools Ajax request/response processing cycle. If you have Firebug and PeopleTools 8.50 (or higher), then load up your User Profile component (/psc/ URL only) and run this JavaScript:

(function() {
  var originalContentLoader = net.ContentLoader;
  net.ContentLoader = function(url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt) {
    console.log(name);
    return new originalContentLoader (url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt);
  }
})();

Next, click on one of the prompt buttons on the user profile General tab. You should see the name of the button you clicked appear in the Firebug console. Notice that the button name appears in the Firebug console before the Ajax HTTP Post. If you wanted to take action after the Ajax response, then you would implement your own onload handler like this:

(function() {
  var originalContentLoader = net.ContentLoader;
  net.ContentLoader = function(url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt) {
    console.log(name);
    
    var originalOnLoad = onload;
    onload = function() {
      if (typeof originalOnLoad == "undefined" || !originalOnLoad) {
        this.processXML();
      } else {
        originalOnLoad.call(this);
      }
      console.log("Ajax response received");
    }

    return new originalContentLoader (url,form,name,method,onload,onerror,params,contentType,bAjax,bPrompt);
  }
})();

Notice that the text "Ajax response received" appears after the HTTP post, meaning it executed after the page received the Ajax response.

When creating Monkey Patches, it is critical that you consider the original purpose of the overridden code. In this example we redefined the net.ContentLoader, but maintained a pointer to the prior definition. It is possible that another developer may come after me and create another patch on net.ContentLoader. By maintaining a pointer to the net.ContentLoader, as it was defined when my code ran, I ensure that each patch continues to function. In essence, I'm developing a chain of patches.

Monkey Patching has a somewhat less than desirable reputation, and for good reason. If allowed to grow, patches on patches can make a system very difficult to troubleshoot and maintain. Furthermore, if one patch is not aware of another patch, then it is entirely possible that a patch could be inserted in the wrong place in the execution chain, upsetting the desired order of patches.

"With great power comes great responsibility" (Voltaire, Thomas Francis Gilroy, Spiderman's Uncle Ben? Hard to say who deserves credit for this phrase). Use this Monkey Patching technique sparingly, and be careful.

Monday, October 03, 2011

Accordion Navigation Collections

A few months ago we released a White paper about PeopleSoft Applications Portal and WorkCenter Pages that showed screen shots of an accordion menu. A lot of you asked how we created these pagelets. Tomorrow in our OOW session PeopleSoft Answers: How to Create a Great PeopleSoft UI, I will demonstrate creating the pagelet, but we won't have time to walk through the XSL -- the critical piece. For those of you that will be there (and those that won't but know how to use Pagelet Wizard), here is the XSL: accordion-nav-hosted.xsl.

Disclaimer: I make no warranty regarding the use of this XSL.

Security Warning: To make sure the XSL will work "out of the box," I pointed the JavaScript at Google's hosted JavaScript API's. Since this code is used on your enterprise home pages, I suggest you replace these references with references to your own site's versions of these libraries. The thought of allowing some external service to run code on my pages makes me a bit nervous.

I have to point out a minor difference between the output of this XSL and the output shown in the white paper: This XSL opens links in the current window or a new window. It does not use modal dialogs. Navigation Collection XML contains absolute PSP URL's, which don't display well in a modal dialog. The version shown in the White paper actually uses a custom transformer and some PeopleCode to convert psp URL's into psc URL's for dialogs.

Update March 5, 2012: Leandro, a reader of this blog, posted his derivative of this stylesheet. You can download it here. Leandro wants to make sure you know that it works on the single nav collection for which he tested, but other exceptions may arise. I looked through the XSL, and it looks good. Here is a list of the differences between Leandro's version and mine:

  • Updated the links to jQuery and jQuery UI (JS and CSS) to the latest versions.
  • Commented out the custom dialog framework code that would open jQuery UI dialog IFrames (because the code to make the iframe is not present in Jim's original).
  • Included the description of the top-level folders in the H3 tag's title attribute, so mouse-over of the accordion items will display the description of the menu. (This was already done by you for inner folders and shortcuts.)
  • The resulting accordion menu will be sorted as you would typically find in a PeopleSoft navigation collection: all folders before all shortcuts, and the "# more..." pseudofolder (if any) at the end.

Thursday, September 22, 2011

Creating Binary Arrays

Lately I have been using PeopleCode to manipulate binary files: moving files, copying files, and even creating zip files. A prerequisite for reading from and writing to binary files is the basic binary array -- the buffer. My blog post Base64 Encoding for PeopleSoft demonstrated a very complicated method for creating binary files that worked with PeopleTools 8.49 and earlier, but does not work on my PeopleTools 8.51 systems. While studying PeopleBooks I found a much easier, well documented method for creating binary arrays:

Local JavaObject &bytes = CreateJavaArray("byte[]", 1024 /* length of array */);

For arrays with known values at construction time, you can use the CreateJavaObject function:

Local JavaObject &bytes = CreateJavaObject("byte[]", 5, 10, 15, 20);

Note: Since this is documented, I suspect these functions will work with PeopleTools 8.49 and earlier, but I haven't tested them on earlier PeopleTools versions. If this method won't work in PeopleTools 8.49 or earlier, then you are welcome to use the alternative:

REM ** get a reference to a Java class instance for the primitive byte array;
Local JavaObject &arrayClass = GetJavaClass("java.lang.reflect.Array");
Local JavaObject &bytes = &arrayClass.newInstance(GetJavaClass("java.lang.Byte").TYPE, 5);

I would like to call out Kris who posted a comment on Base64 Encoding for PeopleSoft stating that the older method no longer worked. I happened to be working on zipping files with PeopleCode the week before Kris's comment and discovered the same issue and resolution. Very timely.

Wednesday, September 21, 2011

OpenWorld Schedule 2011

I can hardly believe it. One more week at home and then I'm off to San Francisco for the biggest Oracle show of the year. I will be in San Francisco pretty much all week and would love to meet any of you that are attending. Here is where you will find me:
  • Monday 9:45 AM to 1:30 PM -- Integration Broker demo pod
  • Tuesday 9:45 AM to 12:00 PM -- Integration Broker demo pod
  • Tuesday 1:15 PM to 2:15 PM -- Session 14020 PeopleSoft Answers: How to Create a Great PeopleSoft UI (Moscone West 2024)
  • Tuesday 3:30 PM to 4:30 PM -- Session 14003 PeopleSoft PeopleTools Tips and Techniques (Moscone West 2022)
  • Wednesday 10:00 AM to 10:30 AM -- Meet the Authors @ the Moscone West bookstore (bring your book so I can sign it)
  • Wednesday 12:30 PM to 4:00 PM -- Integration Broker demo pod
  • Thursday 10:00 AM to 10:30 AM -- Meet the Authors @ the Moscone West bookstore (bring your book so I can sign it)

Wednesday, April 06, 2011

Collaborate 2011 Schedule and Book Signing

Collaborate is only a couple of days away. If you are a reader, I'd love to meet you. Here are some times and places we can connect:

  • Monday, 5/11 6:00 PM - 8:00 PM -- Exhibition Hall PeopleTools demo pod.
  • Tuesday, 5/12 10:15 AM - 2:00 PM -- Exhibition Hall PeopleTools demo pod.
  • Tuesday, 5/12 3:15 PM - 4:15 PM -- Session 85680 PeopleTools 8.51 Highlights - PeopleTools in Action room 203B (Quest)
  • Tuesday, 5/12 4:30 PM - 5:00 PM -- Book signing at the Collaborate book store
  • Tuesday, 5/12 5:30 PM - 7:00 PM -- Exhibition Hall PeopleTools demo pod
  • Wednesday, 5/13 8:00 AM - 9:00 AM -- Session 85670 PeopleTools Tips and Techniques room 203A (Quest)
  • Wednesday, 5/13 10:15 AM - 4:00 PM -- Exhibition Hall PeopleTools demo pod

McGraw Hill was also able to schedule a special book signing event for Tuesday between 4:30 PM and 5:00 PM. Follow me down to the book store after my PeopleTools in Action session, buy a book, and I'll sign it for you. If I lose you, I've been told the bookstore is next to registration. See you there!

Tuesday, April 05, 2011

Pagelets, WorkCenters, etc in White Paper

Some of my friends from sales and product strategy just put together a very nice white paper on some of the new features in PeopleTools and Applications Portal (formerly known as Enterprise Portal). I created some of the content in the screen shots (home page layout, accordion navigation collections, slide show news publications, etc) and they did all the writing. Download a copy and see what you can do with your PeopleSoft application. The paper is titled PeopleSoft Applications Portal and WorkCenter Pages.

Monday, April 04, 2011

blogger.com's Views

Have you seen blogger.com's new dynamic views? For my site, most aren't that exciting, but the flip card view for labels is pretty interesting. Rather than just seeing the usual label (count), you can see the actual titles under each label.

Wednesday, February 16, 2011

Alliance 2011

I'm just finishing my demos for this year's Alliance conference. I will present session 29321, PeopleTools Tips and Tricks, on Monday morning from 9:30 to 10:30 in Korbel 4A-C. In this session I will present some mobile, mashup, and ajax solutions as well as tips for debugging these client/server HTTP interactions. On Tuesday, I will show you some of the new PT 8.50/51 features during the session 29332 "PeopleTools 8.51 in Action" at 12:45 in Korbel 4A-C.

If you are not able to attend these sessions, then please feel free to chat with me in the Exhibition Hall or at Meet the Experts. I will be in the Exhibition Hall Sunday from 5:30 to 8:30, Monday from 12:45 to 2:15, and again on Tuesday from 12:30 to 2:15. I will be at the Meet the Experts PeopleTools table on Monday from 4:30 to 5:30 and on Tuesday from 9:30 to 10:30.

I can't wait to see you there!!

Thursday, February 10, 2011

JavaScript Meta blog

JavaScript is a critical component of PeopleSoft applications. With the web browser pretty much taking over as the rendering engine for enterprise applications, I see JavaScript as a critical language for computer professionals. Of course, technologies like PeopleTools and ADF contain abstraction layers so application developers do not have to write JavaScript, but, in the end, someone has to write the JavaScript generated by those abstraction layers. And, if something goes wrong, odds are very good you will have to dig through the generated JavaScript to see what went wrong (where, when, why, etc).

Anyway, I think JavaScript is one of the most important modern languages a programmer can learn, and I know I'm not alone in this opinion. Of late, I've found some very interesting online resources for people interested in learning JavaScript, so I wrote this post to pass those resources along to PeopleSoft developers.

I will maintain this as a "Meta-blog" post and update it as I find more resources. I will attempt to keep the list short, so you don't have to sift through thousands of irrelevant tutorials. Restated: this is not a complete list. It is just a short list of tutorials that I think stand above the rest.