diff --git a/imixs-workflow-engine/src/main/java/org/imixs/workflow/jee/ejb/ReportService.java b/imixs-workflow-engine/src/main/java/org/imixs/workflow/jee/ejb/ReportService.java index 368cb725f..001ab68b5 100644 --- a/imixs-workflow-engine/src/main/java/org/imixs/workflow/jee/ejb/ReportService.java +++ b/imixs-workflow-engine/src/main/java/org/imixs/workflow/jee/ejb/ReportService.java @@ -109,11 +109,8 @@ public ItemCollection getReport(String aReportName) { public List getReportList() { String sQuery = null; sQuery = "SELECT"; - sQuery += " wi FROM Entity as wi " - + " JOIN wi.textItems t " - + " WHERE wi.type = 'ReportEntity' " - + " AND t.itemName='txtname' " - + " ORDER BY t.itemValue ASC"; + sQuery += " wi FROM Entity as wi " + " JOIN wi.textItems t " + " WHERE wi.type = 'ReportEntity' " + + " AND t.itemName='txtname' " + " ORDER BY t.itemValue ASC"; List col = entityService.findAllEntities(sQuery, 0, -1); @@ -265,35 +262,21 @@ public List executeReport(String reportName, int startPos, int m // next we iterate over all entities from the result set and clone // each entity with the given itemList for (ItemCollection entity : result) { - ItemCollection clone = new ItemCollection(); - Set fieldNames = formatMap.keySet(); - for (String field : fieldNames) { - - // first look for converter - String converter = converterMap.get(field); - // did we have a format definition? - if (converter != null) { - entity = convertItemValue(entity, field, converter); - } - - String format = formatMap.get(field); - // did we have a format definition? - if (!format.isEmpty()) { - String sLocale = XMLParser.findAttribute(format, "locale"); - // create string array of formated values - ArrayList vValues = new ArrayList(); - List rawValues = entity.getItemValue(field); - for (Object rawValue : rawValues) { - vValues.add(formatObjectValue(rawValue, format, sLocale)); - } - clone.replaceItemValue(field, vValues); - } else { - // not format definition - clone value as is - clone.replaceItemValue(field, entity.getItemValue(field)); + // in case _ChildItems are requested the entity will be + // duplicated for each child attribute. + // a child item is identified by the '~' char in the item name + List embeddedChildItems = getEmbeddedChildItems(entity, formatMap.keySet()); + if (!embeddedChildItems.isEmpty()){ + for (ItemCollection child: embeddedChildItems) { + ItemCollection clone = cloneEntity(child, formatMap, converterMap); + clonedResult.add(clone); } + } else { + // default - clone the entity + ItemCollection clone = cloneEntity(entity, formatMap, converterMap); + clonedResult.add(clone); } - clonedResult.add(clone); } logger.fine("executed report '" + reportName + "' in " + (System.currentTimeMillis() - l) + "ms"); return clonedResult; @@ -303,6 +286,91 @@ public List executeReport(String reportName, int startPos, int m } } + /** + * This method returns all embedded child items of a entity. The childItem + * are identified by a fieldname containing a '~'. The left part is the + * container item (List of Map), the right part is the attribute name in the + * child itemcollection. + * + * @param entity + * @param keySet + * @return + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private List getEmbeddedChildItems(ItemCollection entity, Set fieldNames) { + List embeddedItemNames = new ArrayList(); + List result = new ArrayList(); + // first find all items containing a child element + for (String field : fieldNames) { + field=field.toLowerCase(); + if (field.contains("~")) { + field = field.substring(0,field.indexOf('~')); + if (!embeddedItemNames.contains(field)) { + embeddedItemNames.add(field); + } + } + } + if (!embeddedItemNames.isEmpty()) { + for (String field : embeddedItemNames) { + List mapChildItems = entity.getItemValue(field); + // try to convert + for (Object mapOderItem : mapChildItems) { + if (mapOderItem instanceof Map) { + ItemCollection child=new ItemCollection((Map)mapOderItem); + // clone entity and add all map entries + ItemCollection clone=new ItemCollection(entity); + Set childFieldNameList = child.getAllItems().keySet(); + for(String childFieldName : childFieldNameList) { + clone.replaceItemValue(field+"~"+childFieldName, child.getItemValue(childFieldName)); + } + result.add(clone); + } + } + } + } + return result; + } + + /** + * This helper method clones a entity with a given format and converter map. + * + * @param formatMap + * @param converterMap + * @param entity + * @return + */ + private ItemCollection cloneEntity(ItemCollection entity, Map formatMap, + Map converterMap) { + ItemCollection clone = new ItemCollection(); + Set fieldNames = formatMap.keySet(); + for (String field : fieldNames) { + // first look for converter + String converter = converterMap.get(field); + // did we have a format definition? + if (converter != null) { + entity = convertItemValue(entity, field, converter); + } + + String format = formatMap.get(field); + // did we have a format definition? + if (!format.isEmpty()) { + String sLocale = XMLParser.findAttribute(format, "locale"); + // create string array of formated values + ArrayList vValues = new ArrayList(); + List rawValues = entity.getItemValue(field); + for (Object rawValue : rawValues) { + vValues.add(formatObjectValue(rawValue, format, sLocale)); + } + clone.replaceItemValue(field, vValues); + + } else { + // not format definition - clone value as is + clone.replaceItemValue(field, entity.getItemValue(field)); + } + } + return clone; + } + /** * This method parses a xml tag and computes a dynamic date by * parsing the attributes: diff --git a/src/site/markdown/modelling/report_plugin.md b/src/site/markdown/modelling/report_plugin.md index 977d415bf..b0f02e2ed 100644 --- a/src/site/markdown/modelling/report_plugin.md +++ b/src/site/markdown/modelling/report_plugin.md @@ -115,6 +115,12 @@ To convert the item value the tag 'convert' can be appended behind the item nam In case the value is not from the specified type (Double, Integer) the value will be converted into a double or integer object. In case the value can not be converted the value will be reset to 0. +### Embedded Child Items +A Workitem can optional contain embedded child items in a single item value. An embedded ChildItem can be named in the attribute list of a report by seperating the ChildItem name from the item name inside the child with a '~'. For example: + + _childItems~amount + +This attribute definition will extend the JPQL result with all embedded Child Items stored in the attribute '_childItems' and containing the item 'amount'. ## The XSL Transformation To transform the result of a report definition into various output formats a XSL template can be added into each report.