Multiple Asynchronous context in servlet not working - asynchronous

I'm trying to practice multiple asynchronous request chain in servlets and I'm bumping into a weird behavior. Not sure if it has anything to do with tomcat.
So here's the scenario. I have a simple J2EE maven web application.
I have two servlets and a filter. I have marked all of them with asyncSupported=true. When I click on a link in a JSP, the first servlet does indeed take the request and spawns a new worker thread using AsyncContext. The worker thread then writes something to the response, commits it (as I learned it's legal for asynchronous processing in servlets) and then dispatches the request to another servlet. It works fine till this point.
The second servlet is supposed to spawn a second worker thread and then the plan was to make the second worker thread call dispatch (As I was also trying to practice the parameter-less call to dispatch()) to go back to the Second servlet that called it. However, I get the below error when calling startAsync() on the second servlet
06-Apr-2018 19:04:48.128 WARNING [RMI TCP Connection(5)-127.0.0.1] org.apache.catalina.startup.ContextConfig.validateSecurityRoles Security role name [authSupervisor] used in an <auth-constraint> without being defined in a <security-role>
06-Apr-2018 19:04:48.261 INFO [RMI TCP Connection(5)-127.0.0.1] com.kingshuk.listeners.MyServletContextListener.contextInitialized The servlet class com.kingshuk.servlets.MyAppDynamicServlet is now being registered
06-Apr-2018 19:05:09.025 WARNING [http-nio-8080-exec-8] org.apache.catalina.connector.Request.startAsync Unable to start async because the following classes in the processing chain do not support async []
java.lang.IllegalStateException: A filter or servlet of the current chain does not support asynchronous operations.
at org.apache.catalina.connector.Request.startAsync(Request.java:1636)
at org.apache.catalina.connector.Request.startAsync(Request.java:1628)
at org.apache.catalina.connector.RequestFacade.startAsync(RequestFacade.java:1043)
at javax.servlet.ServletRequestWrapper.startAsync(ServletRequestWrapper.java:378)
at com.kingshuk.servlets.BiggestAsyncSecondServlet.doGet(BiggestAsyncSecondServlet.java:23)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.kingshuk.filters.AsyncRequestLoggingFilter.doFilter(AsyncRequestLoggingFilter.java:25)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:712)
at org.apache.catalina.core.ApplicationDispatcher.doDispatch(ApplicationDispatcher.java:633)
at org.apache.catalina.core.ApplicationDispatcher.dispatch(ApplicationDispatcher.java:601)
at org.apache.catalina.core.AsyncContextImpl$AsyncRunnable.run(AsyncContextImpl.java:566)
at org.apache.catalina.core.AsyncContextImpl.doInternalDispatch(AsyncContextImpl.java:352)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:196)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:651)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:235)
at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:228)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:754)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1376)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Below are all the related files
The Filter
#WebFilter(filterName = "AsyncRequestLoggingFilter",
urlPatterns = {"/asyncServlet", "/biggestAsyncRequestTest", "/biggestAsyncRequestTest2"},
asyncSupported = true,
dispatcherTypes = {DispatcherType.ASYNC, DispatcherType.REQUEST})
public class AsyncRequestLoggingFilter implements Filter {
public void init(FilterConfig config) throws ServletException {
System.out.println("<<AsyncRequestLoggingFilter>> Initializing the Filter");
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws ServletException, IOException {
if (DispatcherType.ASYNC.equals(req.getDispatcherType())) {
System.out.println("<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter during the ASYNC dispatching");
} else {
System.out.println("<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter");
}
chain.doFilter(req, resp);
if (DispatcherType.ASYNC.equals(req.getDispatcherType())) {
System.out.println("<<AsyncRequestLoggingFilter>> This is AFTER returning from the doFilter call after the ASYNC dispatching");
} else {
System.out.println("<<AsyncRequestLoggingFilter>> This is AFTER returning from the doFilter call");
}
}
public void destroy() {
System.out.println("<<AsyncRequestLoggingFilter>> Destroying the Filter");
}
}
The First Servlet
#WebServlet(name = "BiggestAsyncFirstServlet",
urlPatterns = "/biggestAsyncRequestTest",
asyncSupported = true)
public class BiggestAsyncFirstServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync();
asyncContext.setTimeout(10000);
asyncContext.addListener(asyncContext.createListener(BiggestAsyncContextListener.class));
//asyncContext.start(new BiggestAsyncFirstWorkerThread());
/*
Step 5.Get the reference to the thread pool that was created in the context listener class
when the app was deployed
*/
ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");
/*
Step 6.Actually creating the worker thread
and kick starting the thread by calling the run method of the class implementing the runnable interface.
*/
executor.execute(new BiggestAsyncFirstWorkerThread(asyncContext));
System.out.println("Hi I'm the servlet " + getServletName() + " and my job is done");
}
}
The Second servlet
#WebServlet(name = "BiggestAsyncSecondServlet",
urlPatterns = "/biggestAsyncRequestTest2",
asyncSupported = true)
public class BiggestAsyncSecondServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
AsyncContext asyncContext = request.startAsync();
//asyncContext.setTimeout(10000);
//asyncContext.createListener(BiggestAsyncContextListener.class);
//asyncContext.start(new BiggestAsyncFirstWorkerThread());
/*
Step 5.Get the reference to the thread pool that was created in the context listener class
when the app was deployed
*/
ThreadPoolExecutor executor = (ThreadPoolExecutor) request.getServletContext().getAttribute("executor");
/*
Step 6.Actually creating the worker thread
and kick starting the thread by calling the run method of the class implementing the runnable interface.
*/
executor.execute(new BiggestAsyncSecondWorkerThread(asyncContext));
System.out.println("Hi I'm the servlet " + getServletName() + " and my job is done");
}
}
The first worker thread
public class BiggestAsyncFirstWorkerThread implements Runnable {
private AsyncContext context;
public BiggestAsyncFirstWorkerThread(AsyncContext context) {
this.context = context;
}
#Override
public void run() {
//The idea is to write something to the response and then dispatch.
try {
AsyncRequestProcessor.waitingTime(6000);
PrintWriter writer = context.getResponse().getWriter();
writer.print("<html>\n" +
"<head>\n" +
" <title>User login</title>\n" +
"\n" +
" <link rel=\"stylesheet\" type=\"text/css\" href=\"/" +
context.getRequest().getServletContext().getServletContextName() + "/style/master_css.css\">\n" +
"\n" +
"\n" +
"</head>");
writer.print("<body>\n" +
"<div id=\"allcontent\">");
context.getRequest().getRequestDispatcher("pages/common/header.jsp").
include(context.getRequest(), context.getResponse());
writer.print(" <div id=\"actual_content\">");
context.getResponse().flushBuffer();
context.dispatch("/biggestAsyncRequestTest2");
} catch (IOException | ServletException e) {
e.printStackTrace();
}
}
}
The second worker thread
public class BiggestAsyncSecondWorkerThread implements Runnable {
private AsyncContext context;
public BiggestAsyncSecondWorkerThread(AsyncContext context) {
this.context = context;
}
#Override
public void run() {
//The idea is to write something to the response and then dispatch.
try {
AsyncRequestProcessor.waitingTime(6000);
PrintWriter writer = context.getResponse().getWriter();
context.getRequest().getRequestDispatcher("pages/common/cr_leftnav.jsp").
include(context.getRequest(), context.getResponse());
writer.print(" <div id=\"content-body\">\n" +
" <h3>The external app</h3>");
writer.print("<p>This is the page you have been waiting so patiently for. After one round of asynchronous processing" +
"here you are. I love you..!!</p>");
writer.print(" </div>\n" +
" </div>\n" +
"</div>\n" +
"</body>\n" +
"</html>");
context.getResponse().flushBuffer();
//context.complete();
context.dispatch();
} catch (IOException | ServletException e) {
e.printStackTrace();
}
}
}
And finally the initial call from the jsp that triggered this request in the first place
<div id="sidebar">
<ul id="parent_nav">
<li>Checking everything async does</li>
</ul>
</div>
Note: I have an async listener too. But the error seems to have nothing to do with it, so leaving it
Some additional info
Before the error I have mentioned at the top prints, the following lines are printed in the logs, suggesting that it's going wrong on line 23 of the Second Servlet.
<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter
Hi I'm the servlet BiggestAsyncFirstServlet and my job is done
<<AsyncRequestLoggingFilter>> This is AFTER returning from the doFilter call
<<AsyncRequestLoggingFilter>> This is BEFORE calling the doFilter during the ASYNC dispatching
My apologies for such a long question. Any help I can get to understand why it's saying "A filter or servlet of the current chain does not support asynchronous operations." despite all the components being marked with asyncSupported=true, is deeply appreciated.
Thanks,
Kingshuk

