On 20 Nov 2012, at 00:50, Radu Creanga wrote:

> Hello everyone,
> 
> Pete,
>> We aren't firing servlet events in CDI 1.1 due to backwards incompatibility 
>> issues with extensions.
> Hmm, I was going off of [1]. There it stills says that it will be done, but 
> ok.

This was proposed but in the end the EG decided not to include it.

The JCP page reflects what is proposed, not what is actually included :-)

> 
> [1] http://jcp.org/en/jsr/detail?id=346
> 
> Mark,
>> Yes, we already discussed this and agreed to import it.
> Sounds good.
>> Txs 4 your report!
> Happy to help, this is fun.
> 
> Gerhard,
>> #1
> This should work.
> 
>> #2
> I need to familiarize myself better with view-access-scope.
> 
>> #3
> Also with window-scoped.
> 
> Intuitively all should work just fine, which one we'll pick will prob
> depend on ease / reliability.
> 
> I've been working on this since last night for our internal project
> since I can't move on without a reliable implementation, so I'd like
> to add the idea to the list.
> 
> #4 I thought it would be a good idea to make a BeanInfo object
> extending WeakReference that would store the bean instance, the
> Contextual object, and the CreationalContext object with strong
> references, but store a weak reference to the view map itself and
> place the bean instance (not the BeanInfo) in the view map. Also, have
> the Context keep a reference queue and use a clean up thread that
> blocks on the queue until some weak reference has been cleared -
> which, won't happen until the view map would be up for GC. I thought
> that, even though JSF doesn't fire the PreDestroyViewMapEvent, it
> would at least release the map for GC, but it appears that this is not
> the case (the implementation reuses them?). Anyhow, I store a marker
> object in the view attributes map and link a weak reference to that
> object while still placing all the bean instances in the view map.
> Once the view goes out of scope, all the associated bean instances get
> properly destroyed right after the next CG cycle. This works for my
> needs for now as I don't need them to be destroyed right away although
> it is important that they get disposed properly eventually. It may not
> be a good general purpose implementation since depending on the server
> load, the next GC cycle may not come for quite some time. Also, I
> don't know how this play out with serialization, I'm guessing not so
> well however.
> 
> Here's a rough copy / paste from my implementation:
> 
> package com.concensus.athena.framework.cdi.extension;
> 
> import java.lang.annotation.Annotation;
> import java.lang.ref.ReferenceQueue;
> import java.lang.ref.WeakReference;
> import java.util.HashSet;
> import java.util.Map;
> import java.util.Set;
> import javax.enterprise.context.ContextNotActiveException;
> import javax.enterprise.context.spi.Context;
> import javax.enterprise.context.spi.Contextual;
> import javax.enterprise.context.spi.CreationalContext;
> import javax.enterprise.inject.spi.Bean;
> import javax.faces.component.UIViewRoot;
> import javax.faces.context.FacesContext;
> 
> public class ViewContext implements Context {
> 
>    private class BeanInfo<T> extends WeakReference<Object> {
> 
>        private final T instance;
>        private final Contextual<T> contextual;
>        private final CreationalContext<T> creationalContext;
> 
>        public BeanInfo(Object pin,
>                ReferenceQueue<Object> queue,
>                Contextual<T> contextual,
>                CreationalContext<T> creationalContext) {
>            super(pin, queue);
>            this.contextual = contextual;
>            this.creationalContext = creationalContext;
>            this.instance = this.contextual.create(this.creationalContext);
>        }
> 
>        public T getInstance() {
>            return this.instance;
>        }
> 
>        public void dispose() {
>            this.contextual.destroy(this.instance, this.creationalContext);
>        }
> 
>    }
> 
>    private boolean run;
>    // needed to make sure the weak references themselves don't become
> stale before they serve their purpose
>    private final Set<BeanInfo> set;
>    private final ReferenceQueue<BeanInfo> queue;
>    private final Thread disposer;
> 
>    public ViewContext() {
>        this.run = true;
>        this.set = new HashSet<BeanInfo>();
>        this.queue = new ReferenceQueue<BeanInfo>();
>        this.disposer = new Thread(new Runnable() {
> 
>            @Override
>            public void run() {
>                BeanInfo beanInfo;
>                while (run) {
>                    try {
>                        beanInfo = (BeanInfo) queue.remove();
>                            set.remove(beanInfo);
>                            beanInfo.dispose();
>                    } catch (InterruptedException e) {
>                        // log
>                    }
>                }
>            }
> 
>        });
>        this.disposer.start();
>    }
> 
>    private UIViewRoot getViewRoot() {
>        FacesContext fc = FacesContext.getCurrentInstance();
>        return fc == null ? null : fc.getViewRoot();
>    }
> 
>    private static final String MARKER =
>            ViewContext.class.getName() + '.' + "MARKER";
> 
>    // make sure to use one marker per view for all of it's instances
>    private Object getMarker(Map<String, Object> attributes) {
>        if (attributes.containsKey(ViewContext.MARKER)) {
>            return attributes.get(ViewContext.MARKER);
>        } else {
>            Long marker = System.currentTimeMillis();
>            attributes.put(ViewContext.MARKER, marker);
>            return marker;
>        }
>    }
> 
>    @Override
>    public Class<? extends Annotation> getScope() {
>        return ViewScoped.class;
>    }
> 
>    @Override
>    public <T> T get(final Contextual<T> contextual,
>            final CreationalContext<T> creationalContext) {
>        UIViewRoot viewRoot = this.getViewRoot();
>        if (viewRoot == null) {
>            throw new ContextNotActiveException();
>        }
>        if (contextual instanceof Bean) {
>            Bean bean = (Bean) contextual;
>            String name = bean.getName();
>            Map<String, Object> viewMap = viewRoot.getViewMap();
>            if (viewMap.containsKey(name)) {
>                return (T) viewMap.get(name);
>            } else {
>                Object marker = this.getMarker(viewRoot.getAttributes());
>                BeanInfo<T> beanInfo = new BeanInfo(
>                        marker, this.queue, contextual, creationalContext);
>                T instance = beanInfo.getInstance();
>                viewMap.put(name, instance);
>                this.set.add(beanInfo);
>                return instance;
>            }
>        } else {
>            return null;
>        }
>    }
> 
>    @Override
>    public <T> T get(Contextual<T> contextual) {
>        UIViewRoot viewRoot = this.getViewRoot();
>        if (viewRoot == null) {
>            throw new ContextNotActiveException();
>        }
>        if (contextual instanceof Bean) {
>            Bean bean = (Bean) contextual;
>            String name = bean.getName();
>            Map<String, Object> viewMap = viewRoot.getViewMap();
>            return (T) viewMap.get(name);
>        } else {
>            return null;
>        }
>    }
> 
>    @Override
>    public boolean isActive() {
>        return this.getViewRoot() != null;
>    }
> 
>    // this is bad, yes, does @PreDestroy work on Context objects?
>    @Override
>    protected void finalize() throws Throwable {
>        try {
>            this.run = false;
>        } finally {
>            super.finalize();
>        }
>    }
> 
> }
> 
> Cheers,
> Radu Creanga
> 
> 
> On Mon, Nov 19, 2012 at 5:35 PM, Gerhard Petracek
> <[email protected]> wrote:
>> hi radu,
>> 
>> imo we have 3 easy options:
>> 
>> #1
>> we continue to rely on jsf-events and just add a session-scoped bean which
>> triggers the cleanup via its @PreDestroy callback (if the cleanup wasn't
>> done already).
>> (we also need one to cleanup the window-context.)
>> 
>> #2
>> since we also need to track the view-ids for the view-access-scope, we just
>> use a similar implementation (which follows the rules of the view-scope) and
>> map it to @ViewScoped.
>> 
>> #3
>> like #2 but with the help of the window-context (instead of the view-map) ->
>> similar to [1].
>> 
>> regards,
>> gerhard
>> 
>> [1]
>> http://os890.blogspot.co.at/2011/06/session-based-view-scope-with-codi.html
>> 
>> 
>> 
>> 
>> 2012/11/19 Mark Struberg <[email protected]>
>>> 
>>> 
>>> 
>>> Hi Radu!
>>> 
>>> Yes, we already discussed this and agreed to import it.
>>> Txs 4 your report!
>>> 
>>> LieGrue,
>>> strub
>>> 
>>> 
>>> 
>>> 
>>> 
>>>> ________________________________
>>>> From: Radu Creanga <[email protected]>
>>>> To: [email protected]
>>>> Sent: Sunday, November 18, 2012 11:56 PM
>>>> Subject: Re: [jira] [Created] (DELTASPIKE-293) Improve the
>>>> ViewScopedContext by observing ServletContext and HttpSession lifecycle
>>>> events.
>>>> 
>>>> Hello everyone,
>>>> 
>>>> It seems this will require ServletContext events and Session events to
>>>> be published to the CDI event bus, which in turn requires adding the
>>>> appropriate listeners to web.xml until CDI 1.1. I know Seam Solder has
>>>> these listeners implemented. Are there plans to import it into
>>>> DeltaSpike?
>>>> 
>>>> Radu Creanga
>>>> 
>>>> 
>>>> On Sun, Nov 18, 2012 at 4:32 PM, Radu Creanga (JIRA) <[email protected]>
>>>> wrote:
>>>>> Radu Creanga created DELTASPIKE-293:
>>>>> ---------------------------------------
>>>>> 
>>>>>             Summary: Improve the ViewScopedContext by observing
>>>>> ServletContext and HttpSession lifecycle events.
>>>>>                 Key: DELTASPIKE-293
>>>>>                 URL:
>>>>> https://issues.apache.org/jira/browse/DELTASPIKE-293
>>>>>             Project: DeltaSpike
>>>>>          Issue Type: Improvement
>>>>>          Components: JSF-Module
>>>>>    Affects Versions: 0.4-incubating
>>>>>            Reporter: Radu Creanga
>>>>>             Fix For: 0.5-incubating
>>>>> 
>>>>> 
>>>>> The CDI specification states that Context implementations are
>>>>> responsible for destroying instances it creates. The current
>>>>> ViewScopedContext relies on PreDestroyViewMapEvents to be notified when a
>>>>> view map is destroyed. But, the JSF 2.0 and 2.1 spec only fire this event
>>>>> when a view map is replaced. This means that in most cases, instances
>>>>> created by ViewScopedContext are not properly destroyed. The
>>>>> ViewScopedContext should be observing ServletContext and HttpSession
>>>>> lifecycle events instead in order to ensure that all instances it creates
>>>>> are properly destroyed. Visible improvements resulting out of this would 
>>>>> be
>>>>> that the @PostConstruct method of @ViewScoped beans is invoked.
>>>>> Additionally, this will probably result in better memory usage, since
>>>>> instances that are not properly destroyed are not eligible for GC.
>>>>> 
>>>>> --
>>>>> This message is automatically generated by JIRA.
>>>>> If you think it was sent incorrectly, please contact your JIRA
>>>>> administrators
>>>>> For more information on JIRA, see:
>>>>> http://www.atlassian.com/software/jira
>>>> 
>>>> 
>>>> 
>> 
>> 

Reply via email to