/* * Copyright (c) 2010-2017 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.schema.util; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.xml.bind.JAXBElement; import javax.xml.namespace.QName; import com.evolveum.midpoint.util.exception.SchemaException; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import com.evolveum.midpoint.prism.marshaller.XPathHolder; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectPaging; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.schema.constants.SchemaConstants; import com.evolveum.midpoint.util.DebugDumpable; import com.evolveum.midpoint.util.DebugUtil; import com.evolveum.midpoint.util.JAXBUtil; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.QNameUtil; import com.evolveum.midpoint.xml.ns._public.common.api_types_3.ObjectListType; import com.evolveum.midpoint.xml.ns._public.common.api_types_3.PropertyReferenceListType; import com.evolveum.midpoint.xml.ns._public.common.common_3.AssignmentType; import com.evolveum.midpoint.xml.ns._public.common.common_3.CachingMetadataType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ConstructionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; import com.evolveum.midpoint.xml.ns._public.common.common_3.OperationResultType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ResourceAttributeDefinitionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.SynchronizationSituationDescriptionType; import com.evolveum.midpoint.xml.ns._public.common.common_3.UnknownJavaObjectType; import com.evolveum.prism.xml.ns._public.query_3.PagingType; import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType; import com.evolveum.prism.xml.ns._public.types_3.ItemPathType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import com.evolveum.prism.xml.ns._public.types_3.RawType; /** * * @author semancik */ public class SchemaDebugUtil { private static int SHOW_LIST_MEMBERS = 3; public static String debugDump(Collection<? extends DebugDumpable> dumpables) { return debugDump(dumpables,0); } public static String debugDump(Collection<? extends DebugDumpable> dumpables, int indent) { StringBuilder sb = new StringBuilder(); indentDebugDump(sb, indent); sb.append(getCollectionOpeningSymbol(dumpables)); if (!dumpables.isEmpty()) { sb.append("\n"); for (DebugDumpable dd : dumpables) { if (dd == null) { indentDebugDump(sb, indent + 1); sb.append("null"); } else { sb.append(dd.debugDump(indent + 1)); } sb.append("\n"); } indentDebugDump(sb, indent); } sb.append(getCollectionClosingSymbol(dumpables)); return sb.toString(); } public static String debugDumpXsdAnyProperties(Collection<?> xsdAnyCollection, int indent) { StringBuilder sb = new StringBuilder(); indentDebugDump(sb, indent); sb.append(getCollectionOpeningSymbol(xsdAnyCollection)); for (Object element : xsdAnyCollection) { sb.append("\n"); indentDebugDump(sb, indent+1); sb.append(prettyPrintElementAsProperty(element)); } sb.append("\n"); indentDebugDump(sb, indent); sb.append(getCollectionClosingSymbol(xsdAnyCollection)); return sb.toString(); } private 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(); } private static String getCollectionOpeningSymbol(Collection<?> col) { if (col instanceof List) { return "["; } if (col instanceof Set) { return "{"; } return col.getClass().getSimpleName()+"("; } private static String getCollectionClosingSymbol(Collection<?> col) { if (col instanceof List) { return "]"; } if (col instanceof Set) { return "}"; } return ")"; } public static void indentDebugDump(StringBuilder sb, int indent) { for(int i = 0; i < indent; i++) { sb.append(DebugDumpable.INDENT_STRING); } } public static <K, V extends DebugDumpable> String dumpMapMultiLine(Map<K, V> map) { StringBuilder sb = new StringBuilder(); debugDumpMapMultiLine(sb, map, 0); return sb.toString(); } public static <K, V extends DebugDumpable> void debugDumpMapMultiLine(StringBuilder sb, Map<K, V> map, int indent) { Iterator<Entry<K, V>> i = map.entrySet().iterator(); while (i.hasNext()) { Entry<K,V> entry = i.next(); indentDebugDump(sb,indent); sb.append(prettyPrint(entry.getKey())); sb.append(" => "); V value = entry.getValue(); if (value == null) { sb.append("null"); } else { sb.append("\n"); sb.append(value.debugDump(indent+1)); } if (i.hasNext()) { sb.append("\n"); } } } public static <K, V> void debugDumpMapSingleLine(StringBuilder sb, Map<K, V> map, int indent) { Iterator<Entry<K, V>> i = map.entrySet().iterator(); while (i.hasNext()) { Entry<K,V> entry = i.next(); indentDebugDump(sb,indent); sb.append(prettyPrint(entry.getKey())); sb.append(" => "); V value = entry.getValue(); if (value == null) { sb.append("null"); } else { sb.append(value); } if (i.hasNext()) { sb.append("\n"); } } } public static String debugDump(ObjectType objectType, int indent) { if (objectType == null) { StringBuilder sb = new StringBuilder(); DebugUtil.indentDebugDump(sb, indent); sb.append("null"); return sb.toString(); } return objectType.asPrismObject().debugDump(indent); } public static String prettyPrint(Collection<?> collection) { if (collection == null) { return null; } StringBuilder sb = new StringBuilder(getCollectionOpeningSymbol(collection)); Iterator<?> iterator = collection.iterator(); while (iterator.hasNext()) { sb.append(prettyPrint(iterator.next())); if (iterator.hasNext()) { sb.append(","); } } sb.append(getCollectionClosingSymbol(collection)); return sb.toString(); } public static String prettyPrint(QName qname) { if (qname == null) { return "null"; } if (qname.getNamespaceURI() != null && qname.getNamespaceURI().startsWith(SchemaConstants.NS_MIDPOINT_PUBLIC_PREFIX)) { return "{..."+qname.getNamespaceURI().substring(SchemaConstants.NS_MIDPOINT_PUBLIC_PREFIX.length())+"}"+qname.getLocalPart(); } return qname.toString(); } public static String prettyPrint(AssignmentType assignmentType) { if (assignmentType == null) { return "null"; } StringBuilder sb = new StringBuilder("AssignmentType("); if (assignmentType.getTarget() != null) { sb.append("target:"); sb.append(prettyPrint(assignmentType.getTarget())); } if (assignmentType.getTargetRef() != null) { sb.append("target:"); sb.append(prettyPrint(assignmentType.getTargetRef())); } if (assignmentType.getConstruction() != null) { sb.append(prettyPrint(assignmentType.getConstruction())); } sb.append(", "); if (assignmentType.getActivation() != null) { sb.append(prettyPrint(assignmentType.getActivation())); } sb.append(")"); return sb.toString(); } public static String prettyPrint(ConstructionType act) { if (act == null) { return "null"; } StringBuilder sb = new StringBuilder("ConstructionType("); if (act.getResource() != null) { sb.append(prettyPrint(act.getResource())); } if (act.getResourceRef() != null) { sb.append(prettyPrint(act.getResourceRef())); } sb.append(", "); if (act.getIntent() != null) { sb.append("intent="); sb.append(act.getIntent()); sb.append(", "); } if (act.getAttribute() != null) { for (ResourceAttributeDefinitionType attrConstr: act.getAttribute()) { sb.append(prettyPrint(attrConstr)); } } // TODO: Other properties sb.append(")"); return sb.toString(); } public static String prettyPrint(ResourceAttributeDefinitionType vc) { if (vc == null) { return "null"; } StringBuilder sb = new StringBuilder("ResourceAttributeDefinitionType("); if (vc.getRef() != null) { sb.append("ref="); sb.append(prettyPrint(vc.getRef())); sb.append("..."); } // TODO: Other properties sb.append(")"); return sb.toString(); } public static String prettyPrint(CachingMetadataType cachingMetadata) { if (cachingMetadata == null) { return "null"; } StringBuilder sb = new StringBuilder("CachingMetadataType("); if (cachingMetadata.getSerialNumber() != null) { sb.append("serialNumber:"); sb.append(prettyPrint(cachingMetadata.getSerialNumber())); } if (cachingMetadata.getRetrievalTimestamp() != null) { sb.append("retrievalTimestamp:"); sb.append(prettyPrint(cachingMetadata.getRetrievalTimestamp())); } sb.append(")"); return sb.toString(); } public static String prettyPrint(ObjectReferenceType ref) { if (ref == null) { return "null"; } StringBuilder sb = new StringBuilder("ref("); sb.append(ref.getOid()); sb.append(","); sb.append(prettyPrint(ref.getType())); sb.append(")"); return sb.toString(); } public static String prettyPrint(PropertyReferenceListType reflist) { if (reflist == null) { return "null"; } StringBuilder sb = new StringBuilder("["); Iterator<ItemPathType> iterator = reflist.getProperty().iterator(); while (iterator.hasNext()) { ItemPathType xpath = iterator.next(); sb.append(xpath.toString()); if (iterator.hasNext()) { sb.append(","); } } sb.append("]"); return sb.toString(); } public static String prettyPrint(ObjectType object) { if (object == null) { return "null"; } return object.asPrismObject().toString(); } public static String prettyPrint(ProtectedStringType protectedStringType) { if (protectedStringType == null) { return "null"; } StringBuilder sb = new StringBuilder("ProtectedStringType("); if (protectedStringType.getEncryptedDataType() != null) { sb.append("[encrypted data]"); } if (protectedStringType.getHashedDataType() != null) { sb.append("[hashed data]"); } if (protectedStringType.getClearValue() != null) { sb.append("\""); sb.append(protectedStringType.getClearValue()); sb.append("\""); } sb.append(")"); return sb.toString(); } public static String prettyPrint(OperationResultType resultType) { if (resultType == null) { return "null"; } StringBuilder sb = new StringBuilder("RT("); sb.append(resultType.getOperation()); sb.append(","); sb.append(resultType.getStatus()); sb.append(","); sb.append(resultType.getMessage()); sb.append(")"); return sb.toString(); } public static String prettyPrint(ItemDeltaType change) throws SchemaException { if (change == null) { return "null"; } StringBuilder sb = new StringBuilder("ProperyModification("); sb.append(change.getModificationType()); sb.append(","); if (change.getPath() != null) { //FIXME : xpath vs itemPath XPathHolder xpath = new XPathHolder(change.getPath().getItemPath()); sb.append(xpath.toString()); } else { sb.append("xpath=null"); } sb.append(","); List<RawType> values = change.getValue(); for (RawType value : values) { sb.append(prettyPrint(value.serializeToXNode())); // todo implement correctly... sb.append(","); } return sb.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(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(ObjectListType list) { if (list == null) { return "null"; } StringBuilder sb = new StringBuilder("ObjectList["); Iterator<ObjectType> iterator = list.getObject().iterator(); int i = 0; while (iterator.hasNext()) { if (i < SHOW_LIST_MEMBERS) { sb.append(prettyPrint(iterator.next())); if (iterator.hasNext()) { sb.append(","); } } else { sb.append("(and "); sb.append(list.getObject().size() - i); sb.append(" more)"); break; } i++; } sb.append("]"); return sb.toString(); } // public static String prettyPrint(QueryType query) { // // if (query == null) { // return "null"; // } // // SearchFilterType filterType = query.getFilter(); // Element filter = null; // if (filterType != null) { // filter = filterType.getFilterClause(); // } // // StringBuilder sb = new StringBuilder("Query("); // // prettyPrintFilter(sb, filter); // // sb.append(")"); // // return sb.toString(); // } private static void prettyPrintFilter(StringBuilder sb, Element filter) { if (filter == null) { sb.append("null"); return; } String tag = filter.getLocalName(); sb.append(tag); sb.append("("); if ("type".equals(tag)) { String uri = filter.getAttribute("uri"); QName typeQname = QNameUtil.uriToQName(uri); sb.append(typeQname.getLocalPart()); sb.append(")"); return; } NodeList childNodes = filter.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node node = childNodes.item(i); if (node.getNodeType() == Node.TEXT_NODE) { sb.append("\""); sb.append(node.getTextContent()); sb.append("\""); } else if (node.getNodeType() == Node.ELEMENT_NODE) { prettyPrintFilter(sb, (Element) node); } else { sb.append("!"); sb.append(node.getNodeType()); } sb.append(","); } sb.append(")"); } private static void prettyPrintFilter(StringBuilder sb, ObjectFilter filter) { if (filter == null) { sb.append("null"); return; } sb.append("("); sb.append(filter.toString()); sb.append(")"); } private static void prettyPrintPaging(StringBuilder sb, ObjectPaging paging) { if (paging == null) { sb.append("null"); return; } sb.append("("); sb.append(paging.toString()); sb.append(")"); } public static String prettyPrint(PagingType paging) { if (paging == null) { return "null"; } StringBuilder sb = new StringBuilder("Paging("); if (paging.getOffset() != null) { sb.append(paging.getOffset()).append(","); } else { sb.append(","); } if (paging.getMaxSize() != null) { sb.append(paging.getMaxSize()).append(","); } else { sb.append(","); } if (paging.getOrderBy() != null) { sb.append(prettyPrint(paging.getOrderBy())).append(","); } else { sb.append(","); } if (paging.getOrderDirection() != null) { sb.append(paging.getOrderDirection()); } sb.append(")"); return sb.toString(); } public static String prettyPrint(SynchronizationSituationDescriptionType syncDescType) { if (syncDescType == null) { return "null"; } StringBuilder sb = new StringBuilder("SyncDesc("); sb.append(syncDescType.getSituation()); sb.append(","); sb.append(syncDescType.getTimestamp()); if (syncDescType.getChannel() != null) { sb.append(","); sb.append(syncDescType.getChannel()); } if (syncDescType.isFull() != null && syncDescType.isFull()) { sb.append(",full"); } sb.append(")"); return sb.toString(); } public static String prettyPrint(JAXBElement<?> element) { return "JAXBElement("+PrettyPrinter.prettyPrint(element.getName())+"): "+element.getValue(); } public static String prettyPrint(UnknownJavaObjectType xml) { if (xml == null) { return "null"; } return "Java("+xml.getClazz()+","+xml.getToString()+")"; } // public static String prettyPrint(OperationProvisioningScriptsType scriptsType) { // if (scriptsType == null) { // return "null"; // } // StringBuilder sb = new StringBuilder("") // for (OperationProvisioningScriptType scriptType: scriptsType.getScript()) { // // } // } 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 prettyPrint((Collection<?>)value); } if (value instanceof ObjectQuery){ return prettyPrint((ObjectQuery) value); } if (value instanceof ObjectType) { // ObjectType has many subtypes, difficult to sort out using reflection // therefore we special-case it return prettyPrint((ObjectType)value); } if (value instanceof Node) { // This is interface, won't catch it using reflection return prettyPrint((Node)value); } for (Method method : SchemaDebugUtil.class.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(); } catch (IllegalAccessException e) { return "###INTERNAL#ERROR### Illegal access: "+e.getMessage(); } catch (InvocationTargetException e) { return "###INTERNAL#ERROR### Illegal target: "+e.getMessage(); } catch (Throwable e) { return "###INTERNAL#ERROR### "+e.getClass().getName()+": "+e.getMessage(); } } } } return null; } public static String prettyPrint(ObjectQuery query){ return query.toString(); } static { PrettyPrinter.registerPrettyPrinter(SchemaDebugUtil.class); } }