Skip to Content

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.Screenshot of sample code running

To report this post you need to login first.

3 Comments

You must be Logged on to comment or reply to a post.

  1. David Halitsky
    If all metadata structures were designed correctly up-front, all recursions would be foolproof.

    Unfortunately, the folks who design metadata structures aren’t always the folks who have to program against them.

    So the designers don’t always take the time to define an extra column here or there that automatically tells the programmer when to stop a recursion.

    (0) 
    1. Boris Magocsi Post author
      Hi David,

      thanks for the kind words. I agree strongly with the statement that the user of the API should be spared as much pain and intimate knowledge of internal structures as possible.

      In this case, the designers have provided us with the tool we need to avoid infinite recursion – we are supposed to use the HierarchyWalker for these tasks, I was hoping to advertise this in the blog.

      As for preventing infinite loops in all recursive operations – that’s a tough one. As you say yourself, that would require the programmer to “check for stop” herself – and there’s no way to guarantee that she will. As long as we are handed powerful tools that allow us to accomplish what we need to accomplish, there will always be the possibility of shooting oneself in the foot.

      (0) 

Leave a Reply