Hi,<br><br>On Friday, November 14, 2014, Jozef Hartinger &lt;<a href="javascript:_e(%7B%7D,&#39;cvml&#39;,&#39;jharting@redhat.com&#39;);" target="_blank">jharting@redhat.com</a>&gt; wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
On 11/14/2014 09:14 AM, Mark Struberg wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I did not say it cannot work but that it is not guaranteed to work. It&#39;s just totally up to implementation details of the container and your actual situation. Basically it&#39;s non-portable at best.<br>
<br>
<br>
E.g. consider the case that you are NOT the outermost interceptor but there are 2 other decorators and interceptors. The decorators will probably not hurt much as they are defined to be called _after_ interceptors. But if there is an interceptor in addition to yours then you will probably kill em and after returning from the chain you might end up in a dead bean (the other interceptor).<br>
</blockquote>
You are right Mark but I think this is not a problem of whether you call AlterableContext.destroy() from within an interceptor or not. This is a more general problem of destroying instances. Say you have an intercepted @ApplicationScoped bean Foo. Thread 1 is calling an intercepted method and is currently in the middle of the interceptor chain. Thread 2 calls AlterableContext.destroy(Foo) in a Servlet (not from an interceptor!). Foo is destroyed together with its interceptors by Thread 2. Thread 1 finds itself executing a dead interceptor chain for a destroyed bean.</blockquote><div><br></div><div>It looks like the issue may be even more general.</div><div><br></div><div>I have to do some more tests to confirm, but I think I observed a situation where thread 1 at the end of a request destroyed session scoped bean Foo in a Servlet. At that point thread 2 was already using bean Foo, and it kept getting the same instance from the proxy and could even destroy the bean again. Meanwhile, while thread 2 was getting the destroyed bean instance, thread 3 that started after the instance was destroyed by thread 1 did get a new instance.<span></span></div><div><br></div><div>It looked like some TLS caching issue, but as said I have to do some more tests to see if this can be reproduced.</div><div><br></div><div>Kind regards,</div><div>Arjan Tijms</div><div> </div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br>
There are just so many things which can go wrong. Even though I like the general idea what you like to do with that interceptor. But I suggest you probably use another trick. Every CDI bean must (as per the interceptors spec) support &#39;self-interception&#39;. Means you only need to add an @AroundInvoke method and do the re-setup of your CONNECTION inside your @ApplicationScoped bean (with full access to the underlying business infrastructure).<br>
<br>
<br>
This is fundamentally different to your approach as I do not ditch the whole service but only fix the thing which broke in it.<br>
<br>
<br>
LieGrue,<br>
strub<br>
<br>
<br>
<br>
On Thursday, 13 November 2014, 16:28, arjan tijms &lt;<a>arjan.tijms@gmail.com</a>&gt; wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi,<br>
<br>
On Wednesday, November 12, 2014, Jozef Hartinger &lt;<a>jharting@redhat.com</a>&gt; wrote:<br>
<br>
Hi Arjan,<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
there is a bug in Weld (WELD-1785) preventing this from working which is going to be fixed in the next release. What you are doing should work IMO as long as the interceptor does not call any other methods on the target instance.<br>
</blockquote>
<br>
That&#39;s great to hear really.<br>
<br>
<br>
I&#39;m slightly confused through why Mark thinks this cannot really work, while you say it should.<br>
<br>
<br>
Is there something in the spec that may need to be clarified here? Ie some words about what an interceptor is at least allowed to do and what is definitely not allowed?<br>
<br>
<br>
<br>
In addition it must count with the target instance being destroyed within the instance.destroy() call.<br>
<br>
<br>
Sorry, I don&#39;t fully follow this. You mean something must be counted?<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Perhaps a nicer way of doing this would be:<br>
<br>
@Inject<br>
@Intercepted<br>
private Bean&lt;?&gt; bean;<br>
<br>
        Context context = manager.getContext(bean.<u></u>getScope());<br>
        if (!(context instanceof AlterableContext)) {<br>
            throw new IllegalStateException(&quot;Context does not support removal of instances&quot;);<br>
        }<br>
        AlterableContext alterableContext = AlterableContext.class.cast(<u></u>context);<br>
        alterableContext.destroy(bean)<u></u>;<br>
