Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create multiple asynchronous java filters?

I'm trying to create a Java application with multiple asynchronous filters, but cannot seem to get them to work well together. I think the main issue is in the run() method I don't know what to do to pass along the request to the next filter in the chain. I've tried chain.doFilter(request, response), but that doesn't seem to work, and there are dispatch() and complete() APIs available on the AsyncContext, but those seem to close out the entire AsyncContext. It seems like there must be another way to get this to work. Below is a snippet of the filter I'm using - the second filter looks almost identical.

Note: I'm adding headers to try and figure out what is getting called.

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException {
        final AsyncContext asyncContext = request.startAsync();
        final HttpServletResponse res = (HttpServletResponse) response;
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {
                res.addHeader("S-AST2", "onComplete");
            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {
                res.addHeader("S-AST3", "onTimeout");
            }

            @Override
            public void onError(AsyncEvent event) throws IOException {
                res.addHeader("S-AST4", "onError");
            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {
                res.addHeader("S-AST0", "onStartAsync");
            }
        });

        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                res.addHeader("S-AST1", "before");
                // This doesn't seem to work...
                asyncContext.dispatch();
                // ... or this ...
                asyncContext.complete();
                // ... or this ...
                chain.doFilter(request, response);
            }
        });
    }

Thanks for any insight!

like image 345
mnd Avatar asked Jul 14 '14 21:07

mnd


People also ask

How do you create asynchronous thread in Java?

We can use the submit method of the ExecutorService to perform the task asynchronously and return the instance of the FutureTask. So let's find the factorial of a number: ExecutorService threadpool = Executors. newCachedThreadPool(); Future<Long> futureTask = threadpool.

What is doFilter () method in Java?

The doFilter method of the Filter is called by the container each time a request/response pair is passed through the chain due to a client request for a resource at the end of the chain. The FilterChain passed in to this method allows the Filter to pass on the request and response to the next entity in the chain.

Is there async await in Java?

There isn't anything native to java that lets you do this like async/await keywords, but what you can do if you really want to is use a CountDownLatch.


1 Answers

There are two parts to this answer.

1) The chain.doFilter(request, response); is still required.

2) The reason this was not working is that in each filter and in the servlet I was calling request.startAsync(), which started a new async process, rather than using an existing one. So if the filter started an async process, and the servlet also started one, it would overwrite/ignore the one started in the filter. To solve this you must check to see if an async process is already started, by calling request.isAsyncStarted(), and if it is, rather than starting a new async context, you should get the existing one with request.getAsyncContext(). Below is a helper class I created to do this for each servlet and filter, so that I can just call AsyncHelper.getAsyncContext(request, response) and it will either retrieve the existing AsyncContext, or create a new one.

public class AsyncHelper {
    public static AsyncContext getAsyncContext(ServletRequest request, ServletResponse response) {
        AsyncContext asyncContext = null;
        if (request.isAsyncStarted()) {
            asyncContext = request.getAsyncContext();
        }
        else {
            asyncContext = request.startAsync(request, response);
            asyncContext.setTimeout(2000);
        }
        return asyncContext;
    }
}
like image 51
mnd Avatar answered Sep 28 '22 16:09

mnd