Friday, October 26, 2007

Create your own JSF variable resolver

The system I am working on, uses a singleton service factory (that uses Spring to configure the services) to lookup service instances. The JSF backing beans use these services to perform business operations and need to lookup the services with the central service locator. This is quite straightforward and unfortunately less straightforward when you want to unit test it: it would be a lot easier to inject the services into the backing beans like we are used to in Spring. Spring has a variable resolver that makes it possible to inject Spring managed beans defined in WEB-INF/applicationContext.xml into JSF managed beans. For various reasons the system I am working on cannot put the services in application context of the web application (service instances must be shared between multiple web applications on the server). To make the same sort of injection possible, I created a JSF variable resolver that will lookup the desired service in the global service locator.
public class ServiceLocatorVariableResolver extends VariableResolver {

private VariableResolver originalVariableResolver;
private ServiceLocator serviceLocator;

/**
* Constructor.
* @param originalVariableResolver Original JSF variable resolver.
*/
public ServiceLocatorVariableResolver(VariableResolver originalVariableResolver) {
   this.originalVariableResolver = originalVariableResolver;
}

/**
* {@inheritDoc}
*/
public Object resolveVariable(FacesContext context, String name) throws EvaluationException {
   Object result = null;
   result = originalVariableResolver.resolveVariable(context, name);
   if (result == null) {
     if (serviceLocator == null) {
         serviceLocator = ServiceLocatorFactory.getInstance().getLocator();
     }
     try {
         result = serviceLocator.getBean(name);
     } catch (NoSuchBeanDefinitionException e) {
         // ignore exception - bean not found
     }
   }
   return result;
}
}
As you can see, creating a variable resolver is quite straightforward and make dependency injection possible, even if you use an old fashioned service locator. Unit testing becomes a lot easier this way.