Improved backward compatibility with default audit settings

- audit.useNewConfig=false is now the default setting and has a new meaning
- In this mode, audit information is broadcast to BOTH the old and new audit configuration, meaning that e.g. you can enjoy new RM and CMIS auditing capabilities whilst still retaining compatibility with your old audit configuration
- When audit.useNewConfig=true only the new config/alfresco/audit/*.xml configuration will be used exclusively. NOT config/auditConfig.xml.
- Note that auditing is still switched off by default and must be switched on with audit.enabled=true
- You can switch on and off individual applications in the new config using
   - audit.repository.enabled
   - audit.cmischangelog.enabled
   - audit.dod5015.enabled
- Simple!

git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@18885 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Dave Ward
2010-02-26 13:54:46 +00:00
parent f527228cfd
commit eaa39abc27
6 changed files with 82 additions and 70 deletions

View File

@@ -252,7 +252,10 @@ db.pool.abandoned.time=300
audit.enabled=false
audit.repository.enabled=true
audit.cmischangelog.enabled=true
audit.useNewConfig=true
# Setting this flag to true will cause alfresco/auditConfig.xml to be ignored
# when audit is enabled. When false both alfresco/auditConfig.xml and
# alfresco/audit/*.xml will be used.
audit.useNewConfig=false
# Email configuration
mail.host=

View File

@@ -94,6 +94,13 @@ public interface AuditComponent
* V3.2 from here on. Put all fixes to the older audit code before this point, please.
*/
/**
* Determines whether audit is globally enabled or disabled.
*
* @return <code>true</code>, if audit is enabled
*/
public boolean isAuditEnabled();
/**
* Determines whether the given source path is mapped to any audit applications. Allows optimizations to be made in
* calling components.

View File

@@ -955,13 +955,22 @@ public class AuditComponentImpl implements AuditComponent
}
}
/**
* {@inheritDoc}
* @since 3.2
*/
public boolean isAuditEnabled()
{
return auditModelRegistry.isAuditEnabled();
}
/**
* {@inheritDoc}
* @since 3.2
*/
public boolean isSourcePathMapped(String sourcePath)
{
return !auditModelRegistry.getAuditPathMapper().isEmpty();
return isAuditEnabled() && !auditModelRegistry.getAuditPathMapper().isEmpty();
}
/**

View File

@@ -102,7 +102,6 @@ public class AuditMethodInterceptor implements MethodInterceptor
private boolean useNewConfig = false;
private final ThreadLocal<Boolean> inAudit = new ThreadLocal<Boolean>();
private final ThreadLocal<Boolean> auditEnabled = new ThreadLocal<Boolean>();
public AuditMethodInterceptor()
{
@@ -136,44 +135,16 @@ public class AuditMethodInterceptor implements MethodInterceptor
public Object invoke(MethodInvocation mi) throws Throwable
{
// Cache the enabled flag at the top of the stack
Boolean wasEnabled = auditEnabled.get();
try
if(!auditComponent.isAuditEnabled())
{
boolean enabled;
if (wasEnabled == null)
{
// There hasn't been an invocation in this thread yet, so check whether we are currently enabled in the
// audit subsystem
enabled = this.auditComponent.isSourcePathMapped(AUDIT_PATH_API_ROOT);
auditEnabled.set(enabled);
}
else
{
enabled = wasEnabled;
}
if(!enabled)
{
// No auditing
return mi.proceed();
}
else if (useNewConfig)
{
// New configuration to be used
return proceed(mi);
}
else
{
// Use previous configuration
return auditComponent.audit(mi);
}
// No auditing
return mi.proceed();
}
finally
else
{
auditEnabled.set(wasEnabled);
// New configuration will be used and optionally old configuration if useNewConfig=false
return proceed(mi);
}
}
/**
@@ -188,41 +159,50 @@ public class AuditMethodInterceptor implements MethodInterceptor
*/
private Object proceed(MethodInvocation mi) throws Throwable
{
Auditable auditableDef = mi.getMethod().getAnnotation(Auditable.class);
if (auditableDef == null)
{
// No annotation, so just continue as normal
return mi.proceed();
}
// First get the argument map, if present
Object[] args = mi.getArguments();
Map<String, Serializable> namedArguments = getInvocationArguments(auditableDef, args);
// Get the service name
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
if (serviceName == null)
{
// Not a public service
return mi.proceed();
}
String methodName = mi.getMethod().getName();
// Are we in a nested audit
// Are we in a nested audit?
Boolean wasInAudit = inAudit.get();
// TODO: Need to make this configurable for the interceptor or a conditional mapping for audit
if (wasInAudit != null)
{
return mi.proceed();
}
// Record that we have entered an audit method
inAudit.set(Boolean.TRUE);
try
{
// If we are already in a nested audit call, there is nothing to do
if (wasInAudit != null)
{
return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
}
// If there are no mapped paths, there is nothing to do
if (!this.auditComponent.isSourcePathMapped(AUDIT_PATH_API_ROOT))
{
// We can ignore the rest of the stack too
inAudit.set(Boolean.TRUE);
return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
}
Auditable auditableDef = mi.getMethod().getAnnotation(Auditable.class);
if (auditableDef == null)
{
// No annotation, so just continue as normal
return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
}
// First get the argument map, if present
Object[] args = mi.getArguments();
Map<String, Serializable> namedArguments = getInvocationArguments(auditableDef, args);
// Get the service name
String serviceName = publicServiceIdentifier.getPublicServiceName(mi);
if (serviceName == null)
{
// Not a public service
return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
}
String methodName = mi.getMethod().getName();
// Record that we have entered an audit method
inAudit.set(Boolean.TRUE);
return proceedWithAudit(mi, auditableDef, serviceName, methodName, namedArguments);
}
finally
{
inAudit.set(wasInAudit);
inAudit.set(wasInAudit);
}
}
@@ -251,7 +231,7 @@ public class AuditMethodInterceptor implements MethodInterceptor
Throwable thrown = null;
try
{
ret = mi.proceed();
ret = useNewConfig ? mi.proceed() : auditComponent.audit(mi);
}
catch (Throwable e)
{

View File

@@ -24,8 +24,6 @@
*/
package org.alfresco.repo.audit.model;
import java.net.URL;
import org.alfresco.util.PathMapper;
/**
@@ -41,14 +39,20 @@ public interface AuditModelRegistry
/**
* Method to load audit models into memory. This method is also responsible for persisting
* the audit models for later retrieval. Models are loaded from the locations given by the
* {@link #registerModel(URL) register} methods.
* the audit models for later retrieval.
* <p/>
* Note, the models are loaded in a new transaction, so this method can be called by any code
* at any time.
*/
public void loadAuditModels();
/**
* Determines whether audit is globally enabled or disabled.
*
* @return <code>true</code>, if audit is enabled
*/
public boolean isAuditEnabled();
/**
* Get the application model for the given root key (as defined on the application)
*

View File

@@ -152,6 +152,15 @@ public class AuditModelRegistryImpl extends AbstractPropertyBackedBean implement
start();
}
/**
* {@inheritDoc}
*/
public boolean isAuditEnabled()
{
String value = getProperty(PROPERTY_AUDIT_ENABLED);
return value != null && value.equalsIgnoreCase("true");
}
/**
* Enables audit and registers an audit model at a given URL. Does not register across the cluster and should only
* be used for unit test purposes.