Uploaded image for project: 'CDI Specification Issues'
  1. CDI Specification Issues
  2. CDI-666

simplify context implementation

    XMLWordPrintable

Details

    • Feature Request
    • Resolution: Obsolete
    • Major
    • None
    • None
    • None
    • None

    Description

      Today implementing a context leads to implementing Context or AlterableContext interface.

      Then for Thread Local related scopes it leads to handle activation, deactivation (thread local set/remove) and delegation of the context to a sub context (implementing or not Context interface). Finally it requires a destroyEnd() method destroying all instances.

      It also requires the instance tracking and instantiation correctly (with lock or not depending the usage).

      Here is a schematic implementation (easier than previous paragraph to read ):

      public class CommandContext implements AlterableContext {
          private final ThreadLocal<Delegate> delegate = new ThreadLocal<>();
      
          @Override
          public Class<? extends Annotation> getScope() {
              return CommandScoped.class;
          }
      
          @Override
          public <T> T get(final Contextual<T> component, final CreationalContext<T> creationalContext) {
              return delegate.get().get(component, creationalContext);
          }
      
          @Override
          public <T> T get(final Contextual<T> component) {
              return delegate.get().get(component);
          }
      
          @Override
          public boolean isActive() {
              final Delegate instance = delegate.get();
              if (instance == null) {
                  delegate.remove();
                  return false;
              }
              return instance.isActive();
          }
      
          @Override
          public void destroy(final Contextual<?> contextual) {
              delegate.get().destroy(contextual);
          }
      
          public Delegate newInstance() {
              return new Delegate();
          }
      
          public void withContext(final Delegate value, final Runnable task) {
              delegate.set(value);
              try {
                  task.run();
              } finally {
                  delegate.remove();
              }
          }
      
          public void destroy(final Delegate delegate) {
              new ArrayList<>(delegate.componentInstanceMap.keySet()).forEach(delegate::destroy);
          }
      
          public class Delegate implements AlterableContext {
              private final Map<Contextual<?>, BeanInstanceBag<?>> componentInstanceMap = new HashMap<>();
      
              private Delegate() {
                  // no-op
              }
      
              @Override
              public Class<? extends Annotation> getScope() {
                  return CommandScoped.class;
              }
      
              @Override
              public <T> T get(final Contextual<T> component, final CreationalContext<T> creationalContext) {
                  final BeanInstanceBag value = new BeanInstanceBag<>(creationalContext);
                  return (T) ofNullable(componentInstanceMap.putIfAbsent(component, value)).orElse(value).create(component);
              }
      
              @Override
              public <T> T get(final Contextual<T> component) {
                  return (T) ofNullable(componentInstanceMap.get(component)).map(b -> b.beanInstance).orElse(null);
              }
      
              @Override
              public void destroy(final Contextual<?> contextual) {
                  ofNullable(componentInstanceMap.remove(contextual)).filter(b -> b.beanInstance != null).ifPresent(b -> {
                      final Contextual c = contextual;
                      c.destroy(b.beanInstance, b.beanCreationalContext);
                      b.beanCreationalContext.release();
                  });
              }
      
              @Override
              public boolean isActive() {
                  return true;
              }
          }
      
          @RequiredArgsConstructor
          private static class BeanInstanceBag<T> {
              private final CreationalContext<T> beanCreationalContext;
              private T beanInstance;
      
              public T create(final Contextual<T> contextual) {
                  if (beanInstance == null) {
                      beanInstance = contextual.create(beanCreationalContext);
                  }
                  return beanInstance;
              }
          }
      }
      

      This is a lot for finally just define (what the user wants) when a context is active.

      Therefore it would be awesome is the spec would provide a context builder. Raw api proposal could be:

      void addContext(@Observes final AfterBeanDiscovery abd) {
          context = abd.contextBuilder().concurrent().scope(TheScoped.class).create();
          abd.addContext(context);
      }
      

      Attachments

        Activity

          People

            Unassigned Unassigned
            rmannibucau@gmail.com Romain Manni-Bucau
            Votes:
            1 Vote for this issue
            Watchers:
            4 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: