Wednesday, August 3, 2011

Java Web Apps - Integrating Charts into a Servlet

Adding a chart to a Java web application is really easy to do - thanks to the open source Java charting API XChart. XChart's charting library lets you very easily make charts an integrate them into all your Java-based applications. In this blog post, I am going to demonstrate how to add charts to a Java web application. If you want to integrate XChart charts in your Java applications, download the JAR here. You can also see more XChart exmaples here.

The Basic Idea

The basic idea for adding XChart charts to a web app is as follows. First, you have a JSP or HTML page with a link on it that will request a new page with a chart. The new JSP or HTML page that is generated has an img tag in it with a reference to an in-memory chart stored in a HashMap in a Servlet that maps the reference and the chart. When the page reloads, the browser parses the img tag and subsequently requests the image from the Servlet. The Servlet then streams the chart to the browser and it is rendered on the page.

An Example

If the basic idea explanation above did not make complete sense, the following example should make it clear.

Step 1: ChartServlet. This Servlet does one of two things in the doGet() method, depending on the request. If it receives and 'action', it generates a chart. Here you could pass in different 'action' parameters to create different charts if you want. If it receives a 'chart_id', it pulls the chart from CHART_MAP and streams it out to the browser.
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xeiam.xcharts.BitmapEncoder;
import com.xeiam.xcharts.Chart;
import com.xeiam.xcharts.QuickChart;

@javax.servlet.annotation.WebServlet(name = "ChartServlet", urlPatterns = { "/chart" })
public class ChartServlet extends HttpServlet {

    private static Map<String, Chart> CHART_MAP = new HashMap<String, Chart>();

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        // generate the Chart
        String action = request.getParameter("action");
        if (action != null && !action.equals("null")) {
            String chartId = generateRandomChart();
            request.setAttribute("chart_id", chartId);
            request.getRequestDispatcher("/chart.jsp").forward(request, response);
        }

        // Fetch the Chart
        String chartId = request.getParameter("chart_id");
        if (chartId != null && !chartId.equals("null")) {

            Chart chart = CHART_MAP.get(chartId);
            if (chart != null) {
                response.setContentType("image/png");
                ServletOutputStream out = response.getOutputStream();
                try {
                    BitmapEncoder.streamPNG(out, chart);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                out.close();
                chart = null;
                CHART_MAP.remove(chartId);
            } else {
                System.err.println("CHART NOT FOUND!!!");
            }
        }
    }

    // generate the chart
    public static String generateRandomChart() {
        Chart chart = QuickChart.getChart("XChart Sample - Random Walk", "X", "Y", null, null, getRandomWalk(105));
        String uuid = UUID.randomUUID().toString();
        CHART_MAP.put(uuid, chart);
        return uuid;
    }

    // generate random walk data set
    private static double[] getRandomWalk(int numPoints) {
        double[] y = new double[numPoints];
        y[0] = 0;
        for (int i = 1; i < y.length; i++) {
            y[i] = y[i - 1] + Math.random() - .5;
        }
        return y;
    }
}

Step 2: Chart JSP. To request and display the Chart, the JSP contains two DIVs - one for a link to request the chart and one for a IMG tag to display the Chart image. I named this JSP chart.jsp.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
 <head>
     <meta http-equiv="content-type" content="text/html;charset=utf-8" />
     <% String chartId = (String) request.getAttribute("chart_id");%>
 </head>
    <body>
     <div>
      <a href="<%=request.getContextPath()%>/chart?action=whatever">Generate Chart</a>
     </div>
     <%if(chartId != null){ %>
     <div>
      <img src="<%=request.getContextPath()%>/chart?chart_id=<%=chartId %>"/> 
     </div>
  <%} %>
    </body>
</html>

Step 3: Test it. Now deploy your webapp with the new Servlet and JSP and in your browser go to: http://localhost/YourWebAppContext/chart.jsp

After clicking on 'Generate Chart' your chart will appear on the web page. Each time you click it, a new chart will show up.

Piece of Cake!!!

See also: Java XChart Library Now Supports Error Bars

No comments: