Wei Zhang created CXF-6395:
------------------------------

             Summary: Call setTimeout() in a second request cause 
illegalStateException from web container.
                 Key: CXF-6395
                 URL: https://issues.apache.org/jira/browse/CXF-6395
             Project: CXF
          Issue Type: Bug
          Components: JAX-RS
            Reporter: Wei Zhang


Come from a TCK test case:
Resource class has two methods:
static AsyncResponse asyncResponse;
    @GET
    @Path("/suspend")
    public void getSuspendResponse(@Suspended AsyncResponse async) {
        asyncResponse = async;
    }

    @GET
    @Path("/setTimeOut")
    public String setTimeOut() {
        boolean setTimeout = asyncResponse.setTimeout(10, TimeUnit.SECONDS);
        return String.valueOf(setTimeout)
    }

The first request invokes method getSuspendResponse(), the AsyncResponse is in 
suspend status. The second request invokes method setTimeOut() to invoke 
setTimeOut() method of the suspend AsyncRespone. AsyncResponseImp.setTimeout() 
-> cont.suspend(timeout)(Servlet3ContinuationProvider$Servlet3Continuation) -> 
context.setTimeout(timeout);
The the impl class of AsyncContext throw a illegalStateException: called 
setTimeout after the container-initiated dispatch which called startAsync has 
returned.
According to the javadoc of AsyncContext class, seemed the behavior of 
AsyncContext is correct. We tried to challenge this test case, but was rejected.

Checked restesay code, found they thought the invocation is illegal, but they 
provide a work around:

    protected WeakReference<Thread> creatingThread = new 
WeakReference<Thread>(Thread.currentThread());
    protected ScheduledFuture timeoutFuture; // this is to get around TCK tests 
that call setTimeout in a separate thread which is illegal.
    protected ScheduledExecutorService asyncScheduler;

public synchronized boolean setTimeout(long time, TimeUnit unit) throws 
IllegalStateException {
......
        Thread thread = creatingThread.get();
        if (thread != null && thread != Thread.currentThread()) {
            // this is to get around TCK tests that call setTimeout in a 
separate thread which is illegal.
            if (timeoutFuture != null && !timeoutFuture.cancel(false)) {
                return false;
            }
            Runnable task = new Runnable() {
                @Override
                public void run()
                {
                    handleTimeout();
                }
            };
            timeoutFuture = asyncScheduler.schedule(task, time, unit);
            return true;
        } else {
        ......
        }
}

Check if current thread is the creating thread of AsyncResponseImpl object, if 
not, means setTimeout() method is called in a second request, then handle the 
timeout with a ScheduledExecutorService instead of AsyncContext to avoid the 
illegalState exception. 

I tried to add above code to setTimeout() method. It's ok when setTimeout() was 
called, and handleTimeout() method was called also when timeout. But client 
can't get a response which said timeout until connection timeout.




--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to