Sunday, October 13, 2013

A simple way to display a long-waiting servlet

I came across a situation that I needed to write a servlet which ran some SQL statements, got some data from web services, compiled all the data in a XML files, and transferred files from one place to another, and finally update the status and others back to database.  All actions had to be done in one-pass, and it was invoked by end-user through a web page.

It's a pretty typical scenario that one needs to have a servlet running and show the messages like "please wait", "do not interrupt", "transaction in process", etc.  How to do it ? The trick is that the servlet itself does not show that message, it's the DIV layer in the parent page.

(1) Create a page in JSP, servlet, or html which contains a DIV with known ID (loader) and has an animated gif (/images/ajax-loader.gif) in it. You can generate one of this image from this link or this link.

(2) Write your long-running servlet (LongServlet), and register it in the web xml. This servlet writes a Javascript block at the end that will hide the DIV block in the parent page.

(3) Put the servlet as a iFrame in the html created in (1).
So, when the parent page is landed, it shows the DIV layer with the animated gif and message which says something is running. The iframe, which is indeed the servlet, keep running for a while but it is not visible until it is done. When the servlet process stops, the Javascript will hide the parent DIV layer and content of the servlet will be shown. You can put a link in the servlet likes
<a href="#" onclick="top.window.location.href='yourURL';">Click here to proceed</a>
and it will allow user to quit the page after the process has finished.

Example code for long-running servlet
public class LongServlet extends HttpServlet {
  public void init(ServletConfig config) throws ServletException {
    super.init(config);
    ....
  }
  public void doGet(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException, IOException {

     PrintWriter out = response.getWriter();
     response.setContentType("text/html; charset=UTF-8");
     response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
     response.setHeader("Pragma","no-cache"); //HTTP 1.0
     response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
     out.println("<html><head/><body bgcolor='Azure' text='LightSlateGray'>");
     out.println("Start running process...<br/>");
     .... 
     out.println("Process done.");
     out.println("<script type='text/javascript'>" +
               "window.parent.document.getElementById('loader').style.visibility='hidden';" +
                  "</script>");
     out.println("</body></html>"); 
  }
}

Example html page which hold the servlet as iframe
<html>
<head>
  <title>Fetch Summary</title>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <meta http-equiv="Pragma" content="no-cache" /><meta http-equiv="Expires" content="-1" /><meta http-equiv="Cache-Control" content="no-cache" />
  <style type="text/css">
  #loader { background:url(/images/ajax-loader.gif) no-repeat center center; height:66px; width:66px; top: 300px; left: 200px;}
  #header { font-size:14px;color:brown;font-weight:bold;}
  </style>
</html>
<body>
<div id="loader"></div>
<div id="header">Running something long and big, please wait...</div>
<iframe src="/servlets/LongServlet" height="600" width="500" scrolling="yes" frameborder="1"></iframe>
</body>
</html>

1 comment :

Anonymous said...

You solved my problem! thank you so much! very good and easy solution!