Related

Can I write code after RequestDispatcher?

public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//some code here
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//performTask(req, resp);
//some code here
}
private void insertRequestTemplate() {
HttpSession session = req.getSession();
responsePage = req.getParameter("ResponsePage");
ServletContext ctx = getServletConfig().getServletContext();
ctx.getRequestDispatcher(responsePage).forward(req,resp);
readMessage();
public void readMessage()
{
System.out.println("calling MessageTrigger_ABean");
MessageTrigger_ABean msg = new MessageTrigger_ABean();
msg.read();
}
msg.read() has the code to read messages from MQ. Inside insertRequestTemplate method, I am calling readMessage method after ctx.getRequestDispatcher(responsePage).forward(req,resp);is this the correct way of calling this?
But inside insertRequestTemplate method, the page is not getting forwarded to the next page untill readMessage() is executed because of which the page keeps on loading for a long time until message is read from MQ. Could you please help me on this.
Most examples I have seen of a servlet forwarding the request to another servlet have the dispatcher forward invocation at the end of the method. ie. there is no more code, other than closing braces at the end of the method.
I am guessing that the forwarding doesn't happen until the invoking method completes. So where you have your msg.read() will stop the insertRequestTemplate method from completing. This will more than likely be because the code inside msg.read is being performed synchronously. Leading to http timeouts on the http request.
How you solve this will depend on what you want to do with the messages you obtain from msg.read().

Error on Part.getSubmittedFileName

I am uploading a file, and I use javax.servlet.http.Part in the Servlet. It seems to behave strangely, since part.getSubmittedFileName() is returning an error (it seems a POST http://localhost:8080/.... 500 (Internal Server Error) ) so I have to use the old JEE 6 method to obtain the name. What could be happening? I tried to capture the error with a try-catch but when the sentence is executed, it just leaves the Servlet method entirely without entering into the catch block.
#MultipartConfig
#WebServlet(name = "UploadServlet", urlPatterns = {"/uploadServlet"})
public class UploadServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Part partFile = request.getPart("file");
....
try {
System.out.println("submName " + partFile.getSubmittedFileName()); // never prints
String fileName = partFile.getSubmittedFileName();
} catch (Exception e) {
System.out.println("EX: " + e); // never executes
}
....
}
}