</blockquote>
<br>
I tried something close to that as well, just used the bean manager to resolve a Bean from the target object. Thanks for the suggestion!<br>
<br>
<br>
Kind regards,<br>
Arjan<br>
<br>
<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On 11/10/2014 02:59 PM, arjan tijms wrote:<br>
<br>
Hi,<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I wonder if it would be allowed according to the CDI spec to destroy a<br>
bean instance from within an interceptor.<br>
<br>
To test this (on Weld) I used the following code:<br>
<br>
@Interceptor<br>
@DestroyOnError<br>
@Priority(APPLICATION)<br>
public class DestroyOnErrorInterceptor implements Serializable {<br>
<br>
     private static final long serialVersionUID = 1L;<br>
<br>
     @AroundInvoke<br>
     public Object tryInvoke(InvocationContext ctx) throws Exception {<br>
<br>
         try {<br>
             return ctx.proceed();<br>
         } catch (Exception e) {<br>
             destroy(ctx.getMethod().<u></u>getDeclaringClass());<br>
             throw e;<br>
         }<br>
     }<br>
<br>
     private &lt;T&gt; void destroy(Class&lt;T&gt; clazz) {<br>
         Instance&lt;T&gt; instance = CDI.current().select(clazz);<br>
         instance.destroy(instance.get(<u></u>));<br>
     }<br>
<br>
}<br>
<br>
<br>
When I use this interceptor on a SessionScoped bean:<br>
<br>
@SessionScoped<br>
public class TestBean implements Serializable {<br>
<br>
     private static final long serialVersionUID = 1L;<br>
<br>
     @DestroyOnError<br>
     public void test() {<br>
         throw new IllegalStateException();<br>
     }<br>
}<br>
<br>
And then inject said bean in say a Servlet and call the test() method,<br>
destruction of the bean happens partially, but as soon as Weld tried<br>
to invocate a preDestroy method, it goes through the bean proxy again,<br>
detects that &quot;the&quot; interceptor handler is already active, promptly<br>
skips its attempt to call a preDestroy method and then to add insult<br>
to injury tries to call a &quot;proceed&quot; method which is always null and<br>
thus throws a NPE.<br>
<br>
(this happens in<br>
org.jboss.weld.bean.proxy.<u></u>CombinedInterceptorAndDecorato<u></u>rStackMethodHandler.invoke)<br>
<br>
I tried some alternative methods to destroy the bean such as:<br>
<br>
<br>
Bean&lt;T&gt; bean = resolve(beanManager, beanClass);<br>
<br>
AlterableContext context = (AlterableContext)<br>
beanManager.getContext(bean.<u></u>getScope());<br>
context.destroy(bean);<br>
<br>
with resolve being:<br>
<br>
public static &lt;T&gt; Bean&lt;T&gt; resolve(BeanManager beanManager, Class&lt;T&gt; beanClass) {<br>
         Set&lt;Bean&lt;?&gt;&gt; beans = beanManager.getBeans(<u></u>beanClass);<br>
<br>
         for (Bean&lt;?&gt; bean : beans) {<br>
             if (bean.getBeanClass() == beanClass) {<br>
                 return (Bean&lt;T&gt;)<br>
beanManager.resolve(<u></u>Collections.&lt;Bean&lt;?&gt;&gt;<u></u>singleton(bean));<br>
             }<br>
         }<br>
<br>
         return (Bean&lt;T&gt;) beanManager.resolve(beans);<br>
     }<br>
<br>
But this resulted in the same problem.<br>
<br>
Any idea?<br>
<br>
Kind regards,<br>
Arjan Tijms<br>
______________________________<u></u>_________________<br>
cdi-dev mailing list<br>
<a>cdi-dev@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/cdi-dev" target="_blank">https://lists.jboss.org/<u></u>mailman/listinfo/cdi-dev</a><br>
<br>
Note that for all code provided on this list, the provider licenses the code under the Apache License, Version 2 (<a href="http://www.apache.org/licenses/LICENSE-2.0.html" target="_blank">http://www.apache.org/<u></u>licenses/LICENSE-2.0.html</a>). For all other ideas provided on this list, the provider waives all patent and other intellectual property rights inherent in such information.<br>
<br>
</blockquote></blockquote>
______________________________<u></u>_________________<br>
cdi-dev mailing list<br>
<a>cdi-dev@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/cdi-dev" target="_blank">https://lists.jboss.org/<u></u>mailman/listinfo/cdi-dev</a><br>
<br>
Note that for all code provided on this list, the provider licenses the code under the Apache License, Version 2 (<a href="http://www.apache.org/licenses/LICENSE-2.0.html" target="_blank">http://www.apache.org/<u></u>licenses/LICENSE-2.0.html</a>). For all other ideas provided on this list, the provider waives all patent and other intellectual property rights inherent in such information.<br>
<br>
<br>
</blockquote></blockquote>
<br>
</blockquote>