RM-947 Remove unwanted properties from being audited for the 'Updated Metadata' event in RM

- Specified a list of properties in Spring's configuration to be ignored by audit.
- If an audit entry ends up with no changes in properties then we discard the entire audit map altogether. Currently this applies only to 'Update RM Object' events as other events still require to be audited even if there are no property changes.


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@55219 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Craig Tan
2013-09-11 09:46:33 +00:00
parent 4e3e0cb7e4
commit cf4c105fa1
5 changed files with 119 additions and 39 deletions

View File

@@ -1050,6 +1050,15 @@
<property name="recordsManagementService" ref="RecordsManagementService" /> <property name="recordsManagementService" ref="RecordsManagementService" />
<property name="recordsManagementActionService" ref="RecordsManagementActionService" /> <property name="recordsManagementActionService" ref="RecordsManagementActionService" />
<property name="filePlanService" ref="FilePlanService" /> <property name="filePlanService" ref="FilePlanService" />
<property name="namespaceService" ref="NamespaceService" />
<property name="ignoredAuditProperties">
<list>
<value>cm:lastThumbnailModification</value>
<value>cm:autoVersion</value>
<value>cm:autoVersionOnUpdateProps</value>
<value>cm:initialVersion</value>
</list>
</property>
</bean> </bean>
<bean id="RecordsManagementAuditService" class="org.springframework.aop.framework.ProxyFactoryBean"> <bean id="RecordsManagementAuditService" class="org.springframework.aop.framework.ProxyFactoryBean">

View File

