Fixed MOB-1656: Audit Log: Log ordering is incorrect for "Last N" results

- Added option to have results in either ascending or descending order
 - RM uses descending listings where the query results are limited


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@16628 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-09-30 15:56:05 +00:00
parent 77457e3670
commit 7bc361268d
12 changed files with 169 additions and 36 deletions

View File

@@ -201,6 +201,14 @@
sp_mpl.value_prop_id = #searchValueId# sp_mpl.value_prop_id = #searchValueId#
</isNotNull> </isNotNull>
</dynamic> </dynamic>
<isEqual property="forward" compareProperty="forwardTrue">
order by
entry.id asc
</isEqual>
<isNotEqual property="forward" compareProperty="forwardTrue">
order by
entry.id desc
</isNotEqual>
</select> </select>
<!-- Get audit entries --> <!-- Get audit entries -->
@@ -242,6 +250,14 @@
sp_mpl.value_prop_id = #searchValueId# sp_mpl.value_prop_id = #searchValueId#
</isNotNull> </isNotNull>
</dynamic> </dynamic>
<isEqual property="forward" compareProperty="forwardTrue">
order by
entry.id asc
</isEqual>
<isNotEqual property="forward" compareProperty="forwardTrue">
order by
entry.id desc
</isNotEqual>
</select> </select>
</sqlMap> </sqlMap>

View File

@@ -188,6 +188,8 @@ public interface AuditComponent
* Get the audit entries that match the given criteria. * Get the audit entries that match the given criteria.
* *
* @param callback the callback that will handle results * @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application * @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user * @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning) * @param from the start search time (<tt>null</tt> to start at the beginning)
@@ -198,6 +200,7 @@ public interface AuditComponent
*/ */
void auditQuery( void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
int maxResults); int maxResults);
@@ -205,6 +208,8 @@ public interface AuditComponent
* Get the audit entries that match the given criteria. * Get the audit entries that match the given criteria.
* *
* @param callback the callback that will handle results * @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application * @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user * @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning) * @param from the start search time (<tt>null</tt> to start at the beginning)
@@ -217,6 +222,7 @@ public interface AuditComponent
*/ */
void auditQuery( void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults); int maxResults);

View File

@@ -1323,6 +1323,7 @@ public class AuditComponentImpl implements AuditComponent
*/ */
public void auditQuery( public void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String applicationName,
String user, String user,
Long from, Long from,
@@ -1338,7 +1339,8 @@ public class AuditComponentImpl implements AuditComponent
return; return;
} }
auditDAO.findAuditEntries(callback, applicationName, user, from, to, maxResults); auditDAO.findAuditEntries(
callback, forward, applicationName, user, from, to, maxResults);
} }
/** /**
@@ -1346,6 +1348,7 @@ public class AuditComponentImpl implements AuditComponent
*/ */
public void auditQuery( public void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String applicationName,
String user, String user,
Long from, Long from,
@@ -1362,6 +1365,7 @@ public class AuditComponentImpl implements AuditComponent
return; return;
} }
auditDAO.findAuditEntries(callback, applicationName, user, from, to, searchKey, searchValue, maxResults); auditDAO.findAuditEntries(
callback, forward, applicationName, user, from, to, searchKey, searchValue, maxResults);
} }
} }

View File

