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.