/* (c) 2014 - 2016 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.web.wicket;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.Iterator;
import java.util.regex.Pattern;
import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
/**
* Dumps a wicket component/page hierarchy to text, eventually writing down the class and the model
* value as a string.
* <p>
* Each line in the dump follow the <code>componentId(class) 'value'</code> format.
* </p>
* <p>
* The class can be reused for multiple prints, but it's not thread safe
* </p>
*/
public class WicketHierarchyPrinter {
static final Pattern NEWLINE = Pattern.compile("\\n", Pattern.MULTILINE);
PrintStream out;
boolean valueDumpEnabled;
boolean classDumpEnabled;
boolean pathDumpEnabled;
/**
* Utility method to dump a single component/page to standard output
* @param c
* @param dumpClass
* @param dumpValue
*/
public static void print(Component c, boolean dumpClass, boolean dumpValue, boolean dumpPath) {
WicketHierarchyPrinter printer = new WicketHierarchyPrinter();
printer.setPathDumpEnabled(dumpClass);
printer.setClassDumpEnabled(dumpClass);
printer.setValueDumpEnabled(dumpValue);
if(c instanceof Page) {
printer.print((Page) c);
} else {
printer.print(c);
}
}
/**
* Utility method to dump a single component/page to standard output
* @param c
* @param dumpClass
* @param dumpValue
*/
public static void print(Component c, boolean dumpClass, boolean dumpValue) {
print(c, dumpClass, dumpValue, false);
}
/**
* Creates a printer that will dump to standard output
*/
public WicketHierarchyPrinter() {
out = System.out;
}
/**
* Creates a printer that will dump to the specified print stream
*/
public WicketHierarchyPrinter(PrintStream out) {
this.out = out;
}
/**
* Set to true if you want to see the model values in the dump
*
* @param valueDumpEnabled
*/
public void setValueDumpEnabled(boolean valueDumpEnabled) {
this.valueDumpEnabled = valueDumpEnabled;
}
/**
* Set to true if you want to see the component classes in the dump
*
* @param classDumpEnabled
*/
public void setClassDumpEnabled(boolean classDumpEnabled) {
this.classDumpEnabled = classDumpEnabled;
}
/**
* Prints the component containment hierarchy
*
* @param c
*/
public void print(Component c) {
walkHierarchy(c, 0);
}
/**
* Walks down the containment hierarchy depth first and prints each component found
*/
private void walkHierarchy(Component c, int level) {
printComponent(c, level);
if (c instanceof MarkupContainer) {
MarkupContainer mc = (MarkupContainer) c;
for (Iterator<?> it = mc.iterator(); it.hasNext();) {
walkHierarchy((Component) it.next(), level + 1);
}
}
}
/**
* Prints a single component
*/
private void printComponent(Component c, int level) {
if(c instanceof Page)
out.print(tab(level) + "PAGE_ROOT");
else
out.print(tab(level) + c.getId());
if(pathDumpEnabled) {
out.print(" " + c.getPageRelativePath());
}
if (classDumpEnabled) {
String className;
if(c.getClass().isAnonymousClass()) {
className = c.getClass().getSuperclass().getName();
} else {
className = c.getClass().getName();
}
out.print("(" + className + ")");
}
if (valueDumpEnabled) {
try {
String value = NEWLINE.matcher(c.getDefaultModelObjectAsString()).replaceAll("\\\\n");
out.print(" '" + value + "'");
} catch(Exception e) {
out.print(" 'ERROR_RETRIEVING_MODEL " + e.getMessage() + "'");
}
}
out.println();
}
/**
* Generates three spaces per level
*/
String tab(int level) {
char[] spaces = new char[level * 3];
Arrays.fill(spaces, ' ');
return new String(spaces);
}
/**
* If the page relative path dumping is enabled
*
*/
public boolean isPathDumpEnabled() {
return pathDumpEnabled;
}
/**
* Sets/unsets the relative path dumping
* @param pathDumpEnabled
*/
public void setPathDumpEnabled(boolean pathDumpEnabled) {
this.pathDumpEnabled = pathDumpEnabled;
}
}