Hi
On 13/11/12 22:24, Gege wrote:
It's kind of getting too far in CXF's core for me.
At least I understand what you said bout re-dispatching the message,
sorry for disagreeing before...
no problems and thanks for spending the time on it
---------
Short version of what i think now :
When "resume-suspend", the request re-goes through doGet and when
calling startAsync a new AsyncContext is created.
We HAVE to keep the same Servlet3Continuation object because the
AsyncResponseImpl has a reference to it.
I think that the best way to keep the same Servlet3Continuation
(AsyncListener) is by using the onStartAsync event (that's what it's
made for).
So we might "just" need to know this request is "special" and call
startAsync on it. The onStartAsync would handle the "switch" from the
older context to the newer one.
However : i don't know of to make the internal mechanics of CXF behave
properly... and if I'm right.
---------
Log version with some code :
I played with simple async servlet 3 and understood how to re-pause a message.
You have to dispatch() it, so that it's dispatched a second time,
exactly the sameway. However, you have to know that it's not the first
time you receive it so that you handle it in a different way.
Here is what i began to do :
I think we have to use the startAsync() method of the AsyncListener.
It's made so that you can re-register the same listener to the new
AsyncContext whete startAsync is called a second time on a request.
@Override
public void onStartAsync(AsyncEvent event) throws IOException {
System.out.println("onStartAsync");
// a new startAsync happened (request was dispatched again)
// but request was not resumed (isPending), so we assume it's
// still paused
if (isPending) {
// re-register ourselve so that AsyncResponseImpl's reference
// to this continuation is still valid
event.getAsyncContext().addListener(this);
// copy the old context's timout to the new context
event.getAsyncContext().setTimeout(context.getTimeout());
// now replace old context reference by the new one
context = event.getAsyncContext();
}
}
I think it's necessary to keep the same Continuation object (the same
AsyncListener) so that the AsyncResponseImpl's reference to the
Continuation object stay valid (for the resume / suspend actions ...).
And the onStartAsync is probably the only way to do it.
So, I also modified the constructor of the Servlet3Continuation so
that it just calls startAsync when beeing created (should trigger the
onStartAsync of the old Servlet3Continuation, and thus making it valid
again because it will register itself against the new AsyncContext).
if (isNew) {
// untouched code
} else {
req.startAsync(req, resp);
}
Problems :
- This newly created Servlet3Continuation is now useless (memory
leak.. invalid reference inside of CXF ?)
- I tried this but i get a NPE in the PhaseInterceptorChain, probably
linked to the "State" of the message... I don't know about the details
...
I hope this helps you more than the previous messages.
It does. Believe it or not but I've got my Servlet3 tests working now,
after making the changes (based on your feedback):
http://svn.apache.org/viewvc?rev=1409193&view=rev
It does appear that "req.startAsync()" is really what is needed to get
the same context (debugger shows it is actually the same reference that
is returned) prepared again, the code does "context = req.startAsync();"
just in case, but looks like the same ref is supposed to be returned
anyway, given that req.startAsync() operates on the earlier provided
servlet request/response objects.
Also, setting a listener after 'req.startAsync()' does not seem to make
any difference, timeouts are observed and then re-dispatches occur with
or without this registration, so it looks like registering a listener is
only required during the initial context initialization in the
constructor.
Can you please experiment with this code in Tomcat ? System tests rely
on Jetty Servlet3 async context implementation.
Dan, others, please review the above change and let me know if you have
any concerns
Thanks, Sergey