Skip to main content link. Accesskey S
  • Log In
  • Help
  • IBM Logo
  • IBM Digital Experience wiki
  • All Wikis
  • All Forums
  • ANNOUNCEMENT: WIKI CHANGE TO READ-ONLY. LEARN MORE...
  • Home
  • Product Documentation
  • Community Articles
  • Learning Center
  • IBM Redbooks
  • API Documentation
Search
Learning Center > Tutorials > Tutorials for Web Content Manager > Retrieving WCM Content using PZN Rules Based on Current User's Categories
  • New Article
  • Share Show Menu▼
  • Subscribe Show Menu▼

About the Original Author

Click to view profileIBM contributorChristopher Knight
Contribution Summary:
  • Articles authored: 9
  • Articles edited: 5
  • Comments Posted: 4

Recent articles by this author

Retrieving WCM Content using PZN Rules Based on Current User's Categories

How to retrieve WCM content based on the current user categories, using PZN rules.

Leveraging WCM rendering portlet configuration values within PZN Rules

Learn how to integrate Personalization (PZN) Rules with IBM Web Content Manager (WCM).

Improving IBM Web Content Manager Personalization rule performance using Include Only

Using real-world examples, this article demonstrates how to use the Include Only option in Personalization rules and explains the performance difference between using and not using the functionality.

Creating a custom rendering plugin to display the average rating for an IBM Web Content Manager item

To leverage the information about rating IBM Web Content Manager (WCM) items, this article uses a custom rendering plugin to display the average rating for a WCM content item. This can be used, for example, within a menu design so you can see what the rating is for a piece of content.

Leveraging JSON JavaScript to extend IBM Lotus Web Content Management component design

This article describes a fully functional example of how to use JavaScript Object Notation (JSON) JavaScript objects within IBM® Lotus® Web Content Management component designs.
Learning Center articleRetrieving WCM Content using PZN Rules Based on Current User's Categories
Added by IBM contributorChristopher Knight | Edited by IBM contributorChristopher Knight on October 22, 2012 | Version 26
expanded Abstract
collapsed Abstract
How to retrieve WCM content based on the current user categories, using PZN rules.
Tags: 7.0.0.2, 8.0, pzn-wcm, WCM API Custom Code
ShowTable of Contents
HideTable of Contents
  • 1 Overview
  • 2 Creating and Deploying the Custom Application Object
    • 2.1 Create the Custom Application Object
      • 2.1.1 Creating the Category Cache Classes
      • 2.1.2 Creating the Class for the Custom Application Object
    • 2.2 Export and Deploy the Custom Application Object
    • 2.3 Create the Application Object within PZN UI
  • 3 Creating the PZN rules
  • 4 Rendering the Results

Overview


Within WCM, content can be categorized. Normally, this is used to allow WCM menus to display content related to specific categories. However, it is also possible for users within WCM to have categories associated with their profile. This can be done within theWCM Authoring UIexternal link, the user can select their own categories using a Taxonomy Elementexternal link, or can be done programmaticallyexternal link. Once the user is associated with categories, a WCM menu can then retrieve content that is associated with the same categories as the user.

In this example, we will show how these categories can be used within PZN rules to retrieve the content that is related to the categories that the user is interested in.

One note, the APAR PM75476 is necessary for this example to work if the WCM Dynamic Mapper is being used.

Creating and Deploying the Custom Application Object


There are 2 approaches that we can use for this application object. One is to retrieve the values that WCM has associated with the user. This is useful if the end user has categories stored within WCM, the dynamic mapper approach is being used (categories added to WCM Users programmatically), or the end user is selecting their own categories using the taxonomy tree. The other approach is that the custom application object can associate categories for the specific user programmatically. This approach is useful, because categories can selected based on things like user cookies, request attributes in the current request, etc. This particular example will retrieve the categories directly from WCM for the user.

