Added AuditService.clearAudit(List<Long>)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@22980 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2010-10-08 09:26:34 +00:00
parent 6c8e135759
commit 6dcd5e5441
10 changed files with 168 additions and 12 deletions

View File

@@ -135,14 +135,20 @@
delete
from
alf_audit_entry
where
<dynamic prepend="where">
<isNotNull property="auditFromTime" prepend="and">
audit_app_id = #auditApplicationId#
<isNotNull property="auditFromTime">
<![CDATA[and audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull property="auditFromTime">
<![CDATA[and audit_time < #auditToTime#]]>
<isNotNull property="auditFromTime" prepend="and">
<![CDATA[audit_time >= #auditFromTime#]]>
</isNotNull>
<isNotNull property="auditFromTime" prepend="and">
<![CDATA[audit_time < #auditToTime#]]>
</isNotNull>
<isNotNull property="auditEntryIds" prepend="and">
id in <iterate property="auditEntryIds" open="(" close=")" conjunction=", ">#auditEntryIds[]#</iterate>
</isNotNull>
</dynamic>
</delete>
<sql id="select_AuditEntriesWhereSnippet">

View File

@@ -19,6 +19,7 @@
package org.alfresco.repo.audit;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.repo.audit.model.AuditApplication;
@@ -89,6 +90,14 @@ public interface AuditComponent
*/
int deleteAuditEntries(String applicationName, Long fromTime, Long toTime);
/**
* Delete a discrete list of audit entries based on ID
*
* @param auditEntryIds the audit entry IDs to delete
* @return Returns the number of entries deleted
*/
int deleteAuditEntries(List<Long> auditEntryIds);
/**
* Check if an audit path is enabled. The path will be disabled if it or any higher
* path has been explicitly disabled. Any disabled path will not be processed when

View File

@@ -146,6 +146,21 @@ public class AuditComponentImpl implements AuditComponent
return deleted;
}
/**
* {@inheritDoc}
* @since 3.2
*/
@Override
public int deleteAuditEntries(List<Long> auditEntryIds)
{
// Shortcut, if necessary
if (auditEntryIds.size() == 0)
{
return 0;
}
return auditDAO.deleteAuditEntries(auditEntryIds);
}
/**
* @param application the audit application object
* @return Returns a copy of the set of disabled paths associated with the application

View File

@@ -523,7 +523,7 @@ public class AuditComponentTest extends TestCase
auditModelRegistry.registerModel(testModelUrl);
auditModelRegistry.loadAuditModels();
final List<Map<String, Serializable>> results = new ArrayList<Map<String,Serializable>>();
final List<Long> results = new ArrayList<Long>(5);
final StringBuilder sb = new StringBuilder();
AuditQueryCallback auditQueryCallback = new AuditQueryCallback()
{
@@ -539,7 +539,7 @@ public class AuditComponentTest extends TestCase
long time,
Map<String, Serializable> values)
{
results.add(values);
results.add(entryId);
if (logger.isDebugEnabled())
{
logger.debug(
@@ -615,11 +615,28 @@ public class AuditComponentTest extends TestCase
{
// Expected
}
try
{
authenticationService.authenticate("banana", "****".toCharArray());
fail("Invalid authentication attempt should fail");
}
catch (AuthenticationException e)
{
// Expected
}
results.clear();
sb.delete(0, sb.length());
queryAuditLog(auditQueryCallback, params, -1);
logger.debug(sb.toString());
assertFalse("Did not get any audit results after failed login", results.isEmpty());
assertEquals("Incorrect number of audit entries after failed login", 2, results.size());
// Check that we can delete explicit entries
deleteAuditEntries(results);
results.clear();
sb.delete(0, sb.length());
queryAuditLog(auditQueryCallback, params, -1);
logger.debug(sb.toString());
assertEquals("Explicit audit entries were not deleted", 0, results.size());
}
public void testAuditQuery_MaxId() throws Exception
@@ -677,6 +694,23 @@ public class AuditComponentTest extends TestCase
AuthenticationUtil.runAs(work, AuthenticationUtil.getAdminRoleName());
}
/**
* Clearn the audit log as 'admin'
*/
private void deleteAuditEntries(final List<Long> auditEntryIds)
{
RunAsWork<Void> work = new RunAsWork<Void>()
{
@Override
public Void doWork() throws Exception
{
auditService.clearAudit(auditEntryIds);
return null;
}
};
AuthenticationUtil.runAs(work, AuthenticationUtil.getAdminRoleName());
}
/**
* Clearn the audit log as 'admin'
*/

View File

@@ -18,7 +18,7 @@
*/
package org.alfresco.repo.audit;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -133,6 +133,16 @@ public class AuditServiceImpl implements AuditService
return auditComponent.deleteAuditEntries(applicationName, fromTime, toTime);
}
/**
* {@inheritDoc}
* @since 3.4
*/
@Override
public int clearAudit(List<Long> auditEntryIds)
{
return auditComponent.deleteAuditEntries(auditEntryIds);
}
/**
* {@inheritDoc}
* @since 3.3

View File

@@ -22,11 +22,13 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.zip.CRC32;
import org.alfresco.error.AlfrescoRuntimeException;
@@ -41,6 +43,7 @@ import org.alfresco.service.cmr.repository.ContentWriter;
import org.alfresco.util.Pair;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.dao.ConcurrencyFailureException;
import org.springframework.dao.DataIntegrityViolationException;
/**
@@ -306,7 +309,39 @@ public abstract class AbstractAuditDAOImpl implements AuditDAO
return entity.getId();
}
public int deleteAuditEntries(List<Long> auditEntryIds)
{
// Ensure that we don't have duplicates
Set<Long> ids = new TreeSet<Long>(auditEntryIds);
int shouldDelete = ids.size();
int deleted = 0;
List<Long> batch = new ArrayList<Long>(shouldDelete > 512 ? 512 : shouldDelete);
for (Long id : ids)
{
batch.add(id);
if (batch.size() >= 512)
{
deleted += deleteAuditEntriesImpl(batch);
batch.clear();
}
}
// Process remaining
if (batch.size() > 0)
{
deleted += deleteAuditEntriesImpl(batch);
}
// Check concurrency
if (deleted != shouldDelete)
{
throw new ConcurrencyFailureException(
"Deleted " + deleted + " audit entries out of a set of " + shouldDelete + " unique IDs.");
}
return deleted;
}
protected abstract AuditEntryEntity createAuditEntry(Long applicationId, long time, Long usernameId, Long valuesId);
protected abstract int deleteAuditEntriesImpl(List<Long> auditEntryIds);
/*
* Searches

View File

@@ -20,6 +20,7 @@ package org.alfresco.repo.domain.audit;
import java.io.Serializable;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -166,6 +167,17 @@ public interface AuditDAO
*/
int deleteAuditEntries(Long applicationId, Long from, Long to);
/**
* Delete a discrete list of audit entries. Duplicate entries are collapsed
* and the number of entries deleted will match the count of unique IDs in
* the list; otherwise a concurrency condition has occured and an exception
* will be generated.
*
* @param auditEntryIds the IDs of all audit entries to delete
* @return Returns the number of entries deleted
*/
int deleteAuditEntries(List<Long> auditEntryIds);
/**
* Create a new audit entry with the given map of values.
*

View File

@@ -19,6 +19,7 @@
package org.alfresco.repo.domain.audit;
import java.util.Date;
import java.util.List;
/**
* Deletion parameters for <b>alf_audit_entry</b> table.
@@ -31,6 +32,7 @@ public class AuditDeleteParameters
private Long auditApplicationId;
private Long auditFromTime;
private Long auditToTime;
private List<Long> auditEntryIds;
public AuditDeleteParameters()
{
@@ -44,6 +46,7 @@ public class AuditDeleteParameters
.append("[ auditApplicationId=").append(auditApplicationId)
.append(", auditFromTime").append(auditFromTime == null ? null : new Date(auditFromTime))
.append(", auditToTime").append(auditToTime == null ? null : new Date(auditToTime))
.append(", auditEntryIds").append(auditEntryIds == null ? null : auditEntryIds.size())
.append("]");
return sb.toString();
}
@@ -77,4 +80,14 @@ public class AuditDeleteParameters
{
this.auditToTime = auditToTime;
}
public List<Long> getAuditEntryIds()
{
return auditEntryIds;
}
public void setAuditEntryIds(List<Long> auditEntryIds)
{
this.auditEntryIds = auditEntryIds;
}
}

View File

@@ -170,6 +170,14 @@ public class AuditDAOImpl extends AbstractAuditDAOImpl
return template.delete(DELETE_ENTRIES, params);
}
@Override
protected int deleteAuditEntriesImpl(List<Long> auditEntryIds)
{
AuditDeleteParameters params = new AuditDeleteParameters();
params.setAuditEntryIds(auditEntryIds);
return template.delete(DELETE_ENTRIES, params);
}
@Override
protected AuditEntryEntity createAuditEntry(Long applicationId, long time, Long usernameId, Long valuesId)
{

View File

@@ -19,6 +19,7 @@
package org.alfresco.service.cmr.audit;
import java.io.Serializable;
import java.util.List;
import java.util.Map;
import org.alfresco.service.PublicService;
@@ -145,6 +146,19 @@ public interface AuditService
*/
int clearAudit(String applicationName, Long fromTime, Long toTime);
/**
* Delete a discrete list of audit entries.
* <p/>
* This method should not be called <i>while</i> processing
* {@link #auditQuery(AuditQueryCallback, AuditQueryParameters, int) query results}.
*
* @param auditEntryIds the IDs of all audit entries to delete
* @return Returns the number of audit entries deleted
*
* @since 3.4
*/
int clearAudit(List<Long> auditEntryIds);
/**
* The interface that will be used to give query results to the calling code.
*