org.ajax4jsf.application.DebugOutputMaker.java Source code

Java tutorial

Introduction

Here is the source code for org.ajax4jsf.application.DebugOutputMaker.java

Source

/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.ajax4jsf.application;

import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.el.MethodBinding;
import javax.faces.el.ValueBinding;
import javax.faces.event.PhaseId;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.ajax4jsf.Messages;
import org.ajax4jsf.resource.InternetResource;
import org.ajax4jsf.resource.InternetResourceBuilder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;

/**
 * @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
 * @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:57:11 $
 *
 */
public class DebugOutputMaker {
    private final static String LT = "<";
    private final static String GT = ">";
    // Attributes that should not be printed
    static public final HashSet IGNORE_ATTRIBUTES;

    static {
        IGNORE_ATTRIBUTES = new HashSet();
        IGNORE_ATTRIBUTES.add("attributes");
        IGNORE_ATTRIBUTES.add("children");
        IGNORE_ATTRIBUTES.add("childCount");
        IGNORE_ATTRIBUTES.add("class");
        IGNORE_ATTRIBUTES.add("facets");
        IGNORE_ATTRIBUTES.add("facetsAndChildren");
        IGNORE_ATTRIBUTES.add("parent");
        IGNORE_ATTRIBUTES.add("actionListeners");
        IGNORE_ATTRIBUTES.add("valueChangeListeners");
        IGNORE_ATTRIBUTES.add("validators");
        IGNORE_ATTRIBUTES.add("rowData");
        IGNORE_ATTRIBUTES.add("javax.faces.webapp.COMPONENT_IDS");
        IGNORE_ATTRIBUTES.add("javax.faces.webapp.FACET_NAMES");
        IGNORE_ATTRIBUTES.add("javax.faces.webapp.CURRENT_VIEW_ROOT");
    }

    private static final String LOGFILE_PARAM = "org.ajax4jsf.LOGFILE";

    /**
     * Output error state for lifecycle.
     * 
     * @param context
     * @param phase
     *            TODO
     * @param error
     * @throws IOException
     */
    public void writeErrorMessage(FacesContext context, Throwable e, String phase) throws FacesException {
        if (null == context) {
            throw new FacesException(Messages.getMessage(Messages.FACES_CONTEXT_NOT_CREATED), e);
        }
        ExternalContext externalContext = context.getExternalContext();
        if (null == externalContext) {
            throw new FacesException(Messages.getMessage(Messages.FACES_CONTEXT_HAS_NOT_EXTERNAL), e);
        }
        // debug for http servlet environment, portlets needs other debugger
        HttpServletResponse response;
        HttpServletRequest request;
        try {
            response = (HttpServletResponse) externalContext.getResponse();
            request = (HttpServletRequest) externalContext.getRequest();
            response.setContentType("text/html;charset=UTF-8");
            // set internal server error status
            response.setStatus(500);
        } catch (Exception er) {
            throw new FacesException(Messages.getMessage(Messages.FACES_CONTEXT_HAS_NOT_RESPONSE), e);
        }
        PrintWriter out;
        try {
            out = response.getWriter();
        } catch (IOException e1) {
            throw new FacesException(e1.getMessage(), e);
        }
        UIViewRoot viewRoot = context.getViewRoot();
        String viewId;
        if (null != viewRoot) {
            viewId = viewRoot.getViewId();
        } else {
            viewId = request.getRequestURL().toString();
        }
        // output html prolog
        out.println("<html><head><title>" + Messages.getMessage(Messages.ERROR_ON_PAGE, viewId)
                + "</title></head><body>");
        // write script
        writeScriptAndStyle(out);
        // Header
        PhaseId facesPhase = (PhaseId) context.getExternalContext().getRequestMap()
                .get(DebugLifecycle.PHASE_ID_PARAM);

        String errorMessage = (facesPhase == null) ? Messages.getMessage(Messages.LIFECYCLE_ERROR, viewId, phase)
                : Messages.getMessage(Messages.LIFECYCLE_ERROR_AT_PHASE,
                        new Object[] { viewId, phase, facesPhase.toString() });
        out.println("<h1 >");
        out.println(errorMessage);
        out.println("</h1>");
        response.setHeader("Ajax-Error-Message",
                errorMessage + ",\n caused by " + e.getClass().getName() + ", with message: " + e.getMessage());
        // Output exceptions
        writeExceptionStack(e, out);
        // Output view tree :
        if (null != viewRoot) {
            writeComponentsTree(context, out);
        } else {
            out.print("<h2 class=' a4j_debug'> " + Messages.getMessage(Messages.COMPONENT_TREE_NOT_CREATED)
                    + " </h2>");
        }
        // Out scope variables
        writeContextVariables(context, out);
        // Write log output iframe :
        writeLog(context, out);
        // out html tail
        out.println("</body></html>");
        out.flush();
        out.close();
    }

