Mittwoch, 14. Mai 2014

CDI ContextResolver Pattern 2.0

What is the ContextResolver Pattern?
It is a pattern describe by Sven Ruppert (here) to solve the following problem.

The Problem
A service has several implementations which are provided to clients depending on a specific environment context (for example: test- or developmentcontext) on the service side. The client does not know about the context and the environment context must be dynamically configurable.

The Solution
Decouple the service creation from the context resolving by introducing
  • a ContextResolver which determines the current context and returns an annotation literal
  • a Service Context Qualifier
  • a service producer which uses the servicecontextqualifier
With that you can develop very flexible and extendable modules or applications which can be dynamically configured at runtime.

The Evolution
The previous version is implemented with CDI extensions which is a little bit harder to understand and needs a javax.enterprise.inject.spi.Extension file. So here is the improved version which uses only plain CDI-Producers and therefore should be easier to understand.

The client:
Instance<DemoLogic> demoLogicInst;

The producer:
public class DemoLogicProducer
 public DemoLogic create(BeanManager beanManager, @Any Instance<ContextResolver> contextResolvers)
  return ManagedBeanCreator.createManagedInstance(beanManager, contextResolvers, DemoLogic.class);

The ContextResolver:
public class DemoLogicContextResolver implements ContextResolver
 Context context;

 public AnnotationLiteral<?> resolveContext(Class<?> targetClass)
  //Determines the context and returns annotionliteral 
  return context.isUseB() ? new MandantB.Literal() : new MandantA.Literal();

The ManagedBeanCreator:
public class ManagedBeanCreator
 public static <T> T createManagedInstance(BeanManager beanManager, Instance<ContextResolver> contextResolvers,
   Class<? extends T> clazz)
  for (ContextResolver contextResolver : contextResolvers)
   AnnotationLiteral<?> annotationLiteral = contextResolver.resolveContext(DemoLogic.class);
   Set<Bean<?>> beans = beanManager.getBeans(clazz, annotationLiteral);

   //Create CDI Managed Bean
   Bean<?> bean = beans.iterator().next();
   CreationalContext<?> ctx = beanManager.createCreationalContext(bean);
   return (T) beanManager.getReference(bean, clazz, ctx);
  return null;

The sources can be found here.

Have fun coding.