Skip to main content

Can't get "asyncSupported" to work

No replies
savvas
Offline
Joined: 2010-02-14
Points: 0

H​ello,

I am experimenting with the servlet async support in Java EE7 and Glassfish 4.0 and just can't seem to get this to work.

So far, I've done the following:

I have created an AsyncReaderServlet class with the following definition:

@WebServlet(urlPatterns = {"/async-reader-servlet"}, asyncSupported = true)
public class AsyncReaderServlet extends HttpServlet {

/**
* Processes requests for both HTTP
* GET and
* POST methods.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
out.println("");
out.println("");
out.println("");
out.println("Servlet AsyncReaderServlet");
out.println("");
out.println("");
out.println("

Servlet AsyncReaderServlet at " + request.getContextPath() + "

");
out.println("

Look at the server log to see data that was read asynchronously from a file

");

AsyncContext asyncContext = request.startAsync();
ServletInputStream servletInputStream = request.getInputStream();

servletInputStream.setReadListener(new AsyncReadListener(servletInputStream, asyncContext, request.getServletContext()));

out.println("

");
out.println("");
} catch (Exception ex) {
ex.printStackTrace();
}
}

/**
* Handles the HTTP
* GET method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Handles the HTTP
* POST method.
*
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
processRequest(request, response);
}

/**
* Returns a short description of the servlet.
*
* @return a String containing servlet description
*/
@Override
public String getServletInfo() {
return "Short description";
}

with the AsyncReadListener class being the following:

public class AsyncReadListener implements ReadListener {

private ServletInputStream servletInputStream;
private AsyncContext asyncContext;
private ServletContext servletContext;

public AsyncReadListener(ServletInputStream servletInputStream, AsyncContext asyncContext,
ServletContext servletContext) {
this.servletInputStream = servletInputStream;
this.asyncContext = asyncContext;
this.servletContext = servletContext;
}

@Override
public void onDataAvailable() throws IOException {
servletContext.log("OnDataAvailable()");
try {
int length = -1;
byte[] buffer = new byte[1024];
while (servletInputStream.isReady() && (length = servletInputStream.read(buffer)) != -1) {
String readContent = new String(buffer, 0, length);
servletContext.log(readContent);
}
} catch (IOException ioex) {
ioex.printStackTrace();
}
}

@Override
public void onAllDataRead() throws IOException {
servletContext.log("All data read...");
asyncContext.complete();
}

@Override
public void onError(Throwable t) {
t.printStackTrace();
asyncContext.complete();
}
}

The client initiating the request in this experimental setup is the following:

public class AsyncReaderDriver {

public static void main(String[] args) {
try {
Path path = Paths.get("/home/savvas/tmp/demo-file");
BufferedReader fileReader = new BufferedReader(new FileReader(path.toFile()));

URL url = new URL("http://localhost:8080/JavaEE7/async-reader-servlet");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setChunkedStreamingMode(1024);
conn.setDoOutput(true);

conn.connect();

String line = "";
try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()))) {

while ((line = fileReader.readLine()) != null) {
writer.write(line);
System.out.println("read line:" + line);
writer.flush();
}
}

} catch (Exception ex) {
ex.printStackTrace();
}
}
}

which simply reads a text file and makes an HTTP request to the above servlet.

Now, every time I run the above main method I get the following exception in my NetBeans console:
SEVERE: java.lang.IllegalStateException: Request is within the scope of a filter or servlet that does not support asynchronous operations
at org.apache.catalina.connector.Request.startAsync(Request.java:4259)
at org.apache.catalina.connector.Request.startAsync(Request.java:4221)
at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:1031)
..........................................................................................................................................................................................................................................................​

............................................................................................................................................................................................
............................................................................................................................................................................................

T​he interesting detail is that if I comment out the following bit as in:
// conn.setChunkedStreamingMode(1024);​

I am no longer getting the above exception but the listener doesn't get called either since nothing gets written to the console​
so I'm assuming the client needs to be setting the correct ​​​h​eaders along with the request which would make perfect sense!

Does anyone know what those headers should be or if I'm doing something completely wrong?

I have already tried the solution of declaring my servlet in web.xml with the correct element set to true but that didn't have any effect.

Any ideas, much appreciated.

Cheers,
Savvas