Added a registry for DataExtractors and DataGenerators

- Uses recently-added NamedObjectRegistry
 - Audit extractors and generators can now be Sprung using 'registeredName' instead of 'class'
 - Simpler to bring in complex, repo-dependent generators and extractors


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15935 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Derek Hulley
2009-08-26 16:43:40 +00:00
parent de4467b12d
commit b57ae75eff
12 changed files with 378 additions and 120 deletions

View File

@@ -37,7 +37,7 @@
<ref bean="auditModel"/>
</property>
<!-- V3.2 specific -->
<property name="auditModelRegistry" ref="auditModel.registry"/>
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
</bean>
<!-- Public service idntifier -->
@@ -78,16 +78,38 @@
<!-- Audit V3.2 implementation -->
<!-- -->
<bean id="auditModel.registry" class="org.alfresco.repo.audit.model.AuditModelRegistry">
<!-- Data extractors -->
<bean id="auditModel.extractorRegistry" class="org.alfresco.util.registry.NamedObjectRegistry">
<property name="storageType" value="org.alfresco.repo.audit.extractor.DataExtractor" />
</bean>
<bean name="auditModel.extractor.simpleValue" class="org.alfresco.repo.audit.extractor.SimpleValueDataExtractor">
<property name="registry" ref="auditModel.extractorRegistry" />
</bean>
<!-- Data Generators -->
<bean id="auditModel.generatorRegistry" class="org.alfresco.util.registry.NamedObjectRegistry">
<property name="storageType" value="org.alfresco.repo.audit.generator.DataGenerator" />
</bean>
<bean name="auditModel.generator.time" class="org.alfresco.repo.audit.generator.SystemTimeDataGenerator">
<property name="registry" ref="auditModel.generatorRegistry" />
</bean>
<bean name="auditModel.generator.user" class="org.alfresco.repo.audit.generator.AuthenticatedUserDataGenerator">
<property name="registry" ref="auditModel.generatorRegistry" />
</bean>
<!-- Models -->
<bean id="auditModel.modelRegistry" class="org.alfresco.repo.audit.model.AuditModelRegistry">
<property name="transactionService" ref="transactionService"/>
<property name="auditDAO" ref="auditDAO"/>
<property name="dataExtractors" ref="auditModel.extractorRegistry"/>
<property name="dataGenerators" ref="auditModel.generatorRegistry"/>
</bean>
<bean id="auditModel.repository" class="org.alfresco.repo.audit.model.AuditModelReader">
<property name="auditModelUrl">
<value>classpath:alfresco/audit/alfresco-audit-repository.xml</value>
</property>
<property name="auditModelRegistry" ref="auditModel.registry"/>
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
</bean>
</beans>

View File

@@ -30,7 +30,8 @@
</xs:complexType>
<xs:complexType name="DataExtractor">
<xs:attribute name="name" type="a:NameAttribute"/>
<xs:attribute name="name" type="a:NameAttribute" use="required"/>
<xs:attribute name="registeredName" type="a:NameAttribute"/>
<xs:attribute name="class" type="a:ClassAttribute"/>
</xs:complexType>
@@ -41,7 +42,8 @@
</xs:complexType>
<xs:complexType name="DataGenerator">
<xs:attribute name="name" type="a:NameAttribute"/>
<xs:attribute name="name" type="a:NameAttribute" use="required"/>
<xs:attribute name="registeredName" type="a:NameAttribute"/>
<xs:attribute name="class" type="a:ClassAttribute"/>
</xs:complexType>
@@ -94,7 +96,7 @@
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="128"/>
<xs:pattern value="([a-z]|[A-Z]|[0-9]|\ |\-)*"/>
<xs:pattern value="([a-z]|[A-Z]|[0-9]|\-|\.|\ )*"/>
</xs:restriction>
</xs:simpleType>

View File

@@ -497,7 +497,7 @@
<!-- Start Auditing -->
<bean id="audit.bootstrap" class="org.alfresco.repo.audit.AuditBootstrap">
<property name="transactionService" ref="transactionService"/>
<property name="auditModelRegistry" ref="auditModel.registry"/>
<property name="auditModelRegistry" ref="auditModel.modelRegistry"/>
</bean>
<!-- Repository helper class -->

View File

