2010

With an app that I worked on recently it was decided that links the user did not have permission to view would show up as disabled. There was quite a lot of links in the application, and I am pretty lazy, so I decided to have a look and see if there was a better way of doing this than having to edit the disabled property of all the links. As it turns out there is using a facelets TagDecorator (this is now part of JSF 2).

 

A TagDecorator allows you to modify a tag on your page before the page is compiled, I decided to use it to automatically add an el based 'disabled' property to all my s:link and s:button controls:

 

 

public class SecurityTagDecorator implements TagDecorator
{

   public Tag decorate(Tag tag)
   {
      if (!tag.getNamespace().equals("http://jboss.com/products/seam/taglib"))
      {
         return null;
      }
      //we are only interested in s:link and s:button
      if (tag.getLocalName().equals("link")
            || tag.getLocalName().equals("button"))
      {
         TagAttribute view = tag.getAttributes().get("view");
         if (view == null)
         {
            return null;
         }
         String viewId = view.getValue();
         //don't try and fix el based permission
         if (viewId.contains("#{"))
         {
            return null;
         }
         //el expression that tests if a page is viewable
         String disabled = "#{not pageSecurityManager.isViewable('" + viewId
               + "')}";
         //we also add the permissionDenied styleClass to the link
         String styleClass = "#{pageSecurityManager.isViewable('" + viewId
               + "') ? '' : ' permissionDenied'}";

         TagAttribute[] at = tag.getAttributes().getAll();
         boolean styleFound = false;
         boolean disFound = false;
         //loop through all the attributes on the tag. We need to make sure there is
         //not an existing diabled or styleClass tag.
         //if there is we replace it
         for (int j = 0; j < at.length; ++j)
         {
            TagAttribute i = at[j];
            if (i.getLocalName().equals("styleClass"))
            {
               styleFound = true;
               String val = i.getValue();
               //add our style el expression to the existing attribute
               TagAttribute ti = new TagAttribute(i.getLocation(), i
                     .getNamespace(), i.getLocalName(), i.getQName(), val
                     + styleClass);
               at[j] = ti;
            }
            if (i.getLocalName().equals("disabled"))
            {
               disFound = true;
               //replace the disabled attribute
               TagAttribute ti = new TagAttribute(i.getLocation(), i
                     .getNamespace(), i.getLocalName(), i.getQName(), disabled);
               at[j] = ti;
            }
         }
         //if the attributes were not found we add new ones
         if (!styleFound)
         {
            TagAttribute ti = new TagAttribute(tag.getLocation(), "",
                  "styleClass", "styleClass", styleClass);
            TagAttribute[] old = at;
            at = new TagAttribute[old.length + 1];
            for (int k = 0; k < old.length; ++k)
            {
               at[k] = old[k];
            }
            at[old.length] = ti;
         }
         if (!disFound)
         {
            TagAttribute ti = new TagAttribute(tag.getLocation(), "",
                  "disabled", "disabled", disabled);
            TagAttribute[] old = at;
            at = new TagAttribute[old.length + 1];
            for (int k = 0; k < old.length; ++k)
            {
               at[k] = old[k];
            }
            at[old.length] = ti;
         }
         //return our modified tag
         TagAttributes ats = new TagAttributes(at);
         return new Tag(tag, ats);
      }
      return null;

   }
}

 

 

We then need to register our TagDecorator in web.xml:

 

 

<context-param>
  <param-name>facelets.DECORATORS</param-name>
  <param-value>
  com.mydomain.SecurityTagDecorator;
  </param-value>
 </context-param>

 

And vola, all the s:links in the application are automatically disabled if the user does not have permission to use them.