Seiten

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:
@Inject
@DemoLogicContext
Instance<DemoLogic> demoLogicInst;

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

The ContextResolver:
public class DemoLogicContextResolver implements ContextResolver
{
 @Inject
 Context context;

 @Override
 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)
 {
  //FindFirst
  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.