FileDocCategorySizeDatePackage
ShowViewStateServlet.javaAPI DocExample5994Tue Jun 08 11:26:42 BST 2004com.mycompany.jsf.servlets

ShowViewStateServlet.java

package com.mycompany.jsf.servlets;

import com.mycompany.jsf.model.TreeNode;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLEncoder;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

/**
 * This class is a servlet that produces a response showing the
 * state captured by the CaptureStatePhaseListener, as a tree
 * with links for opening and closing nodes.
 *
 * @author Hans Bergsten, Gefion Software <hans@gefionsoftware.com>
 * @version 1.0
 */
public class ShowViewStateServlet extends HttpServlet {

    /**
     * If invoked without a "viewId" parameter, renders a response
     * with links back to itself for all views available in the
     * session scope variable "com.mycompany.debug". Otherwise,
     * toggles the "expanded" flag for the node identified by the
     * "nodeId" parameter (if any) and renders the view state
     * tree by calling renderDocument().
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
	throws IOException {

	response.setContentType("text/html");
	PrintWriter out = response.getWriter();

	HttpSession session = request.getSession();
	Map debugMap = 	(Map) session.getAttribute("com.mycompany.debug");
	if (debugMap == null) {
	    response.sendError(HttpServletResponse.SC_BAD_REQUEST,
			       "No state available");
	    return;
	}
	
	String uri = request.getContextPath() + request.getServletPath();
	String viewId = request.getParameter("viewId");
	if (viewId == null) {
	    renderLinks(debugMap, out, uri);
	}
	else {
	    TreeNode root = (TreeNode) debugMap.get(viewId);
	    if (root == null) {
		response.sendError(HttpServletResponse.SC_BAD_REQUEST,
				   "No state for viewId parameter");
		return;
	    }

	    String path = request.getParameter("nodePath");
	    if (path != null) {
		toggleExpanded(path, root);
	    }

	    renderDocument(root, out, viewId, uri);
	}
    }

    /**
     * Renders a response with links for all views in the Map.
     */
    private void renderLinks(Map debugMap, PrintWriter out, String uri) {
	out.println("<html>");
	out.println("  <head>");
	out.println("    <title>Debug info for views</title>");
	out.println("  </head>");
	out.println("  <body bgcolor=\"white\">");
	out.println("    Info for the following views is available:");
	out.println("    <ul>");

	Iterator i = debugMap.keySet().iterator();
	while (i.hasNext()) {
	    String viewId = (String) i.next();
	    out.println(indent(3) + "<li><a href=\"" + uri + 
			"?viewId=" + URLEncoder.encode(viewId) + 
			"\">" + viewId + "</a></li>");
	}
	
	out.println("  </body>");
	out.println("</html>");
    }

    /**
     * Locates the node with the specified path in the tree and
     * flips its "expanded" flag.
     */
    private void toggleExpanded(String path, TreeNode root) {
	List kids = root.getChildren();
	boolean foundElement = false;
	TreeNode matchingNode = null;

	StringTokenizer st = new StringTokenizer(path, "/");
	// Throw away the root token
	st.nextToken();
	while (st.hasMoreTokens()) {
	    String t = st.nextToken();
	    for (int i = 0; i < kids.size(); i++) {
		TreeNode kid = (TreeNode) kids.get(i);
		if (t.equals(kid.getName())) {
		    matchingNode = kid;
		    kids = kid.getChildren();
		    foundElement = true;
		    break;
		}
	    }
	    if (!foundElement) {
		break;
	    }
	}
	if (matchingNode != null) {
	    boolean isExpanded = matchingNode.isExpanded();
	    matchingNode.setExpanded(!isExpanded);
	}
    }

    /**
     * Renders the "html", "head" and "body" elements and calls
     * the renderTreeNode() method to render the tree.
     */
    private void renderDocument(TreeNode root, PrintWriter out,
				String viewId, String uri) {
	out.println("<html>");
	out.println("  <head>");
	out.println("    <title>Info for view '" + viewId + "'</title>");
	out.println("  </head>");
	out.println("  <body bgcolor=\"white\">");
	renderTreeNode(root, out, viewId, uri, 2, "0", 0);
	out.println("  </body>");
	out.println("</html>");
    }

    /**
     * Renders the node, as "name=value" if it's a leaf node or as a
     * link for expanding or collapsing the node otherwise. If the
     * node is expanded, calls itself recursively for all node
     * children, rendering the children within a "blockquote" element.
     */
    private void renderTreeNode(TreeNode node, PrintWriter out, 
				String viewId, String uri, int level,
				String parentNodeId, int childId) {
	if (node.isLeafNode()) {
	    out.println(indent(level) + node.getName() + " = " +
			node.getValue() + "<br>");
	}
	else {
	    String nodeId = parentNodeId + ":" + childId;
	    out.println(indent(level) + "<a id=\"" + nodeId + 
			"\" href=\"" + uri + 
			"?viewId=" + URLEncoder.encode(viewId) + 
			"&nodePath=" + 
			URLEncoder.encode(node.getPath()) +
			"&expand=" + (!node.isExpanded()) +
			"#" + nodeId +
			"\">" + (node.isExpanded() ? "-" : "+") +
			"</a> " + node.getName() + "<br>");
	    if (node.isExpanded()) {
		out.println(indent(level + 1) + "<blockquote>");
		int kidId = 0;
		Iterator i = node.getChildren().iterator();
		while (i.hasNext()) {
		    TreeNode kid = (TreeNode) i.next();
		    renderTreeNode(kid, out, viewId, uri, level + 2, nodeId,
				   kidId++);
		}
		out.println(indent(level + 1) + "</blockquote>");
	    }
	}
    }

    /**
     * Returns a blank String of the appropriate length for the indention
     * level.
     */
    private String indent(int level) {
	StringBuffer sb = new StringBuffer();
	for (int i = 0; i < level; i++) {
	    sb.append("  ");
	}
	return sb.toString();
    }
}