Sunday, February 21, 2010

Page Assembler Strips Empty Elements -- This is Good!

With the new release of PeopleTools and Enterprise Portal, I find myself modifying my old branding themes to incorporate new features. While testing a header, I noticed that it appeared correctly on homepages, but not on transaction pages. Upon further inspection, I noticed that certain HTML elements I included in my HTML definition appeared on homepages, but not on transaction pages. Specifically, if an HTML element had a bind variable as its only content and that bind variable was only relevant on a homepage, then the page assembler would strip my hard-coded empty element from the transaction page. This caused me a bit of concern because I was actually using those elements to provide layout and styling. Consider the "Personalize Content | Layout" links that usually appear underneath the tabs in a standard Enterprise Portal implementation. Those links only appear on homepages, not on transaction pages. The PeopleSoft branding/assembly code uses designated bind variables to insert those links into a header HTML definition. If you wrap a block element, such as an HTML div around that bind variable, then your div will appear on a homepage, but not on a transaction page.

When I saw this behavior the other day I was quite surprised... and then I remembered I had seen it before. Several years ago while working with page level HTML Areas and Ajax, I noticed the same behavior. It is quite common to insert empty, hidden div elements and other structural elements into HTML to act as containers for dynamic content. The only problem with this approach is that the page assembler seems to eliminate these empty elements. Here is the workaround I contrived for this issue: Add an HTML comment inside an empty HTML element as follows:

<div id="jjm_dynamicContent" style="height: 10px; background-color: blue;">
<!-- This comment will force the page assembler to render this element -->
</div>

The page assembler will see content (the comment) inside the element and will allow it to pass through to the browser. Since the content is a comment, the browser will ignore the content and treat the element as if it were empty, giving us our much desired empty element.

Now that we have a solution for creating empty elements, let's consider how to turn this seemingly annoying behavior into a positive feature. The PeopleTools branding makes extensive use of HTML definitions. These HTML definitions contain bind variables that may or may not have values, depending on the execution context. I've already given the example of the Personalize links on a homepage. Wrapping items like these in HTML containers, such as div elements, provides us with conditionals that otherwise might not exist. For example, by wrapping the Personalize bind variable in a named div, you create a div that will exist on homepages, but not on transaction pages. Using JavaScript, you can test for the existence of this named element and execute code accordingly. Likewise, you can use CSS to attach layout and design instructions to these elements that the browser will only apply if the element exists (conditions are met).

There was a time when I thought this was a bug that should be fixed. But, now that I am enlightened to the possibilities of conditionals, I see the benefits of this feature and would be very sorry to see this behavior change.

HEUG Alliance 2010

I can't believe that Alliance is next week! This is one of my favorite conferences - the people, the sessions, the locations... Alliance is one of the best opportunities to learn and share PeopleTools ideas.

I hope you can get into San Antonio early and get a good night's sleep Sunday night because my session, 27202 - PeopleTools Tips and Tricks is the first breakout session Monday morning. The fun run and golf tournament are great ways to get some exercise to acclimate yourself to the timezone differences, or just so you can sleep well in your hotel room.

The Alliance Agenda builder doesn't show sessions by vendor. Since I have a list of PeopleTools sessions offered by Oracle, I thought I would list them here. I will attend some of these sessions, but I am much more interested in attending your (the customer) sessions and seeing what you are doing.

TitleSessionTimeLocation
Monday
PeopleTools Tips and Tricks272029:30 AMRoom 103A
PeopleSoft and WebCenter: The New World of Enterprsie 2.02721710:45 AMRoom 103A
Building Web Services with PeopleTools Integration Broker
2721512:45 PMRoom 103B
PeopleTools Roadmap271973:15 PMGrand Ballroom C3
PeopleTools Performance Tips and Tricks272014:30 PMRoom 103B
Maintenance Strategies for a PeopleSoft Enterprise Application272064:30 PMRoom 007A
Tuesday
PeopleTools 8.50 Highlights - For The Application Developer2720512:45 PMRoom 103A
PeopleTools 8.50 Highlights - SOA and Integration272162:00 PMRoom 103B
PeopleTools 8.50 Highlights - Application and Web Servers272003:15 PMRoom 103A
PeopleSoft PeopleTools Enterprise: A Panel Discussion272044:30 PMRoom 103A
Wednesday
PeopleTools 8.50 Highlights - Reporting and BI271999:30 AMRiver Room 001B
Securing your PeopleSoft Application2719810:45 AMRoom 103B
Web 2.0 in Your Enterprise: Collaboration by Example2720710:45 AMRoom 103A

