Friday, February 15, 2008

Get Your Mix Account and Vote

Do you have a Mix account yet? If not, then get one. After you create an account, add the PeopleSoft and PeopleTools groups to your profile. And then, be sure to vote for ideas submitted by your peers. For example, if you want Code Completion in Application Designer or Search by process name when adding process definitions to projects, then vote for it.

There are several good communities for PeopleSoft developers. Why join Mix? Mix has one thing the other communities don't. Mix has PeopleSoft developers and consultants. Yes, the other communities do have some Oracle staff, but not like Mix. Are you looking for a "Meet the Experts" experience all year, not just at OOW? Then try Mix.

Java, XPath, XML and Facebook

PeopleSoft's Integration Broker and Web Services provide an excellent framework for web services integration. But what if your PeopleSoft system needs synchronous access to another system that doesn't publish web services? For example, let's say you need to communicate with a system like Facebook that has a Java client library (yes, Facebook has a REST-based API, but using the existing Java client is much easier than creating all of the messages, handlers, and Facebook specific publishing logic). Even though we can call Java directly from PeopleCode, the Facebook methods return a value of type org.w3c.dom.Document. Since this return value is a Java object, not a PeopleCode XmlDoc, you cannot use the standard PeopleCode Node methods to extract values from the resultant document. In the absence of an additional client library, we would have to write DOM traversal code to select and concatenate the text node values contained in the Facebook response elements. Fortunately, the PeopleSoft application server installation includes the Xalan XML processor. The Xalan client library includes the org.apache.xpath.XPathAPI class that can be used to select values from a Java DOM Document similar to the XmlDoc.FindNode method. Here is an example of using the XPathAPI in PeopleCode to extract the name of the first friend from a Facebook friends query:

Local JavaObject &results = &fbClient.fql_query("SELECT uid, name, status FROM user WHERE uid IN (SELECT uid2 FROM friend WHERE uid1 = '" | &uid | "')");
Local JavaObject &xpath = GetJavaClass("org.apache.xpath.XPathAPI");
Local string &name = &xpath.selectNodeList(&results, "/fql_query_response/user[1]/name/text()");

Sunday, February 10, 2008

What is an IScript?

It has been a few years since I attended my first PeopleSoft|Connect conference. As a new PeopleSoft developer, I was eager to learn all I could about PeopleSoft's Integration Broker, PeopleTools, and PeopleSoft's web UI. I spent hours pestering the experts (ask Robert Taylor, a prior Integration Broker product manager, and Tushar Chury, a former component interface developer). During one of the sessions I attended, someone from the audience asked a question about integration and the presenter replied, "I would probably create an IScript to do that." I don't remember the question. The only thing that stuck with me was the term "IScript." I had so many other questions for the experts that I didn't ask what an IScript was. Nevertheless, I left the event with a big question: "What is an IScript?" Since I had already taken the PeopleTools and PeopleCode classes and had not heard mention of IScripts, I decided they must be some legacy PeopleSoft technology that I didn't need to learn. To satisfy my curiosity, I looked up IScripts in PeopleBooks and received a... well... thorough definition... just like reading a good dictionary (see Enterprise PeopleTools 8.49 PeopleBook: PeopleCode API Reference > Internet Script Classes (iScript)). Yes, after reading the definition in PeopleBooks, I knew what an IScript was, but I just couldn't figure out why I would want to use one. Now, several years later, I find that I can't work without IScripts. Ajax, pagelets, WML, and SVG provide excellent use cases for IScripts. Each of these "technologies" requires marked up text without the overhead of the PIA rendered component HTML.

I like to think of IScripts as the PeopleTools developer's Swiss Army Knife. Besides a "cutting implement" a Swiss Army Knife might have a leather punch, a screw driver, a can opener, etc. Yes, you can do just about anything with a Swiss Army knife, but it might take you a long time to get the job done. Then, when you are done, the job might not be as satisfactory as it would have been if you had used the right tool. Have you ever opened a can with a Swiss Army Knife can opener? I'll bet you worked up an appetite. Likewise an IScript is the right tool for some jobs, but choose wisely. You can probably replicate the postback behavior of a component with an IScript, but it is a lot of unnecessary work. Likewise, you may have to consider multi-lingual translations, etc.

