diff --git a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/audit-common-SqlMap.xml b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/audit-common-SqlMap.xml index 2d62f3729a..5d822884be 100644 --- a/config/alfresco/ibatis/org.hibernate.dialect.Dialect/audit-common-SqlMap.xml +++ b/config/alfresco/ibatis/org.hibernate.dialect.Dialect/audit-common-SqlMap.xml @@ -50,7 +50,7 @@ - + @@ -203,4 +203,45 @@ + + + \ No newline at end of file diff --git a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java index 0da6e996ef..d08c096708 100644 --- a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java @@ -370,43 +370,46 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO // No more results required return; } - // Get the value map - Map auditValues; - List propMapRows = row.getAuditValues(); - if (propMapRows == null) + // See if the value is available or if it has to be built up + Map auditValues = row.getAuditValue(); + if (auditValues == null) { - // Use the audit values ID - Long auditValuesId = row.getAuditValuesId(); - Pair auditValuesPair = propertyValueDAO.getPropertyValueById(auditValuesId); - if (auditValuesPair == null) + List propMapRows = row.getAuditValueRows(); + if (propMapRows == null) { - // Ignore - logger.warn("Audit entry not joined to audit properties: " + row); - return; + // Use the audit values ID + Long auditValuesId = row.getAuditValuesId(); + Pair auditValuesPair = propertyValueDAO.getPropertyValueById(auditValuesId); + if (auditValuesPair == null) + { + // Ignore + logger.warn("Audit entry not joined to audit properties: " + row); + return; + } + auditValues = (Map) auditValuesPair.getSecond(); } - auditValues = (Map) auditValuesPair.getSecond(); - } - else - { - // Resolve the map - try + else { - auditValues = (Map) propertyValueDAO.convertPropertyIdSearchRows(propMapRows); - } - catch (ClassCastException e) - { - logger.warn("Audit entry not linked to a Map value: " + row); - return; - } - catch (Throwable e) - { - logger.warn("Audit entry unable to extract audited values: " + row, e); - return; - } - if (auditValues == null) - { - logger.warn("Audit entry incompletely joined to audit properties: " + row); - return; + // Resolve the map + try + { + auditValues = (Map) propertyValueDAO.convertPropertyIdSearchRows(propMapRows); + } + catch (ClassCastException e) + { + logger.warn("Audit entry not linked to a Map value: " + row); + return; + } + catch (Throwable e) + { + logger.warn("Audit entry unable to extract audited values: " + row, e); + return; + } + if (auditValues == null) + { + logger.warn("Audit entry incompletely joined to audit properties: " + row); + return; + } } } // Resolve the application and username diff --git a/source/java/org/alfresco/repo/domain/audit/AuditQueryResult.java b/source/java/org/alfresco/repo/domain/audit/AuditQueryResult.java index 933667fa24..5fe57d8c53 100644 --- a/source/java/org/alfresco/repo/domain/audit/AuditQueryResult.java +++ b/source/java/org/alfresco/repo/domain/audit/AuditQueryResult.java @@ -24,8 +24,10 @@ */ package org.alfresco.repo.domain.audit; +import java.io.Serializable; import java.util.Date; import java.util.List; +import java.util.Map; import org.alfresco.repo.domain.propval.PropertyIdSearchRow; @@ -42,7 +44,8 @@ public class AuditQueryResult private Long auditUserId; private long auditTime; private Long auditValuesId; - private List auditValues; + private List auditValueRows; + private Map auditValue; public AuditQueryResult() { @@ -58,7 +61,8 @@ public class AuditQueryResult .append(", auditUserId=").append(auditUserId) .append(", auditTime").append(new Date(auditTime)) .append(", auditValuesId=").append(auditValuesId) - .append(", auditValues=").append(auditValues.size()) + .append(", auditValueRows=").append(auditValueRows == null ? null : auditValueRows.size()) + .append(", auditValue=").append(auditValue) .append("]"); return sb.toString(); } @@ -113,13 +117,23 @@ public class AuditQueryResult this.auditValuesId = auditValuesId; } - public List getAuditValues() + public List getAuditValueRows() { - return auditValues; + return auditValueRows; } - public void setAuditValues(List auditValues) + public void setAuditValueRows(List auditValueRows) { - this.auditValues = auditValues; + this.auditValueRows = auditValueRows; + } + + public Map getAuditValue() + { + return auditValue; + } + + public void setAuditValue(Map auditValue) + { + this.auditValue = auditValue; } } diff --git a/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java b/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java index 2db901ce41..db92801fd9 100644 --- a/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java @@ -25,9 +25,11 @@ package org.alfresco.repo.domain.audit.ibatis; import java.io.Serializable; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.TreeMap; import org.alfresco.ibatis.RollupRowHandler; import org.alfresco.repo.domain.audit.AbstractAuditDAOImpl; @@ -37,6 +39,7 @@ import org.alfresco.repo.domain.audit.AuditEntryEntity; import org.alfresco.repo.domain.audit.AuditModelEntity; import org.alfresco.repo.domain.audit.AuditQueryParameters; import org.alfresco.repo.domain.audit.AuditQueryResult; +import org.alfresco.repo.domain.propval.PropertyValueDAO.PropertyFinderCallback; import org.alfresco.util.Pair; import org.springframework.orm.ibatis.SqlMapClientTemplate; @@ -64,6 +67,7 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl @SuppressWarnings("unused") private static final String SELECT_ENTRIES_SIMPLE = "alfresco.audit.select_AuditEntriesSimple"; private static final String SELECT_ENTRIES_WITH_VALUES = "alfresco.audit.select_AuditEntriesWithValues"; + private static final String SELECT_ENTRIES_WITHOUT_VALUES = "alfresco.audit.select_AuditEntriesWithoutValues"; private SqlMapClientTemplate template; @@ -241,36 +245,66 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl params.setSearchValueId(searchValuePair.getFirst()); } - // RowHandlers in RowHandlers: See 'groupBy' issue https://issues.apache.org/jira/browse/IBATIS-503 - RowHandler shreddedRowHandler = new RowHandler() - { - public void handleRow(Object valueObject) - { - rowHandler.processResult((AuditQueryResult)valueObject); - } - }; - RollupRowHandler rollupRowHandler = new RollupRowHandler( - new String[] {"auditEntryId"}, - "auditValues", - shreddedRowHandler, - maxResults); - if (maxResults > 0) { - // Calculate the maximum results required - int sqlMaxResults = (maxResults > 0 ? ((maxResults+1) * 100) : Integer.MAX_VALUE); - - List rows = template.queryForList(SELECT_ENTRIES_WITH_VALUES, params, 0, sqlMaxResults); + // Query without getting the values. We gather all the results and batch-fetch the audited + // values afterwards. + final TreeMap resultsByValueId = new TreeMap(); + PropertyFinderCallback propertyFinderCallback = new PropertyFinderCallback() + { + public void handleProperty(Long id, Serializable value) + { + // get the row + AuditQueryResult row = resultsByValueId.get(id); + try + { + row.setAuditValue((Map) value); + } + catch (ClassCastException e) + { + // The handler will deal with the entry + } + rowHandler.processResult(row); + } + }; + + List rows = template.queryForList(SELECT_ENTRIES_WITHOUT_VALUES, params, 0, maxResults); for (AuditQueryResult row : rows) { - rollupRowHandler.handleRow(row); + resultsByValueId.put(row.getAuditValuesId(), row); + if (resultsByValueId.size() >= 100) + { + // Fetch values for the results. The treemap is ordered. + List valueIds = new ArrayList(resultsByValueId.keySet()); + propertyValueDAO.getPropertiesByIds(valueIds, propertyFinderCallback); + // Clear and continue + resultsByValueId.clear(); + } + } + // Process any remaining results + if (resultsByValueId.size() > 0) + { + // Fetch values for the results. The treemap is ordered. + List valueIds = new ArrayList(resultsByValueId.keySet()); + propertyValueDAO.getPropertiesByIds(valueIds, propertyFinderCallback); } - // Don't process last result: - // rollupRowHandler.processLastResults(); - // The last result may be incomplete } else { + // RowHandlers in RowHandlers: See 'groupBy' issue https://issues.apache.org/jira/browse/IBATIS-503 + RowHandler queryRowHandler = new RowHandler() + { + public void handleRow(Object valueObject) + { + rowHandler.processResult((AuditQueryResult)valueObject); + } + }; + RollupRowHandler rollupRowHandler = new RollupRowHandler( + new String[] {"auditEntryId"}, + "auditValueRows", + queryRowHandler, + maxResults); + template.queryWithRowHandler(SELECT_ENTRIES_WITH_VALUES, params, rollupRowHandler); rollupRowHandler.processLastResults(); }