Besides great sessions, be sure to stop by the Oracle demo grounds to see our new 8.50 and 9.1 applications! I haven't seen a final schedule, but Meet the Experts will be in the demo grounds some time during the normal exhibit all hours. Be sure to look for the Meet the Experts bistro tables in Oracle booth.

See you next week in San Antonio!

Exec Processes while Controlling stdin and stdout

A few months ago I read a question on the ITToolbox PeopleTools-I forum asking if it was possible to read the output of a spawned process. Unfortunately this is not possible with the delivered PeopleCode Exec function. I got to thinking about this though, and I wondered if it was possible to accomplish this by using Java's Runtime object from PeopleCode. The answer is yes. To test this, create a batch file in your c:\temp directory named sayHello.bat and then add the following batch file commands to this file:

@echo off
echo Hello %1
echo How are you?

Next, open App Designer and create a new App Engine program. Add a new PeopleCode action to this program and insert the following PeopleCode:

Local JavaObject &runtime = GetJavaClass("java.lang.Runtime").getRuntime();
Local JavaObject &process = &runtime.exec("c:\temp\sayHello.bat """ | %OperatorId | """");

Local JavaObject &inputStreamReader = CreateJavaObject("java.io.InputStreamReader", &process.getInputStream());
Local JavaObject &bufferedReader = CreateJavaObject("java.io.BufferedReader", &inputStreamReader);
Local any &inputLine;

While True
&inputLine = &bufferedReader.readLine();
If (&inputLine <> Null) Then
MessageBox(0, "", 0, 0, &inputLine);
Else
Break;
End-If;
End-While;

Open the new App Engine's properties and disable restart. From the App Designer menu bar, choose Edit | Run Program. When the Run Request dialog appears, select the Output Log to File checkbox and then activate the Run button. When the App Engine finishes, open the log file (usually c:\temp\NAME_OF_AE.log) and review its contents. Here is the contents of my log file. Notice that I was logged in as user PS and named my App Engine JJM_JAVAEXEC. I expect your results to differ slightly based on your tools version, operator ID, and program name.

PeopleTools 8.49 - Application Engine
Copyright (c) 1988-2010 PeopleSoft, Inc.
All Rights Reserved


Hello "PS" (0,0)
Message Set Number: 0
Message Number: 0
Message Reason: Hello "PS" (0,0) (0,0)

How are you? (0,0)
Message Set Number: 0
Message Number: 0
Message Reason: How are you? (0,0) (0,0)
Application Engine program JJM_JAVAEXEC ended normally

The following example is similar to the previous, but writes to stdin as well as reading from stdout. To run this example, you need a copy of grep. I use the version that comes with UnxUtils (Note: You do not need grep or UnxUtils to write to stdin. Grep is a common command line tool, so I used it here for example purposes only). The following code writes two lines to the grep program's standard input (stdin): EMPLID and OPRID. It then asks grep to find the line containing OPRID. The PeopleCode then reads the grep program's output and writes it to the App Engine log.

Local JavaObject &runtime = GetJavaClass("java.lang.Runtime").getRuntime();
Local JavaObject &process = &runtime.exec("grep ""OPRID""");

Local JavaObject &inputStreamReader = CreateJavaObject("java.io.InputStreamReader", &process.getInputStream());
Local JavaObject &bufferedReader = CreateJavaObject("java.io.BufferedReader", &inputStreamReader);
Local JavaObject &outputStreamWriter = CreateJavaObject("java.io.OutputStreamWriter", &process.getOutputStream());
Local JavaObject &outputBuffer = CreateJavaObject("java.io.BufferedWriter", &outputStreamWriter);
Local any &inputLine;

&outputBuffer.write("EMPLID: " | %EmployeeId);
&outputBuffer.newLine();
&outputBuffer.write("OPRID: " | %OperatorId);
&outputBuffer.close();

Repeat
&inputLine = &bufferedReader.readLine();
If (All(&inputLine)) Then
MessageBox(0, "", 0, 0, &inputLine);
End-If;
Until None(&inputLine);

If you want to run this example and have a copy of grep in your %PATH% environment variable, then add a new step and PeopleCode action to your App Engine, deactivate the previously created step, and then run the program. Your output should look something like:

PeopleTools 8.49 - Application Engine
Copyright (c) 1988-2010 PeopleSoft, Inc.
All Rights Reserved


OPRID: PS (0,0)
Message Set Number: 0
Message Number: 0
Message Reason: OPRID: PS (0,0) (0,0)
Application Engine program JJM_JAVAEXEC ended normally