@@ -58,7 +58,7 @@ public class AuditBootstrapTest extends TestCase
@Override
public void setUp() throws Exception
{
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.registry");
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.modelRegistry");
// Register a new model
URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml");

View File

@@ -26,6 +26,7 @@ package org.alfresco.repo.audit;
import java.io.Serializable;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@@ -63,7 +64,7 @@ public class AuditComponentTest extends TestCase
@Override
public void setUp() throws Exception
{
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.registry");
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.modelRegistry");
auditComponent = (AuditComponent) ctx.getBean("auditComponent");
transactionService = (TransactionService) ctx.getBean("transactionService");
@@ -71,6 +72,15 @@ public class AuditComponentTest extends TestCase
URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml");
auditModelRegistry.registerModel(testModelUrl);
auditModelRegistry.loadAuditModels();
// Authenticate
AuthenticationUtil.setFullyAuthenticatedUser("User-" + getName() + System.currentTimeMillis());
}
@Override
public void tearDown() throws Exception
{
AuthenticationUtil.clearCurrentSecurityContext();
}
public void testSetUp()
@@ -126,7 +136,7 @@ public class AuditComponentTest extends TestCase
/**
* Start a session and use it within a single txn
*/
public void testBasicSession() throws Exception
public void testSession_Basic() throws Exception
{
final RetryingTransactionCallback<Void> testCallback = new RetryingTransactionCallback<Void>()
{
@@ -137,6 +147,7 @@ public class AuditComponentTest extends TestCase
Map<String, Serializable> values = new HashMap<String, Serializable>(13);
values.put("/test/1.1/2.1/3.1/4.1", new Long(41));
values.put("/test/1.1/2.1/3.1/4.2", "42");
values.put("/test/1.1/2.1/3.1/4.2", new Date());
auditComponent.audit(session, values);
@@ -150,6 +161,37 @@ public class AuditComponentTest extends TestCase
return transactionService.getRetryingTransactionHelper().doInTransaction(testCallback);
}
};
AuthenticationUtil.runAs(testRunAs, "Peanut");
AuthenticationUtil.runAs(testRunAs, "SomeOtherUser");
}
/**
* Start a session and use it within a single txn
*/
public void testSession_Extended01() throws Exception
{
final RetryingTransactionCallback<Void> testCallback = new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
{
AuditSession session = auditComponent.startAuditSession(APPLICATION_TEST, "/test/1.1");
Map<String, Serializable> values = new HashMap<String, Serializable>(13);
values.put("/test/1.1/2.1/3.1/4.1", new Long(41));
values.put("/test/1.1/2.1/3.1/4.2", "42");
values.put("/test/1.1/2.1/3.1/4.2", new Date());
auditComponent.audit(session, values);
return null;
}
};
RunAsWork<Void> testRunAs = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
return transactionService.getRetryingTransactionHelper().doInTransaction(testCallback);
}
};
AuthenticationUtil.runAs(testRunAs, "SomeOtherUser");
}
}

View File

