/* * Copyright 2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.myfaces.util; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import javax.faces.FacesException; import javax.faces.component.*; import javax.faces.context.FacesContext; import javax.faces.el.MethodBinding; import javax.faces.el.ValueBinding; import javax.faces.event.FacesListener; import javax.faces.validator.Validator; import java.beans.BeanInfo; import java.beans.IntrospectionException; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.HashSet; import java.util.Iterator; import java.util.Map; /** * Utilities for logging. * * @author Manfred Geiler (latest modification by $Author$) * @version $Revision$ $Date$ */ public class DebugUtils { private static final Log log = LogFactory.getLog(DebugUtils.class); //Attributes that should not be printed private static 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 JSF_COMPONENT_PACKAGE = "javax.faces.component."; private static final String MYFACES_COMPONENT_PACKAGE = "org.apache.myfaces.component."; private DebugUtils() { // hide from public access } public static void assertError(boolean condition, Log log_, String msg) throws FacesException { if (!condition) { log_.error(msg); throw new FacesException(msg); } } public static void assertFatal(boolean condition, Log log_, String msg) throws FacesException { if (!condition) { log_.fatal(msg); throw new FacesException(msg); } } public static void traceView(String additionalMsg) { if (log.isTraceEnabled()) { FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext == null) { log.error("Cannot not print view to console (no FacesContext)."); return; } UIViewRoot viewRoot = facesContext.getViewRoot(); if (viewRoot == null) { log.error("Cannot not print view to console (no ViewRoot in FacesContext)."); return; } traceView(additionalMsg, viewRoot); } } /** * Be careful, when using this version of traceView: * Some component properties (e.g. getRenderer) assume, that there is a * valid viewRoot set in the FacesContext! * @param additionalMsg * @param viewRoot */ private static void traceView(String additionalMsg, UIViewRoot viewRoot) { ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos); if (additionalMsg != null) { ps.println(additionalMsg); } ps.println("========================================"); printView(viewRoot, ps); ps.println("========================================"); ps.close(); log.trace(baos.toString()); } public static void printView(UIViewRoot uiViewRoot, PrintStream stream) { printComponent(uiViewRoot, stream, 0, true, null); } public static void printComponent(UIComponent comp, PrintStream stream) { printComponent(comp, stream, 0, false, null); } private static void printComponent(UIComponent comp, PrintStream stream, int indent, boolean withChildrenAndFacets, String facetName) { printIndent(stream, indent); stream.print('<'); String compType = comp.getClass().getName(); if (compType.startsWith(JSF_COMPONENT_PACKAGE)) { compType = compType.substring(JSF_COMPONENT_PACKAGE.length()); } else if (compType.startsWith(MYFACES_COMPONENT_PACKAGE)) { compType = compType.substring(MYFACES_COMPONENT_PACKAGE.length()); } stream.print(compType); printAttribute(stream, "id", comp.getId()); if (facetName != null) { printAttribute(stream, "facetName", facetName); } for (Iterator it = comp.getAttributes().entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry)it.next(); if (!"id".equals(entry.getKey())) { printAttribute(stream, (String)entry.getKey(), entry.getValue()); } } //HACK: comp.getAttributes() only returns attributes, that are NOT backed //by a corresponding component property. So, we must explicitly get the //available properties by Introspection: BeanInfo beanInfo; try { beanInfo = Introspector.getBeanInfo(comp.getClass()); } catch (IntrospectionException e) { throw new RuntimeException(e); } PropertyDescriptor propDescriptors[] = beanInfo.getPropertyDescriptors(); for (int i = 0; i < propDescriptors.length; i++) { if (propDescriptors[i].getReadMethod() != null) { String name = propDescriptors[i].getName(); if (!"id".equals(name)) { ValueBinding vb = comp.getValueBinding(name); if (vb != null) { printAttribute(stream, name, vb.getExpressionString()); } else { if (name.equals("value") && comp instanceof ValueHolder) { //-> localValue } else if (!IGNORE_ATTRIBUTES.contains(name)) { try { Object value = comp.getAttributes().get(name); printAttribute(stream, name, value); } catch (Exception e) { log.error(e); printAttribute(stream, name, null); } } } } } } boolean mustClose = true; boolean nestedObjects = false; if (comp instanceof UICommand) { FacesListener[] listeners = ((UICommand)comp).getActionListeners(); if (listeners != null && listeners.length > 0) { nestedObjects = true; stream.println('>'); mustClose = false; for (int i = 0; i < listeners.length; i++) { FacesListener listener = listeners[i]; printIndent(stream, indent + 1); stream.print('<'); stream.print(listener.getClass().getName()); stream.println("/>"); } } } if (comp instanceof UIInput) { FacesListener[] listeners = ((UIInput)comp).getValueChangeListeners(); if (listeners != null && listeners.length > 0) { nestedObjects = true; stream.println('>'); mustClose = false; for (int i = 0; i < listeners.length; i++) { FacesListener listener = listeners[i]; printIndent(stream, indent + 1); stream.print('<'); stream.print(listener.getClass().getName()); stream.println("/>"); } } Validator[] validators = ((UIInput)comp).getValidators(); if (validators != null && validators.length > 0) { nestedObjects = true; stream.println('>'); mustClose = false; for (int i = 0; i < validators.length; i++) { Validator validator = validators[i]; printIndent(stream, indent + 1); stream.print('<'); stream.print(validator.getClass().getName()); stream.println("/>"); } } } if (withChildrenAndFacets) { int childCount = comp.getChildCount(); Map facetsMap = comp.getFacets(); if (childCount > 0 || !facetsMap.isEmpty()) { nestedObjects = true; if (mustClose) { stream.println('>'); mustClose = false; } if (childCount > 0) { for (Iterator it = comp.getChildren().iterator(); it.hasNext(); ) { UIComponent child = (UIComponent)it.next(); printComponent(child, stream, indent + 1, true, null); } } for (Iterator it = facetsMap.entrySet().iterator(); it.hasNext(); ) { Map.Entry entry = (Map.Entry)it.next(); printComponent((UIComponent)entry.getValue(), stream, indent + 1, true, (String)entry.getKey()); } } } if (nestedObjects) { if (mustClose) { stream.println("/>"); } else { printIndent(stream, indent); stream.print("</"); stream.print(compType); stream.println('>'); } } else { stream.println("/>"); } } private static void printAttribute(PrintStream stream, 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()); } stream.print(' '); stream.print(name.toString()); stream.print("=\""); if (value != null) { if (value instanceof UIComponent) { stream.print("[id:"); stream.print(((UIComponent)value).getId()); stream.print(']'); } else if (value instanceof MethodBinding) { stream.print(((MethodBinding)value).getExpressionString()); } else { stream.print(value.toString()); } } else { stream.print("NULL"); } stream.print('"'); } private static void printIndent(PrintStream stream, int depth) { for (int i = 0; i < depth; i++) { stream.print(" "); } } public static String componentAsString(UIComponent comp) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); printComponent(comp, new PrintStream(baos)); baos.close(); return baos.toString(); } catch (IOException e) { throw new RuntimeException(e); } } }