@@ -35,6 +35,7 @@ import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.audit.model.AuditApplication; import org.alfresco.repo.audit.model.AuditApplication;
import org.alfresco.repo.audit.model.AuditModelException; import org.alfresco.repo.audit.model.AuditModelException;
import org.alfresco.repo.audit.model.AuditModelRegistry; import org.alfresco.repo.audit.model.AuditModelRegistry;
@@ -328,11 +329,16 @@ public class AuditComponentTest extends TestCase
rowCount.setValue(rowCount.intValue() + 1); rowCount.setValue(rowCount.intValue() + 1);
return true; return true;
} }
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
{
throw new AlfrescoRuntimeException(errorMsg, error);
}
}; };
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, null, null, null, -1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, null, null, null, -1);
assertTrue("Expected some data", rowCount.intValue() > 0); assertTrue("Expected some data", rowCount.intValue() > 0);
logger.debug(sb.toString()); logger.debug(sb.toString());
int allResults = rowCount.intValue(); int allResults = rowCount.intValue();
@@ -340,21 +346,21 @@ public class AuditComponentTest extends TestCase
// Limit by count // Limit by count
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, null, null, null, 1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, null, null, null, 1);
assertEquals("Expected to limit data", 1, rowCount.intValue()); assertEquals("Expected to limit data", 1, rowCount.intValue());
logger.debug(sb.toString()); logger.debug(sb.toString());
// Limit by time and query up to and excluding the 'before' time // Limit by time and query up to and excluding the 'before' time
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, null, null, beforeTime, -1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, null, null, beforeTime, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
int resultsBefore = rowCount.intValue(); int resultsBefore = rowCount.intValue();
// Limit by time and query from and including the 'before' time // Limit by time and query from and including the 'before' time
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, null, beforeTime, null, -1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, null, beforeTime, null, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
int resultsAfter = rowCount.intValue(); int resultsAfter = rowCount.intValue();
@@ -364,13 +370,13 @@ public class AuditComponentTest extends TestCase
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, user, null, null, -1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, user, null, null, -1);
assertTrue("Expected some data for specific user", rowCount.intValue() > 0); assertTrue("Expected some data for specific user", rowCount.intValue() > 0);
logger.debug(sb.toString()); logger.debug(sb.toString());
sb.delete(0, sb.length()); sb.delete(0, sb.length());
rowCount.setValue(0); rowCount.setValue(0);
auditComponent.auditQuery(callback, APPLICATION_ACTIONS_TEST, "Numpty", null, null, -1); auditComponent.auditQuery(callback, true, APPLICATION_ACTIONS_TEST, "Numpty", null, null, -1);
assertTrue("Expected no data for bogus user", rowCount.intValue() == 0); assertTrue("Expected no data for bogus user", rowCount.intValue() == 0);
logger.debug(sb.toString()); logger.debug(sb.toString());
@@ -483,12 +489,17 @@ public class AuditComponentTest extends TestCase
; ;
return true; return true;
} }
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
{
throw new AlfrescoRuntimeException(errorMsg, error);
}
}; };
auditService.clearAudit(APPLICATION_API_TEST); auditService.clearAudit(APPLICATION_API_TEST);
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, APPLICATION_API_TEST, null, null, null, -1); auditService.auditQuery(auditQueryCallback, true, APPLICATION_API_TEST, null, null, null, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertTrue("There should be no audit entries for the API test after a clear", results.isEmpty()); assertTrue("There should be no audit entries for the API test after a clear", results.isEmpty());
@@ -522,7 +533,7 @@ public class AuditComponentTest extends TestCase
// Check that the call was audited // Check that the call was audited
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, APPLICATION_API_TEST, null, null, null, -1); auditService.auditQuery(auditQueryCallback, true, APPLICATION_API_TEST, null, null, null, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertFalse("Did not get any audit results after successful login", results.isEmpty()); assertFalse("Did not get any audit results after successful login", results.isEmpty());
@@ -539,7 +550,7 @@ public class AuditComponentTest extends TestCase
} }
results.clear(); results.clear();
sb.delete(0, sb.length()); sb.delete(0, sb.length());
auditService.auditQuery(auditQueryCallback, APPLICATION_API_TEST, null, null, null, -1); auditService.auditQuery(auditQueryCallback, true, APPLICATION_API_TEST, null, null, null, -1);
logger.debug(sb.toString()); logger.debug(sb.toString());
assertFalse("Did not get any audit results after failed login", results.isEmpty()); assertFalse("Did not get any audit results after failed login", results.isEmpty());
} }

View File

