ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

JSP Progress Bars
Pages: 1, 2

Showing the Task Status



The status.jsp page uses an HTML-based progress bar to inform the user about the status of the task. The <jsp:useBean> tag gets the bean object created by start.jsp:

<jsp:useBean id="task" scope="session"
    class="com.devsphere.articles.progressbar.TaskBean"/>

The status.jsp page is refreshed automatically from time to time in order to reflect the status changes. The setTimeout("location='status.jsp'", 1000) JavaScript code changes the browser's location after 1000 milliseconds. The browser will request the status.jsp page without any user intervention.

<html>

<head>
    <title>JSP Progress Bar</title>
    <% if (task.isRunning()) { %>
        <SCRIPT LANGUAGE="JavaScript">
            setTimeout("location='status.jsp'", 1000);
        </SCRIPT>
    <% } %>
</head>

<body>

The progress bar is built as an HTML table with 10 cells. Each cell represents 10% of the time that is necessary to execute the task.

<h1 align="center">JSP Progress Bar</h1>

<h2 align="center">
    Result: <%= task.getResult() %><br />
    <% int percent = task.getPercent(); %>
    <%= percent %>%
</h2>

<table width="60%" align="center"
        border="1" cellpadding="0" cellspacing="2">
    <TR>
        <% for (int i = 10; i <= percent; i += 10) { %>
            <td width="10%" bgcolor="#000080">&nbsp;</td>
        <% } %>
        <% for (int i = 100; i > percent; i -= 10) { %>
            <td width="10%">&nbsp;</TD>
        <% } %>
    </tr>
</table>

The task may be in one of the following states: "Running," "Completed," "Not Started," and "Stopped."

<table width="100%" border="0" cellpadding="0" cellspacing="0">
    <tr>
        <td align="center">
            <% if (task.isRunning()) { %>
                Running
            <% } else { %>
                <% if (task.isCompleted()) { %>
                    Completed
                <% } else if (!task.isStarted()) { %>
                    Not Started
                <% } else { %>
                    Stopped
                <% } %>
            <% } %>
        </td>
    </tr>

At the end of the page, there is a button that lets the user stop or restart the task:

    <tr>
        <td align="center">
            <br />
            <% if (task.isRunning()) { %>
                <form method="get" action="stop.jsp">
                    <input type="submit" value="Stop">
                </form>
            <% } else { %>
                <form method="get" action="start.jsp">
                    <input type="submit" value="Start">
                </form>
            <% } %>
        </td>
    </tr>
</table>

</body>
</html>

If you don't stop the task, you'll see the 5050 result in about 10 seconds:

Completed Task
Figure 2. The completed task

Stopping the Task

The stop.jsp page stops the execution of the task by setting the running flag to false:

<jsp:useBean id="task" scope="session"
    class="com.devsphere.articles.progressbar.TaskBean"/>

<% task.setRunning(false); %>

<jsp:forward page="status.jsp"/>

Note that it is not okay to call the Thread.stop() method, which was provided by the first Java version but was deprecated by JDK 1.2. The task should get the chance to stop itself by returning from the run() method when it is appropriate. Otherwise, the TaskBean object might remain in an invalid state.

Stopped Task
Figure 3. A stopped task

When you execute the application the first time, you'll notice some delay when the task is started. Also, when you click the "Stop" button for the first time, the task won't be stopped immediately. The JSP page compilation causes these delays. Once the JSP pages are compiled, the application will respond very quickly to the user requests (assuming that the server isn't overloaded and the network is working properly).

Progress Bars in Real Applications

A progress bar makes the user interface friendlier and may have a good effect on the server performance, because users won't cancel and restart an operation that tells them to be patient and shows them the progress. However, the threads created to execute the tasks consume system resources. You should consider using a thread pool that allows you to reuse the Thread objects. Refreshing the status page from time to time also increases the network traffic. Keep that page small and simple.

In many real-world cases, the heavy task cannot be stopped or its progress cannot be tracked. For example, when accessing or updating a relational database, you cannot stop an SQL statement in the middle of its execution. However, if the user has signaled that she wants to stop or to cancel the task, you could roll back the database transaction after the SQL statement is executed.

When you parse an XML document, there's no way to show the exact percentage of the parsed content. If you use DOM, you get the whole document tree after the parsing is completed. If you use SAX, you know what was parsed, but you usually don't know much about the remaining content that has to be parsed. In such a case, you can only try to estimate the progress of the heavy task.

Estimating the time necessary to execute a heavy task can be difficult, because it depends on the available CPU resources. You can't just do a few tests in the production environment because the server load changes in time. A simple solution is to measure the execution time of the heavy task every time it is invoked, and then use the average time of the last few executions as an estimate. For more accurate estimate, you should think of an algorithm that takes into account variables specific to your application, such as the type of the SQL statement that is executed, or the complexity of the parsed document's XML schema.

Summary

The web application of this article has shown you how easy is to implement a progress bar based on JSP, Java, HTML, and JavaScript. The hard part is to integrate it within existing real applications, taking into account the issues described above. There is no general integration solution. Each real heavy task needs to be analyzed separately.

Resources

Andrei Cioroianu is the founder of Devsphere and an author of many Java articles published by ONJava, JavaWorld, and Java Developer's Journal.


Return to ONJava.com.