Note, we have included these assets as a .jar file already which can be used directly as downloaded. These steps are included for reference, they can be skipped by downloading the customcategoryapp.jar file, placing in /WPHOME/pzn/prereq.pzn/lib directory and restarting the Portal server. Just skip to the section "Create the Application Object within PZN UI".

Create the Custom Application Object


I used Rational Application Developer for this process. If you are using a different IDE, your steps may be different.
  • Click new -> Dynamic Web Project. Name the project CustomUserCategoryApplicationObject. You can pretty much leave the defaults for the values, click finish:
  • In the project that was created expand Java Resources, and right click on the src folder. Click new -> package. Enter com.ibm.websphere.personalization.custom.appobject and click finish. Repeat, and enter com.ibm.wcm.sample.categorycache:

Creating the Category Cache Classes


One piece of the functionality of this custom application object is a WCM Category Cache. The purpose of this is to allow the custom application object to retrieve WCM category information without using WCM API retrievals for every request. At a high level, it basically caches the categories with a variety of keys, including title and path to the category, and returns the UUID of the category for use by the PZN rules.
  • In the /src/com.ibm.wcm.sample.categorycache directory, right click and select New -> Class. Name the new class CategoryInformation. Click finish:
  • Enter the following code for the class, and save the file:

package com.ibm.wcm.sample.categorycache;

import java.io.Serializable;
import java.util.logging.Logger;

public class CategoryInformation implements Serializable {

  /**
   * 
   */
  private static final long serialVersionUID = 1696463479558338290L;

  /**
 * 
 */
  private static final Logger s_log = Logger.getLogger(CategoryInformation.class.getName());

  String categoryId;
  String categoryName;
  String categoryFullPath;

  CategoryInformation()
  {

  }

  CategoryInformation(String p_id, String p_name, String p_fullPath)
  {
setCategoryId(p_id);
setCategoryName(p_name);
setCategoryFullPath(p_fullPath);
  }

  public void setCategoryId(String catId)
  {
categoryId = catId;
  }

  public String getCategoryId()
  {
return categoryId;
  }

  public String getCategoryName()
  {
return categoryName;
  }

  public void setCategoryName(String categoryName)
  {
this.categoryName = categoryName;
  }

  public String getCategoryFullPath()
  {
return getCategoryFullPath(null);
  }

  public String getCategoryFullPath(String libraryName)
  {
if (libraryName != null)
{
  return libraryName + "/" + categoryFullPath;
}
return categoryFullPath;
  }

  public void setCategoryFullPath(String categoryFullPath)
  {
this.categoryFullPath = categoryFullPath;
  }

  public String toString()
  {
return "CategoryInformation Name:" + categoryName + " ID:" + categoryId + "  FullPath:" + categoryFullPath;
  }

}
  • Repeat the process, but this time name the class WCMCategoryUtils. Enter the following for the code, and save the file:

package com.ibm.wcm.sample.categorycache;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.ejb.DuplicateKeyException;
import javax.naming.InitialContext;

import com.ibm.websphere.asynchbeans.Alarm;
import com.ibm.websphere.asynchbeans.AlarmListener;
import com.ibm.websphere.asynchbeans.AlarmManager;
import com.ibm.websphere.asynchbeans.AsynchScope;
import com.ibm.websphere.asynchbeans.WorkManager;
import com.ibm.workplace.wcm.api.Category;
import com.ibm.workplace.wcm.api.DocumentId;
import com.ibm.workplace.wcm.api.DocumentIdIterator;
import com.ibm.workplace.wcm.api.DocumentLibrary;
import com.ibm.workplace.wcm.api.DocumentTypes;
import com.ibm.workplace.wcm.api.Taxonomy;
import com.ibm.workplace.wcm.api.WCM_API;
import com.ibm.workplace.wcm.api.Workspace;
import com.ibm.workplace.wcm.api.exceptions.WCMException;

public class WCMCategoryUtils {

  private static final Logger s_log = Logger.getLogger(WCMCategoryUtils.class.getName());
  /**
   * Set this to the number of minutes inbetween rebuilds of the categoryId Map.
   */
  private static final int REBUILD_INTERVAL_MINUTES = 60;

