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.