@@ -173,13 +173,15 @@ public class AuditServiceImpl implements AuditService
*/ */
public void auditQuery( public void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
int maxResults) int maxResults)
{ {
ParameterCheck.mandatory("callback", callback); ParameterCheck.mandatory("callback", callback);
auditComponent.auditQuery(callback, applicationName, user, from, to, maxResults); auditComponent.auditQuery(
callback, forward, applicationName, user, from, to, maxResults);
} }
/** /**
@@ -188,6 +190,7 @@ public class AuditServiceImpl implements AuditService
*/ */
public void auditQuery( public void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults) int maxResults)
@@ -195,6 +198,7 @@ public class AuditServiceImpl implements AuditService
{ {
ParameterCheck.mandatory("callback", callback); ParameterCheck.mandatory("callback", callback);
auditComponent.auditQuery(callback, applicationName, user, from, to, searchKey, searchValue, maxResults); auditComponent.auditQuery(
callback, forward, applicationName, user, from, to, searchKey, searchValue, maxResults);
} }
} }

View File

@@ -740,6 +740,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
*/ */
public void findAuditEntries( public void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
int maxResults) int maxResults)
{ {
@@ -754,6 +755,7 @@ public class HibernateAuditDAO extends HibernateDaoSupport implements AuditDAO,
*/ */
public void findAuditEntries( public void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults) int maxResults)

View File

@@ -383,7 +383,10 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
if (auditValuesPair == null) if (auditValuesPair == null)
{ {
// Ignore // Ignore
logger.warn("Audit entry not joined to audit properties: " + row); more = callback.handleAuditEntryError(
row.getAuditEntryId(),
"Audit entry not joined to audit properties: " + row,
null);
return; return;
} }
auditValues = (Map<String, Serializable>) auditValuesPair.getSecond(); auditValues = (Map<String, Serializable>) auditValuesPair.getSecond();
@@ -397,17 +400,26 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
} }
catch (ClassCastException e) catch (ClassCastException e)
{ {
logger.warn("Audit entry not linked to a Map<String, Serializable> value: " + row); more = callback.handleAuditEntryError(
row.getAuditEntryId(),
"Audit entry not linked to a Map<String, Serializable> value: " + row,
e);
return; return;
} }
catch (Throwable e) catch (Throwable e)
{ {
logger.warn("Audit entry unable to extract audited values: " + row, e); more = callback.handleAuditEntryError(
row.getAuditEntryId(),
"Audit entry unable to extract audited values: " + row,
e);
return; return;
} }
if (auditValues == null) if (auditValues == null)
{ {
logger.warn("Audit entry incompletely joined to audit properties: " + row); more = callback.handleAuditEntryError(
row.getAuditEntryId(),
"Audit entry incompletely joined to audit properties: " + row,
null);
return; return;
} }
} }
@@ -430,25 +442,28 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
public void findAuditEntries( public void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
int maxResults) int maxResults)
{ {
AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback); AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback);
findAuditEntries(rowHandler, applicationName, user, from, to, maxResults, null, null); findAuditEntries(rowHandler, forward, applicationName, user, from, to, maxResults, null, null);
} }
public void findAuditEntries( public void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults) int maxResults)
{ {
AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback); AuditQueryRowHandler rowHandler = new AuditQueryRowHandler(callback);
findAuditEntries(rowHandler, applicationName, user, from, to, maxResults, searchKey, searchValue); findAuditEntries(rowHandler, forward, applicationName, user, from, to, maxResults, searchKey, searchValue);
} }
protected abstract void findAuditEntries( protected abstract void findAuditEntries(
AuditQueryRowHandler rowHandler, AuditQueryRowHandler rowHandler,
boolean forward,
String applicationName, String user, Long from, Long to, int maxResults, String applicationName, String user, Long from, Long to, int maxResults,
String searchKey, Serializable searchValue); String searchKey, Serializable searchValue);
} }

View File

