mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-06-30 18:15:39 +00:00
- 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
1372 lines
51 KiB
Java
1372 lines
51 KiB
Java
/*
|
|
* Copyright (C) 2005-2007 Alfresco Software Limited.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
* As a special exception to the terms and conditions of version 2.0 of
|
|
* the GPL, you may redistribute this Program in connection with Free/Libre
|
|
* and Open Source Software ("FLOSS") applications as described in Alfresco's
|
|
* FLOSS exception. You should have recieved a copy of the text describing
|
|
* the FLOSS exception, and it is also available here:
|
|
* http://www.alfresco.com/legal/licensing
|
|
*/
|
|
package org.alfresco.repo.audit;
|
|
|
|
import java.io.Serializable;
|
|
import java.lang.reflect.Method;
|
|
import java.net.InetAddress;
|
|
import java.net.UnknownHostException;
|
|
import java.util.Collections;
|
|
import java.util.Date;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
|
|
import org.alfresco.error.AlfrescoRuntimeException;
|
|
import org.alfresco.repo.audit.extractor.DataExtractor;
|
|
import org.alfresco.repo.audit.generator.DataGenerator;
|
|
import org.alfresco.repo.audit.model.AuditApplication;
|
|
import org.alfresco.repo.audit.model.AuditEntry;
|
|
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
|
import org.alfresco.repo.audit.model.TrueFalseUnset;
|
|
import org.alfresco.repo.domain.audit.AuditDAO;
|
|
import org.alfresco.repo.domain.propval.PropertyValueDAO;
|
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
|
import org.alfresco.service.Auditable;
|
|
import org.alfresco.service.NotAuditable;
|
|
import org.alfresco.service.PublicService;
|
|
import org.alfresco.service.cmr.audit.AuditInfo;
|
|
import org.alfresco.service.cmr.audit.AuditService.AuditQueryCallback;
|
|
import org.alfresco.service.cmr.repository.ChildAssociationRef;
|
|
import org.alfresco.service.cmr.repository.NodeRef;
|
|
import org.alfresco.service.cmr.repository.NodeService;
|
|
import org.alfresco.service.cmr.repository.Path;
|
|
import org.alfresco.service.cmr.repository.StoreRef;
|
|
import org.alfresco.service.cmr.search.SearchParameters;
|
|
import org.alfresco.service.namespace.NamespacePrefixResolver;
|
|
import org.alfresco.service.transaction.TransactionService;
|
|
import org.alfresco.util.ParameterCheck;
|
|
import org.alfresco.util.PathMapper;
|
|
import org.aopalliance.intercept.MethodInvocation;
|
|
import org.apache.commons.logging.Log;
|
|
import org.apache.commons.logging.LogFactory;
|
|
|
|
/**
|
|
* The default audit component implementation. TODO: Implement before, after and exception filtering. At the moment
|
|
* these filters are ignored. TODO: Respect audit internal - at the moment audit internal is fixed to false.
|
|
* <p/>
|
|
* The V3.2 audit functionality is contained within the same component. When the newer audit
|
|
* implementation has been tested and approved, then older ones will be deprecated as necessary.
|
|
*
|
|
* @author Andy Hind
|
|
* @author Derek Hulley
|
|
*/
|
|
public class AuditComponentImpl implements AuditComponent
|
|
{
|
|
/**
|
|
* The application name to use for audit entries generated by method interception around public services.
|
|
*/
|
|
private static final String SYSTEM_APPLICATION = "SystemMethodInterceptor";
|
|
|
|
/**
|
|
* Logging
|
|
*/
|
|
private static Log logger = LogFactory.getLog(AuditComponentImpl.class);
|
|
|
|
/**
|
|
* Suspend resume auditing
|
|
*/
|
|
private static ThreadLocal<Boolean> auditFlag = new ThreadLocal<Boolean>();
|
|
|
|
/**
|
|
* IOC
|
|
*/
|
|
private PublicServiceIdentifier publicServiceIdentifier;
|
|
|
|
private AuditConfiguration auditConfiguration;
|
|
|
|
private AuditDAO auditDAO;
|
|
|
|
private TransactionService transactionService;
|
|
|
|
private NodeService nodeService;
|
|
|
|
private NamespacePrefixResolver namespacePrefixResolver;
|
|
|
|
private AuditModel auditModel;
|
|
|
|
/**
|
|
* Keep hold of the host where the audit occurs. TODO: Check that we get the correct address ...
|
|
*/
|
|
|
|
private InetAddress auditHost;
|
|
|
|
|
|
|
|
/**
|
|
* Default constructor
|
|
*/
|
|
public AuditComponentImpl()
|
|
{
|
|
super();
|
|
// Initialise the host address
|
|
try
|
|
{
|
|
auditHost = InetAddress.getLocalHost();
|
|
}
|
|
catch (UnknownHostException e)
|
|
{
|
|
logger.error("Failed to get local host address", e);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* IOC property setters
|
|
*/
|
|
|
|
/**
|
|
* Set the DAO for recording auditable information when no exception occurs.
|
|
*/
|
|
public void setAuditDAO(AuditDAO auditDAO)
|
|
{
|
|
this.auditDAO = auditDAO;
|
|
}
|
|
|
|
/**
|
|
* Set the DAO for recording failed actions - this is done in another transaction.
|
|
*/
|
|
public void setTransactionService(TransactionService transactionService)
|
|
{
|
|
this.transactionService = transactionService;
|
|
}
|
|
|
|
/**
|
|
* Set the NodeService for path extracting.
|
|
*/
|
|
public void setNodeService(NodeService nodeService)
|
|
{
|
|
this.nodeService = nodeService;
|
|
}
|
|
|
|
/**
|
|
* Set the audit configuration.
|
|
*/
|
|
public void setAuditConfiguration(AuditConfiguration auditConfiguration)
|
|
{
|
|
this.auditConfiguration = auditConfiguration;
|
|
}
|
|
|
|
/**
|
|
* Set the helper used to identify public services
|
|
*/
|
|
public void setPublicServiceIdentifier(PublicServiceIdentifier publicServiceIdentifier)
|
|
{
|
|
this.publicServiceIdentifier = publicServiceIdentifier;
|
|
}
|
|
|
|
/**
|
|
* Set the audit model.
|
|
*/
|
|
public void setAuditModel(AuditModel auditModel)
|
|
{
|
|
this.auditModel = auditModel;
|
|
}
|
|
|
|
|
|
/**
|
|
* Set the namespacePrefixResolver.
|
|
*/
|
|
public void setNamespacePrefixResolver(NamespacePrefixResolver namespacePrefixResolver)
|
|
{
|
|
this.namespacePrefixResolver = namespacePrefixResolver;
|
|
}
|
|
|
|
public Object audit(MethodInvocation mi) throws Throwable
|
|
{
|
|
if ((auditFlag.get() == null) || (!auditFlag.get().booleanValue()))
|
|
{
|
|
if (auditModel instanceof AuditEntry && ((AuditEntry) auditModel).getEnabled() == TrueFalseUnset.TRUE)
|
|
{
|
|
boolean auditInternal = (auditModel.getAuditInternalServiceMethods(mi) == TrueFalseUnset.TRUE);
|
|
try
|
|
{
|
|
Method method = mi.getMethod();
|
|
String methodName = method.getName();
|
|
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
|
|
|
|
if (!auditInternal)
|
|
{
|
|
auditFlag.set(Boolean.TRUE);
|
|
}
|
|
else
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Auditing internal service use for - " + serviceName + "." + methodName);
|
|
}
|
|
}
|
|
|
|
if (method.isAnnotationPresent(Auditable.class))
|
|
{
|
|
|
|
if (serviceName != null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Auditing - " + serviceName + "." + methodName);
|
|
}
|
|
return auditImpl(mi);
|
|
}
|
|
else
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("UnknownService." + methodName);
|
|
}
|
|
return auditImpl(mi);
|
|
}
|
|
|
|
}
|
|
else if (method.isAnnotationPresent(NotAuditable.class))
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Not Audited. " + serviceName + "." + methodName);
|
|
}
|
|
return mi.proceed();
|
|
}
|
|
else
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Unannotated service method " + serviceName + "." + methodName);
|
|
}
|
|
if (method.getDeclaringClass().isInterface() && method.getDeclaringClass().isAnnotationPresent(PublicService.class))
|
|
{
|
|
throw new RuntimeException("Unannotated service method " + serviceName + "." + methodName);
|
|
}
|
|
else
|
|
{
|
|
return mi.proceed();
|
|
}
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
if (!auditInternal)
|
|
{
|
|
auditFlag.set(Boolean.FALSE);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return mi.proceed();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return mi.proceed();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Internal audit of a method invocation
|
|
*
|
|
* @param mi -
|
|
* the method to audit
|
|
* @return - the return object from the audited method
|
|
* @throws Throwable -
|
|
* any Throwable that can be thrown by th audtied method.
|
|
*/
|
|
public Object auditImpl(MethodInvocation mi) throws Throwable
|
|
{
|
|
final AuditState auditInfo = new AuditState(auditConfiguration);
|
|
// RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
|
|
AuditMode auditMode = AuditMode.UNSET;
|
|
try
|
|
{
|
|
auditMode = beforeInvocation(auditMode, auditInfo, mi);
|
|
Object o = mi.proceed();
|
|
auditMode = postInvocation(auditMode, auditInfo, mi, o);
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.SUCCESS))
|
|
{
|
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
|
{
|
|
public Object execute() throws Throwable
|
|
{
|
|
auditDAO.audit(auditInfo);
|
|
return null;
|
|
}
|
|
};
|
|
boolean requiresNew = (AlfrescoTransactionSupport.getTransactionReadState() != TxnReadState.TXN_READ_WRITE);
|
|
transactionService.getRetryingTransactionHelper().doInTransaction(cb, false, requiresNew);
|
|
}
|
|
return o;
|
|
}
|
|
catch (Throwable t)
|
|
{
|
|
auditMode = onError(auditMode, auditInfo, mi, t);
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
|
|
{
|
|
try
|
|
{
|
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
|
{
|
|
public Object execute() throws Throwable
|
|
{
|
|
auditDAO.audit(auditInfo);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
transactionService.getRetryingTransactionHelper().doInTransaction(cb, false, true);
|
|
}
|
|
catch (Throwable tt)
|
|
{
|
|
throw new AuditException("Failed to audit exception", new Object[] { tt }, t);
|
|
}
|
|
}
|
|
throw t;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to set auditable properties and to determine if auditing is required when an exception is caught in
|
|
* the audited method.
|
|
*
|
|
* @param auditMode
|
|
* @param auditInfo
|
|
* @param mi
|
|
* @param t
|
|
* @return - the audit mode
|
|
*/
|
|
private AuditMode onError(AuditMode auditMode, AuditState auditInfo, MethodInvocation mi, Throwable t)
|
|
{
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
|
|
{
|
|
auditInfo.setFail(true);
|
|
auditInfo.setThrowable(t);
|
|
}
|
|
|
|
return auditMode;
|
|
}
|
|
|
|
/**
|
|
* Helper method to set audited information after method invocation and to determine if auditing should take place
|
|
* based on the method return value.
|
|
*
|
|
* @param auditMode
|
|
* @param auditInfo
|
|
* @param mi
|
|
* @param returnObject
|
|
* @return - the audit mode.
|
|
*/
|
|
private AuditMode postInvocation(AuditMode auditMode, AuditState auditInfo, MethodInvocation mi, Object returnObject)
|
|
{
|
|
if (returnObject == null)
|
|
{
|
|
auditInfo.setReturnObject(null);
|
|
}
|
|
else if (returnObject instanceof Serializable)
|
|
{
|
|
auditInfo.setReturnObject((Serializable) returnObject);
|
|
}
|
|
else
|
|
{
|
|
auditInfo.setReturnObject(returnObject.toString());
|
|
}
|
|
|
|
Auditable auditable = mi.getMethod().getAnnotation(Auditable.class);
|
|
if (auditable.key() == Auditable.Key.RETURN)
|
|
{
|
|
if (returnObject != null)
|
|
{
|
|
if (returnObject instanceof NodeRef)
|
|
{
|
|
NodeRef key = (NodeRef) returnObject;
|
|
auditInfo.setKeyStore(key.getStoreRef());
|
|
auditInfo.setKeyGUID(key.getId());
|
|
RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
|
|
if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE)
|
|
{
|
|
auditInfo.setPath(getNodePath(key));
|
|
}
|
|
}
|
|
else if (returnObject instanceof StoreRef)
|
|
{
|
|
auditInfo.setKeyStore((StoreRef) returnObject);
|
|
}
|
|
else if (returnObject instanceof ChildAssociationRef)
|
|
{
|
|
ChildAssociationRef car = (ChildAssociationRef) returnObject;
|
|
auditInfo.setKeyStore(car.getChildRef().getStoreRef());
|
|
auditInfo.setKeyGUID(car.getChildRef().getId());
|
|
RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
|
|
if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE)
|
|
{
|
|
auditInfo.setPath(nodeService.getPath(car.getChildRef()).toString());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger.warn("Key argument is not a node, store or child assoc ref for return object on "
|
|
+ publicServiceIdentifier.getPublicServiceName(mi) + "." + mi.getMethod().getName() + " it is " + returnObject.getClass().getName());
|
|
}
|
|
}
|
|
}
|
|
|
|
// If the user name is not set, try and set it after the method call.
|
|
// This covers authentication when the user is only known after the call.
|
|
|
|
if (auditInfo.getUserIdentifier() == null)
|
|
{
|
|
auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
|
|
}
|
|
|
|
return auditMode;
|
|
}
|
|
|
|
/**
|
|
* Set auditable information and determine if auditing is required before method invocation. This would normally be
|
|
* based on the method arguments.
|
|
*
|
|
* @param auditMode
|
|
* @param auditInfo
|
|
* @param mi
|
|
* @return - the audit mode.
|
|
*/
|
|
private AuditMode beforeInvocation(AuditMode auditMode, AuditState auditInfo, MethodInvocation mi)
|
|
{
|
|
AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, mi);
|
|
|
|
if (auditMode != AuditMode.NONE)
|
|
{
|
|
String methodName = mi.getMethod().getName();
|
|
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
|
|
auditInfo.setAuditApplication(SYSTEM_APPLICATION);
|
|
auditInfo.setAuditConfiguration(auditConfiguration);
|
|
auditInfo.setAuditMethod(methodName);
|
|
auditInfo.setAuditService(serviceName);
|
|
auditInfo.setClientAddress(null);
|
|
auditInfo.setDate(new Date());
|
|
auditInfo.setFail(false);
|
|
auditInfo.setFiltered(false);
|
|
auditInfo.setHostAddress(auditHost);
|
|
|
|
auditInfo.setPath(null);
|
|
|
|
Auditable auditable = mi.getMethod().getAnnotation(Auditable.class);
|
|
Object key = null;
|
|
switch (auditable.key())
|
|
{
|
|
case ARG_0:
|
|
checkArgLength(mi, methodName, serviceName, 0);
|
|
key = mi.getArguments()[0];
|
|
break;
|
|
case ARG_1:
|
|
checkArgLength(mi, methodName, serviceName, 1);
|
|
key = mi.getArguments()[1];
|
|
break;
|
|
case ARG_2:
|
|
checkArgLength(mi, methodName, serviceName, 2);
|
|
key = mi.getArguments()[2];
|
|
break;
|
|
case ARG_3:
|
|
checkArgLength(mi, methodName, serviceName, 3);
|
|
key = mi.getArguments()[3];
|
|
break;
|
|
case ARG_4:
|
|
checkArgLength(mi, methodName, serviceName, 4);
|
|
key = mi.getArguments()[4];
|
|
break;
|
|
case ARG_5:
|
|
checkArgLength(mi, methodName, serviceName, 5);
|
|
key = mi.getArguments()[5];
|
|
break;
|
|
case ARG_6:
|
|
checkArgLength(mi, methodName, serviceName, 6);
|
|
key = mi.getArguments()[6];
|
|
break;
|
|
case ARG_7:
|
|
checkArgLength(mi, methodName, serviceName, 7);
|
|
key = mi.getArguments()[7];
|
|
break;
|
|
case ARG_8:
|
|
checkArgLength(mi, methodName, serviceName, 8);
|
|
key = mi.getArguments()[8];
|
|
break;
|
|
case ARG_9:
|
|
checkArgLength(mi, methodName, serviceName, 9);
|
|
key = mi.getArguments()[9];
|
|
break;
|
|
case NO_KEY:
|
|
default:
|
|
break;
|
|
}
|
|
if (key != null)
|
|
{
|
|
RecordOptions recordOptions = auditModel.getAuditRecordOptions(mi);
|
|
if (key instanceof NodeRef)
|
|
{
|
|
auditInfo.setKeyStore(((NodeRef) key).getStoreRef());
|
|
auditInfo.setKeyGUID(((NodeRef) key).getId());
|
|
if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE)
|
|
{
|
|
auditInfo.setPath(getNodePath((NodeRef) key));
|
|
}
|
|
}
|
|
else if (key instanceof StoreRef)
|
|
{
|
|
auditInfo.setKeyStore((StoreRef) key);
|
|
}
|
|
else if (key instanceof ChildAssociationRef)
|
|
{
|
|
ChildAssociationRef car = (ChildAssociationRef) key;
|
|
auditInfo.setKeyStore(car.getParentRef().getStoreRef());
|
|
auditInfo.setKeyGUID(car.getParentRef().getId());
|
|
if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE)
|
|
{
|
|
auditInfo.setPath(getNodePath(car.getParentRef()));
|
|
}
|
|
}
|
|
else if (key instanceof SearchParameters)
|
|
{
|
|
SearchParameters sp = (SearchParameters) key;
|
|
if (sp.getStores().size() > 0)
|
|
{
|
|
auditInfo.setKeyStore(sp.getStores().get(0));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
logger.warn("Key argument is not a node, store or child assoc reference or search parameters on "
|
|
+ serviceName + "." + methodName + " it is " + key.getClass().getName());
|
|
}
|
|
}
|
|
auditInfo.setKeyPropertiesAfter(null);
|
|
auditInfo.setKeyPropertiesBefore(null);
|
|
auditInfo.setMessage(null);
|
|
if (mi.getArguments() != null)
|
|
{
|
|
Serializable[] serArgs = new Serializable[mi.getArguments().length];
|
|
for (int i = 0; i < mi.getArguments().length; i++)
|
|
{
|
|
if ((auditable.recordable() == null) || (auditable.recordable().length <= i) || auditable.recordable()[i])
|
|
{
|
|
if (mi.getArguments()[i] == null)
|
|
{
|
|
serArgs[i] = null;
|
|
}
|
|
else if (mi.getArguments()[i] instanceof Serializable)
|
|
{
|
|
serArgs[i] = (Serializable) mi.getArguments()[i];
|
|
}
|
|
else
|
|
{
|
|
serArgs[i] = mi.getArguments()[i].toString();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
serArgs[i] = "********";
|
|
}
|
|
}
|
|
auditInfo.setMethodArguments(serArgs);
|
|
}
|
|
auditInfo.setReturnObject(null);
|
|
auditInfo.setSessionId(null);
|
|
auditInfo.setThrowable(null);
|
|
auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
|
|
auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
|
|
}
|
|
|
|
return effectiveAuditMode;
|
|
}
|
|
|
|
private void checkArgLength(MethodInvocation mi, String methodName, String serviceName, int position)
|
|
{
|
|
if (mi.getArguments().length <= position)
|
|
{
|
|
logger.warn("Auditable annotation on " + serviceName + "." + methodName + " references non existant argument");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* A simple audit entry Currently we ignore filtering here.
|
|
*/
|
|
public void audit(String source, String description, NodeRef key, Object... args)
|
|
{
|
|
final AuditState auditInfo = new AuditState(auditConfiguration);
|
|
AuditMode auditMode = AuditMode.UNSET;
|
|
try
|
|
{
|
|
auditMode = onApplicationAudit(auditMode, auditInfo, source, description, key, args);
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.SUCCESS))
|
|
{
|
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
|
{
|
|
public Object execute() throws Throwable
|
|
{
|
|
auditDAO.audit(auditInfo);
|
|
return null;
|
|
}
|
|
};
|
|
transactionService.getRetryingTransactionHelper().doInTransaction(cb, false, false);
|
|
}
|
|
}
|
|
catch (Throwable t)
|
|
{
|
|
auditMode = onError(auditMode, auditInfo, t, source, description, key, args);
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
|
|
{
|
|
try
|
|
{
|
|
RetryingTransactionCallback<Object> cb = new RetryingTransactionCallback<Object>()
|
|
{
|
|
public Object execute() throws Throwable
|
|
{
|
|
auditDAO.audit(auditInfo);
|
|
return null;
|
|
}
|
|
};
|
|
|
|
transactionService.getRetryingTransactionHelper().doInTransaction(cb, false, true);
|
|
}
|
|
catch (Throwable tt)
|
|
{
|
|
throw new AuditException("Failed to audit exception", new Object[] { tt }, t);
|
|
}
|
|
}
|
|
throw new AuditException("Application audit failed", t);
|
|
}
|
|
}
|
|
|
|
public List<AuditInfo> getAuditTrail(NodeRef nodeRef)
|
|
{
|
|
return auditDAO.getAuditTrail(nodeRef);
|
|
}
|
|
|
|
private AuditMode onApplicationAudit(AuditMode auditMode, AuditState auditInfo, String source, String description, NodeRef key, Object... args)
|
|
{
|
|
AuditMode effectiveAuditMode = auditModel.beforeExecution(auditMode, source, description, key, args);
|
|
auditModel.getAuditRecordOptions(source);
|
|
if (auditMode != AuditMode.NONE)
|
|
{
|
|
if (source.equals(SYSTEM_APPLICATION))
|
|
{
|
|
throw new AuditException("Application audit can not use the reserved identifier " + SYSTEM_APPLICATION);
|
|
}
|
|
|
|
auditInfo.setAuditApplication(source);
|
|
auditInfo.setAuditConfiguration(auditConfiguration);
|
|
auditInfo.setAuditMethod(null);
|
|
auditInfo.setAuditService(null);
|
|
auditInfo.setClientAddress(null);
|
|
auditInfo.setDate(new Date());
|
|
auditInfo.setFail(false);
|
|
auditInfo.setFiltered(false);
|
|
auditInfo.setHostAddress(auditHost);
|
|
auditInfo.setPath(null);
|
|
if (key != null)
|
|
{
|
|
auditInfo.setKeyStore(key.getStoreRef());
|
|
auditInfo.setKeyGUID(key.getId());
|
|
RecordOptions recordOptions = auditModel.getAuditRecordOptions(source);
|
|
if (recordOptions != null && recordOptions.getRecordPath() == TrueFalseUnset.TRUE)
|
|
{
|
|
auditInfo.setPath(getNodePath(key));
|
|
}
|
|
}
|
|
auditInfo.setKeyPropertiesAfter(null);
|
|
auditInfo.setKeyPropertiesBefore(null);
|
|
auditInfo.setMessage(description);
|
|
if (args != null)
|
|
{
|
|
Serializable[] serArgs = new Serializable[args.length];
|
|
for (int i = 0; i < args.length; i++)
|
|
{
|
|
if (args[i] == null)
|
|
{
|
|
serArgs[i] = null;
|
|
}
|
|
else if (args[i] instanceof Serializable)
|
|
{
|
|
serArgs[i] = (Serializable) args[i];
|
|
}
|
|
else
|
|
{
|
|
serArgs[i] = args[i].toString();
|
|
}
|
|
}
|
|
auditInfo.setMethodArguments(serArgs);
|
|
}
|
|
auditInfo.setReturnObject(null);
|
|
auditInfo.setSessionId(null);
|
|
auditInfo.setThrowable(null);
|
|
auditInfo.setTxId(AlfrescoTransactionSupport.getTransactionId());
|
|
auditInfo.setUserIdentifier(AuthenticationUtil.getFullyAuthenticatedUser());
|
|
}
|
|
|
|
return effectiveAuditMode;
|
|
}
|
|
|
|
private AuditMode onError(AuditMode auditMode, AuditState auditInfo, Throwable t, String source, String description, NodeRef key, Object... args)
|
|
{
|
|
if ((auditMode == AuditMode.ALL) || (auditMode == AuditMode.FAIL))
|
|
{
|
|
auditInfo.setFail(true);
|
|
auditInfo.setThrowable(t);
|
|
}
|
|
|
|
return auditMode;
|
|
|
|
}
|
|
|
|
/**
|
|
* Returns human readable path for node.
|
|
* To improve performance may return simple toString() method of the path.
|
|
*
|
|
* @param nodeRef
|
|
* @return Human readable path for node
|
|
*/
|
|
private String getNodePath(NodeRef nodeRef)
|
|
{
|
|
String result = null;
|
|
if (nodeService.exists(nodeRef))
|
|
{
|
|
Path path = nodeService.getPath(nodeRef);
|
|
return path.toPrefixString(namespacePrefixResolver);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
|
|
*/
|
|
|
|
private AuditModelRegistry auditModelRegistry;
|
|
private PropertyValueDAO propertyValueDAO;
|
|
|
|
/**
|
|
* Set the registry holding the audit models
|
|
* @since 3.2
|
|
*/
|
|
public void setAuditModelRegistry(AuditModelRegistry auditModelRegistry)
|
|
{
|
|
this.auditModelRegistry = auditModelRegistry;
|
|
}
|
|
|
|
/**
|
|
* Set the DAO for manipulating property values
|
|
* @since 3.2
|
|
*/
|
|
public void setPropertyValueDAO(PropertyValueDAO propertyValueDAO)
|
|
{
|
|
this.propertyValueDAO = propertyValueDAO;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public void deleteAuditEntries(String applicationName, Long fromTime, Long toTime)
|
|
{
|
|
ParameterCheck.mandatory("applicationName", applicationName);
|
|
AlfrescoTransactionSupport.checkTransactionReadState(true);
|
|
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByName(applicationName);
|
|
if (application == null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
|
}
|
|
return;
|
|
}
|
|
|
|
Long applicationId = application.getApplicationId();
|
|
|
|
auditDAO.deleteAuditEntries(applicationId, fromTime, toTime);
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Delete audit entries for " + applicationName + " (" + fromTime + " to " + toTime);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param application the audit application object
|
|
* @return Returns a copy of the set of disabled paths associated with the application
|
|
*/
|
|
@SuppressWarnings("unchecked")
|
|
private Set<String> getDisabledPaths(AuditApplication application)
|
|
{
|
|
try
|
|
{
|
|
Long disabledPathsId = application.getDisabledPathsId();
|
|
Set<String> disabledPaths = (Set<String>) propertyValueDAO.getPropertyById(disabledPathsId);
|
|
return new HashSet<String>(disabledPaths);
|
|
}
|
|
catch (Throwable e)
|
|
{
|
|
// Might be an invalid ID, somehow
|
|
auditModelRegistry.loadAuditModels();
|
|
throw new AlfrescoRuntimeException("Unabled to get AuditApplication disabled paths: " + application, e);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public boolean isAuditPathEnabled(String applicationName, String path)
|
|
{
|
|
ParameterCheck.mandatory("applicationName", applicationName);
|
|
ParameterCheck.mandatory("path", path);
|
|
AlfrescoTransactionSupport.checkTransactionReadState(false);
|
|
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByName(applicationName);
|
|
if (application == null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
|
}
|
|
return true;
|
|
}
|
|
// Check the path against the application
|
|
application.checkPath(path);
|
|
|
|
Set<String> disabledPaths = getDisabledPaths(application);
|
|
|
|
// Check if there are any entries that match or superced the given path
|
|
String disablingPath = null;;
|
|
for (String disabledPath : disabledPaths)
|
|
{
|
|
if (path.startsWith(disabledPath))
|
|
{
|
|
disablingPath = disabledPath;
|
|
break;
|
|
}
|
|
}
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit path enabled check: \n" +
|
|
" Application: " + applicationName + "\n" +
|
|
" Path: " + path + "\n" +
|
|
" Disabling Path: " + disablingPath);
|
|
}
|
|
return disablingPath == null;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public void enableAudit(String applicationName, String path)
|
|
{
|
|
ParameterCheck.mandatory("applicationName", applicationName);
|
|
ParameterCheck.mandatory("path", path);
|
|
AlfrescoTransactionSupport.checkTransactionReadState(true);
|
|
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByName(applicationName);
|
|
if (application == null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
|
}
|
|
return;
|
|
}
|
|
// Check the path against the application
|
|
application.checkPath(path);
|
|
|
|
Long disabledPathsId = application.getDisabledPathsId();
|
|
Set<String> disabledPaths = getDisabledPaths(application);
|
|
|
|
// Remove any paths that start with the given path
|
|
boolean changed = false;
|
|
Iterator<String> iterateDisabledPaths = disabledPaths.iterator();
|
|
while (iterateDisabledPaths.hasNext())
|
|
{
|
|
String disabledPath = iterateDisabledPaths.next();
|
|
if (disabledPath.startsWith(path))
|
|
{
|
|
iterateDisabledPaths.remove();
|
|
changed = true;
|
|
}
|
|
}
|
|
// Persist, if necessary
|
|
if (changed)
|
|
{
|
|
propertyValueDAO.updateProperty(disabledPathsId, (Serializable) disabledPaths);
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit disabled paths updated: \n" +
|
|
" Application: " + applicationName + "\n" +
|
|
" Disabled: " + disabledPaths);
|
|
}
|
|
}
|
|
// Done
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public void disableAudit(String applicationName, String path)
|
|
{
|
|
ParameterCheck.mandatory("applicationName", applicationName);
|
|
ParameterCheck.mandatory("path", path);
|
|
AlfrescoTransactionSupport.checkTransactionReadState(true);
|
|
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByName(applicationName);
|
|
if (application == null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
|
}
|
|
return;
|
|
}
|
|
// Check the path against the application
|
|
application.checkPath(path);
|
|
|
|
Long disabledPathsId = application.getDisabledPathsId();
|
|
Set<String> disabledPaths = getDisabledPaths(application);
|
|
|
|
// Shortcut if the disabled paths contain the exact path
|
|
if (disabledPaths.contains(path))
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit disable path already present: \n" +
|
|
" Path: " + path);
|
|
}
|
|
return;
|
|
}
|
|
|
|
// Bring the set up to date by stripping out unwanted paths
|
|
Iterator<String> iterateDisabledPaths = disabledPaths.iterator();
|
|
while (iterateDisabledPaths.hasNext())
|
|
{
|
|
String disabledPath = iterateDisabledPaths.next();
|
|
if (disabledPath.startsWith(path))
|
|
{
|
|
// We will be superceding this
|
|
iterateDisabledPaths.remove();
|
|
}
|
|
else if (path.startsWith(disabledPath))
|
|
{
|
|
// There is already a superceding path
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit disable path superceded: \n" +
|
|
" Path: " + path + "\n" +
|
|
" Superceded by: " + disabledPath);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
// Add our path in
|
|
disabledPaths.add(path);
|
|
// Upload the new set
|
|
propertyValueDAO.updateProperty(disabledPathsId, (Serializable) disabledPaths);
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit disabled paths updated: \n" +
|
|
" Application: " + applicationName + "\n" +
|
|
" Disabled: " + disabledPaths);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public void resetDisabledPaths(String applicationName)
|
|
{
|
|
ParameterCheck.mandatory("applicationName", applicationName);
|
|
AlfrescoTransactionSupport.checkTransactionReadState(true);
|
|
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByName(applicationName);
|
|
if (application == null)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("No audit application named '" + applicationName + "' has been registered.");
|
|
}
|
|
return;
|
|
}
|
|
Long disabledPathsId = application.getDisabledPathsId();
|
|
propertyValueDAO.updateProperty(disabledPathsId, (Serializable) Collections.emptySet());
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Removed all disabled paths for application " + applicationName);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public Map<String, Serializable> recordAuditValues(String rootPath, Map<String, Serializable> values)
|
|
{
|
|
ParameterCheck.mandatory("rootPath", rootPath);
|
|
AuditApplication.checkPathFormat(rootPath);
|
|
|
|
if (values == null || values.isEmpty())
|
|
{
|
|
return Collections.emptyMap();
|
|
}
|
|
// Build the key paths using the session root path
|
|
Map<String, Serializable> pathedValues = new HashMap<String, Serializable>(values.size() * 2);
|
|
for (Map.Entry<String, Serializable> entry : values.entrySet())
|
|
{
|
|
String pathElement = entry.getKey();
|
|
String path = AuditApplication.buildPath(rootPath, pathElement);
|
|
pathedValues.put(path, entry.getValue());
|
|
}
|
|
|
|
// Translate the values map
|
|
PathMapper pathMapper = auditModelRegistry.getAuditPathMapper();
|
|
final Map<String, Serializable> mappedValues = pathMapper.convertMap(pathedValues);
|
|
if (mappedValues.isEmpty())
|
|
{
|
|
return mappedValues;
|
|
}
|
|
|
|
// We have something to record. Start a transaction, if necessary
|
|
TxnReadState txnState = AlfrescoTransactionSupport.getTransactionReadState();
|
|
switch (txnState)
|
|
{
|
|
case TXN_NONE:
|
|
case TXN_READ_ONLY:
|
|
// New transaction
|
|
RetryingTransactionCallback<Map<String, Serializable>> callback =
|
|
new RetryingTransactionCallback<Map<String,Serializable>>()
|
|
{
|
|
public Map<String, Serializable> execute() throws Throwable
|
|
{
|
|
return recordAuditValuesImpl(mappedValues);
|
|
}
|
|
};
|
|
return transactionService.getRetryingTransactionHelper().doInTransaction(callback, false, true);
|
|
case TXN_READ_WRITE:
|
|
return recordAuditValuesImpl(mappedValues);
|
|
default:
|
|
throw new IllegalStateException("Unknown txn state: " + txnState);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
* @since 3.2
|
|
*/
|
|
public Map<String, Serializable> recordAuditValuesImpl(Map<String, Serializable> mappedValues)
|
|
{
|
|
// Group the values by root path
|
|
Map<String, Map<String, Serializable>> mappedValuesByRootKey = new HashMap<String, Map<String,Serializable>>();
|
|
for (Map.Entry<String, Serializable> entry : mappedValues.entrySet())
|
|
{
|
|
String path = entry.getKey();
|
|
String rootKey = AuditApplication.getRootKey(path);
|
|
Map<String, Serializable> rootKeyMappedValues = mappedValuesByRootKey.get(rootKey);
|
|
if (rootKeyMappedValues == null)
|
|
{
|
|
rootKeyMappedValues = new HashMap<String, Serializable>(7);
|
|
mappedValuesByRootKey.put(rootKey, rootKeyMappedValues);
|
|
}
|
|
rootKeyMappedValues.put(path, entry.getValue());
|
|
}
|
|
|
|
Map<String, Serializable> allAuditedValues = new HashMap<String, Serializable>(mappedValues.size()*2+1);
|
|
// Now audit for each of the root keys
|
|
for (Map.Entry<String, Map<String, Serializable>> entry : mappedValuesByRootKey.entrySet())
|
|
{
|
|
String rootKey = entry.getKey();
|
|
Map<String, Serializable> rootKeyMappedValues = entry.getValue();
|
|
// Get the application
|
|
AuditApplication application = auditModelRegistry.getAuditApplicationByKey(rootKey);
|
|
if (application == null)
|
|
{
|
|
// There is no application that uses the root key
|
|
logger.debug(
|
|
"There is no application for root key: " + rootKey);
|
|
continue;
|
|
}
|
|
// Get the disabled paths
|
|
Set<String> disabledPaths = getDisabledPaths(application);
|
|
// Do a quick elimination if the root path is disabled
|
|
if (disabledPaths.contains(AuditApplication.buildPath(rootKey)))
|
|
{
|
|
// The root key has been disabled for this application
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit values root path has been excluded by disabled paths: \n" +
|
|
" Application: " + application + "\n" +
|
|
" Root Path: " + AuditApplication.buildPath(rootKey));
|
|
}
|
|
continue;
|
|
}
|
|
// Do the audit
|
|
Map<String, Serializable> rootKeyAuditValues = audit(application, disabledPaths, rootKeyMappedValues);
|
|
allAuditedValues.putAll(rootKeyAuditValues);
|
|
}
|
|
// Done
|
|
return allAuditedValues;
|
|
}
|
|
|
|
/**
|
|
* Audit values for a given application. No path checking is done.
|
|
*
|
|
* @param application the audit application to audit to
|
|
* @param disabledPaths the application's disabled paths
|
|
* @param values the values to store keyed by <b>full paths</b>.
|
|
* @return Returns all values as audited
|
|
*/
|
|
private Map<String, Serializable> audit(
|
|
AuditApplication application,
|
|
Set<String> disabledPaths,
|
|
Map<String, Serializable> values)
|
|
{
|
|
// Get the model ID for the application
|
|
Long applicationId = application.getApplicationId();
|
|
if (applicationId == null)
|
|
{
|
|
throw new AuditException("No persisted instance exists for audit application: " + application);
|
|
}
|
|
|
|
// Eliminate any paths that have been disabled
|
|
Iterator<String> pathedValuesKeyIterator = values.keySet().iterator();
|
|
while(pathedValuesKeyIterator.hasNext())
|
|
{
|
|
String pathedValueKey = pathedValuesKeyIterator.next();
|
|
for (String disabledPath : disabledPaths)
|
|
{
|
|
if (pathedValueKey.startsWith(disabledPath))
|
|
{
|
|
// The pathed value is excluded
|
|
pathedValuesKeyIterator.remove();
|
|
}
|
|
}
|
|
}
|
|
// Check if there is anything left
|
|
if (values.size() == 0)
|
|
{
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"Audit values have all been excluded by disabled paths: \n" +
|
|
" Application: " + application + "\n" +
|
|
" Values: " + values);
|
|
}
|
|
return Collections.emptyMap();
|
|
}
|
|
|
|
// Generate data
|
|
Map<String, DataGenerator> generators = application.getDataGenerators(values.keySet());
|
|
Map<String, Serializable> auditData = generateData(generators);
|
|
|
|
// Now extract values
|
|
Map<String, Serializable> extractedData = extractData(application, values);
|
|
|
|
// Combine extracted and generated values (extracted data takes precedence)
|
|
auditData.putAll(extractedData);
|
|
|
|
// Time and username are intrinsic
|
|
long time = System.currentTimeMillis();
|
|
String username = AuthenticationUtil.getFullyAuthenticatedUser();
|
|
|
|
Long entryId = null;
|
|
if (!auditData.isEmpty())
|
|
{
|
|
// Persist the values
|
|
entryId = auditDAO.createAuditEntry(applicationId, time, username, auditData);
|
|
}
|
|
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug(
|
|
"New audit entry: \n" +
|
|
" Application ID: " + applicationId + "\n" +
|
|
" Entry ID: " + entryId + "\n" +
|
|
" Values: " + values + "\n" +
|
|
" Audit Data: " + auditData);
|
|
}
|
|
return auditData;
|
|
}
|
|
|
|
/**
|
|
* Extracts data from a given map using data extractors from the given application.
|
|
*
|
|
* @param application the application providing the data extractors
|
|
* @param values the data values from which to generate data
|
|
* @return Returns a map of derived data keyed by full path
|
|
*
|
|
* @since 3.2
|
|
*/
|
|
private Map<String, Serializable> extractData(
|
|
AuditApplication application,
|
|
Map<String, Serializable> values)
|
|
{
|
|
Map<String, Serializable> newData = new HashMap<String, Serializable>(values.size() + 5);
|
|
for (Map.Entry<String, Serializable> entry : values.entrySet())
|
|
{
|
|
String path = entry.getKey();
|
|
Serializable value = entry.getValue();
|
|
// Get the applicable extractor
|
|
Map<String, DataExtractor> extractors = application.getDataExtractors(path);
|
|
for (Map.Entry<String, DataExtractor> extractorElement : extractors.entrySet())
|
|
{
|
|
String extractorPath = extractorElement.getKey();
|
|
DataExtractor extractor = extractorElement.getValue();
|
|
// Check if the extraction is supported
|
|
if (!extractor.isSupported(value))
|
|
{
|
|
continue;
|
|
}
|
|
// Use the extractor to pull the value out
|
|
final Serializable data;
|
|
try
|
|
{
|
|
data = extractor.extractData(value);
|
|
}
|
|
catch (Throwable e)
|
|
{
|
|
throw new AlfrescoRuntimeException(
|
|
"Failed to extract audit data: \n" +
|
|
" Path: " + path + "\n" +
|
|
" Raw value: " + value + "\n" +
|
|
" Extractor: " + extractor,
|
|
e);
|
|
}
|
|
// Add it to the map
|
|
newData.put(extractorPath, data);
|
|
}
|
|
}
|
|
// Done
|
|
if (logger.isDebugEnabled())
|
|
{
|
|
logger.debug("Extracted audit data: \n" +
|
|
" Application: " + application + "\n" +
|
|
" Raw values: " + values + "\n" +
|
|
" Extracted: " + newData);
|
|
}
|
|
return newData;
|
|
}
|
|
|
|
/**
|
|
* @param generators the data generators
|
|
* @return Returns a map of generated data keyed by full path
|
|
*
|
|
* @since 3.2
|
|
*/
|
|
private Map<String, Serializable> generateData(Map<String, DataGenerator> generators)
|
|
{
|
|
Map<String, Serializable> newData = new HashMap<String, Serializable>(generators.size() + 5);
|
|
for (Map.Entry<String, DataGenerator> entry : generators.entrySet())
|
|
{
|
|
String path = entry.getKey();
|
|
DataGenerator generator = entry.getValue();
|
|
final Serializable data;
|
|
try
|
|
{
|
|
data = generator.getData();
|
|
}
|
|
catch (Throwable e)
|
|
{
|
|
throw new AlfrescoRuntimeException(
|
|
"Failed to generate audit data: \n" +
|
|
" Path: " + path + "\n" +
|
|
" Generator: " + generator,
|
|
e);
|
|
}
|
|
// Add it to the map
|
|
newData.put(path, data);
|
|
}
|
|
// Done
|
|
return newData;
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public void auditQuery(
|
|
AuditQueryCallback callback,
|
|
boolean forward,
|
|
String applicationName,
|
|
String user,
|
|
Long from,
|
|
Long to,
|
|
int maxResults)
|
|
{
|
|
ParameterCheck.mandatory("callback", callback);
|
|
|
|
// Shortcuts
|
|
if (from != null && to != null && from.compareTo(to) > 0)
|
|
{
|
|
// Time range can't yield results
|
|
return;
|
|
}
|
|
|
|
auditDAO.findAuditEntries(
|
|
callback, forward, applicationName, user, from, to, maxResults);
|
|
}
|
|
|
|
/**
|
|
* {@inheritDoc}
|
|
*/
|
|
public void auditQuery(
|
|
AuditQueryCallback callback,
|
|
boolean forward,
|
|
String applicationName,
|
|
String user,
|
|
Long from,
|
|
Long to,
|
|
String searchKey, Serializable searchValue,
|
|
int maxResults)
|
|
{
|
|
ParameterCheck.mandatory("callback", callback);
|
|
|
|
// Shortcuts
|
|
if (from != null && to != null && from.compareTo(to) > 0)
|
|
{
|
|
// Time range can't yield results
|
|
return;
|
|
}
|
|
|
|
auditDAO.findAuditEntries(
|
|
callback, forward, applicationName, user, from, to, searchKey, searchValue, maxResults);
|
|
}
|
|
}
|