/*
* Copyright (c) 2010-2013 Evolveum
*
* 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 com.evolveum.midpoint.util;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import javax.xml.XMLConstants;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.Text;
/**
* @author semancik
*
*/
public class PrettyPrinter {
private static final int BYTE_ARRAY_MAX_LEN = 64;
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyy-mm-dd hh:mm:ss");
private static String defaultNamespacePrefix = null;
private static List<Class<?>> prettyPrinters = new ArrayList<>();
public static void setDefaultNamespacePrefix(String prefix) {
defaultNamespacePrefix = prefix;
}
static String prettyPrintElementAsProperty(Object element) {
if (element == null) {
return "null";
}
StringBuilder sb = new StringBuilder("<");
QName elementName = JAXBUtil.getElementQName(element);
sb.append(prettyPrint(elementName));
sb.append(">");
if (element instanceof Element) {
Element domElement = (Element)element;
// TODO: this is too simplistic, expand later
sb.append(domElement.getTextContent());
} else {
sb.append(element.toString());
}
return sb.toString();
}
public static String prettyPrint(Collection<?> collection) {
return prettyPrint(collection, 0);
}
public static String prettyPrint(Collection<?> collection, int maxItems) {
if (collection == null) {
return null;
}
StringBuilder sb = new StringBuilder(DebugUtil.getCollectionOpeningSymbol(collection));
Iterator<?> iterator = collection.iterator();
int items = 0;
while (iterator.hasNext()) {
sb.append(prettyPrint(iterator.next()));
items++;
if (iterator.hasNext()) {
sb.append(",");
if (maxItems != 0 && items >= maxItems) {
sb.append("...");
break;
}
}
}
sb.append(DebugUtil.getCollectionClosingSymbol(collection));
return sb.toString();
}
public static String prettyPrint(QName qname) {
if (qname == null) {
return "null";
}
if (qname.getNamespaceURI() != null) {
if (qname.getNamespaceURI().equals(XMLConstants.W3C_XML_SCHEMA_NS_URI)) {
return "{"+DOMUtil.NS_W3C_XML_SCHEMA_PREFIX+":}"+qname.getLocalPart();
} else if (defaultNamespacePrefix != null && qname.getNamespaceURI().startsWith(defaultNamespacePrefix)) {
return "{..."+qname.getNamespaceURI().substring(defaultNamespacePrefix.length())+"}"+qname.getLocalPart();
}
}
return qname.toString();
}
/**
* Assumes that all elements in the lists have the same QName
*
* @param list
* @return
*/
public static String prettyPrint(List<Element> list) {
if (list == null) {
return "null";
}
StringBuilder sb = new StringBuilder();
if (list.size() > 0) {
Element el0 = list.get(0);
QName elQName;
if (el0.getPrefix() != null) {
elQName = new QName(el0.getNamespaceURI(), el0.getLocalName(), el0.getPrefix());
} else {
elQName = new QName(el0.getNamespaceURI(), el0.getLocalName());
}
sb.append(elQName);
sb.append("[");
Iterator<Element> iterator = list.iterator();
while (iterator.hasNext()) {
// TODO: improve for non-strings
Element el = iterator.next();
sb.append(prettyPrint(el, false));
if (iterator.hasNext()) {
sb.append(",");
}
sb.append("]");
}
} else {
sb.append("[]");
}
return sb.toString();
}
public static String prettyPrint(Node node) {
if (node instanceof Element) {
return prettyPrint((Element) node);
}
// TODO: Better print
return "Node:" + node.getNodeName();
}
public static String prettyPrint(Element element) {
return prettyPrint(element, true);
}
public static String prettyPrint(Element element, boolean displayTag) {
if (element == null) {
return "null";
}
StringBuilder sb = new StringBuilder();
if (displayTag) {
sb.append("<");
if (element.getLocalName() != null) {
sb.append(prettyPrint(new QName(element.getNamespaceURI(), element.getLocalName())));
} else {
sb.append("<null>");
}
sb.append(">");
}
NamedNodeMap attributes = element.getAttributes();
for (int i = 0; i < attributes.getLength(); i++) {
Node attr = attributes.item(i);
if ("xmlns".equals(attr.getPrefix())) {
// Don't display XML NS declarations
// they are too long for prettyPrint
continue;
}
if ((attr.getPrefix() == null || attr.getPrefix().isEmpty())
&& "xmlns".equals(attr.getLocalName())) {
// Skip default ns declaration as well
continue;
}
sb.append("@");
sb.append(attr.getLocalName());
sb.append("=");
sb.append(attr.getTextContent());
if (i < (attributes.getLength() - 1)) {
sb.append(",");
}
}
if (attributes.getLength() > 0) {
sb.append(":");
}
StringBuilder content = new StringBuilder();
Node child = element.getFirstChild();
while (child != null) {
if (child.getNodeType() == Node.TEXT_NODE) {
content.append(((Text) child).getTextContent());
} else if (child.getNodeType() == Node.COMMENT_NODE) {
// just ignore this
} else {
content = new StringBuilder("[complex content]");
break;
}
child = child.getNextSibling();
}
sb.append(content);
return sb.toString();
}
public static String prettyPrint(Date date) {
if (date == null) {
return "null";
}
return dateFormat.format(date);
}
public static String prettyPrint(Object[] value) {
return prettyPrint(Arrays.asList(value));
}
public static String prettyPrint(byte[] value) {
StringBuilder sb = new StringBuilder();
sb.append("byte[");
int printlen = value.length;
if (printlen > BYTE_ARRAY_MAX_LEN) {
printlen = BYTE_ARRAY_MAX_LEN;
}
for(int i=0; i < printlen; i++) {
sb.append(Byte.toString(value[i]));
if (i < printlen) {
sb.append(',');
}
}
if (value.length > BYTE_ARRAY_MAX_LEN) {
sb.append(",... ");
sb.append(value.length);
sb.append(" bytes total");
}
sb.append("]");
return sb.toString();
}
public static String prettyPrint(Object value) {
if (value == null) {
return "null";
}
String out = null;
if (value instanceof JAXBElement) {
Object elementValue = ((JAXBElement)value).getValue();
out = tryPrettyPrint(elementValue);
if (out != null) {
return ("JAXBElement("+((JAXBElement)value).getName()+","+out+")");
}
}
out = tryPrettyPrint(value);
if (out == null) {
out = value.toString();
}
return out;
}
private static String tryPrettyPrint(Object value) {
if (value instanceof Class) {
Class<?> c = (Class<?>)value;
if (c.getPackage().getName().equals("com.evolveum.midpoint.xml.ns._public.common.common_3")) {
return c.getSimpleName();
}
return c.getName();
}
if (value instanceof Collection) {
return PrettyPrinter.prettyPrint((Collection<?>)value);
}
if (value.getClass().isArray()) {
Class<?> cclass = value.getClass().getComponentType();
if (cclass.isPrimitive()) {
if (cclass == byte.class) {
return PrettyPrinter.prettyPrint((byte[])value);
} else {
// TODO: something better
}
} else {
return PrettyPrinter.prettyPrint((Object[])value);
}
}
if (value instanceof Node) {
// This is interface, won't catch it using reflection
return PrettyPrinter.prettyPrint((Node)value);
}
for (Class<?> prettyPrinterClass: prettyPrinters) {
String printerValue = tryPrettyPrint(value, prettyPrinterClass);
if (printerValue != null) {
return printerValue;
}
}
// Fallback to this class
return tryPrettyPrint(value, PrettyPrinter.class);
}
private static String tryPrettyPrint(Object value, Class<?> prettyPrinterClass) {
for (Method method : prettyPrinterClass.getMethods()) {
if (method.getName().equals("prettyPrint")) {
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1 && parameterTypes[0].equals(value.getClass())) {
try {
return (String)method.invoke(null, value);
} catch (IllegalArgumentException e) {
return "###INTERNAL#ERROR### Illegal argument: "+e.getMessage() + "; prettyPrint method for value "+value;
} catch (IllegalAccessException e) {
return "###INTERNAL#ERROR### Illegal access: "+e.getMessage() + "; prettyPrint method for value "+value;
} catch (InvocationTargetException e) {
return "###INTERNAL#ERROR### Illegal target: "+e.getMessage() + "; prettyPrint method for value "+value;
} catch (Throwable e) {
return "###INTERNAL#ERROR### "+e.getClass().getName()+": "+e.getMessage() + "; prettyPrint method for value "+value;
}
}
}
}
return null;
}
public static void registerPrettyPrinter(Class<?> printerClass) {
prettyPrinters.add(printerClass);
}
}