Creating a Pega Listview with data from more than one class

Most Pega developers are familiar with the Listview control which is generated (normally) through the report wizard. This control readily permits access to columnar data from a Pega class/table and permits culling the dataset size down based on criteria on these columns. These Listview controls are utilized not only within reports but also as specialized displays for creative workbasket presentation or selection control and tend to work rather well as long as all your data is aggregated within a single class.

However, you can find yourself in a quandary if you need to join different classes to derive your display data! I have to thank my teammates Payal and Pratap for opening my eyes to this possibility in order to solve a real-world issue. I needed a way to load a specialized work-class based upon criteria in the Assign-Workbasket. In other words, the display class was my specialized class but the criteria to fetch the records existed in another class which would be enforced in the SQL world as a simple join.

The report wizard can be summoned by selecting the Create Custom Reports icon while in the Monitor Activity page. A manual way to create a Listview is to select the Application -> New Rule -> Reports -> Listview which then prompts for some information before creating the report:

This then leads to the actual configuration of the Listview itself:

On the second tab, Content, is the key that we will need to exploit to execute our join statement. It will be found in the Report Source section under Activity Name:

The Listview is powered by this activity! If you follow the link to open the default rule, you will see that it (getContent) is a single-line Java activity that actually creates SQL statements based upon the “Get these Fields” and “Criteria” rows. The net result is to create a Code-Pega-List page named according to the name in the Content Page Name (passed in to this activity as a parameter named pyContentPage) and whose pxResults page list contain records for display (Displayed code is copyrighted by PegaSystems, Inc.).

Examination of this Java code is left for you to accomplish in your own environment.

So, what can we do with this? Actually, many things depending upon your needs:

  1. You might desire to display the contents of a single class but select elements based upon criteria in another one like I did. In this case, your query is really on the other class but the display class matches the class that the Listview expects.
  2. You might need to accomplish a join and effectively bring back components as a blend of each class in the join. This is a bit more complex but one solution might be to create a surrogate placeholder class containing the components needed for display, execute the query in your specialized getContent activity, then subvert the returned items into elements of the surrogate class. These elements can then be used in the “Get these fields” and “Show these fields” lists.

Anyway, the trick is to save the getContent activity as a different name (don’t eclipse the normal Listview handler or you will regret it!) into your ruleset. You can then rework the activity to accomplish your goals. Here is how I reworked it to meet my needs:

My renamed/resaved getContent activity was plugged into the Listview as you can see. The overview of the activity itself is relatively simple. Here is the activity which I named getDataWorkbasketContent…

I opted to break the problem into two simple parts since the quantity of data I had to deal with was actually pretty small. A much larger dataset might require me to actually make the changes as a SQL statement but here I tried to minimize the Java (keeping within Pega’s guardrails) an use as many OOB tricks I could.

Essentially my steps were to (a) derive a list of the objects within the workbasket (a finite list of a few hundred by definition), then (b) for each element that has not been resolved, load its corresponding record from the specialty workclass. Notice that parameters are passed from the Listview control and any parameters passed in turn to the control are simply passed through to our activity. The call to launch this control passes a parameter named WorkbasketID which was needed in this activity, so I exposed it on the Parameters page and made it required:

First, a page needed to be created to contain the results of this activity since the Listview expected it. The name of this page is an indirect page reference contained in the pyContentPage parameter. Its type is expected to be a standard Code-Pega-List:

The next call then is a simple Obj-List to load a list of the items assigned to the workbasket by using the WorkbasketID parameter. This list would then be iterated and handled by the code to fetch the work objects themselves:

Once the workbasket data items have been corralled into our temporary page (WorkbasketContents), it is time to aggregate our specialty class items:

I chose to use a Java activity in combination with the iterator. Instead, I could have also called another activity and been able to accomplish more steps using OOB Pega calls instead of resorting to Java, but the Java itself is so short that it really is not much of an encumbrance. Face it, the native Java call in getContents is way more complex than this one!!

Each time the Java code is called, the step page is the CURRENT Assign-Workbasket embedded page from the iteration of the pxResults. The logic is presented below

ClipboardPage resultsPage = tools.findPage(tools.getParamValue("pyContentPage"));
if (resultsPage == null)
  resultsPage = tools.createPage("Code-Pega-List", tools.getParamValue("pyContentPage"));

// derive the record key to read
ClipboardPage workbasketPage = tools.getStepPage();
String key = workbasketPage.getProperty(".pxRefObjectKey").getStringValue();    // is pzInsKey of other object

// param page is not needed but if it were, here is how to snag it
// ParameterPage paramPage = tools.getParameterPage();

try
{
  ClipboardProperty pxResults = resultsPage.getProperty("pxResults");

  ClipboardPage newPage = tools.getDatabase().open(key, false);
  if (newPage != null)
  {
    String status = newPage.getProperty(".pyStatusWork").getStringValue().toUpperCase();
    if (!status.startsWith("RESOLVED"))
      pxResults.add(newPage);
  }
}
catch (Exception e)
{
  resultsPage.addMessage(e.getMessage());
}

Walking through the logic we see that we snag a copy of the results page by doing an indirect load of its name through the tools.getParamValue(“pyContentPage”) call. The next two lines are unnecessary since the page was actually created but I believe strongly in the “Code defensively” mantra, so there it is.

We need the pzInsKey of the work item from the workbasket class. This is held in the pxRefObjectKey property which we derive by snagging the step page and getting the property’s value as a string (which it is by definition).

The try block contains the code to essentially Obj-Open-By-Handle on the object whose key we derived. First we snag the pxResults embedded page list property from the results page (which, as you remember, is a Code-Pega-List). Using the database object, we call open using the pzInsKey of the object and tell the open to sidestep the security check since all users have access to this view. If the object is found, it is returned as a new page of the appropriate class otherwise a null flags that it was not located.

We have to do a final check here to determine if our work object was actually resolved, or if it is still hovering around waiting for action. This is done by checking the pyStatusWork property for any string beginning with Resolved. If not resolved, it belongs in our list. To add embedded pages to a page list, call the add() method on the embedded list property (this took some time to actually figure out in the Pega Javadocs which certainly lack detail). The add() will append the list and increment the pxResultCount property accordingly.

When the loop completes, we will now have a list of items of the expected class in the results page which we let the Listview process normally. The final step or our activity, since we are good stewards of resources, is to delete the WorkbasketContents temporary page we created, and return.

Hopefully this simple article will help someone at sometime solve what seems to be an insurmountable problem with Listview controls. If it were not for some friendly advice from some of our mature Pega developers, it would have taken longer to determine the proper source of action. Pega’s help on the Listview does present the option under the “Completing the Content tab” topic. It is worth reading through this help article however, it references a KB article on PDN that simply does not exist any longer! Oh well….

About claforet

I have been photographing since my college days. My current gear is a Nikon D-700 along with a plethora of lenses. My first serious camera was a Canon EF back in the early 80s. A Canon A-1 soon followed. Since then, I also have had a Minolta Maxxum, Nikon FM, Nikon F4, and Nikon Point and Shoot in my film days. I have had and maintained a private full color and B&W lab on and off for much of that time. My photos can be found at https://www.flickr.com/photos/claforet/ Photography and painting are my "sanity breaks" that save me from my day-to-day software development existence! I host a group in Facebook called "Painting as a Second Language" for anyone who is interested in painting as an outlet for the day-to-day pressures. Please look it up and join if you think it will meet your needs. Recently, I have also branched into the video world and am learning how to shoot video better and how to edit compelling video sequences. My learning experiences will be part of this blog and my videos can be seen at http://www.vimeo.com/claforet I live in, and photograph mostly around, North Carolina. I love traveling so there are many shots from states around us, out West, and other places. My daughter has been bitten by the photography bug too. She has spent time in a B&W lab and loves the excitement generated by just the smell of the chemicals. Maybe one day she will take over where I leave off....
This entry was posted in Programming, Software architecture and development and tagged , , , , , , , . Bookmark the permalink.

Leave a comment