RM-581 (A user will receive notification of rejected records)

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/modules/recordsmanagement/HEAD@46140 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Tuna Aksoy
2013-02-01 15:35:29 +00:00
parent fb2a90ff29
commit 3ddc70cf74
2 changed files with 156 additions and 152 deletions

View File

@@ -33,4 +33,5 @@ rm.audit.web-record=Set Record As A Web Record
rm.audit.trail-file-fail=Failed to generate audit trail file. rm.audit.trail-file-fail=Failed to generate audit trail file.
rm.audit.audit-report=Audit Report rm.audit.audit-report=Audit Report
rm.audit.create-disposition-schedule=Create Disposition Schedule rm.audit.create-disposition-schedule=Create Disposition Schedule
rm.audit.unfreeze=Unfreeze rm.audit.unfreeze=Unfreeze
rm.audit.reject-record=Reject Record

View File

@@ -83,7 +83,7 @@ import org.springframework.extensions.surf.util.ParameterCheck;
/** /**
* Records Management Audit Service Implementation. * Records Management Audit Service Implementation.
* *
* @author Gavin Cornwell * @author Gavin Cornwell
* @since 3.2 * @since 3.2
*/ */
@@ -129,16 +129,17 @@ public class RecordsManagementAuditServiceImpl
private static final String MSG_AUDIT_REPORT = "rm.audit.audit-report"; private static final String MSG_AUDIT_REPORT = "rm.audit.audit-report";
private static final String MSG_CREATE_DISPOSITION_SCHEDULE = "rm.audit.create-disposition-schedule"; private static final String MSG_CREATE_DISPOSITION_SCHEDULE = "rm.audit.create-disposition-schedule";
private static final String MSG_UNFREEZE = "rm.audit.unfreeze"; private static final String MSG_UNFREEZE = "rm.audit.unfreeze";
private static final String MSG_REJECT_RECORD = "rm.audit.reject-record";
/** Logger */ /** Logger */
private static Log logger = LogFactory.getLog(RecordsManagementAuditServiceImpl.class); private static Log logger = LogFactory.getLog(RecordsManagementAuditServiceImpl.class);
private static final String KEY_RM_AUDIT_NODE_RECORDS = "RMAUditNodeRecords"; private static final String KEY_RM_AUDIT_NODE_RECORDS = "RMAUditNodeRecords";
protected static final String AUDIT_TRAIL_FILE_PREFIX = "audit_"; protected static final String AUDIT_TRAIL_FILE_PREFIX = "audit_";
protected static final String AUDIT_TRAIL_JSON_FILE_SUFFIX = ".json"; protected static final String AUDIT_TRAIL_JSON_FILE_SUFFIX = ".json";
protected static final String AUDIT_TRAIL_HTML_FILE_SUFFIX = ".html"; protected static final String AUDIT_TRAIL_HTML_FILE_SUFFIX = ".html";
private PolicyComponent policyComponent; private PolicyComponent policyComponent;
private DictionaryService dictionaryService; private DictionaryService dictionaryService;
private TransactionService transactionService; private TransactionService transactionService;
@@ -148,16 +149,16 @@ public class RecordsManagementAuditServiceImpl
private AuditService auditService; private AuditService auditService;
private RecordsManagementService rmService; private RecordsManagementService rmService;
private RecordsManagementActionService rmActionService; private RecordsManagementActionService rmActionService;
private boolean shutdown = false; private boolean shutdown = false;
private RMAuditTxnListener txnListener; private RMAuditTxnListener txnListener;
private Map<String, AuditEvent> auditEvents; private Map<String, AuditEvent> auditEvents;
public RecordsManagementAuditServiceImpl() public RecordsManagementAuditServiceImpl()
{ {
} }
/** /**
* Set the component used to bind to behaviour callbacks * Set the component used to bind to behaviour callbacks
*/ */
@@ -187,15 +188,15 @@ public class RecordsManagementAuditServiceImpl
*/ */
public void setNodeService(NodeService nodeService) public void setNodeService(NodeService nodeService)
{ {
this.nodeService = nodeService; this.nodeService = nodeService;
} }
/** /**
* Sets the ContentService instance * Sets the ContentService instance
*/ */
public void setContentService(ContentService contentService) public void setContentService(ContentService contentService)
{ {
this.contentService = contentService; this.contentService = contentService;
} }
/** /**
@@ -213,7 +214,7 @@ public class RecordsManagementAuditServiceImpl
{ {
this.auditService = auditService; this.auditService = auditService;
} }
/** /**
* Set the RecordsManagementService * Set the RecordsManagementService
*/ */
@@ -229,7 +230,7 @@ public class RecordsManagementAuditServiceImpl
{ {
this.rmActionService = rmActionService; this.rmActionService = rmActionService;
} }
/** /**
* Checks that all necessary properties have been set. * Checks that all necessary properties have been set.
*/ */
@@ -244,83 +245,85 @@ public class RecordsManagementAuditServiceImpl
PropertyCheck.mandatory(this, "rmService", rmService); PropertyCheck.mandatory(this, "rmService", rmService);
PropertyCheck.mandatory(this, "rmActionService", rmActionService); PropertyCheck.mandatory(this, "rmActionService", rmActionService);
PropertyCheck.mandatory(this, "dictionaryService", dictionaryService); PropertyCheck.mandatory(this, "dictionaryService", dictionaryService);
// setup the audit events map // setup the audit events map
initAuditEvents(); initAuditEvents();
} }
protected void initAuditEvents() protected void initAuditEvents()
{ {
// TODO: make this map configurable and localisable. // TODO: make this map configurable and localisable.
this.auditEvents = new HashMap<String, AuditEvent>(32); this.auditEvents = new HashMap<String, AuditEvent>(32);
this.auditEvents.put(RM_AUDIT_EVENT_UPDATE_RM_OBJECT, this.auditEvents.put(RM_AUDIT_EVENT_UPDATE_RM_OBJECT,
new AuditEvent(RM_AUDIT_EVENT_UPDATE_RM_OBJECT, MSG_UPDATED_METADATA)); new AuditEvent(RM_AUDIT_EVENT_UPDATE_RM_OBJECT, MSG_UPDATED_METADATA));
this.auditEvents.put(RM_AUDIT_EVENT_CREATE_RM_OBJECT, this.auditEvents.put(RM_AUDIT_EVENT_CREATE_RM_OBJECT,
new AuditEvent(RM_AUDIT_EVENT_CREATE_RM_OBJECT, MSG_CREATED_OBJECT)); new AuditEvent(RM_AUDIT_EVENT_CREATE_RM_OBJECT, MSG_CREATED_OBJECT));
this.auditEvents.put(RM_AUDIT_EVENT_DELETE_RM_OBJECT, this.auditEvents.put(RM_AUDIT_EVENT_DELETE_RM_OBJECT,
new AuditEvent(RM_AUDIT_EVENT_DELETE_RM_OBJECT, MSG_DELETE_OBJECT)); new AuditEvent(RM_AUDIT_EVENT_DELETE_RM_OBJECT, MSG_DELETE_OBJECT));
this.auditEvents.put(RM_AUDIT_EVENT_LOGIN_SUCCESS, this.auditEvents.put(RM_AUDIT_EVENT_LOGIN_SUCCESS,
new AuditEvent(RM_AUDIT_EVENT_LOGIN_SUCCESS, MSG_LOGIN_SUCCEEDED)); new AuditEvent(RM_AUDIT_EVENT_LOGIN_SUCCESS, MSG_LOGIN_SUCCEEDED));
this.auditEvents.put(RM_AUDIT_EVENT_LOGIN_FAILURE, this.auditEvents.put(RM_AUDIT_EVENT_LOGIN_FAILURE,
new AuditEvent(RM_AUDIT_EVENT_LOGIN_FAILURE, MSG_LOGIN_FAILED)); new AuditEvent(RM_AUDIT_EVENT_LOGIN_FAILURE, MSG_LOGIN_FAILED));
this.auditEvents.put("reviewed", this.auditEvents.put("reviewed",
new AuditEvent("reviewed", MSG_REVIEWED)); new AuditEvent("reviewed", MSG_REVIEWED));
this.auditEvents.put("cutoff", this.auditEvents.put("cutoff",
new AuditEvent("cutoff", MSG_CUT_OFF)); new AuditEvent("cutoff", MSG_CUT_OFF));
this.auditEvents.put("unCutoff", this.auditEvents.put("unCutoff",
new AuditEvent("unCutoff", MSG_REVERSED_CUT_OFF)); new AuditEvent("unCutoff", MSG_REVERSED_CUT_OFF));
this.auditEvents.put("destroy", this.auditEvents.put("destroy",
new AuditEvent("destroy", MSG_DESTROYED_ITEM)); new AuditEvent("destroy", MSG_DESTROYED_ITEM));
this.auditEvents.put("openRecordFolder", this.auditEvents.put("openRecordFolder",
new AuditEvent("openRecordFolder", MSG_OPENED_RECORD_FOLDER)); new AuditEvent("openRecordFolder", MSG_OPENED_RECORD_FOLDER));
this.auditEvents.put("closeRecordFolder", this.auditEvents.put("closeRecordFolder",
new AuditEvent("closeRecordFolder", MSG_CLOSED_RECORD_FOLDER)); new AuditEvent("closeRecordFolder", MSG_CLOSED_RECORD_FOLDER));
this.auditEvents.put("declareRecord", this.auditEvents.put("declareRecord",
new AuditEvent("declareRecord", MSG_DECLARED_RECORD)); new AuditEvent("declareRecord", MSG_DECLARED_RECORD));
this.auditEvents.put("undeclareRecord", this.auditEvents.put("undeclareRecord",
new AuditEvent("undeclareRecord", MSG_UNDECLARED_RECORD)); new AuditEvent("undeclareRecord", MSG_UNDECLARED_RECORD));
this.auditEvents.put("freeze", this.auditEvents.put("freeze",
new AuditEvent("freeze", MSG_FROZE_ITEM)); new AuditEvent("freeze", MSG_FROZE_ITEM));
this.auditEvents.put("relinquishHold", this.auditEvents.put("relinquishHold",
new AuditEvent("relinquishHold", MSG_RELINQUISED_HOLD)); new AuditEvent("relinquishHold", MSG_RELINQUISED_HOLD));
this.auditEvents.put("editHoldReason", this.auditEvents.put("editHoldReason",
new AuditEvent("editHoldReason", MSG_UPDATED_HOLD_REASON)); new AuditEvent("editHoldReason", MSG_UPDATED_HOLD_REASON));
this.auditEvents.put("editReviewAsOfDate", this.auditEvents.put("editReviewAsOfDate",
new AuditEvent("editReviewAsOfDate", MSG_UPDATED_REVIEW_AS_OF_DATE)); new AuditEvent("editReviewAsOfDate", MSG_UPDATED_REVIEW_AS_OF_DATE));
this.auditEvents.put("editDispositionActionAsOfDate", this.auditEvents.put("editDispositionActionAsOfDate",
new AuditEvent("editDispositionActionAsOfDate", MSG_UPDATED_DISPOSITION_AS_OF_DATE)); new AuditEvent("editDispositionActionAsOfDate", MSG_UPDATED_DISPOSITION_AS_OF_DATE));
this.auditEvents.put("broadcastVitalRecordDefinition", this.auditEvents.put("broadcastVitalRecordDefinition",
new AuditEvent("broadcastVitalRecordDefinition", MSG_UPDATED_VITAL_RECORD_DEFINITION)); new AuditEvent("broadcastVitalRecordDefinition", MSG_UPDATED_VITAL_RECORD_DEFINITION));
this.auditEvents.put("broadcastDispositionActionDefinitionUpdate", this.auditEvents.put("broadcastDispositionActionDefinitionUpdate",
new AuditEvent("broadcastDispositionActionDefinitionUpdate", MSG_UPDATED_DISPOSITOIN_ACTION_DEFINITION)); new AuditEvent("broadcastDispositionActionDefinitionUpdate", MSG_UPDATED_DISPOSITOIN_ACTION_DEFINITION));
this.auditEvents.put("completeEvent", this.auditEvents.put("completeEvent",
new AuditEvent("completeEvent", MSG_COMPELTED_EVENT)); new AuditEvent("completeEvent", MSG_COMPELTED_EVENT));
this.auditEvents.put("undoEvent", this.auditEvents.put("undoEvent",
new AuditEvent("undoEvent", MSG_REVERSED_COMPLETE_EVENT)); new AuditEvent("undoEvent", MSG_REVERSED_COMPLETE_EVENT));
this.auditEvents.put("transfer", this.auditEvents.put("transfer",
new AuditEvent("transfer", MSG_TRANSFERRED_ITEM)); new AuditEvent("transfer", MSG_TRANSFERRED_ITEM));
this.auditEvents.put("transferComplete", this.auditEvents.put("transferComplete",
new AuditEvent("transferComplete", MSG_COMPLETED_TRANSFER)); new AuditEvent("transferComplete", MSG_COMPLETED_TRANSFER));
this.auditEvents.put("accession", this.auditEvents.put("accession",
new AuditEvent("accession", MSG_ACCESSION)); new AuditEvent("accession", MSG_ACCESSION));
this.auditEvents.put("accessionComplete", this.auditEvents.put("accessionComplete",
new AuditEvent("accessionComplete", MSG_COMPLETED_ACCESSION)); new AuditEvent("accessionComplete", MSG_COMPLETED_ACCESSION));
this.auditEvents.put("applyScannedRecord", this.auditEvents.put("applyScannedRecord",
new AuditEvent("applyScannedRecord", MSG_SCANNED_RECORD)); new AuditEvent("applyScannedRecord", MSG_SCANNED_RECORD));
this.auditEvents.put("applyPdfRecord", this.auditEvents.put("applyPdfRecord",
new AuditEvent("applyPdfRecord", MSG_PDF_RECORD)); new AuditEvent("applyPdfRecord", MSG_PDF_RECORD));
this.auditEvents.put("applyDigitalPhotographRecord", this.auditEvents.put("applyDigitalPhotographRecord",
new AuditEvent("applyDigitalPhotographRecord", MSG_PHOTO_RECORD)); new AuditEvent("applyDigitalPhotographRecord", MSG_PHOTO_RECORD));
this.auditEvents.put("applyWebRecord", this.auditEvents.put("applyWebRecord",
new AuditEvent("applyWebRecord", MSG_WEB_RECORD)); new AuditEvent("applyWebRecord", MSG_WEB_RECORD));
this.auditEvents.put("createDispositionSchedule", this.auditEvents.put("createDispositionSchedule",
new AuditEvent("createDispositionSchedule", MSG_CREATE_DISPOSITION_SCHEDULE)); new AuditEvent("createDispositionSchedule", MSG_CREATE_DISPOSITION_SCHEDULE));
this.auditEvents.put("unfreeze", this.auditEvents.put("unfreeze",
new AuditEvent("unfreeze", MSG_UNFREEZE)); new AuditEvent("unfreeze", MSG_UNFREEZE));
this.auditEvents.put("reject",
new AuditEvent("reject", MSG_REJECT_RECORD));
} }
@Override @Override
protected void onBootstrap(ApplicationEvent event) protected void onBootstrap(ApplicationEvent event)
{ {
@@ -330,15 +333,15 @@ public class RecordsManagementAuditServiceImpl
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
OnUpdatePropertiesPolicy.QNAME, OnUpdatePropertiesPolicy.QNAME,
RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID, RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID,
new JavaBehaviour(this, "onUpdateProperties")); new JavaBehaviour(this, "onUpdateProperties"));
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
OnCreateNodePolicy.QNAME, OnCreateNodePolicy.QNAME,
RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID, RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID,
new JavaBehaviour(this, "onCreateNode")); new JavaBehaviour(this, "onCreateNode"));
policyComponent.bindClassBehaviour( policyComponent.bindClassBehaviour(
BeforeDeleteNodePolicy.QNAME, BeforeDeleteNodePolicy.QNAME,
RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID, RecordsManagementModel.ASPECT_RECORD_COMPONENT_ID,
new JavaBehaviour(this, "beforeDeleteNode")); new JavaBehaviour(this, "beforeDeleteNode"));
} }
@Override @Override
@@ -356,7 +359,7 @@ public class RecordsManagementAuditServiceImpl
RecordsManagementAuditService.RM_AUDIT_APPLICATION_NAME, RecordsManagementAuditService.RM_AUDIT_APPLICATION_NAME,
RecordsManagementAuditService.RM_AUDIT_PATH_ROOT); RecordsManagementAuditService.RM_AUDIT_PATH_ROOT);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -380,7 +383,7 @@ public class RecordsManagementAuditServiceImpl
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
logger.info("Stopped Records Management auditing"); logger.info("Stopped Records Management auditing");
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -390,7 +393,7 @@ public class RecordsManagementAuditServiceImpl
if (logger.isInfoEnabled()) if (logger.isInfoEnabled())
logger.debug("Records Management audit log has been cleared"); logger.debug("Records Management audit log has been cleared");
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -399,7 +402,7 @@ public class RecordsManagementAuditServiceImpl
// TODO: return proper date, for now it's today's date // TODO: return proper date, for now it's today's date
return new Date(); return new Date();
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -408,10 +411,10 @@ public class RecordsManagementAuditServiceImpl
// TODO: return proper date, for now it's today's date // TODO: return proper date, for now it's today's date
return new Date(); return new Date();
} }
/** /**
* A class to carry audit information through the transaction. * A class to carry audit information through the transaction.
* *
* @author Derek Hulley * @author Derek Hulley
* @since 3.2 * @since 3.2
*/ */
@@ -420,7 +423,7 @@ public class RecordsManagementAuditServiceImpl
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 RMAuditNode() private RMAuditNode()
{ {
} }
@@ -455,7 +458,7 @@ public class RecordsManagementAuditServiceImpl
this.nodePropertiesAfter = nodePropertiesAfter; this.nodePropertiesAfter = nodePropertiesAfter;
} }
} }
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)
{ {
auditRMEvent(nodeRef, RM_AUDIT_EVENT_UPDATE_RM_OBJECT, before, after); auditRMEvent(nodeRef, RM_AUDIT_EVENT_UPDATE_RM_OBJECT, before, after);
@@ -465,7 +468,7 @@ public class RecordsManagementAuditServiceImpl
{ {
auditRMEvent(nodeRef, RM_AUDIT_EVENT_DELETE_RM_OBJECT, null, null); auditRMEvent(nodeRef, RM_AUDIT_EVENT_DELETE_RM_OBJECT, null, null);
} }
public void onCreateNode(ChildAssociationRef childAssocRef) public void onCreateNode(ChildAssociationRef childAssocRef)
{ {
auditRMEvent(childAssocRef.getChildRef(), RM_AUDIT_EVENT_CREATE_RM_OBJECT, null, null); auditRMEvent(childAssocRef.getChildRef(), RM_AUDIT_EVENT_CREATE_RM_OBJECT, null, null);
@@ -482,10 +485,10 @@ public class RecordsManagementAuditServiceImpl
{ {
auditRMEvent(nodeRef, action.getName(), null, null); auditRMEvent(nodeRef, action.getName(), null, null);
} }
/** /**
* Audit an event for a node * Audit an event for a node
* *
* @param nodeRef the node to which the event applies * @param nodeRef the node to which the event applies
* @param eventName the name of the event * @param eventName the name of the event
* @param nodePropertiesBefore properties before the event (optional) * @param nodePropertiesBefore properties before the event (optional)
@@ -558,14 +561,14 @@ public class RecordsManagementAuditServiceImpl
* modified nodes and generates the audit information. * 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
*/ */
private class RMAuditTxnListener extends TransactionListenerAdapter private class RMAuditTxnListener extends TransactionListenerAdapter
{ {
private final Log logger = LogFactory.getLog(RecordsManagementAuditServiceImpl.class); private final Log logger = LogFactory.getLog(RecordsManagementAuditServiceImpl.class);
/* /*
* Equality and hashcode generation are left unimplemented; we expect to only have a single * Equality and hashcode generation are left unimplemented; we expect to only have a single
* instance of this class per action. * instance of this class per action.
@@ -578,7 +581,7 @@ public class RecordsManagementAuditServiceImpl
public void afterCommit() public void afterCommit()
{ {
final Map<NodeRef, RMAuditNode> auditedNodes = TransactionalResourceHelper.getMap(KEY_RM_AUDIT_NODE_RECORDS); final Map<NodeRef, RMAuditNode> auditedNodes = TransactionalResourceHelper.getMap(KEY_RM_AUDIT_NODE_RECORDS);
// Start a *new* read-write transaction to audit in // Start a *new* read-write transaction to audit in
RetryingTransactionCallback<Void> auditCallback = new RetryingTransactionCallback<Void>() RetryingTransactionCallback<Void> auditCallback = new RetryingTransactionCallback<Void>()
{ {
@@ -593,7 +596,7 @@ public class RecordsManagementAuditServiceImpl
/** /**
* Do the actual auditing, assuming the presence of a viable transaction * Do the actual auditing, assuming the presence of a viable transaction
* *
* @param auditedNodes details of the nodes that were modified * @param auditedNodes details of the nodes that were modified
*/ */
private void auditInTxn(Map<NodeRef, RMAuditNode> auditedNodes) throws Throwable private void auditInTxn(Map<NodeRef, RMAuditNode> auditedNodes) throws Throwable
@@ -603,15 +606,15 @@ public class RecordsManagementAuditServiceImpl
for (Map.Entry<NodeRef, RMAuditNode> entry : auditedNodes.entrySet()) for (Map.Entry<NodeRef, RMAuditNode> entry : auditedNodes.entrySet())
{ {
NodeRef nodeRef = entry.getKey(); NodeRef nodeRef = entry.getKey();
// If the node is gone, then do nothing // If the node is gone, then do nothing
if (!nodeService.exists(nodeRef)) if (!nodeService.exists(nodeRef))
{ {
continue; continue;
} }
RMAuditNode auditedNode = entry.getValue(); RMAuditNode auditedNode = entry.getValue();
Map<String, Serializable> auditMap = new HashMap<String, Serializable>(13); Map<String, Serializable> auditMap = new HashMap<String, Serializable>(13);
// Action description // Action description
String eventName = auditedNode.getEventName(); String eventName = auditedNode.getEventName();
@@ -676,18 +679,18 @@ public class RecordsManagementAuditServiceImpl
} }
} }
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public File getAuditTrailFile(RecordsManagementAuditQueryParameters params, ReportFormat format) public File getAuditTrailFile(RecordsManagementAuditQueryParameters params, ReportFormat format)
{ {
ParameterCheck.mandatory("params", params); ParameterCheck.mandatory("params", params);
Writer fileWriter = null; Writer fileWriter = null;
try try
{ {
File auditTrailFile = TempFileProvider.createTempFile(AUDIT_TRAIL_FILE_PREFIX, File auditTrailFile = TempFileProvider.createTempFile(AUDIT_TRAIL_FILE_PREFIX,
format == ReportFormat.HTML ? AUDIT_TRAIL_HTML_FILE_SUFFIX : AUDIT_TRAIL_JSON_FILE_SUFFIX); format == ReportFormat.HTML ? AUDIT_TRAIL_HTML_FILE_SUFFIX : AUDIT_TRAIL_JSON_FILE_SUFFIX);
fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(auditTrailFile),"UTF8")); fileWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(auditTrailFile),"UTF8"));
// Get the results, dumping to file // Get the results, dumping to file
@@ -708,14 +711,14 @@ public class RecordsManagementAuditServiceImpl
} }
} }
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public List<RecordsManagementAuditEntry> getAuditTrail(RecordsManagementAuditQueryParameters params) public List<RecordsManagementAuditEntry> getAuditTrail(RecordsManagementAuditQueryParameters params)
{ {
ParameterCheck.mandatory("params", params); ParameterCheck.mandatory("params", params);
List<RecordsManagementAuditEntry> entries = new ArrayList<RecordsManagementAuditEntry>(50); List<RecordsManagementAuditEntry> entries = new ArrayList<RecordsManagementAuditEntry>(50);
try try
{ {
@@ -729,10 +732,10 @@ public class RecordsManagementAuditServiceImpl
throw new AlfrescoRuntimeException(MSG_TRAIL_FILE_FAIL, e); throw new AlfrescoRuntimeException(MSG_TRAIL_FILE_FAIL, e);
} }
} }
/** /**
* Get the audit trail, optionally dumping the results the the given writer dumping to a list. * Get the audit trail, optionally dumping the results the the given writer dumping to a list.
* *
* @param params the search parameters * @param params the search parameters
* @param results the list to which individual results will be dumped * @param results the list to which individual results will be dumped
* @param writer Writer to write the audit trail * @param writer Writer to write the audit trail
@@ -747,13 +750,13 @@ public class RecordsManagementAuditServiceImpl
{ {
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
logger.debug("Retrieving audit trail in '" + reportFormat + "' format using parameters: " + params); logger.debug("Retrieving audit trail in '" + reportFormat + "' format using parameters: " + params);
// define the callback // define the callback
AuditQueryCallback callback = new AuditQueryCallback() AuditQueryCallback callback = new AuditQueryCallback()
{ {
private boolean firstEntry = true; private boolean firstEntry = true;
public boolean valuesRequired() public boolean valuesRequired()
{ {
return true; return true;
@@ -767,7 +770,7 @@ public class RecordsManagementAuditServiceImpl
logger.warn(errorMsg, error); logger.warn(errorMsg, error);
return true; return true;
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean handleAuditEntry( public boolean handleAuditEntry(
Long entryId, Long entryId,
@@ -781,7 +784,7 @@ public class RecordsManagementAuditServiceImpl
{ {
return false; return false;
} }
Date timestamp = new Date(time); Date timestamp = new Date(time);
String eventName = null; String eventName = null;
String fullName = null; String fullName = null;
@@ -793,7 +796,7 @@ public class RecordsManagementAuditServiceImpl
String namePath = null; String namePath = null;
Map<QName, Serializable> beforeProperties = null; Map<QName, Serializable> beforeProperties = null;
Map<QName, Serializable> afterProperties = null; Map<QName, Serializable> afterProperties = null;
if (values.containsKey(RecordsManagementAuditService.RM_AUDIT_DATA_EVENT_NAME)) if (values.containsKey(RecordsManagementAuditService.RM_AUDIT_DATA_EVENT_NAME))
{ {
// This data is /RM/event/... // This data is /RM/event/...
@@ -809,7 +812,7 @@ public class RecordsManagementAuditServiceImpl
RecordsManagementAuditService.RM_AUDIT_DATA_NODE_CHANGES_BEFORE); RecordsManagementAuditService.RM_AUDIT_DATA_NODE_CHANGES_BEFORE);
afterProperties = (Map<QName, Serializable>) values.get( afterProperties = (Map<QName, Serializable>) values.get(
RecordsManagementAuditService.RM_AUDIT_DATA_NODE_CHANGES_AFTER); RecordsManagementAuditService.RM_AUDIT_DATA_NODE_CHANGES_AFTER);
// Convert some of the values to recognizable forms // Convert some of the values to recognizable forms
nodeType = null; nodeType = null;
if (nodeTypeQname != null) if (nodeTypeQname != null)
@@ -842,7 +845,7 @@ public class RecordsManagementAuditServiceImpl
// Skip it // Skip it
return true; return true;
} }
// TODO: Refactor this to use the builder pattern // TODO: Refactor this to use the builder pattern
RecordsManagementAuditEntry entry = new RecordsManagementAuditEntry( RecordsManagementAuditEntry entry = new RecordsManagementAuditEntry(
timestamp, timestamp,
@@ -857,24 +860,24 @@ public class RecordsManagementAuditServiceImpl
namePath, namePath,
beforeProperties, beforeProperties,
afterProperties); afterProperties);
// write out the entry to the file in requested format // write out the entry to the file in requested format
writeEntryToFile(entry); writeEntryToFile(entry);
if (results != null) if (results != null)
{ {
results.add(entry); results.add(entry);
} }
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug(" " + entry); logger.debug(" " + entry);
} }
// Keep going // Keep going
return true; return true;
} }
private void writeEntryToFile(RecordsManagementAuditEntry entry) private void writeEntryToFile(RecordsManagementAuditEntry entry)
{ {
if (writer == null) if (writer == null)
@@ -898,13 +901,13 @@ public class RecordsManagementAuditServiceImpl
{ {
firstEntry = false; firstEntry = false;
} }
// write the entry to the file // write the entry to the file
if (reportFormat == ReportFormat.JSON) if (reportFormat == ReportFormat.JSON)
{ {
writer.write("\n\t\t"); writer.write("\n\t\t");
} }
writeAuditTrailEntry(writer, entry, reportFormat); writeAuditTrailEntry(writer, entry, reportFormat);
} }
catch (IOException ioe) catch (IOException ioe)
@@ -913,17 +916,17 @@ public class RecordsManagementAuditServiceImpl
} }
} }
}; };
String user = params.getUser(); String user = params.getUser();
Long fromTime = (params.getDateFrom() == null ? null : new Long(params.getDateFrom().getTime())); Long fromTime = (params.getDateFrom() == null ? null : new Long(params.getDateFrom().getTime()));
Long toTime = (params.getDateTo() == null ? null : new Long(params.getDateTo().getTime())); Long toTime = (params.getDateTo() == null ? null : new Long(params.getDateTo().getTime()));
NodeRef nodeRef = params.getNodeRef(); NodeRef nodeRef = params.getNodeRef();
int maxEntries = params.getMaxEntries(); int maxEntries = params.getMaxEntries();
boolean forward = maxEntries > 0 ? false : true; // Reverse order if the results are limited boolean forward = maxEntries > 0 ? false : true; // Reverse order if the results are limited
// start the audit trail report // start the audit trail report
writeAuditTrailHeader(writer, params, reportFormat); writeAuditTrailHeader(writer, params, reportFormat);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("RM Audit: Issuing query: " + params); logger.debug("RM Audit: Issuing query: " + params);
@@ -942,50 +945,50 @@ public class RecordsManagementAuditServiceImpl
} }
// Get audit entries // Get audit entries
auditService.auditQuery(callback, auditQueryParams, maxEntries); auditService.auditQuery(callback, auditQueryParams, maxEntries);
// finish off the audit trail report // finish off the audit trail report
writeAuditTrailFooter(writer, reportFormat); writeAuditTrailFooter(writer, reportFormat);
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
public NodeRef fileAuditTrailAsRecord(RecordsManagementAuditQueryParameters params, public NodeRef fileAuditTrailAsRecord(RecordsManagementAuditQueryParameters params,
NodeRef destination, ReportFormat format) NodeRef destination, ReportFormat format)
{ {
ParameterCheck.mandatory("params", params); ParameterCheck.mandatory("params", params);
ParameterCheck.mandatory("destination", destination); ParameterCheck.mandatory("destination", destination);
// NOTE: the underlying RM services will check all the remaining pre-conditions // NOTE: the underlying RM services will check all the remaining pre-conditions
NodeRef record = null; NodeRef record = null;
// get the audit trail for the provided parameters // get the audit trail for the provided parameters
File auditTrail = this.getAuditTrailFile(params, format); File auditTrail = this.getAuditTrailFile(params, format);
if (logger.isDebugEnabled()) if (logger.isDebugEnabled())
{ {
logger.debug("Filing audit trail in file " + auditTrail.getAbsolutePath() + logger.debug("Filing audit trail in file " + auditTrail.getAbsolutePath() +
" as a record in record folder: " + destination); " as a record in record folder: " + destination);
} }
try try
{ {
Map<QName, Serializable> properties = new HashMap<QName, Serializable>(1); Map<QName, Serializable> properties = new HashMap<QName, Serializable>(1);
properties.put(ContentModel.PROP_NAME, auditTrail.getName()); properties.put(ContentModel.PROP_NAME, auditTrail.getName());
// file the audit log as an undeclared record // file the audit log as an undeclared record
record = this.nodeService.createNode(destination, record = this.nodeService.createNode(destination,
ContentModel.ASSOC_CONTAINS, ContentModel.ASSOC_CONTAINS,
QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI, QName.createQName(NamespaceService.CONTENT_MODEL_1_0_URI,
QName.createValidLocalName(auditTrail.getName())), QName.createValidLocalName(auditTrail.getName())),
ContentModel.TYPE_CONTENT, properties).getChildRef(); ContentModel.TYPE_CONTENT, properties).getChildRef();
// Set the content // Set the content
ContentWriter writer = this.contentService.getWriter(record, ContentModel.PROP_CONTENT, true); ContentWriter writer = this.contentService.getWriter(record, ContentModel.PROP_CONTENT, true);
writer.setMimetype(format == ReportFormat.HTML ? MimetypeMap.MIMETYPE_HTML : MimetypeMap.MIMETYPE_JSON); writer.setMimetype(format == ReportFormat.HTML ? MimetypeMap.MIMETYPE_HTML : MimetypeMap.MIMETYPE_JSON);
writer.setEncoding("UTF-8"); writer.setEncoding("UTF-8");
writer.putContent(auditTrail); writer.putContent(auditTrail);
} }
finally finally
{ {
@@ -997,11 +1000,11 @@ public class RecordsManagementAuditServiceImpl
{ {
auditTrail.delete(); auditTrail.delete();
} }
} }
return record; return record;
} }
/** /**
* {@inheritDoc} * {@inheritDoc}
*/ */
@@ -1011,24 +1014,24 @@ public class RecordsManagementAuditServiceImpl
listAuditEvents.addAll(this.auditEvents.values()); listAuditEvents.addAll(this.auditEvents.values());
return listAuditEvents; return listAuditEvents;
} }
/** /**
* Writes the start of the audit trail stream to the given writer * Writes the start of the audit trail stream to the given writer
* *
* @param writer The writer to write to * @param writer The writer to write to
* @params params The parameters being used * @params params The parameters being used
* @param reportFormat The format to write the header in * @param reportFormat The format to write the header in
* @throws IOException * @throws IOException
*/ */
private void writeAuditTrailHeader(Writer writer, private void writeAuditTrailHeader(Writer writer,
RecordsManagementAuditQueryParameters params, RecordsManagementAuditQueryParameters params,
ReportFormat reportFormat) throws IOException ReportFormat reportFormat) throws IOException
{ {
if (writer == null) if (writer == null)
{ {
return; return;
} }
if (reportFormat == ReportFormat.HTML) if (reportFormat == ReportFormat.HTML)
{ {
// write header as HTML // write header as HTML
@@ -1053,35 +1056,35 @@ public class RecordsManagementAuditServiceImpl
writer.write(I18NUtil.getMessage(MSG_AUDIT_REPORT)); writer.write(I18NUtil.getMessage(MSG_AUDIT_REPORT));
writer.write("</h2>\n"); writer.write("</h2>\n");
writer.write("<div class=\"audit-info\">\n"); writer.write("<div class=\"audit-info\">\n");
writer.write("<span class=\"label\">From:</span>"); writer.write("<span class=\"label\">From:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
Date from = params.getDateFrom(); Date from = params.getDateFrom();
writer.write(from == null ? "&lt;Not Set&gt;" : StringEscapeUtils.escapeHtml(from.toString())); writer.write(from == null ? "&lt;Not Set&gt;" : StringEscapeUtils.escapeHtml(from.toString()));
writer.write("</span>"); writer.write("</span>");
writer.write("<span class=\"label\">To:</span>"); writer.write("<span class=\"label\">To:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
Date to = params.getDateTo(); Date to = params.getDateTo();
writer.write(to == null ? "&lt;Not Set&gt;" : StringEscapeUtils.escapeHtml(to.toString())); writer.write(to == null ? "&lt;Not Set&gt;" : StringEscapeUtils.escapeHtml(to.toString()));
writer.write("</span>"); writer.write("</span>");
writer.write("<span class=\"label\">Property:</span>"); writer.write("<span class=\"label\">Property:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
QName prop = params.getProperty(); QName prop = params.getProperty();
writer.write(prop == null ? "All" : StringEscapeUtils.escapeHtml(getPropertyLabel(prop))); writer.write(prop == null ? "All" : StringEscapeUtils.escapeHtml(getPropertyLabel(prop)));
writer.write("</span>"); writer.write("</span>");
writer.write("<span class=\"label\">User:</span>"); writer.write("<span class=\"label\">User:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
writer.write(params.getUser() == null ? "All" : StringEscapeUtils.escapeHtml(params.getUser())); writer.write(params.getUser() == null ? "All" : StringEscapeUtils.escapeHtml(params.getUser()));
writer.write("</span>"); writer.write("</span>");
writer.write("<span class=\"label\">Event:</span>"); writer.write("<span class=\"label\">Event:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
writer.write(params.getEvent() == null ? "All" : StringEscapeUtils.escapeHtml(getAuditEventLabel(params.getEvent()))); writer.write(params.getEvent() == null ? "All" : StringEscapeUtils.escapeHtml(getAuditEventLabel(params.getEvent())));
writer.write("</span>\n"); writer.write("</span>\n");
writer.write("</div>\n"); writer.write("</div>\n");
} }
else else
@@ -1097,10 +1100,10 @@ public class RecordsManagementAuditServiceImpl
writer.write(",\n\t\t\"entries\":["); writer.write(",\n\t\t\"entries\":[");
} }
} }
/** /**
* Writes an audit trail entry to the given writer * Writes an audit trail entry to the given writer
* *
* @param writer The writer to write to * @param writer The writer to write to
* @param entry The entry to write * @param entry The entry to write
* @param reportFormat The format to write the header in * @param reportFormat The format to write the header in
@@ -1113,7 +1116,7 @@ public class RecordsManagementAuditServiceImpl
{ {
return; return;
} }
if (reportFormat == ReportFormat.HTML) if (reportFormat == ReportFormat.HTML)
{ {
writer.write("<div class=\"audit-entry\">\n"); writer.write("<div class=\"audit-entry\">\n");
@@ -1124,8 +1127,8 @@ public class RecordsManagementAuditServiceImpl
writer.write("</span>"); writer.write("</span>");
writer.write("<span class=\"label\">User:</span>"); writer.write("<span class=\"label\">User:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
writer.write(entry.getFullName() != null ? writer.write(entry.getFullName() != null ?
StringEscapeUtils.escapeHtml(entry.getFullName()) : StringEscapeUtils.escapeHtml(entry.getFullName()) :
StringEscapeUtils.escapeHtml(entry.getUserName())); StringEscapeUtils.escapeHtml(entry.getUserName()));
writer.write("</span>"); writer.write("</span>");
if (entry.getUserRole() != null && entry.getUserRole().length() > 0) if (entry.getUserRole() != null && entry.getUserRole().length() > 0)
@@ -1168,19 +1171,19 @@ public class RecordsManagementAuditServiceImpl
{ {
displayPath = "/File Plan" + path.substring(idx); displayPath = "/File Plan" + path.substring(idx);
} }
writer.write("<span class=\"label\">Location:</span>"); writer.write("<span class=\"label\">Location:</span>");
writer.write("<span class=\"value\">"); writer.write("<span class=\"value\">");
writer.write(StringEscapeUtils.escapeHtml(displayPath)); writer.write(StringEscapeUtils.escapeHtml(displayPath));
writer.write("</span>"); writer.write("</span>");
} }
writer.write("</div>\n"); writer.write("</div>\n");
if (entry.getChangedProperties() != null) if (entry.getChangedProperties() != null)
{ {
writer.write("<table class=\"changed-values-table\" cellspacing=\"0\">"); writer.write("<table class=\"changed-values-table\" cellspacing=\"0\">");
writer.write("<tr><th>Property</th><th>Previous Value</th><th>New Value</th></tr>"); writer.write("<tr><th>Property</th><th>Previous Value</th><th>New Value</th></tr>");
// create an entry for each property that changed // create an entry for each property that changed
for (QName valueName : entry.getChangedProperties().keySet()) for (QName valueName : entry.getChangedProperties().keySet())
{ {
@@ -1188,17 +1191,17 @@ public class RecordsManagementAuditServiceImpl
writer.write("<tr><td>"); writer.write("<tr><td>");
writer.write(getPropertyLabel(valueName)); writer.write(getPropertyLabel(valueName));
writer.write("</td><td>"); writer.write("</td><td>");
Serializable oldValue = values.getFirst(); Serializable oldValue = values.getFirst();
writer.write(oldValue == null ? "&lt;none&gt;" : StringEscapeUtils.escapeHtml(oldValue.toString())); writer.write(oldValue == null ? "&lt;none&gt;" : StringEscapeUtils.escapeHtml(oldValue.toString()));
writer.write("</td><td>"); writer.write("</td><td>");
Serializable newValue = values.getSecond(); Serializable newValue = values.getSecond();
writer.write(newValue == null ? "&lt;none&gt;" : StringEscapeUtils.escapeHtml(newValue.toString())); writer.write(newValue == null ? "&lt;none&gt;" : StringEscapeUtils.escapeHtml(newValue.toString()));
writer.write("</td></tr>"); writer.write("</td></tr>");
} }
writer.write("</table>\n"); writer.write("</table>\n");
} }
writer.write("</div>"); writer.write("</div>");
} }
else else
@@ -1206,7 +1209,7 @@ public class RecordsManagementAuditServiceImpl
try try
{ {
JSONObject json = new JSONObject(); JSONObject json = new JSONObject();
json.put("timestamp", entry.getTimestampString()); json.put("timestamp", entry.getTimestampString());
json.put("userName", entry.getUserName()); json.put("userName", entry.getUserName());
json.put("userRole", entry.getUserRole() == null ? "": entry.getUserRole()); json.put("userRole", entry.getUserRole() == null ? "": entry.getUserRole());
@@ -1217,27 +1220,27 @@ public class RecordsManagementAuditServiceImpl
json.put("event", entry.getEvent() == null ? "": getAuditEventLabel(entry.getEvent())); json.put("event", entry.getEvent() == null ? "": getAuditEventLabel(entry.getEvent()));
json.put("identifier", entry.getIdentifier() == null ? "": entry.getIdentifier()); json.put("identifier", entry.getIdentifier() == null ? "": entry.getIdentifier());
json.put("path", entry.getPath() == null ? "": entry.getPath()); json.put("path", entry.getPath() == null ? "": entry.getPath());
JSONArray changedValues = new JSONArray(); JSONArray changedValues = new JSONArray();
if (entry.getChangedProperties() != null) if (entry.getChangedProperties() != null)
{ {
// create an entry for each property that changed // create an entry for each property that changed
for (QName valueName : entry.getChangedProperties().keySet()) for (QName valueName : entry.getChangedProperties().keySet())
{ {
Pair<Serializable, Serializable> values = entry.getChangedProperties().get(valueName); Pair<Serializable, Serializable> values = entry.getChangedProperties().get(valueName);
JSONObject changedValue = new JSONObject(); JSONObject changedValue = new JSONObject();
changedValue.put("name", getPropertyLabel(valueName)); changedValue.put("name", getPropertyLabel(valueName));
changedValue.put("previous", values.getFirst() == null ? "" : values.getFirst().toString()); changedValue.put("previous", values.getFirst() == null ? "" : values.getFirst().toString());
changedValue.put("new", values.getSecond() == null ? "" : values.getSecond().toString()); changedValue.put("new", values.getSecond() == null ? "" : values.getSecond().toString());
changedValues.put(changedValue); changedValues.put(changedValue);
} }
} }
json.put("changedValues", changedValues); json.put("changedValues", changedValues);
writer.write(json.toString()); writer.write(json.toString());
} }
catch (JSONException je) catch (JSONException je)
@@ -1246,10 +1249,10 @@ public class RecordsManagementAuditServiceImpl
} }
} }
} }
/** /**
* Writes the end of the audit trail stream to the given writer * Writes the end of the audit trail stream to the given writer
* *
* @param writer The writer to write to * @param writer The writer to write to
* @param reportFormat The format to write the footer in * @param reportFormat The format to write the footer in
* @throws IOException * @throws IOException
@@ -1260,7 +1263,7 @@ public class RecordsManagementAuditServiceImpl
{ {
return; return;
} }
if (reportFormat == ReportFormat.HTML) if (reportFormat == ReportFormat.HTML)
{ {
// write footer as HTML // write footer as HTML
@@ -1272,10 +1275,10 @@ public class RecordsManagementAuditServiceImpl
writer.write("\n\t\t]\n\t}\n}"); writer.write("\n\t\t]\n\t}\n}");
} }
} }
/** /**
* Returns the display label for a property QName * Returns the display label for a property QName
* *
* @param property The property to get label for * @param property The property to get label for
* @param ddService DictionaryService instance * @param ddService DictionaryService instance
* @param namespaceService NamespaceService instance * @param namespaceService NamespaceService instance
@@ -1284,37 +1287,37 @@ public class RecordsManagementAuditServiceImpl
private String getPropertyLabel(QName property) private String getPropertyLabel(QName property)
{ {
String label = null; String label = null;
PropertyDefinition propDef = this.dictionaryService.getProperty(property); PropertyDefinition propDef = this.dictionaryService.getProperty(property);
if (propDef != null) if (propDef != null)
{ {
label = propDef.getTitle(); label = propDef.getTitle();
} }
if (label == null) if (label == null)
{ {
label = property.getLocalName(); label = property.getLocalName();
} }
return label; return label;
} }
/** /**
* Returns the display label for the given audit event key * Returns the display label for the given audit event key
* *
* @param eventKey The audit event key * @param eventKey The audit event key
* @return The display label or null if the key does not exist * @return The display label or null if the key does not exist
*/ */
private String getAuditEventLabel(String eventKey) private String getAuditEventLabel(String eventKey)
{ {
String label = eventKey; String label = eventKey;
AuditEvent event = this.auditEvents.get(eventKey); AuditEvent event = this.auditEvents.get(eventKey);
if (event != null) if (event != null)
{ {
label = event.getLabel(); label = event.getLabel();
} }
return label; return label;
} }
} }