You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@cxf.apache.org by "Wei Zhang (JIRA)" <ji...@apache.org> on 2015/05/07 05:02:59 UTC

[jira] [Created] (CXF-6395) Call setTimeout() in a second request cause illegalStateException from web container.

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)