@@ -207,6 +207,8 @@ public interface AuditDAO
* Find audit entries using the given parameters, any of which may be null * Find audit entries using the given parameters, any of which may be null
* *
* @param callback the data callback per entry * @param callback the data callback per entry
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName the name of the application to search against (optional) * @param applicationName the name of the application to search against (optional)
* @param user the user to search for (optional) * @param user the user to search for (optional)
* @param from the minimum entry time (optional) * @param from the minimum entry time (optional)
@@ -215,6 +217,7 @@ public interface AuditDAO
*/ */
void findAuditEntries( void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, int maxResults); String applicationName, String user, Long from, Long to, int maxResults);
/** /**
@@ -230,6 +233,7 @@ public interface AuditDAO
*/ */
void findAuditEntries( void findAuditEntries(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults); int maxResults);

View File

@@ -28,10 +28,12 @@ import java.io.File;
import java.io.Serializable; import java.io.Serializable;
import java.net.URL; import java.net.URL;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.alfresco.error.AlfrescoRuntimeException;
import org.alfresco.repo.content.transform.AbstractContentTransformerTest; import org.alfresco.repo.content.transform.AbstractContentTransformerTest;
import org.alfresco.repo.domain.audit.AuditDAO.AuditApplicationInfo; import org.alfresco.repo.domain.audit.AuditDAO.AuditApplicationInfo;
import org.alfresco.repo.domain.contentdata.ContentDataDAO; import org.alfresco.repo.domain.contentdata.ContentDataDAO;
@@ -43,6 +45,7 @@ import org.alfresco.service.cmr.repository.ContentData;
import org.alfresco.service.transaction.TransactionService; import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.ApplicationContextHelper; import org.alfresco.util.ApplicationContextHelper;
import org.alfresco.util.Pair; import org.alfresco.util.Pair;
import org.apache.commons.lang.mutable.MutableInt;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
/** /**
@@ -182,11 +185,13 @@ public class AuditDAOTest extends TestCase
return appName; return appName;
} }
public void testAuditQuery() throws Exception public synchronized void testAuditQuery() throws Exception
{ {
// Some entries // Some entries
doAuditEntryImpl(1); doAuditEntryImpl(1);
final MutableInt count = new MutableInt(0);
final LinkedList<Long> timestamps = new LinkedList<Long>();
// Find everything, but look for a specific key // Find everything, but look for a specific key
final AuditQueryCallback callback = new AuditQueryCallback() final AuditQueryCallback callback = new AuditQueryCallback()
{ {
@@ -197,20 +202,55 @@ public class AuditDAOTest extends TestCase
long time, long time,
Map<String, Serializable> values) Map<String, Serializable> values)
{ {
System.out.println(values); count.setValue(count.intValue() + 1);
timestamps.add(time);
return true; return true;
} }
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
{
throw new AlfrescoRuntimeException(errorMsg, error);
}
}; };
RetryingTransactionCallback<Void> findCallback = new RetryingTransactionCallback<Void>() RetryingTransactionCallback<Void> findCallback = new RetryingTransactionCallback<Void>()
{ {
public Void execute() throws Throwable public Void execute() throws Throwable
{ {
auditDAO.findAuditEntries(callback, null, null, null, null, "/a/b/c", null, -1); auditDAO.findAuditEntries(callback, true, null, null, null, null, "/a/b/c", null, 2);
return null; return null;
} }
}; };
count.setValue(0);
timestamps.clear();
txnHelper.doInTransaction(findCallback); txnHelper.doInTransaction(findCallback);
assertTrue("Expected at least one result", count.intValue() > 0);
// Make sure that the last two entries are in forward order (ascending time)
Long lastTimestamp = timestamps.removeLast();
Long secondLastTimeStamp = timestamps.removeLast();
assertTrue("The timestamps should be in ascending order", lastTimestamp.compareTo(secondLastTimeStamp) > 0);
// Make sure that the last two entries differ in time
wait(1000L);
// Search in reverse order
doAuditEntryImpl(1);
RetryingTransactionCallback<Void> findReverseCallback = new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
auditDAO.findAuditEntries(callback, false, null, null, null, null, "/a/b/c", null, 2);
return null;
}
};
timestamps.clear();
txnHelper.doInTransaction(findReverseCallback);
// Make sure that the last two entries are in reverse order (descending time)
lastTimestamp = timestamps.removeLast();
secondLastTimeStamp = timestamps.removeLast();
assertTrue("The timestamps should be in descending order", lastTimestamp.compareTo(secondLastTimeStamp) < 0);
} }
public void testAuditDeleteEntries() throws Exception public void testAuditDeleteEntries() throws Exception
@@ -227,6 +267,11 @@ public class AuditDAOTest extends TestCase
fail("Expected no results. All entries should have been removed."); fail("Expected no results. All entries should have been removed.");
return false; return false;
} }
public boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error)
{
throw new AlfrescoRuntimeException(errorMsg, error);
}
}; };
// Some entries // Some entries
@@ -239,7 +284,7 @@ public class AuditDAOTest extends TestCase
Long appId = auditDAO.getAuditApplication(appName).getId(); Long appId = auditDAO.getAuditApplication(appName).getId();
auditDAO.deleteAuditEntries(appId, null, null); auditDAO.deleteAuditEntries(appId, null, null);
// There should be no entries // There should be no entries
auditDAO.findAuditEntries(noResultsCallback, appName, null, null, null, -1); auditDAO.findAuditEntries(noResultsCallback, true, appName, null, null, null, -1);
return null; return null;
} }
}; };

View File

@@ -34,7 +34,7 @@ import java.util.Date;
*/ */
public class AuditQueryParameters public class AuditQueryParameters
{ {
private Long auditEntryId; private boolean forward;
private Long auditAppNameId; private Long auditAppNameId;
private Long auditUserId; private Long auditUserId;
private Long auditFromTime; private Long auditFromTime;
@@ -51,25 +51,30 @@ public class AuditQueryParameters
{ {
StringBuilder sb = new StringBuilder(512); StringBuilder sb = new StringBuilder(512);
sb.append("AuditEntryParameters") sb.append("AuditEntryParameters")
.append("[ auditEntryId=").append(auditEntryId) .append("[ forward=").append(forward)
.append(", auditAppNameId=").append(auditAppNameId) .append(", auditAppNameId=").append(auditAppNameId)
.append(", auditUserId=").append(auditUserId) .append(", auditUserId=").append(auditUserId)
.append(", auditFromTime").append(auditFromTime == null ? null : new Date(auditFromTime)) .append(", auditFromTime=").append(auditFromTime == null ? null : new Date(auditFromTime))
.append(", auditToTime").append(auditToTime == null ? null : new Date(auditToTime)) .append(", auditToTime=").append(auditToTime == null ? null : new Date(auditToTime))
.append(", searchKeyId").append(searchKeyId) .append(", searchKeyId=").append(searchKeyId)
.append(", searchValueId").append(searchValueId) .append(", searchValueId=").append(searchValueId)
.append("]"); .append("]");
return sb.toString(); return sb.toString();
} }
public Long getAuditEntryId() public boolean isForward()
{ {
return auditEntryId; return forward;
} }
public void setAuditEntryId(Long entryId) public void setForward(boolean forward)
{ {
this.auditEntryId = entryId; this.forward = forward;
}
public boolean isForwardTrue()
{
return true;
} }
public Long getAuditAppNameId() public Long getAuditAppNameId()

View File

@@ -29,7 +29,6 @@ import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap;
import org.alfresco.ibatis.RollupRowHandler; import org.alfresco.ibatis.RollupRowHandler;
import org.alfresco.repo.domain.audit.AbstractAuditDAOImpl; import org.alfresco.repo.domain.audit.AbstractAuditDAOImpl;
@@ -194,6 +193,7 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
@Override @Override
protected void findAuditEntries( protected void findAuditEntries(
final AuditQueryRowHandler rowHandler, final AuditQueryRowHandler rowHandler,
boolean forward,
String appName, String user, Long from, Long to, int maxResults, String appName, String user, Long from, Long to, int maxResults,
String searchKey, Serializable searchValue) String searchKey, Serializable searchValue)
{ {
@@ -244,12 +244,13 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
} }
params.setSearchValueId(searchValuePair.getFirst()); params.setSearchValueId(searchValuePair.getFirst());
} }
params.setForward(forward);
if (maxResults > 0) if (maxResults > 0)
{ {
// Query without getting the values. We gather all the results and batch-fetch the audited // Query without getting the values. We gather all the results and batch-fetch the audited
// values afterwards. // values afterwards.
final TreeMap<Long, AuditQueryResult> resultsByValueId = new TreeMap<Long, AuditQueryResult>(); final Map<Long, AuditQueryResult> resultsByValueId = new HashMap<Long, AuditQueryResult>(173);
PropertyFinderCallback propertyFinderCallback = new PropertyFinderCallback() PropertyFinderCallback propertyFinderCallback = new PropertyFinderCallback()
{ {
public void handleProperty(Long id, Serializable value) public void handleProperty(Long id, Serializable value)
@@ -264,7 +265,6 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
{ {
// The handler will deal with the entry // The handler will deal with the entry
} }
rowHandler.processResult(row);
} }
}; };
@@ -288,6 +288,11 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
List<Long> valueIds = new ArrayList<Long>(resultsByValueId.keySet()); List<Long> valueIds = new ArrayList<Long>(resultsByValueId.keySet());
propertyValueDAO.getPropertiesByIds(valueIds, propertyFinderCallback); propertyValueDAO.getPropertiesByIds(valueIds, propertyFinderCallback);
} }
// Now pass the filled-out results to the row handler (order-preserved)
for (AuditQueryResult row : rows)
{
rowHandler.processResult(row);
}
} }
else else
{ {

View File

@@ -168,12 +168,24 @@ public interface AuditService
String user, String user,
long time, long time,
Map<String, Serializable> values); Map<String, Serializable> values);
/**
* Handle audit entry failures
*
* @param entryId the entry ID
* @param errorMsg the error message
* @param error the exception causing the error (may be <tt>null</tt>)
* @return Return <tt>true</tt> to continue processing rows or <tt>false</tt> to stop
*/
boolean handleAuditEntryError(Long entryId, String errorMsg, Throwable error);
} }
/** /**
* Get the audit entries that match the given criteria. * Get the audit entries that match the given criteria.
* *
* @param callback the callback that will handle results * @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application * @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user * @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning) * @param from the start search time (<tt>null</tt> to start at the beginning)
@@ -184,6 +196,7 @@ public interface AuditService
*/ */
void auditQuery( void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
int maxResults); int maxResults);
@@ -191,6 +204,8 @@ public interface AuditService
* Get the audit entries that match the given criteria. * Get the audit entries that match the given criteria.
* *
* @param callback the callback that will handle results * @param callback the callback that will handle results
* @param forward <tt>true</tt> for results to ordered from first to last,
* or <tt>false</tt> to order from last to first
* @param applicationName if not <tt>null</tt>, find entries logged against this application * @param applicationName if not <tt>null</tt>, find entries logged against this application
* @param user if not <tt>null</tt>, find entries logged against this user * @param user if not <tt>null</tt>, find entries logged against this user
* @param from the start search time (<tt>null</tt> to start at the beginning) * @param from the start search time (<tt>null</tt> to start at the beginning)
@@ -203,6 +218,7 @@ public interface AuditService
*/ */
void auditQuery( void auditQuery(
AuditQueryCallback callback, AuditQueryCallback callback,
boolean forward,
String applicationName, String user, Long from, Long to, String applicationName, String user, Long from, Long to,
String searchKey, Serializable searchValue, String searchKey, Serializable searchValue,
int maxResults); int maxResults);