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.enabled=false
audit.repository.enabled=true audit.repository.enabled=true
audit.cmischangelog.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 # Email configuration
mail.host= 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. * 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 * Determines whether the given source path is mapped to any audit applications. Allows optimizations to be made in
* calling components. * calling components.

View File

@@ -955,13 +955,22 @@ public class AuditComponentImpl implements AuditComponent
} }
} }
/**
* {@inheritDoc}
* @since 3.2
*/
public boolean isAuditEnabled()
{
return auditModelRegistry.isAuditEnabled();
}
/** /**
* {@inheritDoc} * {@inheritDoc}
* @since 3.2 * @since 3.2
*/ */
public boolean isSourcePathMapped(String sourcePath) 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 boolean useNewConfig = false;
private final ThreadLocal<Boolean> inAudit = new ThreadLocal<Boolean>(); private final ThreadLocal<Boolean> inAudit = new ThreadLocal<Boolean>();
private final ThreadLocal<Boolean> auditEnabled = new ThreadLocal<Boolean>();
public AuditMethodInterceptor() public AuditMethodInterceptor()
{ {
@@ -136,45 +135,17 @@ public class AuditMethodInterceptor implements MethodInterceptor
public Object invoke(MethodInvocation mi) throws Throwable public Object invoke(MethodInvocation mi) throws Throwable
{ {
// Cache the enabled flag at the top of the stack if(!auditComponent.isAuditEnabled())
Boolean wasEnabled = auditEnabled.get();
try
{
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 // No auditing
return mi.proceed(); return mi.proceed();
} }
else if (useNewConfig)
{
// New configuration to be used
return proceed(mi);
}
else else
{ {
// Use previous configuration // New configuration will be used and optionally old configuration if useNewConfig=false
return auditComponent.audit(mi); return proceed(mi);
} }
} }
finally
{
auditEnabled.set(wasEnabled);
}
}
/** /**
* Allow the given method invocation to proceed, auditing values before invocation and * Allow the given method invocation to proceed, auditing values before invocation and
@@ -188,11 +159,29 @@ public class AuditMethodInterceptor implements MethodInterceptor
*/ */
private Object proceed(MethodInvocation mi) throws Throwable private Object proceed(MethodInvocation mi) throws Throwable
{ {
// Are we in a nested audit?
Boolean wasInAudit = inAudit.get();
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); Auditable auditableDef = mi.getMethod().getAnnotation(Auditable.class);
if (auditableDef == null) if (auditableDef == null)
{ {
// No annotation, so just continue as normal // No annotation, so just continue as normal
return mi.proceed(); return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
} }
// First get the argument map, if present // First get the argument map, if present
@@ -203,21 +192,12 @@ public class AuditMethodInterceptor implements MethodInterceptor
if (serviceName == null) if (serviceName == null)
{ {
// Not a public service // Not a public service
return mi.proceed(); return useNewConfig ? mi.proceed() : auditComponent.audit(mi);
} }
String methodName = mi.getMethod().getName(); String methodName = mi.getMethod().getName();
// 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 // Record that we have entered an audit method
inAudit.set(Boolean.TRUE); inAudit.set(Boolean.TRUE);
try
{
return proceedWithAudit(mi, auditableDef, serviceName, methodName, namedArguments); return proceedWithAudit(mi, auditableDef, serviceName, methodName, namedArguments);
} }
finally finally
@@ -251,7 +231,7 @@ public class AuditMethodInterceptor implements MethodInterceptor
Throwable thrown = null; Throwable thrown = null;
try try
{ {
ret = mi.proceed(); ret = useNewConfig ? mi.proceed() : auditComponent.audit(mi);
} }
catch (Throwable e) catch (Throwable e)
{ {

View File

@@ -24,8 +24,6 @@
*/ */
package org.alfresco.repo.audit.model; package org.alfresco.repo.audit.model;
import java.net.URL;
import org.alfresco.util.PathMapper; 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 * 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 * the audit models for later retrieval.
* {@link #registerModel(URL) register} methods.
* <p/> * <p/>
* Note, the models are loaded in a new transaction, so this method can be called by any code * Note, the models are loaded in a new transaction, so this method can be called by any code
* at any time. * at any time.
*/ */
public void loadAuditModels(); 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) * 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(); 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 * 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. * be used for unit test purposes.