/* * Copyright (c) 2010-2015 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.report.impl; import com.evolveum.midpoint.prism.Containerable; import com.evolveum.midpoint.prism.Item; import com.evolveum.midpoint.prism.PrismContainerValue; import com.evolveum.midpoint.prism.PrismObjectValue; import com.evolveum.midpoint.prism.PrismPropertyValue; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.PrismValue; import com.evolveum.midpoint.prism.path.ItemPathSegment; import com.evolveum.midpoint.prism.path.NameItemPathSegment; import java.io.File; import java.sql.Timestamp; import java.text.SimpleDateFormat; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.ResourceBundle; import javax.xml.datatype.XMLGregorianCalendar; import javax.xml.namespace.QName; import com.evolveum.midpoint.xml.ns._public.common.common_3.AccessCertificationResponseType; import com.evolveum.midpoint.xml.ns._public.common.common_3.EvaluatedPolicyRuleTriggerType; import com.evolveum.midpoint.xml.ns._public.common.common_3.EvaluatedSituationTriggerType; import com.evolveum.midpoint.xml.ns._public.common.common_3.EvaluatedExclusionTriggerType; import org.apache.commons.lang.StringUtils; import com.evolveum.midpoint.util.PrettyPrinter; import com.evolveum.midpoint.util.exception.SchemaException; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.xml.ns._public.common.common_3.MetadataType; 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.ReportType; 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.ModificationTypeType; import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType; import com.evolveum.prism.xml.ns._public.types_3.ProtectedStringType; import com.evolveum.prism.xml.ns._public.types_3.RawType; import java.lang.reflect.Method; import java.util.Iterator; import java.util.Locale; import java.util.MissingResourceException; /** * Utility methods for report. Mostly pretty print functions. Do not use any * "prism" object and anything related to them. Methods has to work with both, * common schema types and extended schema types (prism) * * @author Katarina Valalikova * @author Martin Lizner * */ public class ReportUtils { private static String MIDPOINT_HOME = System.getProperty("midpoint.home"); private static String EXPORT_DIR = MIDPOINT_HOME + "export/"; private static final Trace LOGGER = TraceManager .getTrace(ReportUtils.class); public static Timestamp convertDateTime(XMLGregorianCalendar dateTime) { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); try { timestamp = new Timestamp(dateTime.toGregorianCalendar().getTimeInMillis()); } catch (Exception ex) { LOGGER.trace("Incorrect date time value {}", dateTime); } return timestamp; } public static String prettyPrintForReport(XMLGregorianCalendar dateTime) { if (dateTime == null) { return ""; } SimpleDateFormat formatDate = new SimpleDateFormat(); return formatDate.format(new Date(dateTime.toGregorianCalendar().getTimeInMillis())); } public static String prettyPrintForReport(Date date) { if (date == null) { return ""; } SimpleDateFormat formatDate = new SimpleDateFormat(); return formatDate.format(date); } public static String getDateTime() { Date createDate = new Date(System.currentTimeMillis()); SimpleDateFormat formatDate = new SimpleDateFormat("dd-MM-yyyy hh-mm-ss"); return formatDate.format(createDate); } public static String getReportOutputFilePath(ReportType reportType) { File exportFolder = new File(EXPORT_DIR); if (!exportFolder.exists() || !exportFolder.isDirectory()) { exportFolder.mkdir(); } String output = EXPORT_DIR + reportType.getName().getOrig() + " " + getDateTime(); switch (reportType.getExport()) { case PDF: output = output + ".pdf"; break; case CSV: output = output + ".csv"; break; case XML: output = output + ".xml"; break; case XML_EMBED: output = output + "_embed.xml"; break; case HTML: output = output + ".html"; break; case RTF: output = output + ".rtf"; break; case XLS: output = output + ".xls"; break; case ODT: output = output + ".odt"; break; case ODS: output = output + ".ods"; break; case DOCX: output = output + ".docx"; break; case XLSX: output = output + ".xlsx"; break; case PPTX: output = output + ".pptx"; break; case XHTML: output = output + ".x.html"; break; case JXL: output = output + ".jxl.xls"; break; default: break; } return output; } public static String getPropertyString(String key) { return getPropertyString(key, (String) null); } public static String getPropertyString(String key, String defaultValue) { String val = (defaultValue == null) ? key : defaultValue; ResourceBundle bundle; try { bundle = ResourceBundle.getBundle("localization/schema", new Locale("en", "US")); } catch (MissingResourceException e) { return (defaultValue != null) ? defaultValue : key; //workaround for Jasper Studio } if (bundle != null && bundle.containsKey(key)) { val = bundle.getString(key); } return val; } public static String getPropertyString(String key, Object values, String defaultValue) { if (key == null || values == null) { return defaultValue; } if (!List.class.isAssignableFrom(values.getClass())) { return getPropertyString((key.endsWith(".") ? key + values.toString() : key + "." + values.toString()), defaultValue); } List listValues= (List) values; StringBuilder builder = new StringBuilder(); Iterator<Object> objects = listValues.iterator(); ResourceBundle bundle; try { bundle = ResourceBundle.getBundle("localization/schema", new Locale("en", "US")); } catch (MissingResourceException e) { return defaultValue.toString() != null ? defaultValue.toString() : key; // workaround for Jasper Studio } while (objects.hasNext()) { Object o = objects.next(); if (o.getClass().isEnum()) { String constructedKey = (key.endsWith(".")) ? key + ((Enum) o).name(): key +"." + ((Enum) o).name(); if (bundle != null && bundle.containsKey(constructedKey)) { builder.append(bundle.getString(constructedKey)); } else { builder.append(prettyPrintForReport(o)); } } else { String constructedKey = (key.endsWith(".")) ? key + o.toString() : key + "." + o.toString(); if (bundle != null && bundle.containsKey(key)) { builder.append(bundle.getString(constructedKey)); } else { builder.append(prettyPrintForReport(o)); } } if (objects.hasNext()) { builder.append(", "); } } return builder.toString(); } public static String prettyPrintForReport(QName qname) { String ret = ""; if (qname.getLocalPart() != null) { ret = qname.getLocalPart(); } return ret; } public static String prettyPrintForReport(ProtectedStringType pst) { return "*****"; } public static String prettyPrintForReport(PrismPropertyValue ppv) { String retPPV; try { retPPV = prettyPrintForReport(ppv.getValue()); } catch (Throwable t) { return "N/A"; // rare case e.g. for password-type in resource } return retPPV; } public static String prettyPrintForReport(PrismContainerValue pcv) { StringBuilder sb = new StringBuilder(); for (Iterator<Item> iter = pcv.getItems().iterator(); iter.hasNext();) { Item item = iter.next(); if ("metadata".equals(item.getElementName().getLocalPart())) { continue; } sb.append(prettyPrintForReport(item.getElementName())); sb.append("="); sb.append("{"); for (Iterator iter2 = item.getValues().iterator(); iter2.hasNext();) { Object item2 = iter2.next(); sb.append(prettyPrintForReport(item2)); sb.append(", "); } sb.setLength(Math.max(sb.length() - 2, 0)); // delete last delimiter sb.append("}"); sb.append(", "); } sb.setLength(Math.max(sb.length() - 2, 0)); // delete last delimiter return sb.toString(); } public static String prettyPrintForReport(PrismReferenceValue prv) { return prettyPrintForReport(prv, true); } public static String prettyPrintForReport(PrismReferenceValue prv, boolean showType) { StringBuilder sb = new StringBuilder(); if (showType) { sb.append(getTypeDisplayName(prv.getTargetType())); sb.append(": "); } if (prv.getTargetName() != null) { sb.append(prv.getTargetName()); } else { sb.append(prv.getOid()); } return sb.toString(); } public static String prettyPrintForReport(ObjectReferenceType prv) { return prettyPrintForReport(prv, true); } public static String prettyPrintForReport(ObjectReferenceType prv, boolean showType) { if (prv == null) { return ""; } StringBuilder sb = new StringBuilder(); if (showType || prv.getTargetName() == null) { sb.append(getTypeDisplayName(prv.getType())); sb.append(": "); } if (prv.getTargetName() != null) { sb.append(prv.getTargetName()); } else { sb.append(prv.getOid()); } return sb.toString(); } public static String prettyPrintUsersForReport(List<ObjectReferenceType> userRefList) { StringBuilder sb = new StringBuilder(); boolean first = true; for (ObjectReferenceType userRef : userRefList) { if (first) { first = false; } else { sb.append(", "); } sb.append(prettyPrintForReport(userRef, false)); } return sb.toString(); } public static String prettyPrintForReport(OperationResultType ort) { StringBuilder sb = new StringBuilder(); if (ort.getOperation() != null) { sb.append(ort.getOperation()); sb.append(" "); } //sb.append(ort.getParams()); //IMPROVE_ME: implement prettyPrint for List<EntryType> //sb.append(" "); if (ort.getMessage() != null) { sb.append(ort.getMessage()); sb.append(" "); } sb.append(ort.getStatus()); return sb.toString(); } public static String prettyPrintForReport(byte[] ba) { if (ba == null) { return "null"; } return "[" + ((byte[]) ba).length + " bytes]"; //Jasper doesnt like byte[] } public static String prettyPrintForReport(Collection prismValueList) { StringBuilder sb = new StringBuilder(); for (Object pv : prismValueList) { String ps = prettyPrintForReport(pv); if (!ps.isEmpty()) { sb.append(ps); sb.append("#"); } } sb.setLength(Math.max(sb.length() - 1, 0)); // delete last # delimiter return sb.toString(); } /* Multiplexer method for various input classes, using Reflection - Mostly Copied from com.evolveum.midpoint.util.PrettyPrinter - Credit goes to Evolveum */ public static String prettyPrintForReport(Object value) { if (value == null) { return ""; } if (value instanceof MetadataType) { return ""; } //special handling for byte[], some problems with jasper when printing if (byte[].class.equals(value.getClass())) { return prettyPrintForReport((byte[]) value); } // 1. Try to find prettyPrintForReport in this class first if (value instanceof Containerable) { //e.g. RoleType needs to be converted to PCV in order to format properly value = (((Containerable) value).asPrismContainerValue()); } for (Method method : ReportUtils.class.getMethods()) { if (method.getName().equals("prettyPrintForReport")) { Class<?>[] parameterTypes = method.getParameterTypes(); if (parameterTypes.length == 1 && parameterTypes[0].equals(value.getClass())) { try { return (String) method.invoke(null, value); } catch (Throwable e) { return "###INTERNAL#ERROR### " + e.getClass().getName() + ": " + e.getMessage() + "; prettyPrintForReport method for value " + value; } } } } // 2. Default to PrettyPrinter.prettyPrint String str = PrettyPrinter.prettyPrint(value); if (str.length() > 1000) { return str.substring(0, 1000); } return str; } private static String printItemDeltaValues(ItemDeltaType itemDelta) { List values = itemDelta.getValue(); StringBuilder sb = new StringBuilder(); for (Object value : values) { String v = printItemDeltaValue(itemDelta.getPath(), value); if (StringUtils.isNotBlank(v)) { sb.append(v); sb.append(", "); } } sb.setLength(Math.max(sb.length() - 2, 0)); // delete last delimiter return sb.toString(); } private static String printItemDeltaValue(ItemPathType itemPath, Object value) { if (value instanceof MetadataType) { return ""; } else if (value instanceof RawType) { try { if (isMetadata(itemPath)) { return ""; } Object parsedRealValue = ((RawType) value).getParsedRealValue(null, itemPath.getItemPath()); if (parsedRealValue instanceof Containerable) { // this is for PCV return prettyPrintForReport(((Containerable) parsedRealValue).asPrismContainerValue()); } return prettyPrintForReport(parsedRealValue); } catch (SchemaException e) { return "###INTERNAL#ERROR### " + e.getClass().getName() + ": " + e.getMessage() + "; prettyPrintForReport method for value " + value; } catch (RuntimeException e) { return "###INTERNAL#ERROR### " + e.getClass().getName() + ": " + e.getMessage() + "; prettyPrintForReport method for value " + value; } catch (Exception e) { return "###INTERNAL#ERROR### " + e.getClass().getName() + ": " + e.getMessage() + "; prettyPrintForReport method for value " + value; } } else { return prettyPrintForReport(value); } } private static String printItemDeltaOldValues(ItemPathType itemPath, List values) { StringBuilder sb = new StringBuilder(); for (Object value : values) { String v = printItemDeltaValue(itemPath, value); if (StringUtils.isNotBlank(v)) { sb.append(v); sb.append(", "); } } sb.setLength(Math.max(sb.length() - 2, 0)); // delete last delimiter return sb.toString(); } private static boolean isMetadata(ItemDeltaType itemDelta) { List values = itemDelta.getValue(); for (Object v : values) { if (v instanceof MetadataType) { return true; } else if (v instanceof RawType) { return isMetadata(itemDelta.getPath()); } } return false; } private static boolean isMetadata(ItemPathType itemPath) { boolean retMeta = false; for (ItemPathSegment ips : itemPath.getItemPath().getSegments()) { if (ips instanceof NameItemPathSegment && "metadata".equals(((NameItemPathSegment) ips).getName().getLocalPart())) { return true; } } return retMeta; } public static String prettyPrintForReport(ItemDeltaType itemDelta) { StringBuilder sb = new StringBuilder(); boolean displayNA = false; if (isMetadata(itemDelta)) { return sb.toString(); } sb.append(">>> "); sb.append(itemDelta.getPath()); sb.append("="); sb.append("{"); if (itemDelta.getEstimatedOldValue() != null && !itemDelta.getEstimatedOldValue().isEmpty()) { sb.append("Old: "); sb.append("{"); sb.append(printItemDeltaOldValues(itemDelta.getPath(), itemDelta.getEstimatedOldValue())); sb.append("}"); sb.append(", "); displayNA = true; } if (itemDelta.getModificationType() == ModificationTypeType.REPLACE) { sb.append("Replace: "); sb.append("{"); sb.append(printItemDeltaValues(itemDelta)); sb.append("}"); sb.append(", "); displayNA = false; } if (itemDelta.getModificationType() == ModificationTypeType.DELETE) { sb.append("Delete: "); sb.append("{"); sb.append(printItemDeltaValues(itemDelta)); sb.append("}"); sb.append(", "); displayNA = false; } if (itemDelta.getModificationType() == ModificationTypeType.ADD) { sb.append("Add: "); sb.append("{"); sb.append(printItemDeltaValues(itemDelta)); sb.append("}"); sb.append(", "); displayNA = false; } if (displayNA) { sb.append("N/A"); // this is rare case when oldValue is present but replace, delete and add lists are all null } else { sb.setLength(Math.max(sb.length() - 2, 0)); } sb.append("}"); sb.append("\n"); return sb.toString(); } public static String getBusinessDisplayName(ObjectReferenceType ort) { return ort.getDescription(); } private static String printChangeType(String objectName, ObjectDeltaType delta, String opName, String resourceName) { StringBuilder sb = new StringBuilder(); sb.append(opName); sb.append(" "); sb.append(delta.getObjectType().getLocalPart()); if (StringUtils.isNotBlank(objectName)) { sb.append(": "); sb.append(objectName); } else if (delta.getOid() != null) { sb.append(": "); sb.append(delta.getOid()); } if (StringUtils.isNotBlank(resourceName)) { sb.append(" - "); sb.append("Resource: "); sb.append(resourceName); } sb.append("\n"); return sb.toString(); } public static String printDelta(List<ObjectDeltaType> delta) { StringBuilder sb = new StringBuilder(); for (ObjectDeltaType d : delta) { sb.append(printDelta(d, null, null)); sb.append("\n"); } return sb.toString(); } public static String printDelta(ObjectDeltaType delta, String objectName, String resourceName) { StringBuilder sb = new StringBuilder(); switch (delta.getChangeType()) { case MODIFY: Collection<ItemDeltaType> modificationDeltas = delta.getItemDelta(); if (modificationDeltas != null && !modificationDeltas.isEmpty()) { sb.append(printChangeType(objectName, delta, "Modify", resourceName)); } for (ItemDeltaType itemDelta : modificationDeltas) { sb.append(prettyPrintForReport(itemDelta)); } sb.setLength(Math.max(sb.length() - 1, 0)); break; case ADD: ObjectType objectToAdd = (ObjectType) delta.getObjectToAdd(); if (objectToAdd != null) { sb.append(printChangeType(objectName, delta, "Add", resourceName)); if (objectToAdd.getName() != null) { sb.append(prettyPrintForReport(objectToAdd.getClass().getSimpleName())); sb.append("="); sb.append(objectToAdd.getName().toString()); } sb.append(" {"); sb.append(prettyPrintForReport(objectToAdd)); sb.append("}"); } break; case DELETE: sb.append(printChangeType(objectName, delta, "Delete", resourceName)); break; } return sb.toString(); } public static String join(Collection<String> strings) { return StringUtils.join(strings, ", "); } public static Object getItemRealValue(PrismContainerValue containerValue, String itemName) { Item item = containerValue.findItem(new QName(itemName)); if (item == null || item.size() == 0) { return null; } if (item.size() > 1) { throw new IllegalStateException("More than one value in item " + item); } PrismValue value = item.getValue(0); if (value == null) { return null; } if (value instanceof PrismPropertyValue) { return ((PrismPropertyValue) value).getValue(); } else if (value instanceof PrismReferenceValue) { ObjectReferenceType ort = new ObjectReferenceType(); ort.setupReferenceValue((PrismReferenceValue) value); return ort; } else if (value instanceof PrismContainerValue) { return ((PrismContainerValue) value).asContainerable(); // questionable } else { throw new IllegalStateException("Unknown PrismValue: " + value); } } public static String prettyPrintForReport(AccessCertificationResponseType response) { if (response == null || response == AccessCertificationResponseType.NO_RESPONSE) { return ""; } return getPropertyString("AccessCertificationResponseType."+response.name()); } public static String prettyPrintForReport(EvaluatedPolicyRuleTriggerType trigger) { return prettyPrintRuleTriggerForReport(trigger); } public static String prettyPrintForReport(EvaluatedSituationTriggerType trigger) { return prettyPrintRuleTriggerForReport(trigger); } public static String prettyPrintForReport(EvaluatedExclusionTriggerType trigger) { return prettyPrintRuleTriggerForReport(trigger); } public static String prettyPrintForReport(PrismObjectValue pov) { return prettyPrintForReport((PrismContainerValue) pov); } private static String prettyPrintRuleTriggerForReport(EvaluatedPolicyRuleTriggerType trigger) { if (trigger == null) { return ""; } return "Rule: " + (trigger.getRuleName()!=null?trigger.getRuleName():"N/A"); } public static String prettyPrintForReport(Enum e) { if (e == null) { return ""; } return getPropertyString(e.getClass().getSimpleName()+"."+e.name(), e.name()); } public static String getTypeDisplayName(QName typeName) { if (typeName == null) { return null; } return getPropertyString("ObjectType." + typeName.getLocalPart(), typeName.getLocalPart()); } }