  private static AlarmManager s_alarmManager = null;
  private static Alarm s_lastAlarm = null;

  private static Map<String, List<CategoryInformation      s_categoryNamesIDs = new HashMap<String, List<CategoryInformation     ();
  private static AlarmListener s_alarmListener = new AlarmListener()
  {

    public void fired(Alarm p_alarm)
    {
    
  if (s_log.isLoggable(Level.FINER))
  {
s_log.finer("Alarm fired - will rebuild the category map.");

  }
          // This is to try and keep a single rebuild alarm.  If the EAR/WAR is redeployed the previous alarm
          //   is not cancelled.  So see if the alarm firing now is the one scheduled form this load of the class
          //   if it is the same we reschedule, if not, we can ignore it....
          boolean rescheduleAlarm = s_lastAlarm != null;
          if ( rescheduleAlarm )
          {
              rescheduleAlarm = s_lastAlarm.equals( p_alarm );
          }

  // Rebuild the Map, and make sure we reschediule the next rebuild.
  WCMCategoryUtils.buildCategoryIdsMap(rescheduleAlarm);
}

  };

  static
  {
// Now schedule the next time to rebuild
// Lookup the AlarmManager, so we can schedule rebuild tasks
if (s_alarmManager == null)
{
  try
  {

InitialContext context = new InitialContext();
// WorkManager wm = (WorkManager)context.lookup("java:comp/env/wm/default");
WorkManager wm = (WorkManager) context.lookup("wm/default");
AsynchScope ascope;
String scopeName = "WCMCategoryUtils_AScope";
try
{
  ascope = wm.createAsynchScope(scopeName);
}
catch (DuplicateKeyException ex)
{
  ascope = wm.findAsynchScope(scopeName);
  s_log.warning(ex.getMessage());
}

// get an AlarmManager
s_alarmManager = ascope.getAlarmManager();
  }
  catch (Exception e)
  {
s_log.log(Level.SEVERE, "Unable to schedule rebuild of CategoryIDS", e);
  }
}

buildCategoryIdsMap(true);
  }

  public static void rebuildCategoryIdsMap()
  {
// When invoked directly do not rescheuld otherwise we'll end up with multiple scheduled tasks.
buildCategoryIdsMap(false);
  }