@@ -24,14 +24,51 @@
*/
package org.alfresco.repo.audit.extractor;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.registry.NamedObjectRegistry;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
/**
* Abstract implementation to provide support.
*
* @author Derek Hulley
* @since 3.2
*/
public abstract class AbstractDataExtractor implements DataExtractor
public abstract class AbstractDataExtractor implements DataExtractor, InitializingBean, BeanNameAware
{
private String name;
private NamedObjectRegistry<DataExtractor> registry;
/**
* Set the name with which to {@link #setRegistry(NamedObjectRegistry) register}
* @param name the name of the bean
*/
public void setBeanName(String name)
{
this.name = name;
}
/**
* Set the registry with which to register
* @param registry
*/
public void setRegistry(NamedObjectRegistry<DataExtractor> registry)
{
this.registry = registry;
}
/**
* Registers the instance
*/
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "name", name);
PropertyCheck.mandatory(this, "registry", registry);
registry.register(name, this);
}
/**
* This implementation assumes all extractors are stateless i.e. if the class matches
* then the instances are equal.

View File

@@ -24,14 +24,51 @@
*/
package org.alfresco.repo.audit.generator;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.registry.NamedObjectRegistry;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
/**
* Abstract implementation to provide support.
*
* @author Derek Hulley
* @since 3.2
*/
public abstract class AbstractDataGenerator implements DataGenerator
public abstract class AbstractDataGenerator implements DataGenerator, InitializingBean, BeanNameAware
{
private String name;
private NamedObjectRegistry<DataGenerator> registry;
/**
* Set the name with which to {@link #setRegistry(NamedObjectRegistry) register}
* @param name the name of the bean
*/
public void setBeanName(String name)
{
this.name = name;
}
/**
* Set the registry with which to register
* @param registry
*/
public void setRegistry(NamedObjectRegistry<DataGenerator> registry)
{
this.registry = registry;
}
/**
* Registers the instance
*/
public void afterPropertiesSet() throws Exception
{
PropertyCheck.mandatory(this, "name", name);
PropertyCheck.mandatory(this, "registry", registry);
registry.register(name, this);
}
/**
* This implementation assumes all generators are stateless i.e. if the class matches
* then the instances are equal.

View File

@@ -58,6 +58,8 @@ import org.alfresco.repo.domain.audit.AuditDAO;
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.transaction.TransactionService;
import org.alfresco.util.PropertyCheck;
import org.alfresco.util.registry.NamedObjectRegistry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.ResourceUtils;
@@ -80,6 +82,8 @@ public class AuditModelRegistry
private TransactionService transactionService;
private AuditDAO auditDAO;
private NamedObjectRegistry<DataExtractor> dataExtractors;
private NamedObjectRegistry<DataGenerator> dataGenerators;
private final ReentrantReadWriteLock.ReadLock readLock;
private final ReentrantReadWriteLock.WriteLock writeLock;
@@ -87,8 +91,6 @@ public class AuditModelRegistry
private final Set<URL> auditModelUrls;
private final List<Audit> auditModels;
private final Map<String, DataExtractor> dataExtractorsByName;
private final Map<String, DataGenerator> dataGeneratorsByName;
/**
* Used to lookup the audit application java hierarchy
*/
@@ -111,8 +113,6 @@ public class AuditModelRegistry
auditModelUrls = new HashSet<URL>(7);
auditModels = new ArrayList<Audit>(7);
dataExtractorsByName = new HashMap<String, DataExtractor>(13);
dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
auditApplicationsByName = new HashMap<String, AuditApplication>(7);
auditModelIdsByApplicationsName = new HashMap<String, Long>(7);
}
@@ -133,6 +133,33 @@ public class AuditModelRegistry
this.auditDAO = auditDAO;
}
/**
* Set the registry of {@link DataExtractor data extractors}
*/
public void setDataExtractors(NamedObjectRegistry<DataExtractor> dataExtractors)
{
this.dataExtractors = dataExtractors;
}
/**
* Set the registry of {@link DataGenerator data generators}
*/
public void setDataGenerators(NamedObjectRegistry<DataGenerator> dataGenerators)
{
this.dataGenerators = dataGenerators;
}
/**
* Ensures that all properties have been set for use.
*/
private void checkProperties()
{
PropertyCheck.mandatory(this, "transactionService", transactionService);
PropertyCheck.mandatory(this, "auditDAO", auditDAO);
PropertyCheck.mandatory(this, "dataExtractors", dataExtractors);
PropertyCheck.mandatory(this, "dataGenerators", dataGenerators);
}
/**
* Register an audit model at a given URL.
*
@@ -140,6 +167,7 @@ public class AuditModelRegistry
*/
public void registerModel(URL auditModelUrl)
{
checkProperties();
writeLock.lock();
try
{
@@ -162,6 +190,7 @@ public class AuditModelRegistry
*/
public void registerModel(NodeRef auditModelNodeRef)
{
checkProperties();
writeLock.lock();
try
{
@@ -179,8 +208,6 @@ public class AuditModelRegistry
private void clearCaches()
{
auditModels.clear();
dataExtractorsByName.clear();
dataGeneratorsByName.clear();;
auditApplicationsByName.clear();
auditModelIdsByApplicationsName.clear();
}
@@ -194,6 +221,8 @@ public class AuditModelRegistry
*/
public void loadAuditModels()
{
checkProperties();
RetryingTransactionCallback<Void> loadModelsCallback = new RetryingTransactionCallback<Void>()
{
public Void execute() throws Throwable
@@ -365,42 +394,58 @@ public class AuditModelRegistry
private void cacheAuditElements(Long auditModelId, Audit audit)
{
Map<String, DataExtractor> dataExtractorsByName = new HashMap<String, DataExtractor>(13);
Map<String, DataGenerator> dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
// Get the data extractors and check for duplicates
DataExtractors extractorsElement = audit.getDataExtractors();
if (extractorsElement == null)
{
extractorsElement = objectFactory.createDataExtractors();
}
List<org.alfresco.repo.audit.model._3.DataExtractor> converterElements = extractorsElement.getDataExtractor();
for (org.alfresco.repo.audit.model._3.DataExtractor converterElement : converterElements)
List<org.alfresco.repo.audit.model._3.DataExtractor> extractorElements = extractorsElement.getDataExtractor();
for (org.alfresco.repo.audit.model._3.DataExtractor extractorElement : extractorElements)
{
String name = converterElement.getName();
// Construct the converter
final DataExtractor dataExtractor;
try
{
Class<?> dataExtractorClazz = Class.forName(converterElement.getClazz());
dataExtractor = (DataExtractor) dataExtractorClazz.newInstance();
}
catch (ClassNotFoundException e)
{
throw new AuditModelException(
"Audit data extractor '" + name + "' class not found: " + converterElement.getClazz());
}
catch (Exception e)
{
throw new AuditModelException(
"Audit data extractor '" + name + "' could not be constructed: " + converterElement.getClazz());
}
String name = extractorElement.getName();
// If the name is taken, make sure that they are equal
if (dataExtractorsByName.containsKey(name))
{
DataExtractor existing = dataExtractorsByName.get(name);
if (!existing.equals(dataExtractor))
throw new AuditModelException(
"Audit data extractor '" + name + "' has already been defined.");
}
// Construct the converter
final DataExtractor dataExtractor;
if (extractorElement.getClazz() != null)
{
try
{
Class<?> dataExtractorClazz = Class.forName(extractorElement.getClazz());
dataExtractor = (DataExtractor) dataExtractorClazz.newInstance();
}
catch (ClassNotFoundException e)
{
throw new AuditModelException(
"Audit data extractor '" + name + "' is incompatible with an existing instance.");
"Audit data extractor '" + name + "' class not found: " + extractorElement.getClazz());
}
catch (Exception e)
{
throw new AuditModelException(
"Audit data extractor '" + name + "' could not be constructed: " + extractorElement.getClazz());
}
}
else if (extractorElement.getRegisteredName() != null)
{
dataExtractor = dataExtractors.getNamedObject(extractorElement.getRegisteredName());
if (dataExtractor == null)
{
throw new AuditModelException(
"No registered audit data extractor exists for '" + name + "'.");
}
}
else
{
throw new AuditModelException(
"Audit data extractor has no class or registered name: " + name);
}
// Store
dataExtractorsByName.put(name, dataExtractor);
@@ -415,32 +460,45 @@ public class AuditModelRegistry
for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements)
{
String name = generatorElement.getName();
// Construct the converter
final DataGenerator dataGenerator;
try
{
Class<?> dataExtractorClazz = Class.forName(generatorElement.getClazz());
dataGenerator = (DataGenerator) dataExtractorClazz.newInstance();
}
catch (ClassNotFoundException e)
{
throw new AuditModelException(
"Audit data generator '" + name + "' class not found: " + generatorElement.getClazz());
}
catch (Exception e)
{
throw new AuditModelException(
"Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz());
}
// If the name is taken, make sure that they are equal
if (dataGeneratorsByName.containsKey(name))
{
DataGenerator existing = dataGeneratorsByName.get(name);
if (!existing.equals(dataGenerator))
throw new AuditModelException(
"Audit data generator '" + name + "' has already been defined.");
}
// Construct the generator
final DataGenerator dataGenerator;
if (generatorElement.getClazz() != null)
{
try
{
Class<?> dataGeneratorClazz = Class.forName(generatorElement.getClazz());
dataGenerator = (DataGenerator) dataGeneratorClazz.newInstance();
}
catch (ClassNotFoundException e)
{
throw new AuditModelException(
"Audit data generator '" + name + "' is incompatible with an existing instance.");
"Audit data generator '" + name + "' class not found: " + generatorElement.getClazz());
}
catch (Exception e)
{
throw new AuditModelException(
"Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz());
}
}
else if (generatorElement.getRegisteredName() != null)
{
dataGenerator = dataGenerators.getNamedObject(generatorElement.getRegisteredName());
if (dataGenerator == null)
{
throw new AuditModelException(
"No registered audit data generator exists for '" + name + "'.");
}
}
else
{
throw new AuditModelException(
"Audit data generator has no class or registered name: " + name);
}
// Store
dataGeneratorsByName.put(name, dataGenerator);

View File

@@ -16,7 +16,8 @@ import javax.xml.bind.annotation.XmlType;
* &lt;complexType name="DataExtractor">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="name" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="registeredName" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="class" type="{http://www.alfresco.org/repo/audit/model/3.2}ClassAttribute" />
* &lt;/restriction>
* &lt;/complexContent>
@@ -29,8 +30,10 @@ import javax.xml.bind.annotation.XmlType;
@XmlType(name = "DataExtractor")
public class DataExtractor {
@XmlAttribute
@XmlAttribute(required = true)
protected String name;
@XmlAttribute
protected String registeredName;
@XmlAttribute(name = "class")
protected String clazz;
@@ -58,6 +61,30 @@ public class DataExtractor {
this.name = value;
}
/**
* Gets the value of the registeredName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getRegisteredName() {
return registeredName;
}
/**
* Sets the value of the registeredName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setRegisteredName(String value) {
this.registeredName = value;
}
/**
* Gets the value of the clazz property.
*

View File

@@ -16,7 +16,8 @@ import javax.xml.bind.annotation.XmlType;
* &lt;complexType name="DataGenerator">
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="name" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="registeredName" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
* &lt;attribute name="class" type="{http://www.alfresco.org/repo/audit/model/3.2}ClassAttribute" />
* &lt;/restriction>
* &lt;/complexContent>
@@ -29,8 +30,10 @@ import javax.xml.bind.annotation.XmlType;
@XmlType(name = "DataGenerator")
public class DataGenerator {
@XmlAttribute
@XmlAttribute(required = true)
protected String name;
@XmlAttribute
protected String registeredName;
@XmlAttribute(name = "class")
protected String clazz;
@@ -58,6 +61,30 @@ public class DataGenerator {
this.name = value;
}
/**
* Gets the value of the registeredName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getRegisteredName() {
return registeredName;
}
/**
* Sets the value of the registeredName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setRegisteredName(String value) {
this.registeredName = value;
}
/**
* Gets the value of the clazz property.
*

View File

@@ -34,51 +34,11 @@ public class ObjectFactory {
}
/**
* Create an instance of {@link KeyedAuditDefinition }
* Create an instance of {@link Application }
*
*/
public KeyedAuditDefinition createKeyedAuditDefinition() {
return new KeyedAuditDefinition();
}
/**
* Create an instance of {@link DataExtractor }
*
*/
public DataExtractor createDataExtractor() {
return new DataExtractor();
}
/**
* Create an instance of {@link Audit }
*
*/
public Audit createAudit() {
return new Audit();
}
/**
* Create an instance of {@link DataExtractors }
*
*/
public DataExtractors createDataExtractors() {
return new DataExtractors();
}
/**
* Create an instance of {@link AuditPath }
*
*/
public AuditPath createAuditPath() {
return new AuditPath();
}
/**
* Create an instance of {@link DataGenerator }
*
*/
public DataGenerator createDataGenerator() {
return new DataGenerator();
public Application createApplication() {
return new Application();
}
/**
@@ -89,6 +49,22 @@ public class ObjectFactory {
return new DataGenerators();
}
/**
* Create an instance of {@link DataExtractor }
*
*/
public DataExtractor createDataExtractor() {
return new DataExtractor();
}
/**
* Create an instance of {@link AuditPath }
*
*/
public AuditPath createAuditPath() {
return new AuditPath();
}
/**
* Create an instance of {@link RecordValue }
*
@@ -97,14 +73,6 @@ public class ObjectFactory {
return new RecordValue();
}
/**
* Create an instance of {@link Application }
*
*/
public Application createApplication() {
return new Application();
}
/**
* Create an instance of {@link GenerateValue }
*
@@ -113,6 +81,38 @@ public class ObjectFactory {
return new GenerateValue();
}
/**
* Create an instance of {@link Audit }
*
*/
public Audit createAudit() {
return new Audit();
}
/**
* Create an instance of {@link KeyedAuditDefinition }
*
*/
public KeyedAuditDefinition createKeyedAuditDefinition() {
return new KeyedAuditDefinition();
}
/**
* Create an instance of {@link DataExtractors }
*
*/
public DataExtractors createDataExtractors() {
return new DataExtractors();
}
/**
* Create an instance of {@link DataGenerator }
*
*/
public DataGenerator createDataGenerator() {
return new DataGenerator();
}
/**
* Create an instance of {@link JAXBElement }{@code <}{@link Audit }{@code >}}
*

View File

@@ -11,11 +11,12 @@
<!-- Includes duplicate definitions of the extractors and generators -->
<DataExtractors>
<DataExtractor name="simpleValue" class="org.alfresco.repo.audit.extractor.SimpleValueDataExtractor"/>
<DataExtractor name="simpleValue" registeredName="auditModel.extractor.simpleValue"/>
</DataExtractors>
<DataGenerators>
<DataGenerator name="systemTime" class="org.alfresco.repo.audit.generator.SystemTimeDataGenerator"/>
<DataGenerator name="systemTime" registeredName="auditModel.generator.time"/>
<DataGenerator name="user" class="org.alfresco.repo.audit.generator.AuthenticatedUserDataGenerator"/>
</DataGenerators>
<Application name="Alfresco Test" key="test">
@@ -63,6 +64,11 @@
</AuditPath>
</AuditPath>
</AuditPath>
<AuditPath key="node">
<AuditPath key="t1">
<RecordValue key="noderef" dataExtractor="simpleValue"/>
</AuditPath>
</AuditPath>
</Application>
</Audit>