In my previous little rant, I showed you how to use @Alternative and alternative stereotypes to easily change bean implementations based upon deployment scenario. But that's not the end of the story. There's two other things I would sometimes like to be able to change at deployment time:
- interceptors
- decorators
Let's consider security. Suppose I have an interceptor that implements method-level role-based security for beans in the business layer
.
@Secure @Interceptor
class SecurityInterceptor {
@Inject User user;
@AroundInvoke
Object checkRole(InvocationContext ctx) throws Exception {
String[] roles = ctx.getMethod().getAnnotation(Secure.class).value();
for (String role: role) {
if ( !user.getRoles().contains(role) ) throw new AuthorizationException(role);
}
return ctx.proceed();
}
}
I also have a separate data access layer, consisting of beans that implement the following interface:
public interface DataAccess<T, V> {
public V getId(T object);
public T load(V id);
public void save(T object);
public void delete(T object);
public Class<T> getDataType();
...
}
And I have a decorator that adds row-level security to my data access layer.
@Decorator
class DataSecurityDecorator<T, V> implements DataAccess<T, V> {
@Inject @Delegate DataAccess<T, V> delegate;
@Inject User user;
public void save(T object) {
authorize(SecureAction.SAVE, object);
delegate.save(object);
}
public void delete(T object) {
authorize(SecureAction.DELETE, object);
delegate.delete(object);
}
private void authorize(SecureAction action, T object) {
V id = delegate.getId(object);
Class<T> type = delegate.getDataType();
if ( !user.getPermissions().contains( new Permission(action, type, id) ) ) {
throw new AuthorizationException(action);
}
}
}
Well, that's all very well, but in my test environment I don't want these interceptors and decorators to be enabled. And that's why, by default, they aren't.
We need to expilicity enable the interceptor and decorator for all deployments that require security access controls by declaring them in beans.xml.
<beans>
<interceptors>
<class>org.mycompany.security.SecurityInterceptor</class>
</interceptors>
<decorators>
<class>org.mycompany.security.DataSecurityDecorator</class>
</decorators>
</beans>