Tuesday, November 19, 2024

Generating Activity Guide URLs

Creating Activity Guide navigation is challenging for two reasons:

  1. Simple Fluid Activity Guides all use the same component. This means we can't use a simple content reference. To use security to show or hide an Activity Guide content reference, we must use the URL type of PeopleSoft Generic URL. We must type a PeopleSoft URL fragment rather than leverage the traditional Content Reference fields (menu, component, market).
  2. Activity Guides with Runtime Context require dynamically generated URLs. These Activity Guides cannot leverage simple content references.

My PeopleCode for launching Activity Guides with Runtime Context usually starts with a GenerateComponentPortalURL to generate the base Activity Guide framework URL and then a bit of URL concatenation to assemble the Runtime context attributes. Here is an App Class I put together to make this easier.



Here is how you would use it:

import JSM_URL_UTIL:ActivityGuideURL;   
   
Local JSM_URL_UTIL:ActivityGuideURL &urlBuilder = create JSM_URL_UTIL:ActivityGuideURL("JSM_AWE_AG");
Local string &url;

&urlBuilder.addContextItem(Field.EOAWPRCS_ID, "FacilityAccessRequest");
&urlBuilder.addContextItem(Field.DESCR, "Facility Access Request");

&url = &urlBuilder.generateFluidURL();

The addContextItem method takes a key/value pair, both of which are strings (they will become part of the URL string). Since context IDs (keys) are fields, then using Field.FIELDNAME syntax is preferred so Edit | Find Definition References will locate your field usage.

We added one more convenience method: generateGenericPeopleSoftFluidURL(). Use this method to help you craft a PeopleSoft Generic URL to a static Activity Guide. This is a one-time-use method you would call at design time to create that static URL fragment required by a Content Reference. If you have a simple, static Activity Guide with no context, then you may want to create a Content Reference. However, typing all of the parameters correctly can be a challenge. Use this helper method to generate the full Generic PeopleSoft URL for you. We invoke this method from a design-time App Engine, but you may want to create a page for it instead.

Are you interested in learning more about PeopleCode Application Classes? Check out our two-day course available live virtual or on-demand!

Tuesday, October 22, 2024

PeopleSoft Reconnect 2024

 


I have the privilege of sharing the following sessions at PeopleSoft Reconnect 2024:

  • Getting the Most out of PeopleSoft PeopleTools: Tips and Techniques on Monday at 4:45 PM Eastern. During this session, I will share PeopleTools tips to help you become a more productive PeopleSoft developer, including ways to use Java, JavaScript, and Integration to build solutions without customizing Oracle's code. Functional staff and business analysts will benefit from experiencing what is possible with the PeopleSoft platform.
  • Isolate and Configure: Don't Customize on Tuesday at 12:00 PM Eastern. With selective adoption and continuous delivery, it is important that we avoid customizing PeopleSoft. The more we customize, the less we adopt new features and apply maintenance. Join this session to understand options to help us isolate and replace customizations. Experience the art of the possible through incredible examples and use cases.
  • PeopleSoft Test Framework: Your New Compare Report on Wednesday at 3:45 PM Eastern. Event Mapping, Drop Zones, and Page and Field Configurator allow us to isolate (not eliminate) customizations. A key difference between traditional and isolated customizations is that traditional customizations are listed in a compare report. Isolated customizations are not. However, isolated customizations run the same risk of breaking as traditional customizations. Join me on Wednesday to learn how we can use the PeopleSoft Test Framework to replace the compare report, allowing us to analyze broken customizations rather than the traditional approach of analyzing everything.
  • PeopleSoft Fluid Best Practices on Thursday at 1:15 PM Eastern. Fluid is PeopleSoft's strategic direction. But how does it differ from Classic? In this session, I will share with you tips and design patterns to help you build better Fluid solutions faster. Tips will include grid handling, adaptive and responsive design, CSS, and CSS variables.
I look forward to seeing the PeopleSoft community online virtually next week, October 28-31!

Thursday, October 03, 2024

Finding Tiles

Fluid Homepage Tiles are Content References just like all other content references, with one exception: They are really hard to find! Fluid tile definitions exist in a subfolder of Fluid Structure and Content > Fluid Pages. The question is: Which folder?

