mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Audit validation using XSD and related tests
git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@15875 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
@@ -79,6 +79,7 @@
|
|||||||
<!-- -->
|
<!-- -->
|
||||||
|
|
||||||
<bean id="auditModel.registry" class="org.alfresco.repo.audit.model.AuditModelRegistry">
|
<bean id="auditModel.registry" class="org.alfresco.repo.audit.model.AuditModelRegistry">
|
||||||
|
<property name="transactionService" ref="transactionService"/>
|
||||||
<property name="auditDAO" ref="auditDAO"/>
|
<property name="auditDAO" ref="auditDAO"/>
|
||||||
</bean>
|
</bean>
|
||||||
|
|
||||||
|
@@ -57,7 +57,6 @@
|
|||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="a:KeyedAuditDefinition">
|
<xs:extension base="a:KeyedAuditDefinition">
|
||||||
<xs:sequence>
|
<xs:sequence>
|
||||||
<xs:element name="AuditSession" type="a:AuditSession" minOccurs="0" maxOccurs="1"/>
|
|
||||||
<xs:element name="RecordValue" type="a:RecordValue" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="RecordValue" type="a:RecordValue" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
<xs:element name="GenerateValue" type="a:GenerateValue" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="GenerateValue" type="a:GenerateValue" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
<xs:element name="AuditPath" type="a:AuditPath" minOccurs="0" maxOccurs="unbounded"/>
|
<xs:element name="AuditPath" type="a:AuditPath" minOccurs="0" maxOccurs="unbounded"/>
|
||||||
@@ -66,12 +65,6 @@
|
|||||||
</xs:complexContent>
|
</xs:complexContent>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
|
|
||||||
<xs:complexType name="AuditSession">
|
|
||||||
<xs:sequence>
|
|
||||||
<xs:element name="GenerateValue" type="a:GenerateValue" minOccurs="0" maxOccurs="unbounded"/>
|
|
||||||
</xs:sequence>
|
|
||||||
</xs:complexType>
|
|
||||||
|
|
||||||
<xs:complexType name="RecordValue">
|
<xs:complexType name="RecordValue">
|
||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="a:KeyedAuditDefinition">
|
<xs:extension base="a:KeyedAuditDefinition">
|
||||||
@@ -84,6 +77,7 @@
|
|||||||
<xs:complexContent>
|
<xs:complexContent>
|
||||||
<xs:extension base="a:KeyedAuditDefinition">
|
<xs:extension base="a:KeyedAuditDefinition">
|
||||||
<xs:attribute name="dataGenerator" type="a:NameAttribute" use="required" />
|
<xs:attribute name="dataGenerator" type="a:NameAttribute" use="required" />
|
||||||
|
<xs:attribute name="scope" type="a:ScopeAttribute" use="required" />
|
||||||
</xs:extension>
|
</xs:extension>
|
||||||
</xs:complexContent>
|
</xs:complexContent>
|
||||||
</xs:complexType>
|
</xs:complexType>
|
||||||
@@ -108,7 +102,7 @@
|
|||||||
<xs:restriction base="xs:string">
|
<xs:restriction base="xs:string">
|
||||||
<xs:minLength value="1"/>
|
<xs:minLength value="1"/>
|
||||||
<xs:maxLength value="128"/>
|
<xs:maxLength value="128"/>
|
||||||
<xs:pattern value="([a-z]|\-)*"/>
|
<xs:pattern value="([a-z]|[0-9]|\-|\.)*"/>
|
||||||
</xs:restriction>
|
</xs:restriction>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
|
|
||||||
@@ -118,4 +112,12 @@
|
|||||||
</xs:restriction>
|
</xs:restriction>
|
||||||
</xs:simpleType>
|
</xs:simpleType>
|
||||||
|
|
||||||
|
<xs:simpleType name="ScopeAttribute">
|
||||||
|
<xs:restriction base="xs:string">
|
||||||
|
<xs:enumeration value="SESSION"/>
|
||||||
|
<xs:enumeration value="AUDIT"/>
|
||||||
|
<xs:enumeration value="ALL"/>
|
||||||
|
</xs:restriction>
|
||||||
|
</xs:simpleType>
|
||||||
|
|
||||||
</xs:schema>
|
</xs:schema>
|
@@ -23,12 +23,10 @@
|
|||||||
</DataGenerators>
|
</DataGenerators>
|
||||||
|
|
||||||
<Application name="Alfresco Repository" key="repository">
|
<Application name="Alfresco Repository" key="repository">
|
||||||
<AuditSession>
|
<GenerateValue key="user" dataGenerator="authenticatedUser" scope="SESSION"/>
|
||||||
<GenerateValue key="user" dataGenerator="authenticatedUser"/>
|
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSION"/>
|
||||||
<GenerateValue key="time" dataGenerator="systemTime"/>
|
|
||||||
</AuditSession>
|
|
||||||
<AuditPath key="services">
|
<AuditPath key="services">
|
||||||
<GenerateValue key="txn" dataGenerator="transactionId"/>
|
<GenerateValue key="txn" dataGenerator="transactionId" scope="AUDIT"/>
|
||||||
<AuditPath key="nodeservice">
|
<AuditPath key="nodeservice">
|
||||||
<AuditPath key="createstore">
|
<AuditPath key="createstore">
|
||||||
<AuditPath key="protocol">
|
<AuditPath key="protocol">
|
||||||
@@ -39,10 +37,12 @@
|
|||||||
</AuditPath>
|
</AuditPath>
|
||||||
<AuditPath key="return">
|
<AuditPath key="return">
|
||||||
<RecordValue key="value" dataExtractor="simpleValue"/>
|
<RecordValue key="value" dataExtractor="simpleValue"/>
|
||||||
|
<!--
|
||||||
<RecordValue key="root-node" dataExtractor="storeRootNode"/>
|
<RecordValue key="root-node" dataExtractor="storeRootNode"/>
|
||||||
</AuditPath>
|
</AuditPath>
|
||||||
<AuditPath key="error">
|
<AuditPath key="error">
|
||||||
<RecordValue key="value" dataExtractor="stackTrace"/>
|
<RecordValue key="value" dataExtractor="stackTrace"/>
|
||||||
|
-->
|
||||||
</AuditPath>
|
</AuditPath>
|
||||||
</AuditPath>
|
</AuditPath>
|
||||||
</AuditPath>
|
</AuditPath>
|
||||||
|
@@ -24,11 +24,20 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.audit;
|
package org.alfresco.repo.audit;
|
||||||
|
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||||
|
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||||
|
import org.alfresco.repo.audit.generator.DataGenerator.DataGeneratorScope;
|
||||||
|
import org.alfresco.repo.audit.model.AuditApplication;
|
||||||
|
import org.alfresco.repo.audit.model.AuditModelException;
|
||||||
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
||||||
import org.alfresco.util.ApplicationContextHelper;
|
import org.alfresco.util.ApplicationContextHelper;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests that auditing is loaded properly on repository startup.
|
* Tests that auditing is loaded properly on repository startup.
|
||||||
@@ -40,7 +49,7 @@ import org.springframework.context.ApplicationContext;
|
|||||||
*/
|
*/
|
||||||
public class AuditBootstrapTest extends TestCase
|
public class AuditBootstrapTest extends TestCase
|
||||||
{
|
{
|
||||||
private static final String APPLICATION_REPOSITORY = "Alfresco Repository";
|
private static final String APPLICATION_TEST = "Alfresco Test";
|
||||||
|
|
||||||
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
private static ApplicationContext ctx = ApplicationContextHelper.getApplicationContext();
|
||||||
|
|
||||||
@@ -50,6 +59,11 @@ public class AuditBootstrapTest extends TestCase
|
|||||||
public void setUp() throws Exception
|
public void setUp() throws Exception
|
||||||
{
|
{
|
||||||
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.registry");
|
auditModelRegistry = (AuditModelRegistry) ctx.getBean("auditModel.registry");
|
||||||
|
|
||||||
|
// Register a new model
|
||||||
|
URL testModelUrl = ResourceUtils.getURL("classpath:alfresco/audit/alfresco-audit-test.xml");
|
||||||
|
auditModelRegistry.registerModel(testModelUrl);
|
||||||
|
auditModelRegistry.loadAuditModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testSetUp()
|
public void testSetUp()
|
||||||
@@ -57,9 +71,116 @@ public class AuditBootstrapTest extends TestCase
|
|||||||
// Just here to fail if the basic startup fails
|
// Just here to fail if the basic startup fails
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadBadModel(String url) throws Exception
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
URL testModelUrl = ResourceUtils.getURL(url);
|
||||||
|
auditModelRegistry.registerModel(testModelUrl);
|
||||||
|
auditModelRegistry.loadAuditModels();
|
||||||
|
fail("Expected model loading to fail.");
|
||||||
|
}
|
||||||
|
catch (AuditModelException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModelLoading_NoDataExtractor() throws Exception
|
||||||
|
{
|
||||||
|
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-01.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModelLoading_NoDataGenerator() throws Exception
|
||||||
|
{
|
||||||
|
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-02.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModelLoading_DuplicatePath() throws Exception
|
||||||
|
{
|
||||||
|
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-03.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModelLoading_UppercasePath() throws Exception
|
||||||
|
{
|
||||||
|
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-04.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testModelLoading_InvalidScope() throws Exception
|
||||||
|
{
|
||||||
|
loadBadModel("classpath:alfresco/audit/alfresco-audit-test-bad-05.xml");
|
||||||
|
}
|
||||||
|
|
||||||
public void testGetModelId()
|
public void testGetModelId()
|
||||||
{
|
{
|
||||||
Long repoId = auditModelRegistry.getAuditModelId(APPLICATION_REPOSITORY);
|
Long repoId = auditModelRegistry.getAuditModelId(APPLICATION_TEST);
|
||||||
assertNotNull("No audit model ID for " + APPLICATION_REPOSITORY, repoId);
|
assertNotNull("No audit model ID for " + APPLICATION_TEST, repoId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testBadPath(AuditApplication app, String path)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
app.checkPath(path);
|
||||||
|
fail("Expected path check to fail.");
|
||||||
|
}
|
||||||
|
catch (AuditModelException e)
|
||||||
|
{
|
||||||
|
// Expected
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAuditApplication_Path()
|
||||||
|
{
|
||||||
|
AuditApplication app = auditModelRegistry.getAuditApplication(APPLICATION_TEST);
|
||||||
|
assertNotNull(app);
|
||||||
|
|
||||||
|
// Check that path checks are working
|
||||||
|
testBadPath(app, null);
|
||||||
|
testBadPath(app, "");
|
||||||
|
testBadPath(app, "test");
|
||||||
|
testBadPath(app, "/Test");
|
||||||
|
testBadPath(app, "/test/");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAuditApplication_GetDataExtractors()
|
||||||
|
{
|
||||||
|
AuditApplication app = auditModelRegistry.getAuditApplication(APPLICATION_TEST);
|
||||||
|
assertNotNull(app);
|
||||||
|
|
||||||
|
Map<String, DataExtractor> extractors = app.getDataExtractors("/blah");
|
||||||
|
assertNotNull("Should never get a null map", extractors);
|
||||||
|
assertTrue("Expected no extractors", extractors.isEmpty());
|
||||||
|
|
||||||
|
extractors = app.getDataExtractors("/test/1.1/2.1/3.1/4.1");
|
||||||
|
assertEquals(2, extractors.size());
|
||||||
|
assertTrue(extractors.containsKey("/test/1.1/2.1/3.1/value.1"));
|
||||||
|
assertTrue(extractors.containsKey("/test/1.1/2.1/3.1/4.1/value.1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testAuditApplication_GetDataGenerators_AnyScope()
|
||||||
|
{
|
||||||
|
AuditApplication app = auditModelRegistry.getAuditApplication(APPLICATION_TEST);
|
||||||
|
assertNotNull(app);
|
||||||
|
|
||||||
|
Map<String, DataGenerator> generators = app.getDataGenerators("/blah", DataGeneratorScope.ALL);
|
||||||
|
assertNotNull("Should never get a null map", generators);
|
||||||
|
assertTrue("Expected no generators", generators.isEmpty());
|
||||||
|
|
||||||
|
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1", DataGeneratorScope.ALL);
|
||||||
|
assertEquals(1, generators.size());
|
||||||
|
assertTrue(generators.containsKey("/test/time"));
|
||||||
|
|
||||||
|
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1", DataGeneratorScope.SESSION);
|
||||||
|
assertEquals(1, generators.size());
|
||||||
|
assertTrue(generators.containsKey("/test/time"));
|
||||||
|
|
||||||
|
generators = app.getDataGenerators("/test/1.1/2.1/3.1/4.1", DataGeneratorScope.AUDIT);
|
||||||
|
assertEquals(0, generators.size());
|
||||||
|
|
||||||
|
generators = app.getDataGenerators("/test/1.1/2.2/3.2/4.1", DataGeneratorScope.ALL);
|
||||||
|
assertEquals(2, generators.size());
|
||||||
|
assertTrue(generators.containsKey("/test/time"));
|
||||||
|
assertTrue(generators.containsKey("/test/1.1/2.2/3.2/4.1/time"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -91,14 +91,14 @@ public interface AuditComponent
|
|||||||
*
|
*
|
||||||
* @param application the name of the application to log against
|
* @param application the name of the application to log against
|
||||||
* @param rootPath a base path of {@link AuditPath} key entries concatenated with <b>.</b> (period)
|
* @param rootPath a base path of {@link AuditPath} key entries concatenated with <b>.</b> (period)
|
||||||
* @return Returns the unique session identifier
|
* @return Returns the unique session
|
||||||
*/
|
*/
|
||||||
public Long startAuditSession(String application, String rootPath);
|
public AuditSession startAuditSession(String application, String rootPath);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Record a set of values against the given session.
|
* Record a set of values against the given session.
|
||||||
*
|
*
|
||||||
* @param sessionId a pre-existing audit session to continue with
|
* @param session a pre-existing audit session to continue with
|
||||||
* @param values the values to audit mapped by {@link AuditPath} key relative to the session
|
* @param values the values to audit mapped by {@link AuditPath} key relative to the session
|
||||||
* root path
|
* root path
|
||||||
*
|
*
|
||||||
@@ -106,5 +106,5 @@ public interface AuditComponent
|
|||||||
*
|
*
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public void audit(Long sessionId, Map<String, Object> values);
|
public void audit(AuditSession session, Map<String, Object> values);
|
||||||
}
|
}
|
||||||
|
@@ -32,14 +32,13 @@ import java.util.Date;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.alfresco.repo.audit.model.AuditApplication;
|
||||||
import org.alfresco.repo.audit.model.AuditEntry;
|
import org.alfresco.repo.audit.model.AuditEntry;
|
||||||
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
import org.alfresco.repo.audit.model.AuditModelRegistry;
|
||||||
import org.alfresco.repo.audit.model.TrueFalseUnset;
|
import org.alfresco.repo.audit.model.TrueFalseUnset;
|
||||||
import org.alfresco.repo.audit.model._3.Application;
|
|
||||||
import org.alfresco.repo.domain.audit.AuditDAO;
|
import org.alfresco.repo.domain.audit.AuditDAO;
|
||||||
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
||||||
import org.alfresco.repo.transaction.TransactionalResourceHelper;
|
|
||||||
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
import org.alfresco.repo.transaction.AlfrescoTransactionSupport.TxnReadState;
|
||||||
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
import org.alfresco.repo.transaction.RetryingTransactionHelper.RetryingTransactionCallback;
|
||||||
import org.alfresco.service.Auditable;
|
import org.alfresco.service.Auditable;
|
||||||
@@ -752,8 +751,7 @@ public class AuditComponentImpl implements 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.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private static final Long NO_AUDIT_SESSION = new Long(-1);
|
private static final AuditSession NO_AUDIT_SESSION = new AuditSession();
|
||||||
private static final String KEY_AUDIT_SESSION = "Audit.Sessions";
|
|
||||||
|
|
||||||
private AuditModelRegistry auditModelRegistry;
|
private AuditModelRegistry auditModelRegistry;
|
||||||
|
|
||||||
@@ -766,13 +764,10 @@ public class AuditComponentImpl implements AuditComponent
|
|||||||
this.auditModelRegistry = auditModelRegistry;
|
this.auditModelRegistry = auditModelRegistry;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long startAuditSession(String applicationName, String rootPath)
|
public AuditSession startAuditSession(String applicationName, String rootPath)
|
||||||
{
|
{
|
||||||
// First check that we can store a session on the transaction
|
|
||||||
Map<Long, AuditSession> sessionsById = TransactionalResourceHelper.getMap(KEY_AUDIT_SESSION);
|
|
||||||
|
|
||||||
// Get the application
|
// Get the application
|
||||||
Application application = auditModelRegistry.getAuditApplication(applicationName);
|
AuditApplication application = auditModelRegistry.getAuditApplication(applicationName);
|
||||||
if (application == null)
|
if (application == null)
|
||||||
{
|
{
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
@@ -788,25 +783,34 @@ public class AuditComponentImpl implements AuditComponent
|
|||||||
throw new AuditException("No model exists for audit application: " + applicationName);
|
throw new AuditException("No model exists for audit application: " + applicationName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Validate root path against application
|
// Validate root path against application
|
||||||
|
String appRootKey = application.getApplicationKey() + AuditApplication.AUDIT_PATH_SEPARATOR;
|
||||||
|
if (rootPath == null || !rootPath.startsWith(appRootKey))
|
||||||
|
{
|
||||||
|
throw new AuditException(
|
||||||
|
"An audit session's root path must start with the application's root key.\n" +
|
||||||
|
" Application: " + application.getApplicationName() + "\n" +
|
||||||
|
" Root key: " + application.getApplicationKey() + "\n" +
|
||||||
|
" Given root: " + rootPath);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Pull out session properties and persist
|
// TODO: Pull out session properties and persist
|
||||||
|
|
||||||
// Now create the session
|
// Now create the session
|
||||||
Long sessionId = auditDAO.createAuditSession(modelId, applicationName);
|
Long sessionId = auditDAO.createAuditSession(modelId, applicationName);
|
||||||
// Create the session info and store it on the transaction
|
// Create the session info and store it on the transaction
|
||||||
AuditSession session = new AuditSession(application, rootPath, sessionId);
|
AuditSession session = new AuditSession(application, rootPath, sessionId);
|
||||||
sessionsById.put(sessionId, session);
|
|
||||||
// Done
|
// Done
|
||||||
if (logger.isDebugEnabled())
|
if (logger.isDebugEnabled())
|
||||||
{
|
{
|
||||||
logger.debug("New audit session: " + session);
|
logger.debug("New audit session: " + session);
|
||||||
}
|
}
|
||||||
return sessionId;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void audit(Long sessionId, Map<String, Object> values)
|
public void audit(AuditSession session, Map<String, Object> values)
|
||||||
{
|
{
|
||||||
if (sessionId == NO_AUDIT_SESSION)
|
if (session == NO_AUDIT_SESSION)
|
||||||
{
|
{
|
||||||
// For some reason, the session was not to be used
|
// For some reason, the session was not to be used
|
||||||
return;
|
return;
|
||||||
|
@@ -24,7 +24,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.alfresco.repo.audit;
|
package org.alfresco.repo.audit;
|
||||||
|
|
||||||
import org.alfresco.repo.audit.model._3.Application;
|
import org.alfresco.repo.audit.model.AuditApplication;
|
||||||
import org.alfresco.util.ParameterCheck;
|
import org.alfresco.util.ParameterCheck;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -35,16 +35,26 @@ import org.alfresco.util.ParameterCheck;
|
|||||||
*/
|
*/
|
||||||
public class AuditSession
|
public class AuditSession
|
||||||
{
|
{
|
||||||
private final Application application;
|
private final AuditApplication application;
|
||||||
private final String rootPath;
|
private final String rootPath;
|
||||||
private final Long sessionId;
|
private final Long sessionId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor used to denote a dummy (no-audit) session
|
||||||
|
*/
|
||||||
|
/* package */ AuditSession()
|
||||||
|
{
|
||||||
|
application = null;
|
||||||
|
rootPath = null;
|
||||||
|
sessionId = null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param application the audit application config being used
|
* @param application the audit application config being used
|
||||||
* @param rootPath the root path being used for the session
|
* @param rootPath the root path being used for the session
|
||||||
* @param sessionId the ID produced for the persisted session
|
* @param sessionId the ID produced for the persisted session
|
||||||
*/
|
*/
|
||||||
public AuditSession(Application application, String rootPath, Long sessionId)
|
public AuditSession(AuditApplication application, String rootPath, Long sessionId)
|
||||||
{
|
{
|
||||||
ParameterCheck.mandatory("application", application);
|
ParameterCheck.mandatory("application", application);
|
||||||
ParameterCheck.mandatoryString("rootPath", rootPath);
|
ParameterCheck.mandatoryString("rootPath", rootPath);
|
||||||
@@ -58,7 +68,7 @@ public class AuditSession
|
|||||||
@Override
|
@Override
|
||||||
public int hashCode()
|
public int hashCode()
|
||||||
{
|
{
|
||||||
return (application.getName().hashCode() + rootPath.hashCode());
|
return (application.hashCode() + rootPath.hashCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,7 +81,7 @@ public class AuditSession
|
|||||||
else if (obj instanceof AuditSession)
|
else if (obj instanceof AuditSession)
|
||||||
{
|
{
|
||||||
AuditSession that = (AuditSession) obj;
|
AuditSession that = (AuditSession) obj;
|
||||||
return this.application.getName().equals(that.application.getName()) &&
|
return this.application.equals(that.application) &&
|
||||||
this.rootPath.equals(that.rootPath);
|
this.rootPath.equals(that.rootPath);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -85,14 +95,14 @@ public class AuditSession
|
|||||||
{
|
{
|
||||||
StringBuilder sb = new StringBuilder(512);
|
StringBuilder sb = new StringBuilder(512);
|
||||||
sb.append("AuditSession")
|
sb.append("AuditSession")
|
||||||
.append("[ application=").append(application.getName())
|
.append("[ application=").append(application)
|
||||||
.append(", rootPath=").append(rootPath)
|
.append(", rootPath=").append(rootPath)
|
||||||
.append(", sessionId=").append(sessionId)
|
.append(", sessionId=").append(sessionId)
|
||||||
.append("]");
|
.append("]");
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Application getApplication()
|
public AuditApplication getApplication()
|
||||||
{
|
{
|
||||||
return application;
|
return application;
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2009 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.extractor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract implementation to provide support.
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDataExtractor implements DataExtractor
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This implementation assumes all extractors are stateless i.e. if the class matches
|
||||||
|
* then the instances are equal.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj != null && obj.getClass().equals(this.getClass()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -32,7 +32,7 @@ package org.alfresco.repo.audit.extractor;
|
|||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class SimpleValueDataExtractor implements DataExtractor
|
public class SimpleValueDataExtractor extends AbstractDataExtractor
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Returns <tt>true</tt> always
|
* @return Returns <tt>true</tt> always
|
||||||
|
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2009 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.generator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract implementation to provide support.
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public abstract class AbstractDataGenerator implements DataGenerator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This implementation assumes all generators are stateless i.e. if the class matches
|
||||||
|
* then the instances are equal.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (obj != null && obj.getClass().equals(this.getClass()))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -32,7 +32,7 @@ import org.alfresco.repo.security.authentication.AuthenticationUtil;
|
|||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class AuthenticatedUserDataGenerator implements DataGenerator
|
public class AuthenticatedUserDataGenerator extends AbstractDataGenerator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Returns the currently-authenticated user
|
* @return Returns the currently-authenticated user
|
||||||
|
@@ -36,6 +36,16 @@ package org.alfresco.repo.audit.generator;
|
|||||||
*/
|
*/
|
||||||
public interface DataGenerator
|
public interface DataGenerator
|
||||||
{
|
{
|
||||||
|
public static enum DataGeneratorScope
|
||||||
|
{
|
||||||
|
/** Data is generated for new audit sessions only */
|
||||||
|
SESSION,
|
||||||
|
/** Data is generated for individual audit calls only */
|
||||||
|
AUDIT,
|
||||||
|
/** Data is generated for new audit sessions and audit calls */
|
||||||
|
ALL
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the data generated by the instance.
|
* Get the data generated by the instance.
|
||||||
*
|
*
|
||||||
|
@@ -32,7 +32,7 @@ import java.util.Date;
|
|||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class SystemTimeDataGenerator implements DataGenerator
|
public class SystemTimeDataGenerator extends AbstractDataGenerator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Returns the current time
|
* @return Returns the current time
|
||||||
|
@@ -32,7 +32,7 @@ import org.alfresco.repo.transaction.AlfrescoTransactionSupport;
|
|||||||
* @author Derek Hulley
|
* @author Derek Hulley
|
||||||
* @since 3.2
|
* @since 3.2
|
||||||
*/
|
*/
|
||||||
public class TransactionIdDataGenerator implements DataGenerator
|
public class TransactionIdDataGenerator extends AbstractDataGenerator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @return Returns the current transaction ID (<tt>null</tt> if not in a transction)
|
* @return Returns the current transaction ID (<tt>null</tt> if not in a transction)
|
||||||
|
395
source/java/org/alfresco/repo/audit/model/AuditApplication.java
Normal file
395
source/java/org/alfresco/repo/audit/model/AuditApplication.java
Normal file
@@ -0,0 +1,395 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2005-2009 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.model;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||||
|
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||||
|
import org.alfresco.repo.audit.generator.DataGenerator.DataGeneratorScope;
|
||||||
|
import org.alfresco.repo.audit.model._3.Application;
|
||||||
|
import org.alfresco.repo.audit.model._3.AuditPath;
|
||||||
|
import org.alfresco.repo.audit.model._3.GenerateValue;
|
||||||
|
import org.alfresco.repo.audit.model._3.RecordValue;
|
||||||
|
import org.alfresco.repo.audit.model._3.ScopeAttribute;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper class that wraps the {@link Application audit application}.
|
||||||
|
* Once wrapped, client code doesn't need access to any of the generated
|
||||||
|
* model-driven classes.
|
||||||
|
*
|
||||||
|
* @author Derek Hulley
|
||||||
|
* @since 3.2
|
||||||
|
*/
|
||||||
|
public class AuditApplication
|
||||||
|
{
|
||||||
|
public static final String AUDIT_PATH_SEPARATOR = "/";
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AuditApplication.class);
|
||||||
|
|
||||||
|
private final String applicationName;
|
||||||
|
private final String applicationKey;
|
||||||
|
|
||||||
|
private final Map<String, DataExtractor> dataExtractorsByName;
|
||||||
|
private final Map<String, DataGenerator> dataGeneratorsByName;
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private final Application application;
|
||||||
|
|
||||||
|
/** Derived expaned map for fast lookup */
|
||||||
|
private Map<String, Map<String, DataExtractor>> dataExtractors = new HashMap<String, Map<String, DataExtractor>>(11);
|
||||||
|
/** Derived expaned map for fast lookup */
|
||||||
|
private Map<String, Map<String, DataGenerator>> dataGenerators = new HashMap<String, Map<String, DataGenerator>>(11);
|
||||||
|
/** Derived expaned map for fast lookup */
|
||||||
|
private Map<String, DataGeneratorScope> dataGeneratorScopes = new HashMap<String, DataGeneratorScope>(11);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param application the application that will be wrapped
|
||||||
|
* @param dataExtractorsByName data extractors to use
|
||||||
|
* @param dataGeneratorsByName data generators to use
|
||||||
|
*/
|
||||||
|
/* package */ AuditApplication(
|
||||||
|
Map<String, DataExtractor> dataExtractorsByName,
|
||||||
|
Map<String, DataGenerator> dataGeneratorsByName,
|
||||||
|
Application application)
|
||||||
|
{
|
||||||
|
this.dataExtractorsByName = dataExtractorsByName;
|
||||||
|
this.dataGeneratorsByName = dataGeneratorsByName;
|
||||||
|
this.application = application;
|
||||||
|
|
||||||
|
this.applicationName = application.getName();
|
||||||
|
this.applicationKey = application.getKey();
|
||||||
|
|
||||||
|
buildAuditPaths(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return applicationName.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj)
|
||||||
|
{
|
||||||
|
if (this == obj)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (obj instanceof AuditApplication)
|
||||||
|
{
|
||||||
|
AuditApplication that = (AuditApplication) obj;
|
||||||
|
return this.applicationName.equals(that.applicationName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder(56);
|
||||||
|
sb.append("AuditApplication")
|
||||||
|
.append("[ name=").append(applicationName)
|
||||||
|
.append("]");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the application name
|
||||||
|
*/
|
||||||
|
public String getApplicationName()
|
||||||
|
{
|
||||||
|
return applicationName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the key (root path) for the application
|
||||||
|
*/
|
||||||
|
public String getApplicationKey()
|
||||||
|
{
|
||||||
|
return applicationKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper method to check that a path is correct for this application instance
|
||||||
|
*
|
||||||
|
* @param path the path in format <b>/app-key/x/y/z</b>
|
||||||
|
* @throws AuditModelException if the path is invalid
|
||||||
|
*/
|
||||||
|
public void checkPath(String path)
|
||||||
|
{
|
||||||
|
if (path == null || path.length() == 0)
|
||||||
|
{
|
||||||
|
generateException(path, "Invalid audit path.");
|
||||||
|
}
|
||||||
|
if (!path.startsWith(AUDIT_PATH_SEPARATOR))
|
||||||
|
{
|
||||||
|
generateException(
|
||||||
|
path,
|
||||||
|
"An audit path must always start with the separator '" + AUDIT_PATH_SEPARATOR + "'.");
|
||||||
|
}
|
||||||
|
if (path.indexOf(applicationKey, 0) != 1)
|
||||||
|
{
|
||||||
|
generateException(
|
||||||
|
path,
|
||||||
|
"An audit path's first element must be the application's key i.e. '" + applicationKey + "'.");
|
||||||
|
}
|
||||||
|
if (path.endsWith(AUDIT_PATH_SEPARATOR))
|
||||||
|
{
|
||||||
|
generateException(
|
||||||
|
path,
|
||||||
|
"An audit path may not end with the separator '" + AUDIT_PATH_SEPARATOR + "'.");
|
||||||
|
}
|
||||||
|
if (!path.toLowerCase().equals(path))
|
||||||
|
{
|
||||||
|
generateException(
|
||||||
|
path,
|
||||||
|
"An audit path may only contain lowercase letters, '-' and '.' i.e. regex ([a-z]|[0-9]|\\-|\\.)*");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all data extractors applicable to a given path and scope.
|
||||||
|
*
|
||||||
|
* @param path the audit path
|
||||||
|
* @return Returns all data extractors mapped to their key-path
|
||||||
|
*/
|
||||||
|
public Map<String, DataExtractor> getDataExtractors(String path)
|
||||||
|
{
|
||||||
|
Map<String, DataExtractor> extractors = dataExtractors.get(path);
|
||||||
|
if (extractors == null)
|
||||||
|
{
|
||||||
|
// Don't give back a null
|
||||||
|
extractors = Collections.emptyMap();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we don't want to give back a modifiable map
|
||||||
|
extractors = Collections.unmodifiableMap(extractors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(
|
||||||
|
"Looked up data extractors: \n" +
|
||||||
|
" Path: " + path + "\n" +
|
||||||
|
" Found: " + extractors);
|
||||||
|
}
|
||||||
|
return extractors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all data generators applicable to a given path and scope.
|
||||||
|
*
|
||||||
|
* @param path the audit path
|
||||||
|
* @param scope the audit scope (e.g. SESSION or AUDIT)
|
||||||
|
* @return Returns all data generators mapped to their key-path
|
||||||
|
*/
|
||||||
|
public Map<String, DataGenerator> getDataGenerators(String path, DataGeneratorScope scope)
|
||||||
|
{
|
||||||
|
Map<String, DataGenerator> generators = dataGenerators.get(path);
|
||||||
|
if (generators == null)
|
||||||
|
{
|
||||||
|
// Don't give back a null
|
||||||
|
generators = new HashMap<String, DataGenerator>(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Copy the map so that (a) we can modify it during iteration and (b) we return
|
||||||
|
// something that the client can't mess up.
|
||||||
|
generators = new HashMap<String, DataGenerator>(generators);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scope != DataGeneratorScope.ALL)
|
||||||
|
{
|
||||||
|
// Go through them and eliminate the ones in the wrong scope
|
||||||
|
Iterator<Map.Entry<String, DataGenerator>> iterator = generators.entrySet().iterator();
|
||||||
|
while (iterator.hasNext())
|
||||||
|
{
|
||||||
|
Map.Entry<String, DataGenerator> entry = iterator.next();
|
||||||
|
String generatorPath = entry.getKey();
|
||||||
|
DataGeneratorScope generatorScope = dataGeneratorScopes.get(generatorPath);
|
||||||
|
if (generatorScope == DataGeneratorScope.ALL)
|
||||||
|
{
|
||||||
|
// This one always applies
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (generatorScope != scope)
|
||||||
|
{
|
||||||
|
// Wrong scope
|
||||||
|
iterator.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
{
|
||||||
|
logger.debug(
|
||||||
|
"Looked up data generators: \n" +
|
||||||
|
" Path: " + path + "\n" +
|
||||||
|
" Scope: " + scope + "\n" +
|
||||||
|
" Found: " + generators);
|
||||||
|
}
|
||||||
|
return generators;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal helper method to kick off generator and extractor path mappings
|
||||||
|
*/
|
||||||
|
private void buildAuditPaths(AuditPath auditPath)
|
||||||
|
{
|
||||||
|
buildAuditPaths(
|
||||||
|
auditPath,
|
||||||
|
"",
|
||||||
|
new HashSet<String>(37),
|
||||||
|
new HashMap<String, DataExtractor>(13),
|
||||||
|
new HashMap<String, DataGenerator>(13));
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Recursive method to build generator and extractor mappings
|
||||||
|
*/
|
||||||
|
private void buildAuditPaths(
|
||||||
|
AuditPath auditPath,
|
||||||
|
String currentPath,
|
||||||
|
Set<String> existingPaths,
|
||||||
|
Map<String, DataExtractor> upperExtractorsByPath,
|
||||||
|
Map<String, DataGenerator> upperGeneratorsByPath)
|
||||||
|
{
|
||||||
|
// Clone the upper maps to prevent pollution
|
||||||
|
upperExtractorsByPath = new HashMap<String, DataExtractor>(upperExtractorsByPath);
|
||||||
|
upperGeneratorsByPath = new HashMap<String, DataGenerator>(upperGeneratorsByPath);
|
||||||
|
|
||||||
|
// Append the current audit path to the current path
|
||||||
|
currentPath = (currentPath + AUDIT_PATH_SEPARATOR + auditPath.getKey());
|
||||||
|
// Make sure we have not processed it before
|
||||||
|
if (!existingPaths.add(currentPath))
|
||||||
|
{
|
||||||
|
generateException(currentPath, "The audit path already exists.");
|
||||||
|
}
|
||||||
|
// Make sure that the path is all lowercase
|
||||||
|
checkPathCase(currentPath);
|
||||||
|
|
||||||
|
// Get the data extractors declared for this key
|
||||||
|
for (RecordValue element : auditPath.getRecordValue())
|
||||||
|
{
|
||||||
|
String key = element.getKey();
|
||||||
|
String extractorPath = (currentPath + AUDIT_PATH_SEPARATOR + key);
|
||||||
|
if (!existingPaths.add(extractorPath))
|
||||||
|
{
|
||||||
|
generateException(extractorPath, "The audit path already exists.");
|
||||||
|
}
|
||||||
|
// Make sure that the path is all lowercase
|
||||||
|
checkPathCase(extractorPath);
|
||||||
|
|
||||||
|
String extractorName = element.getDataExtractor();
|
||||||
|
DataExtractor extractor = dataExtractorsByName.get(extractorName);
|
||||||
|
if (extractor == null)
|
||||||
|
{
|
||||||
|
generateException(extractorPath, "No data extractor exists for name: " + extractorName);
|
||||||
|
}
|
||||||
|
// All generators that occur earlier in the path will also be applicable here
|
||||||
|
upperExtractorsByPath.put(extractorPath, extractor);
|
||||||
|
}
|
||||||
|
// All the extractors apply to the current path
|
||||||
|
dataExtractors.put(currentPath, upperExtractorsByPath);
|
||||||
|
|
||||||
|
// Get the data generators declared for this key
|
||||||
|
for (GenerateValue element : auditPath.getGenerateValue())
|
||||||
|
{
|
||||||
|
String key = element.getKey();
|
||||||
|
String generatorPath = (currentPath + AUDIT_PATH_SEPARATOR + key);
|
||||||
|
if (!existingPaths.add(generatorPath))
|
||||||
|
{
|
||||||
|
generateException(generatorPath, "The audit path already exists.");
|
||||||
|
}
|
||||||
|
// Make sure that the path is all lowercase
|
||||||
|
checkPathCase(generatorPath);
|
||||||
|
|
||||||
|
String generatorName = element.getDataGenerator();
|
||||||
|
DataGenerator generator = dataGeneratorsByName.get(generatorName);
|
||||||
|
if (generator == null)
|
||||||
|
{
|
||||||
|
generateException(generatorPath, "No data generator exists for name: " + generatorName);
|
||||||
|
}
|
||||||
|
// Store the scope
|
||||||
|
ScopeAttribute scopeAttribute = element.getScope();
|
||||||
|
if (scopeAttribute == null)
|
||||||
|
{
|
||||||
|
generateException(generatorPath, "No scope defined for generator: " + generatorName);
|
||||||
|
}
|
||||||
|
String scopeStr = scopeAttribute.value();
|
||||||
|
if (scopeStr == null)
|
||||||
|
{
|
||||||
|
scopeStr = DataGeneratorScope.AUDIT.toString();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DataGeneratorScope scope = DataGeneratorScope.valueOf(scopeStr);
|
||||||
|
dataGeneratorScopes.put(generatorPath, scope);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
generateException(generatorPath, "Illegal generator scope value: " + scopeStr);
|
||||||
|
}
|
||||||
|
// All generators that occur earlier in the path will also be applicable here
|
||||||
|
upperGeneratorsByPath.put(generatorPath, generator);
|
||||||
|
}
|
||||||
|
// All the generators apply to the current path
|
||||||
|
dataGenerators.put(currentPath, upperGeneratorsByPath);
|
||||||
|
|
||||||
|
// Find all sub audit paths and recurse
|
||||||
|
for (AuditPath element : auditPath.getAuditPath())
|
||||||
|
{
|
||||||
|
buildAuditPaths(element, currentPath, existingPaths, upperExtractorsByPath, upperGeneratorsByPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkPathCase(String path)
|
||||||
|
{
|
||||||
|
if (!path.equals(path.toLowerCase()))
|
||||||
|
{
|
||||||
|
generateException(path, "Audit key entries may only be in lowercase to ensure case-insensitivity.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateException(String path, String msg) throws AuditModelException
|
||||||
|
{
|
||||||
|
throw new AuditModelException("" +
|
||||||
|
msg + "\n" +
|
||||||
|
" Application: " + applicationName + "\n" +
|
||||||
|
" Path: " + path);
|
||||||
|
}
|
||||||
|
}
|
@@ -25,8 +25,6 @@
|
|||||||
package org.alfresco.repo.audit.model;
|
package org.alfresco.repo.audit.model;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
@@ -41,16 +39,29 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
|
|||||||
import javax.xml.bind.JAXBContext;
|
import javax.xml.bind.JAXBContext;
|
||||||
import javax.xml.bind.JAXBElement;
|
import javax.xml.bind.JAXBElement;
|
||||||
import javax.xml.bind.Unmarshaller;
|
import javax.xml.bind.Unmarshaller;
|
||||||
|
import javax.xml.bind.ValidationEvent;
|
||||||
|
import javax.xml.bind.ValidationEventHandler;
|
||||||
|
import javax.xml.bind.ValidationEventLocator;
|
||||||
|
import javax.xml.validation.Schema;
|
||||||
|
import javax.xml.validation.SchemaFactory;
|
||||||
|
|
||||||
import org.alfresco.error.AlfrescoRuntimeException;
|
import org.alfresco.error.AlfrescoRuntimeException;
|
||||||
|
import org.alfresco.error.ExceptionStackUtil;
|
||||||
import org.alfresco.repo.audit.extractor.DataExtractor;
|
import org.alfresco.repo.audit.extractor.DataExtractor;
|
||||||
import org.alfresco.repo.audit.generator.DataGenerator;
|
import org.alfresco.repo.audit.generator.DataGenerator;
|
||||||
import org.alfresco.repo.audit.model._3.Application;
|
import org.alfresco.repo.audit.model._3.Application;
|
||||||
import org.alfresco.repo.audit.model._3.Audit;
|
import org.alfresco.repo.audit.model._3.Audit;
|
||||||
import org.alfresco.repo.audit.model._3.DataExtractors;
|
import org.alfresco.repo.audit.model._3.DataExtractors;
|
||||||
import org.alfresco.repo.audit.model._3.DataGenerators;
|
import org.alfresco.repo.audit.model._3.DataGenerators;
|
||||||
|
import org.alfresco.repo.audit.model._3.ObjectFactory;
|
||||||
import org.alfresco.repo.domain.audit.AuditDAO;
|
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.cmr.repository.NodeRef;
|
||||||
|
import org.alfresco.service.transaction.TransactionService;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
import org.xml.sax.SAXParseException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component used to store audit model definitions. It ensures that duplicate application and converter
|
* Component used to store audit model definitions. It ensures that duplicate application and converter
|
||||||
@@ -61,8 +72,13 @@ import org.alfresco.service.cmr.repository.NodeRef;
|
|||||||
*/
|
*/
|
||||||
public class AuditModelRegistry
|
public class AuditModelRegistry
|
||||||
{
|
{
|
||||||
|
public static final String AUDIT_SCHEMA_LOCATION = "classpath:alfresco/audit/alfresco-audit-3.2.xsd";
|
||||||
|
|
||||||
|
private TransactionService transactionService;
|
||||||
private AuditDAO auditDAO;
|
private AuditDAO auditDAO;
|
||||||
|
|
||||||
|
private static final Log logger = LogFactory.getLog(AuditModelRegistry.class);
|
||||||
|
|
||||||
private final ReentrantReadWriteLock.ReadLock readLock;
|
private final ReentrantReadWriteLock.ReadLock readLock;
|
||||||
private final ReentrantReadWriteLock.WriteLock writeLock;
|
private final ReentrantReadWriteLock.WriteLock writeLock;
|
||||||
|
|
||||||
@@ -73,7 +89,7 @@ public class AuditModelRegistry
|
|||||||
/**
|
/**
|
||||||
* Used to lookup the audit application java hierarchy
|
* Used to lookup the audit application java hierarchy
|
||||||
*/
|
*/
|
||||||
private final Map<String, Application> auditApplicationsByName;
|
private final Map<String, AuditApplication> auditApplicationsByName;
|
||||||
/**
|
/**
|
||||||
* Used to lookup a reference to the persisted config binary for an application
|
* Used to lookup a reference to the persisted config binary for an application
|
||||||
*/
|
*/
|
||||||
@@ -92,10 +108,18 @@ public class AuditModelRegistry
|
|||||||
auditModels = new ArrayList<Audit>(7);
|
auditModels = new ArrayList<Audit>(7);
|
||||||
dataExtractorsByName = new HashMap<String, DataExtractor>(13);
|
dataExtractorsByName = new HashMap<String, DataExtractor>(13);
|
||||||
dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
|
dataGeneratorsByName = new HashMap<String, DataGenerator>(13);
|
||||||
auditApplicationsByName = new HashMap<String, Application>(7);
|
auditApplicationsByName = new HashMap<String, AuditApplication>(7);
|
||||||
auditModelIdsByApplicationsName = new HashMap<String, Long>(7);
|
auditModelIdsByApplicationsName = new HashMap<String, Long>(7);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service to ensure DAO calls are transactionally wrapped
|
||||||
|
*/
|
||||||
|
public void setTransactionService(TransactionService transactionService)
|
||||||
|
{
|
||||||
|
this.transactionService = transactionService;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the DAO used to persisted the registered audit models
|
* Set the DAO used to persisted the registered audit models
|
||||||
*/
|
*/
|
||||||
@@ -116,8 +140,7 @@ public class AuditModelRegistry
|
|||||||
{
|
{
|
||||||
if (auditModelUrls.contains(auditModelUrl))
|
if (auditModelUrls.contains(auditModelUrl))
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException(
|
logger.warn("An audit model has already been registered at URL " + auditModelUrl);
|
||||||
"An audit model has already been registered at URL " + auditModelUrl);
|
|
||||||
}
|
}
|
||||||
auditModelUrls.add(auditModelUrl);
|
auditModelUrls.add(auditModelUrl);
|
||||||
}
|
}
|
||||||
@@ -145,26 +168,67 @@ public class AuditModelRegistry
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans out all derived data
|
||||||
|
*/
|
||||||
|
private void clearCaches()
|
||||||
|
{
|
||||||
|
auditModels.clear();
|
||||||
|
dataExtractorsByName.clear();
|
||||||
|
dataGeneratorsByName.clear();;
|
||||||
|
auditApplicationsByName.clear();
|
||||||
|
auditModelIdsByApplicationsName.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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. Models are loaded from the locations given by the
|
||||||
* {@link #registerModel(URL) register} methods.
|
* {@link #registerModel(URL) register} methods.
|
||||||
|
* <p/>
|
||||||
|
* Note, the models are loaded in a new transaction.
|
||||||
*/
|
*/
|
||||||
public void loadAuditModels()
|
public void loadAuditModels()
|
||||||
{
|
{
|
||||||
|
RetryingTransactionCallback<Void> loadModelsCallback = new RetryingTransactionCallback<Void>()
|
||||||
|
{
|
||||||
|
public Void execute() throws Throwable
|
||||||
|
{
|
||||||
|
// Load models from the URLs
|
||||||
|
Set<URL> auditModelUrlsInner = new HashSet<URL>(auditModelUrls);
|
||||||
|
for (URL auditModelUrl : auditModelUrlsInner)
|
||||||
|
{
|
||||||
|
Audit audit = AuditModelRegistry.unmarshallModel(auditModelUrl);
|
||||||
|
// That worked, so now get an input stream and write the model
|
||||||
|
Long auditModelId = auditDAO.getOrCreateAuditModel(auditModelUrl).getFirst();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Now cache it (eagerly)
|
||||||
|
cacheAuditElements(auditModelId, audit);
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
// Mainly for test purposes, we clear out the failed URL
|
||||||
|
auditModelUrls.remove(auditModelUrl);
|
||||||
|
clearCaches();
|
||||||
|
|
||||||
|
throw new AuditModelException(
|
||||||
|
"Failed to load audit model: " + auditModelUrl + "\n" +
|
||||||
|
e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// NOTE: If we support other types of loading, then that will have to go here, too
|
||||||
|
|
||||||
|
// Done
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
writeLock.lock();
|
writeLock.lock();
|
||||||
|
// Drop all cached data
|
||||||
|
clearCaches();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Load models from the URLs
|
transactionService.getRetryingTransactionHelper().doInTransaction(loadModelsCallback);
|
||||||
for (URL auditModelUrl : auditModelUrls)
|
|
||||||
{
|
|
||||||
Audit audit = AuditModelRegistry.unmarshallModel(auditModelUrl);
|
|
||||||
// That worked, so now get an input stream and write the model
|
|
||||||
Long auditModelId = auditDAO.getOrCreateAuditModel(auditModelUrl).getFirst();
|
|
||||||
// Now cache it (eagerly)
|
|
||||||
cacheAuditElements(auditModelId, audit);
|
|
||||||
}
|
|
||||||
// NOTE: If we support other types of loading, then that will have to go here, too
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -197,7 +261,7 @@ public class AuditModelRegistry
|
|||||||
* @param application the name of the audited application
|
* @param application the name of the audited application
|
||||||
* @return the java model (<tt>null</tt> if not found)
|
* @return the java model (<tt>null</tt> if not found)
|
||||||
*/
|
*/
|
||||||
public Application getAuditApplication(String application)
|
public AuditApplication getAuditApplication(String application)
|
||||||
{
|
{
|
||||||
readLock.lock();
|
readLock.lock();
|
||||||
try
|
try
|
||||||
@@ -219,14 +283,8 @@ public class AuditModelRegistry
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
File file = new File(configUrl.getFile());
|
|
||||||
if (!file.exists())
|
|
||||||
{
|
|
||||||
throw new AlfrescoRuntimeException("The Audit model XML was not found: " + configUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load it
|
// Load it
|
||||||
InputStream is = new BufferedInputStream(new FileInputStream(file));
|
InputStream is = new BufferedInputStream(configUrl.openStream());
|
||||||
return unmarshallModel(is, configUrl.toString());
|
return unmarshallModel(is, configUrl.toString());
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
catch (IOException e)
|
||||||
@@ -238,25 +296,61 @@ public class AuditModelRegistry
|
|||||||
/**
|
/**
|
||||||
* Unmarshalls the Audit model from a stream
|
* Unmarshalls the Audit model from a stream
|
||||||
*/
|
*/
|
||||||
private static Audit unmarshallModel(InputStream is, String source)
|
private static Audit unmarshallModel(InputStream is, final String source)
|
||||||
{
|
{
|
||||||
|
final Schema schema;
|
||||||
|
final JAXBContext jaxbCtx;
|
||||||
|
final Unmarshaller jaxbUnmarshaller;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
JAXBContext jaxbCtx = JAXBContext.newInstance("org.alfresco.repo.audit.model._3");
|
SchemaFactory sf = SchemaFactory.newInstance(javax.xml.XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
||||||
Unmarshaller jaxbUnmarshaller = jaxbCtx.createUnmarshaller();
|
schema = sf.newSchema(ResourceUtils.getURL(AUDIT_SCHEMA_LOCATION));
|
||||||
|
jaxbCtx = JAXBContext.newInstance("org.alfresco.repo.audit.model._3");
|
||||||
|
jaxbUnmarshaller = jaxbCtx.createUnmarshaller();
|
||||||
|
jaxbUnmarshaller.setSchema(schema);
|
||||||
|
jaxbUnmarshaller.setEventHandler(new ValidationEventHandler()
|
||||||
|
{
|
||||||
|
public boolean handleEvent(ValidationEvent ve)
|
||||||
|
{
|
||||||
|
if (ve.getSeverity() == ValidationEvent.FATAL_ERROR || ve.getSeverity() == ValidationEvent.ERROR)
|
||||||
|
{
|
||||||
|
ValidationEventLocator locator = ve.getLocator();
|
||||||
|
logger.error("Invalid Audit XML: \n" +
|
||||||
|
" Source: " + source + "\n" +
|
||||||
|
" Location: Line " + locator.getLineNumber() + " column " + locator.getColumnNumber() + "\n" +
|
||||||
|
" Error: " + ve.getMessage());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Throwable e)
|
||||||
|
{
|
||||||
|
throw new AlfrescoRuntimeException(
|
||||||
|
"Failed to load Alfresco Audit Schema from " + AUDIT_SCHEMA_LOCATION, e);
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Unmarshall with validation
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
JAXBElement<Audit> auditElement = (JAXBElement<Audit>) jaxbUnmarshaller.unmarshal(is);
|
JAXBElement<Audit> auditElement = (JAXBElement<Audit>) jaxbUnmarshaller.unmarshal(is);
|
||||||
|
|
||||||
Audit audit = auditElement.getValue();
|
Audit audit = auditElement.getValue();
|
||||||
// Done
|
// Done
|
||||||
return audit;
|
return audit;
|
||||||
}
|
}
|
||||||
catch (Throwable e)
|
catch (Throwable e)
|
||||||
{
|
{
|
||||||
throw new AlfrescoRuntimeException(
|
// Dig out a SAXParseException, if there is one
|
||||||
|
Throwable saxError = ExceptionStackUtil.getCause(e, SAXParseException.class);
|
||||||
|
if (saxError != null)
|
||||||
|
{
|
||||||
|
e = saxError;
|
||||||
|
}
|
||||||
|
throw new AuditModelException(
|
||||||
"Failed to read Audit model XML: \n" +
|
"Failed to read Audit model XML: \n" +
|
||||||
" Source: " + source + "\n" +
|
" Source: " + source + "\n" +
|
||||||
" Error: " + e.getMessage(),
|
" Error: " + e.getMessage());
|
||||||
e);
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -268,14 +362,14 @@ public class AuditModelRegistry
|
|||||||
{
|
{
|
||||||
// Get the data extractors and check for duplicates
|
// Get the data extractors and check for duplicates
|
||||||
DataExtractors extractorsElement = audit.getDataExtractors();
|
DataExtractors extractorsElement = audit.getDataExtractors();
|
||||||
|
if (extractorsElement == null)
|
||||||
|
{
|
||||||
|
extractorsElement = new ObjectFactory().createDataExtractors();
|
||||||
|
}
|
||||||
List<org.alfresco.repo.audit.model._3.DataExtractor> converterElements = extractorsElement.getDataExtractor();
|
List<org.alfresco.repo.audit.model._3.DataExtractor> converterElements = extractorsElement.getDataExtractor();
|
||||||
for (org.alfresco.repo.audit.model._3.DataExtractor converterElement : converterElements)
|
for (org.alfresco.repo.audit.model._3.DataExtractor converterElement : converterElements)
|
||||||
{
|
{
|
||||||
String name = converterElement.getName();
|
String name = converterElement.getName();
|
||||||
if (dataExtractorsByName.containsKey(name))
|
|
||||||
{
|
|
||||||
throw new AuditModelException("Audit data extractor '" + name + "' has already been defined.");
|
|
||||||
}
|
|
||||||
// Construct the converter
|
// Construct the converter
|
||||||
final DataExtractor dataExtractor;
|
final DataExtractor dataExtractor;
|
||||||
try
|
try
|
||||||
@@ -293,18 +387,29 @@ public class AuditModelRegistry
|
|||||||
throw new AuditModelException(
|
throw new AuditModelException(
|
||||||
"Audit data extractor '" + name + "' could not be constructed: " + converterElement.getClazz());
|
"Audit data extractor '" + name + "' could not be constructed: " + converterElement.getClazz());
|
||||||
}
|
}
|
||||||
|
// 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 + "' is incompatible with an existing instance.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store
|
||||||
dataExtractorsByName.put(name, dataExtractor);
|
dataExtractorsByName.put(name, dataExtractor);
|
||||||
}
|
}
|
||||||
// Get the data generators and check for duplicates
|
// Get the data generators and check for duplicates
|
||||||
DataGenerators generatorsElement = audit.getDataGenerators();
|
DataGenerators generatorsElement = audit.getDataGenerators();
|
||||||
|
if (generatorsElement == null)
|
||||||
|
{
|
||||||
|
generatorsElement = new ObjectFactory().createDataGenerators();
|
||||||
|
}
|
||||||
List<org.alfresco.repo.audit.model._3.DataGenerator> generatorElements = generatorsElement.getDataGenerator();
|
List<org.alfresco.repo.audit.model._3.DataGenerator> generatorElements = generatorsElement.getDataGenerator();
|
||||||
for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements)
|
for (org.alfresco.repo.audit.model._3.DataGenerator generatorElement : generatorElements)
|
||||||
{
|
{
|
||||||
String name = generatorElement.getName();
|
String name = generatorElement.getName();
|
||||||
if (dataGeneratorsByName.containsKey(name))
|
|
||||||
{
|
|
||||||
throw new AuditModelException("Audit data generator '" + name + "' has already been defined.");
|
|
||||||
}
|
|
||||||
// Construct the converter
|
// Construct the converter
|
||||||
final DataGenerator dataGenerator;
|
final DataGenerator dataGenerator;
|
||||||
try
|
try
|
||||||
@@ -322,6 +427,17 @@ public class AuditModelRegistry
|
|||||||
throw new AuditModelException(
|
throw new AuditModelException(
|
||||||
"Audit data generator '" + name + "' could not be constructed: " + generatorElement.getClazz());
|
"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 + "' is incompatible with an existing instance.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Store
|
||||||
dataGeneratorsByName.put(name, dataGenerator);
|
dataGeneratorsByName.put(name, dataGenerator);
|
||||||
}
|
}
|
||||||
// Get the application and check for duplicates
|
// Get the application and check for duplicates
|
||||||
@@ -333,7 +449,8 @@ public class AuditModelRegistry
|
|||||||
{
|
{
|
||||||
throw new AuditModelException("Audit application '" + name + "' has already been defined.");
|
throw new AuditModelException("Audit application '" + name + "' has already been defined.");
|
||||||
}
|
}
|
||||||
auditApplicationsByName.put(name, application);
|
AuditApplication wrapperApp = new AuditApplication(dataExtractorsByName, dataGeneratorsByName, application);
|
||||||
|
auditApplicationsByName.put(name, wrapperApp);
|
||||||
auditModelIdsByApplicationsName.put(name, auditModelId);
|
auditModelIdsByApplicationsName.put(name, auditModelId);
|
||||||
}
|
}
|
||||||
// Store the model itself
|
// Store the model itself
|
||||||
|
@@ -20,7 +20,6 @@ import javax.xml.bind.annotation.XmlType;
|
|||||||
* <complexContent>
|
* <complexContent>
|
||||||
* <extension base="{http://www.alfresco.org/repo/audit/model/3.2}KeyedAuditDefinition">
|
* <extension base="{http://www.alfresco.org/repo/audit/model/3.2}KeyedAuditDefinition">
|
||||||
* <sequence>
|
* <sequence>
|
||||||
* <element name="AuditSession" type="{http://www.alfresco.org/repo/audit/model/3.2}AuditSession" minOccurs="0"/>
|
|
||||||
* <element name="RecordValue" type="{http://www.alfresco.org/repo/audit/model/3.2}RecordValue" maxOccurs="unbounded" minOccurs="0"/>
|
* <element name="RecordValue" type="{http://www.alfresco.org/repo/audit/model/3.2}RecordValue" maxOccurs="unbounded" minOccurs="0"/>
|
||||||
* <element name="GenerateValue" type="{http://www.alfresco.org/repo/audit/model/3.2}GenerateValue" maxOccurs="unbounded" minOccurs="0"/>
|
* <element name="GenerateValue" type="{http://www.alfresco.org/repo/audit/model/3.2}GenerateValue" maxOccurs="unbounded" minOccurs="0"/>
|
||||||
* <element name="AuditPath" type="{http://www.alfresco.org/repo/audit/model/3.2}AuditPath" maxOccurs="unbounded" minOccurs="0"/>
|
* <element name="AuditPath" type="{http://www.alfresco.org/repo/audit/model/3.2}AuditPath" maxOccurs="unbounded" minOccurs="0"/>
|
||||||
@@ -34,7 +33,6 @@ import javax.xml.bind.annotation.XmlType;
|
|||||||
*/
|
*/
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
@XmlAccessorType(XmlAccessType.FIELD)
|
||||||
@XmlType(name = "AuditPath", propOrder = {
|
@XmlType(name = "AuditPath", propOrder = {
|
||||||
"auditSession",
|
|
||||||
"recordValue",
|
"recordValue",
|
||||||
"generateValue",
|
"generateValue",
|
||||||
"auditPath"
|
"auditPath"
|
||||||
@@ -46,8 +44,6 @@ public class AuditPath
|
|||||||
extends KeyedAuditDefinition
|
extends KeyedAuditDefinition
|
||||||
{
|
{
|
||||||
|
|
||||||
@XmlElement(name = "AuditSession")
|
|
||||||
protected AuditSession auditSession;
|
|
||||||
@XmlElement(name = "RecordValue")
|
@XmlElement(name = "RecordValue")
|
||||||
protected List<RecordValue> recordValue;
|
protected List<RecordValue> recordValue;
|
||||||
@XmlElement(name = "GenerateValue")
|
@XmlElement(name = "GenerateValue")
|
||||||
@@ -55,30 +51,6 @@ public class AuditPath
|
|||||||
@XmlElement(name = "AuditPath")
|
@XmlElement(name = "AuditPath")
|
||||||
protected List<AuditPath> auditPath;
|
protected List<AuditPath> auditPath;
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the auditSession property.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* possible object is
|
|
||||||
* {@link AuditSession }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public AuditSession getAuditSession() {
|
|
||||||
return auditSession;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value of the auditSession property.
|
|
||||||
*
|
|
||||||
* @param value
|
|
||||||
* allowed object is
|
|
||||||
* {@link AuditSession }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public void setAuditSession(AuditSession value) {
|
|
||||||
this.auditSession = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the recordValue property.
|
* Gets the value of the recordValue property.
|
||||||
*
|
*
|
||||||
|
@@ -1,69 +0,0 @@
|
|||||||
|
|
||||||
package org.alfresco.repo.audit.model._3;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessType;
|
|
||||||
import javax.xml.bind.annotation.XmlAccessorType;
|
|
||||||
import javax.xml.bind.annotation.XmlElement;
|
|
||||||
import javax.xml.bind.annotation.XmlType;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* <p>Java class for AuditSession complex type.
|
|
||||||
*
|
|
||||||
* <p>The following schema fragment specifies the expected content contained within this class.
|
|
||||||
*
|
|
||||||
* <pre>
|
|
||||||
* <complexType name="AuditSession">
|
|
||||||
* <complexContent>
|
|
||||||
* <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
|
|
||||||
* <sequence>
|
|
||||||
* <element name="GenerateValue" type="{http://www.alfresco.org/repo/audit/model/3.2}GenerateValue" maxOccurs="unbounded" minOccurs="0"/>
|
|
||||||
* </sequence>
|
|
||||||
* </restriction>
|
|
||||||
* </complexContent>
|
|
||||||
* </complexType>
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
@XmlAccessorType(XmlAccessType.FIELD)
|
|
||||||
@XmlType(name = "AuditSession", propOrder = {
|
|
||||||
"generateValue"
|
|
||||||
})
|
|
||||||
public class AuditSession {
|
|
||||||
|
|
||||||
@XmlElement(name = "GenerateValue")
|
|
||||||
protected List<GenerateValue> generateValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of the generateValue property.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* This accessor method returns a reference to the live list,
|
|
||||||
* not a snapshot. Therefore any modification you make to the
|
|
||||||
* returned list will be present inside the JAXB object.
|
|
||||||
* This is why there is not a <CODE>set</CODE> method for the generateValue property.
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* For example, to add a new item, do as follows:
|
|
||||||
* <pre>
|
|
||||||
* getGenerateValue().add(newItem);
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* Objects of the following type(s) are allowed in the list
|
|
||||||
* {@link GenerateValue }
|
|
||||||
*
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public List<GenerateValue> getGenerateValue() {
|
|
||||||
if (generateValue == null) {
|
|
||||||
generateValue = new ArrayList<GenerateValue>();
|
|
||||||
}
|
|
||||||
return this.generateValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -17,6 +17,7 @@ import javax.xml.bind.annotation.XmlType;
|
|||||||
* <complexContent>
|
* <complexContent>
|
||||||
* <extension base="{http://www.alfresco.org/repo/audit/model/3.2}KeyedAuditDefinition">
|
* <extension base="{http://www.alfresco.org/repo/audit/model/3.2}KeyedAuditDefinition">
|
||||||
* <attribute name="dataGenerator" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
|
* <attribute name="dataGenerator" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}NameAttribute" />
|
||||||
|
* <attribute name="scope" use="required" type="{http://www.alfresco.org/repo/audit/model/3.2}ScopeAttribute" />
|
||||||
* </extension>
|
* </extension>
|
||||||
* </complexContent>
|
* </complexContent>
|
||||||
* </complexType>
|
* </complexType>
|
||||||
@@ -32,6 +33,8 @@ public class GenerateValue
|
|||||||
|
|
||||||
@XmlAttribute(required = true)
|
@XmlAttribute(required = true)
|
||||||
protected String dataGenerator;
|
protected String dataGenerator;
|
||||||
|
@XmlAttribute(required = true)
|
||||||
|
protected ScopeAttribute scope;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the value of the dataGenerator property.
|
* Gets the value of the dataGenerator property.
|
||||||
@@ -57,4 +60,28 @@ public class GenerateValue
|
|||||||
this.dataGenerator = value;
|
this.dataGenerator = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value of the scope property.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* possible object is
|
||||||
|
* {@link ScopeAttribute }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public ScopeAttribute getScope() {
|
||||||
|
return scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of the scope property.
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* allowed object is
|
||||||
|
* {@link ScopeAttribute }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void setScope(ScopeAttribute value) {
|
||||||
|
this.scope = value;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -33,6 +33,30 @@ public class ObjectFactory {
|
|||||||
public ObjectFactory() {
|
public ObjectFactory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of {@link KeyedAuditDefinition }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
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 }
|
* Create an instance of {@link DataExtractors }
|
||||||
*
|
*
|
||||||
@@ -49,6 +73,14 @@ public class ObjectFactory {
|
|||||||
return new AuditPath();
|
return new AuditPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create an instance of {@link DataGenerator }
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public DataGenerator createDataGenerator() {
|
||||||
|
return new DataGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link DataGenerators }
|
* Create an instance of {@link DataGenerators }
|
||||||
*
|
*
|
||||||
@@ -57,14 +89,6 @@ public class ObjectFactory {
|
|||||||
return new DataGenerators();
|
return new DataGenerators();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of {@link KeyedAuditDefinition }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public KeyedAuditDefinition createKeyedAuditDefinition() {
|
|
||||||
return new KeyedAuditDefinition();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link RecordValue }
|
* Create an instance of {@link RecordValue }
|
||||||
*
|
*
|
||||||
@@ -73,38 +97,6 @@ public class ObjectFactory {
|
|||||||
return new RecordValue();
|
return new RecordValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of {@link DataGenerator }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public DataGenerator createDataGenerator() {
|
|
||||||
return new DataGenerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of {@link AuditSession }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public AuditSession createAuditSession() {
|
|
||||||
return new AuditSession();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of {@link GenerateValue }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public GenerateValue createGenerateValue() {
|
|
||||||
return new GenerateValue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create an instance of {@link DataExtractor }
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public DataExtractor createDataExtractor() {
|
|
||||||
return new DataExtractor();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link Application }
|
* Create an instance of {@link Application }
|
||||||
*
|
*
|
||||||
@@ -114,11 +106,11 @@ public class ObjectFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an instance of {@link Audit }
|
* Create an instance of {@link GenerateValue }
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public Audit createAudit() {
|
public GenerateValue createGenerateValue() {
|
||||||
return new Audit();
|
return new GenerateValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -0,0 +1,40 @@
|
|||||||
|
|
||||||
|
package org.alfresco.repo.audit.model._3;
|
||||||
|
|
||||||
|
import javax.xml.bind.annotation.XmlEnum;
|
||||||
|
import javax.xml.bind.annotation.XmlType;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Java class for ScopeAttribute.
|
||||||
|
*
|
||||||
|
* <p>The following schema fragment specifies the expected content contained within this class.
|
||||||
|
* <p>
|
||||||
|
* <pre>
|
||||||
|
* <simpleType name="ScopeAttribute">
|
||||||
|
* <restriction base="{http://www.w3.org/2001/XMLSchema}string">
|
||||||
|
* <enumeration value="SESSION"/>
|
||||||
|
* <enumeration value="AUDIT"/>
|
||||||
|
* <enumeration value="ALL"/>
|
||||||
|
* </restriction>
|
||||||
|
* </simpleType>
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@XmlType(name = "ScopeAttribute")
|
||||||
|
@XmlEnum
|
||||||
|
public enum ScopeAttribute {
|
||||||
|
|
||||||
|
SESSION,
|
||||||
|
AUDIT,
|
||||||
|
ALL;
|
||||||
|
|
||||||
|
public String value() {
|
||||||
|
return name();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ScopeAttribute fromValue(String v) {
|
||||||
|
return valueOf(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test Bad 01" key="test-bad-01">
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="blah"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test Bad 02" key="test-bad-02">
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<GenerateValue key="value.1" dataGenerator="blah" scope="AUDIT"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
@@ -0,0 +1,22 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test Bad 03" key="test-bad-03">
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test Bad 04" key="test-bad-04">
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<RecordValue key="value.UPPER" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
@@ -0,0 +1,19 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test Bad 05" key="test-bad-05">
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSIOn"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
66
source/test-resources/alfresco/audit/alfresco-audit-test.xml
Normal file
66
source/test-resources/alfresco/audit/alfresco-audit-test.xml
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
<?xml version='1.0' encoding='UTF-8'?>
|
||||||
|
|
||||||
|
<!-- Default Audit Configuration -->
|
||||||
|
|
||||||
|
<Audit
|
||||||
|
xmlns="http://www.alfresco.org/repo/audit/model/3.2"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.alfresco.org/repo/audit/model/3.2 alfresco-audit-3.2.xsd"
|
||||||
|
>
|
||||||
|
|
||||||
|
<!-- Includes duplicate definitions of the extractors and generators -->
|
||||||
|
|
||||||
|
<DataExtractors>
|
||||||
|
<DataExtractor name="simpleValue" class="org.alfresco.repo.audit.extractor.SimpleValueDataExtractor"/>
|
||||||
|
</DataExtractors>
|
||||||
|
|
||||||
|
<DataGenerators>
|
||||||
|
<DataGenerator name="systemTime" class="org.alfresco.repo.audit.generator.SystemTimeDataGenerator"/>
|
||||||
|
</DataGenerators>
|
||||||
|
|
||||||
|
<Application name="Alfresco Test" key="test">
|
||||||
|
<GenerateValue key="time" dataGenerator="systemTime" scope="SESSION"/>
|
||||||
|
<AuditPath key="1.1">
|
||||||
|
<AuditPath key="2.1">
|
||||||
|
<AuditPath key="3.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
<AuditPath key="4.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="4.2">
|
||||||
|
<RecordValue key="value.2" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="3.2">
|
||||||
|
<AuditPath key="4.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
<GenerateValue key="time" dataGenerator="systemTime" scope="AUDIT"/>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="4.2">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="2.2">
|
||||||
|
<AuditPath key="3.1">
|
||||||
|
<AuditPath key="4.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="4.2">
|
||||||
|
<RecordValue key="value.2" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="3.2">
|
||||||
|
<AuditPath key="4.1">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
<GenerateValue key="time" dataGenerator="systemTime" scope="ALL"/>
|
||||||
|
</AuditPath>
|
||||||
|
<AuditPath key="4.2">
|
||||||
|
<RecordValue key="value.1" dataExtractor="simpleValue"/>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</AuditPath>
|
||||||
|
</Application>
|
||||||
|
|
||||||
|
</Audit>
|
Reference in New Issue
Block a user