I compare IScripts to JSP or ASP. Basically an IScript is PeopleCode that has access to the Request and Response objects. Just like JSP and ASP, you, the developer, writes code to read parameters from the request and write information, data, etc to the response. Unfortunately, just like ASP, the response object's write methods only render text. Since the response object does not contain any binary write methods, you will have to ignore the dynamic image generation possibilities (I was hoping to use IScripts to render images stored in a user table, but I haven't figured out how to make that work since the write method only accepts plain text).

How do you create an IScript? For more information, you can look it up in PeopleBooks, but just to vaguely satisfy your curiosity, IScripts follow the same design pattern as FUNCLIBS. An IScript is a PeopleCode function stored in a record definition. The record definition name must start with WEBLIB_. The function can be in any field event of the record definition. By convention, we generally use the field ISCRIPT1 and the event FieldFormula. The function name, however, must start with IScript_ and cannot take any parameters or return a value.

How do you call an IScript? IScripts can be called a number of ways. How you call it depends on the purpose of the IScript. If your IScript is a pagelet, then you will create a CREF for your IScript in the portal registry under Portal Objects > Pagelets. If your IScript is called from JavaScript (Ajax, etc), then you call your IScript using a URL like http://server:port/psc/site_name/portal_name/node_name/s/WEBLIB_name.FIELDNAME.FieldFormula.IScript_name. To make it easier, you can generate an IScript URL using the PeopleCode built-in function GenerateScriptContentURL.

Now that you know what an IScript is, you might be interested in looking at some examples. Chris Heller posted a couple of IScripts that can be used as Bookmarklets. These Bookmarklets allow us, the developer, to exend our existing tool set by writing tools that we can use where we work: in the web browser. On Wednesday, April 4th, 2006, Chris posted a bookmarklet/IScript that will drill into a portal registry content reference from a PeopleSoft page. In his 2006 Open World and 2007 Alliance presentations, Chris showed us how to use IScripts and bookmarklets to turn on tracing and display security information. ERP Associates also has some good PeopleSoft Bookmarklet examples.

Thursday, February 07, 2008

Portal Template Settings