  private static void buildCategoryIdsMap(boolean rescheduleRebuild)
  {
if (s_log.isLoggable(Level.FINER))
{
  s_log.entering("WCMCategoryUtils", "buildCategoryIdsMap");
}
Map<String, List<CategoryInformation      categoryIdsMap = new HashMap<String, List<CategoryInformation     ();
try
{
  Workspace sysWorkspace = WCM_API.getRepository().getSystemWorkspace();
  DocumentLibrary currentLibrary = null;
  sysWorkspace.login();
  try
  {
currentLibrary = sysWorkspace.getCurrentDocumentLibrary();
// iterate All document libraries
Iterator allLibs = sysWorkspace.getDocumentLibraries();
while (allLibs.hasNext()) {
DocumentLibrary designLibrary = (DocumentLibrary) allLibs
.next();
String libName = designLibrary.getName();
sysWorkspace.setCurrentDocumentLibrary(designLibrary);
DocumentIdIterator idIter = sysWorkspace.findByType(
DocumentTypes.Taxonomy,
Workspace.WORKFLOWSTATUS_PUBLISHED);
while (idIter.hasNext()) {
DocumentId docid = idIter.nextId();
Taxonomy tax = (Taxonomy) sysWorkspace.getById(docid,
true);
String fullPath = tax.getName();
DocumentIdIterator catIter = tax.getChildren();
while (catIter.hasNext()) {
DocumentId catId = catIter.nextId();
Category cat = (Category) sysWorkspace.getById(
catId, true);
computeChildPath(libName, sysWorkspace, categoryIdsMap, cat,
fullPath);
}
}
}
if (s_log.isLoggable(Level.FINE))
{
  s_log.fine("Finished computing Category mapping information for a total of " + (categoryIdsMap.size() / 5) + "categories");
  if (s_log.isLoggable(Level.FINER))
  {
s_log.finer("Computed the following keys for the Categories");
for (String key : categoryIdsMap.keySet())
{
  s_log.finer("   " + key);
}

try
{
  ByteArrayOutputStream baos = new ByteArrayOutputStream();
  ObjectOutputStream oos = new ObjectOutputStream(baos);
  oos.writeObject(categoryIdsMap);
  oos.flush();
  NumberFormat intFormatter = NumberFormat.getIntegerInstance();
  s_log.finer("Computed Size of the entire Map is " + intFormatter.format(baos.toByteArray().length) + " bytes");
}
catch (Exception e)
{
  e.printStackTrace();
}
  }

}
  }
  finally
  {
if (currentLibrary != null)
  sysWorkspace.setCurrentDocumentLibrary(currentLibrary);
sysWorkspace.logout();
  }
}
catch (WCMException e)
{

}

// Now assign the new map to the static var
s_categoryNamesIDs = categoryIdsMap;

// If we resolved the alaram Manager, schedule the rebuild.
if (rescheduleRebuild && s_alarmManager != null)
{
   s_lastAlarm = s_alarmManager.create(s_alarmListener, s_alarmListener, REBUILD_INTERVAL_MINUTES * 60 * 1000);
}

if (s_log.isLoggable(Level.FINER))
{
  s_log.exiting("WCMCategoryUtils", "buildCategoryIdsMap");
}
  }

