Additional Blogs by SAP
cancel
Showing results for 
Search instead for 
Did you mean: 
former_member189326
Active Participant
0 Kudos

Sometimes it's necessary to process the contents of a KM repository recursively - when writing a report using the KM Reporting API, for instance. Writing the logic for recursion isn't hard to do, but it's also easy to shoot yourself in the foot if you're not mindful of what you're doing.

On mulitple occasions, I have seen custom-implemented recursion fail and bring a server to its knees because one simple scenario was overlooked: it's possible for end users (although not necessarily reasonable) to create a link in a KM folder that points to a parent folder of itself (/documents/sample/myLink points to /documents/sample, for instance). Because of the way folder listings work in KM (ICollection.getChildren() follows links by default), this case is deadly if not handled expressly by the implementor. The result is an endless loop unless links are expressly not followed in the recursive code.

Here's a simple example of what I mean. Consider the following sample code, which probably won't compile but illustrates the point:


private void processFolder( ICollection col )
{
     // ... do some processing ...
     IResourceList list = col.getChildren( );
     for( int i = 0 ; i<list.size() ; i ++ )
     {
          IResource res = list.get(i);
          if( res.isCollection() )
          {
               processFolder( (ICollection) res );
          }
     }
}
  If this method is called on /documents/sample, the call to getChildren() will return myLink. Next, processFolder is called from within itself, this time on myLink. Listing the contents of myLink results in a set of resources also containing myLink again! Ouch.

As as side note: checking for cycles in the link structure of a repository isn't all that easy, since it's possible to create a cycle using more than one link. It turns out the easiest way to avoid this problem is to check for and not follow links when processing recursively using the method linkType(), available on any IResource:


     if( res.isCollection &&
         LinkType.NONE.equals( res.getLinkType ) )
     {
          processFolder( (ICollection) res );
     }

Luckily recursive processing has already been done for you and is available in the KM API via the utility classes in the com.sapportals.wcm.service.reporting.walker package, so it's best to reuse those classes if you can. Using these classes means that links won't be followed (no infinite loop!) at all, and you'll also save yourself the coding and maintenance of custom recursion.

The two interfaces IResourceObserver and IWalker are the main entry points into using and understanding this set of classes.

The IWalker object is responsible for the traversal of either namespace hierarchies (recursively, that's what the HierarchyWalker class does) or a list of resources / RIDs (that's what the RidWalker is for).

The IResourceObserver object passed in during creation of the IWalker will receive notification of each resource visited, and also offers methods for pruning the tree during traversal, i.e. controlling when processing is to be stopped.

Here is some sample code that illustrates how to use the classes in question. This is an iView, so you'll have to create a portal project and a new iView using the names used in this code (or adjust the code). When run from a browser, you'll get an overview of the structure of your repository as shown in the screenshot.

3 Comments