Issue Details (XML | Word | Printable)

Key: GLASSFISH-17152
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Shing Wai Chan
Reporter: Neil Rutherford
Votes: 1
Watchers: 3
Operations

If you were logged in you would be able to see more operations.
glassfish

CDI HttpServletRequestContext not active for asynchronous servlet

Created: 05/Aug/11 01:36 PM   Updated: 27/Feb/13 06:35 PM   Resolved: 27/Feb/13 06:31 PM
Component/s: web_container
Affects Version/s: 3.1.1
Fix Version/s: 4.0_b78

Time Tracking:
Not Specified

File Attachments: 1. Zip Archive gf-async-error.zip (6 kB) 09/Nov/11 03:39 PM - Neil Rutherford

Environment:

Windows 7 (x64), JDK 7 (x64), Eclipse Indigo (3.7), Glassfish Open Source 3.1.1


Tags: 3_1_2-exclude weld-int-required
Participants: jjsnyder83, Joe Di Pol, Neil Rutherford, Shing Wai Chan and Sivakumar Thyagarajan


 Description  « Hide

I have a servlet which performs background processing using servlet 3 AsyncContext:

final AsyncContext context = request.startAsync();
context.addListener(this);
context.start(new Runnable() {
public void run() { // [ ... do background RPC call, store result in request ...] context.dispatch(); });

This will dispatch back to the original servlet which uses a request scoped managed bean, which causes the following exception:

org.jboss.weld.context.ContextNotActiveException: WELD-001303 No active contexts for scope type javax.enterprise.context.RequestScoped
at org.jboss.weld.manager.BeanManagerImpl.getContext(BeanManagerImpl.java:664)
at org.jboss.weld.bean.proxy.ContextBeanInstance.getInstance(ContextBeanInstance.java:77)
at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:87)
at [Weld Client Proxy]
at AuthenticateServlet.doPost(AuthenticateServlet.java:78)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:754)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:847)
at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1539)
at org.apache.catalina.core.ApplicationDispatcher.doInvoke(ApplicationDispatcher.java:787)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:649)
at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:483)
at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:454)
at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:350)
at org.apache.catalina.connector.AsyncContextImpl$Handler.run(AsyncContextImpl.java:406)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)

After some investigation, it seems this is related to Weld ServletRequestListener not be notified of "new" request.

This also seems to have happened under different conditions as well, both in Glassfish and Tomcat 7:

https://issues.apache.org/bugzilla/show_bug.cgi?id=49991
https://issues.apache.org/bugzilla/show_bug.cgi?id=50789

http://java.net/jira/browse/GLASSFISH-11504
http://java.net/jira/browse/GLASSFISH-12642 (this fix should have handled my case, but was reverted by change in GLASSFISH-13974)
http://java.net/jira/browse/GLASSFISH-13974



Sivakumar Thyagarajan added a comment - 21/Oct/11 03:46 PM

Requesting Shing Wai to investigate this further.


Sivakumar Thyagarajan made changes - 21/Oct/11 03:46 PM
Field Original Value New Value
Assignee Sivakumar Thyagarajan [ sivakumart ] Shing Wai Chan [ swchan2 ]
Component/s cdi [ 10637 ]
Shing Wai Chan added a comment - 25/Oct/11 01:16 AM

Can you provide a unit test case for the scenario?


Shing Wai Chan added a comment - 27/Oct/11 07:59 PM

Please provide a test case for further investigation.


Shing Wai Chan made changes - 27/Oct/11 07:59 PM
Assignee Shing Wai Chan [ swchan2 ] Sivakumar Thyagarajan [ sivakumart ]
Neil Rutherford added a comment - 09/Nov/11 03:39 PM

Sorry for the delay, been really busy with Family and Work.

I've attached a simple eclipse maven project with 1 servlet and 1 request scoped bean.

If you perform a GET or POST on the servlet it will start an async context and start a runnable which will wait for 3 seconds, set a request attribute and then do a context.dispatch() back to servlet which will try and access request scoped bean - which will throw a ContextNotActiveException.