PeopleTools 8.60 added a new feature that may help: groupletid. Tile HTML now contains a custom attribute called groupletid. You may read more about this new feature in PeopleSoft PeopleTools 8.60 New Features Overview (Doc ID 2897533.1) on My Oracle Support.

As stated in the support document, the Grouplet ID is the Content Reference ID (CREF ID). Fantastic! What that means is you and I can capture the CREF ID directly from the HTML!

Once I have the CREF ID, I can visit Enterprise Components > Find Object Navigation to find the tile's Portal Registry folder and path.

Are you interested in printing a list of all tile CREFs for a particular user? Fire up your browser's JavaScript console and type (or paste) the following:

document.querySelectorAll("div[groupletid]").forEach(function(el) {
  console.log(el.getAttribute('groupletid'))
});

All tiles from all homepages exist in the HTML as soon as the homepage loads. They are just hidden. Want to just see the tiles for the active homepage? Try this derivative:

document.querySelectorAll(".lptab-cont:not(.psc_invisible) div[groupletid]").forEach(function(el) {
  console.log(el.getAttribute('groupletid'))
});


At JSMpros, we teach PeopleTools tips like this every week! Check out our class schedule to see what we are offering next. Want to learn on your own time? Become a subscriber to access all our courses anytime from anywhere!

Tuesday, August 13, 2024

Should you use the Override and/or Replace Features?

I absolutely love Isolated Customization strategies such as Event Mapping and App Engine Action Plugins. These strategies allow us to extend Oracle's delivered solution without touching Oracle-delivered code. The benefit is more efficient maintenance cycles because of fewer retrofits.

Both of these features, Event Mapping and App Engine Action Plugins, have one shortcoming: You may not use them to inject code into the middle of an Oracle-delivered code listing. Event Mapping and App Engine Action Plugins only allow code to be inserted before or after an entire listing. What if you need to inject code in the middle? Until recently, the only option was to continue modifying Oracle's delivered code.

Both Event Mapping and App Engine Action Plugins have a feature allowing a developer to replace or override Oracle's delivered code listing with your own. Customers looking for "clean" compare reports may be tempted to copy the Oracle-delivered code into their own code listing, modify it, and then replace/override Oracle's delivered code. The end result is a clean compare report and hopefully less work when applying maintenance.

But does it really work that way? Let's say you take this approach. You clone Oracle's delivered code into your own code listing. You modify your copy. You use Event Mapping or App Engine Action Plugins to replace Oracle's code. Time passes, and you apply maintenance. Since the compare reports show no customizations, you adopt Oracle's changes with no retrofits. You test the system, and because of your overrides, the system continues using your code, not Oracle's code. This is good, right? Isn't this what you want? MAYBE NOT! Oracle delivered maintenance for a reason. Did they patch a security vulnerability? Did they fix a bug? Did they alter the data model or business logic in a manner that renders your clone less effective?

If you use the override/replace in this manner, you have no way of knowing what Oracle "fixed." The only way to know that you are using the latest version of their code is to perform your own manual compare and retrofit outside of PeopleTools. And if you are going to do that, wouldn't it be easier to just modify Oracle-delivered anyway? You know what is worse? Since overridden and replaced code listings don't show on compare reports, your system may be fully patched and still suffer security vulnerabilities in your clones of Oracle-delivered code.

The Override/Replace features are fantastic for REPLACING Oracle's delivered code. In other words, if you don't want Oracle's code to run at all, then override or replace it.

Want to learn more about PeopleTools Event Mapping? Check out our one-day on-demand Event Mapping course! Or even better, subscribe and get a full year of access to the entire JSMpros on-demand PeopleTools training library!

Want to further reduce your maintenance workload? Replace customization analysis and review with PeopleSoft's Automated Testing Tool (PTF). Learn how through our two-day PTF course, which is available on-demand and live!

Thursday, June 27, 2024

PeopleSoft Data Masking Options

PeopleSoft customers have several Data Masking options:

Let's compare the various options.

Event Mapping

Event Mapping is the most flexible option, allowing us to use any masking character, from alpha-numeric to emoji. In fact, you may even combine the space character with custom CSS to leverage any character, including custom Fonts, such as FontAwesome. Relevant PeopleCode functions and methods include:

Field.SetDisplayMask
Field.AddFFClass
AddStylesheet

Check out this video to learn more about Event Mapping for Data Masking:


Page and Field Configurator

Page and Field Configurator is less flexible but easier to apply than Event Mapping. Page and Field Configurator offers a point-click interface to configure masking against page fields. Masking characters are limited to * and x (although this is configurable through masking profiles).

App-specific masking

The HCM team built its own registry of sensitive fields with a masking utility. You can learn more about this feature in the Quest blog post Maintaining Data Privacy in PeopleSoft HCM. What makes this option compelling is:

  1. The HCM team wrote all the code. All we have to do is choose our sensitive fields, components, and roles.
  2. If anything breaks, we file a ticket for the HCM team to fix. This is in contrast to Page and Field Configurator and Event Mapping, which are site-specific isolated customizations and, therefore, the customer's responsibility to fix.
  3. This solution has broad coverage. If we choose to mask a sensitive field, such as birth date, then all HCM pages and components should mask that field. Event Mapping and Page and Field Configurator, on the other hand, only mask one component. If we used either of those solutions to mask the birth date field, we would need to apply that masking to all components ourselves.

Data Privacy Framework

The Data Privacy Framework allows us to apply masking to query results. This is not mutually exclusive. You may choose to apply the Data Privacy Framework along with any of the other options.

Bolt-on Solutions

My favorite data masking solution is Pathlock's Security Solution for PeopleSoft. Besides the basics of masking, Pathlock's solution also allows us to unmask using a variety of techniques, including:

  • Click-to-view (a loggable event) and
  • MFA-to-view (also loggable but requiring a second factor to confirm your identity).

Interested in learning more? We teach PeopleTools Tips like this every week at JSMpros! Check out our online schedule to see what we are offering next! Or do you have a specific topic you want to study? Subscribe to gain access to all of our on-demand content at a fraction of the cost!

Wednesday, June 12, 2024

Is "Restartable" an App Engine Best Practice?

The first thing I do when creating an App Engine is disable restart. Because restartable is the default, it might seem like Restartable is a best practice. But is it?

A restartable App Engine is a batch program that iterates over data and commits changes on an interval. This behavior contrasts with the default behavior, which is to roll back changes on failure. A restartable program restarts at the last checkpoint. Without restart, ALL data must be reprocessed on failure. The obvious benefit is that restartable App Engines don't have to reprocess successful data. This sounds fantastic! But is it?

There are two main data processing strategies:

  • Set-based processing
  • Row-by-row processing

Set-based processing allows the database to optimize and execute commands at the database. Row-by-row processing, however, requires each row of data to be transferred to the process scheduler server and then processed. Row-by-row processing, therefore, is dramatically slower.

App Engines utilizing either strategy may be restartable, but a restartable set-based program would be rare. Restart is only valuable on failure. Before restarting, we would fix whatever data caused an error so we may reprocess that data. With set-based processing, that error would already be stored in an intermediate downstream processing table. Therefore, row-by-row processing is the only processing method that seems relevant for restart.

Another problem with a Restartable App Engine is that it must commit on intervals to benefit from the restart. What makes this a problem is that databases, such as Oracle, close any open cursors on commits. Therefore, a Restartable App Engine must also re-fetch (close and reopen) SQL cursors on every commit.

What does this mean? A Restartable App Engine may be the slowest, least-performing option available! It is an option we may use when it makes sense, but should it be the default? What do you think?

Ready to take your PeopleTools skills to the next level? Become a subscriber to gain access to our vast library of PeopleTools training courses, hands-on activities, downloads, instruction videos, and more!

Thursday, April 25, 2024

HOWTO Override Fluid Component Event Handlers

Oracle's delivered Fluid components use an interesting pattern: App Class Event Handlers. This isn't required. It's just a design decision. Here is how it works: a Fluid page's Component PreBuild usually initializes a component-scoped App Class variable and every subsequent event delegates to a custom App Class method. If done properly, this design decision has the following potential benefits:

  • Reusable,
  • Unit testable,
  • Extensible, and
  • It eliminates the "Data Integrity Error" when making changes to Component-specific PeopleCode while a component transaction is in progress.