@@ -75,7 +75,7 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
String eventName); String eventName);
/** /**
* Audits an event, assumes that the event should not be audited immediately. * Audits an event, assumes that the event should not be audited immediately and not be removed if no property is changed.
* *
* @param nodeRef node reference * @param nodeRef node reference
* @param eventName event name * @param eventName event name
@@ -90,17 +90,19 @@ public interface RecordsManagementAuditService extends RecordsManagementAuditSer
/** /**
* Audit event. * Audit event.
* *
* @param nodeRef node reference * @param nodeRef node reference
* @param eventName event name * @param eventName event name
* @param before property values before event * @param before property values before event
* @param after property values after event * @param after property values after event
* @param immediate true if event is to be audited immediately, false otherwise * @param immediate true if event is to be audited immediately, false otherwise
* @param removeIfNoPropertyChanged true if event is not audited when there are no properties changed, false otherwise
*/ */
void auditEvent(NodeRef nodeRef, void auditEvent(NodeRef nodeRef,
String eventName, String eventName,
Map<QName, Serializable> before, Map<QName, Serializable> before,
Map<QName, Serializable> after, Map<QName, Serializable> after,
boolean immediate); boolean immediate,
boolean removeIfNoPropertyChanged);
/** /**
* Determines whether the RM audit log is currently enabled. * Determines whether the RM audit log is currently enabled.

View File

@@ -150,9 +150,14 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
private RecordsManagementService rmService; private RecordsManagementService rmService;
private RecordsManagementActionService rmActionService; private RecordsManagementActionService rmActionService;
private FilePlanService filePlanService; private FilePlanService filePlanService;
private NamespaceService namespaceService;
private boolean shutdown = false; private boolean shutdown = false;
private List<String> ignoredAuditProperties;
private List<QName> propertiesToBeRemoved = new ArrayList<QName>();
private RMAuditTxnListener txnListener = new RMAuditTxnListener(); private RMAuditTxnListener txnListener = new RMAuditTxnListener();
/** Registered and initialised records management auditEvents */ /** Registered and initialised records management auditEvents */
@@ -238,6 +243,22 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
this.filePlanService = filePlanService; this.filePlanService = filePlanService;
} }
/**
* @param namespaceService namespace service
*/
public void setNamespaceService(NamespaceService namespaceService)
{
this.namespaceService = namespaceService;
}
/**
* @param ignoredAuditProperties
*/
public void setIgnoredAuditProperties(List<String> ignoredAuditProperties)
{
this.ignoredAuditProperties = ignoredAuditProperties;
}
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService#registerAuditEvent(java.lang.String, java.lang.String) * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService#registerAuditEvent(java.lang.String, java.lang.String)
*/ */
@@ -282,6 +303,12 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
registerAuditEvent(AUDIT_EVENT_START, MSG_AUDIT_START); registerAuditEvent(AUDIT_EVENT_START, MSG_AUDIT_START);
registerAuditEvent(AUDIT_EVENT_STOP, MSG_AUDIT_STOP); registerAuditEvent(AUDIT_EVENT_STOP, MSG_AUDIT_STOP);
registerAuditEvent(AUDIT_EVENT_VIEW, MSG_AUDIT_VIEW); registerAuditEvent(AUDIT_EVENT_VIEW, MSG_AUDIT_VIEW);
// properties to be ignored by audit
for (String qname : ignoredAuditProperties)
{
this.propertiesToBeRemoved.add(QName.createQName(qname, this.namespaceService));
}
} }
/** /**
@@ -332,7 +359,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
logger.info("Started Records Management auditing"); logger.info("Started Records Management auditing");
} }
auditEvent(filePlan, AUDIT_EVENT_START, null, null, true); auditEvent(filePlan, AUDIT_EVENT_START, null, null, true, false);
} }
/** /**
@@ -343,7 +370,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
ParameterCheck.mandatory("filePlan", filePlan); ParameterCheck.mandatory("filePlan", filePlan);
// TODO use file plan to scope audit log // TODO use file plan to scope audit log
auditEvent(filePlan, AUDIT_EVENT_STOP, null, null, true); auditEvent(filePlan, AUDIT_EVENT_STOP, null, null, true, false);
auditService.disableAudit( auditService.disableAudit(
RM_AUDIT_APPLICATION_NAME, RM_AUDIT_APPLICATION_NAME,
@@ -370,7 +397,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
logger.debug("Records Management audit log has been cleared"); logger.debug("Records Management audit log has been cleared");
} }
auditEvent(filePlan, AUDIT_EVENT_CLEAR, null, null, true); auditEvent(filePlan, AUDIT_EVENT_CLEAR, null, null, true, false);
} }
/** /**
@@ -404,7 +431,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
@Override @Override
public void auditEvent(NodeRef nodeRef, String eventName) public void auditEvent(NodeRef nodeRef, String eventName)
{ {
auditEvent(nodeRef, eventName, null, null, false); auditEvent(nodeRef, eventName, null, null, false, false);
} }
/** /**
@@ -413,19 +440,19 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
@Override @Override
public void auditEvent(NodeRef nodeRef, String eventName, Map<QName, Serializable> before, Map<QName, Serializable> after) public void auditEvent(NodeRef nodeRef, String eventName, Map<QName, Serializable> before, Map<QName, Serializable> after)
{ {
auditEvent(nodeRef, eventName, before, after, false); auditEvent(nodeRef, eventName, before, after, false, false);
} }
/** /**
* @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService#auditEvent(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.util.Map, java.util.Map, boolean) * @see org.alfresco.module.org_alfresco_module_rm.audit.RecordsManagementAuditService#auditEvent(org.alfresco.service.cmr.repository.NodeRef, java.lang.String, java.util.Map, java.util.Map, boolean)
*/ */
@Override @Override
public void auditEvent(NodeRef nodeRef, String eventName, Map<QName, Serializable> before, Map<QName, Serializable> after, boolean immediate) public void auditEvent(NodeRef nodeRef, String eventName, Map<QName, Serializable> before, Map<QName, Serializable> after, boolean immediate, boolean removeIfNoPropertyChanged)
{ {
// deal with immediate auditing if required // deal with immediate auditing if required
if (immediate == true) if (immediate == true)
{ {
Map<String, Serializable> auditMap = buildAuditMap(nodeRef, eventName, before, after); Map<String, Serializable> auditMap = buildAuditMap(nodeRef, eventName, before, after, removeIfNoPropertyChanged);
auditComponent.recordAuditValues(RM_AUDIT_PATH_ROOT, auditMap); auditComponent.recordAuditValues(RM_AUDIT_PATH_ROOT, auditMap);
} }
else else
@@ -457,6 +484,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
auditedNode.setEventName(eventName); auditedNode.setEventName(eventName);
auditedNode.setNodePropertiesBefore(before); auditedNode.setNodePropertiesBefore(before);
auditedNode.setNodePropertiesAfter(after); auditedNode.setNodePropertiesAfter(after);
auditedNode.setRemoveIfNoPropertyChanged(removeIfNoPropertyChanged);
auditDetails.add(auditedNode); auditDetails.add(auditedNode);
} }
@@ -471,7 +499,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
* @return * @return
* @since 2.0.3 * @since 2.0.3
*/ */
private Map<String, Serializable> buildAuditMap(NodeRef nodeRef, String eventName, Map<QName, Serializable> propertiesBefore, Map<QName, Serializable> propertiesAfter) private Map<String, Serializable> buildAuditMap(NodeRef nodeRef, String eventName, Map<QName, Serializable> propertiesBefore, Map<QName, Serializable> propertiesAfter, boolean removeOnNoPropertyChange)
{ {
Map<String, Serializable> auditMap = new HashMap<String, Serializable>(13); Map<String, Serializable> auditMap = new HashMap<String, Serializable>(13);
auditMap.put( auditMap.put(
@@ -488,33 +516,63 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
RM_AUDIT_SNIPPET_NODE), RM_AUDIT_SNIPPET_NODE),
nodeRef); nodeRef);
} }
// Filter out any properties to be audited if specified in the Spring configuration.
if (ignoredAuditProperties.isEmpty() == false)
{
removeAuditProperties(ignoredAuditProperties, propertiesBefore, propertiesAfter);
}
// Property changes // Property changes
Pair<Map<QName, Serializable>, Map<QName, Serializable>> deltaPair = PropertyMap.getBeforeAndAfterMapsForChanges(propertiesBefore, propertiesAfter); Pair<Map<QName, Serializable>, Map<QName, Serializable>> deltaPair = PropertyMap.getBeforeAndAfterMapsForChanges(propertiesBefore, propertiesAfter);
auditMap.put(
AuditApplication.buildPath( // If both the first and second Map in the deltaPair are empty and removeOnNoPropertyChange is true, the entire auditMap is discarded so it won't be audited.
RM_AUDIT_SNIPPET_EVENT, if (deltaPair.getFirst().isEmpty() && deltaPair.getSecond().isEmpty() && removeOnNoPropertyChange == true)
RM_AUDIT_SNIPPET_NODE, {
RM_AUDIT_SNIPPET_CHANGES, auditMap.clear();
RM_AUDIT_SNIPPET_BEFORE), }
(Serializable) deltaPair.getFirst()); else
auditMap.put( {
AuditApplication.buildPath( auditMap.put(
RM_AUDIT_SNIPPET_EVENT, AuditApplication.buildPath(
RM_AUDIT_SNIPPET_NODE, RM_AUDIT_SNIPPET_EVENT,
RM_AUDIT_SNIPPET_CHANGES, RM_AUDIT_SNIPPET_NODE,
RM_AUDIT_SNIPPET_AFTER), RM_AUDIT_SNIPPET_CHANGES,
(Serializable) deltaPair.getSecond()); RM_AUDIT_SNIPPET_BEFORE),
(Serializable) deltaPair.getFirst());
auditMap.put(
AuditApplication.buildPath(
RM_AUDIT_SNIPPET_EVENT,
RM_AUDIT_SNIPPET_NODE,
RM_AUDIT_SNIPPET_CHANGES,
RM_AUDIT_SNIPPET_AFTER),
(Serializable) deltaPair.getSecond());
}
return auditMap; return auditMap;
} }
/** /**
* A <b>stateless</b> transaction listener for RM auditing. This component picks up the data of * Helper method to remove system properties from maps
* modified nodes and generates the audit information. *
* @param properties
*/
private void removeAuditProperties(List<String> ignoredAuditProperties, Map<QName, Serializable> before, Map<QName, Serializable> after)
{
if (before != null)
{
before.keySet().removeAll(this.propertiesToBeRemoved);
}
if (after != null)
{
after.keySet().removeAll(this.propertiesToBeRemoved);
}
}
/**
* A <b>stateless</b> transaction listener for RM auditing. This component picks up the data of modified nodes and generates the audit information.
* <p/> * <p/>
* This class is not static so that the instances will have access to the action's implementation. * This class is not static so that the instances will have access to the action's implementation.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 3.2 * @since 3.2
*/ */
@@ -570,8 +628,8 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
Map<String, Serializable> auditMap = buildAuditMap(nodeRef, Map<String, Serializable> auditMap = buildAuditMap(nodeRef,
auditedNode.getEventName(), auditedNode.getEventName(),
auditedNode.getNodePropertiesBefore(), auditedNode.getNodePropertiesBefore(),
auditedNode.getNodePropertiesAfter()); auditedNode.getNodePropertiesAfter(),
auditedNode.getRemoveIfNoPropertyChanged());
// Audit it // Audit it
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
@@ -926,7 +984,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
// grab the default file plan, but don't fail if it can't be found! // grab the default file plan, but don't fail if it can't be found!
nodeRef = filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID); nodeRef = filePlanService.getFilePlanBySiteId(FilePlanService.DEFAULT_RM_SITE_ID);
} }
auditEvent(nodeRef, AUDIT_EVENT_VIEW, null, null, true); auditEvent(nodeRef, AUDIT_EVENT_VIEW, null, null, true, false);
} }
/** /**
@@ -1408,6 +1466,7 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
private String eventName; private String eventName;
private Map<QName, Serializable> nodePropertiesBefore; private Map<QName, Serializable> nodePropertiesBefore;
private Map<QName, Serializable> nodePropertiesAfter; private Map<QName, Serializable> nodePropertiesAfter;
private boolean removeIfNoPropertyChanged = false;
public NodeRef getNodeRef() public NodeRef getNodeRef()
{ {
@@ -1448,6 +1507,16 @@ public class RecordsManagementAuditServiceImpl extends AbstractLifecycleBean
{ {
this.nodePropertiesAfter = nodePropertiesAfter; this.nodePropertiesAfter = nodePropertiesAfter;
} }
public boolean getRemoveIfNoPropertyChanged()
{
return removeIfNoPropertyChanged;
}
public void setRemoveIfNoPropertyChanged(boolean removeIfNoPropertyChanged)
{
this.removeIfNoPropertyChanged = removeIfNoPropertyChanged;
}
} }
/** Deprecated Method Implementations **/ /** Deprecated Method Implementations **/

View File

@@ -38,7 +38,7 @@ public class DeleteObjectAuditEvent extends AuditEvent implements BeforeDeleteNo
public void beforeDeleteNode(NodeRef nodeRef) public void beforeDeleteNode(NodeRef nodeRef)
{ {
recordsManagementAuditService.auditEvent(nodeRef, name, null, null, true); recordsManagementAuditService.auditEvent(nodeRef, name, null, null, true, false);
} }
} }

View File

@@ -43,7 +43,7 @@ public class UpdateObjectAuditEvent extends AuditEvent implements OnUpdateProper
public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after) public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after)
{ {
recordsManagementAuditService.auditEvent(nodeRef, name, before, after); recordsManagementAuditService.auditEvent(nodeRef, name, before, after, false, true);
} }
} }