[cdi-dev] [JBoss JIRA] (CDI-666) simplify context implementation

Romain Manni-Bucau (JIRA) issues at jboss.org
Tue Dec 13 06:23:00 EST 2016


Romain Manni-Bucau created CDI-666:
--------------------------------------

             Summary: simplify context implementation
                 Key: CDI-666
                 URL: https://issues.jboss.org/browse/CDI-666
             Project: CDI Specification Issues
          Issue Type: Feature Request
            Reporter: Romain Manni-Bucau


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 ;)):

{code}
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;
        }
    }
}
{code}

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:

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



--
This message was sent by Atlassian JIRA
(v7.2.3#72005)


More information about the cdi-dev mailing list