    /**
     * @param e
     * @param out
     */
    public void writeExceptionStack(Throwable e, PrintWriter out) {
        out.println("<h2 class=\"a4j_debug\">Exceptions: </h2>");
        Throwable error = e;
        int errorId = 0;
        String caused = "exception ";
        while (null != error) {
            out.print("<h3 onclick=\"toggle('exception" + errorId + "')\"  class='exception a4j_debug'>");
            writeToggleMark(out, "exception" + errorId);
            out.print(caused + error.getClass().getName() + " : " + error.getMessage() + "</h3>");
            out.println("<div id='exception" + errorId
                    + "' style='display: none;' class='exception'><p>Exception stack :</p><pre>");
            StackTraceElement[] stackTrace = error.getStackTrace();
            for (int i = 0; i < stackTrace.length; i++) {
                out.print("  at " + stackTrace[i].getClassName());
                out.print("." + stackTrace[i].getMethodName());
                out.println(" in " + stackTrace[i].getFileName() + " line " + stackTrace[i].getLineNumber());
            }
            // error.printStackTrace(out);
            out.println("</pre></div>");
            error = error.getCause();
            caused = "caused by ";
            errorId++;
        }
    }

    /**
     * @param context
     * @param out
     */
    public void writeContextVariables(FacesContext context, PrintWriter out) {
        out.print("<h2  class=\"a4j_debug\" onclick=\"toggle('variables')\">");
        writeToggleMark(out, "variables");
        out.println(
                "Faces variables: </h2><div id='variables' style='display: none;'  class='variables a4j_debug'>");
        writeVariables(out, context);
        out.println("</div>");
    }

    /**
     * @param context
     * @param out
     */
    public void writeComponentsTree(FacesContext context, PrintWriter out) {
        out.print("<h2 class=\"a4j_debug\" onclick=\"toggle('tree')\">");
        writeToggleMark(out, "tree");
        out.println("Component tree: </h2><div id='tree' style='display: none;'  class='tree a4j_debug'><dl>");
        writeComponent(context, out, context.getViewRoot(), null);
        out.println("</dl></div>");
    }

    public void writeScriptAndStyle(PrintWriter out) {
        writeScript(out);
        writeStyleSheet(out);
    }

    /**
     * @param context
     * @param out
     * @throws FacesException
     */
    public void writeLog(FacesContext context, PrintWriter out) throws FacesException {
        String logname = context.getExternalContext().getInitParameter(LOGFILE_PARAM);
        if (null != logname) {
            InternetResource logResource = InternetResourceBuilder.getInstance().createResource(this, logname);
            out.print("<h2 onclick=\"toggle('log')\" class=\"a4j_debug\">");
            writeToggleMark(out, "log");
            out.println("Faces log: </h2><div id='log' style='display: none;'  class='log a4j_debug'>");
            out.print("<iframe name='log' class='log' src='" + logResource.getUri(context, null)
                    + "'><a href='src='" + logResource.getUri(context, null) + "'>Faces log file </a> </iframe>");
            out.println("</div>");
        }
    }

    public void writeToggleMark(PrintWriter out, String id) {
        out.print("<span style=\"display:none;\" id=\"" + id + "_expanded\" >-&nbsp;</span>");
        out.print("<span style=\"display:inline;\" id=\"" + id + "_collapsed\" >+</span>&nbsp;");
    }