Stop servlet forcefully

What should be done to manually stop Servlet as calling destroy doesn't help unless all threads exited from service.
Say, If I have n number of Servlets and I want to stop only one of them.
That behavior is very important when dealing with Servlets. Instances can be created after the multi-thread model and are thus not thread-safe.
The container does not allow a thread to invoke the service method after destroy has been called.
This gives you the means to close all resources that your Servlet is using (db, file, memory, etc).
#WebServlet
public class OncePerApplicationServlet extends HttpServlet {
private Connection connection;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if(req.getParameter("closeServlet").equals("true"))
this.destroy();
else
this.service(req, resp); // normal flow
}
// this method will never be called by the container after the destroy method has been invoked
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1.
try {
connection = DriverManager.getConnection("someDbUrl");
Statement stm = connection.createStatement();
stm.execute("select * from someTable");
} catch (SQLException e) {
e.printStackTrace();
}
}
#Override
public void destroy() {
// the point is that when this method is called you should be able to
// clean up and close all resources, you can rest assured that there are no "loose"
// threads that need the connection-instance
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
Here is a quote from the API-docs:
This interface defines methods to initialize a servlet, to service
requests, and to remove a servlet from the server. These are known as
life-cycle methods and are called in the following sequence:
The servlet is constructed, then initialized with the init method. Any
calls from clients to the service method are handled. The servlet is
taken out of service, then destroyed with the destroy method, then
garbage collected and finalized.
|
Link to the documentation
Good luck!

Async Servlet - preferred implementation

Lately, during my research about asynchronous processing in Servlets, I came across at at least three ways to implement
some functionality using this approach.
The questions are:
Which one is the best?
Maybe some of these approaches are not recommended?
Maybe there is another one approach better than all of mentioned below?
Found approaches:
Using AsyncContext.start(Runnable).
This approach is quite simple and straightforward. But many serwers executes such a job in thread pool created for HTTP requests
(more about it here http://www.nurkiewicz.com/2012/05/javaxservletservletrequeststartasync.html)
Using custom threads pool created during Servlet context initialization
(sample here: http://www.journaldev.com/2008/async-servlet-feature-of-servlet-3).
But can I create my own threads in Servlet container? It was not recommended (or even prohibited) in EJB (before JavaEE7).
Can I use JavaSE Executors or should I use ManagedExecutors from JavaEE7 (assuming that I use JavaEE7)?
Using EJB and #Asynchronious annotation
(example here: https://github.com/wildfly/quickstart/tree/master/servlet-async/src/main/java/org/jboss/as/quickstarts/servlet/async).
But here I have no control over threads executing my task (i.e. how many thread should by created etc.)
I would by glad to hear your thoughts on this issue and your experience with AsyncContext.
All will have the same performance, at the backend all threads are replacing the request processing thread to another thread, so that more requests can be served.
Below you'll find a simple implementation:
#WebServlet(urlPatterns = "/AsyncLongRunningServlet", asyncSupported = true)
public class AsyncLongRunningServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("Request Processing Thread "+Thread.currentThread().getName());
request.setAttribute("org.apache.catalina.ASYNC_SUPPORTED", true);
response.setContentType("text/html");
PrintWriter printWriter=response.getWriter();
printWriter.println("<html><head><title>Asynchronous servlet</title></head><body>");
printWriter.println("Request Processing Thread "+Thread.currentThread().getName());
printWriter.println("<br>");
printWriter.println("<progress id='progress' max='100')></progress>");
printWriter.println("<br>");
AsyncContext asyncCtx = request.startAsync();
asyncCtx.addListener(new AppAsyncListener());
asyncCtx.setTimeout(12000);
//release of request processing thread
asyncCtx.start(() ->{
printWriter.println("<br>");
printWriter.println("Async thread Name "+Thread.currentThread().getName());
printWriter.println("<br>");
int i=0;
while(i<100)
{
printWriter.println("<script>document.getElementById('progress').value=\""+i+"\";</script>");
printWriter.flush();
try {
Thread.sleep(100);
} catch (Exception e) {
}
i++;
}
printWriter.println("</body></html>");
asyncCtx.complete();
}
);
printWriter.println("<br>");
printWriter.println("End of response");
}
}
package com.journaldev.servlet.async;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebListener;
#WebListener
public class AppAsyncListener implements AsyncListener {
#Override
public void onComplete(AsyncEvent asyncEvent) throws IOException {
System.out.println("AppAsyncListener onComplete");
// we can do resource cleanup activity here
}
#Override
public void onError(AsyncEvent asyncEvent) throws IOException {
System.out.println("AppAsyncListener onError");
//we can return error response to client
}
#Override
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
System.out.println("AppAsyncListener onStartAsync");
//we can log the event here
}
#Override
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
System.out.println("AppAsyncListener onTimeout");
//we can send appropriate response to client
ServletResponse response = asyncEvent.getAsyncContext().getResponse();
PrintWriter out = response.getWriter();
out.write("TimeOut Error in Processing");
}
}

