com.sun.faces.facelets.util.DevTools Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jakarta.faces Show documentation
Show all versions of jakarta.faces Show documentation
EE4J Compatible Implementation for Jakarta Faces API
The newest version!
/*
* Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package com.sun.faces.facelets.util;
import static com.sun.faces.util.Util.unmodifiableSet;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.ByteArrayOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.sun.faces.RIConstants;
import com.sun.faces.util.Util;
import jakarta.el.Expression;
import jakarta.faces.component.UIComponent;
import jakarta.faces.context.ExternalContext;
import jakarta.faces.context.FacesContext;
import jakarta.faces.context.Flash;
/**
* Utility class for displaying Facelet error/debug information.
*
*
* The public static methods of this class are exposed as EL functions under the namespace
* mojarra.private.functions
*
*
*/
public final class DevTools {
private final static String SunNamespace = "http://java.sun.com/mojarra/private/functions";
private final static String JcpNamespace = "http://xmlns.jcp.org/mojarra/private/functions";
private final static String JakartaNamespace = "mojarra.private.functions";
public final static Set NAMESPACES = unmodifiableSet(JakartaNamespace, JcpNamespace, SunNamespace);
public final static String DEFAULT_NAMESPACE = JakartaNamespace;
private static final Logger LOGGER = Logger.getLogger(DevTools.class.getPackage().getName());
private final static String TS = "<";
private static final String ERROR_TEMPLATE = "META-INF/facelet-dev-error.xml";
private static String[] ERROR_PARTS;
private static final String DEBUG_TEMPLATE = "META-INF/facelet-dev-debug.xml";
private static String[] DEBUG_PARTS;
// ------------------------------------------------------------ Constructors
private DevTools() {
throw new IllegalStateException();
}
// ---------------------------------------------------------- Public Methods
public static void debugHtml(Writer writer, FacesContext faces, Throwable e) throws IOException {
init();
Date now = new Date();
for (String ERROR_PART : ERROR_PARTS) {
if (null != ERROR_PART) {
switch (ERROR_PART) {
case "message":
writeMessage(writer, e);
break;
case "trace":
writeException(writer, e);
break;
case "now":
writer.write(DateFormat.getDateTimeInstance().format(now));
break;
case "tree":
writeComponent(writer, faces.getViewRoot());
break;
case "vars":
writeVariables(writer, faces);
break;
default:
writer.write(ERROR_PART);
break;
}
}
}
}
public static void writeMessage(Writer writer, Throwable e) throws IOException {
if (e != null) {
String msg = e.getMessage();
if (msg != null) {
writer.write(msg.replace("<", TS));
} else {
writer.write(e.getClass().getName());
}
}
}
public static void writeException(Writer writer, Throwable e) throws IOException {
if (e != null) {
StringWriter str = new StringWriter(256);
PrintWriter pstr = new PrintWriter(str);
e.printStackTrace(pstr);
pstr.close();
writer.write(str.toString().replace("<", TS));
}
}
public static void debugHtml(Writer writer, FacesContext faces) throws IOException {
// PENDING - this and debugHtml(Writer, FacesContext, Exception) should
// be refactored to share code.
init();
Date now = new Date();
for (String DEBUG_PART : DEBUG_PARTS) {
if (null != DEBUG_PART) {
switch (DEBUG_PART) {
case "message":
writer.write(faces.getViewRoot().getViewId());
break;
case "now":
writer.write(DateFormat.getDateTimeInstance().format(now));
break;
case "tree":
writeComponent(writer, faces.getViewRoot());
break;
case "vars":
writeVariables(writer, faces);
break;
default:
writer.write(DEBUG_PART);
break;
}
}
}
}
public static void writeVariables(Writer writer, FacesContext faces) throws IOException {
ExternalContext ctx = faces.getExternalContext();
writeVariables(writer, ctx.getRequestParameterMap(), "Request Parameters");
if (faces.getViewRoot() != null) {
Map viewMap = faces.getViewRoot().getViewMap(false);
if (viewMap != null) {
writeVariables(writer, viewMap, "View Attributes");
} else {
writeVariables(writer, Collections.emptyMap(), "View Attributes");
}
} else {
writeVariables(writer, Collections.emptyMap(), "View Attributes");
}
writeVariables(writer, ctx.getRequestMap(), "Request Attributes");
Flash flash = ctx.getFlash();
try {
flash = ctx.getFlash();
} catch (UnsupportedOperationException uoe) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Flash not supported", uoe);
}
}
if (flash != null) {
writeVariables(writer, flash, "Flash Attributes");
} else {
writeVariables(writer, Collections.emptyMap(), "Flash Attributes");
}
if (ctx.getSession(false) != null) {
writeVariables(writer, ctx.getSessionMap(), "Session Attributes");
} else {
writeVariables(writer, Collections.emptyMap(), "Session Attributes");
}
writeVariables(writer, ctx.getApplicationMap(), "Application Attributes");
}
public static void writeComponent(Writer writer, UIComponent c) throws IOException {
writer.write(
"- ");
if (c == null) {
return;
}
boolean hasChildren = c.getChildCount() > 0 || c.getFacets().size() > 0;
writeStart(writer, c, hasChildren);
writer.write("
");
if (hasChildren) {
if (c.getFacets().size() > 0) {
for (Map.Entry entry : c.getFacets().entrySet()) {
writer.write("- ");
writer.write("");
writer.write((String) entry.getKey());
writer.write("");
writeComponent(writer, (UIComponent) entry.getValue());
writer.write("
");
}
}
if (c.getChildCount() > 0) {
for (UIComponent child : c.getChildren()) {
writer.write("- ");
writeComponent(writer, child);
writer.write("
");
}
}
writer.write(
"- ");
writeEnd(writer, c);
writer.write("
");
}
writer.write("
");
}
// --------------------------------------------------------- Private Methods
private static void init() throws IOException {
if (ERROR_PARTS == null) {
ERROR_PARTS = splitTemplate(ERROR_TEMPLATE);
}
if (DEBUG_PARTS == null) {
DEBUG_PARTS = splitTemplate(DEBUG_TEMPLATE);
}
}
private static String[] splitTemplate(String rsc) throws IOException {
ClassLoader loader = Util.getCurrentLoader(DevTools.class);
String str = "";
InputStream is = null;
try {
is = loader.getResourceAsStream(rsc);
if (is == null) {
loader = DevTools.class.getClassLoader();
is = loader.getResourceAsStream(rsc);
if (is == null) {
throw new FileNotFoundException(rsc);
}
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[512];
int read;
while ((read = is.read(buff)) != -1) {
baos.write(buff, 0, read);
}
str = baos.toString(RIConstants.CHAR_ENCODING);
} finally {
if (null != is) {
is.close();
}
}
return str.split("@@");
}
private static void writeVariables(Writer writer, Map vars, String caption) throws IOException {
writer.write(
"");
writer.write(caption);
writer.write(
" Name Value ");
boolean written = false;
if (!vars.isEmpty()) {
SortedMap map = new TreeMap<>(vars);
for (Map.Entry entry : map.entrySet()) {
String key = entry.getKey();
if (key.indexOf('.') == -1) {
writer.write("");
writer.write(key.replace("<", TS));
writer.write(" ");
writer.write(entry.getValue() == null ? "null" : entry.getValue().toString().replace("<", TS));
writer.write(" ");
written = true;
}
}
}
if (!written) {
writer.write("None ");
}
writer.write("
");
}
private static void writeEnd(Writer writer, UIComponent c) throws IOException {
if (!isText(c)) {
writer.write(TS);
writer.write('/');
writer.write(getName(c));
writer.write('>');
}
}
private final static String[] IGNORE = new String[] { "parent", "rendererType" };
private static void writeAttributes(Writer writer, UIComponent c) {
try {
BeanInfo info = Introspector.getBeanInfo(c.getClass());
PropertyDescriptor[] pd = info.getPropertyDescriptors();
for (PropertyDescriptor aPd : pd) {
if (aPd.getWriteMethod() != null && Arrays.binarySearch(IGNORE, aPd.getName()) < 0) {
Method m = aPd.getReadMethod();
try {
Object v = m.invoke(c);
if (v != null) {
if (v instanceof Collection || v instanceof Map || v instanceof Iterator) {
continue;
}
writer.write(" ");
writer.write(aPd.getName());
writer.write("=\"");
String str;
if (v instanceof Expression) {
str = ((Expression) v).getExpressionString();
} else {
str = v.toString();
}
writer.write(str.replace("<", TS));
writer.write("\"");
}
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | IOException e) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Error writing out attribute", e);
}
} catch (Exception e) {
if (LOGGER.isLoggable(Level.FINEST)) {
LOGGER.log(Level.FINEST, "Error writing out attribute", e);
}
}
}
}
} catch (IntrospectionException e) {
LOGGER.log(Level.FINEST, e, () -> "Error writing out attributes");
}
}
private static void writeStart(Writer writer, UIComponent c, boolean children) throws IOException {
if (isText(c)) {
String str = c.toString().trim();
writer.write(str.replace("<", TS));
} else {
writer.write(TS);
writer.write(getName(c));
writeAttributes(writer, c);
if (children) {
writer.write('>');
} else {
writer.write("/>");
}
}
}
private static String getName(UIComponent component) {
String componentName = component.getClass().getName();
return componentName.substring(componentName.lastIndexOf('.') + 1);
}
private static boolean isText(UIComponent c) {
return c.getClass().getName().startsWith("com.sun.faces.facelets.compiler");
}
}