Unfortunately, to be reusable and testable, App Class code must be context-agnostic. That means it can't leverage component buffer-specific functions, such as GetLevel0, GetRow, and GetRowset; it can't use context-specific variables, such as %Component; and it can't use bare references, such as RECORD.FIELD references.

We discuss these design concepts regularly in our PeopleCode Application Classes two-day course, and we wrote about the extensibility idea in this blog post. In the blog post, we noted that Oracle would need to change the way they load their App Classes in Component PreBuild to make event handlers extensible. But do we need to wait? We came up with an idea that allows us to implement this idea now: we can use Event Mapping to replace Component PreBuild so we can load our own App Class. As long as our new App Class extends the Oracle-delivered App class, all other event PeopleCode will delegate properly. In other words, PeopleSoft will use our code in all other events. What's interesting about this idea is that it may allow you to apply just one Event Mapping service to a component rather than one per event.

As an example, let's extend Direct Deposit by subclassing (overriding) one of its App Classes. Components that apply the event delegation pattern instantiate App Classes in PreBuild. Within the PreBuild of the Direct Deposit component (PY_IC_DIR_DEP_FL), we see the App Class PY_DD_SELFSERVICE:Utilities. That class includes several important methods, including one appropriately named PageActivate. Our goal is to use the PageActivate event to hide the Pay Statement Print Options box. We will accomplish this goal by using Event Mapping to replace PY_DD_SELFSERVICE:Utilities with our own Utilities subclass. Here is the code for the Utilities subclass:

import PY_DD_SELFSERVICE:Utilities;

class CustomUtilities extends PY_DD_SELFSERVICE:Utilities;
   method pageactivate();
   REM ** Add more methods to override mor functionality;
end-class;

method pageactivate
   /+ Extends/implements PY_DD_SELFSERVICE:Utilities.pageactivate +/
   REM ** invoke original pageactivate method since we are just extending, not replacing;
   %Super.pageactivate();
   REM ** The following line doesn't work because later Oracle-delivered code overrides it;
   REM PY_IC_WRK2.PRINT_OPTN.Visible = False
   PY_IC_WRK2.PRINT_OPTN.AddFFClass("psc_hidden");
end-method;

The next step is to apply Event Mapping to override Component PreBuild. Here is our sample code:

import PT_RCF:ServiceInterface;
import PY_DD_SELFSERVICE:Utilities;
import TRN_PY_IC_DIR_DEP_FL_OVRD:CustomUtilities;

class PreBuild extends PT_RCF:ServiceInterface
   method execute();
end-class;

Component PY_DD_SELFSERVICE:Utilities &DDUltities;

method execute
   /+ Extends/implements PT_RCF:ServiceInterface.execute +/
   
   &DDUltities = create TRN_PY_IC_DIR_DEP_FL_OVRD:CustomUtilities();
end-method;



After applying Event Mapping, the delivered Direct Deposit component will now pass all Utilities requests through our subclass. The standard, delivered &DDUtilities.pageactivate call that is in the middle of the delivered PageActiviate PeopleCode will now invoke our pageactivate method instead.

Summary

This was an interesting academic exercise with some benefits over Event Mapping:

  • This approach allowed me to indirectly inject code into the middle of an Oracle-delivered code listing. The delivered PageActivate event invokes &DDUtilities.pageactivate in the middle. Event Mapping would have required my change to appear at the end or beginning, but not in the middle.
  • I only had to configure one Event Mapping, not one for each event I desired to extend.

I also found some challenges that this approach could not solve:

  • I wanted to run code at the end of PageActivate, not in the middle. My CustomUtilities code triggers too soon. As you can see from the first code listing, I run Oracle's code through %Super, and then mine. But the actual event code listing has more code that overrides my code. Event Mapping is the only way to make sure your code runs last.
  • I would like to mask the routing number within the rows of the Direct Deposit grid. I would use RowInit to apply this masking. The delivered Direct Deposit component does not have code in RowInit. I would, therefore, have to use Event Mapping to apply RowInit code.

This is a pattern I'm going to keep in my toolbox. For this scenario specifically, Event Mapping without overriding was a better solution. But there are times where subclassing a backing App Class may make more sense.

Are you interested in learning more about PeopleTools and PeopleCode? Check out our live virtual and on-demand courses. Or even better, subscribe and get access to all of our content for a full year!