Neil Rutherford made changes - 09/Nov/11 03:39 PM
Attachment gf-async-error.zip [ 48021 ]
Sivakumar Thyagarajan made changes - 14/Nov/11 08:51 AM
Status Open [ 1 ] In Progress [ 3 ]
Sivakumar Thyagarajan made changes - 14/Nov/11 08:52 AM
Tags 3_1_2-review
Sivakumar Thyagarajan added a comment - 11/Dec/11 06:48 AM

Shing Wai: I am able to reproduce this issue with the attached testcase. I think this may be due to a request listeners not getting called during async dispatched back to the original servlet. Could you please look into this?


Sivakumar Thyagarajan made changes - 11/Dec/11 06:48 AM
Assignee Sivakumar Thyagarajan [ sivakumart ] Shing Wai Chan [ swchan2 ]
Shing Wai Chan added a comment - 13/Dec/11 01:41 AM

Web container integrated with weld through org.jboss.weld.servlet.WeldListener which is a ServletRequestListener.
There are two issues in the case of async.

I. When should ServletRequestListener#requestDestroyed be called?
Suppose we have a servlet A which has startAsync.
One one hand, servlet A will continue to the end of javax.servlet.Servlet#service.
(ii) On the other hand, the async request will continue processing.

Is it after ? Or after (ii)? Or wait until both and (ii) are done.
I have started the discussion in expert group.

II. I have manually put a sleep at the end of Servlet#service in the test case.
It still does not work.
In WeldListener#requestInitialized, we invoke
org.jboss.weld.context.http.HttpRequestContextImpl.active()
which will invoke RequestScopedBeanCache.beginRequest()
which will set a ThreadLocal list.
The given test case start async in a different thread. Hence the data is lost and the test fails.

So, we may like to fix (II) in weld code in this case.


Sivakumar Thyagarajan added a comment - 04/Jan/12 11:57 AM

RequestScoped Beans do not seem to be available during an async invocation (running in a thread that is different from the thread that initiated the ServletRequest in the Servlet). Shingwai debugged this above and found out that this is due to the ThreadLocal usage to cache RequestScoped Beans in org.jboss.weld.context.cache.RequestScopedBeanCache.

As per the definition of RequestScoped [3], the request scope must be active until a call to onComplete is done. So, I assume the request scoped bean must also be available in the Servlet when it was dispatched to from the async thread. I am following this up with the weld team. There already seems to be a WELD issue at https://issues.jboss.org/browse/WELD-1020


Joe Di Pol added a comment - 24/Jan/12 05:41 PM

Since this likely requires a new Weld integration, and it's too late in 3.1.2 for this to happen, I'm excluding from 3.1.2.


Joe Di Pol made changes - 24/Jan/12 05:41 PM
Tags 3_1_2-review 3_1_2-exclude
Sivakumar Thyagarajan added a comment - 24/Jan/12 06:20 PM

The CDI 1.0 spec does not define this behaviour and so we can't expect this to work portably. We are discussing this with the CDI 1.1 group to clarify this in CDI 1.1 and hence this could only be fixed in Weld 2.0 builds when it becomes available. Marking this issue as weld-int-required as well.


Sivakumar Thyagarajan made changes - 24/Jan/12 06:20 PM
Tags 3_1_2-exclude 3_1_2-exclude weld-int-required
jjsnyder83 added a comment - 27/Feb/13 06:31 PM

Committed revision 59872.


jjsnyder83 made changes - 27/Feb/13 06:31 PM
Status In Progress [ 3 ] Resolved [ 5 ]
Fix Version/s 4.0_b78 [ 16107 ]
Resolution Fixed [ 1 ]
jjsnyder83 added a comment - 27/Feb/13 06:35 PM

I had to make sure that the weld listener's requestInitialized method was called before the async method was called and make sure that the weld listener's requestDestroyed method was called after the async method was called. This is necessary because CDI requires that a request context is active during async method executions. Calling the Weld listener's methods sets up the request context correctly for Weld.