Monday, October 1, 2007

Architectural Pattern - Layering Enforcement

There are times in just about any Software Architects’ or Lead Developers’ careers when they wish that they had enforced a pattern more effectively – usually this comes when they find some code that has been around for ages that, for example, accesses a Data Access Object directly from a Servlet, a JSF Managed Bean, or (*gulp*) a JSP page… It usually leads to about a week of brainstorming and discussing ways to do better code reviews, and promises that each line of code will be painstakingly inspected before each commit – usually these efforts fall flat before long…

Before I go any further, let me make it clear that nothing can take the place of solid processes that include code reviews at every level, but let’s face it, we don’t all have an infrastructure like Google that will support this level of rigor – in these cases, we’ll take all the help we can get, and there are ways that we can both prevent the situation listed above, and (more importantly) remind the project developers to think about what they’re doing before it's done… That’s primarily what the following Architectural Pattern is about – a little technical help to try and keep things in line until someone gets a chance to do that code review…

So here I present the Layering Enforcement pattern, the purpose of which is to help ensure that certain classes, or types of classes are only called in certain situations… there could be many places where this will be useful in a given project – the example that follows involves a situation where the Generic CRUD Components from a recent blog entry by Adam Bien should only be called by Repository classes, so that database access is confined to places where it is expected, rather than spread around the classes in the project…

Many different implementations and variations of this are possible – my choice here has been to model a simple user management system with EJB 3 components… in addition, we get some help from a custom Java 5 Annotation, and an EJB Interceptor – this example could just as effectively be implemented with a Spring-based framework as well (probably better, as the EJB 3 Interception functionality is pretty weak – this effort was just as much about proving that EJB Interceptors could be useful as it was about proving the pattern itself :) )…

First off, we have the CRUD Component – I take no credit for this, it is purely from an example by Adam Bien:


public interface GenericCrudService {
public Object create(Object t);
public Object find(Object id,Class type);
public void delete(Object t);
public Object update(Object t);
public Collection findByNamedQuery(String queryName);
public Collection findByNamedQuery(String queryName,int resultLimit);
}


And the implementation:


@Stateless
@Local(GenericCrudService.class)
@Interceptors(RepositoryChecker.class)
public class GenericCrudServiceBean implements GenericCrudService {

@PersistenceContext
private EntityManager em;

public Object create(Object t) {
this.em.persist(t);
return t;
}

@SuppressWarnings("unchecked")
public Object find(Object id, Class type) {
return (Object) this.em.find(type, id);
}

public void delete(Object t) {
t = this.em.merge(t);
this.em.remove(t);
}

public Object update(Object t) {
return this.em.merge(t);
}

public Collection findByNamedQuery(String queryName) {
return this.em.createNamedQuery(queryName).getResultList();
}

public Collection findByNamedQuery(String queryName, int resultLimit) {
return this.em.createNamedQuery(queryName).setMaxResults(resultLimit).getResultList();
}
}



Next, we need a way to identify that a class is a Repository – this may be done in any number of ways, including a properties file that lists each Repository class, a specific class naming pattern (i.e. – MyFavoriteRepository.class), but my favorite is to use a custom Annotation – this particular one has no ‘data’ attached to it, and could potentially be considered a Marker Annotation (thanks again, Adam)… at any rate, any class annotated with @Repository will be able to access the CRUD Component either directly or indirectly (It also serves as a self-documenting annotation, which is another great benefit):



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Repository {

}


Finally, we need our EJB 3 Interceptor – as you saw above, the GenericCrudServiceBean listed the ‘RepositoryChecker’ Interceptor… the implementation, listed below, will be executed ‘around’ all method calls against the business interface of the GenericCrudServiceBean – it will inspect the StackTrace on the current thread, and use reflection to try and find any class that is annotated with @Repository… as soon as it finds one, it will allow processing to continue – if it does not find one, it will throw an IllegalStateException, indicating the problem for the developer:



public class RepositoryChecker {

public RepositoryChecker() {
}

@AroundInvoke
public Object verifyRepositoryInStack(InvocationContext ctx) throws Exception {

List<StackTraceElement> trace = Arrays.asList(Thread.currentThread().getStackTrace());

boolean foundRepository = false;

for(StackTraceElement element: trace) {
Class currentClass = Class.forName(element.getClassName());

Repository rep = (Repository)currentClass.getAnnotation(Repository.class);
if(rep != null) {
foundRepository = true;
break;
}
}

if(foundRepository)
return ctx.proceed();
else
throw new IllegalStateException("The target class "+ctx.getTarget().getClass().getName()+" must be called by a class marked with @Repository");
}
}



As I said, there are many ways that this could be implemented – I experimented with the idea of using another Interceptor that would place a variable into the InvocationContext when executing around a class marked with @Repository, and simply looking for the existence of that variable in the RepositoryChecker class, but decided against it, as I would need to either explicitly add the new Interceptor on each Repository class, or add it to all EJB 3 components (I could use it instead of @Repository, but I like the self-documenting nature of the annotation)… This alternative implementation would be simpler to build with Spring, as you could use a pointcut to specifically intercept calls on classes with the @Repository annotation…

As for using reflection for this solution – it may become a concern from a performance point of view, but I’m not inclined to worry about it unless there is a real problem… we’re not likely to be spending enormous amounts of time here, and if we are seeing a problem, then we can simply turn off the Interceptor in our staging and production environments, but leave it on for development (or integration, or whatever you call it) – we still get all of the benefits of the pattern (assuming that you actually use the development environment :) ), and most importantly, any developers that break the layering rule will hit it on their own machines, which will make them think twice about what they’re trying to do – ultimately, this is where the most value comes from when using this pattern, as it will help your team to better understand the patterns and policies that are in place on the project…

M

Err... Whaaaaaahhh?

Leave it to Sun to pull a WTF on what may be the most important release for Java on the Desktop in the last decade -- after finally announcing that we're going to get a streamlined, fast, easy to install JRE to compete with Flash and the like, they go an give it possibly the worst product name ever (does anyone remember Bob?) -- "Java SE 6 Update N"... My God, what are they thinking?

M