How to create multiple asynchronous java filters?
asynchronous, filter, java, servlet-filters, servlets
Solution
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;
}
}
Problem
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!