  static void computeChildPath(String libraryName, Workspace sysWorkspace, Map<String, List<CategoryInformation      categoryIdsMap, Category cat, String path)
  {
String categoryName = cat.getName();
DocumentId catId = cat.getId();
String catIdString = catId.getId();
path = path + "/" + categoryName;

List<CategoryInformation> catInfoList = categoryIdsMap.get(categoryName);
if (catInfoList == null)
{
  catInfoList = new ArrayList<CategoryInformation>(1);
}
CategoryInformation catInfo = new CategoryInformation();
catInfo.setCategoryName(categoryName);
catInfo.setCategoryFullPath(path);
catInfo.setCategoryId(catIdString);
catInfoList.add(catInfo);

List<CategoryInformation> catInfoPathList = new ArrayList<CategoryInformation>(1);
catInfoPathList.add(catInfo);

categoryIdsMap.put(categoryName, catInfoList);
categoryIdsMap.put(libraryName + "/" + categoryName, catInfoList);
categoryIdsMap.put(path, catInfoPathList);
categoryIdsMap.put(libraryName + "/" + path, catInfoPathList);
// add a full lower case path as well
String loweredpath = libraryName + "/" + path;
categoryIdsMap.put(loweredpath.toLowerCase(), catInfoPathList);
categoryIdsMap.put(catIdString, catInfoPathList);
// add a full lower case path as well
String encodedPath = "";
try 
{
encodedPath = sysWorkspace.getPathById(catId, false, false);

}
catch (Exception e)
{
e.printStackTrace();


DocumentIdIterator catIter = cat.getChildren();
while (catIter.hasNext())
{
  DocumentId childCatId = catIter.nextId();
  try
  {
Category childCat = (Category) sysWorkspace.getById(childCatId, true);
computeChildPath(libraryName, sysWorkspace, categoryIdsMap, childCat, path);
  }
  catch (WCMException e)
  {
e.printStackTrace();
  }
}

return;
  }

  public static String getCategoryId(String categoryName)
  {
String categoryId = null;
CategoryInformation catInfo = getCategoryInformation(categoryName);
if (catInfo != null)
{
  categoryId = catInfo.getCategoryId();
}
return categoryId;
  }

  public static List<CategoryInformation> getCategoryInformations(String categoryNameOrId)
  {

return s_categoryNamesIDs.get(categoryNameOrId);
  }

  public static CategoryInformation getCategoryInformation(String categoryNameOrId)
  {
if (s_log.isLoggable(Level.FINER))
{
  s_log.entering("WCMCategoryUtils", "getCategoryInformation", categoryNameOrId);
}
CategoryInformation catInfo = null;
List<CategoryInformation> catInfoList = s_categoryNamesIDs.get(categoryNameOrId);
if (catInfoList != null)
{
  catInfo = catInfoList.get(0);
}

if (s_log.isLoggable(Level.FINER))
{
  s_log.exiting("WCMCategoryUtils", "getCategoryInformation", catInfo);
}
return catInfo;
  }

  public static String getCategoryPath(String categoryId)
  {
String categoryPath = null;
CategoryInformation catInfo = getCategoryInformation(categoryId);
if (catInfo != null)
{
  categoryPath = catInfo.getCategoryFullPath();
}
return categoryPath;

  }

  public static String convertQueryStringToFullPath(String queryString, String libraryName)
  {
if (s_log.isLoggable(Level.FINER))
{
  s_log.entering("WCMCategoryUtils", "convertQueryStringToFullPath", new String[] { queryString, libraryName });
}
StringBuilder builder = new StringBuilder();
String[] categoryNames = queryString.split(",");
for (String categoryName : categoryNames)
{
  List<CategoryInformation> categoryInfos = getCategoryInformations(categoryName);
      if ( categoryInfos != null &&  categoryInfos.size() > 0 ) {
  for (CategoryInformation info : categoryInfos)
  {

String path = info.getCategoryFullPath();
if (path != null)
{
  if (libraryName != null)
  {
builder.append(libraryName);
builder.append("/");
  }
  builder.append(path);
  builder.append(",");
}
  }
      }

}
// Trim off the trailing comma
if (builder.length() > 0)
{
  builder.setLength(builder.length() - 1);
}

if (s_log.isLoggable(Level.FINER))
{
  s_log.exiting("WCMCategoryUtils", "convertQueryStringToFullPath", builder.toString());
}
return builder.toString();

  }

  public static List<String> getCategoryIds(String categoryName) throws WCMException
  {
return getCategoryIds(categoryName, false);
  }

  public static List<String> getCategoryIds(String categoryName, boolean includeParents) throws WCMException
  {
if (s_log.isLoggable(Level.FINER))
{
  s_log.entering("WCMCategoryUtils", "getCategoryIds", new String[] { categoryName, "includeParents=" + includeParents });
}
Set<String> categoryIds = null;
List<CategoryInformation> categoryInfos = getCategoryInformations(categoryName);
if (categoryInfos != null && categoryInfos.size() > 0)
{
  categoryIds = new HashSet<String>(categoryInfos.size());
  for (CategoryInformation info : categoryInfos)
  {
categoryIds.add(info.getCategoryId());
if (includeParents)
{
  boolean keepFindingParents = true;

  // Strip off the taxonomy part.
  // String path =
  // info.getCategoryFullPath().substring(info.getCategoryFullPath().indexOf("/")+1);
  String path = info.getCategoryFullPath();
  while (keepFindingParents)
  {
int index = path.lastIndexOf("/");
if (index > 0)
{
  path = path.substring(0, index);
  if (!categoryIds.contains(path))
  {
String catid = getCategoryId(path);
if (catid != null)
{
  categoryIds.add(getCategoryId(catid));
}
else
{
  keepFindingParents = false;
}
  }
  else
  {
keepFindingParents = false;
  }
}
else
{
  keepFindingParents = false;
}
  }
}
  }
}
List<String> ids = new ArrayList<String>(categoryIds.size());
ids.addAll(categoryIds);

if (s_log.isLoggable(Level.FINER))
{
  s_log.exiting("WCMCategoryUtils", "getCategoryIds", ids);
}
return ids;
  }

}

Creating the Class for the Custom Application Object


Now, follow the above process and create a class named UserCategoriesObject in the package com.ibm.websphere.personalization.custom.appobject. Enter the following for the code:

package com.ibm.websphere.personalization.custom.appobject;

import java.security.Principal;
import java.util.*;

import com.ibm.portal.um.PumaHome;
import com.ibm.portal.um.PumaLocator;
import com.ibm.portal.um.User;
import com.ibm.portal.um.exceptions.PumaException;
import com.ibm.workplace.wcm.api.*;
import com.ibm.wcm.sample.categorycache.*;
import com.ibm.websphere.personalization.RequestContext;
import com.ibm.websphere.personalization.applicationObjects.SelfInitializingApplicationObject;
import com.ibm.websphere.personalization.context.PersonalizationContext;

import java.io.Serializable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class UserCategoriesObject implements SelfInitializingApplicationObject, Serializable
{

   private static final Logger s_log = Logger.getLogger(UserCategoriesObject.class.getName());

   private Workspace workspace;

   private static PumaHome puma_home = null;

   private String currentCategoriesUuidString = "";

   public static String UUID_PREFIX = "uuid:";

   public List currentCategories;  

   /**
    * @return the currentCategoriesString
    */
   public String getCurrentCategoriesUuidString()
   {
      if (s_log.isLoggable(Level.FINEST))
      {
         s_log.log(Level.FINEST, "getCurrentCategoriesUuidString returning " + currentCategoriesUuidString);
      }
      return currentCategoriesUuidString;
   }

   /**
    * @param currentCategoriesUuidString the currentCategoriesString to set
    */
   public void setCurrentCategoriesUuidString(String currentCategoriesUuidString)
   {
      if (s_log.isLoggable(Level.FINEST))
      {
         s_log.log(Level.FINEST, "setCurrentCategoriesUuidString called with " + currentCategoriesUuidString);
      }
      this.currentCategoriesUuidString = currentCategoriesUuidString;
   }

   /**
    * @param currentCategories the currentCategories to set
    */
   public List getCurrentCategories()
   {
      return currentCategories;
   }

   /* (non-Javadoc)
    * @see com.ibm.websphere.personalization.applicationObjects.SelfInitializingApplicationObject#init(com.ibm.websphere.personalization.RequestContext)
    * In this init, we will basically check to see if the value we wish 
    * to use is null, and if so set it
    */
   public void init(RequestContext rc)
   {
      boolean isFinest = s_log.isLoggable(Level.FINEST);
      // TODO Auto-generated method stub
      // check if the current cats are null.  If so, set them;
      if (isFinest)
      {
         s_log.entering(this.getClass().getName(), "init");
      }
      PersonalizationContext pc = (PersonalizationContext) rc;

      if (s_log.isLoggable(Level.FINEST))
      {
         s_log.log(Level.FINEST, "getCurrentCategories() null");
      }
      ArrayList holdingList = new ArrayList();
      // generate a WCM workspace and render WCM content
      // have to pull the current user from puma
      if (puma_home == null)
      {
         getPumaHome();
      }
      try
      {                        
         User thisUser = puma_home.getProfile().getCurrentUser();
         InitialContext ctx = new InitialContext();
         // Retrieve WebContentService using JNDI name
         WebContentService webContentService = (WebContentService) ctx.lookup("portal:service/wcm/WebContentService");

         workspace = webContentService.getRepository().getWorkspace(thisUser);
         if (isFinest)
         {
            s_log.log(Level.FINEST, "workspace retrieved for " + thisUser.toString());
         }
         UserProfile currentUserProfile = workspace.getUserProfile();
         String[] currentCats = currentUserProfile.getCategories();
         if (isFinest)
         {
            s_log.log(Level.FINEST, "currentCats was length " + currentCats.length);
            if (currentCats.length > 0)
            {
               for (int x = 0; x < currentCats.length; x++)
               {
                  s_log.log(Level.FINEST, "currentCats contained " + currentCats[x]);
               }
            }
         }
         String tempCatString = "";
         String fullCatsUuidString = "";         
         String holdingString = null;        

         for (int x = 0; x < currentCats.length; x++)
         {
            tempCatString = currentCats[x];            
            // ditch the leading /
            if (tempCatString.charAt(0) == '/')
            {
               tempCatString = tempCatString.substring(1);
            }
            // lower it
            tempCatString = tempCatString.toLowerCase();
            holdingString = null;
            holdingString = WCMCategoryUtils.getCategoryId(tempCatString);
            if (holdingString != null)
            {
               tempCatString = UUID_PREFIX + holdingString;
               fullCatsUuidString = fullCatsUuidString + tempCatString;
               if (x < currentCats.length - 1)
               {
                  fullCatsUuidString = fullCatsUuidString + ",";
               }
            }
         }
         // if the fullCatsString has trailing , remove
         if (fullCatsUuidString.endsWith(","))
         {
            fullCatsUuidString = fullCatsUuidString.substring(0, fullCatsUuidString.length() - 1);
         }

         setCurrentCategoriesUuidString(fullCatsUuidString);
      }
      catch (Exception e)
      {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      // set myself in the session
      // that way, won't have to reinit
      pc.setSessionAttribute("CurrentCats", this);
      if (isFinest)
      {
         s_log.exiting(this.getClass().getName(), "init");
      }
   }

   /**
    * 
    * getPumaHome helper method to retrieve pumahome
    * @return
    */
   PumaHome getPumaHome()
   {
      if (puma_home == null)
      {
         try
         {
            Context ctx = new InitialContext();
            puma_home = (PumaHome) ctx.lookup(PumaHome.JNDI_NAME);
         }
         catch (Exception ex)
         {
            ex.printStackTrace();
         }
      }
      return puma_home;
   }

}

At a high level, this code retrieves the current user from PUMA SPI, creates a WCM workspace for that user, and then retrieves that user's categories. These categories are returned as path values, such as /LibraryName/Taxonomy/path/to/category. When PZN rules use categories, they use the uuid of the categories, so we have to convert the path to the category to a uuid value. Also, the rule expects the UUID to be passed in as comma delimited list of uuid values, with "uuid:" prepended to them. So this custom code does just this. Now, when the custom application object is referenced, it will retrieve the current user categories by retrieving the string using the getCurrentCategoriesUuidString method.

Export and Deploy the Custom Application Object


Now that the custom application object code is in place, we need to deploy to the WebSphere Portal server. In order for custom application objects to be used by Personalization, the code has to be placed in /WPHOME/pzn/prereq.pzn/lib.
  • In your custom application project, right click the src folder, and select export. Select to export as a .jar file
  • Ensure the Export generated class files and resources is checked.
  • Ensure the Export java source files and resources is checked.
  • Ensure the Add directory entries is checked.
  • Ensure the Compress contents of the JAR file is checked.
  • Select a location for the .jar, name it customcategoryapp.jar, and click finish.

  • Copy the .jar file to /WPHOME/pzn/prereq.pzn/lib directory and restart the Portal server.

Create the Application Object within PZN UI


Now that the code is in place, in order to use the UserCategoriesObject, we have to create the application object within the PZN UI.
  • Navigate to the PZN Personalization Navigator
  • Click New -> Application Object
  • For the name, enter CurrentUserCatsApp. For the Session Key, enter CurrentCats. For the Class Name, enter com.ibm.websphere.personalization.custom.appobject.UserCategoriesObject

  • Click save.

Creating the PZN rules


To display the results, we will create a WCM PZN Component in order to reference the rule.
  • Navigate to the WCM Authoring UI, open the library that you wish to store the PZN component in.
  • Create new -> Component -> Personalization
  • Name the component PZN - Current User Category Content
  • For the Personalization Element, click New. Create the rule to select Web Content whose category is associated with CurrentUserCatsApp.currentCategoriesUuidString:


  • Click Save.
  • In the PZN Component, for the Design for each Menu search result, put the following:
    [Property type="content" context="autofill" field="title"] - [Property type="content" context="autofill" field="categories"]<br>

    This will render the title of the content, as well as the categories that the content is associated with. This will tell us whether the rule is working.
  • Save and close the component

Rendering the Results


Now that we have the WCM Component in place, we just have to reference it from a WCM Rendering Portlet.
expanded Attachments (0)
collapsed Attachments (0)
expanded Versions (32)
collapsed Versions (32)
Version Comparison     
VersionDateChanged by              Summary of changes
32Oct 22, 2012, 2:08:58 PMChristopher Knight  IBM contributor
31Oct 22, 2012, 2:08:21 PMChristopher Knight  IBM contributor
30Oct 22, 2012, 2:05:52 PMChristopher Knight  IBM contributor
28Oct 22, 2012, 1:37:07 PMChristopher Knight  IBM contributor
27Oct 22, 2012, 1:22:43 PMChristopher Knight  IBM contributor
This version (26)Oct 22, 2012, 1:18:19 PMChristopher Knight  IBM contributor
25Oct 22, 2012, 10:47:57 AMChristopher Knight  IBM contributor
24Oct 22, 2012, 10:43:18 AMChristopher Knight  IBM contributor
23Oct 22, 2012, 10:21:03 AMChristopher Knight  IBM contributor
22Oct 22, 2012, 10:16:48 AMChristopher Knight  IBM contributor
21Oct 22, 2012, 10:11:47 AMChristopher Knight  IBM contributor
20Oct 22, 2012, 10:00:55 AMChristopher Knight  IBM contributor
19Oct 22, 2012, 9:55:37 AMChristopher Knight  IBM contributor
18Oct 19, 2012, 6:24:12 PMChristopher Knight  IBM contributor
17Oct 19, 2012, 5:06:13 PMChristopher Knight  IBM contributor
16Oct 19, 2012, 4:39:33 PMChristopher Knight  IBM contributor
15Oct 19, 2012, 12:13:40 PMChristopher Knight  IBM contributor
14Oct 19, 2012, 11:42:14 AMChristopher Knight  IBM contributor
13Oct 19, 2012, 10:23:31 AMChristopher Knight  IBM contributor
12Oct 19, 2012, 10:11:10 AMChristopher Knight  IBM contributor
11Oct 19, 2012, 10:03:19 AMChristopher Knight  IBM contributor
10Oct 17, 2012, 4:48:23 PMChristopher Knight  IBM contributor
9Oct 17, 2012, 3:51:07 PMChristopher Knight  IBM contributor
8Oct 17, 2012, 3:32:53 PMChristopher Knight  IBM contributor
7Oct 17, 2012, 3:23:23 PMChristopher Knight  IBM contributor
6Oct 17, 2012, 11:05:37 AMChristopher Knight  IBM contributor
5Oct 17, 2012, 10:59:39 AMChristopher Knight  IBM contributor
4Oct 17, 2012, 10:50:55 AMChristopher Knight  IBM contributor
3Oct 17, 2012, 10:50:26 AMChristopher Knight  IBM contributor
2Oct 17, 2012, 10:47:46 AMChristopher Knight  IBM contributor
1Oct 16, 2012, 2:44:48 PMChristopher Knight  IBM contributor
1Oct 16, 2012, 4:28:38 PMChristopher Knight  IBM contributor
Copy and paste this wiki markup to link to this article from another article in this wiki.
Go ElsewhereStay ConnectedHelpAbout
  • IBM Collaboration Solutions wikis
  • IBM developerWorks
  • IBM Software support
  • Twitter LinkIBMSocialBizUX on Twitter
  • FacebookIBMSocialBizUX on Facebook
  • ForumsLotus product forums
  • BlogsIBM Social Business UX blog
  • Community LinkThe Social Lounge
  • Wiki Help
  • Forgot user name/password
  • About the wiki
  • About IBM
  • Privacy
  • Accessibility
  • IBM Terms of use
  • Wiki terms of use