PeopleSoft uses Content References (CREF's) to describe how to display content within the PeopleSoft Portal (Enterprise or standard PeopleTools Portal). A very important setting for describing how to display a CREF is the CREF's template. The template describes how the content should be wrapped or "framed." Some templates proxy content into a single HTML page. Other templates use frames to display content. The most common frames template is the template that displays the header at the top, a menu on the left, and a content window on the right. If a CREF does not specify a template, then the Portal will use the default template. The default CREF template is set in PeopleTools > Portal > General Settings. If you haven't changed this setting, then your template is DEFAULT_TEMPLATE, also known as Portal default template. After looking up the default template, we can navigate to PeopleTools > Portal > Structure and Content to view the definition for this template. Templates are stored in the portal registry under Portal Objects > Templates. If your template has a storage type of "Local (in HTML Catalog)", then you can modify your template's HTML directly in this CREF. CREF's with a storage type of "Remote by URL", like the Portal default template, usually retrieve dynamic content from an IScript. Theoretically, you could store your template definition in any format or system as long as it is accessible by a URL (think of the possibilities for dynamic or even hosted templates). The IScript for the delivered Portal default template reads its settings from a different Content Reference. The name of this settings content reference is stored in the field PT_PORTAL_PROFILE of table PS_PTPP_OPTIONS.

SELECT PT_PORTAL_PROFILE FROM PS_PTPP_OPTIONS

With just a CREF name, you will have a hard time changing the template's values. The post Query for Component and/or CREF Navigation contains SQL to help you find the Structure and Content navigation for the CREF stored in PT_PORTAL_PROFILE. If you haven't customized your system, the settings CREF is PT_PORTAL_PROFILE (or PAPP_PORTAL_PROFILE if you are using Enterprise Portal). The PT_PORTAL_PROFILE CREF is stored in the Portal Registry's structure and content at Tools - Hidden > PeopleTools Portal Profile (For Enterprise Portal: Enterprise Portal - Hidden > Enterprise Portal Profile). From this CREF's attributes, you can specify the frame header height, whether to display the menu title, whether to show Search in the menu, as well as many other portal related settings. For example, if you wanted to change the frame header height from the default of 65 to 48 to give you more space for content, you would change the value of the attribute HEADER_FRAME_ROWS from 65 to 48.

Thursday, January 31, 2008

%Component Gotcha

I was just writing an IScript for the Approval Workflow Engine (AWE) that called the Approval Manager class to approve a transaction. The transaction failed because the Application Classes used in the Event notification handler used the %Component system variable. This would have been fine except %Component cannot be called from an IScript. To work around this, I wrapped the calls to %Component in a function that checks whether the execution context is a component. Here is the code:

Function GetComponentName() Returns String
If (%ContentType = "c") Then
Return %Component;
Else
Return "";
End-If;
End-Function;

If you are writing your code in a Page or a Component and use the %Component system variable, then you shouldn't have any problems. But, if your code is in a FUNCLIB or Application Class, a reusable component, then be aware that one of those "reuses" might be from PeopleCode that runs outside a Component (IScript, AppEngine, Message Subscription, etc). If that is the case, then please be kind to the developer that follows you by wrapping your calls to %Component in a function that tests to see if your code is executing within a Component.

%Request.GetParameterNames

I was working on an IScript that wrote WML to the browser and needed to pass the query string parameters back to the client as postfields. I thought I would just loop through the %Request.GetParameterNames array and write those parameters back to the client marked up as postfields. When I did this I saw 6 additional parameters:

PSHome
Portal
Node
ContentType
ContentID
ICScriptName

To test this, run the following IScript:

Function IScript_TestParams
Local array of string ¶ms = %Request.GetParameterNames();
Local string ¶mName;
Local number ¶mIdx;

%Response.SetContentType("text/plain");

For ¶mIdx = 1 To ¶ms.Len
¶mName = ¶ms [¶mIdx];
%Response.WriteLine(¶mName | ": " | %Request.GetParameter(¶mName));
End-For;

End-Function;

Now, the part that really, really threw me was how PeopleSoft interpreted the ICScriptName parameter. The code I wrote copied the request parameters to the response as postfields and then posted them back to a different IScript on the same server. After a good hour of troubleshooting, trying to figure out why the browser never displayed the second IScript, I realized that the psc servlet was using the IScript from the ICScriptName parameter, not the IScript in the main URL. In fact, modifying the URL a little bit, I noticed that you can leave off the Record.Field.Event.IScript_Name portion of the URL in favor of ?ICScriptName=Record.Field.Event.IScript_Name (not that you would want to do that).

So what now? How can we work around this %Request.GetParameterNames dilemma? Here is a function that will parse the %Request.QueryString into key/value pairs and print them to the browser:

Function IScript_TestParams2
Local array of string ¶ms = Split(%Request.QueryString, "&");
Local array of string &keyValue;
Local number ¶mIdx;

%Response.SetContentType("text/plain");

For ¶mIdx = 1 To ¶ms.Len
&keyValue = Split(¶ms [¶mIdx], "=");
%Response.WriteLine(&keyValue [1] | ": " | Unencode(&keyValue [2]));
End-For;

End-Function;

Of course, this function does not account for parameter arrays, etc. I'll leave that up to you.

Caveat: I was working on a PeopleTools 8.48.07 instance. I have no idea if this behavior is the same on other PeopleTools versions

Tuesday, December 04, 2007

Query for Component and/or CREF Navigation

I regulary have to figure out the menu/portal navigation to a component given nothing more than a component or a CREF name (AKA Content Reference or Portal Object Name). For example, looking at a Pagelet definition in the Pagelet Wizard, you may see the cryptic content reference name for a component, but nothing telling you how to navigate to that component and no hint to help you find it in the portal registry. Likewise, a user might give you the menu and component name of a troubled component, but not the navigation to that component. It is situations like this that we, as developers, can realize value from the PeopleTools meta-data. Since the navigation, CREF name, and menu/component relationship is stored in the PeopleTools database, we can query a tools table to determine this navigation. The following Oracle specific SQL displays the navigation to a given CREF name. If you use a different database, and are familiar enough with your database's SQL, please translate this statement and post it as a comment for the benefit of the rest of the community.

WITH PORTAL_REGISTRY AS (
SELECT RTRIM(REVERSE(SYS_CONNECT_BY_PATH(REVERSE(PORTAL_LABEL), ' >> ')), ' >> ') PATH
, LEVEL LVL
FROM PSPRSMDEFN
WHERE PORTAL_NAME = 'EMPLOYEE'
START WITH PORTAL_OBJNAME = :1
CONNECT BY PRIOR PORTAL_PRNTOBJNAME = PORTAL_OBJNAME )
SELECT PATH
FROM PORTAL_REGISTRY
WHERE LVL = (
SELECT MAX(LVL)
FROM PORTAL_REGISTRY )

NOTE: Even though I've written my fair share of SQL, I'm no expert. Please don't grade me on the elegance and efficiency of the previous statement. If you are an SQL expert, and have a better way of writing this recursive SQL statement, then, please, for the benefit of the community, paste that statement into a comment. That said, I'll continue with the topic at hand...

If we pass EP_STANDARD_CF_TMPLT_GBL as bind :1, then the result will be Root >> Set Up Financials/Supply Chain >> Common Definitions >> Design ChartFields >> Configure >> Standard Configuration.

Modifying the above SQL statement a little, we can determine the navigation for a given menu, component, and market (the Ctrl-J data our users usually give us):

WITH PORTAL_REGISTRY AS (
SELECT RTRIM(REVERSE(SYS_CONNECT_BY_PATH(REVERSE(PORTAL_LABEL), ' >> ')), ' >> ') PATH
, LEVEL LVL
FROM PSPRSMDEFN
WHERE PORTAL_NAME = 'EMPLOYEE'
START WITH PORTAL_REFTYPE = 'C'
AND PORTAL_URI_SEG1 = :1
AND PORTAL_URI_SEG2 = :2
AND PORTAL_URI_SEG3 = :3
CONNECT BY PRIOR PORTAL_PRNTOBJNAME = PORTAL_OBJNAME )
SELECT PATH
FROM PORTAL_REGISTRY
WHERE LVL = (
SELECT MAX(LVL)
FROM PORTAL_REGISTRY )

If we pass DESIGN_CHARTFIELDS for bind :1 (menu), STANDARD_CF_TMPLT for bind :2 (component), and GBL for bind :3 (market), then we will get the same result as the previous query, but using the Ctrl-J data rather than the CREF name.

Tuesday, November 13, 2007

Create Your Own Meta-HTML Elements

One thing that keeps me excited about PeopleSoft is the flexibility of the PeopleTools platform. As I was working on a a custom Pagelet Transform Type, following the details outlined in Rich's blog post Markdow Text Filtering for PeopleSoft, I realized I was actually creating a custom Meta-HTML element. How cool is that? Not only can I extend the PeopleCode language using Java, I can also extend the Meta tag set. Here is the code:

Function ResolveMetaHTML(&html as string) returns string
Local JavaObject &pattern;
Local JavaObject &matcher;
Local String &node_url;

REM ** Resolve %NodePortalURL(NODENAME) tags;
&pattern = GetJavaClass("java.util.regex.Pattern")
.compile("(?i)%NodePortalURL\((\w+)\)");

&matcher = &pattern.matcher(
CreateJavaObject("java.lang.String", &html));

While &matcher.find()
SQLExec("SELECT URI_TEXT FROM PSNODEURITEXT WHERE MSGNODENAME = :1 AND URI_TYPE = 'PL'", &matcher.group(1), &node_url);
&html = Substitute(&html, &matcher.group(), &node_url);
End-While;
End-Function;

This Meta-HTML element replaces %NodePortalURL(NAMEOFNODE) with the Portal URL defined on the portal tab of the node NAMEOFNODE. This can be used to ensure images, scripts, CSS, links, iframes, etc point to the correct server at runtime.

If you want to create your own Meta-HTML elements, I suggest you place the implementation of those elements inside an Application Class. This custom Application Class would be responsible for accessing its HTML definition using GetHtmlText and replacing all instances of custom Meta-HTML elements with your implementation of those Meta-HTML elements. Rather than call GetHtmlText directly, your PeopleCode would use your custom Application Class.

If this works for Meta-HTML, why not custom Meta-SQL?

Monday, November 12, 2007

Desktop Integrated Signon

Several months ago I had the opportunity to configure a PeopleSoft system to "trust" users' desktop credentials. Some would call this single signon or even Desktop Integrated Signon. Implementing desktop integrated signon requires some configuration and a small amount of development. The process looks like this:

  1. Download the JCIFS NtlmHttpFilter,

  2. Modify the filter to pass the desktop user name to the app server as a request header (compile and deploy included, of course),

  3. Write some signon PeopleCode,

  4. Enable public access,

  5. Enable signon PeopleCode, and

  6. Configure your web server to use your new filter (see the JCIFS NtlmHttpFilter documentation for configuration details as details will differ depending on your environment).

After downloading the filter and filter source code, open the NtlmHttpServletRequest and implement the getHeader and getHeaderNames overrides with the following code.

    public String getHeader(String name) {

if(name.equals("XX_REMOTE_USER") {
return getRemoteUser();
} else {
HttpServletRequest req = (HttpServletRequest)this.getRequest();
return req.getHeader(name);
}

}
public Enumeration getHeaderNames() {
Vector headers = new Vector();
HttpServletRequest req = (HttpServletRequest)this.getRequest();

for (Enumeration e = req.getHeaderNames() ; e.hasMoreElements() ;) {
headers.add(e.nextElement());
}

headers.add("XX_REMOTE_USER");
return headers.elements();
}

Next, put the following PeopleCode in a FUNCLIB:

Function WWW_NTLM_AUTHENTICATE()
Local string &userName = %Request.GetHeader("XX_REMOTE_USER");
Local number &foundSlash = Find("/", &userName);

REM ** remove the NT/AD domain;
If(&foundSlash > 0) Then
&userName = Substring(&userName, &foundSlash + 1, Len(&userName));
Else
&foundSlash = Find("\", &username);
If(&foundSlash > 0) Then
&userName = Substring(&userName, &foundSlash + 1, Len(&userName));
Else
End-If;

If(Len(&userName) > 0) Then
SetAuthenticationResult(True, &userName);
Else
SetAuthenticationResult(False, &userName, "Web server authentication failure");
End-If;
End-Function;

Like I said, it has been a few months since I wrote this code, and, unfortunately, I'm typing it here from memory. Please correct any mistakes I've made. Refer to PeopleBooks for enabling signon PeopleCode and enabling public access. Both are documented in the Security Administration PeopleBook.

A couple of issues I've found with this approach:

  • If you are using Enterprise Portal and want to allow desktop integrated signon to both the portal and to the content provider apps, then you will need to further customize the filter to skip NTLM on your content provider web servers when the client is the portal server. Otherwise, the NtlmHttpFilter will not allow portal to access those web servers (this only affects homepage creation when you have pagelets that come from a content provider). If you only access your PeopleSoft systems through Enterprise Portal, then this is not an issue. Likewise, if you are configuring this solution on your PeopleSoft applications and you do not have Enterprise Portal, then this is not an issue.

  • In this scenario, your app server trusts the security information provided by the web server, bypassing the app server's standard authentication routine. This may pose a security threat if users can gain access to your app server. To mitigate this risk, you may want to either hide your app server behind a firewall or perform additional validation/authentication (digitally encrypt the user ID request header on the web server with a certificate and decrypt it on the app server, pass the NTLM authentication token on to the app server and validate it again, etc).

  • Since this solution requires your web server to trust your desktop, make sure your organization has a strong password policy forcing strong passwords. If you use a desktop integrated sign on solution, then any user that can gain access to a desktop by cracking a password can also gain access to your Enterprise applications. As an alternative to passwords, consider key fobs.

If you would like to allow administrators to log in as someone other than their desktop user (psadmin, for example), then you can add an "if" test to your signon PeopleCode that compares %SignonUserId to the public user name. If the user name is the same as your public user name, then log the user into the application as the user given by the web server. Otherwise, return from this function and allow the standard signon processing to authenticate the user.

Network Enabling Technologies

Besides my OpenWorld presentation on Wednesday, I'm also staffing demo pod 15 Monday, Tuesday, and Thursday. Today, while discussing PeopleTools with our customers at pod 15, a brilliant gentleman asked me, "How can I encrypt and digitally sign e-mails sent by the PeopleSoft process scheduler and the workflow engine?" My first answer? "Hmmm..." My first action? Turn to legendary Chris Heller, who happened to be standing near me, to ask him what he thought. The three of us, along with my pod mate Rahul, discussed some options and came up with the following ideas:

  • If your SMTP server can be configured to do so, then have it digitally sign and encrypt your e-mails.

  • If your SMTP server can't handle this task, then setup a secure e-mail relay between PeopleSoft and your SMTP server for the purpose of encrypting and signing e-mails.

This question reminded me of another networking related enabling solution. This problem and solution relate to Integration Broker's proxy settings. If your Integration Broker resides behind a proxy server and you have configured Integration Broker to use that proxy server, then you may have noticed that Integration Broker will send all requests through your proxy server. This is good, if the request target resides outside your firewall. This may not be good if the requested resource is inside your firewall. The problem is caused by the fact that Integration Broker cannot be configured to bypass its proxy server for specific hosts. If you find yourself in this situation, then here are a couple of solutions:

  • Configure your firewall proxy server to be an Intercepting Proxy. From a PeopleSoft configuration perspective, this solution is the easiest because it allows you to ignore the proxy issue.

  • Use a forwarding proxy server. Apache's mod_proxy is the first that comes to mind. If you use a forwarding proxy, then be sure to secure it. The last thing you want is for your forwarding proxy to become an open proxy.

Another option is to configure your proxy server to connect to both internal and external sites. I do not recommend this for a couple of reasons:

  1. You may inadvertently make a path for other, external programs to access your internal servers.

  2. You unnecessarily increase the amount of traffic your firewall proxy server has to handle.

Before choosing a solution to either of these network related issues, be sure to discuss your options with your network security staff.

Thursday, September 27, 2007

Presenting at OpenWorld 2007

Have you made your reservations for the 2007 Oracle OpenWorld experience? Are you looking for a PeopleSoft session packed with highly technical content that goes beyond App Designer? I will be presenting PeopleSoft PeopleTools Advanced Tips and Techniques on Wednesday afternoon. I am planning to talk about IScripts, Ajax, Java, JSP, and Servlet filters, all within the context of PeopleSoft. I'm also scheduled to staff the PeopleTools demo pod at various times throughout the conference. I hope to see you there!

Wednesday, September 26, 2007

log4j and PeopleCode Part III

John Wagenleitner has posted some additional ways to configure log4j with PeopleCode in his post, appropriately titled, Log4j in PeopleCode. If you are considering using log4j with PeopleCode, you will want to take a look at the comments. Scheming together, John and I have come up with a couple of ways to store the log4j configuration in the PeopleSoft database. This is critical if you work in an environment where you don't have access to the application server's file system.

Tuesday, September 04, 2007

A Quasi-dynamic Signout Template

Nested under the WEB-INF/psftdocs directory of your PeopleSoft web server, you will find several HTML templates. Even though the title of this post references the signout template specifically, the concepts outlined in this post are relevant to the other templates as well.

Template Variables

As you browse the delivered templates, you will notice that several templates include JSP/ASP style tags used to insert text into the template. To include additional localized text in the signout.html template, you can add an entry to your language's text.properties file. For example, to include the text Please contact the IT Help Desk for further information in your template, add the following text to the text.properties file.

6000=Please contact the IT Help Desk for further information

To insert that text into your template, add <%=6000%> to your template.

Query String

Since HTML templates are read and parsed by PeopleSoft, we really can't enhance them with dynamic content beyond the functionality built into that parser. Therefore, our ability to inject dynamic content into these templates is somewhat limited. Nevertheless, if we can get additional data into the logout URL as query string parameters, we can access those parameters from the template at "runtime" using JavaScript.

Now the real trick... appending key/value pairs to the logout URL. If you are using PeopleSoft's Enterprise Portal, you can modify the sign out link from the Define Headers component (Portal Administration > Branding > Define Headers). Other alternatives for enhancing the sign out link include modifying the HTML objects that define the header or using JavaScript to modify the href attribute of the Sign out link.

ServletFilter

Using a Servlet Filter like Monkeygrease we can inject valid HTML content (including JavaScript, CSS, HTML, etc) into the PeopleSoft response. If you really want to get dynamic, you can create your own filter to do just about anything (access a database with JDBC, call a web service, etc).

Thursday, June 28, 2007

How to Sell Enterprise Ajax

I've heard that IT staffs are having trouble selling Ajax to the enterprise. The main enterprise response is "we don't need cute, we need fast and functional." In my opinion, that is the definition of Ajax: fast and functional. We don't add Ajax functionality to PeopleSoft applications to make them cute, we add Ajax to make our applications easier to use. We use Ajax to simplify and automate user system tasks.

I like to compare common web applications like Expedia and Amazon to enterprise applications. Those external-facing portals are enterprise class systems. The difference between those external-facing systems and the standard internal-use enterprise system is the amount of training required to use those systems. Ajax, Flex, and other RIA enabling technologies allow us to refactor our user interfaces to make them intuitive.

Consider complex enterprise purchasing systems... our purchasing agents should not need to learn our purchasing systems. We want them to be contract experts, not purchasing system experts. Instead, our purchasing systems should be so intuitive our users can figure out how to use them with little or no training. This is especially critical for our casual users.

Business Performance Management Magazine recently published an article explaining this usability issue from the perspective of budgeting and planning titled About Face: Why BPM Front Ends Are Failing.

When selling RIA, remember, it is not cute, it is usable.

Monday, June 18, 2007

Presenting at OracleDay 2007

On June 28th at 4:15 PM I will be presenting the topic Add the Adjective "Rich" to your PeopleSoft User Experience in room 408 of the Meydenbauer Conference Center. You can read the description on the OracleDay schedule. I hope to have a working demo of some of the rich internet technologies we have integrated with our PeopleSoft applications. Depending on the interests of the audience, this will either be a high level demonstration of what is possible, or a technical discussion of how to implement Web 2.0 in a PeopleTools 8.4x environment.

Saturday, June 09, 2007

Using Regular Expressions in PeopleCode

Where are the PeopleCode Regular Expressions? They don't exist. Fortunately, since PeopleCode supports Java, we can "borrow" them for use in our PeopleCode. Here is an example similar to the BSF example I posted earlier:

Function get_site_name() Returns string
Local JavaObject &patternClass = GetJavaClass("java.util.regex.Pattern");
Local JavaObject &pattern = &patternClass.compile("/??(\w+?)(?:_\d+?)?/.+$");
Local JavaObject &jstring = CreateJavaObject("java.lang.String", %Request.PathInfo);
Local JavaObject &matches = &pattern.matcher(&jstring.subSequence(0, &jstring.length()));

If (&matches.matches()) Then
Return &matches.group(1);
Else
Return "";
End-If;
End-Function;

Where is Jim?

Just in case you are wondering why I haven't been posting fantastic PeopleSoft tricks the past few months, it is because I was spending my off hours helping out at home while anxiously awaiting the arrival of Esther May Hope, our third child. She arrived May 17th. She is "healthy as an ox" and "eats like a horse."

Scripting PeopleSoft

In many organizations, the IT programmers are divided into two groups: those that program in the language of the enterprise system (PeopleSoft) and those that don't. Those that don't may prefer scripting languages like Python or Ruby. Whatever the language, the two groups will occasionally have to work together.

There are a couple of ways to execute scripts from PeopleSoft. If the target scripting language's binaries exist on your app or process scheduler server, then you can either call the script through the PeopleCode exec function or setup a process definition.

What if you want to pass data between PeopleCode and a scripting language? If your scripting language has a Java implementation, then you can actually pass objects between PeopleCode and that scripting language using the Apache Bean Scripting Framework (BSF). BSF supports Javascript, Python, Groovy, Ruby, NetRexx, TCL, XSLT, PROLOG, Java, JudoScript, ObjectScript, and ooRexx through Java implementations of those languages.

Here is a basic example of executing a PeopleCode generated Javascript. The script declares a regular expression object and extracts the site name from the PeopleSoft URL.

Local JavaObject &manager = CreateJavaObject("org.apache.bsf.BSFManager");
Local string &script;
Local string &siteName;

&script = "var re = /\/??(\w+?)(?:_\d+?)?\/.+$/;";
&script = &script | "var a = re.exec('" | %Request.PathInfo | "');";
&script = &script | "a[1];";

&siteName = &manager.eval("javascript", "site_name.js", 0, 0, &script).toString();


Where would I use this? Anywhere that I needed to pass objects between a scripting language and PeopleCode. My favorite example is using BSF inside an Integration Broker custom target connector. This allows the programmer of the non-PeopleSoft system to code the integration using a more familiar language.

To use the example above, place rhino-js-1.6r5.jar, bsf-2.4.0.jar, and commons-logging.jar in your app server classpath. To use a different scripting language, place the appropriate language jar in your classpath. See the BSF web site for more details.

Friday, June 08, 2007

Signing on with Oracle

Today I turned in my resignation to my supervisor at Chelan County PUD. I will miss my co-workers. On Monday, July 2nd, I move into Rich Manalang's old position at Oracle.