Lifecycle/Scope of #WebServlet [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do servlets work? Instantiation, session variables and multithreading
I have a weird (but probably expected) behaviour in my WebServlet. Environment is:
- Apache 2.2.x
- Glassfish 3.1.1 + mod_jk
- JSF Mojarra 2.1.3
I have an abstract servlet that implements some code to check in the FacesContext/Session if there is a specific #SessionScoped managed bean and if so, whether the user is signed-in. If user is signed-in, then proceeds to the file delivery. The implementing #WebServlet only provides the actual file download.
Abstract Servlet:
public abstract class SecureDownloadServlet extends HttpServlet {
#EJB
private UserProductBean userProductBean;
private UserInfoView userInfoView = null;
private UserInfoView getUserInfoView(HttpServletRequest req) {
FacesContext context = FacesContext.getCurrentInstance();
if (context != null) {
userInfoView = (UserInfoView) context.getApplication()
.getELResolver().getValue(FacesContext.
getCurrentInstance().getELContext(), null, "userInfoView");
}
if (userInfoView == null) {
userInfoView = (UserInfoView) getServletContext().
getAttribute("userInfoView");
}
if (userInfoView == null) {
userInfoView = (UserInfoView) req.getSession().
getAttribute("userInfoView");
}
return userInfoView;
}
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
if (getUserInfoView(req) == null || !getUserInfoView(req).getLoggedIn()) {
response.sendRedirect("message.xhtml?msg=noLogin");
return;
}
doDownload(req, response);
}
public abstract void doDownload(HttpServletRequest req,
HttpServletResponse response)
throws IOException, ServletException;
}
Then I have a #WebServlet that extends the above abstract HttpServlet and implements the abstract method:
#WebServlet(name = "SecureImageServlet", urlPatterns = {"/print","/m/print"})
public class SecureImageServlet extends SecureDownloadServlet {
#Override
public void doDownload(HttpServletRequest req, HttpServletResponse response)
throws IOException, ServletException {
// some code
}
}
Now here is the issue:
- From computer A, sign in, then call the SecureImageServlet servlet to get a file (i.e. http://www.example.com/print?id=12345). The userInfoView session bean is initialized as expected, and the file is delivered.
- From computer B, without being signed-in, call http://www.example.com/print?id=12345. The userInfoView is already initialized with the session of user on computer A!!! And the file is delivered too.
It looks like the WebServlet becomes ApplicationScope or something like that. Is it the #EJB injection that does that?
Note the the instance of userInfoView is the same (the object id in the debugger shows the same number) which means somehow the computer B is seen as the same user as computer A
Edited format
Ok, a friend of mine (without an account on SO :) ) pointed out my mistake:
I am using userInfoView as a class member instead of keeping it within the request scope. I fixed it by removing the class member and voila!

Resources