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 4efa79f994..7a7337f4c3 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 @@ -46,8 +46,7 @@ + class="AuditQueryResult"> diff --git a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java index 40ae76eda7..ad4182ab3c 100644 --- a/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/audit/AbstractAuditDAOImpl.java @@ -38,6 +38,7 @@ import org.alfresco.repo.audit.AuditState; import org.alfresco.repo.audit.hibernate.HibernateAuditDAO; import org.alfresco.repo.content.MimetypeMap; import org.alfresco.repo.domain.contentdata.ContentDataDAO; +import org.alfresco.repo.domain.propval.PropertyIdSearchRow; import org.alfresco.repo.domain.propval.PropertyValueDAO; import org.alfresco.service.cmr.audit.AuditInfo; import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback; @@ -298,15 +299,39 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO return; } // Get the value map - // TODO: Should be done with a nested resultmapping - Long auditValuesId = row.getAuditValuesId(); - Pair auditValuesPair = propertyValueDAO.getPropertyValueById(auditValuesId); - if (auditValuesPair == null) + Map auditValues; + List propMapRows = row.getAuditValues(); + if (propMapRows == null) { - // Ignore - 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(); + } + else + { + // Resolve the map + try + { + auditValues = (Map) propertyValueDAO.convertPropertyIdSearchRows(propMapRows); + } + catch (ClassCastException e) + { + logger.warn("Audit entry not linked to a Map value: " + row); + return; + } + if (auditValues == null) + { + logger.warn("Audit entry incompletely joined to audit properties: " + row); + return; + } } - Map auditValues = (Map) auditValuesPair.getSecond(); more = callback.handleAuditEntry( row.getAuditEntryId(), row.getAuditAppName(), 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 372978f39a..ed00c30894 100644 --- a/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/audit/ibatis/AuditDAOImpl.java @@ -29,6 +29,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import org.alfresco.ibatis.RollupRowHandler; import org.alfresco.repo.domain.audit.AbstractAuditDAOImpl; import org.alfresco.repo.domain.audit.AuditApplicationEntity; import org.alfresco.repo.domain.audit.AuditEntryEntity; @@ -175,25 +176,38 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl params.setAuditFromTime(from); params.setAuditToTime(to); + // 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) { - List rows = template.queryForList(SELECT_ENTRIES_SIMPLE, params, 0, maxResults); + // Calculate the maximum results required + int sqlMaxResults = (maxResults > 0 ? ((maxResults+1) * 20) : Integer.MAX_VALUE); + + List rows = template.queryForList(SELECT_ENTRIES_WITH_VALUES, params, 0, sqlMaxResults); for (AuditQueryResult row : rows) { - rowHandler.processResult(row); + rollupRowHandler.handleRow(row); } + // Don't process last result: + // rollupRowHandler.processLastResults(); + // The last result may be incomplete } else { - RowHandler rowHandlerInternal = new RowHandler() - { - public void handleRow(Object valueObject) - { - AuditQueryResult row = (AuditQueryResult) valueObject; - rowHandler.processResult(row); - } - }; - template.queryWithRowHandler(SELECT_ENTRIES_SIMPLE, params, rowHandlerInternal); + template.queryWithRowHandler(SELECT_ENTRIES_WITH_VALUES, params, rollupRowHandler); + rollupRowHandler.processLastResults(); } } } diff --git a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java index 7a4f51ea74..4f9b612a08 100644 --- a/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java +++ b/source/java/org/alfresco/repo/domain/propval/AbstractPropertyValueDAOImpl.java @@ -833,7 +833,7 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO protected abstract PropertyValueEntity createPropertyValue(Serializable value); @SuppressWarnings("unchecked") - protected Serializable convertPropertyIdSearchRows(List rows) + public Serializable convertPropertyIdSearchRows(List rows) { /* * The results are ordered by the root_prop_id, current_prop_id and value_prop_id. @@ -843,8 +843,21 @@ public abstract class AbstractPropertyValueDAOImpl implements PropertyValueDAO final Map values = new HashMap(rows.size()); List keyRows = new ArrayList(5); Serializable result = null; + Long rootPropId = null; for (PropertyIdSearchRow row : rows) { + // Check that we are handling a single root property + if (rootPropId == null) + { + rootPropId = row.getLinkEntity().getRootPropId(); + } + else if (!rootPropId.equals(row.getLinkEntity().getRootPropId())) + { + throw new IllegalArgumentException( + "The root_prop_id for the property search rows must not change: \n" + + " Rows: " + rows); + } + PropertyLinkEntity linkEntity = row.getLinkEntity(); PropertyValueEntity valueEntity = row.getValueEntity(); // Construct the value (Maps and Collections should be CONSTRUCTABLE) diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyIdSearchRow.java b/source/java/org/alfresco/repo/domain/propval/PropertyIdSearchRow.java index 44c06c2253..cb7b76ed8a 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyIdSearchRow.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyIdSearchRow.java @@ -43,34 +43,6 @@ public class PropertyIdSearchRow valueEntity = new PropertyValueEntity(); } -// @Override -// public int hashCode() -// { -// return (int) rootCollectionPropId + (int) valuePropId; -// } -// -// @Override -// public boolean equals(Object obj) -// { -// if (this == obj) -// { -// return true; -// } -// else if (obj instanceof PropertyCollectionLinkEntity) -// { -// PropertyCollectionLinkEntity that = (PropertyCollectionLinkEntity) obj; -// return -// this.rootCollectionPropId == that.rootCollectionPropId && -// this.currentCollectionPropId == that.currentCollectionPropId && -// this.valuePropId == that.valuePropId && -// this.keyPropId == that.keyPropId; -// } -// else -// { -// return false; -// } -// } -// @Override public String toString() { diff --git a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java index 7d20dc5bad..831b8f325e 100644 --- a/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java +++ b/source/java/org/alfresco/repo/domain/propval/PropertyValueDAO.java @@ -26,6 +26,7 @@ package org.alfresco.repo.domain.propval; import java.io.Serializable; import java.util.Date; +import java.util.List; import org.alfresco.repo.domain.CrcHelper; import org.alfresco.util.Pair; @@ -195,4 +196,18 @@ public interface PropertyValueDAO * @param maxDepth the maximum depth of collections and maps to iterate into */ Pair getOrCreatePropertyValue(Serializable value, int maxDepth); + + /** + * Utility method to convert property query results into the original value. Note + * that the rows must all share the same root property ID. + *

+ * If the rows passed in don't constitute a valid, full property - they don't contain all + * the link entities for the property - then the result may be null. + * + * @param rows the search results for a single root property + * @return Returns the root property as originally persisted, or null + * if the rows don't represent a complete property + * @throws IllegalArgumentException if rows don't all share the same root property ID + */ + Serializable convertPropertyIdSearchRows(List rows); }