    /**
     * Out component with properties and it's facets and childrens
     * @param context TODO
     * @param out
     * @param viewRoot
     */
    private void writeComponent(FacesContext context, PrintWriter out, UIComponent component, String facetName) {
        String clientId = "_tree:" + component.getClientId(context);
        out.println("<dt onclick=\"toggle('" + clientId + "')\" class='tree'>");
        writeToggleMark(out, clientId);
        // out component name
        if (null != facetName) {
            out.print("Facet:'" + facetName + "' ");
        }
        out.println("<code>" + component.getClass().getName() + "</code> Id:[" + component.getId() + "]");
        out.println("</dt>");
        out.println("<dd id='" + clientId + "' style='display:none;'   class='tree' ><ul   class='tree'>");
        // out bean properties
        try {
            PropertyDescriptor propertyDescriptors[] = PropertyUtils.getPropertyDescriptors(component);
            for (int i = 0; i < propertyDescriptors.length; i++) {
                if (PropertyUtils.isReadable(component, propertyDescriptors[i].getName())) {
                    String name = propertyDescriptors[i].getName();
                    ValueBinding vb = component.getValueBinding(name);
                    if (vb != null) {
                        writeAttribute(out, name, vb.getExpressionString());
                    } else {
                        if (!IGNORE_ATTRIBUTES.contains(name)) {
                            try {
                                String value = BeanUtils.getProperty(component, name);
                                writeAttribute(out, name, value);
                            } catch (Exception e) {
                                writeAttribute(out, name, null);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            // Do nothing - we in error page.
        }

        // out bindings
        // out attributes map
        for (Iterator it = component.getAttributes().entrySet().iterator(); it.hasNext();) {
            Map.Entry entry = (Map.Entry) it.next();
            writeAttribute(out, (String) entry.getKey(), entry.getValue());
        }
        // out listeners
        out.println("</ul></dd>");
        if (component.getFacetsAndChildren().hasNext()) {
            out.println("<dd class='tree_childs'><dl class='tree_childs'>");
            // out childs of this component
            // facets
            for (Iterator facetEntry = component.getFacets().entrySet().iterator(); facetEntry.hasNext();) {
                Map.Entry entry = (Map.Entry) facetEntry.next();
                writeComponent(context, out, (UIComponent) entry.getValue(), (String) entry.getKey());
            }
            // childs components
            for (Iterator childIter = component.getChildren().iterator(); childIter.hasNext();) {
                UIComponent child = (UIComponent) childIter.next();
                writeComponent(context, out, child, null);
            }
            out.println("</dl></dd>");
        }

    }

    private void writeAttribute(PrintWriter out, String name, Object value) {
        if (IGNORE_ATTRIBUTES.contains(name))
            return;
        if (name.startsWith("javax.faces.webapp.UIComponentTag.")) {
            name = name.substring("javax.faces.webapp.UIComponentTag.".length());
        }
        out.print("<li>");
        out.print(name);
        out.print("=\"");
        if (value != null) {
            if (value instanceof UIComponent) {
                out.print("[id:");
                out.print(((UIComponent) value).getId());
                out.print(']');
            } else if (value instanceof MethodBinding) {
                out.print(((MethodBinding) value).getExpressionString());
            } else if (value instanceof ValueBinding) {
                out.print(((ValueBinding) value).getExpressionString());
            } else {
                out.print(value.toString());
            }
        } else {
            out.print("NULL");
        }
        out.println("\"</li>");
    }

    private void writeVariables(PrintWriter out, FacesContext faces) {
        ExternalContext ctx = faces.getExternalContext();
        writeVariables(out, ctx.getRequestParameterMap(), "Request Parameters");
        writeVariables(out, ctx.getRequestMap(), "Request Attributes");
        if (ctx.getSession(false) != null) {
            writeVariables(out, ctx.getSessionMap(), "Session Attributes");
        }
        writeVariables(out, ctx.getApplicationMap(), "Application Attributes");
    }

    private void writeVariables(PrintWriter out, Map vars, String caption) {
        out.print("<table><caption>");
        out.print(caption);
        out.println(
                "</caption><thead><tr><th style=\"width: 10%; \">Name</th><th style=\"width: 90%; \">Value</th></tr></thead><tbody>");
        boolean written = false;
        if (!vars.isEmpty()) {
            SortedMap map = new TreeMap(vars);
            Map.Entry entry = null;
            String key = null;
            for (Iterator itr = map.entrySet().iterator(); itr.hasNext();) {
                entry = (Map.Entry) itr.next();
                key = entry.getKey().toString();
                if (key.indexOf('.') == -1) {
                    out.println("<tr><td>");
                    out.println(key.replaceAll("<", LT).replaceAll(">", GT));
                    out.println("</td><td><span class='value'>");
                    Object value = entry.getValue();
                    out.println(value.toString().replaceAll("<", LT).replaceAll(">", GT));
                    out.println("</span>");
                    try {
                        PropertyDescriptor propertyDescriptors[] = PropertyUtils.getPropertyDescriptors(value);
                        if (propertyDescriptors.length > 0) {
                            out.print("<div class='properties'><ul class=\'properties\'>");
                            for (int i = 0; i < propertyDescriptors.length; i++) {
                                String beanPropertyName = propertyDescriptors[i].getName();
                                if (PropertyUtils.isReadable(value, beanPropertyName)) {
                                    out.print("<li class=\'properties\'>");
                                    out.print(beanPropertyName + " = "
                                            + BeanUtils.getProperty(value, beanPropertyName));
                                    out.print("</li>");

                                }
                            }
                            out.print("</ul></div>");
                        }
                    } catch (Exception e) {
                        // TODO: log exception
                    }

                    out.println("</td></tr>");
                    written = true;
                }
            }
        }
        if (!written) {
            out.println("<tr><td colspan=\"2\"><em>None</em></td></tr>");
        }
        out.println("</tbody></table>");
    }

    /**
     * @param out
     */
    private void writeScript(PrintWriter out) {
        out.println("<script type='text/javascript' language='javascript'>\n" + "function toggle(id) {\n"
                + "var style = document.getElementById(id).style;\n" + "if ('block' == style.display) {\n"
                + "style.display = 'none';\n"
                + "document.getElementById(id+'_collapsed').style.display = 'inline';\n"
                + "document.getElementById(id+'_expanded').style.display = 'none';\n" + "} else {\n"
                + "style.display = 'block';\n"
                + "document.getElementById(id+'_collapsed').style.display = 'none';\n"
                + "document.getElementById(id+'_expanded').style.display = 'inline';\n" + "}\n" + "}\n\n" +

                "</script>");
    }

    /**
     * @param out
     */
    private void writeStyleSheet(PrintWriter out) {
        out.println("<style type=\'text/css\' >\n"
                + "div.a4j_debug, .a4j_debug span, .a4j_debug td, .a4j_debug th, .a4j_debug caption { font-family: Verdana, Arial, Sans-Serif; }\n"
                + ".a4j_debug li{\n" + "   list-style-position : inside;\n" + "}\n" + "\n"
                + ".a4j_debug li, .a4j_debug pre { padding: 0; margin: 0;  font-size : 12px;}\n"
                + ".a4j_debug ul { padding: 0 0 10 0; margin: 0;  font-size : 12px;}\n"
                + ".a4j_debug h1 { color: #fff; background-color : #a00; font-size : 17px; padding : 7px 10px 10px 10px}\n"
                + "h2.a4j_debug , h2.a4j_debug  span { color: #a00;  font-size : 17px; padding : 0px 0px 0px 10px;}\n"
                + "h2.a4j_debug  a { text-decoration: none; color: #a00; }\n"
                + ".exception { color: #000;  font-size : 14px; padding : 0px 0px 0px 10px;}\n"
                + ".grayBox { padding: 8px; margin: 10px 0; border: 1px solid #CCC; background-color: #f9f9f9;   font-size : 12px; }\n"
                + "#error { color: #900; font-weight: bold; font-size: medium; }\n"
                + "#trace, #tree, #vars { display: none; }\n"
                + ".a4j_debug code { font-size: medium;   font-size : 14px;}\n" + "#tree dl { color: #666; }\n"
                + "#tree dd {   font-size : 12px;}\n"
                + "#tree dt { border: 1px solid #DDD; padding: 2px 4px 4px 4px; border-left: 2px solid #a00; font-family: \"Courier New\", Courier, mono; font-size: small;   font-size : 12px; margin-top: 2px; margin-bottom: 2px;}\n"
                + ".uicText { color: #999;  }\n"
                + ".a4j_debug table { border: 1px solid #CCC; border-collapse: collapse; border-spacing: 0px; width: 100%; text-align: left; }\n"
                + ".a4j_debug td { border: 1px solid #CCC;    font-size : 12px; vertical-align : top}\n"
                + ".a4j_debug thead tr th { padding: 2px; color: #030; background-color: #F9F9F9;   font-size : 12px;}\n"
                + ".a4j_debug tbody tr td { padding: 10px 6px; }\n"
                + ".a4j_debug table caption { text-align: left; padding: 20 0 5 0; font-size : 12px; font-weight : bold;}\n"
                + ".value {font-size : 12px; font-weight : bold;}\n" + "div.log { width: 100%; height: 400px;}\n"
                + "iframe.log { width: 99%; height: 99%; border: 1px solid #CCC;}\n" + "</style>");
    }

}