Final fix for MOB-1609: Incorrect number of results returned from audit log

- When the query size is limited, the DB query returns only the audit entries
 - The audited properties are pulled back in batches


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16567 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-09-28 17:58:37 +00:00
parent a58c74a04a
commit 5b8650fb4b
4 changed files with 154 additions and 62 deletions

View File

@@ -370,43 +370,46 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
// No more results required
return;
}
// Get the value map
Map<String, Serializable> auditValues;
List<PropertyIdSearchRow> propMapRows = row.getAuditValues();
if (propMapRows == null)
// See if the value is available or if it has to be built up
Map<String, Serializable> auditValues = row.getAuditValue();
if (auditValues == null)
{
// Use the audit values ID
Long auditValuesId = row.getAuditValuesId();
Pair<Long, Serializable> auditValuesPair = propertyValueDAO.getPropertyValueById(auditValuesId);
if (auditValuesPair == null)
List<PropertyIdSearchRow> 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<Long, Serializable> auditValuesPair = propertyValueDAO.getPropertyValueById(auditValuesId);
if (auditValuesPair == null)
{
// Ignore
logger.warn("Audit entry not joined to audit properties: " + row);
return;
}
auditValues = (Map<String, Serializable>) auditValuesPair.getSecond();
}
auditValues = (Map<String, Serializable>) auditValuesPair.getSecond();
}
else
{
// Resolve the map
try
else
{
auditValues = (Map<String, Serializable>) propertyValueDAO.convertPropertyIdSearchRows(propMapRows);
}
catch (ClassCastException e)
{
logger.warn("Audit entry not linked to a Map<String, Serializable> 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<String, Serializable>) propertyValueDAO.convertPropertyIdSearchRows(propMapRows);
}
catch (ClassCastException e)
{
logger.warn("Audit entry not linked to a Map<String, Serializable> 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

View File

@@ -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<PropertyIdSearchRow> auditValues;
private List<PropertyIdSearchRow> auditValueRows;
private Map<String, Serializable> 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<PropertyIdSearchRow> getAuditValues()
public List<PropertyIdSearchRow> getAuditValueRows()
{
return auditValues;
return auditValueRows;
}
public void setAuditValues(List<PropertyIdSearchRow> auditValues)
public void setAuditValueRows(List<PropertyIdSearchRow> auditValueRows)
{
this.auditValues = auditValues;
this.auditValueRows = auditValueRows;
}
public Map<String, Serializable> getAuditValue()
{
return auditValue;
}
public void setAuditValue(Map<String, Serializable> auditValue)
{
this.auditValue = auditValue;
}
}

View File

@@ -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<AuditQueryResult> 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<Long, AuditQueryResult> resultsByValueId = new TreeMap<Long, AuditQueryResult>();
PropertyFinderCallback propertyFinderCallback = new PropertyFinderCallback()
{
public void handleProperty(Long id, Serializable value)
{
// get the row
AuditQueryResult row = resultsByValueId.get(id);
try
{
row.setAuditValue((Map<String, Serializable>) value);
}
catch (ClassCastException e)
{
// The handler will deal with the entry
}
rowHandler.processResult(row);
}
};
List<AuditQueryResult> 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<Long> valueIds = new ArrayList<Long>(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<Long> valueIds = new ArrayList<Long>(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();
}